From 5c08fb8e3b60d77211c4426a3026900b588b4231 Mon Sep 17 00:00:00 2001 From: Shu Chen Date: Wed, 12 Sep 2018 23:42:19 +0800 Subject: [PATCH] [diags] support platform specific diags in radio-only ncp (#3024) --- Android.mk | 1 - src/core/api/link_raw_api.cpp | 84 ++++++++++++++++++++---- src/posix/platform/Makefile.am | 1 - src/posix/platform/diag.c | 88 ------------------------- src/posix/platform/radio_spinel.cpp | 99 +++++++++++++++++++++++++++++ src/posix/platform/radio_spinel.hpp | 38 +++++++++++ 6 files changed, 210 insertions(+), 101 deletions(-) delete mode 100644 src/posix/platform/diag.c diff --git a/Android.mk b/Android.mk index 7a925ac36..6aac0720a 100644 --- a/Android.mk +++ b/Android.mk @@ -178,7 +178,6 @@ LOCAL_SRC_FILES := \ src/ncp/spinel_decoder.cpp \ src/ncp/spinel_encoder.cpp \ src/posix/platform/alarm.c \ - src/posix/platform/diag.c \ src/posix/platform/misc.c \ src/posix/platform/logging.c \ src/posix/platform/random.c \ diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp index 514779c60..6f6fc551a 100644 --- a/src/core/api/link_raw_api.cpp +++ b/src/core/api/link_raw_api.cpp @@ -33,7 +33,9 @@ #include "openthread-core-config.h" +#include #include +#include #include "common/debug.hpp" #include "common/instance.hpp" @@ -41,6 +43,7 @@ #include "common/owner-locator.hpp" #include "common/random.hpp" #include "mac/mac.hpp" +#include "utils/parse_cmdline.hpp" #if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API @@ -766,35 +769,94 @@ uint16_t otLinkGetShortAddress(otInstance *aInstance) } #if OPENTHREAD_ENABLE_DIAG +static otInstance *sDiagInstance; + void otDiagInit(otInstance *aInstance) { - (void)aInstance; + sDiagInstance = aInstance; } void otDiagProcessCmdLine(const char *aString, char *aOutput, size_t aOutputMaxLen) { - (void)aString; - (void)aOutput; - (void)aOutputMaxLen; + enum + { + kMaxArgs = OPENTHREAD_CONFIG_DIAG_CMD_LINE_ARGS_MAX, + kMaxCommandBuffer = OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE, + }; + + otError error = OT_ERROR_NONE; + char buffer[kMaxCommandBuffer]; + char * argVector[kMaxArgs]; + uint8_t argCount = 0; + + VerifyOrExit(strnlen(aString, kMaxCommandBuffer) < kMaxCommandBuffer, error = OT_ERROR_NO_BUFS); + + strcpy(buffer, aString); + SuccessOrExit(error = Utils::CmdLineParser::ParseCmd(buffer, argCount, argVector, kMaxArgs)); + VerifyOrExit(argCount >= 1, error = OT_ERROR_INVALID_ARGS); + + if (strcmp(argVector[0], "power") == 0) + { + char * endptr; + int8_t power; + + VerifyOrExit(argCount == 2, error = OT_ERROR_INVALID_ARGS); + power = static_cast(strtol(argVector[1], &endptr, 0)); + VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS); + + otPlatDiagTxPowerSet(power); + } + else if (strcmp(argVector[0], "channel") == 0) + { + char * endptr; + uint8_t channel; + + VerifyOrExit(argCount == 2, error = OT_ERROR_INVALID_ARGS); + channel = static_cast(strtol(argVector[1], &endptr, 0)); + VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS); + + otPlatDiagChannelSet(channel); + } + else if (strcmp(argVector[0], "start") == 0) + { + otPlatDiagModeSet(true); + } + else if (strcmp(argVector[0], "stop") == 0) + { + otPlatDiagModeSet(false); + } + else + { + otPlatDiagProcess(sDiagInstance, argCount, argVector, aOutput, aOutputMaxLen); + } + +exit: + switch (error) + { + case OT_ERROR_NONE: + break; + + default: + snprintf(aOutput, aOutputMaxLen, "failed: invalid command: %s\r\n", otThreadErrorToString(error)); + break; + } } extern "C" void otPlatDiagAlarmFired(otInstance *aInstance) { - (void)aInstance; + otPlatDiagAlarmCallback(aInstance); } extern "C" void otPlatDiagRadioTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) { - (void)aInstance; - (void)aFrame; - (void)aError; + // notify OpenThread Diags module on host side + otPlatRadioTxDone(aInstance, aFrame, NULL, aError); } extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) { - (void)aInstance; - (void)aFrame; - (void)aError; + // notify OpenThread Diags module on host side + otPlatRadioReceiveDone(aInstance, aFrame, aError); } #endif // OPENTHREAD_ENABLE_DIAG diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index d3ec7842a..cdaeee4c0 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -41,7 +41,6 @@ libopenthread_posix_a_CPPFLAGS = \ libopenthread_posix_a_SOURCES = \ alarm.c \ - diag.c \ flash.c \ frame_queue.cpp \ hdlc.cpp \ diff --git a/src/posix/platform/diag.c b/src/posix/platform/diag.c deleted file mode 100644 index 800a0c0be..000000000 --- a/src/posix/platform/diag.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2016, 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. - */ - -#include "platform-posix.h" - -#include -#include -#include -#include - -#include -#include -#include - -#if OPENTHREAD_ENABLE_DIAG - -/** - * Diagnostics mode variables. - * - */ -static bool sDiagMode = false; - -void otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[], char *aOutput, size_t aOutputMaxLen) -{ - // Add more plarform specific diagnostics features here. - snprintf(aOutput, aOutputMaxLen, "diag feature '%s' is not supported\r\n", argv[0]); - (void)argc; - (void)aInstance; -} - -void otPlatDiagModeSet(bool aMode) -{ - sDiagMode = aMode; -} - -bool otPlatDiagModeGet() -{ - return sDiagMode; -} - -void otPlatDiagChannelSet(uint8_t aChannel) -{ - (void)aChannel; -} - -void otPlatDiagTxPowerSet(int8_t aTxPower) -{ - (void)aTxPower; -} - -void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) -{ - (void)aInstance; - (void)aFrame; - (void)aError; -} - -void otPlatDiagAlarmCallback(otInstance *aInstance) -{ - (void)aInstance; -} - -#endif // OPENTHREAD_ENABLE_DIAG diff --git a/src/posix/platform/radio_spinel.cpp b/src/posix/platform/radio_spinel.cpp index fb4a75d90..94a13ebce 100644 --- a/src/posix/platform/radio_spinel.cpp +++ b/src/posix/platform/radio_spinel.cpp @@ -368,6 +368,11 @@ RadioSpinel::RadioSpinel(void) , mIsDecoding(false) , mIsPromiscuous(false) , mIsReady(false) +#if OPENTHREAD_ENABLE_DIAG + , mDiagMode(false) + , mDiagOutput(NULL) + , mDiagOutputMaxLen(0) +#endif { } @@ -551,6 +556,17 @@ void RadioSpinel::HandleWaitingResponse(uint32_t aCommand, VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE); mError = SpinelStatusToOtError(status); } +#if OPENTHREAD_ENABLE_DIAG + else if (aKey == SPINEL_PROP_NEST_STREAM_MFG) + { + spinel_ssize_t unpacked; + + VerifyOrExit(mDiagOutput != NULL); + unpacked = + spinel_datatype_unpack_in_place(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, mDiagOutput, &mDiagOutputMaxLen); + VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE); + } +#endif else if (aKey == mWaitingKey) { if (mPropertyFormat) @@ -1454,6 +1470,23 @@ exit: return error; } +#if OPENTHREAD_ENABLE_DIAG +otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen) +{ + otError error; + + mDiagOutput = aOutput; + mDiagOutputMaxLen = aOutputMaxLen; + + error = Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString); + + mDiagOutput = NULL; + mDiagOutputMaxLen = 0; + + return error; +} +#endif + } // namespace ot void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) @@ -1714,3 +1747,69 @@ void otSimRadioSpinelProcess(otInstance *aInstance, const struct Event *aEvent) OT_UNUSED_VARIABLE(aInstance); } #endif // OPENTHREAD_POSIX_VIRTUAL_TIME + +#if OPENTHREAD_ENABLE_DIAG +void otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[], char *aOutput, size_t aOutputMaxLen) +{ + // deliver the platform specific diags commands to radio only ncp. + OT_UNUSED_VARIABLE(aInstance); + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'}; + char *cur = cmd; + char *end = cmd + sizeof(cmd); + + for (int index = 0; index < argc; index++) + { + cur += snprintf(cur, end - cur, "%s ", argv[index]); + } + + sRadioSpinel.PlatDiagProcess(cmd, aOutput, aOutputMaxLen); +} + +void otPlatDiagModeSet(bool aMode) +{ + SuccessOrExit(sRadioSpinel.PlatDiagProcess(aMode ? "start" : "stop", NULL, 0)); + sRadioSpinel.SetDiagEnabled(aMode); + +exit: + return; +} + +bool otPlatDiagModeGet(void) +{ + return sRadioSpinel.IsDiagEnabled(); +} + +void otPlatDiagTxPowerSet(int8_t aTxPower) +{ + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; + + snprintf(cmd, sizeof(cmd), "power %d", aTxPower); + SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); + +exit: + return; +} + +void otPlatDiagChannelSet(uint8_t aChannel) +{ + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; + + snprintf(cmd, sizeof(cmd), "channel %d", aChannel); + SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); + +exit: + return; +} + +void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) +{ + (void)aInstance; + (void)aFrame; + (void)aError; +} + +void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + (void)aInstance; +} +#endif // OPENTHREAD_ENABLE_DIAG diff --git a/src/posix/platform/radio_spinel.hpp b/src/posix/platform/radio_spinel.hpp index 1832ba2e4..b26dbdf6a 100644 --- a/src/posix/platform/radio_spinel.hpp +++ b/src/posix/platform/radio_spinel.hpp @@ -399,6 +399,38 @@ public: void Update(struct timeval &aTimeout); #endif +#if OPENTHREAD_ENABLE_DIAG + /** + * This method enables/disables the factory diagnostics mode. + * + * @param[in] aMode TRUE to enable diagnostics mode, FALSE otherwise. + * + */ + void SetDiagEnabled(bool aMode) { mDiagMode = aMode; } + + /** + * This method indicates whether or not factory diagnostics mode is enabled. + * + * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise. + * + */ + bool IsDiagEnabled(void) const { return mDiagMode; } + + /** + * This method processes platform diagnostics commands. + * + * @param[in] aString A NULL-terminated input string. + * @param[out] aOutput The diagnostics execution result. + * @param[in] aOutputMaxLen The output buffer size. + * + * @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 PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); +#endif + private: enum { @@ -553,6 +585,12 @@ private: bool mIsDecoding : 1; ///< Decoding hdlc frames. bool mIsPromiscuous : 1; ///< Promiscuous mode. bool mIsReady : 1; ///< NCP ready. + +#if OPENTHREAD_ENABLE_DIAG + bool mDiagMode; + char * mDiagOutput; + size_t mDiagOutputMaxLen; +#endif }; } // namespace ot