diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index a17ee5d81..a20eb9059 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -51,6 +51,9 @@ SubMac::SubMac(Instance &aInstance) , mRadioCaps(Get().GetCaps()) , mTransmitFrame(Get().GetTransmitBuffer()) , mCallbacks(aInstance) +#if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + , mListenScheduler(aInstance) +#endif , mTimer(aInstance) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE , mCslReceiver(aInstance) @@ -89,6 +92,7 @@ void SubMac::Init(void) #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE mActiveTimedRx.Clear(); mPendingTimedRx.Clear(); + mListenScheduler.Stop(); #endif #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -212,6 +216,10 @@ Error SubMac::Enable(void) SetState(kStateSleep); +#if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + mListenScheduler.Start(); +#endif + exit: SuccessOrAssert(error); return error; @@ -224,10 +232,7 @@ Error SubMac::Disable(void) #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE mActiveTimedRx.Clear(); mPendingTimedRx.Clear(); -#endif - -#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - mCslReceiver.Stop(); + mListenScheduler.Stop(); #endif mTimer.Stop(); @@ -847,9 +852,16 @@ void SubMac::HandleEnergyScanDone(int8_t aMaxRssi) #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE void SubMac::ReceiveAt(Radio::Time64 aStartTime, uint32_t aDuration, uint8_t aChannel) +{ + TimedRx timedRx; + + timedRx.Init(aStartTime, aDuration, aChannel); + ReceiveAt(timedRx); +} + +void SubMac::ReceiveAt(const TimedRx &aTimedRx) { Radio::SyncedTime now; - TimedRx timedRx; VerifyOrExit(mState != kStateDisabled); @@ -860,18 +872,29 @@ void SubMac::ReceiveAt(Radio::Time64 aStartTime, uint32_t aDuration, uint8_t aCh } #endif - timedRx.Init(aStartTime, aDuration, aChannel); + if (!aTimedRx.IsSpecified()) + { + CancelPendingReceiveAt(); + ExitNow(); + } now.SetToNow(Get()); - VerifyOrExit(!timedRx.HasEnded(now)); + VerifyOrExit(!aTimedRx.HasEnded(now)); if (!ShouldHandle(kCapReceiveTiming)) { - timedRx.ScheduleOnRadio(Get()); + aTimedRx.ScheduleOnRadio(Get()); ExitNow(); } + VerifyOrExit(mPendingTimedRx != aTimedRx); + + if (!mPendingTimedRx.IsSpecified()) + { + VerifyOrExit(aTimedRx != mActiveTimedRx); + } + if (mPendingTimedRx.IsSpecified() && mPendingTimedRx.HasStarted(now) && !mPendingTimedRx.HasEnded(now)) { // Before replacing `mPendingTimedRx` check if the existing one @@ -891,7 +914,7 @@ void SubMac::ReceiveAt(Radio::Time64 aStartTime, uint32_t aDuration, uint8_t aCh } } - mPendingTimedRx = timedRx; + mPendingTimedRx = aTimedRx; switch (mState) { @@ -948,20 +971,15 @@ void SubMac::ProcessTimedRx(void) // timed RX, scheduling the timer for upcoming windows, or putting // the radio to sleep when active reception window ends. - Radio::Time64 fireTime = Radio::kMaxTime64; - Radio::SyncedTime now; - - mTimer.Stop(); - - now.SetToNow(Get()); + NextRadioFireTime nextFireTime(GetInstance()); // Start pending `TimedRx` if due, or clear it if missed. if (mPendingTimedRx.IsSpecified()) { - if (mPendingTimedRx.HasStarted(now)) + if (mPendingTimedRx.HasStarted(nextFireTime.GetNow())) { - if (!mPendingTimedRx.HasEnded(now)) + if (!mPendingTimedRx.HasEnded(nextFireTime.GetNow())) { StartPendingTimedRx(); } @@ -970,13 +988,13 @@ void SubMac::ProcessTimedRx(void) } else { - fireTime = mPendingTimedRx.GetStartTime(); + nextFireTime.UpdateIfEarlier(mPendingTimedRx.GetStartTime()); } } VerifyOrExit(mActiveTimedRx.IsSpecified()); - if (!mActiveTimedRx.HasEnded(now)) + if (!mActiveTimedRx.HasEnded(nextFireTime.GetNow())) { if (mState != kStateTimedReceive) { @@ -984,7 +1002,7 @@ void SubMac::ProcessTimedRx(void) SetState(kStateTimedReceive); } - fireTime = Min(fireTime, mActiveTimedRx.GetEndTime()); + nextFireTime.UpdateIfEarlier(mActiveTimedRx.GetEndTime()); ExitNow(); } @@ -1005,22 +1023,7 @@ void SubMac::ProcessTimedRx(void) } exit: - - if (fireTime != Radio::kMaxTime64) - { - // Schedule the timer to fire at a target radio time `fireTime`, - // using the synced reference `now` to translate radio time to - // local time. - - uint32_t delay = 0; - - if (fireTime > now.GetAsTime64()) - { - delay = ClampToUint32(fireTime - now.GetAsTime64()); - } - - StartTimerAt(now.GetAsLocalTimeMicro(), delay); - } + nextFireTime.ScheduleTimer(mTimer); } void SubMac::TimedRx::Init(Radio::Time64 aStartTime, uint32_t aDuration, uint8_t aChannel) @@ -1038,6 +1041,17 @@ void SubMac::TimedRx::ScheduleOnRadio(Radio::Radio &aRadio) const LogWarnOnError(error, "Radio::ReceiveAt()"); } +bool SubMac::TimedRx::operator==(const TimedRx &aOther) const +{ + bool matches = false; + + VerifyOrExit(mIsSpecified && aOther.mIsSpecified); + matches = (mStartTime == aOther.mStartTime) && (mDuration == aOther.mDuration) && (mChannel == aOther.mChannel); + +exit: + return matches; +} + #endif // OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE void SubMac::HandleTimer(void) @@ -1259,5 +1273,126 @@ const char *SubMac::StateToString(State aState) // LCOV_EXCL_STOP +#if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + +//--------------------------------------------------------------------------------------------------------------------- +// NextRadioFireTime + +SubMac::NextRadioFireTime::NextRadioFireTime(Instance &aInstance) + : mFireTime(Radio::kMaxTime64) +{ + mNow.SetToNow(aInstance.Get()); +} + +void SubMac::NextRadioFireTime::ScheduleTimer(TimerMicro &aTimer) const +{ + // Schedule `aTimer` to fire at the radio time `mFireTime` + // using the synced reference `mNow` to translate radio time to + // local time. + + uint32_t delay; + + if (mFireTime == Radio::kMaxTime64) + { + aTimer.Stop(); + ExitNow(); + } + + delay = (mFireTime <= mNow.GetAsTime64()) ? 0 : ClampToUint32(mFireTime - mNow.GetAsTime64()); + + aTimer.StartAt(mNow.GetAsLocalTimeMicro(), delay); + +exit: + return; +} + +//--------------------------------------------------------------------------------------------------------------------- +// ListenScheduler + +SubMac::ListenScheduler::ListenScheduler(Instance &aInstance) + : InstanceLocator(aInstance) + , mTimer(aInstance) +{ +} + +void SubMac::ListenScheduler::Stop(void) { mTimer.Stop(); } + +void SubMac::ListenScheduler::Schedule(void) +{ + SchedInfo info(GetInstance()); + + VerifyOrExit(Get().IsEnabled()); + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + ScheduleCsl(info); +#endif + + Get().ReceiveAt(info.GetTimedRx()); + + info.ScheduleNextFireTimeOn(mTimer); + +exit: + return; +} + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +void SubMac::ListenScheduler::ScheduleCsl(SchedInfo &aInfo) +{ + CslReceiver &cslReceiver = Get().mCslReceiver; + + VerifyOrExit(cslReceiver.IsEnabled()); + + // Advance the CSL window once within `kCslTransitionToNextAheadTime` + // of the next window's start time, and set the next timer fire time + // to that transition point. Both current and next windows are then + // considered for timed RX (selecting the earliest one that has not + // yet ended). + + while (cslReceiver.GetNextWindow().GetStartTime() <= aInfo.GetNow().GetAsTime64() + kCslTransitionToNextAheadTime) + { + cslReceiver.AdvanceToNextWindow(); + } + + aInfo.UpdateNextFireTime(cslReceiver.GetNextWindow().GetStartTime() - kCslTransitionToNextAheadTime); + + aInfo.UpdateTimedRxIfEarlier(cslReceiver.GetNextWindow()); + aInfo.UpdateTimedRxIfEarlier(cslReceiver.GetCurWindow()); + +exit: + return; +} + +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +//--------------------------------------------------------------------------------------------------------------------- +// ListenScheduler::SchedInfo + +SubMac::ListenScheduler::SchedInfo::SchedInfo(Instance &aInstance) + : mNextFireTime(aInstance) +{ +} + +void SubMac::ListenScheduler::SchedInfo::UpdateTimedRxIfEarlier(const TimedRx &aTimedRx) +{ + // Updates `mTimedRx` to `aTimedRx` if `aTimedRx` is specified, has + // not yet ended, and starts earlier than the current `mTimedRx`. + + VerifyOrExit(aTimedRx.IsSpecified()); + VerifyOrExit(!aTimedRx.HasEnded(GetNow())); + + if (mTimedRx.IsSpecified()) + { + VerifyOrExit(aTimedRx.GetStartTime() < mTimedRx.GetStartTime()); + } + + mTimedRx = aTimedRx; + +exit: + return; +} + +#endif // OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + } // namespace Mac } // namespace ot diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index 395431ea4..69853f1b8 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -42,6 +42,7 @@ #include "common/callback.hpp" #include "common/clearable.hpp" +#include "common/equatable.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "common/timer.hpp" @@ -597,7 +598,27 @@ private: #endif #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE - class TimedRx : public Clearable + class NextRadioFireTime + { + // Tracks the current synced time (`mNow`) and the earliest + // upcoming target radio fire time (`Radio::Time64`). Used to + // schedule a `TimerMicro` by converting the target radio time + // to local timer time relative to `mNow`. + + public: + explicit NextRadioFireTime(Instance &aInstance); + + const Radio::SyncedTime &GetNow(void) const { return mNow; } + + void UpdateIfEarlier(Radio::Time64 aFireTime) { mFireTime = Min(mFireTime, aFireTime); } + void ScheduleTimer(TimerMicro &aTimer) const; + + private: + Radio::SyncedTime mNow; + Radio::Time64 mFireTime; + }; + + class TimedRx : public Clearable, public Unequatable { public: TimedRx(void) { Clear(); } @@ -606,10 +627,12 @@ private: bool IsSpecified(void) const { return mIsSpecified; } Radio::Time64 GetStartTime(void) const { return mStartTime; } Radio::Time64 GetEndTime(void) const { return mStartTime + mDuration; } + uint32_t GetDuration(void) const { return mDuration; } uint8_t GetChannel(void) const { return mChannel; } bool HasStarted(const Radio::SyncedTime &aNow) const { return mStartTime <= aNow.GetAsTime64(); } bool HasEnded(const Radio::SyncedTime &aNow) const { return GetEndTime() <= aNow.GetAsTime64(); } void ScheduleOnRadio(Radio::Radio &aRadio) const; + bool operator==(const TimedRx &aOther) const; private: Radio::Time64 mStartTime; @@ -617,53 +640,90 @@ private: uint8_t mChannel; bool mIsSpecified; }; -#endif + + void HandleListenSchedulerTimer(void) { mListenScheduler.HandleTimer(); } + + class ListenScheduler : public InstanceLocator + { + public: + explicit ListenScheduler(Instance &aInstance); + + void Start(void) { Schedule(); } + void Stop(void); + void HandleTimer(void) { Schedule(); } #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - void HandleCslReceiverTimer(void) { mCslReceiver.HandleTimer(); } + void UpdateOnCslChange(void) { Schedule(); } +#endif + private: + static constexpr uint32_t kCslTransitionToNextAheadTime = OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD; + + class SchedInfo + { + public: + explicit SchedInfo(Instance &aInstance); + + const Radio::SyncedTime &GetNow(void) const { return mNextFireTime.GetNow(); } + + const TimedRx &GetTimedRx(void) const { return mTimedRx; } + void UpdateTimedRxIfEarlier(const TimedRx &aTimedRx); + void UpdateNextFireTime(Radio::Time64 aTime) { mNextFireTime.UpdateIfEarlier(aTime); } + void ScheduleNextFireTimeOn(TimerMicro &aTimer) { mNextFireTime.ScheduleTimer(aTimer); } + + private: + NextRadioFireTime mNextFireTime; + TimedRx mTimedRx; + }; + + void Schedule(void); +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + void ScheduleCsl(SchedInfo &aInfo); +#endif + + using ListenTimer = TimerMicroIn; + + ListenTimer mTimer; + }; + +#endif // OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE class CslReceiver : public InstanceLocator { public: explicit CslReceiver(Instance &aInstance); void Init(void); - void Stop(void) { mTimer.Stop(); } + bool IsEnabled(void) const { return mPeriod > 0; } void SetParams(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAddr, const ExtAddress &aExtAddr); void ProcessTxDone(const TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame); void ProcessRxFrame(const RxFrame &aFrame); - void HandleTimer(void) { ScheduleSampleWindow(); } + void AdvanceToNextWindow(void); + const TimedRx &GetCurWindow(void) const { return mCurWindow; } + const TimedRx &GetNextWindow(void) const { return mNextWindow; } const CslAccuracy &GetParentAccuracy(void) const { return mParentAccuracy; } void SetParentAccuracy(const CslAccuracy &aCslAccuracy) { mParentAccuracy = aCslAccuracy; } private: static constexpr uint32_t kMinReceiveOnAhead = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AHEAD; static constexpr uint32_t kMinReceiveOnAfter = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AFTER; - static constexpr uint32_t kReceiveTimeAhead = OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD; - struct Window - { - Radio::SyncedTime mStartTime; - uint32_t mDuration; - }; - - void RestartTimerAfterSyncUpdate(void); void SetLastSyncToNow(void); - void ScheduleSampleWindow(void); - void DetermineWindow(const Radio::SyncedTime &aSampleTime, Window &aWindow) const; + void Schedule(void); + void UpdateCurAndNextWindows(void); + void DetermineWindow(const Radio::SyncedTime &aSampleTime, TimedRx &aTimedRx) const; uint32_t DetermineClockDrift(uint32_t aIntervalUs) const; - bool IsEnabled(void) const { return mPeriod > 0; } void LogReceived(const RxFrame &aFrame); - using CslTimer = TimerMicroIn; - uint16_t mPeriod; uint8_t mChannel; uint16_t mPeerShort; Radio::SyncedTime mSampleTime; CslAccuracy mParentAccuracy; - CslTimer mTimer; + TimedRx mCurWindow; + TimedRx mNextWindow; #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_LOCAL_TIME_SYNC TimeMicro mLastSync; #else @@ -674,11 +734,10 @@ private: #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE void Init(void); - + bool IsEnabled(void) const { return mState != kStateDisabled; } bool RadioSupports(Capability aCapability) const { return (mRadioCaps & aCapability) != 0; } bool ShouldHandle(Capability aCapability) const; bool ShouldHandleCsmaBackoff(void) const; - void ProcessTransmitSecurity(TxFrame::ParseInfo &aFrameInfo); void ReprocessSecurityForRetx(TxFrame::ParseInfo &aFrameInfo); void SignalFrameCounterUsed(uint32_t aFrameCounter, uint8_t aKeyIndex); @@ -688,7 +747,6 @@ private: void SampleRssi(void); void StartTimer(uint32_t aDelayUs); void StartTimerAt(Time aStartTime, uint32_t aDelayUs); - void HandleReceiveDone(RxFrame *aFrame, Error aError); void HandleTransmitStarted(TxFrame &aFrame); void HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError); @@ -697,6 +755,7 @@ private: void HandleTimer(void); #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE + void ReceiveAt(const TimedRx &aTimedRx); void StartPendingTimedRx(void); void ProcessTimedRx(void); #endif @@ -732,8 +791,9 @@ private: uint8_t mRetxDelayBackoffExponent; #endif #if OT_CONFIG_MAC_TARGET_TIME_RX_ENABLE - TimedRx mActiveTimedRx; - TimedRx mPendingTimedRx; + TimedRx mActiveTimedRx; + TimedRx mPendingTimedRx; + ListenScheduler mListenScheduler; #endif SubMacTimer mTimer; diff --git a/src/core/mac/sub_mac_csl_receiver.cpp b/src/core/mac/sub_mac_csl_receiver.cpp index ab256cea3..04962e639 100644 --- a/src/core/mac/sub_mac_csl_receiver.cpp +++ b/src/core/mac/sub_mac_csl_receiver.cpp @@ -44,7 +44,6 @@ RegisterLogModule("SubMac"); SubMac::CslReceiver::CslReceiver(Instance &aInstance) : InstanceLocator(aInstance) - , mTimer(aInstance) { Init(); } @@ -56,7 +55,8 @@ void SubMac::CslReceiver::Init(void) mPeerShort = 0; mParentAccuracy.Init(); mSampleTime.Clear(); - mTimer.Stop(); + mCurWindow.Clear(); + mNextWindow.Clear(); #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_LOCAL_TIME_SYNC mLastSync.SetValue(0); #else @@ -64,23 +64,6 @@ void SubMac::CslReceiver::Init(void) #endif } -void SubMac::CslReceiver::RestartTimerAfterSyncUpdate(void) -{ - if (mTimer.IsRunning()) - { - uint32_t periodUs = CslPeriodToUsec(mPeriod); - - mTimer.Stop(); - - // Rewind sample times by one period. `ScheduleSampleWindow()` will add - // this period back, effectively re-evaluating the current CSL period's - // schedule using the updated mLastSync. - mSampleTime -= periodUs; - - ScheduleSampleWindow(); - } -} - void SubMac::CslReceiver::ProcessTxDone(const TxFrame::ParseInfo &aFrameInfo, RxFrame *aAckFrame) { // Actual synchronization timestamp should be from the sent frame instead of the current time. @@ -92,7 +75,7 @@ void SubMac::CslReceiver::ProcessTxDone(const TxFrame::ParseInfo &aFrameInfo, Rx VerifyOrExit(aFrameInfo.Has()); SetLastSyncToNow(); - RestartTimerAfterSyncUpdate(); + Schedule(); exit: return; @@ -114,7 +97,7 @@ void SubMac::CslReceiver::ProcessRxFrame(const RxFrame &aFrame) #else mLastSync = aFrame.GetTimestamp(); #endif - RestartTimerAfterSyncUpdate(); + Schedule(); } exit: @@ -126,18 +109,23 @@ void SubMac::CslReceiver::SetParams(uint16_t aPeriod, ShortAddress aShortAddr, const ExtAddress &aExtAddr) { - mChannel = aChannel; - - VerifyOrExit((aPeriod != mPeriod) || (aShortAddr != mPeerShort)); + if ((aPeriod == mPeriod) && (aShortAddr == mPeerShort)) + { + // Handle a CSL channel change only + VerifyOrExit(mChannel != aChannel); + mChannel = aChannel; + VerifyOrExit(IsEnabled()); + Schedule(); + ExitNow(); + } + mPeriod = aPeriod; + mChannel = aChannel; mPeerShort = aShortAddr; + IgnoreError(Get().EnableCsl(aPeriod, aShortAddr, aExtAddr)); - mPeriod = aPeriod; - - mTimer.Stop(); - - if (mPeriod > 0) + if (IsEnabled()) { mSampleTime.SetToNow(Get()); @@ -146,37 +134,60 @@ void SubMac::CslReceiver::SetParams(uint16_t aPeriod, #else mLastSync = mSampleTime.GetAsTime64(); #endif - ScheduleSampleWindow(); - } - else - { - Get().CancelPendingReceiveAt(); } + Schedule(); + exit: return; } -void SubMac::CslReceiver::ScheduleSampleWindow(void) +void SubMac::CslReceiver::Schedule(void) { - Window window; - - DetermineWindow(mSampleTime, window); - Get().ReceiveAt(window.mStartTime.GetAsTime64(), window.mDuration, mChannel); - - LogDebg("CSL window start %lu, duration %lu", ToUlong(window.mStartTime.GetAsTime32()), ToUlong(window.mDuration)); - - // Advance sample time to the next CSL period, update the radio - // sample time on `Radio` and schedule the timer ahead of the - // next window's start time. - - mSampleTime += CslPeriodToUsec(mPeriod); - Get().UpdateCslSampleTime(mSampleTime.GetAsTime32()); - DetermineWindow(mSampleTime, window); - mTimer.FireAt(window.mStartTime.GetAsLocalTimeMicro() - kReceiveTimeAhead); + UpdateCurAndNextWindows(); + Get().mListenScheduler.UpdateOnCslChange(); } -void SubMac::CslReceiver::DetermineWindow(const Radio::SyncedTime &aSampleTime, Window &aWindow) const +void SubMac::CslReceiver::AdvanceToNextWindow(void) +{ + VerifyOrExit(IsEnabled()); + + mSampleTime += CslPeriodToUsec(mPeriod); + UpdateCurAndNextWindows(); + +exit: + return; +} + +void SubMac::CslReceiver::UpdateCurAndNextWindows(void) +{ + Radio::SyncedTime nextSampleTime; + + if (!IsEnabled()) + { + mCurWindow.Clear(); + mNextWindow.Clear(); + ExitNow(); + } + + DetermineWindow(mSampleTime, mCurWindow); + + nextSampleTime = mSampleTime; + nextSampleTime += CslPeriodToUsec(mPeriod); + + Get().UpdateCslSampleTime(nextSampleTime.GetAsTime32()); + + DetermineWindow(nextSampleTime, mNextWindow); + + LogDebg("CSL windows (start, dur) - cur (%lu, %lu), next (%lu, %lu)", + ToUlong(Radio::ConvertTime64To32(mCurWindow.GetStartTime())), ToUlong(mCurWindow.GetDuration()), + ToUlong(Radio::ConvertTime64To32(mNextWindow.GetStartTime())), ToUlong(mNextWindow.GetDuration())); + +exit: + return; +} + +void SubMac::CslReceiver::DetermineWindow(const Radio::SyncedTime &aSampleTime, TimedRx &aTimedRx) const { /* * CSL sample timing diagram: @@ -215,10 +226,7 @@ void SubMac::CslReceiver::DetermineWindow(const Radio::SyncedTime &aSampleTime, ahead = Min(guardInterval + kMinReceiveOnAhead, halfPeriod); after = Min(guardInterval + kMinReceiveOnAfter, halfPeriod); - aWindow.mStartTime = aSampleTime; - aWindow.mStartTime -= ahead; - - aWindow.mDuration = ahead + after; + aTimedRx.Init(aSampleTime.GetAsTime64() - ahead, ahead + after, mChannel); } uint32_t SubMac::CslReceiver::DetermineClockDrift(uint32_t aIntervalUs) const @@ -241,8 +249,6 @@ void SubMac::CslReceiver::SetLastSyncToNow(void) void SubMac::CslReceiver::LogReceived(const RxFrame &aFrame) { RxFrame::ParseInfo frameInfo; - Radio::SyncedTime sampleTime; - Window window; uint32_t margin; Radio::Time64 timestamp; uint32_t deviation; @@ -258,28 +264,23 @@ void SubMac::CslReceiver::LogReceived(const RxFrame &aFrame) VerifyOrExit((Get().mState == kStateTimedReceive) || (Get().mState == kStateSleep)); - sampleTime = mSampleTime; - sampleTime -= CslPeriodToUsec(mPeriod); - - DetermineWindow(sampleTime, window); - // The `kMinReceiveOnAhead` is not considered for the margin since // it has no impact on understanding possible deviation errors // between transmitter and receiver. - margin = sampleTime.GetAsTime32() - window.mStartTime.GetAsTime32(); + margin = mSampleTime.GetAsTime32() - Radio::ConvertTime64To32(mCurWindow.GetStartTime()); margin -= Min(margin, kMinReceiveOnAhead); timestamp = aFrame.GetTimestamp() + Radio::kHeaderPhrDuration; - if (timestamp >= sampleTime.GetAsTime64()) + if (timestamp >= mSampleTime.GetAsTime64()) { - deviation = ClampToUint32(timestamp - sampleTime.GetAsTime64()); + deviation = ClampToUint32(timestamp - mSampleTime.GetAsTime64()); signChar = '+'; } else { - deviation = ClampToUint32(sampleTime.GetAsTime64() - timestamp); + deviation = ClampToUint32(mSampleTime.GetAsTime64() - timestamp); signChar = '-'; } @@ -296,7 +297,7 @@ void SubMac::CslReceiver::LogReceived(const RxFrame &aFrame) // expected sample time. This can be due to clock drift and/or // CSL Phase rounding error. - LogAt(logLevel, "Expected sample time %lu, margin ±%lu, deviation %c%lu", ToUlong(sampleTime.GetAsTime32()), + LogAt(logLevel, "Expected sample time %lu, margin ±%lu, deviation %c%lu", ToUlong(mSampleTime.GetAsTime32()), ToUlong(margin), signChar, ToUlong(deviation)); exit: