[diag] add gpio diag command support (#8316)

This commit is contained in:
Zhanglong Xia
2022-11-01 08:05:20 +08:00
committed by GitHub
parent 1d1e5d16e0
commit 11a24d111f
14 changed files with 369 additions and 23 deletions
+29
View File
@@ -166,6 +166,13 @@ static otMacKeyMaterial sCurrKey;
static otMacKeyMaterial sNextKey;
static otRadioKeyType sKeyType;
enum
{
SIM_GPIO = 0,
};
static bool sGpioValue = false;
static int8_t GetRssi(uint16_t aChannel);
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
@@ -1399,3 +1406,25 @@ void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue)
}
}
}
otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION(aGpio == SIM_GPIO, error = OT_ERROR_INVALID_ARGS);
sGpioValue = aValue;
exit:
return error;
}
otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION((aGpio == SIM_GPIO) && (aValue != NULL), error = OT_ERROR_INVALID_ARGS);
*aValue = sGpioValue;
exit:
return error;
}
+6 -1
View File
@@ -85,8 +85,13 @@ otError otDiagProcessCmd(otInstance *aInstance,
* @param[out] aOutput The diagnostics execution result.
* @param[in] aOutputMaxLen The output buffer size.
*
* @retval OT_ERROR_NONE The command is successfully process.
* @retval OT_ERROR_INVALID_ARGS The command is supported but invalid arguments provided.
* @retval OT_ERROR_NOT_IMPLEMENTED The command is not supported.
* @retval OT_ERROR_NO_BUFS The command string is too long.
*
*/
void otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen);
otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen);
/**
* This function indicates whether or not the factory diagnostics mode is enabled.
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (256)
#define OPENTHREAD_API_VERSION (257)
/**
* @addtogroup api-instance
+26
View File
@@ -129,6 +129,32 @@ void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otErro
*/
void otPlatDiagAlarmCallback(otInstance *aInstance);
/**
* This function sets the gpio value.
*
* @param[in] aGpio The gpio number.
* @param[in] aValue true to set the gpio to high level, or false otherwise.
*
* @retval OT_ERROR_NONE Successfully set the gpio.
* @retval OT_ERROR_INVALID_ARGS @p aGpio is not supported.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on the platform.
*
*/
otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue);
/**
* This function gets the gpio value.
*
* @param[in] aGpio The gpio number.
* @param[out] aValue A pointer where to put gpio value.
*
* @retval OT_ERROR_NONE Successfully got the gpio value.
* @retval OT_ERROR_INVALID_ARGS @p aGpio is not supported or @p aValue is NULL.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on the platform.
*
*/
otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue);
/**
* @}
*
+2 -2
View File
@@ -42,11 +42,11 @@
using namespace ot;
void otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen)
otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen)
{
AssertPointerIsNotNull(aString);
AsCoreType(aInstance).Get<FactoryDiags::Diags>().ProcessLine(aString, aOutput, aOutputMaxLen);
return AsCoreType(aInstance).Get<FactoryDiags::Diags>().ProcessLine(aString, aOutput, aOutputMaxLen);
}
otError otDiagProcessCmd(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen)
+22
View File
@@ -14,6 +14,7 @@ The diagnostics module supports common diagnostics features that are listed belo
- [diag repeat](#diag-repeat-delay-length)
- [diag radio](#diag-radio-sleep)
- [diag stats](#diag-stats)
- [diag gpio](#diag-gpio-get-gpio)
- [diag stop](#diag-stop)
### diag
@@ -157,6 +158,27 @@ Clear statistics during diagnostics mode.
stats cleared
```
### diag gpio get \<gpio\>
Get the gpio value.
```bash
> diag gpio get 0
1
Done
```
### diag gpio set \<gpio\> \<value\>
Set the gpio value.
The parameter `value` has to be `0` or `1`.
```bash
> diag gpio set 0 1
Done
```
### diag stop
Stop diagnostics mode and print statistics.
+69 -7
View File
@@ -70,8 +70,8 @@ namespace FactoryDiags {
#if OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI
const struct Diags::Command Diags::sCommands[] = {
{"channel", &Diags::ProcessChannel}, {"echo", &Diags::ProcessEcho}, {"power", &Diags::ProcessPower},
{"start", &Diags::ProcessStart}, {"stop", &Diags::ProcessStop},
{"channel", &Diags::ProcessChannel}, {"echo", &Diags::ProcessEcho}, {"gpio", &Diags::ProcessGpio},
{"power", &Diags::ProcessPower}, {"start", &Diags::ProcessStart}, {"stop", &Diags::ProcessStop},
};
Diags::Diags(Instance &aInstance)
@@ -181,9 +181,9 @@ extern "C" void otPlatDiagAlarmFired(otInstance *aInstance)
#else // OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI
// For OPENTHREAD_FTD, OPENTHREAD_MTD, OPENTHREAD_RADIO_CLI
const struct Diags::Command Diags::sCommands[] = {
{"channel", &Diags::ProcessChannel}, {"power", &Diags::ProcessPower}, {"radio", &Diags::ProcessRadio},
{"repeat", &Diags::ProcessRepeat}, {"send", &Diags::ProcessSend}, {"start", &Diags::ProcessStart},
{"stats", &Diags::ProcessStats}, {"stop", &Diags::ProcessStop},
{"channel", &Diags::ProcessChannel}, {"gpio", &Diags::ProcessGpio}, {"power", &Diags::ProcessPower},
{"radio", &Diags::ProcessRadio}, {"repeat", &Diags::ProcessRepeat}, {"send", &Diags::ProcessSend},
{"start", &Diags::ProcessStart}, {"stats", &Diags::ProcessStats}, {"stop", &Diags::ProcessStop},
};
Diags::Diags(Instance &aInstance)
@@ -543,6 +543,37 @@ exit:
#endif // OPENTHREAD_RADIO
Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen)
{
Error error = kErrorNone;
long value;
uint32_t gpio;
bool level;
if ((aArgsLength == 2) && (strcmp(aArgs[0], "get") == 0))
{
SuccessOrExit(error = ParseLong(aArgs[1], value));
gpio = static_cast<uint32_t>(value);
SuccessOrExit(error = otPlatDiagGpioGet(gpio, &level));
snprintf(aOutput, aOutputMaxLen, "%d\r\n", level);
}
else if ((aArgsLength == 3) && (strcmp(aArgs[0], "set") == 0))
{
SuccessOrExit(error = ParseLong(aArgs[1], value));
gpio = static_cast<uint32_t>(value);
SuccessOrExit(error = ParseBool(aArgs[2], level));
SuccessOrExit(error = otPlatDiagGpioSet(gpio, level));
}
else
{
error = kErrorInvalidArgs;
}
exit:
AppendErrorResult(error, aOutput, aOutputMaxLen);
return error;
}
void Diags::AppendErrorResult(Error aError, char *aOutput, size_t aOutputMaxLen)
{
if (aError != kErrorNone)
@@ -558,6 +589,19 @@ Error Diags::ParseLong(char *aString, long &aLong)
return (*endptr == '\0') ? kErrorNone : kErrorParse;
}
Error Diags::ParseBool(char *aString, bool &aBool)
{
Error error;
long value;
SuccessOrExit(error = ParseLong(aString, value));
VerifyOrExit((value == 0) || (value == 1), error = kErrorParse);
aBool = static_cast<bool>(value);
exit:
return error;
}
Error Diags::ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[])
{
Error error;
@@ -571,7 +615,7 @@ exit:
return error;
}
void Diags::ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen)
Error Diags::ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen)
{
constexpr uint16_t kMaxCommandBuffer = OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE;
@@ -591,7 +635,7 @@ exit:
{
case kErrorNone:
aOutput[0] = '\0'; // In case there is no output.
IgnoreError(ProcessCmd(argCount, &args[0], aOutput, aOutputMaxLen));
error = ProcessCmd(argCount, &args[0], aOutput, aOutputMaxLen);
break;
case kErrorNoBufs:
@@ -606,6 +650,8 @@ exit:
snprintf(aOutput, aOutputMaxLen, "failed to parse command string\r\n");
break;
}
return error;
}
Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen)
@@ -663,4 +709,20 @@ bool Diags::IsEnabled(void)
} // namespace FactoryDiags
} // namespace ot
OT_TOOL_WEAK otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
{
OT_UNUSED_VARIABLE(aGpio);
OT_UNUSED_VARIABLE(aValue);
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
{
OT_UNUSED_VARIABLE(aGpio);
OT_UNUSED_VARIABLE(aValue);
return OT_ERROR_NOT_IMPLEMENTED;
}
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
+3 -1
View File
@@ -68,7 +68,7 @@ public:
* @param[in] aOutputMaxLen The output buffer size.
*
*/
void ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen);
Error ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen);
/**
* This method processes a factory diagnostics command line.
@@ -144,6 +144,7 @@ private:
Error ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]);
Error ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen);
Error ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen);
Error ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen);
Error ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen);
Error ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen);
@@ -159,6 +160,7 @@ private:
static void AppendErrorResult(Error aError, char *aOutput, size_t aOutputMaxLen);
static Error ParseLong(char *aString, long &aLong);
static Error ParseBool(char *aString, bool &aBool);
static const struct Command sCommands[];
+1
View File
@@ -790,6 +790,7 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleWaitingResponse(uint3
{
spinel_ssize_t unpacked;
mError = OT_ERROR_NONE;
VerifyOrExit(mDiagOutput != nullptr);
unpacked =
spinel_datatype_unpack_in_place(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, mDiagOutput, &mDiagOutputMaxLen);
+1 -1
View File
@@ -1370,7 +1370,7 @@ otError NcpBase::HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader)
}
#endif
otDiagProcessCmdLine(mInstance, string, output, sizeof(output));
SuccessOrExit(error = otDiagProcessCmdLine(mInstance, string, output, sizeof(output)));
// Prepare the response
SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_NEST_STREAM_MFG));
+28
View File
@@ -547,6 +547,34 @@ exit:
return;
}
otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
{
otError error;
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
snprintf(cmd, sizeof(cmd), "gpio set %d %d", aGpio, aValue);
SuccessOrExit(error = sRadioSpinel.PlatDiagProcess(cmd, nullptr, 0));
exit:
return error;
}
otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
{
otError error;
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE];
char * str;
snprintf(cmd, sizeof(cmd), "gpio get %d", aGpio);
SuccessOrExit(error = sRadioSpinel.PlatDiagProcess(cmd, output, sizeof(output)));
VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED);
*aValue = static_cast<bool>(atoi(str));
exit:
return error;
}
void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
{
OT_UNUSED_VARIABLE(aInstance);
+3 -1
View File
@@ -207,12 +207,14 @@ otError otDiagProcessCmd(otInstance *aInstance, uint8_t aArgsLength, char *aArgs
return OT_ERROR_NOT_IMPLEMENTED;
}
void otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen)
otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aString);
OT_UNUSED_VARIABLE(aOutput);
OT_UNUSED_VARIABLE(aOutputMaxLen);
return OT_ERROR_NOT_IMPLEMENTED;
}
void otPlatReset(otInstance *aInstance)
+175
View File
@@ -0,0 +1,175 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2022, 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"
source "tests/scripts/expect/_multinode.exp"
spawn_node 1
spawn_node 2
switch_node 1
send "diag start\n"
expect "start diagnostics mode"
expect "status 0x00"
expect_line "Done"
send "diag channel 11\n"
expect "set channel to 11"
expect "status 0x00"
expect_line "Done"
send "diag stats clear\n"
expect "stats cleared"
expect_line "Done"
switch_node 2
send "diag start\n"
expect "start diagnostics mode"
expect "status 0x00"
expect_line "Done"
send "diag channel 11\n"
expect "set channel to 11"
expect "status 0x00"
expect_line "Done"
send "diag stats clear\n"
expect "stats cleared"
expect_line "Done"
send "diag send 10 100\n"
expect "sending 0xa packet(s), length 0x64"
expect "status 0x00"
expect_line "Done"
sleep 2
send "diag stats\n"
expect "received packets: 0"
expect "sent packets: 10"
expect "first received packet: rssi=0, lqi=0"
expect "last received packet: rssi=0, lqi=0"
expect_line "Done"
switch_node 1
send "diag stats\n"
expect "received packets: 10"
expect "sent packets: 0"
expect "first received packet: rssi=-20, lqi=0"
expect "last received packet: rssi=-20, lqi=0"
expect_line "Done"
send "diag stats clear\n"
expect "stats cleared"
expect_line "Done"
switch_node 2
send "diag repeat 20 100\n"
expect "sending packets of length 0x64 at the delay of 0x14 ms"
expect "status 0x00"
expect_line "Done"
sleep 1
send "diag repeat stop\n"
expect "repeated packet transmission is stopped"
expect "status 0x00"
expect_line "Done"
switch_node 1
send "diag stats\n"
expect -r {received packets: \d+}
expect "sent packets: 0"
expect "first received packet: rssi=-20, lqi=0"
expect "last received packet: rssi=-20, lqi=0"
expect_line "Done"
send "diag stats clear\n"
expect "stats cleared"
expect_line "Done"
dispose_all
spawn_node 1
send "diag start\n"
expect "start diagnostics mode"
expect "status 0x00"
expect_line "Done"
send "diag channel 11\n"
expect "set channel to 11"
expect "status 0x00"
expect_line "Done"
send "diag power 10\n"
expect "set tx power to 10 dBm"
expect "status 0x00"
expect_line "Done"
send "diag radio sleep\n"
expect "set radio from receive to sleep"
expect "status 0x00"
expect_line "Done"
send "diag radio state\n"
expect "sleep"
expect_line "Done"
send "diag radio receive\n"
expect "set radio from sleep to receive on channel 11"
expect "status 0x00"
expect_line "Done"
send "diag radio state\n"
expect "receive"
expect_line "Done"
send "diag gpio set 0 1\n"
expect_line "Done"
send "diag gpio get 0\n"
expect "1"
expect_line "Done"
send "diag invalid_commad\n"
expect "Error 35: InvalidCommand"
send "diag stop\n"
expect_line "Done"
send "diag channel\n"
expect "failed"
expect "status 0xd"
expect "Error 13: InvalidState"
dispose_all
+3 -9
View File
@@ -42,21 +42,15 @@ send "diag rcp\n"
expect "diagnostics mode is enabled"
expect_line "Done"
send "diag rcp channel\n"
expect "failed"
expect "status 0x7"
expect_line "Done"
expect "Error 7: InvalidArgs"
send "diag rcp channel 11\n"
expect_line "Done"
send "diag rcp power\n"
expect "failed"
expect "status 0x7"
expect_line "Done"
expect "Error 7: InvalidArgs"
send "diag rcp power 10\n"
expect_line "Done"
send "diag rcp echo\n"
expect "failed"
expect "status 0x7"
expect_line "Done"
expect "Error 7: InvalidArgs"
send "diag rcp echo 0123456789\n"
expect_line "0123456789"
expect_line "Done"