Radio Control Layer (RCL)
Generic Tx Command Handler

Introduction

The generic Tx command allows to transmit a packet at a specific RF frequency and with a specific syncword. 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 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_t command has been initialized and configured.
  3. A Tx buffer has been initialized.
  4. An entry has been added to the buffer, that is, an element has been placed at the end of the Tx Buffer list.

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 command is normally employed when the user wants to transmit a packet for which the RCL does not provide a dedicated handler for the communication protocol. In this case, it is up to the application to define how packets are built 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 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;

Just as with any command, it's necessary to declare it and configure it before submitting it. However, since this is a Tx operation, in addition to performing the command configuration, it is also necessary to set up the Tx buffers and build the packets.

void runGenericTx(void)
{
ExampleRCL_GenericHdrDef hdrDef = FSK_hdrDef_DefaultRuntime();
/* Set up Tx buffers considering 4 packets, packet length of 200 bytes, 2 header bytes and 3 padding bytes */
RCL_Buffer_TxBuffer *txBuffers[NUM_PKT];
uint32_t pktBuffer[NUM_PKT][RCL_TxBuffer_len_u32(NUM_PAD, HDR_LEN, PKT_LEN)];
RCL_Handle h = RCL_open(&rclClient, &LRF_configGfsk500Kbps);
for (int i = 0; i < NUM_PKT; i++)
{
txBuffers[i] = (RCL_Buffer_TxBuffer *)pktBuffer[i];
}
/* Declare command */
RCL_CmdGenericTx cmd;
/* Command configuration */
cmd.common.scheduling = RCL_Schedule_AbsTime;
cmd.common.runtime.callback = defaultCallback;
cmd.common.runtime.rclCallbackMask = RCL_EventLastCmdDone;
cmd.rfFrequency = FREQUENCY;
cmd.syncWord = SYNCWORD;
generatePackets(txBuffers, NUM_PKT, PKT_LEN, &hdrDef, EXAMPLE_HDR);
for(int i = 0; i < NUM_PKT; i++)
{
RCL_TxBuffer_put(&cmd.txBuffers, txBuffers[i]);
}
/* Schedule first command considering a start delay of 600 us */
for (int i = 0; i < NUM_PKT; i++)
{
cmd.common.status = RCL_CommandStatus_Idle;
cmd.common.timing.absStartTime = nextTime;
/* Wait for command to conclude */
/* Schedule next command considering the same start delay */
}
}

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;
}
}
}
}

Architecture

The Generic Tx command handler life cycle is relatively simple in that mostly depends on the packet being sent. Unlike the Generic Rx command handler, the operation itself is not bound by a timeout, and once the packet is sent and an LRF event is received, the command will end.

Generic Tx handler state machine
RCL Event (In) Description
setup Setup has been performed
timerStart Timer-based start 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