Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: openthread: Adding diag transmit command. #82911

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 169 additions & 12 deletions modules/openthread/platform/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,44 @@
#include <zephyr/drivers/gpio.h>

#include <openthread/error.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/radio.h>

#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, ...)
{
Expand All @@ -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);
canisLupus1313 marked this conversation as resolved.
Show resolved Hide resolved
}

/* Add more platform specific diagnostics features here. */
diag_output("diag feature '%s' is not supported\r\n", aArgs[0]);

Expand All @@ -80,6 +105,7 @@ bool otPlatDiagModeGet(void)
void otPlatDiagChannelSet(uint8_t aChannel)
{
ARG_UNUSED(aChannel);
sChannel = aChannel;
}

void otPlatDiagTxPowerSet(int8_t aTxPower)
Expand All @@ -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,
Expand Down Expand Up @@ -291,25 +319,154 @@ 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];

if (aArgsLength <= 0) {
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;
maciejbaczmanski marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Loading