From 76df2ad277802aa50ad5f113d19c7b9fae89232a Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Thu, 12 Dec 2024 09:25:12 +0100 Subject: [PATCH] net: openthread: Adding `diag transmit` command. Commit adds `diag transmit` used for transmission IEEE802154 packets in specific amount and interval. Signed-off-by: Przemyslaw Bida --- modules/openthread/platform/diag.c | 181 +++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 12 deletions(-) diff --git a/modules/openthread/platform/diag.c b/modules/openthread/platform/diag.c index 23ea3b979860e2..edf8ad09dd5696 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,147 @@ 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 *txPacket; + const uint16_t diag_packet_len = 30; + + if (sTransmitMode == DIAG_TRANSMIT_MODE_PACKETS) { + if ((sTxCount > 0) || (sTxCount == -1)) { + txPacket = otPlatRadioGetTransmitBuffer(aInstance); + + txPacket->mInfo.mTxInfo.mTxDelayBaseTime = 0; + txPacket->mInfo.mTxInfo.mTxDelay = 0; + txPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = 0; + txPacket->mInfo.mTxInfo.mMaxFrameRetries = 0; + txPacket->mInfo.mTxInfo.mRxChannelAfterTxDone = sChannel; + txPacket->mInfo.mTxInfo.mTxPower = OT_RADIO_POWER_INVALID; + txPacket->mInfo.mTxInfo.mIsHeaderUpdated = false; + txPacket->mInfo.mTxInfo.mIsARetx = false; + txPacket->mInfo.mTxInfo.mCsmaCaEnabled = false; + txPacket->mInfo.mTxInfo.mCslPresent = false; + txPacket->mInfo.mTxInfo.mIsSecurityProcessed = false; + + txPacket->mLength = diag_packet_len; + + for (uint8_t i = 0; i < diag_packet_len; i++) { + txPacket->mPsdu[i] = i; + } + + otPlatRadioTransmit(aInstance, txPacket); + + 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 (!otPlatDiagModeGet()) { + return OT_ERROR_INVALID_STATE; + } + + 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\n"); + 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\n", + sTxRequestedCount, sTxPeriod); + } 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\n", sTxPeriod); + + } 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\n", + sTxRequestedCount); + } else { + return OT_ERROR_INVALID_ARGS; + } + + return error; +}