From 8ef2228ab2878c3b1a27ffba5e4579107f8696f9 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 19 Dec 2017 21:32:24 -0800 Subject: [PATCH] [mac] ensure MAC operations get started from a tasklet (#2427) This commit changes how MAC operations (frame tx, active/energy scan, etc.) get started by adding a new tasklet `mOperationTask` which is used to start/perform any pending operation. This ensures that callbacks related to an operation are invoked after the method which initiates the operation returns. For example, when a new `Mac::Sender` is registered with a call to `Mac::SendFrameRequest()`, its callback `FrameRequestHandler` would be invoked after the `SendFrameRequest()` call itself returns. The `mOperationTask` serves two purposes. It's mainly used for starting a new operation. It is also used during Energy Scan to take an RSSI sample. --- src/core/mac/mac.cpp | 50 +++++++++++++++++++++++++++++++------------- src/core/mac/mac.hpp | 8 ++++--- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 9c16100df..2e24107f0 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -89,6 +89,7 @@ Mac::Mac(Instance &aInstance): #if OPENTHREAD_CONFIG_STAY_AWAKE_BETWEEN_FRAGMENTS mDelaySleep(false), #endif + mOperationTask(aInstance, &Mac::PerformOperation, this), mMacTimer(aInstance, &Mac::HandleMacTimer, this), mBackoffTimer(aInstance, &Mac::HandleBeginTransmit, this), mReceiveTimer(aInstance, &Mac::HandleReceiveTimer, this), @@ -109,7 +110,6 @@ Mac::Mac(Instance &aInstance): mEnergyScanCurrentMaxRssi(kInvalidRssiValue), mScanContext(NULL), mActiveScanHandler(NULL), // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union - mEnergyScanSampleRssiTask(aInstance, &Mac::HandleEnergyScanSampleRssi, this), mPcapCallback(NULL), mPcapCallbackContext(NULL), #if OPENTHREAD_ENABLE_MAC_FILTER @@ -273,7 +273,7 @@ void Mac::PerformEnergyScan(void) { RadioReceive(mScanChannel); mEnergyScanCurrentMaxRssi = kInvalidRssiValue; - mEnergyScanSampleRssiTask.Post(); + mOperationTask.Post(); if (mScanDuration != 0) { @@ -335,17 +335,10 @@ void Mac::EnergyScanDone(int8_t aRssi) PerformEnergyScan(); } -void Mac::HandleEnergyScanSampleRssi(Tasklet &aTasklet) -{ - aTasklet.GetOwner().HandleEnergyScanSampleRssi(); -} - -void Mac::HandleEnergyScanSampleRssi(void) +void Mac::SampleRssi(void) { int8_t rssi; - VerifyOrExit(mOperation == kOperationEnergyScan); - rssi = otPlatRadioGetRssi(&GetInstance()); if (rssi != kInvalidRssiValue) @@ -362,11 +355,8 @@ void Mac::HandleEnergyScanSampleRssi(void) } else { - mEnergyScanSampleRssiTask.Post(); + mOperationTask.Post(); } - -exit: - return; } otError Mac::RegisterReceiver(Receiver &aReceiver) @@ -577,6 +567,30 @@ void Mac::StartOperation(Operation aOperation) break; } + if (mOperation == kOperationIdle) + { + mOperationTask.Post(); + } +} + +void Mac::PerformOperation(Tasklet &aTasklet) +{ + aTasklet.GetOwner().PerformOperation(); +} + +void Mac::PerformOperation(void) +{ + // The `mOperationTask` tasklet serves two purposes: + // + // (a) it is used to start a pending operation, + // (b) while performing Energy Scan, it is used to take RSSI samples. + + if (mOperation == kOperationEnergyScan) + { + SampleRssi(); + ExitNow(); + } + VerifyOrExit(mOperation == kOperationIdle); // `WaitingForData` should be checked before any other pending @@ -634,7 +648,13 @@ void Mac::FinishOperation(void) otLogDebgMac(GetInstance(), "Finishing operation \"%s\"", OperationToString(mOperation)); mOperation = kOperationIdle; - StartOperation(kOperationIdle); + + // Note that we do not want to post the `mOperationTask` here and + // instead we do a direct call to `PerformOperation()`. This helps + // ensure that if there is no pending operation, the radio is + // switched to idle mode immediately. + + PerformOperation(); } void Mac::GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce) diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 0b1ee7050..c90b75c87 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -644,8 +644,8 @@ private: void HandleBeginTransmit(void); static void HandleReceiveTimer(Timer &aTimer); void HandleReceiveTimer(void); - static void HandleEnergyScanSampleRssi(Tasklet &aTasklet); - void HandleEnergyScanSampleRssi(void); + static void PerformOperation(Tasklet &aTasklet); + void PerformOperation(void); void StartCsmaBackoff(void); @@ -654,6 +654,7 @@ private: void PerformActiveScan(void); void PerformEnergyScan(void); void ReportEnergyScanResult(int8_t aRssi); + void SampleRssi(void); otError RadioTransmit(Frame *aSendFrame); otError RadioReceive(uint8_t aChannel); @@ -674,6 +675,8 @@ private: bool mDelaySleep : 1; #endif + Tasklet mOperationTask; + TimerMilli mMacTimer; #if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER TimerMicro mBackoffTimer; @@ -708,7 +711,6 @@ private: ActiveScanHandler mActiveScanHandler; EnergyScanHandler mEnergyScanHandler; }; - Tasklet mEnergyScanSampleRssiTask; otLinkPcapCallback mPcapCallback; void *mPcapCallbackContext;