mirror of
https://github.com/espressif/openthread.git
synced 2026-09-21 00:17:37 +00:00
[sub-mac] generalize timed transmission handling and states (#13460)
This commit simplifies and generalizes target TX time handling in `SubMac`: - Encapsulates `TxDelay` and `TxDelayBaseTime` in `TxFrameProperties` behind `IsTargetTxTimeSpecified()`, `GetTargetTxTime()`, `ClearTargetTxTime()`, and `SetTargetTxTime()`, moving low-level delay accessors to private scope. - Introduces derived config `OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE` to generalize timed TX handling across CSL transmitter and Wakeup (Thread Direct). - Renames `SubMac` state `kStateCslTransmit` to `kStateTimedTransmit` and replaces `kCslTransmitTimeAhead` with `kTimedTxLeadTime`. - Updates `CslTxScheduler` and `WakeupTxScheduler` to use new methods like `SetTargetTxTime()`.
This commit is contained in:
@@ -171,8 +171,7 @@ public:
|
||||
mTxFrame802154.SetIsSecurityProcessed(false);
|
||||
mTxFrame802154.SetCsmaCaEnabled(true); // Set to true by default, only set to `false` for CSL transmission
|
||||
mTxFrame802154.SetIsHeaderUpdated(false);
|
||||
mTxFrame802154.SetTxDelay(0);
|
||||
mTxFrame802154.SetTxDelayBaseTime(0);
|
||||
mTxFrame802154.ClearTargetTxTime();
|
||||
mTxFrame802154.SetTxPower(Radio::kInvalidPower);
|
||||
mTxFrame802154.SetCslIePresent(false);
|
||||
#endif
|
||||
|
||||
+26
-33
@@ -116,7 +116,7 @@ SubMac::Capabilities SubMac::GetCaps(void) const
|
||||
#endif
|
||||
{
|
||||
caps |= (kCapAckTimeout | kCapCsmaBackoff | kCapTransmitRetries | kCapEnergyScan | kCapTransmitSec);
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
caps |= kCapTransmitTiming;
|
||||
#endif
|
||||
}
|
||||
@@ -295,8 +295,8 @@ Error SubMac::Send(void)
|
||||
{
|
||||
case kStateDisabled:
|
||||
case kStateCsmaBackoff:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case kStateCslTransmit:
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
case kStateTimedTransmit:
|
||||
#endif
|
||||
case kStateTransmit:
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
@@ -392,24 +392,19 @@ exit:
|
||||
|
||||
void SubMac::StartCsmaBackoff(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
if (mTransmitFrame.GetTxDelay() != 0 || mTransmitFrame.GetTxDelayBaseTime() != 0)
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
if (mTransmitFrame.IsTargetTxTimeSpecified())
|
||||
{
|
||||
SetState(kStateCslTransmit);
|
||||
SetState(kStateTimedTransmit);
|
||||
|
||||
if (ShouldHandleTransmitTargetTime())
|
||||
if (ShouldHandle(kCapTransmitTiming))
|
||||
{
|
||||
static constexpr uint32_t kAheadTime =
|
||||
kCcaSampleInterval + kCslTransmitTimeAhead + Radio::kHeaderShrDuration;
|
||||
Radio::Time32 txStart = mTransmitFrame.GetTargetTxTime() - kTimedTxLeadTime;
|
||||
Radio::Time32 radioNow = Get<Radio::Radio>().GetNowAsTime32();
|
||||
|
||||
Radio::Time32 radioNow = Get<Radio::Radio>().GetNowAsTime32();
|
||||
Radio::Time32 txStartTime = mTransmitFrame.GetTxDelayBaseTime();
|
||||
|
||||
txStartTime += (mTransmitFrame.GetTxDelay() - kAheadTime);
|
||||
|
||||
if (Radio::IsTimeStrictlyBefore(radioNow, txStartTime))
|
||||
if (Radio::IsTimeStrictlyBefore(radioNow, txStart))
|
||||
{
|
||||
StartTimer(txStartTime - radioNow);
|
||||
StartTimer(txStart - radioNow);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
@@ -419,7 +414,7 @@ void SubMac::StartCsmaBackoff(void)
|
||||
BeginTransmit();
|
||||
ExitNow();
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
#endif // OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
|
||||
SetState(kStateCsmaBackoff);
|
||||
|
||||
@@ -468,8 +463,8 @@ void SubMac::BeginTransmit(void)
|
||||
{
|
||||
Error error;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
VerifyOrExit(mState == kStateCsmaBackoff || mState == kStateCslTransmit);
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
VerifyOrExit(mState == kStateCsmaBackoff || mState == kStateTimedTransmit);
|
||||
#else
|
||||
VerifyOrExit(mState == kStateCsmaBackoff);
|
||||
#endif
|
||||
@@ -483,14 +478,14 @@ void SubMac::BeginTransmit(void)
|
||||
|
||||
error = Get<Radio::Radio>().Transmit(mTransmitFrame);
|
||||
|
||||
if (error == kErrorInvalidState && mTransmitFrame.GetTxDelay() > 0)
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
if (error == kErrorInvalidState && mTransmitFrame.IsTargetTxTimeSpecified())
|
||||
{
|
||||
// Platform `transmit_at` fails and we send the frame directly.
|
||||
mTransmitFrame.SetTxDelay(0);
|
||||
mTransmitFrame.SetTxDelayBaseTime(0);
|
||||
|
||||
mTransmitFrame.ClearTargetTxTime();
|
||||
error = Get<Radio::Radio>().Transmit(mTransmitFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrAssert(error);
|
||||
|
||||
@@ -714,8 +709,8 @@ Error SubMac::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
case kStateDisabled:
|
||||
case kStateCsmaBackoff:
|
||||
case kStateTransmit:
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case kStateCslTransmit:
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
case kStateTimedTransmit:
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
case kStateDelayBeforeRetx:
|
||||
@@ -796,10 +791,8 @@ void SubMac::HandleTimer(void)
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case kStateCslTransmit:
|
||||
BeginTransmit();
|
||||
break;
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
case kStateTimedTransmit:
|
||||
#endif
|
||||
case kStateCsmaBackoff:
|
||||
BeginTransmit();
|
||||
@@ -1078,7 +1071,7 @@ const char *SubMac::StateToString(State aState)
|
||||
_(kStateCsmaBackoff, "CsmaBackoff") \
|
||||
_(kStateTransmit, "Transmit") \
|
||||
_(kStateEnergyScan, "EnergyScan") \
|
||||
DelayBeforeRetxStateMapList(_) CslTxStateMapList(_) RadioSampleMapList(_)
|
||||
DelayBeforeRetxStateMapList(_) TimedTxStateMapList(_) RadioSampleMapList(_)
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
#define DelayBeforeRetxStateMapList(_) _(kStateDelayBeforeRetx, "DelayBeforeRetx")
|
||||
@@ -1086,10 +1079,10 @@ const char *SubMac::StateToString(State aState)
|
||||
#define DelayBeforeRetxStateMapList(_)
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
#define CslTxStateMapList(_) _(kStateCslTransmit, "CslTransmit")
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
#define TimedTxStateMapList(_) _(kStateTimedTransmit, "TimedTransmit")
|
||||
#else
|
||||
#define CslTxStateMapList(_)
|
||||
#define TimedTxStateMapList(_)
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
+25
-10
@@ -60,6 +60,20 @@ namespace ot {
|
||||
|
||||
namespace Mac {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Derived configs
|
||||
|
||||
#ifdef OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
#error "OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE MUST NOT be defined directly. It is derived from other configs"
|
||||
#endif
|
||||
|
||||
#define OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE \
|
||||
(OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || \
|
||||
((OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE) && OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE))
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Config validity checks
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
|
||||
#error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE."
|
||||
#endif
|
||||
@@ -81,6 +95,8 @@ namespace Mac {
|
||||
#error "OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE is required for OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE."
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
|
||||
class LinkRaw;
|
||||
#endif
|
||||
@@ -519,8 +535,7 @@ private:
|
||||
ConditionalCap(kCapTransmitRetries, OPENTHREAD_CONFIG_MAC_SOFTWARE_RETRANSMIT_ENABLE) |
|
||||
ConditionalCap(kCapCsmaBackoff, OPENTHREAD_CONFIG_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE) |
|
||||
ConditionalCap(kCapTransmitSec, OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE) |
|
||||
ConditionalCap(kCapTransmitTiming,
|
||||
OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE &&OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE) |
|
||||
ConditionalCap(kCapTransmitTiming, OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE) |
|
||||
ConditionalCap(kCapSleepToTx, OPENTHREAD_RADIO);
|
||||
|
||||
#undef ConditionalCap
|
||||
@@ -538,8 +553,8 @@ private:
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
kStateDelayBeforeRetx, // Delay before retx
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
kStateCslTransmit, // CSL transmission.
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
kStateTimedTransmit, // Timed TX (e.g., for CSL)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
kStateRadioSample, // Mac layer has requested the SubMac to enter sleep state, but the SubMac is in the periodic
|
||||
@@ -563,11 +578,12 @@ private:
|
||||
static constexpr uint32_t kWedReceiveTimeAfter = OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
// CSL transmitter would schedule delayed transmission `kCslTransmitTimeAhead` earlier
|
||||
// than expected delayed transmit time. The value is in usec.
|
||||
// Only for radios not supporting kCapTransmitTiming.
|
||||
static constexpr uint32_t kCslTransmitTimeAhead = OPENTHREAD_CONFIG_CSL_TRANSMIT_TIME_AHEAD;
|
||||
#if OT_CONFIG_MAC_TARGET_TIME_TX_ENABLE
|
||||
// Lead time (in microseconds) to schedule a delayed tx earlier
|
||||
// than expected target tx time. Only used when radio does not
|
||||
// itself support `kCapTransmitTiming`.
|
||||
static constexpr uint32_t kTimedTxLeadTime =
|
||||
OPENTHREAD_CONFIG_CSL_TRANSMIT_TIME_AHEAD + kCcaSampleInterval + Radio::kHeaderShrDuration;
|
||||
#endif
|
||||
|
||||
void Init(void);
|
||||
@@ -578,7 +594,6 @@ private:
|
||||
bool ShouldHandleAckTimeout(void) const { return ShouldHandle(kCapAckTimeout); }
|
||||
bool ShouldHandleRetries(void) const { return ShouldHandle(kCapTransmitRetries); }
|
||||
bool ShouldHandleEnergyScan(void) const { return ShouldHandle(kCapEnergyScan); }
|
||||
bool ShouldHandleTransmitTargetTime(void) const { return ShouldHandle(kCapTransmitTiming); }
|
||||
bool ShouldHandleCsmaBackOff(void) const;
|
||||
|
||||
void ProcessTransmitSecurity(void);
|
||||
|
||||
@@ -83,7 +83,8 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
|
||||
Mac::Address source;
|
||||
uint32_t radioTxDelay;
|
||||
uint32_t rendezvousTimeUs;
|
||||
TimeMicro nowUs = TimerMicro::GetNow();
|
||||
TimeMicro nowUs = TimerMicro::GetNow();
|
||||
Radio::Time64 radioNow = Get<Radio::Radio>().GetNow();
|
||||
Mac::ConnectionIe *connectionIe;
|
||||
|
||||
VerifyOrExit(mIsRunning);
|
||||
@@ -100,8 +101,8 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
|
||||
|
||||
VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), mWakeupRequest, source) == kErrorNone,
|
||||
frame = nullptr);
|
||||
frame->SetTxDelayBaseTime(Get<Radio::Radio>().GetNowAsTime32());
|
||||
frame->SetTxDelay(radioTxDelay);
|
||||
|
||||
frame->SetTargetTxTime(radioNow + radioTxDelay, radioNow);
|
||||
frame->SetCsmaCaEnabled(kWakeupFrameTxCca);
|
||||
frame->SetMaxCsmaBackoffs(0);
|
||||
frame->SetMaxFrameRetries(0);
|
||||
|
||||
@@ -449,34 +449,47 @@ public:
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
/**
|
||||
* Gets the TX delay field for the frame.
|
||||
* Indicates whether or not a target transmission time is specified for the frame.
|
||||
*
|
||||
* @returns The delay time for the TX frame in microseconds.
|
||||
* @retval TRUE If a target transmission time is specified.
|
||||
* @retval FALSE If no target transmission time is specified.
|
||||
*/
|
||||
uint32_t GetTxDelay(void) const { return AsFrame().mInfo.mTxInfo.mTxDelay; }
|
||||
bool IsTargetTxTimeSpecified(void) const { return GetTxDelay() != 0 || GetTxDelayBaseTime() != 0; }
|
||||
|
||||
/**
|
||||
* Set TX delay field for the frame.
|
||||
* Gets the target transmission time for the frame as a `Time32`.
|
||||
*
|
||||
* @param[in] aTxDelay The delay time for the TX frame.
|
||||
* @returns The target transmission time.
|
||||
*/
|
||||
void SetTxDelay(uint32_t aTxDelay) { AsFrame().mInfo.mTxInfo.mTxDelay = aTxDelay; }
|
||||
Time32 GetTargetTxTime(void) const { return GetTxDelayBaseTime() + GetTxDelay(); }
|
||||
|
||||
/**
|
||||
* Gets the TX delay base time field for the frame.
|
||||
*
|
||||
* @returns The delay base time for the TX frame as a `Time32`.
|
||||
* Clears the target transmission time for the frame (sets delay and base time to zero).
|
||||
*/
|
||||
Time32 GetTxDelayBaseTime(void) const { return AsFrame().mInfo.mTxInfo.mTxDelayBaseTime; }
|
||||
void ClearTargetTxTime(void)
|
||||
{
|
||||
SetTxDelayBaseTime(0);
|
||||
SetTxDelay(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TX delay base time field for the frame.
|
||||
* Sets the target transmission time and base reference time for the frame.
|
||||
*
|
||||
* @param[in] aTxDelayBaseTime The delay base time for the TX frame.
|
||||
* @param[in] aTargetTxTime The target transmission time.
|
||||
* @param[in] aBaseTime The base reference time.
|
||||
*/
|
||||
void SetTxDelayBaseTime(Time32 aTxDelayBaseTime) { AsFrame().mInfo.mTxInfo.mTxDelayBaseTime = aTxDelayBaseTime; }
|
||||
void SetTargetTxTime(Time64 aTargetTxTime, Time64 aBaseTime)
|
||||
{
|
||||
SetTxDelayBaseTime(ConvertTime64To32(aBaseTime));
|
||||
SetTxDelay(static_cast<uint32_t>(aTargetTxTime - aBaseTime));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t GetTxDelay(void) const { return AsFrame().mInfo.mTxInfo.mTxDelay; }
|
||||
void SetTxDelay(uint32_t aTxDelay) { AsFrame().mInfo.mTxInfo.mTxDelay = aTxDelay; }
|
||||
Time32 GetTxDelayBaseTime(void) const { return AsFrame().mInfo.mTxInfo.mTxDelayBaseTime; }
|
||||
void SetTxDelayBaseTime(Time32 aTxDelayBaseTime) { AsFrame().mInfo.mTxInfo.mTxDelayBaseTime = aTxDelayBaseTime; }
|
||||
|
||||
Frame &AsFrame(void) { return *static_cast<TxFrameType *>(this); }
|
||||
const Frame &AsFrame(void) const { return *static_cast<const TxFrameType *>(this); }
|
||||
};
|
||||
|
||||
@@ -52,7 +52,8 @@ namespace Radio {
|
||||
#define OT_CONFIG_RADIO_TIME_ENABLE \
|
||||
(OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || \
|
||||
OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE || OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || \
|
||||
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE)
|
||||
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || \
|
||||
((OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE) && OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE))
|
||||
|
||||
class Radio;
|
||||
|
||||
|
||||
@@ -290,8 +290,7 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
frame->SetTxDelayBaseTime(Radio::ConvertTime64To32(mCslTxNeighbor->GetLastRxTimestamp()));
|
||||
frame->SetTxDelay(static_cast<uint32_t>(mNeighborCslWindow - mCslTxNeighbor->GetLastRxTimestamp()));
|
||||
frame->SetTargetTxTime(mNeighborCslWindow, mCslTxNeighbor->GetLastRxTimestamp());
|
||||
frame->SetCsmaCaEnabled(true);
|
||||
|
||||
exit:
|
||||
|
||||
Reference in New Issue
Block a user