[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.
This commit is contained in:
Abtin Keshavarzian
2017-12-20 05:32:24 +00:00
committed by Jonathan Hui
parent debf68dd09
commit 8ef2228ab2
2 changed files with 40 additions and 18 deletions
+35 -15
View File
@@ -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<Mac>().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<Mac>().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)
+5 -3
View File
@@ -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;