[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).
This commit is contained in:
Abtin Keshavarzian
2025-03-10 17:17:12 -07:00
committed by GitHub
parent 255db173b7
commit 7d488bcf24
2 changed files with 33 additions and 26 deletions
+9 -8
View File
@@ -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
+24 -18
View File
@@ -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<uint32_t>(Get<Radio>().GetNow()));
mIsCslSampling = false;
mCslSampleTimeRadio = static_cast<uint32_t>(Get<Radio>().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<Radio>().UpdateCslSampleTime(mCslSampleTime.GetValue());
mCslSampleTimeRadio += periodUs;
mCslSampleTimeLocal += periodUs;
Get<Radio>().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<Radio>().UpdateCslSampleTime(mCslSampleTime.GetValue());
mCslSampleTimeRadio += periodUs;
mCslSampleTimeLocal += periodUs;
Get<Radio>().UpdateCslSampleTime(mCslSampleTimeRadio);
if (mState == kStateCslSample)
{
IgnoreError(Get<Radio>().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<uint32_t>(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.