diff --git a/examples/platforms/simulation/diag.c b/examples/platforms/simulation/diag.c index ddb8c2659..cf8523571 100644 --- a/examples/platforms/simulation/diag.c +++ b/examples/platforms/simulation/diag.c @@ -35,8 +35,11 @@ #include #include +#include #include +#include "utils/code_utils.h" + #if OPENTHREAD_CONFIG_DIAG_ENABLE /** @@ -45,6 +48,14 @@ */ static bool sDiagMode = false; +enum +{ + SIM_GPIO = 0, +}; + +static otGpioMode sGpioMode = OT_GPIO_MODE_INPUT; +static bool sGpioValue = false; + void otPlatDiagModeSet(bool aMode) { sDiagMode = aMode; @@ -77,4 +88,47 @@ void otPlatDiagAlarmCallback(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); } +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; +} + +otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(aGpio == SIM_GPIO, error = OT_ERROR_INVALID_ARGS); + sGpioMode = aMode; + +exit: + return error; +} + +otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION((aGpio == SIM_GPIO) && (aMode != NULL), error = OT_ERROR_INVALID_ARGS); + *aMode = sGpioMode; + +exit: + return error; +} #endif // OPENTHREAD_CONFIG_DIAG_ENABLE diff --git a/examples/platforms/simulation/radio.c b/examples/platforms/simulation/radio.c index 9f9db6ead..4d6ab8810 100644 --- a/examples/platforms/simulation/radio.c +++ b/examples/platforms/simulation/radio.c @@ -166,13 +166,6 @@ 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 @@ -1406,25 +1399,3 @@ 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; -} diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 4ee0f28c3..83bc6eae5 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 (261) +#define OPENTHREAD_API_VERSION (262) /** * @addtogroup api-instance diff --git a/include/openthread/platform/diag.h b/include/openthread/platform/diag.h index 46e944403..d358c84b3 100644 --- a/include/openthread/platform/diag.h +++ b/include/openthread/platform/diag.h @@ -56,6 +56,16 @@ extern "C" { * */ +/** + * This enumeration defines the gpio modes. + * + */ +typedef enum +{ + OT_GPIO_MODE_INPUT = 0, ///< Input mode without pull resistor. + OT_GPIO_MODE_OUTPUT = 1, ///< Output mode. +} otGpioMode; + /** * This function processes a factory diagnostics command line. * @@ -155,6 +165,34 @@ otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue); */ otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue); +/** + * This function sets the gpio mode. + * + * @param[in] aGpio The gpio number. + * @param[out] aMode The gpio mode. + * + * @retval OT_ERROR_NONE Successfully set the gpio mode. + * @retval OT_ERROR_INVALID_ARGS @p aGpio is not supported. + * @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on the platform. + * + */ +otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode); + +/** + * This function gets the gpio mode. + * + * @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_FAILED The gpio is neither in input nor output mode. For example, if the gpio is in + * analog mode. + * @retval OT_ERROR_INVALID_ARGS @p aGpio is not supported or @p aMode is NULL. + * @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on the platform. + * + */ +otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode); + /** * @} * diff --git a/src/core/diags/README.md b/src/core/diags/README.md index 7fa128fd6..62f5603d7 100644 --- a/src/core/diags/README.md +++ b/src/core/diags/README.md @@ -179,6 +179,34 @@ The parameter `value` has to be `0` or `1`. Done ``` +### diag gpio mode \ + +Get the gpio mode. + +```bash +> diag gpio mode 1 +in +Done +``` + +### diag gpio mode \ in + +Sets the given gpio to the input mode without pull resistor. + +```bash +> diag gpio mode 1 in +Done +``` + +### diag gpio mode \ out + +Sets the given gpio to the output mode. + +```bash +> diag gpio mode 1 out +Done +``` + ### diag stop Stop diagnostics mode and print statistics. diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index ec9a0c7cf..7bb6fd35b 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -545,10 +545,11 @@ exit: Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) { - Error error = kErrorNone; - long value; - uint32_t gpio; - bool level; + Error error = kErrorInvalidArgs; + long value; + uint32_t gpio; + bool level; + otGpioMode mode; if ((aArgsLength == 2) && (strcmp(aArgs[0], "get") == 0)) { @@ -564,9 +565,31 @@ Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size SuccessOrExit(error = ParseBool(aArgs[2], level)); SuccessOrExit(error = otPlatDiagGpioSet(gpio, level)); } - else + else if ((aArgsLength >= 2) && (strcmp(aArgs[0], "mode") == 0)) { - error = kErrorInvalidArgs; + SuccessOrExit(error = ParseLong(aArgs[1], value)); + gpio = static_cast(value); + + if (aArgsLength == 2) + { + SuccessOrExit(error = otPlatDiagGpioGetMode(gpio, &mode)); + if (mode == OT_GPIO_MODE_INPUT) + { + snprintf(aOutput, aOutputMaxLen, "in\r\n"); + } + else if (mode == OT_GPIO_MODE_OUTPUT) + { + snprintf(aOutput, aOutputMaxLen, "out\r\n"); + } + } + else if ((aArgsLength == 3) && (strcmp(aArgs[2], "in") == 0)) + { + SuccessOrExit(error = otPlatDiagGpioSetMode(gpio, OT_GPIO_MODE_INPUT)); + } + else if ((aArgsLength == 3) && (strcmp(aArgs[2], "out") == 0)) + { + SuccessOrExit(error = otPlatDiagGpioSetMode(gpio, OT_GPIO_MODE_OUTPUT)); + } } exit: @@ -725,4 +748,20 @@ OT_TOOL_WEAK otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue) return OT_ERROR_NOT_IMPLEMENTED; } +OT_TOOL_WEAK otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode) +{ + OT_UNUSED_VARIABLE(aGpio); + OT_UNUSED_VARIABLE(aMode); + + return OT_ERROR_NOT_IMPLEMENTED; +} + +OT_TOOL_WEAK otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) +{ + OT_UNUSED_VARIABLE(aGpio); + OT_UNUSED_VARIABLE(aMode); + + return OT_ERROR_NOT_IMPLEMENTED; +} + #endif // OPENTHREAD_CONFIG_DIAG_ENABLE diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 495cc69d2..675738252 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -575,6 +575,46 @@ exit: return error; } +otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode) +{ + otError error; + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; + + snprintf(cmd, sizeof(cmd), "gpio mode %d %s", aGpio, aMode == OT_GPIO_MODE_INPUT ? "in" : "out"); + SuccessOrExit(error = sRadioSpinel.PlatDiagProcess(cmd, nullptr, 0)); + +exit: + return error; +} + +otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) +{ + 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 mode %d", aGpio); + SuccessOrExit(error = sRadioSpinel.PlatDiagProcess(cmd, output, sizeof(output))); + VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED); + + if (strcmp(str, "in") == 0) + { + *aMode = OT_GPIO_MODE_INPUT; + } + else if (strcmp(str, "out") == 0) + { + *aMode = OT_GPIO_MODE_OUTPUT; + } + else + { + error = OT_ERROR_FAILED; + } + +exit: + return error; +} + void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) { OT_UNUSED_VARIABLE(aInstance); diff --git a/tests/scripts/expect/cli-diags.exp b/tests/scripts/expect/cli-diags.exp index 686680862..0c247d2ae 100755 --- a/tests/scripts/expect/cli-diags.exp +++ b/tests/scripts/expect/cli-diags.exp @@ -161,6 +161,20 @@ send "diag gpio get 0\n" expect "1" expect_line "Done" +send "diag gpio mode 0 in\n" +expect_line "Done" + +send "diag gpio mode 0\n" +expect "in" +expect_line "Done" + +send "diag gpio mode 0 out\n" +expect_line "Done" + +send "diag gpio mode 0\n" +expect "out" +expect_line "Done" + send "diag invalid_commad\n" expect "Error 35: InvalidCommand"