diff --git a/include/openthread.h b/include/openthread.h index 5e7941806..cc80d386e 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -325,7 +325,7 @@ typedef void (*otHandleEnergyScanResult)(otEnergyScanResult *aResult, void *aCon * @param[in] aCallbackContext A pointer to application-specific context. * * @retval kThreadError_None Accepted the Energy Scan request. - * @retval kThreadError_Busy Already performing an Active Scan. + * @retval kThreadError_Busy Could not start the energy scan. * */ ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 4711ccfc2..1c3fe3bc9 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -80,6 +80,7 @@ Mac::Mac(ThreadNetif &aThreadNetif): mKeyManager(aThreadNetif.GetKeyManager()), mMle(aThreadNetif.GetMle()), mNetif(aThreadNetif), + mEnergyScanSampleRssiTask(aThreadNetif.GetIp6().mTaskletScheduler, &HandleEnergyScanSampleRssi, this), mWhitelist(), mBlacklist() { @@ -92,12 +93,14 @@ Mac::Mac(ThreadNetif &aThreadNetif): mTransmitAttempts = 0; mTransmitBeacon = false; - mActiveScanRequest = false; + mPendingScanRequest = kScanTypeNone; mScanChannel = kPhyMinChannel; mScanChannels = 0xff; mScanDuration = 0; + mScanContext = NULL; mActiveScanHandler = NULL; - mActiveScanContext = NULL; + mEnergyScanHandler = NULL; + mEnergyScanCurrentMaxRssi = kInvalidRssiValue; mSendHead = NULL; mSendTail = NULL; @@ -134,13 +137,35 @@ Mac::Mac(ThreadNetif &aThreadNetif): } ThreadError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext) +{ + ThreadError error; + + SuccessOrExit(error = Scan(kScanTypeActive, aScanChannels, aScanDuration, aContext)); + mActiveScanHandler = aHandler; + +exit: + return error; +} + +ThreadError Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext) +{ + ThreadError error; + + SuccessOrExit(error = Scan(kScanTypeEnergy, aScanChannels, aScanDuration, aContext)); + mEnergyScanHandler = aHandler; + +exit: + return error; +} + +ThreadError Mac::Scan(ScanType aScanType, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext) { ThreadError error = kThreadError_None; - VerifyOrExit(mState != kStateActiveScan && mActiveScanRequest == false, error = kThreadError_Busy); + VerifyOrExit((mState != kStateActiveScan) && (mState != kStateEnergyScan) && (mPendingScanRequest == kScanTypeNone), + error = kThreadError_Busy); - mActiveScanHandler = aHandler; - mActiveScanContext = aContext; + mScanContext = aContext; mScanChannels = (aScanChannels == 0) ? static_cast(kScanChannelsAll) : aScanChannels; mScanDuration = (aScanDuration == 0) ? static_cast(kScanDurationDefault) : aScanDuration; @@ -155,12 +180,19 @@ ThreadError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, Acti if (mState == kStateIdle) { - mState = kStateActiveScan; - StartCsmaBackoff(); + if (aScanType == kScanTypeActive) + { + mState = kStateActiveScan; + StartCsmaBackoff(); + } + else if (aScanType == kScanTypeEnergy) + { + StartEnergyScan(); + } } else { - mActiveScanRequest = true; + mPendingScanRequest = aScanType; } exit: @@ -169,7 +201,49 @@ exit: bool Mac::IsActiveScanInProgress(void) { - return (mState == kStateActiveScan) || mActiveScanRequest; + return (mState == kStateActiveScan) || (mPendingScanRequest == kScanTypeActive); +} + +bool Mac::IsEnergyScanInProgress(void) +{ + return (mState == kStateEnergyScan) || (mPendingScanRequest == kScanTypeEnergy); +} + +void Mac::StartEnergyScan(void) +{ + mState = kStateEnergyScan; + mEnergyScanCurrentMaxRssi = kInvalidRssiValue; + mAckTimer.Start(mScanDuration); + mEnergyScanSampleRssiTask.Post(); + NextOperation(); +} + +void Mac::HandleEnergyScanSampleRssi(void *aContext) +{ + Mac *obj = static_cast(aContext); + obj->HandleEnergyScanSampleRssi(); +} + +void Mac::HandleEnergyScanSampleRssi(void) +{ + int8_t rssi; + + VerifyOrExit(mState == kStateEnergyScan, ;); + + rssi = otPlatRadioGetRssi(NULL); + + if (rssi != kInvalidRssiValue) + { + if ((mEnergyScanCurrentMaxRssi == kInvalidRssiValue) || (rssi > mEnergyScanCurrentMaxRssi)) + { + mEnergyScanCurrentMaxRssi = rssi; + } + } + + mEnergyScanSampleRssiTask.Post(); + +exit: + return; } ThreadError Mac::RegisterReceiver(Receiver &aReceiver) @@ -329,6 +403,7 @@ void Mac::NextOperation(void) switch (mState) { case kStateActiveScan: + case kStateEnergyScan: otPlatRadioReceive(NULL, mScanChannel); break; @@ -348,12 +423,17 @@ void Mac::NextOperation(void) void Mac::ScheduleNextTransmission(void) { - if (mActiveScanRequest) + if (mPendingScanRequest == kScanTypeActive) { - mActiveScanRequest = false; + mPendingScanRequest = kScanTypeNone; mState = kStateActiveScan; StartCsmaBackoff(); } + else if (mPendingScanRequest == kScanTypeEnergy) + { + mPendingScanRequest = kScanTypeNone; + StartEnergyScan(); + } else if (mTransmitBeacon) { mTransmitBeacon = false; @@ -634,7 +714,7 @@ void Mac::HandleAckTimer(void) if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel) { - mActiveScanHandler(mActiveScanContext, NULL); + mActiveScanHandler(mScanContext, NULL); ScheduleNextTransmission(); ExitNow(); } @@ -644,6 +724,34 @@ void Mac::HandleAckTimer(void) StartCsmaBackoff(); 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; + mAckTimer.Start(mScanDuration); + break; + case kStateTransmitData: otLogDebgMac("ack timer fired\n"); mCounters.mTxTotal++; @@ -981,7 +1089,7 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) if (aFrame->GetType() == Frame::kFcfFrameBeacon) { mCounters.mRxBeacon++; - mActiveScanHandler(mActiveScanContext, aFrame); + mActiveScanHandler(mScanContext, aFrame); } else { diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 22778fba6..e1b5da78b 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -210,6 +210,30 @@ public: */ ThreadError ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext); + /** + * This function pointer is called during an "Energy Scan" when the result for a channel is ready or the scan + * completes. + * + * @param[in] aResult A valid pointer to the energy scan result information or NULL when the energy scan completes. + * @param[in] aContext A pointer to arbitrary context information. + * + */ + typedef void (*EnergyScanHandler)(void *aContext, otEnergyScanResult *aResult); + + /** + * This function starts an IEEE 802.15.4 Energy Scan. + * + * @param[in] aScanChannels A bit vector indicating on which channels to perform energy scan. + * @param[in] aScanDuration The time in milliseconds to spend scanning each channel. + * @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. + * + * @retval kThreadError_None Accepted the Energy Scan request. + * @retval kThreadError_Busy Could not start the energy scan. + * + */ + ThreadError EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext); + /** * This method indicates whether or not rx-on-when-idle is enabled. * @@ -416,6 +440,12 @@ public: */ bool IsActiveScanInProgress(void); + /** + * This method returns if an energy scan is in progress. + * + */ + bool IsEnergyScanInProgress(void); + /** * This function registers a callback to provide received raw IEEE 802.15.4 frames. * @@ -462,6 +492,18 @@ public: LinkQualityInfo &GetNoiseFloor(void) { return mNoiseFloor; } private: + enum ScanType + { + kScanTypeNone = 0, + kScanTypeActive, + kScanTypeEnergy, + }; + + enum + { + kInvalidRssiValue = 127 + }; + void GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce); void NextOperation(void); void ProcessTransmitSecurity(Frame &aFrame); @@ -471,6 +513,7 @@ private: void SendBeaconRequest(Frame &aFrame); void SendBeacon(Frame &aFrame); void StartBackoff(void); + void StartEnergyScan(void); ThreadError HandleMacCommand(Frame &aFrame); static void HandleAckTimer(void *aContext); @@ -479,8 +522,11 @@ private: void HandleBeginTransmit(void); static void HandleReceiveTimer(void *aContext); void HandleReceiveTimer(void); + static void HandleEnergyScanSampleRssi(void *aContext); + void HandleEnergyScanSampleRssi(void); void StartCsmaBackoff(void); + ThreadError Scan(ScanType aType, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext); Tasklet mBeginTransmit; Timer mAckTimer; @@ -507,6 +553,7 @@ private: { kStateIdle = 0, kStateActiveScan, + kStateEnergyScan, kStateTransmitBeacon, kStateTransmitData, }; @@ -519,12 +566,18 @@ private: uint8_t mTransmitAttempts; bool mTransmitBeacon; - bool mActiveScanRequest; + ScanType mPendingScanRequest; uint8_t mScanChannel; uint32_t mScanChannels; uint16_t mScanDuration; - ActiveScanHandler mActiveScanHandler; - void *mActiveScanContext; + void *mScanContext; + union + { + ActiveScanHandler mActiveScanHandler; + EnergyScanHandler mEnergyScanHandler; + }; + int8_t mEnergyScanCurrentMaxRssi; + Tasklet mEnergyScanSampleRssiTask; LinkQualityInfo mNoiseFloor; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 7c1441423..cca425112 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -84,6 +84,7 @@ extern "C" { static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t); static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame); +static void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult); static void HandleMleDiscover(otActiveScanResult *aResult, void *aContext); static otHandleActiveScanResult sActiveScanCallback = NULL; @@ -1063,23 +1064,28 @@ exit: return; } -ThreadError otEnergyScan(otInstance *, uint32_t aScanChannels, uint16_t aScanDuration, +ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, otHandleEnergyScanResult aCallback, void *aCallbackContext) { sEnergyScanCallback = aCallback; sEnergyScanCallbackContext = aCallbackContext; - - (void)aScanChannels; - (void)aScanDuration; - - // TODO: Implement the energy scan at mac layer. - - return kThreadError_NotImplemented; + return sThreadNetif->GetMac().EnergyScan(aScanChannels, aScanDuration, &HandleEnergyScanResult, aInstance); } -bool otIsEnegyScanInProgress(otInstance *) +void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult) { - return false; + otInstance *aInstance = static_cast(aContext); + + sEnergyScanCallback(aResult, sEnergyScanCallbackContext); + + (void)aInstance; +} + + +bool otIsEnergyScanInProgress(otInstance *aInstance) +{ + (void)aInstance; + return sThreadNetif->GetMac().IsEnergyScanInProgress(); } ThreadError otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId, diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index d84420543..7e756daed 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -1143,7 +1143,7 @@ ThreadError NcpBase::CommandHandler_RESET(uint8_t header, unsigned int command, // We only get to this point if the // platform doesn't support resetting. // In such a case we fake it. - + otThreadStop(mInstance); otInterfaceDown(mInstance); @@ -1465,6 +1465,16 @@ ThreadError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_pr SPINEL_SCAN_STATE_BEACON ); } + else if (otIsEnergyScanInProgress(mInstance)) + { + errorCode = SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_UINT8_S, + SPINEL_SCAN_STATE_ENERGY + ); + } else { errorCode = SendPropertyUpdate( @@ -3173,7 +3183,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t header, spin (void)meta_ptr; (void)meta_len; (void)parsedLength; - + errorCode = otAppendMessage(message, frame_ptr, static_cast(frame_len)); } @@ -3218,7 +3228,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t header, spinel_prop_k unsigned int frame_len(0); const uint8_t *meta_ptr(NULL); unsigned int meta_len(0); - + // STREAM_NET requires layer 2 security. otMessage message = otNewIp6Message(mInstance, true); @@ -3243,7 +3253,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t header, spinel_prop_k (void)meta_ptr; (void)meta_len; (void)parsedLength; - + errorCode = otAppendMessage(message, frame_ptr, static_cast(frame_len)); }