diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp index 2b59c0d05..54a8da408 100644 --- a/src/ncp/changed_props_set.cpp +++ b/src/ncp/changed_props_set.cpp @@ -79,6 +79,10 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = { SPINEL_PROP_NET_XPANID, SPINEL_STATUS_OK, true }, // 25 { SPINEL_PROP_NET_MASTER_KEY, SPINEL_STATUS_OK, true }, // 26 { SPINEL_PROP_NET_PSKC, SPINEL_STATUS_OK, true }, // 27 +#if OPENTHREAD_ENABLE_CHANNEL_MANAGER + { SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_STATUS_OK, true }, // 28 +#endif + }; uint8_t ChangedPropsSet::GetNumEntries(void) const diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index dcb47b28e..e1b65339b 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -245,6 +245,10 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_NEW_CHANNEL), NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_DELAY), NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_SUPPORTED_CHANNELS), + NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_FAVORED_CHANNELS), + NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_CHANNEL_SELECT), + NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED), + NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL), #endif #endif // OPENTHREAD_FTD @@ -347,6 +351,10 @@ const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_NEW_CHANNEL), NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_DELAY), NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_SUPPORTED_CHANNELS), + NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_FAVORED_CHANNELS), + NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_CHANNEL_SELECT), + NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED), + NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL), #endif #endif // #if OPENTHREAD_FTD }; @@ -1253,8 +1261,12 @@ otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKe ExitNow(error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_PROP_NOT_FOUND)); } + mDisableStreamWrite = false; + error = (this->*handler)(); + mDisableStreamWrite = true; + if (error == OT_ERROR_NONE) { error = PrepareSetResponse(aHeader, aKey); @@ -1304,8 +1316,12 @@ otError NcpBase::HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_ mDecoder.ReadData(valuePtr, valueLen); mDecoder.ResetToSaved(); + mDisableStreamWrite = false; + error = (this->*handler)(); + mDisableStreamWrite = true; + VerifyOrExit(error == OT_ERROR_NONE, error = PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(error))); error = WritePropertyValueInsertedRemovedFrame(aHeader, responseCommand, aKey, valuePtr, valueLen); diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index f4ca49d79..667b2d8b7 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -671,6 +671,14 @@ protected: NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_DELAY); NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_SUPPORTED_CHANNELS); NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_SUPPORTED_CHANNELS); + NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_FAVORED_CHANNELS); + NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_FAVORED_CHANNELS); + NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_CHANNEL_SELECT); + NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_CHANNEL_SELECT); + NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_ENABLED); + NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_ENABLED); + NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL); + NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL); #endif #endif // OPENTHREAD_FTD diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 2ce700e86..2de6453ce 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -913,6 +913,74 @@ exit: return error; } +otError NcpBase::GetPropertyHandler_CHANNEL_MANAGER_FAVORED_CHANNELS(void) +{ + return EncodeChannelMask(otChannelManagerGetFavoredChannels(mInstance)); +} + +otError NcpBase::SetPropertyHandler_CHANNEL_MANAGER_FAVORED_CHANNELS(void) +{ + uint32_t channelMask = 0; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = DecodeChannelMask(channelMask)); + otChannelManagerSetFavoredChannels(mInstance, channelMask); + +exit: + return error; +} + +otError NcpBase::GetPropertyHandler_CHANNEL_MANAGER_CHANNEL_SELECT(void) +{ + return mEncoder.WriteBool(false); +} + +otError NcpBase::SetPropertyHandler_CHANNEL_MANAGER_CHANNEL_SELECT(void) +{ + bool skipQualityCheck = false; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadBool(skipQualityCheck)); + error = otChannelManagerRequestChannelSelect(mInstance, skipQualityCheck); + +exit: + return error; +} + +otError NcpBase::GetPropertyHandler_CHANNEL_MANAGER_AUTO_SELECT_ENABLED(void) +{ + return mEncoder.WriteBool(otChannelManagerGetAutoChannelSelectionEnabled(mInstance)); +} + +otError NcpBase::SetPropertyHandler_CHANNEL_MANAGER_AUTO_SELECT_ENABLED(void) +{ + bool enabled = false; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadBool(enabled)); + otChannelManagerSetAutoChannelSelectionEnabled(mInstance, enabled); + +exit: + return error; +} + +otError NcpBase::GetPropertyHandler_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL(void) +{ + return mEncoder.WriteUint32(otChannelManagerGetAutoChannelSelectionInterval(mInstance)); +} + +otError NcpBase::SetPropertyHandler_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL(void) +{ + uint32_t interval; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadUint32(interval)); + error = otChannelManagerSetAutoChannelSelectionInterval(mInstance, interval); + +exit: + return error; +} + #endif // OPENTHREAD_ENABLE_CHANNEL_MANAGER } // namespace Ncp diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 23f309e0b..4f519634e 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -2969,6 +2969,7 @@ void NcpBase::ProcessThreadChangedFlags(void) { OT_CHANGED_THREAD_EXT_PANID, SPINEL_PROP_NET_XPANID }, { OT_CHANGED_MASTER_KEY, SPINEL_PROP_NET_MASTER_KEY }, { OT_CHANGED_PSKC, SPINEL_PROP_NET_PSKC }, + { OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL }, }; VerifyOrExit(mThreadChangedFlags != 0); diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index dc3a10be6..79f7b335d 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1605,6 +1605,22 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS"; break; + case SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS: + ret = "PROP_CHANNEL_MANAGER_FAVORED_CHANNELS"; + break; + + case SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT: + ret = "PROP_CHANNEL_MANAGER_CHANNEL_SELECT"; + break; + + case SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED: + ret = "PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED"; + break; + + case SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL: + ret = "PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL"; + break; + case SPINEL_PROP_UART_BITRATE: ret = "PROP_UART_BITRATE"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 940652af7..7abfd6246 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -1500,6 +1500,70 @@ typedef enum SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS = SPINEL_PROP_OPENTHREAD__BEGIN + 2, + /// Channel Manager Favored Channels + /** Format 'A(C)' + * + * Required capability: SPINEL_CAP_CHANNEL_MANAGER + * + * This property specifies the list of favored channels (when `ChannelManager` is asked to select channel) + * + */ + SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS + = SPINEL_PROP_OPENTHREAD__BEGIN + 3, + + /// Channel Manager Channel Select Trigger + /** Format 'b' + * + * Required capability: SPINEL_CAP_CHANNEL_MANAGER + * + * Writing to this property triggers a request on `ChannelManager` to select a new channel. + * + * Once a Channel Select is triggered, the Channel Manager will perform the following 3 steps: + * + * 1) `ChannelManager` decides if the channel change would be helpful. This check can be skipped if in the input + * boolean to this property is set to `true` (skipping the quality check). + * This step uses the collected link quality metrics on the device such as CCA failure rate, frame and message + * error rates per neighbor, etc. to determine if the current channel quality is at the level that justifies + * a channel change. + * + * 2) If first step passes, then `ChannelManager` selects a potentially better channel. It uses the collected + * channel quality data by `ChannelMonitor` module. The supported and favored channels are used at this step. + * + * 3) If the newly selected channel is different from the current channel, `ChannelManager` requests/starts the + * channel change process. + * + * Reading this property always yields `false`. + * + */ + SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT + = SPINEL_PROP_OPENTHREAD__BEGIN + 4, + + /// Channel Manager Auto Channel Selection Enabled + /** Format 'b' + * + * Required capability: SPINEL_CAP_CHANNEL_MANAGER + * + * This property indicates if auto-channel-selection functionality is enabled/disabled on `ChannelManager`. + * + * When enabled, `ChannelManager` will periodically checks and attempts to select a new channel. The period interval + * is specified by `SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL`. + * + */ + SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED + = SPINEL_PROP_OPENTHREAD__BEGIN + 5, + + /// Channel Manager Auto Channel Selection Interval + /** Format 'L' + * units: seconds + * + * Required capability: SPINEL_CAP_CHANNEL_MANAGER + * + * This property specifies the auto-channel-selection check interval (in seconds). + * + */ + SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL + = SPINEL_PROP_OPENTHREAD__BEGIN + 6, + SPINEL_PROP_OPENTHREAD__END = 0x2000, /// UART Bitrate