diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index ee8312f0c..677951c80 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -57,6 +57,7 @@ namespace Thread static NcpBase *sNcpContext = NULL; +#define NCP_INVALID_SCAN_CHANNEL (-1) #define NCP_PLAT_RESET_REASON (1U<<31) #define NCP_ON_MESH_NETS_CHANGED_BIT_FLAG (1U<<30) @@ -491,6 +492,7 @@ NcpBase::NcpBase(otInstance *aInstance): #if OPENTHREAD_ENABLE_RAW_LINK_API mCurTransmitTID(0), mCurReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL), + mCurScanChannel(NCP_INVALID_SCAN_CHANNEL), #endif // OPENTHREAD_ENABLE_RAW_LINK_API mFramingErrorCounter(0), @@ -850,6 +852,40 @@ void NcpBase::LinkRawTransmitDone(RadioPacket *, bool aFramePending, ThreadError otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); } +void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi) +{ + sNcpContext->LinkRawEnergyScanDone(aEnergyScanMaxRssi); +} + +void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi) +{ + SendPropertyUpdate( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_MAC_ENERGY_SCAN_RESULT, + "Cc", + mCurScanChannel, + aEnergyScanMaxRssi + ); + + // Clear current scan channel + mCurScanChannel = NCP_INVALID_SCAN_CHANNEL; + + // Make sure we are back listening on the original receive channel, + // since the energy scan could have been on a different channel. + otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); + + // We are finished with the scan, so send out + // a property update indicating such. + SendPropertyUpdate( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_MAC_SCAN_STATE, + SPINEL_DATATYPE_UINT8_S, + SPINEL_SCAN_STATE_IDLE + ); +} + #endif // OPENTHREAD_ENABLE_RAW_LINK_API // ---------------------------------------------------------------------------- @@ -1798,6 +1834,21 @@ ThreadError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_pr { ThreadError errorCode = kThreadError_None; +#if OPENTHREAD_ENABLE_RAW_LINK_API + if (otLinkRawIsEnabled(mInstance)) + { + errorCode = SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_UINT8_S, + mCurScanChannel == NCP_INVALID_SCAN_CHANNEL ? + SPINEL_SCAN_STATE_IDLE : + SPINEL_SCAN_STATE_ENERGY + ); + } + else +#endif // OPENTHREAD_ENABLE_RAW_LINK_API if (otIsActiveScanInProgress(mInstance)) { errorCode = SendPropertyUpdate( @@ -3460,6 +3511,21 @@ ThreadError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t header return errorCode; } +bool HasOnly1BitSet(uint32_t aValue) +{ + return aValue != 0 && ((aValue & (aValue-1)) == 0); +} + +uint8_t IndexOfMSB(uint32_t aValue) +{ + uint8_t index = 0; + while (aValue >>= 1) + { + index++; + } + return index; +} + ThreadError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { @@ -3483,13 +3549,22 @@ ThreadError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_pr break; case SPINEL_SCAN_STATE_BEACON: - errorCode = otActiveScan( - mInstance, - mChannelMask, - mScanPeriod, - &HandleActiveScanResult_Jump, - this - ); +#if OPENTHREAD_ENABLE_RAW_LINK_API + if (otLinkRawIsEnabled(mInstance)) + { + errorCode = kThreadError_NotImplemented; + } + else +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + { + errorCode = otActiveScan( + mInstance, + mChannelMask, + mScanPeriod, + &HandleActiveScanResult_Jump, + this + ); + } if (errorCode == kThreadError_None) { @@ -3499,13 +3574,46 @@ ThreadError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_pr break; case SPINEL_SCAN_STATE_ENERGY: - errorCode = otEnergyScan( - mInstance, - mChannelMask, - mScanPeriod, - &HandleEnergyScanResult_Jump, - this - ); +#if OPENTHREAD_ENABLE_RAW_LINK_API + if (otLinkRawIsEnabled(mInstance)) + { + // Make sure we aren't already scanning and that we have + // only 1 bit set for the channel mask. + if (mCurScanChannel == NCP_INVALID_SCAN_CHANNEL) + { + if (HasOnly1BitSet(mChannelMask)) + { + uint8_t scanChannel = IndexOfMSB(mChannelMask); + mCurScanChannel = (int8_t)scanChannel; + + errorCode = otLinkRawEnergyScan( + mInstance, + scanChannel, + mScanPeriod, + LinkRawEnergyScanDone + ); + } + else + { + errorCode = kThreadError_InvalidArgs; + } + } + else + { + errorCode = kThreadError_InvalidState; + } + } + else +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + { + errorCode = otEnergyScan( + mInstance, + mChannelMask, + mScanPeriod, + &HandleEnergyScanResult_Jump, + this + ); + } if (errorCode == kThreadError_None) { diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index a353e7504..e0080f8f8 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -205,6 +205,13 @@ private: void LinkRawTransmitDone(RadioPacket *aPacket, bool aFramePending, ThreadError aError); + /** + * Trampoline for LinkRawEnergyScanDone(). + */ + static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi); + + void LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi); + #endif // OPENTHREAD_ENABLE_RAW_LINK_API static void HandleNetifStateChanged(uint32_t flags, void *context); @@ -554,6 +561,7 @@ private: #if OPENTHREAD_ENABLE_RAW_LINK_API uint8_t mCurTransmitTID; uint8_t mCurReceiveChannel; + int8_t mCurScanChannel; #endif // OPENTHREAD_ENABLE_RAW_LINK_API uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames.