[mac] enable wake-up frame periodic sniffing (#10762)

When `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE` is enabled:

- APIs are available to configure and enable wake-up frames sniffing.
- `SubMac::HandleWedTimer` periodically schedules receive slots on
  wake-up channel.
- Wake-up frames are processed.
- Upon reception of a wake-up frame, WUL is stopped.
This commit is contained in:
Eduardo Montoya
2024-10-14 13:11:37 -07:00
committed by GitHub
parent 072e53740b
commit ef8f1709cd
18 changed files with 687 additions and 50 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (454)
#define OPENTHREAD_API_VERSION (455)
/**
* @addtogroup api-instance
+54
View File
@@ -1126,6 +1126,60 @@ uint8_t otLinkGetWakeupChannel(otInstance *aInstance);
*/
otError otLinkSetWakeupChannel(otInstance *aInstance, uint8_t aChannel);
/**
* Enables or disables listening for wake-up frames.
*
* Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aEnable true to enable listening for wake-up frames, or false otherwise.
*
* @retval OT_ERROR_NONE Successfully enabled / disabled the listening for wake-up frames.
* @retval OT_ERROR_INVALID_ARGS The listen duration is greater than the listen interval.
* @retval OT_ERROR_INVALID_STATE Could not enable listening for wake-up frames due to bad configuration.
*/
otError otLinkSetWakeUpListenEnabled(otInstance *aInstance, bool aEnable);
/**
* Returns whether listening for wake-up frames is enabled.
*
* Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE If listening for wake-up frames is enabled.
* @retval FALSE If listening for wake-up frames is not enabled.
*/
bool otLinkIsWakeupListenEnabled(otInstance *aInstance);
/**
* Get the wake-up listen parameters.
*
* Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aInterval A pointer to return the wake-up listen interval in microseconds.
* @param[out] aDuration A pointer to return the wake-up listen duration in microseconds.
*/
void otLinkGetWakeupListenParameters(otInstance *aInstance, uint32_t *aInterval, uint32_t *aDuration);
/**
* Set the wake-up listen parameters.
*
* The listen interval must be greater than the listen duration.
* The listen duration must be greater or equal than the minimum supported.
*
* Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aInterval The wake-up listen interval in microseconds.
* @param[in] aDuration The wake-up listen duration in microseconds.
*
* @retval OT_ERROR_NONE Successfully set the wake-up listen parameters.
* @retval OT_ERROR_INVALID_ARGS Invalid wake-up listen parameters.
*/
otError otLinkSetWakeupListenParameters(otInstance *aInstance, uint32_t aInterval, uint32_t aDuration);
/**
* @}
*/
+52 -5
View File
@@ -133,7 +133,7 @@ Done
- [vendor](#vendor-name)
- [verhoeff](#verhoeff-calculate)
- [version](#version)
- [wakeupchannel](#wakeupchannel)
- [wakeup](#wakeup-channel)
## OpenThread Command Details
@@ -4402,25 +4402,72 @@ Factory Diagnostics module is enabled only when building OpenThread with `OPENTH
[diag]: ../../src/core/diags/README.md
### wakeupchannel
### wakeup channel
Get the wake-up channel.
Requires `OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE` or `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
```bash
> wakeupchannel
> wakeup channel
12
Done
```
### wakeupchannel \<channel\>
### wakeup channel \<channel\>
Set the wake-up channel.
Requires `OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE` or `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
```bash
> wakeupchannel 12
> wakeup channel 12
Done
```
### wakeup parameters
Get the wake-up listen interval and duration.
Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
```bash
> wakeup parameters
interval: 1000000us
duration: 8000us
Done
```
### wakeup parameters \<interval\> \<duration\>
Set the wake-up listen interval and duration.
Requires `OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE`.
```bash
> wakeup parameters 1000000 8000
Done
```
### wakeup listen
Show the state of wake-up listening feature.
`OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE` is required.
```bash
> wakeup listen
Enabled
Done
```
### wakeup listen \[enable|disable\]
Enable/disable listening for wake-up frames.
`OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE` is required.
```bash
> wakeup listen enable
Done
```
+101 -18
View File
@@ -8213,25 +8213,103 @@ exit:
#endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_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<Cmd("wakeupchannel")>(Arg aArgs[])
template <> otError Interpreter::Process<Cmd("wakeup")>(Arg aArgs[])
{
return ProcessGetSet(aArgs, otLinkGetWakeupChannel, otLinkSetWakeupChannel);
otError error = OT_ERROR_NONE;
/**
* @cli wakeup channel (get,set)
* @code
* wakeup channel
* 12
* Done
* @endcode
* @code
* wakeup channel 12
* Done
* @endcode
* @cparam wakeup channel [@ca{channel}]
* Use `channel` to set the wake-up channel.
* @par
* Gets or sets the wake-up channel value.
* @sa otLinkGetWakeupChannel
* @sa otLinkSetWakeupChannel
*/
if (aArgs[0] == "channel")
{
error = ProcessGetSet(aArgs + 1, otLinkGetWakeupChannel, otLinkSetWakeupChannel);
}
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* @cli wakeup parameters (get,set)
* @code
* wakeup parameters
* interval: 1000000us
* duration: 8000us
* Done
* @endcode
* @code
* wakeup parameters 1000000 8000
* Done
* @endcode
* @cparam wakeup parameters @ca{interval} @ca{duration}
* @par
* Gets or sets the wake-up listen interval and wake-up listen duration values.
* @sa otLinkGetWakeUpListenParameters
* @sa otLinkSetWakeUpListenParameters
*/
else if (aArgs[0] == "parameters")
{
uint32_t interval;
uint32_t duration;
if (aArgs[1].IsEmpty())
{
otLinkGetWakeupListenParameters(GetInstancePtr(), &interval, &duration);
OutputLine("interval: %luus", ToUlong(interval));
OutputLine("duration: %luus", ToUlong(duration));
}
else
{
SuccessOrExit(error = aArgs[1].ParseAsUint32(interval));
SuccessOrExit(error = aArgs[2].ParseAsUint32(duration));
error = otLinkSetWakeupListenParameters(GetInstancePtr(), interval, duration);
}
}
/**
* @cli wakeup listen (enable,disable)
* @code
* wakeup listen
* disabled
* Done
* @endcode
* @code
* wakeup listen enable
* Done
* @endcode
* @code
* wakeup listen
* enabled
* Done
* @endcode
* @cparam wakeup listen @ca{enable}
* @par
* Gets or sets current wake-up listening link state.
* @sa otLinkIsWakeupListenEnabled
* @sa otLinkSetWakeUpListenEnabled
*/
else if (aArgs[0] == "listen")
{
error = ProcessEnableDisable(aArgs + 1, otLinkIsWakeupListenEnabled, otLinkSetWakeUpListenEnabled);
}
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
@@ -8544,6 +8622,11 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
#endif
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
CmdEntry("version"),
#if OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
CmdEntry("wakeup"),
#endif
#endif
};
#undef CmdEntry
+3
View File
@@ -508,6 +508,7 @@ openthread_core_files = [
"mac/sub_mac.hpp",
"mac/sub_mac_callbacks.cpp",
"mac/sub_mac_csl_receiver.cpp",
"mac/sub_mac_wed.cpp",
"meshcop/announce_begin_client.cpp",
"meshcop/announce_begin_client.hpp",
"meshcop/border_agent.cpp",
@@ -777,6 +778,8 @@ openthread_radio_sources = [
"mac/mac_types.cpp",
"mac/sub_mac.cpp",
"mac/sub_mac_callbacks.cpp",
"mac/sub_mac_csl_receiver.cpp",
"mac/sub_mac_wed.cpp",
"radio/radio.cpp",
"radio/radio_callbacks.cpp",
"radio/radio_platform.cpp",
+2
View File
@@ -146,6 +146,7 @@ set(COMMON_SOURCES
mac/sub_mac.cpp
mac/sub_mac_callbacks.cpp
mac/sub_mac_csl_receiver.cpp
mac/sub_mac_wed.cpp
meshcop/announce_begin_client.cpp
meshcop/border_agent.cpp
meshcop/commissioner.cpp
@@ -295,6 +296,7 @@ set(RADIO_COMMON_SOURCES
mac/sub_mac.cpp
mac/sub_mac_callbacks.cpp
mac/sub_mac_csl_receiver.cpp
mac/sub_mac_wed.cpp
radio/radio.cpp
radio/radio_callbacks.cpp
radio/radio_platform.cpp
+22
View File
@@ -504,3 +504,25 @@ otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
return error;
}
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
otError otLinkSetWakeUpListenEnabled(otInstance *aInstance, bool aEnable)
{
return AsCoreType(aInstance).Get<Mac::Mac>().SetWakeupListenEnabled(aEnable);
}
bool otLinkIsWakeupListenEnabled(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mac::Mac>().IsWakeupListenEnabled();
}
void otLinkGetWakeupListenParameters(otInstance *aInstance, uint32_t *aInterval, uint32_t *aDuration)
{
AsCoreType(aInstance).Get<Mac::Mac>().GetWakeupListenParameters(*aInterval, *aDuration);
}
otError otLinkSetWakeupListenParameters(otInstance *aInstance, uint32_t aInterval, uint32_t aDuration)
{
return AsCoreType(aInstance).Get<Mac::Mac>().SetWakeupListenParameters(aInterval, aDuration);
}
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
+28
View File
@@ -63,6 +63,34 @@
#define OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL
*
* The default wake-up listen interval in microseconds.
*/
#ifndef OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL
#define OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL 1000000
#endif
/**
* @def OPENTHREAD_CONFIG_WED_LISTEN_DURATION
*
* The default wake-up listen duration in microseconds.
*/
#ifndef OPENTHREAD_CONFIG_WED_LISTEN_DURATION
#define OPENTHREAD_CONFIG_WED_LISTEN_DURATION 8000
#endif
/**
* @def OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER
*
* Margin to be applied after the end of a wake-up listen duration to schedule the next listen interval, in units of
* microseconds.
*/
#ifndef OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER
#define OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER 500
#endif
/**
* @}
*/
+154 -2
View File
@@ -59,6 +59,9 @@ Mac::Mac(Instance &aInstance)
#if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
, mShouldDelaySleep(false)
, mDelayingSleep(false)
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
, mWakeupListenEnabled(false)
#endif
, mOperation(kOperationIdle)
, mPendingOperations(0)
@@ -83,6 +86,10 @@ Mac::Mac(Instance &aInstance)
, mCslPeriod(0)
#endif
, mWakeupChannel(OPENTHREAD_CONFIG_DEFAULT_WAKEUP_CHANNEL)
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
, mWakeupListenInterval(kDefaultWedListenInterval)
, mWakeupListenDuration(kDefaultWedListenDuration)
#endif
, mActiveScanHandler(nullptr) // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union
, mScanHandlerContext(nullptr)
, mLinks(aInstance)
@@ -1590,8 +1597,27 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig
break;
case Frame::kKeyIdMode2:
macKey = &mMode2KeyMaterial;
extAddress = &AsCoreType(&sMode2ExtAddress);
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
if (aFrame.IsWakeupFrame())
{
uint32_t sequence;
// TODO: Avoid generating a new key if a wake-up frame was recently received already
IgnoreError(aFrame.GetKeyId(keyid));
sequence = BigEndian::ReadUint32(aFrame.GetKeySource());
VerifyOrExit(((sequence & 0x7f) + 1) == keyid, error = kErrorSecurity);
macKey = (sequence == keyManager.GetCurrentKeySequence()) ? mLinks.GetCurrentMacKey(aFrame)
: &keyManager.GetTemporaryMacKey(sequence);
extAddress = &aSrcAddr.GetExtended();
}
else
#endif
{
macKey = &mMode2KeyMaterial;
extAddress = &AsCoreType(&sMode2ExtAddress);
}
break;
default:
@@ -1973,6 +1999,12 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError)
mCounters.mRxData++;
break;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
case Frame::kTypeMultipurpose:
SuccessOrExit(error = HandleWakeupFrame(*aFrame));
OT_FALL_THROUGH;
#endif
default:
mCounters.mRxOther++;
ExitNow();
@@ -2317,6 +2349,14 @@ void Mac::SetCslChannel(uint8_t aChannel)
void Mac::SetCslPeriod(uint16_t aPeriod)
{
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
if (IsWakeupListenEnabled() && aPeriod != 0)
{
IgnoreError(SetWakeupListenEnabled(false));
LogWarn("Disabling wake-up frame listening due to CSL period change");
}
#endif
mCslPeriod = aPeriod;
UpdateCsl();
}
@@ -2417,10 +2457,122 @@ Error Mac::SetWakeupChannel(uint8_t aChannel)
VerifyOrExit(mSupportedChannelMask.ContainsChannel(aChannel), error = kErrorInvalidArgs);
mWakeupChannel = aChannel;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
UpdateWakeupListening();
#endif
exit:
return error;
}
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
void Mac::GetWakeupListenParameters(uint32_t &aInterval, uint32_t &aDuration) const
{
aInterval = mWakeupListenInterval;
aDuration = mWakeupListenDuration;
}
Error Mac::SetWakeupListenParameters(uint32_t aInterval, uint32_t aDuration)
{
Error error = kErrorNone;
VerifyOrExit(aDuration >= kMinWakeupListenDuration, error = kErrorInvalidArgs);
VerifyOrExit(aInterval > aDuration, error = kErrorInvalidArgs);
mWakeupListenInterval = aInterval;
mWakeupListenDuration = aDuration;
UpdateWakeupListening();
exit:
return error;
}
Error Mac::SetWakeupListenEnabled(bool aEnable)
{
Error error = kErrorNone;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (aEnable && GetCslPeriod() > 0)
{
LogWarn("Cannot enable wake-up frame listening while CSL is enabled");
ExitNow(error = kErrorInvalidState);
}
#endif
if (aEnable == mWakeupListenEnabled)
{
LogInfo("Listening for wake up frames was already %s", aEnable ? "started" : "stopped");
ExitNow();
}
mWakeupListenEnabled = aEnable;
UpdateWakeupListening();
LogInfo("Listening for wake up frames %s: chan:%u, addr:%s", aEnable ? "started" : "stopped", mWakeupChannel,
GetExtAddress().ToString().AsCString());
exit:
return error;
}
void Mac::UpdateWakeupListening(void)
{
uint8_t channel = mWakeupChannel ? mWakeupChannel : mPanChannel;
mLinks.UpdateWakeupListening(mWakeupListenEnabled, mWakeupListenInterval, mWakeupListenDuration, channel);
}
Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
{
Error error = kErrorNone;
const ConnectionIe *connectionIe;
uint32_t rvTimeUs;
uint64_t rvTimestampUs;
uint32_t attachDelayMs;
uint64_t radioNowUs;
uint8_t retryInterval;
uint8_t retryCount;
VerifyOrExit(mWakeupListenEnabled && aFrame.IsWakeupFrame());
connectionIe = aFrame.GetConnectionIe();
retryInterval = connectionIe->GetRetryInterval();
retryCount = connectionIe->GetRetryCount();
VerifyOrExit(retryInterval > 0 && retryCount > 0, error = kErrorInvalidArgs);
radioNowUs = otPlatRadioGetNow(&GetInstance());
rvTimeUs = aFrame.GetRendezvousTimeIe()->GetRendezvousTime() * kUsPerTenSymbols;
rvTimestampUs = aFrame.GetTimestamp() + kRadioHeaderPhrDuration + aFrame.GetLength() * kOctetDuration + rvTimeUs;
if (rvTimestampUs > radioNowUs + OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US)
{
attachDelayMs = static_cast<uint32_t>(rvTimestampUs - radioNowUs - OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US);
attachDelayMs = attachDelayMs / 1000;
}
else
{
attachDelayMs = 0;
}
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
{
uint32_t frameCounter;
IgnoreError(aFrame.GetFrameCounter(frameCounter));
LogInfo("Received wake-up frame, fc:%lu, rendezvous:%luus, retries:%u/%u", ToUlong(frameCounter),
ToUlong(rvTimeUs), retryCount, retryInterval);
}
#endif
// Stop receiving more wake up frames
IgnoreError(SetWakeupListenEnabled(false));
// TODO: start MLE attach process with the WC
OT_UNUSED_VARIABLE(attachDelayMs);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
} // namespace Mac
} // namespace ot
+61 -5
View File
@@ -89,6 +89,9 @@ constexpr uint8_t kTxNumBcast = OPENTHREAD_CONFIG_MAC_TX_NUM_BCAST; ///< Num of
constexpr uint16_t kMinCslIePeriod = OPENTHREAD_CONFIG_MAC_CSL_MIN_PERIOD;
constexpr uint32_t kDefaultWedListenInterval = OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL;
constexpr uint32_t kDefaultWedListenDuration = OPENTHREAD_CONFIG_WED_LISTEN_DURATION;
/**
* Defines the function pointer called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
*/
@@ -681,17 +684,17 @@ public:
Error GetRegion(uint16_t &aRegionCode) const;
/**
* Gets the Wake-up channel.
* Gets the wake-up channel.
*
* @returns Wake-up channel.
* @returns wake-up channel.
*/
uint8_t GetWakeupChannel(void) const { return mWakeupChannel; }
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Sets the Wake-up channel.
* Sets the wake-up channel.
*
* @param[in] aChannel The Wake-up channel.
* @param[in] aChannel The wake-up channel.
*
* @retval kErrorNone Successfully set the wake-up channel.
* @retval kErrorInvalidArgs The @p aChannel is not in the supported channel mask.
@@ -699,6 +702,49 @@ public:
Error SetWakeupChannel(uint8_t aChannel);
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Gets the wake-up listen parameters.
*
* @param[out] aInterval A reference to return the wake-up listen interval in microseconds.
* @param[out] aDuration A reference to return the wake-up listen duration in microseconds.
*/
void GetWakeupListenParameters(uint32_t &aInterval, uint32_t &aDuration) const;
/**
* Sets the wake-up listen parameters.
*
* The listen interval must be greater than the listen duration.
* The listen duration must be greater or equal than `kMinWakeupListenDuration`.
*
* @param[in] aInterval The wake-up listen interval in microseconds.
* @param[in] aDuration The wake-up listen duration in microseconds.
*
* @retval kErrorNone Successfully set the wake-up listen parameters.
* @retval kErrorInvalidArgs Configured listen interval is not greater than listen duration.
*/
Error SetWakeupListenParameters(uint32_t aInterval, uint32_t aDuration);
/**
* Enables/disables listening for wake-up frames.
*
* @param[in] aEnable TRUE to enable listening for wake-up frames, FALSE otherwise
*
* @retval kErrorNone Successfully enabled/disabled listening for wake-up frames.
* @retval kErrorInvalidArgs Configured listen interval is not greater than listen duration.
* @retval kErrorInvalidState Could not enable/disable listening for wake-up frames.
*/
Error SetWakeupListenEnabled(bool aEnable);
/**
* Returns whether listening for wake-up frames is enabled.
*
* @retval TRUE If listening for wake-up frames is enabled.
* @retval FALSE If listening for wake-up frames is not enabled.
*/
bool IsWakeupListenEnabled(void) const { return mWakeupListenEnabled; }
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
private:
static constexpr uint16_t kMaxCcaSampleCount = OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW;
@@ -786,6 +832,10 @@ private:
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor);
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
Error HandleWakeupFrame(const RxFrame &aFrame);
void UpdateWakeupListening(void);
#endif
static const char *OperationToString(Operation aOperation);
@@ -803,6 +853,9 @@ private:
#if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
bool mShouldDelaySleep : 1;
bool mDelayingSleep : 1;
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
bool mWakeupListenEnabled : 1;
#endif
Operation mOperation;
uint16_t mPendingOperations;
@@ -829,7 +882,10 @@ private:
uint16_t mCslPeriod;
#endif
uint8_t mWakeupChannel;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint32_t mWakeupListenInterval;
uint32_t mWakeupListenDuration;
#endif
union
{
ActiveScanHandler mActiveScanHandler;
+21
View File
@@ -473,6 +473,27 @@ public:
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Configures wake-up listening parameters in all radios.
*
* @param[in] aEnable Whether to enable or disable wake-up listening.
* @param[in] aInterval The wake-up listen interval in microseconds.
* @param[in] aDuration The wake-up listen duration in microseconds.
* @param[in] aChannel The wake-up channel.
*/
void UpdateWakeupListening(bool aEnable, uint32_t aInterval, uint32_t aDuration, uint8_t aChannel)
{
OT_UNUSED_VARIABLE(aEnable);
OT_UNUSED_VARIABLE(aInterval);
OT_UNUSED_VARIABLE(aDuration);
OT_UNUSED_VARIABLE(aChannel);
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
mSubMac.UpdateWakeupListening(aEnable, aInterval, aDuration, aChannel);
#endif
}
#endif
/**
* Transitions all radio links to Receive.
*
+9
View File
@@ -53,6 +53,9 @@ SubMac::SubMac(Instance &aInstance)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
, mCslTimer(aInstance, SubMac::HandleCslTimer)
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
, mWedTimer(aInstance, SubMac::HandleWedTimer)
#endif
{
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
mCslParentAccuracy.Init();
@@ -90,6 +93,9 @@ void SubMac::Init(void)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
CslInit();
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
WedInit();
#endif
}
otRadioCaps SubMac::GetCaps(void) const
@@ -203,6 +209,9 @@ Error SubMac::Disable(void)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
mCslTimer.Stop();
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
mWedTimer.Stop();
#endif
mTimer.Stop();
SuccessOrExit(error = Get<Radio>().Sleep());
+34 -2
View File
@@ -480,6 +480,18 @@ public:
bool IsRadioFilterEnabled(void) const { return mRadioFilterEnabled; }
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Configures wake-up listening parameters in all radios.
*
* @param[in] aEnable Whether to enable or disable wake-up listening.
* @param[in] aInterval The wake-up listen interval in microseconds.
* @param[in] aDuration The wake-up listen duration in microseconds.
* @param[in] aChannel The wake-up channel.
*/
void UpdateWakeupListening(bool aEnable, uint32_t aInterval, uint32_t aDuration, uint8_t aChannel);
#endif
private:
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
void CslInit(void);
@@ -492,6 +504,11 @@ private:
#if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
void LogReceived(RxFrame *aFrame);
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
void WedInit(void);
static void HandleWedTimer(Timer &aTimer);
void HandleWedTimer(void);
#endif
static constexpr uint8_t kCsmaMinBe = 3; // macMinBE (IEEE 802.15.4-2006).
@@ -530,16 +547,22 @@ private:
#endif
};
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
// Radio on times needed before and after MHR time for proper frame detection
static constexpr uint32_t kMinReceiveOnAhead = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AHEAD;
static constexpr uint32_t kMinReceiveOnAfter = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AFTER;
// CSL receivers would wake up `kCslReceiveTimeAhead` earlier
// CSL/wake-up listening receivers would wake up `kCslReceiveTimeAhead` earlier
// than expected sample window. The value is in usec.
static constexpr uint32_t kCslReceiveTimeAhead = OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD;
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
// Margin to be applied after the end of a wake-up listen duration to schedule the next listen interval.
// The value is in usec.
static constexpr uint32_t kWedReceiveTimeAfter = OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER;
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
// CSL transmitter would schedule delayed transmission `kCslTransmitTimeAhead` earlier
// than expected delayed transmit time. The value is in usec.
@@ -635,6 +658,15 @@ private:
CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty).
TimerMicro mCslTimer;
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint32_t mWakeupListenInterval; // The wake-up listen interval, in microseconds.
uint32_t mWakeupListenDuration; // The wake-up listen duration, in microseconds.
uint8_t mWakeupChannel; // The wake-up sample channel.
TimeMicro mWedSampleTime; // The WED sample time of the current interval in local time.
uint64_t mWedSampleTimeRadio; // The WED sample time of the current interval in radio time.
TimerMicro mWedTimer;
#endif
};
/**
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the Wake-up End Device of the subset of IEEE 802.15.4 MAC primitives.
*/
#include "sub_mac.hpp"
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
#include "instance/instance.hpp"
namespace ot {
namespace Mac {
RegisterLogModule("SubMac");
void SubMac::WedInit(void)
{
mWakeupListenInterval = 0;
mWedTimer.Stop();
}
void SubMac::UpdateWakeupListening(bool aEnable, uint32_t aInterval, uint32_t aDuration, uint8_t aChannel)
{
VerifyOrExit(RadioSupportsReceiveTiming());
mWakeupListenInterval = aInterval;
mWakeupListenDuration = aDuration;
mWakeupChannel = aChannel;
mWedTimer.Stop();
if (aEnable)
{
mWedSampleTime = TimerMicro::GetNow() + kCslReceiveTimeAhead - mWakeupListenInterval;
mWedSampleTimeRadio = Get<Radio>().GetNow() + kCslReceiveTimeAhead - mWakeupListenInterval;
HandleWedTimer();
}
exit:
return;
}
void SubMac::HandleWedTimer(Timer &aTimer) { aTimer.Get<SubMac>().HandleWedTimer(); }
void SubMac::HandleWedTimer(void)
{
mWedSampleTime += mWakeupListenInterval;
mWedSampleTimeRadio += mWakeupListenInterval;
mWedTimer.FireAt(mWedSampleTime + mWakeupListenDuration + kWedReceiveTimeAfter);
if (mState != kStateDisabled)
{
IgnoreError(
Get<Radio>().ReceiveAt(mWakeupChannel, static_cast<uint32_t>(mWedSampleTimeRadio), mWakeupListenDuration));
}
}
} // namespace Mac
} // namespace ot
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
+30 -16
View File
@@ -51,6 +51,7 @@ namespace ot {
static constexpr uint32_t kUsPerTenSymbols = OT_US_PER_TEN_SYMBOLS; ///< Time for 10 symbols in units of microseconds
static constexpr uint32_t kRadioHeaderShrDuration = 160; ///< Duration of SHR in us
static constexpr uint32_t kRadioHeaderPhrDuration = 32; ///< Duration of PHR in us
static constexpr uint32_t kOctetDuration = 32; ///< Duration of one octet in us
static constexpr int8_t kRadioPowerInvalid = OT_RADIO_POWER_INVALID; ///< Invalid TX power value
@@ -62,6 +63,13 @@ static constexpr uint64_t kMinCslPeriod = OPENTHREAD_CONFIG_MAC_CSL_MIN_PERIOD
static constexpr uint64_t kMaxCslTimeout = OPENTHREAD_CONFIG_MAC_CSL_MAX_TIMEOUT;
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Minimum wake-up listen duration supported in microseconds.
*/
static constexpr uint32_t kMinWakeupListenDuration = 100;
#endif
/**
* @addtogroup core-radio
*
@@ -473,14 +481,7 @@ public:
*/
Error Receive(uint8_t aChannel);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
* Updates the CSL sample time in radio.
*
* @param[in] aCslSampleTime The CSL sample time.
*/
void UpdateCslSampleTime(uint32_t aCslSampleTime);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Schedules a radio reception window at a specific time and duration.
*
@@ -492,6 +493,15 @@ public:
* @retval kErrorFailed The receive window could not be scheduled.
*/
Error ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
* Updates the CSL sample time in radio.
*
* @param[in] aCslSampleTime The CSL sample time.
*/
void UpdateCslSampleTime(uint32_t aCslSampleTime);
/**
* Enables CSL sampling in radio.
@@ -902,12 +912,7 @@ inline Error Radio::Receive(uint8_t aChannel)
return otPlatRadioReceive(GetInstancePtr(), aChannel);
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime)
{
otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime);
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
{
Error error = otPlatRadioReceiveAt(GetInstancePtr(), aChannel, aStart, aDuration);
@@ -919,6 +924,13 @@ inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDurat
#endif
return error;
}
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime)
{
otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime);
}
inline Error Radio::EnableCsl(uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr)
{
@@ -1023,11 +1035,13 @@ inline Error Radio::Sleep(void) { return kErrorNone; }
inline Error Radio::Receive(uint8_t) { return kErrorNone; }
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) { return kErrorNone; }
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
inline void Radio::UpdateCslSampleTime(uint32_t) {}
inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) { return kErrorNone; }
inline Error Radio::EnableCsl(uint32_t, otShortAddress aShortAddr, const otExtAddress *)
{
return kErrorNotImplemented;
+12
View File
@@ -400,6 +400,18 @@ const Mle::KeyMaterial &KeyManager::GetTemporaryMleKey(uint32_t aKeySequence)
return mTemporaryMleKey;
}
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
const Mle::KeyMaterial &KeyManager::GetTemporaryMacKey(uint32_t aKeySequence)
{
HashKeys hashKeys;
ComputeKeys(aKeySequence, hashKeys);
mTemporaryMacKey.SetFrom(hashKeys.GetMacKey());
return mTemporaryMacKey;
}
#endif
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
const Mac::KeyMaterial &KeyManager::GetTemporaryTrelMacKey(uint32_t aKeySequence)
{
+13
View File
@@ -358,6 +358,15 @@ public:
*/
const Mle::KeyMaterial &GetTemporaryMleKey(uint32_t aKeySequence);
/**
* Returns a temporary MAC key Material computed from the given key sequence.
*
* @param[in] aKeySequence The key sequence value.
*
* @returns The temporary MAC key.
*/
const Mle::KeyMaterial &GetTemporaryMacKey(uint32_t aKeySequence);
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
/**
* Returns the current MAC Frame Counter value for 15.4 radio link.
@@ -598,6 +607,10 @@ private:
Mle::KeyMaterial mMleKey;
Mle::KeyMaterial mTemporaryMleKey;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
Mle::KeyMaterial mTemporaryMacKey;
#endif
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
Mac::KeyMaterial mTrelKey;
Mac::KeyMaterial mTemporaryTrelKey;
-1
View File
@@ -98,7 +98,6 @@ public:
/**
* Sets the local socket address to RLOC address and the peer socket address to leader RLOC.
q *
*/
void SetSockAddrToRlocPeerAddrToLeaderRloc(void);