Commit 1512ed2d authored by Przemyslaw Bida's avatar Przemyslaw Bida Committed by Benjamin Cabé
Browse files

net: openthread: Adding `diag transmit` command.



Commit adds `diag transmit` used for transmission IEEE802154 packets
in specific amount and interval.

Signed-off-by: default avatarPrzemyslaw Bida <przemyslaw.bida@nordicsemi.no>
parent 60a2888d
Loading
Loading
Loading
Loading
+169 −12
Original line number Diff line number Diff line
@@ -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, ...)
{
@@ -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,18 +125,20 @@ 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;
	}

	return platformRadioTransmitCarrier(aInstance, aEnable);
	if (aEnable) {
		sTransmitMode = DIAG_TRANSMIT_MODE_CARRIER;
	} else {
		sTransmitMode = DIAG_TRANSMIT_MODE_IDLE;
	}
#endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */

void otPlatDiagAlarmCallback(otInstance *aInstance)
{
	ARG_UNUSED(aInstance);
	return platformRadioTransmitCarrier(aInstance, aEnable);
}
#endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */

/*
 * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path
@@ -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;
}