From 3b362071e594375035e063c0c25988b1aa52bd5f Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Thu, 18 Jun 2020 05:42:39 +0800 Subject: [PATCH] [link-raw] set receive done callback when enabled (#5108) --- examples/platforms/simulation/radio.c | 4 +- examples/platforms/simulation/system.c | 27 ++++-- include/openthread/instance.h | 2 +- include/openthread/link_raw.h | 33 +++---- src/core/api/link_raw_api.cpp | 8 +- src/core/mac/link_raw.cpp | 12 +-- src/core/mac/link_raw.hpp | 15 ++- src/ncp/ncp_base.cpp | 4 +- src/ncp/ncp_base_radio.cpp | 18 +--- .../scripts/expect/posix-scan-tx-to-sleep.exp | 93 +++++++++++++++++++ 10 files changed, 154 insertions(+), 62 deletions(-) create mode 100755 tests/scripts/expect/posix-scan-tx-to-sleep.exp diff --git a/examples/platforms/simulation/radio.c b/examples/platforms/simulation/radio.c index 1145c4d9c..1829f4143 100644 --- a/examples/platforms/simulation/radio.c +++ b/examples/platforms/simulation/radio.c @@ -117,6 +117,8 @@ static bool sSrcMatchEnabled = false; static bool sRadioCoexEnabled = true; #endif +otRadioCaps gRadioCaps = OT_RADIO_CAPS_NONE; + static void ReverseExtAddress(otExtAddress *aReversed, const otExtAddress *aOrigin) { for (size_t i = 0; i < sizeof(*aReversed); i++) @@ -462,7 +464,7 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) assert(aInstance != NULL); - return OT_RADIO_CAPS_NONE; + return gRadioCaps; } bool otPlatRadioGetPromiscuous(otInstance *aInstance) diff --git a/examples/platforms/simulation/system.c b/examples/platforms/simulation/system.c index f929870e0..993b3f9fa 100644 --- a/examples/platforms/simulation/system.c +++ b/examples/platforms/simulation/system.c @@ -47,10 +47,12 @@ #include #include +#include uint32_t gNodeId = 1; -extern bool gPlatformPseudoResetWasRequested; +extern bool gPlatformPseudoResetWasRequested; +extern otRadioCaps gRadioCaps; static volatile bool gTerminate = false; @@ -65,6 +67,7 @@ void otSysInit(int aArgCount, char *aArgVector[]) { char * endptr; uint32_t speedUpFactor = 1; + int argIndex = 0; if (gPlatformPseudoResetWasRequested) { @@ -74,31 +77,39 @@ void otSysInit(int aArgCount, char *aArgVector[]) if (aArgCount < 2) { - fprintf(stderr, "Syntax:\n %s NodeId [TimeSpeedUpFactor]\n", aArgVector[0]); + fprintf(stderr, "Syntax:\n %s [--sleep-to-tx] NodeId [TimeSpeedUpFactor]\n", aArgVector[0]); exit(EXIT_FAILURE); } - openlog(basename(aArgVector[0]), LOG_PID, LOG_USER); + openlog(basename(aArgVector[argIndex++]), LOG_PID, LOG_USER); setlogmask(setlogmask(0) & LOG_UPTO(LOG_NOTICE)); signal(SIGTERM, &handleSignal); signal(SIGHUP, &handleSignal); - gNodeId = (uint32_t)strtol(aArgVector[1], &endptr, 0); + if (!strcmp(aArgVector[argIndex], "--sleep-to-tx")) + { + gRadioCaps |= OT_RADIO_CAPS_SLEEP_TO_TX; + ++argIndex; + } + + gNodeId = (uint32_t)strtol(aArgVector[argIndex], &endptr, 0); if (*endptr != '\0' || gNodeId < 1 || gNodeId >= WELLKNOWN_NODE_ID) { - fprintf(stderr, "Invalid NodeId: %s\n", aArgVector[1]); + fprintf(stderr, "Invalid NodeId: %s\n", aArgVector[argIndex]); exit(EXIT_FAILURE); } - if (aArgCount > 2) + ++argIndex; + + if (aArgCount > argIndex) { - speedUpFactor = (uint32_t)strtol(aArgVector[2], &endptr, 0); + speedUpFactor = (uint32_t)strtol(aArgVector[argIndex], &endptr, 0); if (*endptr != '\0' || speedUpFactor == 0) { - fprintf(stderr, "Invalid value for TimerSpeedUpFactor: %s\n", aArgVector[2]); + fprintf(stderr, "Invalid value for TimerSpeedUpFactor: %s\n", aArgVector[argIndex]); exit(EXIT_FAILURE); } } diff --git a/include/openthread/instance.h b/include/openthread/instance.h index bbb994d6d..38f354f6a 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (6) +#define OPENTHREAD_API_VERSION (7) /** * @addtogroup api-instance diff --git a/include/openthread/link_raw.h b/include/openthread/link_raw.h index f6d5199db..24626d272 100644 --- a/include/openthread/link_raw.h +++ b/include/openthread/link_raw.h @@ -51,17 +51,30 @@ extern "C" { * */ +/** + * This function pointer on receipt of a IEEE 802.15.4 frame. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aFrame A pointer to the received frame or NULL if the receive operation was aborted. + * @param[in] aError OT_ERROR_NONE when successfully received a frame. + * OT_ERROR_ABORT when reception was aborted and a frame was not received. + * + */ +typedef void (*otLinkRawReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, otError aError); + /** * This function enables/disables the raw link-layer. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aEnabled TRUE to enable raw link-layer, FALSE otherwise. + * @param[in] aCallback A pointer to a function called on receipt of a IEEE 802.15.4 frame. NULL to disable the + * raw-link layer. * - * @retval OT_ERROR_NONE If the enable state was successfully set. + * @retval OT_ERROR_FAILED The radio could not be enabled/disabled. * @retval OT_ERROR_INVALID_STATE If the OpenThread Ip6 interface is already enabled. + * @retval OT_ERROR_NONE If the enable state was successfully set. * */ -otError otLinkRawSetEnable(otInstance *aInstance, bool aEnabled); +otError otLinkRawSetReceiveDone(otInstance *aInstance, otLinkRawReceiveDone aCallback); /** * This function indicates whether or not the raw link-layer is enabled. @@ -122,29 +135,17 @@ otError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddress); */ otError otLinkRawSleep(otInstance *aInstance); -/** - * This function pointer on receipt of a IEEE 802.15.4 frame. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aFrame A pointer to the received frame or NULL if the receive operation was aborted. - * @param[in] aError OT_ERROR_NONE when successfully received a frame. - * OT_ERROR_ABORT when reception was aborted and a frame was not received. - * - */ -typedef void (*otLinkRawReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, otError aError); - /** * Transitioning the radio from Sleep to Receive. * Turn on the radio. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aCallback A pointer to a function called on receipt of a IEEE 802.15.4 frame. * * @retval OT_ERROR_NONE Successfully transitioned to Receive. * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting. * */ -otError otLinkRawReceive(otInstance *aInstance, otLinkRawReceiveDone aCallback); +otError otLinkRawReceive(otInstance *aInstance); /** * The radio transitions from Transmit to Receive. diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp index e753606cd..98d67d063 100644 --- a/src/core/api/link_raw_api.cpp +++ b/src/core/api/link_raw_api.cpp @@ -50,9 +50,9 @@ using namespace ot; -otError otLinkRawSetEnable(otInstance *aInstance, bool aEnabled) +otError otLinkRawSetReceiveDone(otInstance *aInstance, otLinkRawReceiveDone aCallback) { - return static_cast(aInstance)->Get().SetEnabled(aEnabled); + return static_cast(aInstance)->Get().SetReceiveDone(aCallback); } bool otLinkRawIsEnabled(otInstance *aInstance) @@ -95,9 +95,9 @@ exit: return error; } -otError otLinkRawReceive(otInstance *aInstance, otLinkRawReceiveDone aCallback) +otError otLinkRawReceive(otInstance *aInstance) { - return static_cast(aInstance)->Get().Receive(aCallback); + return static_cast(aInstance)->Get().Receive(); } otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance) diff --git a/src/core/mac/link_raw.cpp b/src/core/mac/link_raw.cpp index 2e0e420dd..1eea09f29 100644 --- a/src/core/mac/link_raw.cpp +++ b/src/core/mac/link_raw.cpp @@ -51,7 +51,6 @@ namespace Mac { LinkRaw::LinkRaw(Instance &aInstance) : InstanceLocator(aInstance) - , mEnabled(false) , mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL) , mPanId(kPanIdBroadcast) , mReceiveDoneCallback(NULL) @@ -65,17 +64,17 @@ LinkRaw::LinkRaw(Instance &aInstance) { } -otError LinkRaw::SetEnabled(bool aEnabled) +otError LinkRaw::SetReceiveDone(otLinkRawReceiveDone aCallback) { otError error = OT_ERROR_NONE; - otLogDebgMac("LinkRaw::Enabled(%s)", aEnabled ? "true" : "false"); + otLogDebgMac("LinkRaw::Enabled(%s)", (aCallback != NULL ? "true" : "false")); #if OPENTHREAD_MTD || OPENTHREAD_FTD VerifyOrExit(!Get().IsUp(), error = OT_ERROR_INVALID_STATE); #endif - if (aEnabled) + if (aCallback) { SuccessOrExit(error = mSubMac.Enable()); } @@ -84,7 +83,7 @@ otError LinkRaw::SetEnabled(bool aEnabled) IgnoreError(mSubMac.Disable()); } - mEnabled = aEnabled; + mReceiveDoneCallback = aCallback; exit: return error; @@ -135,14 +134,13 @@ exit: return error; } -otError LinkRaw::Receive(otLinkRawReceiveDone aCallback) +otError LinkRaw::Receive(void) { otError error = OT_ERROR_NONE; VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE); SuccessOrExit(error = mSubMac.Receive(mReceiveChannel)); - mReceiveDoneCallback = aCallback; exit: return error; diff --git a/src/core/mac/link_raw.hpp b/src/core/mac/link_raw.hpp index fcd9a1229..4bcec7772 100644 --- a/src/core/mac/link_raw.hpp +++ b/src/core/mac/link_raw.hpp @@ -71,19 +71,21 @@ public: * @returns true if enabled, false otherwise. * */ - bool IsEnabled(void) const { return mEnabled; } + bool IsEnabled(void) const { return mReceiveDoneCallback != NULL; } /** * This method enables/disables the raw link-layer. * - * @param[in] aEnabled Whether enable raw link-layer. + * @param[in] aCallback A pointer to a function called on receipt of a IEEE 802.15.4 frame, NULL to disable + * raw link-layer. + * * * @retval OT_ERROR_INVALID_STATE Thread stack is enabled. - * @retval OT_ERROR_FAILED The radio could not be enabled. + * @retval OT_ERROR_FAILED The radio could not be enabled/disabled. * @retval OT_ERROR_NONE Successfully enabled/disabled raw link. * */ - otError SetEnabled(bool aEnabled); + otError SetReceiveDone(otLinkRawReceiveDone aCallback); /** * This method returns the capabilities of the raw link-layer. @@ -96,13 +98,11 @@ public: /** * This method starts a (recurring) Receive on the link-layer. * - * @param[in] aCallback A pointer to a function called on receipt of a IEEE 802.15.4 frame. - * * @retval OT_ERROR_NONE Successfully transitioned to Receive. * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting. * */ - otError Receive(otLinkRawReceiveDone aCallback); + otError Receive(void); /** * This method invokes the mReceiveDoneCallback, if set. @@ -302,7 +302,6 @@ public: #endif private: - bool mEnabled; uint8_t mReceiveChannel; PanId mPanId; otLinkRawReceiveDone mReceiveDoneCallback; diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index fccf96f31..7e1c6b6c2 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -1361,7 +1361,7 @@ template <> otError NcpBase::HandlePropertySet(void) // stream enabled already if (otLinkRawIsEnabled(mInstance) && mIsRawStreamEnabled) { - error = otLinkRawReceive(mInstance, &NcpBase::LinkRawReceiveDone); + error = otLinkRawReceive(mInstance); } #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE @@ -1462,7 +1462,7 @@ template <> otError NcpBase::HandlePropertySet otError NcpBase::HandlePropertySet(void) if (value == false) { - // If we have raw stream enabled stop receiving - if (mIsRawStreamEnabled) - { - IgnoreError(otLinkRawSleep(mInstance)); - } - - error = otLinkRawSetEnable(mInstance, false); + error = otLinkRawSetReceiveDone(mInstance, NULL); } else { - error = otLinkRawSetEnable(mInstance, true); - - // If we have raw stream enabled already, start receiving - if (error == OT_ERROR_NONE && mIsRawStreamEnabled) - { - error = otLinkRawReceive(mInstance, &NcpBase::LinkRawReceiveDone); - } + error = otLinkRawSetReceiveDone(mInstance, &NcpBase::LinkRawReceiveDone); } exit: diff --git a/tests/scripts/expect/posix-scan-tx-to-sleep.exp b/tests/scripts/expect/posix-scan-tx-to-sleep.exp new file mode 100755 index 000000000..ee6357056 --- /dev/null +++ b/tests/scripts/expect/posix-scan-tx-to-sleep.exp @@ -0,0 +1,93 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2020, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + +set timeout 1 + +spawn $env(OT_COMMAND) "spinel+hdlc+uart://$env(RCP_COMMAND)?forkpty-arg=--sleep-to-tx 1" +set node_1 $spawn_id +expect_after { + timeout { exit 1 } +} + +send "dataset init new\n" +expect "Done" +send "dataset panid 0xface\n" +expect "Done" +send "dataset commit active\n" +expect "Done" +send "ifconfig up\n" +expect "Done" +send "thread start\n" +expect "Done" +wait_for "state" "leader" + +send "extaddr\n" +expect "extaddr" +expect -re {([0-9a-f]{16})} +set extaddr $expect_out(1,string) +expect "Done" +send "panid\n" +expect "panid" +expect -re {([0-9a-f]{4})} +set pan $expect_out(1,string) +expect "Done" +send "extpanid\n" +expect "extpanid" +expect -re {([0-9a-f]{16})} +set extpan $expect_out(1,string) +expect "Done" +send "networkname\n" +expect "networkname" +expect -re {[\r\n]([^\r\n]+)[\r\n]} +set network $expect_out(1,string) +expect "Done" +send "channel\n" +expect "channel" +expect -re {(\d+)} +set channel $expect_out(1,string) +expect "Done" + +spawn $env(OT_COMMAND) "spinel+hdlc+uart://$env(RCP_COMMAND)?forkpty-arg=--sleep-to-tx 2" +set node_2 $spawn_id +expect_after { + timeout { exit 1 } +} + +send "scan\n" +expect "| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |" +expect "+---+------------------+------------------+------+------------------+----+-----+-----+" +wait_for "" "\\| \\d \\| $network +\\| $extpan \\| $pan \\| $extaddr \\| +$channel \\| +-?\\d+ \\| +\\d \\|" +wait_for "" "Done" + +dispose + +set spawn_id $node_1 +dispose