From 829f65f35bb5aad7446f4b92b37d445c1fd42238 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 4 Mar 2025 10:23:32 +0800 Subject: [PATCH] [csl] refactor the csl receiver (#11302) This commit refactors the `sub_mac_csl_receiver.cpp` to handle `ReceiveAt()` and `Sleep() or Receive()` operations in different functions to simplify the code logic. --- src/core/mac/sub_mac.hpp | 3 + src/core/mac/sub_mac_csl_receiver.cpp | 112 +++++++++++++++++--------- 2 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index b0cf1456607..2e2ee8947fd 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -513,6 +513,9 @@ class SubMac : public InstanceLocator, private NonCopyable #if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE void LogReceived(RxFrame *aFrame); #endif + void HandleCslReceiveAt(uint32_t aTimeAhead, uint32_t aTimeAfter); + void HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter); + void LogCslWindow(uint32_t aWinStart, uint32_t aWinDuration); #endif #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE void WedInit(void); diff --git a/src/core/mac/sub_mac_csl_receiver.cpp b/src/core/mac/sub_mac_csl_receiver.cpp index 1b75e3af606..f0b83659f65 100644 --- a/src/core/mac/sub_mac_csl_receiver.cpp +++ b/src/core/mac/sub_mac_csl_receiver.cpp @@ -137,18 +137,25 @@ bool SubMac::UpdateCsl(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAd void SubMac::HandleCslTimer(Timer &aTimer) { aTimer.Get().HandleCslTimer(); } void SubMac::HandleCslTimer(void) +{ + uint32_t timeAhead, timeAfter; + + GetCslWindowEdges(timeAhead, timeAfter); + + // The handler works in different ways when the radio supports receive-timing and doesn't. + if (RadioSupportsReceiveTiming()) + { + HandleCslReceiveAt(timeAhead, timeAfter); + } + else + { + HandleCslReceiveOrSleep(timeAhead, timeAfter); + } +} + +void SubMac::HandleCslReceiveAt(uint32_t aTimeAhead, uint32_t aTimeAfter) { /* - * CSL sample timing diagram - * |<---------------------------------Sample--------------------------------->|<--------Sleep--------->| - * | | | - * |<--Ahead-->|<--UnCert-->|<--Drift-->|<--Drift-->|<--UnCert-->|<--MinWin-->| | - * | | | | | | | | - * ---|-----------|------------|-----------|-----------|------------|------------|----------//------------|--- - * -timeAhead CslPhase +timeAfter -timeAhead - * - * The handler works in different ways when the radio supports receive-timing and doesn't. - * * When the radio supports receive-timing: * The handler will be called once per CSL period. When the handler is called, it will set the timer to * fire at the next CSL sample time and call `Radio::ReceiveAt` to start sampling for the current CSL period. @@ -161,7 +168,32 @@ void SubMac::HandleCslTimer(void) * ^ ^ * x-|------------|-------------------------------------x-|------------|---------------------------------------| * sample sleep sample sleep - * + */ + uint32_t periodUs = mCslPeriod * kUsPerTenSymbols; + uint32_t winStart; + uint32_t winDuration; + + mCslTimer.FireAt(mCslSampleTime - aTimeAhead + periodUs); + aTimeAhead -= kCslReceiveTimeAhead; + winStart = mCslSampleTime.GetValue() - aTimeAhead; + winDuration = aTimeAhead + aTimeAfter; + mCslSampleTime += periodUs; + + Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); + + // Schedule reception window for any state except RX - so that CSL RX Window has lower priority + // than scanning or RX after the data poll. + if ((mState != kStateDisabled) && (mState != kStateReceive)) + { + IgnoreError(Get().ReceiveAt(mCslChannel, winStart, winDuration)); + } + + LogCslWindow(winStart, winDuration); +} + +void SubMac::HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter) +{ + /* * When the radio doesn't support receive-timing: * The handler will be called twice per CSL period: at the beginning of sample and sleep. When the handler is * called, it will explicitly change the radio state due to the current state by calling `Radio::Receive` or @@ -172,15 +204,11 @@ void SubMac::HandleCslTimer(void) * |------------|---------------------------------------|------------|---------------------------------------| * sample sleep sample sleep */ - uint32_t periodUs = mCslPeriod * kUsPerTenSymbols; - uint32_t timeAhead, timeAfter, winStart, winDuration; - - GetCslWindowEdges(timeAhead, timeAfter); if (mIsCslSampling) { mIsCslSampling = false; - mCslTimer.FireAt(mCslSampleTime - timeAhead); + mCslTimer.FireAt(mCslSampleTime - aTimeAhead); if (mState == kStateCslSample) { #if !OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE @@ -191,41 +219,38 @@ void SubMac::HandleCslTimer(void) } else { - if (RadioSupportsReceiveTiming()) - { - mCslTimer.FireAt(mCslSampleTime - timeAhead + periodUs); - timeAhead -= kCslReceiveTimeAhead; - winStart = mCslSampleTime.GetValue() - timeAhead; - } - else - { - mCslTimer.FireAt(mCslSampleTime + timeAfter); - mIsCslSampling = true; - winStart = ot::TimerMicro::GetNow().GetValue(); - } - - winDuration = timeAhead + timeAfter; + uint32_t periodUs = mCslPeriod * kUsPerTenSymbols; + uint32_t winStart; + uint32_t winDuration; + + mCslTimer.FireAt(mCslSampleTime + aTimeAfter); + mIsCslSampling = true; + winStart = TimerMicro::GetNow().GetValue(); + winDuration = aTimeAhead + aTimeAfter; mCslSampleTime += periodUs; Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); - - // Schedule reception window for any state except RX - so that CSL RX Window has lower priority - // than scanning or RX after the data poll. - if (RadioSupportsReceiveTiming() && (mState != kStateDisabled) && (mState != kStateReceive)) - { - IgnoreError(Get().ReceiveAt(mCslChannel, winStart, winDuration)); - } - else if (mState == kStateCslSample) + if (mState == kStateCslSample) { IgnoreError(Get().Receive(mCslChannel)); } - LogDebg("CSL window start %lu, duration %lu", ToUlong(winStart), ToUlong(winDuration)); + LogCslWindow(winStart, winDuration); } } void SubMac::GetCslWindowEdges(uint32_t &aAhead, uint32_t &aAfter) { + /* + * CSL sample timing diagram + * |<---------------------------------Sample--------------------------------->|<--------Sleep--------->| + * | | | + * |<--Ahead-->|<--UnCert-->|<--Drift-->|<--Drift-->|<--UnCert-->|<--MinWin-->| | + * | | | | | | | | + * ---|-----------|------------|-----------|-----------|------------|------------|----------//------------|--- + * -timeAhead CslPhase +timeAfter -timeAhead + * + */ uint32_t semiPeriod = mCslPeriod * kUsPerTenSymbols / 2; uint32_t curTime, elapsed, semiWindow; @@ -254,6 +279,15 @@ uint32_t SubMac::GetLocalTime(void) return now; } +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) +void SubMac::LogCslWindow(uint32_t aWinStart, uint32_t aWinDuration) +{ + LogDebg("CSL window start %lu, duration %lu", ToUlong(aWinStart), ToUlong(aWinDuration)); +} +#else +void SubMac::LogCslWindow(uint32_t, uint32_t) {} +#endif + #if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE void SubMac::LogReceived(RxFrame *aFrame) {