diff --git a/include/openthread/dataset.h b/include/openthread/dataset.h index 50b174a0e6fb..5e24b8b07d90 100644 --- a/include/openthread/dataset.h +++ b/include/openthread/dataset.h @@ -213,6 +213,7 @@ typedef struct otOperationalDatasetComponents bool mIsPskcPresent; ///< TRUE if PSKc is present, FALSE otherwise. bool mIsSecurityPolicyPresent; ///< TRUE if Security Policy is present, FALSE otherwise. bool mIsChannelMaskPresent; ///< TRUE if Channel Mask is present, FALSE otherwise. + bool mIsWakeupChannelPresent; ///< TRUE if Wake-up Channel is present, FALSE otherwise. } otOperationalDatasetComponents; /** @@ -243,6 +244,7 @@ typedef struct otOperationalDataset uint32_t mDelay; ///< Delay Timer otPanId mPanId; ///< PAN ID uint16_t mChannel; ///< Channel + uint16_t mWakeupChannel; ///< Wake-up Channel otPskc mPskc; ///< PSKc otSecurityPolicy mSecurityPolicy; ///< Security Policy otChannelMask mChannelMask; ///< Channel Mask @@ -310,6 +312,7 @@ typedef enum otMeshcopTlvType OT_MESHCOP_TLV_PERIOD = 55, ///< meshcop Period TLV OT_MESHCOP_TLV_SCAN_DURATION = 56, ///< meshcop Scan Duration TLV OT_MESHCOP_TLV_ENERGY_LIST = 57, ///< meshcop Energy List TLV + OT_MESHCOP_TLV_WAKEUP_CHANNEL = 74, ///< meshcop Wake-up Channel TLV OT_MESHCOP_TLV_DISCOVERYREQUEST = 128, ///< meshcop Discovery Request TLV OT_MESHCOP_TLV_DISCOVERYRESPONSE = 129, ///< meshcop Discovery Response TLV OT_MESHCOP_TLV_JOINERADVERTISEMENT = 241, ///< meshcop Joiner Advertisement TLV diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 3d005568efa2..aef8c65cb95f 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (446) +#define OPENTHREAD_API_VERSION (447) /** * @addtogroup api-instance diff --git a/include/openthread/link.h b/include/openthread/link.h index bd42cff20de8..fe7aa847e973 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -1204,6 +1204,29 @@ otError otLinkSetRegion(otInstance *aInstance, uint16_t aRegionCode); */ otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode); +/** + * The Wake-up channel. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Wake-up channel. + * + */ +uint8_t otLinkGetWakeupChannel(otInstance *aInstance); + +/** + * Sets the Wake-up channel. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aChannel The Wake-up sample channel. Channel value should be `0` (Set Wake-up Channel unspecified) + * or within the range [1, 10] (if 915-MHz supported) and [11, 26] (if 2.4 GHz supported). + * + * @retval OT_ERROR_NONE Successfully set the Wake-up channel. + * @retval OT_ERROR_INVALID_ARGS Invalid @p aChannel. + * + */ +otError otLinkSetWakeupChannel(otInstance *aInstance, uint8_t aChannel); + /** * @} * diff --git a/src/cli/README.md b/src/cli/README.md index 47af9a6a0653..c8ac5c1553b0 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -133,6 +133,7 @@ Done - [vendor](#vendor-name) - [verhoeff](#verhoeff-calculate) - [version](#version) +- [wakeupchannel](#wakeupchannel) ## OpenThread Command Details @@ -4371,3 +4372,22 @@ Done Factory Diagnostics module is enabled only when building OpenThread with `OPENTHREAD_CONFIG_DIAG_ENABLE=1` option. Go [diagnostics module][diag] for more information. [diag]: ../../src/core/diags/README.md + +### wakeupchannel + +Get the wake-up channel. + +```bash +> wakeupchannel +12 +Done +``` + +### wakeupchannel \ + +Set the wake-up channel. + +```bash +> wakeupchannel 12 +Done +``` diff --git a/src/cli/README_DATASET.md b/src/cli/README_DATASET.md index abed5080d627..5e70037611ba 100644 --- a/src/cli/README_DATASET.md +++ b/src/cli/README_DATASET.md @@ -19,6 +19,7 @@ The Active Operational Dataset includes parameters that are currently in use acr - Active Timestamp - Channel +- Wake-up Channel - Channel Mask - Extended PAN ID - Mesh-Local Prefix @@ -46,6 +47,7 @@ The Pending Operational Dataset is used to communicate changes to the Active Ope > dataset Active Timestamp: 1 Channel: 15 + Wake-up Channel: 16 Channel Mask: 0x07fff800 Ext PAN ID: 39758ec8144b07fb Mesh Local Prefix: fdf1:f1ad:d079:7dc0::/64 @@ -105,6 +107,7 @@ After the device successfully attaches to a Thread network, the device will retr > dataset active Active Timestamp: 1 Channel: 15 + Wake-up Channel: 16 Channel Mask: 0x07fff800 Ext PAN ID: 39758ec8144b07fb Mesh Local Prefix: fdf1:f1ad:d079:7dc0::/64 @@ -303,6 +306,7 @@ Normally, an active Commissioner will set a new Pending Operational Dataset. For - [securitypolicy](#securitypolicy) - [tlvs](#tlvs) - [updater](#updater) +- [wakeupchannel](#wakeupchannel) ## Command Details @@ -336,6 +340,7 @@ pskc securitypolicy set tlvs +wakeupchannel Done ``` @@ -349,6 +354,7 @@ Print Active Operational Dataset in human-readable form. > dataset active Active Timestamp: 1 Channel: 15 +Wake-up Channel: 16 Channel Mask: 0x07fff800 Ext PAN ID: 39758ec8144b07fb Mesh Local Prefix: fdf1:f1ad:d079:7dc0::/64 @@ -364,7 +370,7 @@ Print Active Operational Dataset as hex-encoded TLVs. ```bash > dataset active -x -0e080000000000010000000300000f35060004001fffe0020839758ec8144b07fb0708fdf1f1add0797dc00510f366cec7a446bab978d90d27abe38f23030f4f70656e5468726561642d353933380102593804103ca67c969efb0d0c74a4d8ee923b576c0c0402a0f7f8 +0e08000000000001000000030000164a0300001735060004001fffe00208b182e6a17996cecc0708fd3f363fa8f1b0bc0510ebb6f6a447c96e1542176df3a834ac0e030f4f70656e5468726561642d3663393901026c99041096e9cdfe1eb1363a3676e2b94df0271b0c0402a0f7f8 Done ``` @@ -828,3 +834,22 @@ Done Disabled Done ``` + +### wakeupchannel + +Usage: `wakeupchannel [channel]` + +Get wake-up channel. + +```bash +> dataset wakeupchannel +13 +Done +``` + +Set wake-up channel. + +```bash +> dataset wakeupchannel 13 +Done +``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 5da53f96fad4..2de03efce4c2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -8206,6 +8206,27 @@ template <> otError Interpreter::Process(Arg aArgs[]) #endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE +/** + * @cli wakeupchannel (get,set) + * @code + * wakeupchannel + * 12 + * Done + * @endcode + * @code + * wakeupchannel 12 + * Done + * @endcode + * @cparam wakeupchannel [@ca{channel}] + * Use `channel` to set the wake-up channel. + * @par + * Gets or sets the wake-up channel value. + */ +template <> otError Interpreter::Process(Arg aArgs[]) +{ + return ProcessGetSet(aArgs, otLinkGetWakeupChannel, otLinkSetWakeupChannel); +} + #endif // OPENTHREAD_FTD || OPENTHREAD_MTD void Interpreter::Initialize(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext) diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 327a2411d0d5..d7d7d678e16c 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -134,6 +134,12 @@ const Dataset::ComponentMapper *Dataset::LookupMapper(const char *aName) const &Dataset::OutputSecurityPolicy, &Dataset::ParseSecurityPolicy, }, + { + "wakeupchannel", + &Components::mIsWakeupChannelPresent, + &Dataset::OutputWakeupChannel, + &Dataset::ParseWakeupChannel, + }, }; static_assert(BinarySearch::IsSorted(kMappers), "kMappers is not sorted"); @@ -182,6 +188,24 @@ void Dataset::OutputActiveTimestamp(const otOperationalDataset &aDataset) */ void Dataset::OutputChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mChannel); } +/** + * @cli dataset wakeupchannel (get,set) + * @code + * dataset wakeupchannel + * 13 + * Done + * @endcode + * @code + * dataset wakeupchannel 13 + * Done + * @endcode + * @cparam dataset wakeupchannel [@ca{channel-num}] + * Use the optional `channel-num` argument to set the wake-up channel. + * @par + * Gets or sets #otOperationalDataset::mWakeupChannel. + */ +void Dataset::OutputWakeupChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mWakeupChannel); } + /** * @cli dataset channelmask (get,set) * @code @@ -412,6 +436,11 @@ otError Dataset::ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset) return aArgs++->ParseAsUint16(aDataset.mChannel); } +otError Dataset::ParseWakeupChannel(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return aArgs++->ParseAsUint16(aDataset.mWakeupChannel); +} + otError Dataset::ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset) { return aArgs++->ParseAsUint32(aDataset.mChannelMask); @@ -561,6 +590,7 @@ otError Dataset::Print(otOperationalDatasetTlvs &aDatasetTlvs) {"Pending Timestamp", "pendingtimestamp"}, {"Active Timestamp", "activetimestamp"}, {"Channel", "channel"}, + {"Wake-up Channel", "wakeupchannel"}, {"Channel Mask", "channelmask"}, {"Delay", "delay"}, {"Ext PAN ID", "extpanid"}, diff --git a/src/cli/cli_dataset.hpp b/src/cli/cli_dataset.hpp index 708e4790e2f2..22174a2386ca 100644 --- a/src/cli/cli_dataset.hpp +++ b/src/cli/cli_dataset.hpp @@ -94,6 +94,7 @@ class Dataset : private Utils void OutputActiveTimestamp(const otOperationalDataset &aDataset); void OutputChannel(const otOperationalDataset &aDataset); + void OutputWakeupChannel(const otOperationalDataset &aDataset); void OutputChannelMask(const otOperationalDataset &aDataset); void OutputDelay(const otOperationalDataset &aDataset); void OutputExtendedPanId(const otOperationalDataset &aDataset); @@ -107,6 +108,7 @@ class Dataset : private Utils otError ParseActiveTimestamp(Arg *&aArgs, otOperationalDataset &aDataset); otError ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseWakeupChannel(Arg *&aArgs, otOperationalDataset &aDataset); otError ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset); otError ParseDelay(Arg *&aArgs, otOperationalDataset &aDataset); otError ParseExtendedPanId(Arg *&aArgs, otOperationalDataset &aDataset); diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp index c7127020f1dc..fdf1e3e7d556 100644 --- a/src/core/api/link_api.cpp +++ b/src/core/api/link_api.cpp @@ -79,6 +79,27 @@ otError otLinkSetChannel(otInstance *aInstance, uint8_t aChannel) return error; } +uint8_t otLinkGetWakeupChannel(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetWakeupChannel(); +} + +otError otLinkSetWakeupChannel(otInstance *aInstance, uint8_t aChannel) +{ + Error error = kErrorNone; + Instance &instance = AsCoreType(aInstance); + + VerifyOrExit(instance.Get().IsDisabled(), error = kErrorInvalidState); + + instance.Get().SetWakeupChannel(aChannel); + + instance.Get().Clear(); + instance.Get().Clear(); + +exit: + return error; +} + uint32_t otLinkGetSupportedChannelMask(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetSupportedChannelMask().GetMask(); diff --git a/src/core/config/misc.h b/src/core/config/misc.h index 56dd92bed7f9..ded0a2862160 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -517,6 +517,16 @@ #endif // OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT #endif // OPENTHREAD_CONFIG_DEFAULT_CHANNEL +/** + * @def OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL + * + * The default IEEE 802.15.4 wake-up channel. + * + */ +#ifndef OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL +#define OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL 11 +#endif // OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL + /** * @def OPENTHREAD_CONFIG_OTNS_ENABLE * diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 19f8d0037fb2..d00d90f52e18 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -82,6 +82,7 @@ Mac::Mac(Instance &aInstance) , mCslChannel(0) , mCslPeriod(0) #endif + , mWakeupChannel(OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL) , mActiveScanHandler(nullptr) // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union , mScanHandlerContext(nullptr) , mLinks(aInstance) @@ -2399,5 +2400,7 @@ void Mac::SetRadioFilterEnabled(bool aFilterEnabled) } #endif +void Mac::SetWakeupChannel(uint8_t aChannel) { mWakeupChannel = aChannel; } + } // namespace Mac } // namespace ot diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 6f95ab7d3e5b..614f700f281d 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -751,6 +751,22 @@ class Mac : public InstanceLocator, private NonCopyable */ Error GetRegion(uint16_t &aRegionCode) const; + /** + * Gets the Wake-up channel. + * + * @returns Wake-up channel. + * + */ + uint8_t GetWakeupChannel(void) const { return mWakeupChannel; } + + /** + * Sets the Wake-up channel. + * + * @param[in] aChannel The Wake-up channel. + * + */ + void SetWakeupChannel(uint8_t aChannel); + private: static constexpr uint16_t kMaxCcaSampleCount = OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW; @@ -880,6 +896,7 @@ class Mac : public InstanceLocator, private NonCopyable uint8_t mCslChannel; uint16_t mCslPeriod; #endif + uint8_t mWakeupChannel; union { diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index aa1261dd2150..fcb85fc1287c 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -66,6 +66,7 @@ Error Dataset::Info::GenerateRandom(Instance &aInstance) mActiveTimestamp.mAuthoritative = false; mChannel = preferredChannels.ChooseRandomChannel(); mChannelMask = supportedChannels.GetMask(); + mWakeupChannel = OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL; mPanId = Mac::GenerateRandomPanId(); AsCoreType(&mSecurityPolicy).SetToDefault(); @@ -83,6 +84,7 @@ Error Dataset::Info::GenerateRandom(Instance &aInstance) mComponents.mIsMeshLocalPrefixPresent = true; mComponents.mIsPanIdPresent = true; mComponents.mIsChannelPresent = true; + mComponents.mIsWakeupChannelPresent = true; mComponents.mIsPskcPresent = true; mComponents.mIsSecurityPolicyPresent = true; mComponents.mIsChannelMaskPresent = true; @@ -148,6 +150,10 @@ bool Dataset::IsTlvValid(const Tlv &aTlv) VerifyOrExit(aTlv.GetLength() >= sizeof(ChannelTlvValue), isValid = false); isValid = aTlv.ReadValueAs().IsValid(); break; + case Tlv::kWakeupChannel: + VerifyOrExit(aTlv.GetLength() >= sizeof(ChannelTlvValue), isValid = false); + isValid = aTlv.ReadValueAs().IsValid(); + break; case Tlv::kNetworkName: isValid = As(aTlv).IsValid(); break; @@ -194,6 +200,7 @@ bool Dataset::ContainsAllRequiredTlvsFor(Type aType) const static const Tlv::Type kDatasetTlvs[] = { Tlv::kActiveTimestamp, Tlv::kChannel, + // Tlv::kWakeupChannel, Tlv::kChannelMask, Tlv::kExtendedPanId, Tlv::kMeshLocalPrefix, @@ -235,6 +242,10 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const aDatasetInfo.Set(cur->ReadValueAs().GetChannel()); break; + case Tlv::kWakeupChannel: + aDatasetInfo.Set(cur->ReadValueAs().GetChannel()); + break; + case Tlv::kChannelMask: { uint32_t mask; @@ -433,6 +444,14 @@ Error Dataset::WriteTlvsFrom(const Dataset::Info &aDatasetInfo) SuccessOrExit(error = Write(channelValue)); } + if (aDatasetInfo.IsPresent()) + { + ChannelTlvValue channelValue; + + channelValue.SetChannelAndPage(aDatasetInfo.Get()); + SuccessOrExit(error = Write(channelValue)); + } + if (aDatasetInfo.IsPresent()) { ChannelMaskTlv::Value value; diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index 75e448ead417..c4aa1a5f6c26 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -94,6 +94,7 @@ class Dataset kDelay, ///< Delay kPanId, ///< PAN Identifier kChannel, ///< Channel + kWakeupChannel, ///< Wakeup Channel kPskc, ///< PSKc kSecurityPolicy, ///< Security Policy kChannelMask, ///< Channel Mask @@ -742,6 +743,7 @@ DefineIsPresentAndMarkAsPresent(MeshLocalPrefix) DefineIsPresentAndMarkAsPresent(Delay) DefineIsPresentAndMarkAsPresent(PanId) DefineIsPresentAndMarkAsPresent(Channel) +DefineIsPresentAndMarkAsPresent(WakeupChannel) DefineIsPresentAndMarkAsPresent(Pskc) DefineIsPresentAndMarkAsPresent(SecurityPolicy) DefineIsPresentAndMarkAsPresent(ChannelMask) @@ -760,6 +762,7 @@ template <> struct Dataset::TypeFor { using Type = I template <> struct Dataset::TypeFor { using Type = uint32_t; }; template <> struct Dataset::TypeFor { using Type = Mac::PanId; }; template <> struct Dataset::TypeFor { using Type = uint16_t; }; +template <> struct Dataset::TypeFor { using Type = uint16_t; }; template <> struct Dataset::TypeFor { using Type = Pskc; }; template <> struct Dataset::TypeFor { using Type = SecurityPolicy; }; template <> struct Dataset::TypeFor { using Type = uint32_t; }; @@ -795,6 +798,8 @@ template <> inline const Mac::PanId &Dataset::Info::Get(void) c template <> inline const uint16_t &Dataset::Info::Get(void) const { return mChannel; } +template <> inline const uint16_t &Dataset::Info::Get(void) const { return mWakeupChannel; } + template <> inline const Pskc &Dataset::Info::Get(void) const { return AsCoreType(&mPskc); } template <> inline const SecurityPolicy &Dataset::Info::Get(void) const diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 9f20831ceb20..3fb50414b025 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -193,6 +193,10 @@ Error DatasetManager::ApplyConfiguration(const Dataset &aDataset) const break; } + case Tlv::kWakeupChannel: + Get().SetWakeupChannel(static_cast(cur->ReadValueAs().GetChannel())); + break; + case Tlv::kPanId: Get().SetPanId(cur->ReadValueAs()); break; @@ -679,6 +683,11 @@ Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponen tlvList.Add(Tlv::kChannel); } + if (aDatasetComponents.IsPresent()) + { + tlvList.Add(Tlv::kWakeupChannel); + } + if (aDatasetComponents.IsPresent()) { tlvList.Add(Tlv::kPskc); diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index dbfaee3c0510..db3854279a11 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -93,6 +93,12 @@ Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand, aInfo.mAffectsConnectivity = true; } + if ((dataset.Read(channelValue) == kErrorNone) && + (channelValue.GetChannel() != Get().GetWakeupChannel())) + { + aInfo.mAffectsConnectivity = true; + } + if ((dataset.Read(panId) == kErrorNone) && (panId != Get().GetPanId())) { aInfo.mAffectsConnectivity = true; @@ -284,6 +290,14 @@ Error ActiveDatasetManager::GenerateLocal(void) IgnoreError(dataset.Write(channelValue)); } + if (!dataset.Contains()) + { + ChannelTlvValue channelValue; + + channelValue.SetChannelAndPage(Get().GetWakeupChannel()); + IgnoreError(dataset.Write(channelValue)); + } + if (!dataset.Contains()) { ChannelMaskTlv::Value value; diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 9d9b6f3a2a21..60bd11d2eae3 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -111,6 +111,7 @@ class Tlv : public ot::Tlv kPeriod = OT_MESHCOP_TLV_PERIOD, ///< Period TLV kScanDuration = OT_MESHCOP_TLV_SCAN_DURATION, ///< Scan Duration TLV kEnergyList = OT_MESHCOP_TLV_ENERGY_LIST, ///< Energy List TLV + kWakeupChannel = OT_MESHCOP_TLV_WAKEUP_CHANNEL, ///< Wakeup Channel TLV kDiscoveryRequest = OT_MESHCOP_TLV_DISCOVERYREQUEST, ///< Discovery Request TLV kDiscoveryResponse = OT_MESHCOP_TLV_DISCOVERYRESPONSE, ///< Discovery Response TLV kJoinerAdvertisement = OT_MESHCOP_TLV_JOINERADVERTISEMENT, ///< Joiner Advertisement TLV @@ -253,6 +254,12 @@ typedef Mle::ChannelTlvValue ChannelTlvValue; */ typedef SimpleTlvInfo ChannelTlv; +/** + * Defines Wake-up Channel TLV constants and types. + * + */ +typedef SimpleTlvInfo WakeupChannelTlv; + /** * Defines PAN ID TLV constants and types. * diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index 023bac0ee423..6b1af0207378 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -101,6 +101,7 @@ class Tlv : public ot::Tlv kPendingDataset = 25, ///< Pending Operational Dataset TLV kDiscovery = 26, ///< Thread Discovery TLV kSupervisionInterval = 27, ///< Supervision Interval TLV + kWakeupChannel = 74, ///< Wakeup Channel TLV kCslChannel = 80, ///< CSL Channel TLV kCslTimeout = 85, ///< CSL Timeout TLV kCslClockAccuracy = 86, ///< CSL Clock Accuracy TLV @@ -1139,6 +1140,12 @@ typedef SimpleTlvInfo ChannelTlv; */ typedef SimpleTlvInfo CslChannelTlv; +/** + * Defines Wake-up Channel TLV constants and types. + * + */ +typedef SimpleTlvInfo WakeupChannelTlv; + #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE /** * Defines Time Request TLV constants and types. diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index dc9e2ca256af..230aafa8908f 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1364,6 +1364,7 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER, "THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER"}, {SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, "THREAD_MGMT_SET_PENDING_DATASET_TLVS"}, + {SPINEL_PROP_THREAD_WAKEUP_CHANNEL, "THREAD_WAKEUP_CHANNEL"}, {SPINEL_PROP_MESHCOP_JOINER_STATE, "MESHCOP_JOINER_STATE"}, {SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING, "MESHCOP_JOINER_COMMISSIONING"}, {SPINEL_PROP_IPV6_LL_ADDR, "IPV6_LL_ADDR"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 169b12ab8795..c3a11f0cb2b2 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -3431,6 +3431,15 @@ enum */ SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS = SPINEL_PROP_THREAD_EXT__BEGIN + 62, + /// Wake-up Channel + /** Format: `C` + * + * The Wake-up sample channel. Channel value should be `0` (Set Wake-up Channel unspecified) + * or within the range [1, 10] (if 915-MHz supported) and [11, 26] (if 2.4 GHz supported). + * + */ + SPINEL_PROP_THREAD_WAKEUP_CHANNEL = SPINEL_PROP_THREAD_EXT__BEGIN + 63, + SPINEL_PROP_THREAD_EXT__END = 0x1600, SPINEL_PROP_IPV6__BEGIN = 0x60, diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index c7b7c1fe8e5d..8d9b4f859ee1 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -337,6 +337,7 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_PENDING_DATASET_TLVS), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS), + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_WAKEUP_CHANNEL), #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHANNEL_MANAGER_DELAY), @@ -609,6 +610,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_PENDING_DATASET_TLVS), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS), + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_WAKEUP_CHANNEL), #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN), diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 64f2f1fa6af6..163da84560d5 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -4793,6 +4793,24 @@ void NcpBase::ProcessThreadChangedFlags(void) return; } +template <> otError NcpBase::HandlePropertySet(void) +{ + uint8_t wakeupChannel; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadUint8(wakeupChannel)); + + error = otLinkSetWakeupChannel(mInstance, wakeupChannel); + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteUint8(otLinkGetWakeupChannel(mInstance)); +} + } // namespace Ncp } // namespace ot diff --git a/tools/otci/otci/otci.py b/tools/otci/otci/otci.py index 90097956cd1f..cef2323cab6f 100644 --- a/tools/otci/otci/otci.py +++ b/tools/otci/otci/otci.py @@ -1762,6 +1762,7 @@ def __parse_dataset(self, output: List[str]) -> Dict[str, Any]: # # Active Timestamp: 1 # Channel: 22 + # Wake-up Channel: 11 # Channel Mask: 0x07fff800 # Ext PAN ID: 5c93ae980ff22d35 # Mesh Local Prefix: fdc7:55fe:6363:bd01::/64 @@ -1781,6 +1782,8 @@ def __parse_dataset(self, output: List[str]) -> Dict[str, Any]: dataset['active_timestamp'] = int(val) elif key == 'Channel': dataset['channel'] = int(val) + elif key == 'Wake-up Channel': + dataset['wakeupchannel'] = int(val) elif key == 'Channel Mask': dataset['channel_mask'] = int(val, 16) elif key == 'Ext PAN ID': @@ -1829,6 +1832,7 @@ def get_dataset_tlvs_bytes(self) -> bytes: def dataset_set_buffer(self, active_timestamp: Optional[int] = None, channel: Optional[int] = None, + wakeupchannel: Optional[int] = None, channel_mask: Optional[int] = None, extpanid: Optional[str] = None, mesh_local_prefix: Optional[str] = None, @@ -1844,6 +1848,9 @@ def dataset_set_buffer(self, if channel is not None: self.execute_command(f'dataset channel {channel}') + if wakeupchannel is not None: + self.execute_command(f'dataset wakeupchannel {wakeupchannel}') + if channel_mask is not None: self.execute_command(f'dataset channelmask {channel_mask}')