mirror of
https://github.com/espressif/openthread.git
synced 2026-08-30 13:59:54 +00:00
[sub-mac] WED performs periodic sampling by calling Sleep() and Receive() (#11318)
The WED listener only supports calling the `Radio::ReceiveAt()` for periodic sampling. This commit adds support for the WED to perform periodic sampling by calling `Radio::Sleep()` and `Radio::Receive()`.
This commit is contained in:
+104
-11
@@ -240,10 +240,10 @@ Error SubMac::Sleep(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (IsCslEnabled())
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
if (IsRadioSampleEnabled())
|
||||
{
|
||||
CslSample();
|
||||
RadioSample();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -343,8 +343,8 @@ Error SubMac::Send(void)
|
||||
#endif
|
||||
case kStateSleep:
|
||||
case kStateReceive:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
case kStateCslSample:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
case kStateRadioSample:
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -721,8 +721,8 @@ Error SubMac::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
|
||||
case kStateReceive:
|
||||
case kStateSleep:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
case kStateCslSample:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
case kStateRadioSample:
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -1029,6 +1029,99 @@ void SubMac::StartTimerAt(Time aStartTime, uint32_t aDelayUs)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
void SubMac::RadioSample(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
VerifyOrExit(!mRadioFilterEnabled, IgnoreError(Get<Radio>().Sleep()));
|
||||
#endif
|
||||
|
||||
SetState(kStateRadioSample);
|
||||
|
||||
if (!RadioSupportsReceiveTiming())
|
||||
{
|
||||
UpdateRadioSampleState();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
exit:
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
bool SubMac::IsRadioSampleEnabled(void) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
ret = IsCslEnabled();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
ret = ret || mIsWedEnabled;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The radio state (receive/sleep) is determined by the request from both CSL and WED:
|
||||
* 1. If both CSL and WED request to enter sleep state, the radio is set to sleep state.
|
||||
* 2. If either CSL or WED requests to enter the receive state and the other requests to enter sleep state, the radio
|
||||
* is set to receive state using the channel that is requested to enter the receive state.
|
||||
* 3. If both CSL and WED request to enter the receive state, the radio is set to the receive state using the CSL
|
||||
* channel.
|
||||
*
|
||||
* The diagram below illustrates how to set the radio state based on the request of WED and CSL.
|
||||
*
|
||||
* CSL ------========------------========------------========------------========---
|
||||
* ^ ^
|
||||
* | |
|
||||
* | mIsCslSampling=false
|
||||
* mIsCslSampling=true
|
||||
*
|
||||
* WED -----------++++++++----------------++++++++----------------++++++++----------
|
||||
* ^ ^
|
||||
* | |
|
||||
* | mIsWedSampling=false
|
||||
* mIsWedSampling=true
|
||||
*
|
||||
* Radio ------========+++++-------========-++++++++---========-----+++++++========---
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* | | Radio::Sleep()
|
||||
* | Radio::Receive(WedCh)
|
||||
* Radio::Receive(CslCh)
|
||||
*/
|
||||
void SubMac::UpdateRadioSampleState(void)
|
||||
{
|
||||
VerifyOrExit(mState == kStateRadioSample);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (mIsCslSampling)
|
||||
{
|
||||
IgnoreError(Get<Radio>().Receive(mCslChannel));
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
if (mIsWedSampling)
|
||||
{
|
||||
IgnoreError(Get<Radio>().Receive(mWakeupChannel));
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
|
||||
IgnoreError(Get<Radio>().Sleep()); // Don't actually sleep for debugging
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
const char *SubMac::StateToString(State aState)
|
||||
@@ -1046,8 +1139,8 @@ const char *SubMac::StateToString(State aState)
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
"CslTransmit", // (7) kStateCslTransmit
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
"CslSample", // (8) kStateCslSample
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
"RadioSample", // (8) kStateRadioSample
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1067,8 +1160,8 @@ const char *SubMac::StateToString(State aState)
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
ValidateNextEnum(kStateCslTransmit);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
ValidateNextEnum(kStateCslSample);
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
ValidateNextEnum(kStateRadioSample);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -501,7 +501,6 @@ public:
|
||||
private:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
void CslInit(void);
|
||||
void CslSample(void);
|
||||
void UpdateCslLastSyncTimestamp(TxFrame &aFrame, RxFrame *aAckFrame);
|
||||
void UpdateCslLastSyncTimestamp(RxFrame *aFrame, Error aError);
|
||||
static void HandleCslTimer(Timer &aTimer);
|
||||
@@ -520,6 +519,8 @@ private:
|
||||
void WedInit(void);
|
||||
static void HandleWedTimer(Timer &aTimer);
|
||||
void HandleWedTimer(void);
|
||||
void HandleWedReceiveAt(void);
|
||||
void HandleWedReceiveOrSleep(void);
|
||||
#endif
|
||||
|
||||
static constexpr uint8_t kCsmaMinBe = 3; // macMinBE (IEEE 802.15.4-2006).
|
||||
@@ -553,8 +554,9 @@ private:
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
kStateCslTransmit, // CSL transmission.
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
kStateCslSample, // CSL receive.
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
kStateRadioSample, // Mac layer has requested the SubMac to enter sleep state, but the SubMac is in the periodic
|
||||
// sample state.
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -628,6 +630,12 @@ private:
|
||||
void SetState(State aState);
|
||||
static const char *StateToString(State aState);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
bool IsRadioSampleEnabled(void) const;
|
||||
void UpdateRadioSampleState(void);
|
||||
void RadioSample(void);
|
||||
#endif
|
||||
|
||||
using SubMacTimer =
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
||||
TimerMicroIn<SubMac, &SubMac::HandleTimer>;
|
||||
@@ -664,8 +672,8 @@ private:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
uint16_t mCslPeriod; // The CSL sample period, in units of 10 symbols (160 microseconds).
|
||||
uint8_t mCslChannel : 7; // The CSL sample channel.
|
||||
bool mIsCslSampling : 1; // Indicates that the radio is receiving in CSL state for platforms not supporting
|
||||
// delayed reception.
|
||||
bool mIsCslSampling : 1; // Indicates that the current time is in CSL sample window
|
||||
// for platforms not supporting `Radio::ReceiveAt()`.
|
||||
uint16_t mCslPeerShort; // The CSL peer short address.
|
||||
uint32_t mCslSampleTimeRadio; // The CSL sample time of the current period based on radio time (lower 32-bit).
|
||||
TimeMicro mCslSampleTimeLocal; // The CSL sample time of the current period based on local time.
|
||||
@@ -675,6 +683,9 @@ private:
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
bool mIsWedSampling : 1; // Indicates that the current time is in WED's sample window
|
||||
// for platforms not supporting `Radio::ReceiveAt()`.
|
||||
bool mIsWedEnabled : 1; // Indicates if the WED is enabled.
|
||||
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.
|
||||
|
||||
@@ -86,28 +86,6 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SubMac::CslSample(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
VerifyOrExit(!mRadioFilterEnabled, IgnoreError(Get<Radio>().Sleep()));
|
||||
#endif
|
||||
|
||||
SetState(kStateCslSample);
|
||||
|
||||
if (mIsCslSampling && !RadioSupportsReceiveTiming())
|
||||
{
|
||||
IgnoreError(Get<Radio>().Receive(mCslChannel));
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
#if !OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
|
||||
IgnoreError(Get<Radio>().Sleep()); // Don't actually sleep for debugging
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SubMac::SetCslParams(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAddr, const ExtAddress &aExtAddr)
|
||||
{
|
||||
bool diffPeriod = aPeriod != mCslPeriod;
|
||||
@@ -119,18 +97,24 @@ void SubMac::SetCslParams(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShor
|
||||
mCslChannel = aChannel;
|
||||
|
||||
VerifyOrExit(diffPeriod || diffPeer);
|
||||
mCslPeriod = aPeriod;
|
||||
mCslPeerShort = aShortAddr;
|
||||
IgnoreError(Get<Radio>().EnableCsl(aPeriod, aShortAddr, aExtAddr));
|
||||
|
||||
mIsCslSampling = false;
|
||||
mCslPeriod = aPeriod;
|
||||
|
||||
mCslTimer.Stop();
|
||||
if (mCslPeriod > 0)
|
||||
{
|
||||
mCslSampleTimeRadio = static_cast<uint32_t>(Get<Radio>().GetNow());
|
||||
mCslSampleTimeLocal = TimerMicro::GetNow();
|
||||
mIsCslSampling = false;
|
||||
|
||||
HandleCslTimer();
|
||||
}
|
||||
else if (!RadioSupportsReceiveTiming())
|
||||
{
|
||||
UpdateRadioSampleState();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -213,11 +197,8 @@ void SubMac::HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter)
|
||||
{
|
||||
mIsCslSampling = false;
|
||||
mCslTimer.FireAt(mCslSampleTimeLocal - aTimeAhead);
|
||||
if (mState == kStateCslSample)
|
||||
if (mState == kStateRadioSample)
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
|
||||
IgnoreError(Get<Radio>().Sleep()); // Don't actually sleep for debugging
|
||||
#endif
|
||||
LogDebg("CSL sleep %lu", ToUlong(mCslTimer.GetNow().GetValue()));
|
||||
}
|
||||
}
|
||||
@@ -236,13 +217,11 @@ void SubMac::HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter)
|
||||
mCslSampleTimeLocal += periodUs;
|
||||
|
||||
Get<Radio>().UpdateCslSampleTime(mCslSampleTimeRadio);
|
||||
if (mState == kStateCslSample)
|
||||
{
|
||||
IgnoreError(Get<Radio>().Receive(mCslChannel));
|
||||
}
|
||||
|
||||
LogCslWindow(winStart, winDuration);
|
||||
}
|
||||
|
||||
UpdateRadioSampleState();
|
||||
}
|
||||
|
||||
void SubMac::GetCslWindowEdges(uint32_t &aAhead, uint32_t &aAfter)
|
||||
@@ -313,7 +292,7 @@ void SubMac::LogReceived(RxFrame *aFrame)
|
||||
mIsCslSampling ? "CslSample" : "CslSleep",
|
||||
ToUlong(static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp)));
|
||||
|
||||
VerifyOrExit(mState == kStateCslSample);
|
||||
VerifyOrExit(mState == kStateRadioSample);
|
||||
|
||||
GetCslWindowEdges(ahead, after);
|
||||
ahead -= kMinReceiveOnAhead + kCslReceiveTimeAhead;
|
||||
|
||||
@@ -44,17 +44,20 @@ RegisterLogModule("SubMac");
|
||||
|
||||
void SubMac::WedInit(void)
|
||||
{
|
||||
mIsWedSampling = false;
|
||||
mIsWedEnabled = false;
|
||||
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;
|
||||
mIsWedSampling = false;
|
||||
mIsWedEnabled = aEnable;
|
||||
|
||||
mWedTimer.Stop();
|
||||
|
||||
if (aEnable)
|
||||
@@ -64,14 +67,27 @@ void SubMac::UpdateWakeupListening(bool aEnable, uint32_t aInterval, uint32_t aD
|
||||
|
||||
HandleWedTimer();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
else if (!RadioSupportsReceiveTiming())
|
||||
{
|
||||
UpdateRadioSampleState();
|
||||
}
|
||||
}
|
||||
|
||||
void SubMac::HandleWedTimer(Timer &aTimer) { aTimer.Get<SubMac>().HandleWedTimer(); }
|
||||
|
||||
void SubMac::HandleWedTimer(void)
|
||||
{
|
||||
if (RadioSupportsReceiveTiming())
|
||||
{
|
||||
HandleWedReceiveAt();
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleWedReceiveOrSleep();
|
||||
}
|
||||
}
|
||||
|
||||
void SubMac::HandleWedReceiveAt(void)
|
||||
{
|
||||
mWedSampleTime += mWakeupListenInterval;
|
||||
mWedSampleTimeRadio += mWakeupListenInterval;
|
||||
@@ -84,6 +100,26 @@ void SubMac::HandleWedTimer(void)
|
||||
}
|
||||
}
|
||||
|
||||
void SubMac::HandleWedReceiveOrSleep(void)
|
||||
{
|
||||
TimeMilli fireTime;
|
||||
|
||||
mIsWedSampling = !mIsWedSampling;
|
||||
|
||||
if (mIsWedSampling)
|
||||
{
|
||||
fireTime = mWedSampleTime + mWakeupListenDuration + kMinReceiveOnAfter;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWedSampleTime += mWakeupListenInterval;
|
||||
fireTime = mWedSampleTime - kMinReceiveOnAhead;
|
||||
}
|
||||
|
||||
mWedTimer.FireAt(fireTime);
|
||||
|
||||
UpdateRadioSampleState();
|
||||
}
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
|
||||
Reference in New Issue
Block a user