Skip to content

Commit

Permalink
[csl] refactor the csl receiver (openthread#11302)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
zhanglongxia authored Mar 4, 2025
1 parent ab7a874 commit 829f65f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 39 deletions.
3 changes: 3 additions & 0 deletions src/core/mac/sub_mac.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
112 changes: 73 additions & 39 deletions src/core/mac/sub_mac_csl_receiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,25 @@ bool SubMac::UpdateCsl(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAd
void SubMac::HandleCslTimer(Timer &aTimer) { aTimer.Get<SubMac>().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.
Expand All @@ -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<Radio>().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<Radio>().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
Expand All @@ -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
Expand All @@ -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<Radio>().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<Radio>().ReceiveAt(mCslChannel, winStart, winDuration));
}
else if (mState == kStateCslSample)
if (mState == kStateCslSample)
{
IgnoreError(Get<Radio>().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;

Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 829f65f

Please sign in to comment.