mirror of
https://github.com/espressif/openthread.git
synced 2026-10-01 13:27:42 +00:00
[mac] simplify scan implementation (#2420)
This commit contains the following changes: It simplifies the MAC scan implementation by adding common helper methods such as `UpdateScanChannel()`. It also fixes an issue where invoking back-to- back scan could cause the handler to be overwritten with NULL. It adds support for special case of Energy Scan with zero scan duration to collect a single RSSI sample per channel.
This commit is contained in:
committed by
Jonathan Hui
parent
3a46740c24
commit
38b7d9e652
+90
-96
@@ -133,63 +133,45 @@ Mac::Mac(Instance &aInstance):
|
|||||||
|
|
||||||
otError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext)
|
otError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext)
|
||||||
{
|
{
|
||||||
otError error;
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
|
VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = OT_ERROR_BUSY);
|
||||||
|
|
||||||
mActiveScanHandler = aHandler;
|
mActiveScanHandler = aHandler;
|
||||||
SuccessOrExit(error = Scan(kOperationActiveScan, aScanChannels, aScanDuration, aContext));
|
|
||||||
|
|
||||||
exit:
|
if (aScanDuration == 0)
|
||||||
|
|
||||||
if (OT_ERROR_NONE != error)
|
|
||||||
{
|
{
|
||||||
mActiveScanHandler = NULL;
|
aScanDuration = kScanDurationDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scan(kOperationActiveScan, aScanChannels, aScanDuration, aContext);
|
||||||
|
|
||||||
|
exit:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
otError Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext)
|
otError Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext)
|
||||||
{
|
|
||||||
otError error;
|
|
||||||
|
|
||||||
mEnergyScanHandler = aHandler;
|
|
||||||
SuccessOrExit(error = Scan(kOperationEnergyScan, aScanChannels, aScanDuration, aContext));
|
|
||||||
|
|
||||||
exit:
|
|
||||||
|
|
||||||
if (OT_ERROR_NONE != error)
|
|
||||||
{
|
|
||||||
mEnergyScanHandler = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
otError Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext)
|
|
||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = OT_ERROR_BUSY);
|
VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = OT_ERROR_BUSY);
|
||||||
|
|
||||||
mScanContext = aContext;
|
mEnergyScanHandler = aHandler;
|
||||||
mScanChannels = (aScanChannels == 0) ? static_cast<uint32_t>(kScanChannelsAll) : aScanChannels;
|
Scan(kOperationEnergyScan, aScanChannels, aScanDuration, aContext);
|
||||||
mScanDuration = (aScanDuration == 0) ? static_cast<uint16_t>(kScanDurationDefault) : aScanDuration;
|
|
||||||
|
|
||||||
mScanChannel = OT_RADIO_CHANNEL_MIN;
|
|
||||||
mScanChannels >>= OT_RADIO_CHANNEL_MIN;
|
|
||||||
|
|
||||||
while ((mScanChannels & 1) == 0)
|
|
||||||
{
|
|
||||||
mScanChannels >>= 1;
|
|
||||||
mScanChannel++;
|
|
||||||
}
|
|
||||||
|
|
||||||
StartOperation(aScanOperation);
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext)
|
||||||
|
{
|
||||||
|
mScanContext = aContext;
|
||||||
|
mScanDuration = aScanDuration;
|
||||||
|
mScanChannels = (aScanChannels == 0) ? static_cast<uint32_t>(kScanChannelsAll) : aScanChannels;
|
||||||
|
mScanChannel = OT_RADIO_CHANNEL_MIN - 1;
|
||||||
|
StartOperation(aScanOperation);
|
||||||
|
}
|
||||||
|
|
||||||
bool Mac::IsActiveScanInProgress(void)
|
bool Mac::IsActiveScanInProgress(void)
|
||||||
{
|
{
|
||||||
return (mOperation == kOperationActiveScan) || (mPendingActiveScan);
|
return (mOperation == kOperationActiveScan) || (mPendingActiveScan);
|
||||||
@@ -250,26 +232,66 @@ exit:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mac::StartEnergyScan(void)
|
otError Mac::UpdateScanChannel(void)
|
||||||
{
|
{
|
||||||
if (!(otPlatRadioGetCaps(&GetInstance()) & OT_RADIO_CAPS_ENERGY_SCAN))
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
mEnergyScanCurrentMaxRssi = kInvalidRssiValue;
|
mScanChannel++;
|
||||||
mMacTimer.Start(mScanDuration);
|
VerifyOrExit(mScanChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_NOT_FOUND);
|
||||||
mEnergyScanSampleRssiTask.Post();
|
|
||||||
RadioReceive(mScanChannel);
|
}
|
||||||
|
while ((mScanChannels & (1U << mScanChannel)) == 0);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mac::PerformActiveScan(void)
|
||||||
|
{
|
||||||
|
if (UpdateScanChannel() == OT_ERROR_NONE)
|
||||||
|
{
|
||||||
|
// If there are more channels to scan, start CSMA backoff to send the beacon request.
|
||||||
|
StartCsmaBackoff();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
otError error = otPlatRadioEnergyScan(&GetInstance(), mScanChannel, mScanDuration);
|
otPlatRadioSetPanId(&GetInstance(), mPanId);
|
||||||
|
mActiveScanHandler(mScanContext, NULL);
|
||||||
|
FinishOperation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error != OT_ERROR_NONE)
|
void Mac::PerformEnergyScan(void)
|
||||||
|
{
|
||||||
|
otError error = OT_ERROR_NONE;
|
||||||
|
|
||||||
|
SuccessOrExit(error = UpdateScanChannel());
|
||||||
|
|
||||||
|
if (!(otPlatRadioGetCaps(&GetInstance()) & OT_RADIO_CAPS_ENERGY_SCAN) || (mScanDuration == 0))
|
||||||
|
{
|
||||||
|
RadioReceive(mScanChannel);
|
||||||
|
mEnergyScanCurrentMaxRssi = kInvalidRssiValue;
|
||||||
|
mEnergyScanSampleRssiTask.Post();
|
||||||
|
|
||||||
|
if (mScanDuration != 0)
|
||||||
{
|
{
|
||||||
// Cancel scan
|
mMacTimer.Start(mScanDuration);
|
||||||
mEnergyScanHandler(mScanContext, NULL);
|
|
||||||
FinishOperation();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SuccessOrExit(error = otPlatRadioEnergyScan(&GetInstance(), mScanChannel, mScanDuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
|
||||||
|
if (error != OT_ERROR_NONE)
|
||||||
|
{
|
||||||
|
mEnergyScanHandler(mScanContext, NULL);
|
||||||
|
FinishOperation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
|
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
|
||||||
@@ -294,40 +316,23 @@ exit:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mac::EnergyScanDone(int8_t aEnergyScanMaxRssi)
|
void Mac::ReportEnergyScanResult(int8_t aRssi)
|
||||||
{
|
{
|
||||||
// Trigger a energy scan handler callback if necessary
|
if (aRssi != kInvalidRssiValue)
|
||||||
if (aEnergyScanMaxRssi != kInvalidRssiValue)
|
|
||||||
{
|
{
|
||||||
otEnergyScanResult result;
|
otEnergyScanResult result;
|
||||||
|
|
||||||
result.mChannel = mScanChannel;
|
result.mChannel = mScanChannel;
|
||||||
result.mMaxRssi = aEnergyScanMaxRssi;
|
result.mMaxRssi = aRssi;
|
||||||
|
|
||||||
mEnergyScanHandler(mScanContext, &result);
|
mEnergyScanHandler(mScanContext, &result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update to the next scan channel
|
void Mac::EnergyScanDone(int8_t aRssi)
|
||||||
do
|
{
|
||||||
{
|
ReportEnergyScanResult(aRssi);
|
||||||
mScanChannels >>= 1;
|
PerformEnergyScan();
|
||||||
mScanChannel++;
|
|
||||||
|
|
||||||
// If we have scanned all the channels, then fire the final callback
|
|
||||||
// and finish scan operation.
|
|
||||||
if (mScanChannels == 0 || mScanChannel > OT_RADIO_CHANNEL_MAX)
|
|
||||||
{
|
|
||||||
mEnergyScanHandler(mScanContext, NULL);
|
|
||||||
FinishOperation();
|
|
||||||
ExitNow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((mScanChannels & 1) == 0);
|
|
||||||
|
|
||||||
// Start scanning the next channel
|
|
||||||
StartEnergyScan();
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mac::HandleEnergyScanSampleRssi(Tasklet &aTasklet)
|
void Mac::HandleEnergyScanSampleRssi(Tasklet &aTasklet)
|
||||||
@@ -351,7 +356,14 @@ void Mac::HandleEnergyScanSampleRssi(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mEnergyScanSampleRssiTask.Post();
|
if (mScanDuration == 0)
|
||||||
|
{
|
||||||
|
EnergyScanDone(mEnergyScanCurrentMaxRssi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEnergyScanSampleRssiTask.Post();
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return;
|
return;
|
||||||
@@ -581,13 +593,13 @@ void Mac::StartOperation(Operation aOperation)
|
|||||||
{
|
{
|
||||||
mPendingActiveScan = false;
|
mPendingActiveScan = false;
|
||||||
mOperation = kOperationActiveScan;
|
mOperation = kOperationActiveScan;
|
||||||
StartCsmaBackoff();
|
PerformActiveScan();
|
||||||
}
|
}
|
||||||
else if (mPendingEnergyScan)
|
else if (mPendingEnergyScan)
|
||||||
{
|
{
|
||||||
mPendingEnergyScan = false;
|
mPendingEnergyScan = false;
|
||||||
mOperation = kOperationEnergyScan;
|
mOperation = kOperationEnergyScan;
|
||||||
StartEnergyScan();
|
PerformEnergyScan();
|
||||||
}
|
}
|
||||||
else if (mPendingTransmitBeacon)
|
else if (mPendingTransmitBeacon)
|
||||||
{
|
{
|
||||||
@@ -1262,22 +1274,7 @@ void Mac::HandleMacTimer(void)
|
|||||||
switch (mOperation)
|
switch (mOperation)
|
||||||
{
|
{
|
||||||
case kOperationActiveScan:
|
case kOperationActiveScan:
|
||||||
do
|
PerformActiveScan();
|
||||||
{
|
|
||||||
mScanChannels >>= 1;
|
|
||||||
mScanChannel++;
|
|
||||||
|
|
||||||
if (mScanChannels == 0 || mScanChannel > OT_RADIO_CHANNEL_MAX)
|
|
||||||
{
|
|
||||||
otPlatRadioSetPanId(&GetInstance(), mPanId);
|
|
||||||
mActiveScanHandler(mScanContext, NULL);
|
|
||||||
FinishOperation();
|
|
||||||
ExitNow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((mScanChannels & 1) == 0);
|
|
||||||
|
|
||||||
StartCsmaBackoff();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kOperationEnergyScan:
|
case kOperationEnergyScan:
|
||||||
@@ -1293,9 +1290,6 @@ void Mac::HandleMacTimer(void)
|
|||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mac::HandleReceiveTimer(Timer &aTimer)
|
void Mac::HandleReceiveTimer(Timer &aTimer)
|
||||||
|
|||||||
+17
-8
@@ -226,7 +226,7 @@ public:
|
|||||||
* This function pointer is called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
|
* This function pointer is called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
|
||||||
*
|
*
|
||||||
* @param[in] aContext A pointer to arbitrary context information.
|
* @param[in] aContext A pointer to arbitrary context information.
|
||||||
* @param[in] aBeaconFrame A pointer to the Beacon frame.
|
* @param[in] aBeaconFrame A pointer to the Beacon frame or NULL to indicate end of Active Scan operation.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef void (*ActiveScanHandler)(void *aContext, Frame *aBeaconFrame);
|
typedef void (*ActiveScanHandler)(void *aContext, Frame *aBeaconFrame);
|
||||||
@@ -234,11 +234,15 @@ public:
|
|||||||
/**
|
/**
|
||||||
* This method starts an IEEE 802.15.4 Active Scan.
|
* This method starts an IEEE 802.15.4 Active Scan.
|
||||||
*
|
*
|
||||||
* @param[in] aScanChannels A bit vector indicating which channels to scan.
|
* @param[in] aScanChannels A bit vector indicating which channels to scan. Zero is mapped to all channels.
|
||||||
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
|
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel. Zero duration maps to
|
||||||
|
* default value `kScanDurationDefault` = 300 ms.
|
||||||
* @param[in] aHandler A pointer to a function that is called on receiving an IEEE 802.15.4 Beacon.
|
* @param[in] aHandler A pointer to a function that is called on receiving an IEEE 802.15.4 Beacon.
|
||||||
* @param[in] aContext A pointer to arbitrary context information.
|
* @param[in] aContext A pointer to arbitrary context information.
|
||||||
*
|
*
|
||||||
|
* @retval OT_ERROR_NONE Successfully scheduled the Active Scan request.
|
||||||
|
* @retval OT_ERROR_BUSY Could not schedule the scan (a scan is ongoing or scheduled).
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
otError ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext);
|
otError ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext);
|
||||||
|
|
||||||
@@ -256,7 +260,7 @@ public:
|
|||||||
otError ConvertBeaconToActiveScanResult(Frame *aBeaconFrame, otActiveScanResult &aResult);
|
otError ConvertBeaconToActiveScanResult(Frame *aBeaconFrame, otActiveScanResult &aResult);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function pointer is called during an "Energy Scan" when the result for a channel is ready or the scan
|
* This function pointer is called during an Energy Scan when the result for a channel is ready or the scan
|
||||||
* completes.
|
* completes.
|
||||||
*
|
*
|
||||||
* @param[in] aContext A pointer to arbitrary context information.
|
* @param[in] aContext A pointer to arbitrary context information.
|
||||||
@@ -269,8 +273,9 @@ public:
|
|||||||
/**
|
/**
|
||||||
* This method starts an IEEE 802.15.4 Energy Scan.
|
* This method starts an IEEE 802.15.4 Energy Scan.
|
||||||
*
|
*
|
||||||
* @param[in] aScanChannels A bit vector indicating on which channels to perform energy scan.
|
* @param[in] aScanChannels A bit vector indicating on which channels to scan. Zero is mapped to all channels.
|
||||||
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
|
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel. If the duration is set to
|
||||||
|
* zero, a single RSSI sample will be taken per channel.
|
||||||
* @param[in] aHandler A pointer to a function called to pass on scan result or indicate scan completion.
|
* @param[in] aHandler A pointer to a function called to pass on scan result or indicate scan completion.
|
||||||
* @param[in] aContext A pointer to arbitrary context information.
|
* @param[in] aContext A pointer to arbitrary context information.
|
||||||
*
|
*
|
||||||
@@ -631,7 +636,6 @@ private:
|
|||||||
void SendBeaconRequest(Frame &aFrame);
|
void SendBeaconRequest(Frame &aFrame);
|
||||||
void SendBeacon(Frame &aFrame);
|
void SendBeacon(Frame &aFrame);
|
||||||
void StartBackoff(void);
|
void StartBackoff(void);
|
||||||
void StartEnergyScan(void);
|
|
||||||
otError HandleMacCommand(Frame &aFrame);
|
otError HandleMacCommand(Frame &aFrame);
|
||||||
|
|
||||||
static void HandleMacTimer(Timer &aTimer);
|
static void HandleMacTimer(Timer &aTimer);
|
||||||
@@ -644,7 +648,12 @@ private:
|
|||||||
void HandleEnergyScanSampleRssi(void);
|
void HandleEnergyScanSampleRssi(void);
|
||||||
|
|
||||||
void StartCsmaBackoff(void);
|
void StartCsmaBackoff(void);
|
||||||
otError Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext);
|
|
||||||
|
void Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext);
|
||||||
|
otError UpdateScanChannel(void);
|
||||||
|
void PerformActiveScan(void);
|
||||||
|
void PerformEnergyScan(void);
|
||||||
|
void ReportEnergyScanResult(int8_t aRssi);
|
||||||
|
|
||||||
otError RadioTransmit(Frame *aSendFrame);
|
otError RadioTransmit(Frame *aSendFrame);
|
||||||
otError RadioReceive(uint8_t aChannel);
|
otError RadioReceive(uint8_t aChannel);
|
||||||
|
|||||||
Reference in New Issue
Block a user