CC2755R10: IEEE802.15.4 uses rxAction to receive the encountered problems

Part Number: CC2755R10
Other Parts Discussed in Thread: SYSCONFIG

Hi E2E/R&D

-1. We are currently using the latest CSS and SDK-F3, but no IEEE802.15.4 routines related to CC2755R10 were found in it. When can this part be updated, or where can it be obtained?
-2. We built a project manually by ourselves and associated it with the relevant library files. 
If RCL_CmdGenericRx and RCL_CmdGenericTx are used, normal sending and receiving can be carried out, but this mode cannot filter PanID and address. The current issue is how to use the RCL CmdIeeeRxTx method for sending and receiving, and examples in this regard are needed.

         

 

  • Hi RC CHEN,

    /*
     * Copyright (c) 2024-2025, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *  ======== rfPacket_ieee_test.c ========
     */
    
    /* XDC module Headers */
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    
    /* POSIX Header files */
    #include <pthread.h>
    
    /* BIOS module Headers */
    #include <FreeRTOS.h>
    #include <task.h>
    
    #include <ti/drivers/rcl/RCL.h>
    #include <ti/drivers/rcl/RCL_Scheduler.h>
    #include <ti/drivers/rcl/commands/ieee.h>
    
    #include "ti_radio_config.h"
    
    #define PKT_LEN 38
    #define ACK_LEN 12
    #define HDR_LEN 2
    #define NUM_PAD 0
    #define PKT_TYPE_PKT 25
    #define PKT_TYPE_ACK 2
    #define NUM_RX_BUF 2
    #define MULTI_BUF_SZ 256
    #define FREQUENCY 2435000000
    
    #define EXAMPLE_MODE_WAIT_FOR_DEBUGGER 0
    #define EXAMPLE_MODE_RX 1
    #define EXAMPLE_MODE_TX 2
    
    /* Set to 0 to send the same packet an unlimited number of times */
    /* Another value gives different packets - make sure all can fit in the receive buffer*/
    volatile uint8_t numPkt = 0;
    
    /* Define EXAMPLE_MODE to build for RX or TX, or use debugger to write to exampleMode variable to set the mode */
    #ifndef EXAMPLE_MODE
    volatile uint32_t exampleMode = EXAMPLE_MODE_TX;
    #else
    volatile uint32_t exampleMode = EXAMPLE_MODE;
    #endif
    
    volatile uint16_t numPktOk = 0;
    volatile ti_drivers_utils_List__include
    RCL_CommandStatus lastStatus;
    uint8_t ieeeAddr[8] = {0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d};
    //uint8_t ieeeAddr[8] = {0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06};
    
    static RCL_Client  rclClient;
    
    /* Generate example packets */
    void generatePacketIeee(RCL_Buffer_TxBuffer *txBuffer, uint32_t pktLen, uint8_t pktType, uint8_t sequenceNumber)
    {
        uint8_t *txData;
    
        /* Initialize Tx Buffer */
        txData = RCL_TxBuffer_init(txBuffer, NUM_PAD, HDR_LEN, pktLen);
    
        /* Insert length field in the header */
        txData[0] = pktLen;
        /* Write packet type  */
        //txData[1] = pktType;
        txData[1] = 0x61;
        /* Write sequence number */
        //txData[2] = sequenceNumber;
        txData[2] = 0x88;
    
        for (uint32_t i = 3; i < pktLen + HDR_LEN; i++)
        {
            txData[i] = i & 0xFF;
        }
        txData[PKT_LEN-3] = 0x8a;
        txData[PKT_LEN-2] = 0x48;
        txData[PKT_LEN-1] = 0x31;
        txData[PKT_LEN] = 0x17;
    }
    
    /* Callback function for use in RX in order to process packets and send ACK */
    void ieeeCallback(RCL_Command *cmd, LRF_Events lrfEvents, RCL_Events rclEvents)
    {
        RCL_CmdIeeeRxTx *rxTxCmd = (RCL_CmdIeeeRxTx *)cmd;
    
        if (lrfEvents.rxCtrlAck)
        {
            uint32_t rxBuffer[RCL_Buffer_bytesToWords(RCL_Buffer_entryLen(NUM_PAD, HDR_LEN, PKT_LEN))];
            RCL_Buffer_DataEntry *rxEntry = (RCL_Buffer_DataEntry *)rxBuffer;
            /* Ack is under reception. Look at the packet received so far */
            RCL_IEEE_readPartialFrame(rxTxCmd, rxEntry, sizeof(rxBuffer));
            if (rxEntry->length >= 4)
            {
    
            }
        }
    
        if (rclEvents.rxEntryAvail)
        {
            /* Packet received */
            List_List finishedBuffers;
            RCL_MultiBuffer *multiBuffer;
            /* Prepare list of RX buffers that are done */
            List_clearList(&finishedBuffers);
            RCL_Buffer_DataEntry *rxPkt = RCL_MultiBuffer_RxEntry_get(&rxTxCmd->rxAction->rxBuffers, &finishedBuffers);
            /* Make finished buffers available to RCL command */
            while ((multiBuffer = RCL_MultiBuffer_get(&finishedBuffers)) != NULL)
            {
                RCL_MultiBuffer_clear(multiBuffer);
                RCL_MultiBuffer_put(&rxTxCmd->rxAction->rxBuffers, multiBuffer);
            }
    
            bool pktOk = false;
            if (rxPkt != NULL)
            {
                /* Check contents of packet */
                if (rxPkt->length > 8)
                {
                    pktOk = true;
                }
            }
        }
    }
    
    /* Function for running TX and trying to receive ACK */
    void runIeeeTx(void)
    {
        RCL_init();
    
        RCL_Handle h = RCL_open(&rclClient, &LRF_config);
    
        /* Prepare command */
        RCL_CmdIeeeRxTx cmd = RCL_CmdIeeeRxTx_DefaultRuntime();
        RCL_CmdIeee_RxAction rxAction = RCL_CmdIeee_RxAction_DefaultRuntime();
        RCL_CmdIeee_TxAction txAction = RCL_CmdIeee_TxAction_DefaultRuntime();
        uint32_t rxMultiBuffer[NUM_RX_BUF][MULTI_BUF_SZ / 4];
        uint32_t pktBuffer[RCL_TxBuffer_len_u32(NUM_PAD, HDR_LEN, PKT_LEN)];
        RCL_Buffer_TxBuffer *txBuffer;
    
        cmd.rfFrequency = FREQUENCY;
        /* Start command immediately */
        cmd.common.scheduling = RCL_Schedule_Now;
        cmd.common.allowDelay = true;
        cmd.txPower = (RCL_Command_TxPower) {.dBm = 0, .fraction = 0}; /* Send with 0 dBm */
        cmd.rxAction = &rxAction;
        cmd.txAction = &txAction;
    
        /* Set up RX action; used when receiving ACKs */
        rxAction = RCL_CmdIeee_RxAction_DefaultRuntime();
        rxAction.numPan = 1;
        rxAction.panConfig[0] = RCL_CmdIeee_PanConfig_DefaultRuntime();
    
        /* Set up TX Action */
        /* End command after TX and receiving ACK */
        txAction.endCmdWhenDone = true;
        /* Start TX immediately */
        txAction.ccaScheduling = RCL_Schedule_Now;
        txAction.allowDelay = true;
        /* Expect ACK after TX (set to false if no ACK is expected) */
        txAction.expectImmAck = true;
    
        uint8_t sequenceNumber = 0;
        uint32_t pktCount = 0;
        txBuffer = (RCL_Buffer_TxBuffer *)pktBuffer;
    
        /* Set up Rx (multi)buffer */
        for (int i = 0; i < NUM_RX_BUF; i++)
        {
            RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *) rxMultiBuffer[i];
            RCL_MultiBuffer_init(multiBuffer, MULTI_BUF_SZ);
            RCL_MultiBuffer_put(&rxAction.rxBuffers, multiBuffer);
        }
        generatePacketIeee(txBuffer, PKT_LEN, PKT_TYPE_PKT, sequenceNumber);
        txAction.txEntry = (RCL_Buffer_DataEntry *) (&txBuffer->length);
        /* Set status back */
        cmd.common.status = RCL_CommandStatus_Idle;
        txAction.txStatus = RCL_CommandStatus_Idle;
        /* Enter command */
        RCL_Command_submit(h, &cmd);
        /* Wait for command to finish. Alternatively, a callback on lastCmdDone may be used */
        RCL_Command_pend(&cmd);
        /* Record command status, may be checked to look for errors */
        lastStatus = cmd.common.status;
    
    }
    
    /* Function for running RX and sending ACK */
    void runIeeeRx(void)
    {
        RCL_init();
    
        RCL_Handle h = RCL_open(&rclClient, &LRF_config);
    
        /* Prepare command */
        RCL_CmdIeeeRxTx cmd = RCL_CmdIeeeRxTx_DefaultRuntime();
        RCL_CmdIeee_RxAction rxAction = RCL_CmdIeee_RxAction_DefaultRuntime();
        uint32_t rxMultiBuffer[NUM_RX_BUF][MULTI_BUF_SZ / 4];
    
        cmd.rfFrequency = FREQUENCY;
        /* Start command immediately */
        cmd.common.scheduling = RCL_Schedule_Now;
        cmd.common.allowDelay = true;
        cmd.txPower = (RCL_Command_TxPower) {.dBm = 0, .fraction = 0}; /* Send with 0 dBm */
        /* Set the command to run for up to 20 seconds */
        /* If relGracefulStopTime is set to 0, the RX command will run until stopped or until it gets an error */
        cmd.common.timing.relGracefulStopTime = RCL_SCHEDULER_SYSTIM_MS(20000);
    
        cmd.rxAction = &rxAction;
        cmd.common.runtime.callback = ieeeCallback;
        /* Set up callback on packet under reception; trigger for ACK generation */
        cmd.common.runtime.lrfCallbackMask.value = LRF_EventRxCtrlAck.value | LRF_EventRxCtrl.value | LRF_EventRxOk.value | LRF_EventRxNok.value;
        /* Set up callbacks on packet fully received and command done */
        cmd.common.runtime.rclCallbackMask.value =
            RCL_EventLastCmdDone.value | RCL_EventRxEntryAvail.value;
    
        /* Set up RX action */
        rxAction = RCL_CmdIeee_RxAction_DefaultRuntime();
        rxAction.numPan = 1;
        rxAction.panConfig[0] = RCL_CmdIeee_PanConfig_DefaultRuntime();
        /* Enable ACK of received packets */
        //rxAction.panConfig[0].autoAckMode = RCL_CmdIeee_AutoAck_ImmAckProvidedFrame;
        rxAction.panConfig[0].panCoord        = 1;
        rxAction.panConfig[0].localPanId      = 0x0504;
        memcpy(&rxAction.panConfig[0].localExtAddr, ieeeAddr, sizeof(rxAction.panConfig[0].localExtAddr));
        rxAction.panConfig[0].localShortAddr  = 0x0706;
        rxAction.panConfig[0].autoAckMode     = RCL_CmdIeee_AutoAck_ImmAckAutoPendAll;
        rxAction.panConfig[0].defaultPend     = 1;
        rxAction.panConfig[0].maxFrameVersion = 1;
        rxAction.panConfig[0].sourceMatchingTableShort             = NULL;
    
        /* Set up Rx (multi)buffer */
        for (int i = 0; i < NUM_RX_BUF; i++)
        {
            RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *) rxMultiBuffer[i];
            RCL_MultiBuffer_init(multiBuffer, MULTI_BUF_SZ);
            RCL_MultiBuffer_put(&rxAction.rxBuffers, multiBuffer);
        }
    
        /* Enter command */
        RCL_Command_submit(h, &cmd);
    
        /* Wait for command to finish. Alternatively, the callback on lastCmdDone may be used */
        RCL_Command_pend(&cmd);
    
        /* Record command status, may be checked to look for errors */
        lastStatus = cmd.common.status;
    }
    
    /*
     *  ======== mainThread ========
     */
    
    void *mainThread(void *arg0)
    {
        while (exampleMode == EXAMPLE_MODE_WAIT_FOR_DEBUGGER)
        {
            /* Wait for debugger */
        }
    
        if (exampleMode == EXAMPLE_MODE_TX)
        {
            runIeeeTx();
        }
        else if (exampleMode == EXAMPLE_MODE_RX)
        {
            runIeeeRx();
        }
    
        pthread_exit(NULL);
        return NULL;
    }

    Attached is a very basic example which I’ve confirmed works for the IEEE PHY.  When exampleMode = EXAMPLE_MODE_TX, the example sends a packet every time the device is started.  Here are the packet contents by default:

    I am using the 250 kbps O-QPSK IEEE 802.15.4 PHY in SysConfig, non-generic

    When exampleMode = EXAMPLE_MODE_RX, the example will enable the reception of packets for 20 seconds

    cmd.common.timing.relGracefulStopTime = RCL_SCHEDULER_SYSTIM_MS(20000);

    If modifying the example then it is very important that the last two bytes of the generatePacketBmack have the correct CRC-16 value, or else rclEvents.rxEntryAvail will not be entered from ieeeCallback as the packet will be filtered out (see LRF Events on how to detect and evaluate CRC and frame filtering errors).  localPanId and localShortAddr are also important, as well as localExtAddr if using an extended destination address in your TX packet’s Frame Control Field.

    This will help you get started with IEEE Proprietary RF packet transmission and reception.  This example was designed according to the IEEE 802.15.4 Rx and Tx Command Handler documentation, and I recommend that you reference it for further development.

    Regards,
    Ryan

  • Hi Ryan. Thank you, it work.