Radio Control Layer (RCL)
Generic Tx Repeat Command Handler

Introduction

The generic Tx Repeat command allows to repeatedly transmit a packet. The following sections describe how the command can be configured and used, its life cycle, and how it fits into the RCL architecture.

In order to submit a Generic Tx Repeat command, the following steps must have taken place:

  1. RCL has been initialized (See RCL_init) and a handle must exist (See RCL_open).
  2. The RCL_CMD_GENERIC_TX_REPEAT_t command has been initialized and configured.
  3. A data entry (packet) has been set up.
  4. The command has been configured according to the needs of the user

Once these steps have been completed, RCL_Command_submit and RCL_Command_pend are called to effectively send and then wait for the command to conclude. Once this has happened, the callback and the command status can be used for error checking and the application can proceed according to its specification.

Usage

The Generic Tx Repeat command can be employed for various reasons. It is mostly meant to be used for testing purposes, but it can also be used for periodic transmissions of the same packet. This means that the application must also consider the time period or repeated transmissions (back-to-back), and the number of times that the packet is to be sent.

The following code snippet shows a normal use-case for the command.

void runGenericTxRepeat(void)
{
ExampleRCL_GenericHdrDef hdrDef = FSK_hdrDef_DefaultRuntime();
/* Set up Tx buffer considering a packet length of 200 bytes, 2 header bytes and 3 padding bytes */
RCL_Buffer_TxBuffer *txBuffer;
uint32_t pktBuffer[RCL_TxBuffer_len_u32(NUM_PAD, HDR_LEN, PKT_LEN)];
txBuffer = (RCL_Buffer_TxBuffer *)pktBuffer;
RCL_Handle h = RCL_open(&rclClient, &LRF_configGfsk500Kbps);
/* Declare command */
RCL_CmdGenericTxRepeat cmd;
generatePackets(&txBuffer, 1, PKT_LEN, &hdrDef, EXAMPLE_HDR);
/* Command configuration */
cmd.common.scheduling = RCL_Schedule_Now;
cmd.common.runtime.callback = defaultCallback;
cmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value | RCL_EventCmdStarted.value;
cmd.rfFrequency = FREQUENCY;
cmd.syncWord = SYNCWORD;
cmd.timePeriod = 10000; // Send the packet every 2.5 [ms]
cmd.numPackets = 100; // Send the packets 100 times and then stop
cmd.txEntry = (RCL_Buffer_DataEntry *)(&txBuffer->length); // Packet to transmit
cmd.common.status = RCL_CommandStatus_Idle;
/* Wait for command to conclude */
}

Just like a regular Generic Tx command, it is up to the application to define how the packet is built while also considering the internal packet format used to store packets in the LRF FIFOs.

This can be accomplished by using a struct to define the various fields that need to be considered when building the the packet.

#define PKT_LEN 200
#define HDR_LEN 3
#define NUM_PKT 4
#define NUM_PAD 3
#define FREQUENCY 2470000000
#define SYNCWORD 0xAB0B51DE
#define SYNCWORD_B 0xCC0781BA
#define EXAMPLE_HDR 0x00051AA
#define FSK_hdrDef_Default() \
{ \
.numHdrBits = 8, \
.numLenBits = 8, \
.lenPos = 0, \
.lenOffset = 0, \
.numPad = 3, \
}
#define FSK_hdrDef_DefaultRuntime() (ExampleRCL_GenericHdrDef) FSK_hdrDef_Default()
typedef struct {
uint8_t numHdrBits;
uint8_t numLenBits;
uint8_t lenPos;
int8_t lenOffset;
uint8_t numPad;
} ExampleRCL_GenericHdrDef;

The following function serves as an example of how packets can be generated so that they are compatible with the internal packet format of the LRF.

void generatePackets(RCL_Buffer_TxBuffer **txBuffers, uint32_t numPkt, uint32_t pktLen,
ExampleRCL_GenericHdrDef *hdrDef, uint32_t exampleHeader)
{
union
{
uint32_t value;
uint8_t bytes[4];
} header;
uint8_t hdrLen = (hdrDef->numHdrBits + 7) / 8;
header.value = exampleHeader;
for (int i = 0; i < numPkt; i++)
{
uint8_t *txData;
/* Initialize Tx Buffer */
txData = RCL_TxBuffer_init(txBuffers[i], hdrDef->numPad, hdrLen, pktLen);
/* Insert length field at the specified position in the header */
if (hdrDef->numLenBits > 0)
{
header.value &= ~(((1 << hdrDef->numLenBits) - 1) << hdrDef->lenPos);
header.value |= (pktLen - hdrDef->lenOffset) << hdrDef->lenPos;
}
/* Write header to buffer */
for (int i = 0; i < hdrLen; i++)
{
txData[i] = header.bytes[i];
}
/* Write the payload */
if(pktLen > 0)
{
for(uint32_t i = 0; i < pktLen; i++)
{
txData[hdrLen + i] = i & 0xFF;
}
}
}
}

It's worth mentioning the that use of the Generic Tx Repeat command for periodic transmissions is discouraged, given that it keeps the device from going into a low power mode during the waiting period between transmissions.

Architecture

The Generic Tx Repeat command handler has a life cycle that mostly depends on the packet being sent, the number of times that is supposed to be sent and the time period.

Generic Tx Repeat handler state machine
RCL Event (In) Description
setup Setup has been performed
timerStart Timer-based start signalled
hardStop Timer/api-based hard-stop signalled
gracefulStop Timer/api-based graceful-stop signalled
RCL Event (Out) Description
lastCmdDone The RCL is finished with the command
cmdStarted Command handler has accepted and started executing
LRF Event Description
opDone The PBE operation has finished
opError Something went wrong. Cause located in the PBE ENDCAUSE register
systim1 SYSTIM1 event indicating that a graceful stop wsa observed