diff --git a/modules/openthread/platform/diag.c b/modules/openthread/platform/diag.c index 23ea3b979860e20..4f851a85e24e690 100644 --- a/modules/openthread/platform/diag.c +++ b/modules/openthread/platform/diag.c @@ -8,20 +8,44 @@ #include #include +#include #include +#include #include "platform-zephyr.h" #include "zephyr/sys/util.h" +enum { + diag_transmit_mode_idle, + diag_transmit_mode_packets, + diag_transmit_mode_carrier, + diag_transmit_mode_modcarrier + +} diag_trasmit_mode; + /** * Diagnostics mode variables. * */ + static bool sDiagMode; static void *sDiagCallbackContext; static otPlatDiagOutputCallback sDiagOutputCallback; +static uint8_t sTransmitMode = diag_transmit_mode_idle; +static uint8_t sChannel = 20; +static uint32_t sTxPeriod = 1; +static int32_t sTxCount; +static int32_t sTxRequestedCount = 1; static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); +static otError processTransmit(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); + +static otError parse_long(char *aArgs, long *aValue) +{ + char *endptr; + *aValue = strtol(aArgs, &endptr, 0); + return (*endptr == '\0') ? OT_ERROR_NONE : OT_ERROR_PARSE; +} static void diag_output(const char *aFormat, ...) { @@ -48,15 +72,16 @@ void otPlatDiagSetOutputCallback(otInstance *aInstance, otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { - ARG_UNUSED(aInstance); - ARG_UNUSED(aArgsLength); - #if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) if (strcmp(aArgs[0], "modcarrier") == 0) { return startModCarrier(aInstance, aArgsLength - 1, aArgs + 1); } #endif + if (strcmp(aArgs[0], "transmit") == 0) { + return processTransmit(aInstance, aArgsLength - 1, aArgs + 1); + } + /* Add more platform specific diagnostics features here. */ diag_output("diag feature '%s' is not supported\r\n", aArgs[0]); @@ -80,6 +105,7 @@ bool otPlatDiagModeGet(void) void otPlatDiagChannelSet(uint8_t aChannel) { ARG_UNUSED(aChannel); + sChannel = aChannel; } void otPlatDiagTxPowerSet(int8_t aTxPower) @@ -99,19 +125,21 @@ void otPlatDiagRadioReceived(otInstance *aInstance, #if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) { - if (!otPlatDiagModeGet()) { + if (!otPlatDiagModeGet() && (sTransmitMode != diag_transmit_mode_idle || + sTransmitMode != diag_transmit_mode_carrier)) { return OT_ERROR_INVALID_STATE; } + if (aEnable) { + sTransmitMode = diag_transmit_mode_carrier; + } else { + sTransmitMode = diag_transmit_mode_idle; + } + return platformRadioTransmitCarrier(aInstance, aEnable); } #endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */ -void otPlatDiagAlarmCallback(otInstance *aInstance) -{ - ARG_UNUSED(aInstance); -} - /* * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path * with `compatible = "openthread,config"` property and `diag-gpios` property, @@ -291,9 +319,6 @@ otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { - ARG_UNUSED(aInstance); - ARG_UNUSED(aArgsLength); - bool enable = true; uint8_t data[OT_RADIO_FRAME_MAX_SIZE + 1]; @@ -301,15 +326,145 @@ static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char return OT_ERROR_INVALID_ARGS; } + if (!otPlatDiagModeGet() && (sTransmitMode != diag_transmit_mode_idle || + sTransmitMode != diag_transmit_mode_modcarrier)) { + return OT_ERROR_INVALID_STATE; + } + if (strcmp(aArgs[0], "stop") == 0) { enable = false; + sTransmitMode = diag_transmit_mode_idle; } else { if (hex2bin(aArgs[0], strlen(aArgs[0]), data, ARRAY_SIZE(data)) == 0) { return OT_ERROR_INVALID_ARGS; } + sTransmitMode = diag_transmit_mode_modcarrier; } return platformRadioTransmitModulatedCarrier(aInstance, enable, data); } #endif + +void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + uint32_t now; + otRadioFrame *sTxPacket; + const uint16_t diag_packet_len = 30; + + if (sTransmitMode == diag_transmit_mode_packets) { + if ((sTxCount > 0) || (sTxCount == -1)) { + sTxPacket = otPlatRadioGetTransmitBuffer(aInstance); + + sTxPacket->mInfo.mTxInfo.mTxDelayBaseTime = 0; + sTxPacket->mInfo.mTxInfo.mTxDelay = 0; + sTxPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = 0; + sTxPacket->mInfo.mTxInfo.mMaxFrameRetries = 0; + sTxPacket->mInfo.mTxInfo.mRxChannelAfterTxDone = sChannel; + sTxPacket->mInfo.mTxInfo.mTxPower = OT_RADIO_POWER_INVALID; + sTxPacket->mInfo.mTxInfo.mIsHeaderUpdated = false; + sTxPacket->mInfo.mTxInfo.mIsARetx = false; + sTxPacket->mInfo.mTxInfo.mCsmaCaEnabled = false; + sTxPacket->mInfo.mTxInfo.mCslPresent = false; + sTxPacket->mInfo.mTxInfo.mIsSecurityProcessed = false; + + sTxPacket->mLength = diag_packet_len; + + for (uint8_t i = 0; i < diag_packet_len; i++) { + sTxPacket->mPsdu[i] = i; + } + + otPlatRadioTransmit(aInstance, sTxPacket); + + if (sTxCount != -1) { + sTxCount--; + } + + now = otPlatAlarmMilliGetNow(); + otPlatAlarmMilliStartAt(aInstance, now, sTxPeriod); + } else { + sTransmitMode = diag_transmit_mode_idle; + otPlatAlarmMilliStop(aInstance); + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "Transmit done"); + } + } +} + +static otError processTransmit(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) +{ + otError error = OT_ERROR_NONE; + long value; + uint32_t now; + + if (aArgsLength == 0) { + diag_output("transmit will send %" PRId32 " diagnostic messages with %" PRIu32 + " ms interval\r\n", + sTxRequestedCount, sTxPeriod); + + } else if (strcmp(aArgs[0], "stop") == 0) { + if (sTransmitMode == diag_transmit_mode_idle) { + return OT_ERROR_INVALID_STATE; + } + + otPlatAlarmMilliStop(aInstance); + diag_output("diagnostic message transmission is stopped\r\nstatus 0x%02x\r\n", + error); + sTransmitMode = diag_transmit_mode_idle; + otPlatRadioReceive(aInstance, sChannel); + + } else if (strcmp(aArgs[0], "start") == 0) { + if (sTransmitMode != diag_transmit_mode_idle) { + return OT_ERROR_INVALID_STATE; + } + + otPlatAlarmMilliStop(aInstance); + sTransmitMode = diag_transmit_mode_packets; + sTxCount = sTxRequestedCount; + now = otPlatAlarmMilliGetNow(); + otPlatAlarmMilliStartAt(aInstance, now, sTxPeriod); + diag_output("sending %" PRId32 " diagnostic messages with %" PRIu32 + " ms interval\r\nstatus 0x%02x\r\n", + sTxRequestedCount, sTxPeriod, error); + } else if (strcmp(aArgs[0], "interval") == 0) { + + if (aArgsLength != 2) { + return OT_ERROR_INVALID_ARGS; + } + + error = parse_long(aArgs[1], &value); + if (error != OT_ERROR_NONE) { + return error; + } + + if (value <= 0) { + return OT_ERROR_INVALID_ARGS; + } + sTxPeriod = (uint32_t)(value); + diag_output("set diagnostic messages interval to %" PRIu32 + " ms\r\nstatus 0x%02x\r\n", + sTxPeriod, error); + + } else if (strcmp(aArgs[0], "count") == 0) { + + if (aArgsLength != 2) { + return OT_ERROR_INVALID_ARGS; + } + + error = parse_long(aArgs[1], &value); + if (error != OT_ERROR_NONE) { + return error; + } + + if ((value <= 0) && (value != -1)) { + return OT_ERROR_INVALID_ARGS; + } + + sTxRequestedCount = (uint32_t)(value); + diag_output("set diagnostic messages count to %" PRId32 "\r\nstatus 0x%02x\r\n", + sTxRequestedCount, error); + } else { + return OT_ERROR_INVALID_ARGS; + } + + return error; +}