From 7d488bcf244eca8944b0f07e33a97690d5a2798e Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 10 Mar 2025 17:17:12 -0700 Subject: [PATCH] [csl] use correct time basis for CSL sample time (#11314) This commit updates how the CSL sample time is tracked in `SubMac`, ensuring that it is tracked using both radio time based on `otPlatRadioGetNow()` and the local time (`TimeMicro::GetNow()`). These two time sources may not necessarily be the same. This change addresses the issue where the same time value was used for both scheduling `mCslTimer` (which should be based on local time) and for calls to the radio APIs (which should use radio time). --- src/core/mac/sub_mac.hpp | 17 ++++++----- src/core/mac/sub_mac_csl_receiver.cpp | 42 +++++++++++++++------------ 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index 2e2ee8947..82fce50ef 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -663,14 +663,15 @@ private: SubMacTimer mTimer; #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. - uint16_t mCslPeerShort; // The CSL peer short address. - TimeMicro mCslSampleTime; // The CSL sample time of the current period relative to the local radio clock. - TimeMicro mCslLastSync; // The timestamp of the last successful CSL synchronization. - CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty). + 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. + 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. + TimeMicro mCslLastSync; // The timestamp of the last successful CSL synchronization. + CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty). TimerMicro mCslTimer; #endif diff --git a/src/core/mac/sub_mac_csl_receiver.cpp b/src/core/mac/sub_mac_csl_receiver.cpp index f0b83659f..d83e7ce09 100644 --- a/src/core/mac/sub_mac_csl_receiver.cpp +++ b/src/core/mac/sub_mac_csl_receiver.cpp @@ -44,12 +44,13 @@ RegisterLogModule("SubMac"); void SubMac::CslInit(void) { - mCslPeriod = 0; - mCslChannel = 0; - mCslPeerShort = 0; - mIsCslSampling = false; - mCslSampleTime = TimeMicro{0}; - mCslLastSync = TimeMicro{0}; + mCslPeriod = 0; + mCslChannel = 0; + mCslPeerShort = 0; + mIsCslSampling = false; + mCslSampleTimeRadio = 0; + mCslSampleTimeLocal.SetValue(0); + mCslLastSync.SetValue(0); mCslTimer.Stop(); } @@ -125,8 +126,9 @@ bool SubMac::UpdateCsl(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAd mCslTimer.Stop(); if (mCslPeriod > 0) { - mCslSampleTime = TimeMicro(static_cast(Get().GetNow())); - mIsCslSampling = false; + mCslSampleTimeRadio = static_cast(Get().GetNow()); + mCslSampleTimeLocal = TimerMicro::GetNow(); + mIsCslSampling = false; HandleCslTimer(); } @@ -173,13 +175,15 @@ void SubMac::HandleCslReceiveAt(uint32_t aTimeAhead, uint32_t aTimeAfter) uint32_t winStart; uint32_t winDuration; - mCslTimer.FireAt(mCslSampleTime - aTimeAhead + periodUs); + mCslTimer.FireAt(mCslSampleTimeLocal - aTimeAhead + periodUs); aTimeAhead -= kCslReceiveTimeAhead; - winStart = mCslSampleTime.GetValue() - aTimeAhead; + winStart = mCslSampleTimeRadio - aTimeAhead; winDuration = aTimeAhead + aTimeAfter; - mCslSampleTime += periodUs; - Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); + mCslSampleTimeRadio += periodUs; + mCslSampleTimeLocal += periodUs; + + Get().UpdateCslSampleTime(mCslSampleTimeRadio); // Schedule reception window for any state except RX - so that CSL RX Window has lower priority // than scanning or RX after the data poll. @@ -208,7 +212,7 @@ void SubMac::HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter) if (mIsCslSampling) { mIsCslSampling = false; - mCslTimer.FireAt(mCslSampleTime - aTimeAhead); + mCslTimer.FireAt(mCslSampleTimeLocal - aTimeAhead); if (mState == kStateCslSample) { #if !OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE @@ -223,13 +227,15 @@ void SubMac::HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter) uint32_t winStart; uint32_t winDuration; - mCslTimer.FireAt(mCslSampleTime + aTimeAfter); + mCslTimer.FireAt(mCslSampleTimeLocal + aTimeAfter); mIsCslSampling = true; winStart = TimerMicro::GetNow().GetValue(); winDuration = aTimeAhead + aTimeAfter; - mCslSampleTime += periodUs; - Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); + mCslSampleTimeRadio += periodUs; + mCslSampleTimeLocal += periodUs; + + Get().UpdateCslSampleTime(mCslSampleTimeRadio); if (mState == kStateCslSample) { IgnoreError(Get().Receive(mCslChannel)); @@ -312,8 +318,8 @@ void SubMac::LogReceived(RxFrame *aFrame) GetCslWindowEdges(ahead, after); ahead -= kMinReceiveOnAhead + kCslReceiveTimeAhead; - sampleTime = mCslSampleTime.GetValue() - mCslPeriod * kUsPerTenSymbols; - deviation = aFrame->mInfo.mRxInfo.mTimestamp + kRadioHeaderPhrDuration - sampleTime; + sampleTime = mCslSampleTimeRadio - mCslPeriod * kUsPerTenSymbols; + deviation = static_cast(aFrame->mInfo.mRxInfo.mTimestamp) + kRadioHeaderPhrDuration - sampleTime; // This logs three values (all in microseconds): // - Absolute sample time in which the CSL receiver expected the MHR of the received frame.