From b795c729d3e8436eca515a431a864bbae9ee7e63 Mon Sep 17 00:00:00 2001 From: Shu Chen Date: Fri, 7 Sep 2018 14:57:38 +0800 Subject: [PATCH] [posix-app] support platform energy scan in posix-app (#3038) --- src/ncp/ncp_base.cpp | 183 +++++++++++++++++++++++++++ src/ncp/ncp_base.hpp | 5 +- src/ncp/ncp_base_dispatcher.cpp | 36 +++--- src/ncp/ncp_base_mtd.cpp | 187 ---------------------------- src/posix/platform/radio_spinel.cpp | 19 ++- src/posix/platform/radio_spinel.hpp | 13 ++ tests/unit/test_diag.cpp | 6 + 7 files changed, 236 insertions(+), 213 deletions(-) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index af636c446..d1318993c 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -52,6 +52,25 @@ namespace Ncp { // MARK: Utility Functions // ---------------------------------------------------------------------------- +#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API +static bool HasOnly1BitSet(uint32_t aValue) +{ + return aValue != 0 && ((aValue & (aValue - 1)) == 0); +} + +static uint8_t IndexOfMSB(uint32_t aValue) +{ + uint8_t index = 0; + + while (aValue >>= 1) + { + index++; + } + + return index; +} +#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API + spinel_status_t NcpBase::ThreadErrorToSpinelStatus(otError aError) { spinel_status_t ret; @@ -1475,6 +1494,170 @@ exit: return error; } +otError NcpBase::EncodeChannelMask(uint32_t aChannelMask) +{ + otError error = OT_ERROR_NONE; + + for (uint8_t i = 0; i < 32; i++) + { + if (0 != (aChannelMask & (1 << i))) + { + SuccessOrExit(error = mEncoder.WriteUint8(i)); + } + } + +exit: + return error; +} + +otError NcpBase::DecodeChannelMask(uint32_t &aChannelMask) +{ + otError error = OT_ERROR_NONE; + uint8_t channel; + + aChannelMask = 0; + + while (!mDecoder.IsAllReadInStruct()) + { + SuccessOrExit(error = mDecoder.ReadUint8(channel)); + VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS); + aChannelMask |= (1U << channel); + } + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return EncodeChannelMask(mScanChannelMask); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + uint32_t newMask = 0; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = DecodeChannelMask(newMask)); + mScanChannelMask = newMask; + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteUint16(mScanPeriod); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + return mDecoder.ReadUint16(mScanPeriod); +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + uint8_t scanState = SPINEL_SCAN_STATE_IDLE; + +#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API + + if (otLinkRawIsEnabled(mInstance)) + { + scanState = (mCurScanChannel == kInvalidScanChannel) ? SPINEL_SCAN_STATE_IDLE : SPINEL_SCAN_STATE_ENERGY; + } + else + +#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API + + { +#if OPENTHREAD_MTD || OPENTHREAD_FTD + if (otLinkIsActiveScanInProgress(mInstance)) + { + scanState = SPINEL_SCAN_STATE_BEACON; + } + else if (otLinkIsEnergyScanInProgress(mInstance)) + { + scanState = SPINEL_SCAN_STATE_ENERGY; + } + else if (otThreadIsDiscoverInProgress(mInstance)) + { + scanState = SPINEL_SCAN_STATE_DISCOVER; + } + else + { + scanState = SPINEL_SCAN_STATE_IDLE; + } +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD + } + + return mEncoder.WriteUint8(scanState); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + uint8_t state = 0; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadUint8(state)); + + switch (state) + { + case SPINEL_SCAN_STATE_IDLE: + error = OT_ERROR_NONE; + break; + +#if OPENTHREAD_MTD || OPENTHREAD_FTD + case SPINEL_SCAN_STATE_BEACON: + error = otLinkActiveScan(mInstance, mScanChannelMask, mScanPeriod, &HandleActiveScanResult_Jump, this); + SuccessOrExit(error); + break; +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD + + case SPINEL_SCAN_STATE_ENERGY: +#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API + if (otLinkRawIsEnabled(mInstance)) + { + uint8_t scanChannel; + + // Make sure we aren't already scanning and that we have + // only 1 bit set for the channel mask. + VerifyOrExit(mCurScanChannel == kInvalidScanChannel, error = OT_ERROR_INVALID_STATE); + VerifyOrExit(HasOnly1BitSet(mScanChannelMask), error = OT_ERROR_INVALID_ARGS); + + scanChannel = IndexOfMSB(mScanChannelMask); + mCurScanChannel = (int8_t)scanChannel; + + error = otLinkRawEnergyScan(mInstance, scanChannel, mScanPeriod, LinkRawEnergyScanDone); + } + else +#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API + { +#if OPENTHREAD_MTD || OPENTHREAD_FTD + error = otLinkEnergyScan(mInstance, mScanChannelMask, mScanPeriod, &HandleEnergyScanResult_Jump, this); +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD + } + + SuccessOrExit(error); + break; + +#if OPENTHREAD_MTD || OPENTHREAD_FTD + case SPINEL_SCAN_STATE_DISCOVER: + error = otThreadDiscover(mInstance, mScanChannelMask, mDiscoveryScanPanId, mDiscoveryScanJoinerFlag, + mDiscoveryScanEnableFiltering, &HandleActiveScanResult_Jump, this); + + SuccessOrExit(error); + break; +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD + + default: + error = OT_ERROR_NOT_IMPLEMENTED; + break; + } + +exit: + return error; +} + template <> otError NcpBase::HandlePropertyGet(void) { otError error = OT_ERROR_NONE; diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index e8631f6b5..f47d6daf4 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -240,6 +240,9 @@ protected: static void HandleRawFrame(const otRadioFrame *aFrame, void *aContext); void HandleRawFrame(const otRadioFrame *aFrame); + otError EncodeChannelMask(uint32_t aChannelMask); + otError DecodeChannelMask(uint32_t &aChannelMask); + #if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError); @@ -299,8 +302,6 @@ protected: static void SendDoneTask(void *aContext); void SendDoneTask(void); - otError EncodeChannelMask(uint32_t aChannelMask); - otError DecodeChannelMask(uint32_t &aChannelMask); otError EncodeOperationalDataset(const otOperationalDataset &aDataset); #if OPENTHREAD_FTD diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index cd80207d8..5d0718359 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -110,6 +110,15 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_MAC_PROMISCUOUS_MODE: handler = &NcpBase::HandlePropertyGet; break; + case SPINEL_PROP_MAC_SCAN_STATE: + handler = &NcpBase::HandlePropertyGet; + break; + case SPINEL_PROP_MAC_SCAN_MASK: + handler = &NcpBase::HandlePropertyGet; + break; + case SPINEL_PROP_MAC_SCAN_PERIOD: + handler = &NcpBase::HandlePropertyGet; + break; case SPINEL_PROP_NCP_VERSION: handler = &NcpBase::HandlePropertyGet; break; @@ -133,15 +142,6 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_MAC_EXTENDED_ADDR: handler = &NcpBase::HandlePropertyGet; break; - case SPINEL_PROP_MAC_SCAN_STATE: - handler = &NcpBase::HandlePropertyGet; - break; - case SPINEL_PROP_MAC_SCAN_MASK: - handler = &NcpBase::HandlePropertyGet; - break; - case SPINEL_PROP_MAC_SCAN_PERIOD: - handler = &NcpBase::HandlePropertyGet; - break; case SPINEL_PROP_MAC_CCA_FAILURE_RATE: handler = &NcpBase::HandlePropertyGet; break; @@ -668,6 +668,15 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_MAC_RAW_STREAM_ENABLED: handler = &NcpBase::HandlePropertySet; break; + case SPINEL_PROP_MAC_SCAN_MASK: + handler = &NcpBase::HandlePropertySet; + break; + case SPINEL_PROP_MAC_SCAN_STATE: + handler = &NcpBase::HandlePropertySet; + break; + case SPINEL_PROP_MAC_SCAN_PERIOD: + handler = &NcpBase::HandlePropertySet; + break; // -------------------------------------------------------------------------- // MTD (or FTD) Properties (Set Handler) @@ -679,15 +688,6 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_MAC_DATA_POLL_PERIOD: handler = &NcpBase::HandlePropertySet; break; - case SPINEL_PROP_MAC_SCAN_MASK: - handler = &NcpBase::HandlePropertySet; - break; - case SPINEL_PROP_MAC_SCAN_STATE: - handler = &NcpBase::HandlePropertySet; - break; - case SPINEL_PROP_MAC_SCAN_PERIOD: - handler = &NcpBase::HandlePropertySet; - break; case SPINEL_PROP_NET_IF_UP: handler = &NcpBase::HandlePropertySet; break; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 50c4f587a..012875658 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -68,27 +68,6 @@ namespace ot { namespace Ncp { -#if OPENTHREAD_ENABLE_RAW_LINK_API - -static bool HasOnly1BitSet(uint32_t aValue) -{ - return aValue != 0 && ((aValue & (aValue - 1)) == 0); -} - -static uint8_t IndexOfMSB(uint32_t aValue) -{ - uint8_t index = 0; - - while (aValue >>= 1) - { - index++; - } - - return index; -} - -#endif // OPENTHREAD_ENABLE_RAW_LINK_API - static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig) { uint8_t flags(0); @@ -2639,172 +2618,6 @@ exit: } #endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC -otError NcpBase::EncodeChannelMask(uint32_t aChannelMask) -{ - otError error = OT_ERROR_NONE; - - for (uint8_t i = 0; i < 32; i++) - { - if (0 != (aChannelMask & (1 << i))) - { - SuccessOrExit(error = mEncoder.WriteUint8(i)); - } - } - -exit: - return error; -} - -otError NcpBase::DecodeChannelMask(uint32_t &aChannelMask) -{ - otError error = OT_ERROR_NONE; - uint8_t channel; - - aChannelMask = 0; - - while (!mDecoder.IsAllReadInStruct()) - { - SuccessOrExit(error = mDecoder.ReadUint8(channel)); - VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS); - aChannelMask |= (1U << channel); - } - -exit: - return error; -} - -template <> otError NcpBase::HandlePropertyGet(void) -{ - return EncodeChannelMask(mScanChannelMask); -} - -template <> otError NcpBase::HandlePropertySet(void) -{ - uint32_t newMask = 0; - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = DecodeChannelMask(newMask)); - mScanChannelMask = newMask; - -exit: - return error; -} - -template <> otError NcpBase::HandlePropertyGet(void) -{ - return mEncoder.WriteUint16(mScanPeriod); -} - -template <> otError NcpBase::HandlePropertySet(void) -{ - return mDecoder.ReadUint16(mScanPeriod); -} - -template <> otError NcpBase::HandlePropertyGet(void) -{ - uint8_t scanState = SPINEL_SCAN_STATE_IDLE; - -#if OPENTHREAD_ENABLE_RAW_LINK_API - - if (otLinkRawIsEnabled(mInstance)) - { - scanState = (mCurScanChannel == kInvalidScanChannel) ? SPINEL_SCAN_STATE_IDLE : SPINEL_SCAN_STATE_ENERGY; - } - else - -#endif // OPENTHREAD_ENABLE_RAW_LINK_API - - { - if (otLinkIsActiveScanInProgress(mInstance)) - { - scanState = SPINEL_SCAN_STATE_BEACON; - } - else if (otLinkIsEnergyScanInProgress(mInstance)) - { - scanState = SPINEL_SCAN_STATE_ENERGY; - } - else if (otThreadIsDiscoverInProgress(mInstance)) - { - scanState = SPINEL_SCAN_STATE_DISCOVER; - } - else - { - scanState = SPINEL_SCAN_STATE_IDLE; - } - } - - return mEncoder.WriteUint8(scanState); -} - -template <> otError NcpBase::HandlePropertySet(void) -{ - uint8_t state = 0; - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = mDecoder.ReadUint8(state)); - - switch (state) - { - case SPINEL_SCAN_STATE_IDLE: - error = OT_ERROR_NONE; - break; - - case SPINEL_SCAN_STATE_BEACON: -#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API - if (otLinkRawIsEnabled(mInstance)) - { - error = OT_ERROR_NOT_IMPLEMENTED; - } - else -#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API - { - error = otLinkActiveScan(mInstance, mScanChannelMask, mScanPeriod, &HandleActiveScanResult_Jump, this); - } - - SuccessOrExit(error); - break; - - case SPINEL_SCAN_STATE_ENERGY: -#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API - if (otLinkRawIsEnabled(mInstance)) - { - uint8_t scanChannel; - - // Make sure we aren't already scanning and that we have - // only 1 bit set for the channel mask. - VerifyOrExit(mCurScanChannel == kInvalidScanChannel, error = OT_ERROR_INVALID_STATE); - VerifyOrExit(HasOnly1BitSet(mScanChannelMask), error = OT_ERROR_INVALID_ARGS); - - scanChannel = IndexOfMSB(mScanChannelMask); - mCurScanChannel = (int8_t)scanChannel; - - error = otLinkRawEnergyScan(mInstance, scanChannel, mScanPeriod, LinkRawEnergyScanDone); - } - else -#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API - { - error = otLinkEnergyScan(mInstance, mScanChannelMask, mScanPeriod, &HandleEnergyScanResult_Jump, this); - } - - SuccessOrExit(error); - break; - - case SPINEL_SCAN_STATE_DISCOVER: - error = otThreadDiscover(mInstance, mScanChannelMask, mDiscoveryScanPanId, mDiscoveryScanJoinerFlag, - mDiscoveryScanEnableFiltering, &HandleActiveScanResult_Jump, this); - - SuccessOrExit(error); - break; - - default: - error = OT_ERROR_INVALID_ARGS; - break; - } - -exit: - return error; -} - void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext) { static_cast(aContext)->HandleActiveScanResult(aResult); diff --git a/src/posix/platform/radio_spinel.cpp b/src/posix/platform/radio_spinel.cpp index e2757faa0..f7e8e1f77 100644 --- a/src/posix/platform/radio_spinel.cpp +++ b/src/posix/platform/radio_spinel.cpp @@ -618,9 +618,7 @@ void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, unpacked = spinel_datatype_unpack(aBuffer, aLength, "Cc", &scanChannel, &maxRssi); VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE); -#if !OPENTHREAD_ENABLE_DIAG otPlatRadioEnergyScanDone(mInstance, maxRssi); -#endif } else if (aKey == SPINEL_PROP_STREAM_DEBUG) { @@ -927,6 +925,18 @@ otError RadioSpinel::SetTransmitPower(int8_t aPower) return error; } +otError RadioSpinel::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration) +{ + otError error; + + SuccessOrExit(error = Set(SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_DATA_S, &aScanChannel, sizeof(uint8_t))); + SuccessOrExit(error = Set(SPINEL_PROP_MAC_SCAN_PERIOD, SPINEL_DATATYPE_UINT16_S, aScanDuration)); + SuccessOrExit(error = Set(SPINEL_PROP_MAC_SCAN_STATE, SPINEL_DATATYPE_UINT8_S, SPINEL_SCAN_STATE_ENERGY)); + +exit: + return error; +} + otError RadioSpinel::Get(spinel_prop_key_t aKey, const char *aFormat, ...) { otError error; @@ -1607,10 +1617,7 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aScanChannel); - OT_UNUSED_VARIABLE(aScanDuration); - - return OT_ERROR_NOT_IMPLEMENTED; + return sRadioSpinel.EnergyScan(aScanChannel, aScanDuration); } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) diff --git a/src/posix/platform/radio_spinel.hpp b/src/posix/platform/radio_spinel.hpp index f20f30dd9..e5e3a95a5 100644 --- a/src/posix/platform/radio_spinel.hpp +++ b/src/posix/platform/radio_spinel.hpp @@ -278,6 +278,19 @@ public: */ otError ClearSrcMatchExtEntries(void); + /** + * This method begins the energy scan sequence on the radio. + * + * @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 OT_ERROR_NONE Succeeded. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. + * + */ + otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration); + /** * This method switches the radio state from Receive to Transmit. * diff --git a/tests/unit/test_diag.cpp b/tests/unit/test_diag.cpp index 685635100..0f8528749 100644 --- a/tests/unit/test_diag.cpp +++ b/tests/unit/test_diag.cpp @@ -84,6 +84,12 @@ extern "C" void otPlatRadioTxStarted(otInstance *, otRadioFrame *aFrame) (void)aFrame; } +extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi) +{ + (void)aInstance; + (void)aEnergyScanMaxRssi; +} + /** * Converts a given string replacing '\n', '\r', '\t', etc. with literal strings "\n", "\r", "\t", etc. to make it * printable on console.