From 2df41313a9a1bf774d78487778cf1b75f718149a Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 6 Oct 2016 23:20:50 -0700 Subject: [PATCH] Add support for radio energy scan API (#749) * Add support for radio energy scan API --- examples/platforms/cc2538/radio.c | 8 +++ examples/platforms/posix/radio.c | 8 +++ include/platform/radio.h | 22 ++++++++ src/core/mac/mac.cpp | 90 +++++++++++++++++++++---------- src/core/mac/mac.hpp | 8 +++ tests/unit/test_platform.cpp | 5 ++ 6 files changed, 112 insertions(+), 29 deletions(-) diff --git a/examples/platforms/cc2538/radio.c b/examples/platforms/cc2538/radio.c index 02ecf48fa..e60e5aa62 100644 --- a/examples/platforms/cc2538/radio.c +++ b/examples/platforms/cc2538/radio.c @@ -737,3 +737,11 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) HWREG(addrAutoPendEn++) = 0; } } + +ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + (void)aInstance; + (void)aScanChannel; + (void)aScanDuration; + return kThreadError_NotImplemented; +} diff --git a/examples/platforms/posix/radio.c b/examples/platforms/posix/radio.c index 28dcb0a41..a96eacad4 100644 --- a/examples/platforms/posix/radio.c +++ b/examples/platforms/posix/radio.c @@ -763,3 +763,11 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) { (void)aInstance; } + +ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + (void)aInstance; + (void)aScanChannel; + (void)aScanDuration; + return kThreadError_NotImplemented; +} diff --git a/include/platform/radio.h b/include/platform/radio.h index 97aabbf32..e11bdc9a6 100644 --- a/include/platform/radio.h +++ b/include/platform/radio.h @@ -89,6 +89,7 @@ typedef enum otRadioCaps { kRadioCapsNone = 0, ///< None kRadioCapsAckTimeout = 1, ///< Radio supports AckTime event + kRadioCapsEnergyScan = 2, ///< Radio supports Enegery Scans } otRadioCaps; /** @@ -436,6 +437,27 @@ extern void otPlatDiagRadioTransmitDone(otInstance *aInstance, bool aFramePendin */ extern void otPlatDiagRadioReceiveDone(otInstance *aInstance, RadioPacket *aPacket, ThreadError aError); +/** + * This method begins the energy scan sequence on the radio. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aScanChannel The channel to perform the energy scan on. + * @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned. + * + * @retval ::kThreadError_None Successfully started scanning the channel. + * @retval ::kThreadError_NotImplemented The radio doesn't support energy scanning. + */ +ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration); + +/** + * The radio driver calls this method to notify OpenThread that the energy scan is complete. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aEnergyScanMaxRssi The maximum RSSI encountered on the scanned channel. + * + */ +extern void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi); + /** * @} * diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index ad5482c39..a9b2be6d2 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -222,10 +222,66 @@ bool Mac::IsEnergyScanInProgress(void) void Mac::StartEnergyScan(void) { mState = kStateEnergyScan; - mEnergyScanCurrentMaxRssi = kInvalidRssiValue; - mMacTimer.Start(mScanDuration); - mEnergyScanSampleRssiTask.Post(); - NextOperation(); + + if (!(otPlatRadioGetCaps(mNetif.GetInstance()) & kRadioCapsEnergyScan)) + { + mEnergyScanCurrentMaxRssi = kInvalidRssiValue; + mMacTimer.Start(mScanDuration); + mEnergyScanSampleRssiTask.Post(); + NextOperation(); + } + else + { + ThreadError error = otPlatRadioEnergyScan(mNetif.GetInstance(), mScanChannel, mScanDuration); + + if (error != kThreadError_None) + { + // Cancel scan + mEnergyScanHandler(mScanContext, NULL); + ScheduleNextTransmission(); + } + } +} + +extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi) +{ + aInstance->mThreadNetif.GetMac().EnergyScanDone(aEnergyScanMaxRssi); +} + +void Mac::EnergyScanDone(int8_t aEnergyScanMaxRssi) +{ + // Trigger a energy scan handler callback if necessary + if (aEnergyScanMaxRssi != kInvalidRssiValue) + { + otEnergyScanResult result; + + result.mChannel = mScanChannel; + result.mMaxRssi = aEnergyScanMaxRssi; + mEnergyScanHandler(mScanContext, &result); + } + + // Update to the next scan channel + do + { + mScanChannels >>= 1; + mScanChannel++; + + // If we have scanned all the channels, then fire the final callback + // and start the next transmission task + if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel) + { + mEnergyScanHandler(mScanContext, NULL); + ScheduleNextTransmission(); + ExitNow(); + } + } + while ((mScanChannels & 1) == 0); + + // Start scanning the next channel + StartEnergyScan(); + +exit: + return; } void Mac::HandleEnergyScanSampleRssi(void *aContext) @@ -769,31 +825,7 @@ void Mac::HandleMacTimer(void) break; case kStateEnergyScan: - if (mEnergyScanCurrentMaxRssi != kInvalidRssiValue) - { - otEnergyScanResult result; - - result.mChannel = mScanChannel; - result.mMaxRssi = mEnergyScanCurrentMaxRssi; - mEnergyScanHandler(mScanContext, &result); - } - - do - { - mScanChannels >>= 1; - mScanChannel++; - - if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel) - { - mEnergyScanHandler(mScanContext, NULL); - ScheduleNextTransmission(); - ExitNow(); - } - } - while ((mScanChannels & 1) == 0); - - mEnergyScanCurrentMaxRssi = kInvalidRssiValue; - mMacTimer.Start(mScanDuration); + EnergyScanDone(mEnergyScanCurrentMaxRssi); break; case kStateTransmitData: diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 733c8a370..617484fe7 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -235,6 +235,14 @@ public: */ ThreadError EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext); + /** + * This function indicates the energy scan for the current channel is complete. + * + * @param[in] aEnergyScanMaxRssi The maximum RSSI encountered on the scanned channel. + * + */ + void EnergyScanDone(int8_t aEnergyScanMaxRssi); + /** * This method indicates whether or not rx-on-when-idle is enabled. * diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 85d554b7b..622812909 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -204,6 +204,11 @@ extern "C" { (void)aInstance; } + ThreadError otPlatRadioEnergyScan(otInstance *, uint8_t, uint16_t) + { + return kThreadError_NotImplemented; + } + // // Random //