From 5c8a9cb5bc28ce6f794c0d8db7189b1f2dd586ba Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 19 Apr 2022 11:05:24 -0700 Subject: [PATCH] [mesh-forwarder] collision avoidance delay mechanism (#7512) This commit adds a new feature in `MeshForwarder` to add wait delay after a successful frame tx to a neighbor which is expected to forward the frame. This wait time applies before the next direct tx to any neighbor on an FTD. This mechanism is intended to help prevent self-interference when messages are sent to a destination that is at least 2-hops away. This commit adds new OT build configs to enable/disable this behavior and specify the wait interval (default is set to 8 msec). --- src/core/config/mac.h | 26 +++++++++++++++++ src/core/thread/mesh_forwarder.cpp | 39 ++++++++++++++++++++++++++ src/core/thread/mesh_forwarder.hpp | 12 +++++++- src/core/thread/mesh_forwarder_ftd.cpp | 10 +++++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/core/config/mac.h b/src/core/config/mac.h index f4821a0c6..6572dd0e8 100644 --- a/src/core/config/mac.h +++ b/src/core/config/mac.h @@ -119,6 +119,32 @@ #define OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT 5 #endif +/** + * @def OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + * + * Define as 1 to enable collision avoidance delay feature, which adds a delay wait time after a successful frame tx + * to a neighbor which is expected to forward the frame. This delay is applied before the next direct frame tx (towards + * any neighbor) on an FTD. + * + * The delay interval is specified by `OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL` (in milliseconds). + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE +#define OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE 1 +#endif + +/** + * @def OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL + * + * Specifies the collision avoidance delay interval in milliseconds. This is added after a successful frame tx to a + * neighbor that is expected to forward the frame (when `OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE` is + * enabled). + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL +#define OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL 8 +#endif + /** * @def OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE * diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 05eddb515..7a1a18e8a 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -101,6 +101,10 @@ MeshForwarder::MeshForwarder(Instance &aInstance) , mEnabled(false) , mTxPaused(false) , mSendBusy(false) +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + , mDelayNextTx(false) + , mTxDelayTimer(aInstance, HandleTxDelayTimer) +#endif , mScheduleTransmissionTask(aInstance, MeshForwarder::ScheduleTransmissionTask) #if OPENTHREAD_FTD , mIndirectSender(aInstance) @@ -145,6 +149,11 @@ void MeshForwarder::Stop(void) mFragmentPriorityList.Clear(); #endif +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + mTxDelayTimer.Stop(); + mDelayNextTx = false; +#endif + mEnabled = false; mSendMessage = nullptr; Get().SetRxOnWhenIdle(false); @@ -237,6 +246,20 @@ void MeshForwarder::ResumeMessageTransmissions(void) } } +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE +void MeshForwarder::HandleTxDelayTimer(Timer &aTimer) +{ + aTimer.Get().HandleTxDelayTimer(); +} + +void MeshForwarder::HandleTxDelayTimer(void) +{ + mDelayNextTx = false; + mScheduleTransmissionTask.Post(); + LogDebg("Tx delay timer expired"); +} +#endif + void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet) { aTasklet.Get().ScheduleTransmissionTask(); @@ -246,6 +269,10 @@ void MeshForwarder::ScheduleTransmissionTask(void) { VerifyOrExit(!mSendBusy && !mTxPaused); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + VerifyOrExit(!mDelayNextTx); +#endif + mSendMessage = PrepareNextDirectTransmission(); VerifyOrExit(mSendMessage != nullptr); @@ -996,6 +1023,18 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, Error aError) VerifyOrExit(mEnabled); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + if (mDelayNextTx && (aError == kErrorNone)) + { + mTxDelayTimer.Start(kTxDelayInterval); + LogDebg("Start tx delay timer for %u msec", kTxDelayInterval); + } + else + { + mDelayNextTx = false; + } +#endif + if (!aFrame.IsEmpty()) { IgnoreError(aFrame.GetDstAddr(macDest)); diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index bbf6d62ee..603e567ef 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -334,6 +334,8 @@ private: static constexpr uint8_t kMeshHeaderFrameMtu = OT_RADIO_FRAME_MAX_SIZE; // Max MTU with a Mesh Header frame. static constexpr uint8_t kMeshHeaderFrameFcsSize = sizeof(uint16_t); // Frame FCS size for Mesh Header frame. + static constexpr uint32_t kTxDelayInterval = OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL; // In msec + enum MessageAction : uint8_t { kMessageReceive, // Indicates that the message was received. @@ -503,11 +505,15 @@ private: void PauseMessageTransmissions(void) { mTxPaused = true; } void ResumeMessageTransmissions(void); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + static void HandleTxDelayTimer(Timer &aTimer); + void HandleTxDelayTimer(void); +#endif + void LogMessage(MessageAction aAction, const Message & aMessage, Error aError = kErrorNone, const Mac::Address *aAddress = nullptr); - void LogFrame(const char *aActionText, const Mac::Frame &aFrame, Error aError); void LogFragmentFrameDrop(Error aError, uint16_t aFrameLength, @@ -585,6 +591,10 @@ private: bool mEnabled : 1; bool mTxPaused : 1; bool mSendBusy : 1; +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + bool mDelayNextTx : 1; + TimerMilli mTxDelayTimer; +#endif Tasklet mScheduleTransmissionTask; diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index ffe80bff9..ef1f60df1 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -403,6 +403,13 @@ Error MeshForwarder::UpdateMeshRoute(Message &aMessage) mMeshDest = meshHeader.GetDestination(); mMeshSource = meshHeader.GetSource(); +#if OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + if (mMacDest.GetShort() != mMeshDest) + { + mDelayNextTx = true; + } +#endif + exit: return error; } @@ -616,6 +623,9 @@ Error MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage // destination is not neighbor mMacSource.SetShort(mMeshSource); mAddMeshHeader = true; +#if OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE + mDelayNextTx = true; +#endif } exit: