mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 00:27:47 +00:00
[mac] feature to add delay on no-ack error before tx retry (#7346)
This commit adds a new feature in `SubMac` to add random delay before frame retransmissions. The delay is added only if the previous tx resulted in `kErrorNoAck`. A backoff algorithm similar to one used for CSMA is used to determine the random delay, i.e., starting with a min backoff exponent (BE) which is incremented each time delay is added up to a max backoff exponent. The backoff interval is derived by selecting a random value from `[0, 2^BE]` range multiplied by `kUnitBackoffPeriod=20` times radio symbol time (20x16=320 usec). The `OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY` is added to enable this behavior (which is enabled by default). This commit also adds other configs for this feature including minimum and maximum backoff exponents (the values are from Thread 1.3 spec recommendations).
This commit is contained in:
@@ -85,6 +85,40 @@
|
||||
#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
*
|
||||
* Define as 1 to add random backoff delay in between frame transmission retries when the previous attempt resulted in
|
||||
* no-ack error.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
#define OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_RETX_DELAY_MIN_BACKOFF_EXPONENT
|
||||
*
|
||||
* Specifies the minimum backoff exponent to start with when adding random delay in between frame transmission
|
||||
* retries on no-ack error. It is applicable only when `OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY`
|
||||
* is enabled.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAC_RETX_DELAY_MIN_BACKOFF_EXPONENT
|
||||
#define OPENTHREAD_CONFIG_MAC_RETX_DELAY_MIN_BACKOFF_EXPONENT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT
|
||||
*
|
||||
* Specifies the maximum backoff exponent when adding random delay in between frame transmission retries on no-ack
|
||||
* error. It is applicable only when `OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY` is enabled.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT
|
||||
#define OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT 5
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
|
||||
*
|
||||
|
||||
+70
-11
@@ -78,6 +78,9 @@ void SubMac::Init(void)
|
||||
mRxOnWhenBackoff = true;
|
||||
mEnergyScanMaxRssi = kInvalidRssiValue;
|
||||
mEnergyScanEndTime = Time{0};
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
mRetxDelayBackOffExponent = kRetxDelayMinBackoffExponent;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
mRadioFilterEnabled = false;
|
||||
@@ -342,6 +345,9 @@ Error SubMac::Send(void)
|
||||
case kStateCslTransmit:
|
||||
#endif
|
||||
case kStateTransmit:
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
case kStateDelayBeforeRetx:
|
||||
#endif
|
||||
case kStateEnergyScan:
|
||||
ExitNow(error = kErrorInvalidState);
|
||||
OT_UNREACHABLE_CODE(break);
|
||||
@@ -363,8 +369,14 @@ Error SubMac::Send(void)
|
||||
#endif
|
||||
|
||||
ProcessTransmitSecurity();
|
||||
|
||||
mCsmaBackoffs = 0;
|
||||
mTransmitRetries = 0;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
mRetxDelayBackOffExponent = kRetxDelayMinBackoffExponent;
|
||||
#endif
|
||||
|
||||
StartCsmaBackoff();
|
||||
|
||||
exit:
|
||||
@@ -414,8 +426,7 @@ exit:
|
||||
|
||||
void SubMac::StartCsmaBackoff(void)
|
||||
{
|
||||
uint32_t backoff;
|
||||
uint32_t backoffExponent = kCsmaMinBe + mTransmitRetries + mCsmaBackoffs;
|
||||
uint8_t backoffExponent = kCsmaMinBe + mCsmaBackoffs;
|
||||
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
if (mTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)
|
||||
@@ -444,6 +455,7 @@ void SubMac::StartCsmaBackoff(void)
|
||||
ExitNow();
|
||||
}
|
||||
#endif // !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
|
||||
SetState(kStateCsmaBackoff);
|
||||
|
||||
VerifyOrExit(ShouldHandleCsmaBackOff(), BeginTransmit());
|
||||
@@ -453,8 +465,18 @@ void SubMac::StartCsmaBackoff(void)
|
||||
backoffExponent = kCsmaMaxBe;
|
||||
}
|
||||
|
||||
backoff = Random::NonCrypto::GetUint32InRange(0, static_cast<uint32_t>(1UL << backoffExponent));
|
||||
backoff *= (kUnitBackoffPeriod * OT_RADIO_SYMBOL_TIME);
|
||||
StartTimerForBackoff(backoffExponent);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SubMac::StartTimerForBackoff(uint8_t aBackoffExponent)
|
||||
{
|
||||
uint32_t backoff;
|
||||
|
||||
backoff = Random::NonCrypto::GetUint32InRange(0, static_cast<uint32_t>(1UL << aBackoffExponent));
|
||||
backoff *= (kUnitBackoffPeriod * Radio::kSymbolTime);
|
||||
|
||||
if (mRxOnWhenBackoff)
|
||||
{
|
||||
@@ -471,8 +493,12 @@ void SubMac::StartCsmaBackoff(void)
|
||||
mTimer.Start(backoff / 1000UL);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
if (mState == kStateDelayBeforeRetx)
|
||||
{
|
||||
LogDebg("Delaying retx for %u usec (be=%d)", backoff, aBackoffExponent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SubMac::BeginTransmit(void)
|
||||
@@ -593,6 +619,17 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
|
||||
{
|
||||
mTransmitRetries++;
|
||||
aFrame.SetIsARetransmission(true);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
if (aError == kErrorNoAck)
|
||||
{
|
||||
SetState(kStateDelayBeforeRetx);
|
||||
StartTimerForBackoff(mRetxDelayBackOffExponent);
|
||||
mRetxDelayBackOffExponent = OT_MIN(mRetxDelayBackOffExponent + 1, kRetxDelayMaxBackoffExponent);
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
StartCsmaBackoff();
|
||||
ExitNow();
|
||||
}
|
||||
@@ -672,6 +709,9 @@ Error SubMac::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
case kStateTransmit:
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case kStateCslTransmit:
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
case kStateDelayBeforeRetx:
|
||||
#endif
|
||||
case kStateEnergyScan:
|
||||
ExitNow(error = kErrorInvalidState);
|
||||
@@ -769,6 +809,12 @@ void SubMac::HandleTimer(void)
|
||||
HandleTransmitDone(mTransmitFrame, nullptr, kErrorNoAck);
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
case kStateDelayBeforeRetx:
|
||||
StartCsmaBackoff();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case kStateEnergyScan:
|
||||
SampleRssi();
|
||||
break;
|
||||
@@ -968,11 +1014,14 @@ const char *SubMac::StateToString(State aState)
|
||||
"CsmaBackoff", // (3) kStateCsmaBackoff
|
||||
"Transmit", // (4) kStateTransmit
|
||||
"EnergyScan", // (5) kStateEnergyScan
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
"DelayBeforeRetx", // (6) kStateDelayBeforeRetx
|
||||
#endif
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
"CslTransmit", // (6) kStateCslTransmit
|
||||
"CslTransmit", // (7) kStateCslTransmit
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
"CslSample", // (7) kStateCslSample
|
||||
"CslSample", // (8) kStateCslSample
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -982,15 +1031,25 @@ const char *SubMac::StateToString(State aState)
|
||||
static_assert(kStateCsmaBackoff == 3, "kStateCsmaBackoff value is not correct");
|
||||
static_assert(kStateTransmit == 4, "kStateTransmit value is not correct");
|
||||
static_assert(kStateEnergyScan == 5, "kStateEnergyScan value is not correct");
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
static_assert(kStateDelayBeforeRetx == 6, "kStateDelayBeforeRetx value is not correct");
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
static_assert(kStateCslTransmit == 7, "kStateCslTransmit value is not correct");
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static_assert(kStateCslSample == 8, "kStateCslSample value is not correct");
|
||||
#endif
|
||||
#elif OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static_assert(kStateCslSample == 7, "kStateCslSample value is not correct");
|
||||
#endif
|
||||
|
||||
#elif !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
static_assert(kStateCslTransmit == 6, "kStateCslTransmit value is not correct");
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static_assert(kStateCslSample == 7, "kStateCslSample value is not correct");
|
||||
#endif
|
||||
#else
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
#elif OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static_assert(kStateCslSample == 6, "kStateCslSample value is not correct");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return kStateStrings[aState];
|
||||
|
||||
@@ -584,6 +584,11 @@ private:
|
||||
static constexpr uint32_t kAckTimeout = 16; // Timeout for waiting on an ACK (in msec).
|
||||
static constexpr uint32_t kCcaSampleInterval = 128; // CCA sample interval, 128 usec.
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
static constexpr uint8_t kRetxDelayMinBackoffExponent = OPENTHREAD_CONFIG_MAC_RETX_DELAY_MIN_BACKOFF_EXPONENT;
|
||||
static constexpr uint8_t kRetxDelayMaxBackoffExponent = OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
||||
static constexpr uint32_t kEnergyScanRssiSampleInterval = 128; // RSSI sample interval for energy scan, 128 usec
|
||||
#else
|
||||
@@ -598,6 +603,9 @@ private:
|
||||
kStateCsmaBackoff, // CSMA backoff before transmission.
|
||||
kStateTransmit, // Radio is transmitting.
|
||||
kStateEnergyScan, // Energy scan.
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
kStateDelayBeforeRetx, // Delay before retx
|
||||
#endif
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
kStateCslTransmit, // CSL transmission.
|
||||
#endif
|
||||
@@ -650,6 +658,7 @@ private:
|
||||
void ProcessTransmitSecurity(void);
|
||||
void SignalFrameCounterUsed(uint32_t aFrameCounter);
|
||||
void StartCsmaBackoff(void);
|
||||
void StartTimerForBackoff(uint8_t aBackoffExponent);
|
||||
void BeginTransmit(void);
|
||||
void SampleRssi(void);
|
||||
|
||||
@@ -689,6 +698,9 @@ private:
|
||||
KeyMaterial mNextKey;
|
||||
uint32_t mFrameCounter;
|
||||
uint8_t mKeyId;
|
||||
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
|
||||
uint8_t mRetxDelayBackOffExponent;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
||||
TimerMicro mTimer;
|
||||
#else
|
||||
|
||||
@@ -81,6 +81,7 @@ class Radio : public InstanceLocator, private NonCopyable
|
||||
friend class Instance;
|
||||
|
||||
public:
|
||||
static constexpr uint32_t kSymbolTime = OT_RADIO_SYMBOL_TIME;
|
||||
#if (OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT)
|
||||
static constexpr uint16_t kNumChannelPages = 2;
|
||||
static constexpr uint32_t kSupportedChannels =
|
||||
|
||||
Reference in New Issue
Block a user