This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/LAUNCHXL-CC2640R2: Question about inserting an operation between Rx and Tx operations in rfEchoRx example project

Part Number: LAUNCHXL-CC2640R2


Tool/software: Code Composer Studio

Hello, I am modifying the rfEchoRx example project and have two questions.

I would like to insert an ultrasound listening section between the Rx and Tx operations of the board. Currently, how the project works is that a RF packet is received by the board in Rx mode; there is a 100 ms echo delay; then the board switches to Tx mode and echoes the RF packet. I am trying to insert an operation between the Rx and Tx operations, so that a RF packet would be received by the board in Rx mode; upon successful reception of the RF packet, the voltage from an ultrasound waveform would be read; there would be a 100 ms echo delay; then the board would switch to Tx mode and echo the RF packet.

1) My idea was to implement the ultrasound listening functionality in the case that the RF_EventCmdDone and RF_EventRxEntryDone events were raised (since raising both these flags indicates a successful packet reception). Would this work or would it disrupt the Rx and Tx chain of commands? 

if (e & RF_EventRxEntryDone)



        /* Successful RX */

        /* Toggle LED2, clear LED1 to indicate RX */

        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 0);

        PIN_setOutputValue(ledPinHandle, Board_PIN_LED2,

                           !PIN_getOutputValue(Board_PIN_LED2));



/*********INSERT ULTRASOUND LISTENING SECTION HERE **********/



        /* Get current unhandled data entry */

        currentDataEntry = RFQueue_getDataEntry();



        /* Handle the packet data, located at &currentDataEntry->data:

         * - Length is the first byte with the current configuration

         * - Data starts from the second byte */

        packetLength      = *(uint8_t *)(&(currentDataEntry->data));

        packetDataPointer = (uint8_t *)(&(currentDataEntry->data) + 1);



        /* Copy the payload + status byte to the rxPacket variable, and then

         * over to the txPacket

         */

        memcpy(txPacket, packetDataPointer, packetLength);



        RFQueue_nextEntry();

    }

2) How would I obtain the timestamp of the reception of the ultrasound signal? I want to measure how long after the RF packet it arrives. If I set the RF packet reception timestamp to time zero (RF_cmdPropRx.startTime = 0), then I just need to see how many RAT ticks after this the ultrasound signal appears. Could I use RF_getCurrentTime()? Or something else?

  • Hi N-M,

    Generally I would not advice to input additional code into the callback, you typically want to avoid holding this up more than needed. An alternative to this (assuming you keep the basic example structure) is to maybe perform the reading continuous on the side in it's own thread and instead poll for a value update in the callback (for example a shared variable keeping the most up to date value).

    If you want to perform the reading only at the time of the RX done then maybe you would like to brake up the chain and instead setup the task application along the lines of:

    RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal,
                                               echoCallback, (RF_EventRxEntryDone |
                                               RF_EventLastCmdDone));
    
    ...
    
    uint32_t cmdStatus = ((volatile RF_Op*)&RF_cmdPropRx)->status;
    
    switch(cmdStatus)
    {
        case PROP_DONE_OK:
            **** DO READING ****
            break;
    }
    
    // Take the timestamp from RX received as the base
    RF_cmdPropTx.startTime = rxStatistics.timestamp + TX_DELAY;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_ABS;
    
    RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal,
                                               NULL, RF_EventLastCmdDone);
    

    In this example the structure passed to RF_cmdPropRx.pOutput (which in this case is rxStatistics) will contain information on for example RSSI and the timestamp from when the packet was first received. This timestamp - RF_getCurrentTime() should give you the delta RAT ticks from reception start -> reading done.

  • Hi M-W,

    Thank you for the help! I have some follow-up questions:

    1) What is the purpose of having:

    RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal,
                                               NULL, RF_EventLastCmdDone);

    We already have:

    RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, echoCallback, (RF_EventRxEntryDone | RF_EventLastCmdDone));


    Won't the two variables clash since they are defined in the same scope in your code above? I am not sure I understand the purpose of having this line of code with another terminationReason and how it fits into the chain of commands.



    2) 'uint32_t cmdStatus' is never used anywhere else in the code. What is the purpose of having this variable?


    3) I currently have my Ultrasound reading code in the section you suggested:

    switch(cmdStatus)
    {
        case PROP_DONE_OK:
            **** DO READING ****
            break;
    }


    The Ultrasound reading works. However, the RF operation stops working after 2 successful transmissions and receptions. On the third transmission, board 1 (Tx board) transmits but board 2 (Rx board) never receives it (the red LED on board 2 never turns on). All subsequent RF packets are also not received by board 2, so board 1 keeps timing out and switching between transmission and abort mode. I have attached a picture of the waveforms to show this. The yellow channel is probing the green LED on board 1. The blue channel is probing the red LED on board 2. As you can see, only the first two transmissions are received by board 2 (since the blue probe only goes high on the first two transmissions). Note that RX timeout is 500ms, packet interval is 1s, and Tx delay is 100ms.

    What could be causing this issue?






  • Hi N-M,

    1) The redefinition of the variable is simply a copy-paste error from my side, it should only be done once. Note that the example assumes you have broken up the chain. In other words, TX is not chained to RX anymore. This is why there is two "runCmd" and also why we might be interest in the termination reason two times (first we want to know how the RX went, then how the TX did). 

    2) My best guess is that this variable is used just to create a clear example overview. You could just put the status right into the switch if you prefer that.

    3) If you moved to ABS time as suggested by me it could be that you are getting the timestamps wrong and the devices basically run out of sync. Try enabling the PA and LNA radio signals to external IOs so that you an monitor the devices going into TX/RX. For this, please see the following section in the uses guide:

    http://dev.ti.com/tirex/explore/content/simplelink_cc2640r2_sdk_4_10_00_10/docs/proprietary-rf/proprietary-rf-users-guide/rf-core/signal-routing.html#routing-doorbell-signals-to-gpio-pins

    You can scroll up for a table of available signals but the example given there should be for PA and LNA signals already. You also need to make sure the pins you try to MUX them to is setup as output prior to this. You can do this by adding the two pins you want to route to into the same PIN table that the LED pins uses.

  • Thank you.

    I commented out the following lines so that the Rx and Tx are not chained together anymore. I don't think there's anything else to remove to unchain these operations, but maybe I am wrong.

      // RF_cmdPropRx.pNextOp = (rfc_radioOp_t *)&RF_cmdPropTx; // UNCHAIN RX AND TX COMMANDS
        /* Only run the TX command if RX is successful */
    // RF_cmdPropRx.condition.rule = COND_STOP_ON_FALSE;

    I understand what you are saying about needing two "RF_runCmd". One of them is labeled with variable "terminationReason" and it is to see how the Rx goes and it calls the function "echoCallback" that raises certain flags (already in example project code). The other  "RF_runCmd" is to see how Tx goes. But with the code you provided, it looks like the callback function is null. So how are any flags raised and how does this line of code communicate with the rest of the code?

    You said that the definition of the variable was a copy-paste error on your part. Does that mean we are still needing two "Rf_runCmd" but the one for the Tx doesn't need to be assigned to a variable? 

  • What I meant by the copy paste error was simply that the "terminationReason" would be declared at the top with the first RF_runCmd call. The second call could just re-use that same variable (as the return from the RX is no longer interesting at this point in time).

    You do not need to assign a callback to raise the flags. The flags you pass into the functions is the flags it will pend on for you (including the base-line flags like LastCmdDone/Stop/Aborted).

    If you give a callback to the function, it will invoke this for you so that you could take action (like in the RX case the example initially wanted to make swift work of the RX buffer to echo). This callback has nothing to do with the flags such as "RF_EventLastCmdDone" or "RF_EventRxEntryDone" being raised. 

  • Thank you, I have an update.

    I have been able to unchain the Rx and Tx operations in the rfEchoRx project. So Tx operation triggers with TRIG_ABSTIME and its start time is rxStatistics.timeStamp + Txdelay. I verified that the output is the same as the regular rfEchoRx project (that has chained commands) by mapping the LNA (RFC_GPO0) radio signal and the transmission initiation (RFC_GPO3) radio signal to GPIOs.

    However, I am still unable to add some extra code for the 'ultrasound listening' as I discussed above. As we discussed, I tried to add some code from the adcBufContinuous project under the 'case PROP_DONE_OK' section. This extra code from the adcBufContinuous project is so that I can read and process the voltages. Although I have most of the adc code in this section (like creating a UART, setting up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS, and calling adcCallback which performs some simple calculations on the read voltages), the specific line of code that breaks the RF functionality on board 2 is:

    if (ADCBuf_convert(adcBuf, &continuousConversion, 1) !=
                        ADCBuf_STATUS_SUCCESS) {
    }

    If I comment this specific line out, the unchained Rx and Tx operations work fine. However, with the inclusion of this line of code, the RF operations on receiving board (which is running this modified version of rfEchoRx) stops functioning. It does not even receive (LNA signal never turns on), so it obviously never transmits. Because of this the transmitting board switches between transmitting and aborting.

    Why does board 2's RF functionality stop? Is the ADC somehow blocking the RF? Should the ADC conversion not be performed in this section under ''case PROP_DONE_OK''? We don't want to put the ADC code inside the RF callback, so where else would it make sense to include?

  • Hi N-M,

    You should minimize the work done here, initialization should preferably be done prior to this (so that you only had to do a convert). While the ADC should not break the Radio code (there is no such block that I'm aware of), it might not be advisable as the radio would affect the readings. The fact that you say it stops after this call leads me to believe that  this call either stalls the CPU or is blocking your task in another way. 

    If you "pause" the device when the radio activity stops, what state is it in, what is it doing? Also, could you share the current code for me to look at to see if I could spot something obvious?

  • Thank you for the help, I am attaching my versions of rfEchoTx.c and rfEchoRx.c

    In rfEchoRx, I moved the initialization code outside of the "case PROP_DONE_OK" as you suggested. But the RF functionality on board 2 still stops with the ADC conversion code line. When I "pause" the device, the board 2 is completely inactive. It acts essentially as a turned-off radio from the very beginning. 

    In rfEchoTx, most of the code is the same as the original example project. But there are a few differences (lines 236-254): along with transmitting an RF packet, I am also transmitting a PWM 40 kHz burst of 10ms. The PWM then stays idle for 1s which corresponds to the packet interval. I had to slightly delay the transmission of the RF packet to occur after the transmission of the PWM signal because it seems like they cannot be transmitted at the same time. I don't think these changes should affect my question (because the boards works fine with this modification as long as the ADC code line is omitted) but just wanted to let you know. The PWM being transmitted from board 1 is what I am trying to read using the ADC code in board 2.

    Also both files have mappings to GPIO pins to debug the LNA and transmission initiation radio signals.

    Thanks again.

    /*
     * Copyright (c) 2019, 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.
     */
    
    /***** Includes *****/
    /* Standard C Libraries */
    #include <stdlib.h>
    #include <stdint.h>
    #include <stdio.h>
    /* For sleep() */
    #include <unistd.h>
    
    /* TI Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/ADCBuf.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    
    /* Driverlib Header files */
    #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
    
    /* Board Header files */
    #include "Board.h"
    
    /* Application Header files */
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    /***** Definitions for ADC Sampling *****/
    #define ADCBUFFERSIZE    (500)
    #define UARTBUFFERSIZE   (500)
    
    uint16_t sampleBufferOne[ADCBUFFERSIZE];
    uint16_t sampleBufferTwo[ADCBUFFERSIZE];
    uint32_t microVoltBuffer[ADCBUFFERSIZE];
    uint32_t buffersCompletedCounter = 0;
    char uartTxBuffer[UARTBUFFERSIZE];
    
    /***** Definitions for RF *****/
    /* Packet RX/TX Configuration */
    /* Max length byte the radio will accept */
    #define PAYLOAD_LENGTH         30
    /* Set Transmit (echo) delay to 100ms */
    #define TX_DELAY             (uint32_t)(4000000*0.1f)
    /* NOTE: Only two data entries supported at the moment */
    #define NUM_DATA_ENTRIES       2
    /* The Data Entries data field will contain:
     * 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1)
     * Max 30 payload bytes
     * 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */
    #define NUM_APPENDED_BYTES     2
    
    /* Log radio events in the callback */
    //#define LOG_RADIO_EVENTS
    
    /***** Prototypes *****/
    static void echoCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    void adcBufCallback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion,
        void *completedADCBuffer, uint32_t completedChannel);
    void uartCallback(UART_Handle handle, void *buf, size_t count);
    
    /***** Variable declarations *****/
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    UART_Handle uart; /* Driver handle shared between the task and the callback function */
    
    /* Pin driver handle */
    static PIN_Handle pinHandle;
    static PIN_State pinState;
    
    /* Buffer which contains all Data Entries for receiving data.
     * Pragmas are needed to make sure this buffer is aligned to a 4 byte boundary
     * (requirement from the RF core)
     */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN(rxDataEntryBuffer, 4)
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)];
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)];
    #elif defined(__GNUC__)
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)]
                                                      __attribute__((aligned(4)));
    #else
    #error This compiler is not supported
    #endif //defined(__TI_COMPILER_VERSION__)
    
    
    /* Receive Statistics */
    static rfc_propRxOutput_t rxStatistics;
    
    /* Receive dataQueue for RF Core to fill in data */
    static dataQueue_t dataQueue;
    static rfc_dataEntryGeneral_t* currentDataEntry;
    static uint8_t packetLength;
    static uint8_t* packetDataPointer;
    
    
    static uint8_t txPacket[PAYLOAD_LENGTH];
    
    #ifdef LOG_RADIO_EVENTS
    static volatile RF_EventMask eventLog[32];
    static volatile uint8_t evIndex = 0;
    #endif // LOG_RADIO_EVENTS
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config pinTable[] =
    {
    #if defined(Board_CC1350_LAUNCHXL)
     Board_DIO30_SWPWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    #endif
     Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_PIN_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_DIO15 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_DIO24_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_DIO26_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     PIN_TERMINATE
    }; // ADDED Board_DIO21 (pin that connects to buzzer)
    
    /***** Function definitions *****/
    
    void *mainThread(void *arg0)
    {
        /***** RF Params *****/
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        /***** Added ADC Sampling Params *****/
        UART_Params uartParams;
        ADCBuf_Handle adcBuf;
        ADCBuf_Params adcBufParams;
        ADCBuf_Conversion continuousConversion;
    
        /* Open LED pins */
        pinHandle = PIN_open(&pinState, pinTable);
        if (pinHandle == NULL)
        {
            while(1);
        }
    
        /********** Added ADC Code **********/
        /* Call driver init functions */
        ADCBuf_init();
        UART_init();
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
        uartParams.writeDataMode = UART_DATA_BINARY;
        uartParams.writeMode = UART_MODE_CALLBACK;
        uartParams.writeCallback = uartCallback;
        uartParams.baudRate = 115200;
        uart = UART_open(Board_UART0, &uartParams);
    
        /* Set up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS */
        ADCBuf_Params_init(&adcBufParams);
        adcBufParams.callbackFxn = adcBufCallback;
        adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS;
        adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
        adcBufParams.samplingFrequency = 200000; // 200kHz
        adcBuf = ADCBuf_open(Board_ADCBUF0, &adcBufParams);
    
        /* Configure the conversion struct */
        continuousConversion.arg = NULL;
        continuousConversion.adcChannel = Board_ADCBUF0CHANNEL0;
        continuousConversion.sampleBuffer = sampleBufferOne;
        continuousConversion.sampleBufferTwo = sampleBufferTwo;
        continuousConversion.samplesRequestedCount = ADCBUFFERSIZE;
        /******************************/
    
        if( RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                PAYLOAD_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            PIN_setOutputValue(pinHandle, Board_PIN_LED1, 1);
            PIN_setOutputValue(pinHandle, Board_PIN_LED2, 1);
            while(1);
        }
    
        /* Modify CMD_PROP_TX and CMD_PROP_RX commands for application needs */
        /* Set the Data Entity queue for received data */
        RF_cmdPropRx.pQueue = &dataQueue;
        /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;
        /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;
        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRx.maxPktLen = PAYLOAD_LENGTH;
        /* End RX operation when a packet is received correctly and move on to the
         * next command in the chain */
        RF_cmdPropRx.pktConf.bRepeatOk = 0;
        RF_cmdPropRx.pktConf.bRepeatNok = 1;
        RF_cmdPropRx.startTrigger.triggerType = TRIG_NOW;
    
    //    RF_cmdPropRx.pNextOp = (rfc_radioOp_t *)&RF_cmdPropTx; // UNCHAIN RX AND TX COMMANDS
        /* Only run the TX command if RX is successful */
    //    RF_cmdPropRx.condition.rule = COND_STOP_ON_FALSE;
    //    RF_cmdPropRx.condition.rule = COND_ALWAYS;
    
        RF_cmdPropRx.pOutput = (uint8_t *)&rxStatistics;
    
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = txPacket;
    
    
        /* Request access to the radio */
    #if defined(DeviceFamily_CC26X0R2)
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioSetup, &rfParams);
    #else
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    #endif// DeviceFamily_CC26X0R2
    
        /* Set the frequency */
        RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
        while(1)
        {
            /* Wait for a packet
             * - When the first of the two chained commands (RX) completes, the
             * RF_EventCmdDone and RF_EventRxEntryDone events are raised on a
             * successful packet reception, and then the next command in the chain
             * (TX) is run
             * - If the RF core runs into an issue after receiving the packet
             * incorrectly onlt the RF_EventCmdDone event is raised; this is an
             * error condition
             * - If the RF core successfully echos the received packet the RF core
             * should raise the RF_EventLastCmdDone event
             */
            RF_EventMask terminationReason =
                    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal,
                              echoCallback, (RF_EventRxEntryDone | RF_EventLastCmdDone));
    
    
            /********** Mapping RF signals to GPIO for debugging **********/
            // Map RFC_GPO0 to IO 24
            PINCC26XX_setMux(pinHandle, IOID_24, PINCC26XX_MUX_RFC_GPO0); // LNA radio signal (high in Rx mode)
            // Map IO 26 to RFC_GPI1
            PINCC26XX_setMux(pinHandle, IOID_26, PINCC26XX_MUX_RFC_GPO3); // transmission initiation radio signal (high when transmission initiated)
    
    
            switch(terminationReason)
            {
                case RF_EventLastCmdDone:
                    // A stand-alone radio operation command or the last radio
                    // operation command in a chain finished.
                    break;
                case RF_EventCmdCancelled:
                    // Command cancelled before it was started; it can be caused
                    // by RF_cancelCmd() or RF_flushCmd().
                    break;
                case RF_EventCmdAborted:
                    // Abrupt command termination caused by RF_cancelCmd() or
                    // RF_flushCmd().
                    break;
                case RF_EventCmdStopped:
                    // Graceful command termination caused by RF_cancelCmd() or
                    // RF_flushCmd().
                    break;
                default:
                    // Uncaught error event
                    while(1);
            }
    
           uint32_t cmdStatus = ((volatile RF_Op*)&RF_cmdPropRx)->status;
            switch(cmdStatus)
            {
    
                case PROP_DONE_OK:
                    // Packet received with CRC OK
    
                    /******************  Added ADC code *******************/
    
                    if (adcBuf == NULL){
                        /* ADCBuf failed to open. */
                        while(1);
                    }
    
                    /* Start converting. */
                    if (ADCBuf_convert(adcBuf, &continuousConversion, 1) !=
                        ADCBuf_STATUS_SUCCESS) {
                        /* Did not start conversion process correctly. */
                        while(1);
                    }
    
                    /*
                     * Go to sleep in the foreground thread forever. The ADC hardware will
                     * perform conversions and invoke the callback function when a buffer is
                     * full.
                     */
                    while(1) {
                        sleep(1000);
                    }
    
                    /************************************/
    
    //                break;
    
                case PROP_DONE_RXERR:
                    // Packet received with CRC error
                    break;
                case PROP_DONE_RXTIMEOUT:
                    // Observed end trigger while in sync search
                    break;
                case PROP_DONE_BREAK:
                    // Observed end trigger while receiving packet when the command is
                    // configured with endType set to 1
                    break;
                case PROP_DONE_ENDED:
                    // Received packet after having observed the end trigger; if the
                    // command is configured with endType set to 0, the end trigger
                    // will not terminate an ongoing reception
                    break;
                case PROP_DONE_STOPPED:
                    // received CMD_STOP after command started and, if sync found,
                    // packet is received
                    break;
                case PROP_DONE_ABORT:
                    // Received CMD_ABORT after command started
                    break;
                case PROP_ERROR_RXBUF:
                    // No RX buffer large enough for the received data available at
                    // the start of a packet
                    break;
                case PROP_ERROR_RXFULL:
                    // Out of RX buffer space during reception in a partial read
                    break;
                case PROP_ERROR_PAR:
                    // Observed illegal parameter
                    break;
                case PROP_ERROR_NO_SETUP:
                    // Command sent without setting up the radio in a supported
                    // mode using CMD_PROP_RADIO_SETUP or CMD_RADIO_SETUP
                    break;
                case PROP_ERROR_NO_FS:
                    // Command sent without the synthesizer being programmed
                    break;
                case PROP_ERROR_RXOVF:
                    // RX overflow observed during operation
                    break;
                default:
                    // Uncaught error event - these could come from the
                    // pool of states defined in rf_mailbox.h
                    while(1);
            }
    
            /******* Added code for execution of unchained Tx command *******/
    
           RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;   // CHANGED TO TRIG_ABS so Tx can trigger at absolute time defined by Tx.startTime
    
           RF_cmdPropTx.startTime = rxStatistics.timeStamp + TX_DELAY; // ADDED rxStatistics.timeStamp
    
           terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal,
                                                      NULL, RF_EventLastCmdDone);
           /******************************************/
    
        }
    }
    
    static void echoCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
    #ifdef LOG_RADIO_EVENTS
        eventLog[evIndex++ & 0x1F] = e;
    #endif// LOG_RADIO_EVENTS
    
        if (e & RF_EventRxEntryDone)
        {
            /* Successful RX */
            /* Toggle LED2, clear LED1 to indicate RX */
            PIN_setOutputValue(pinHandle, Board_PIN_LED1, 0);
            PIN_setOutputValue(pinHandle, Board_PIN_LED2,
                               !PIN_getOutputValue(Board_PIN_LED2));
    
            /* Get current unhandled data entry */
            currentDataEntry = RFQueue_getDataEntry();
    
            /* Handle the packet data, located at &currentDataEntry->data:
             * - Length is the first byte with the current configuration
             * - Data starts from the second byte */
            packetLength      = *(uint8_t *)(&(currentDataEntry->data));
            packetDataPointer = (uint8_t *)(&(currentDataEntry->data) + 1);
    
            /* Copy the payload + status byte to the rxPacket variable, and then
             * over to the txPacket
             */
            memcpy(txPacket, packetDataPointer, packetLength);
    
            RFQueue_nextEntry();
        }
        else if (e & RF_EventLastCmdDone)
        {
    //        /* Successful Echo (TX)*/
    //        /* Toggle LED2, clear LED1 to indicate RX */
            PIN_setOutputValue(pinHandle, Board_PIN_LED1, 0);
            PIN_setOutputValue(pinHandle, Board_PIN_LED2,
                               !PIN_getOutputValue(Board_PIN_LED2));
    
        }
        else // any uncaught event
        {
            /* Error Condition: set LED1, clear LED2 */
            PIN_setOutputValue(pinHandle, Board_PIN_LED1, 1);
            PIN_setOutputValue(pinHandle, Board_PIN_LED2, 0);
        }
    }
    
    /*
     * This function is called whenever an ADC buffer is full.
     * The content of the buffer is then converted into human-readable format and
     * sent to the PC via UART.
     */
    void adcBufCallback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion,
        void *completedADCBuffer, uint32_t completedChannel) {
    
        uint_fast16_t i;
        uint_fast16_t uartTxBufferOffset = 0;
    
        /* Adjust raw ADC values and convert them to microvolts */
        ADCBuf_adjustRawValues(handle, completedADCBuffer, ADCBUFFERSIZE,
            completedChannel);
        ADCBuf_convertAdjustedToMicroVolts(handle, completedChannel,
            completedADCBuffer, microVoltBuffer, ADCBUFFERSIZE);
    
        //**************************  added code for calculations **************************//
    
         uint16_t a = 0;
         uint16_t b = 0;
         uint64_t sum = 0;
         uint32_t average = 0;
         uint32_t max = 0;
    
         // loop through the 10 bins
         while (a < (ADCBUFFERSIZE/50)) {
             // loop through the 50 microvoltbuffer values associated with each bin (b<50, 50<b<100, 100<b<150, etc.)
             while (b < (ADCBUFFERSIZE/10 + 50*a)) {
                 sum = sum + abs(microVoltBuffer[b]);
                 b++; // increment sample number (will do 50 samples for each bin)
    
                 // printf("%u\n", (unsigned int) microVoltBuffer[b]);
             }
             average = sum / 500; // calculate average of the bin
             // to find max average value among the 10 bins
             if (average > max) {
                 max = average;
             }
             a++; // increment bin number
         }
    
         // make pin go high if peak average value over the 2.5 ms sampling interval is greater than a threshold value
         if (max > 150000) { // 150mV
             // digital pin 15 goes high
             PIN_setOutputValue(pinHandle, Board_DIO15, 1);
         }
         else {
             // digital pin 15 goes low
             PIN_setOutputValue(pinHandle, Board_DIO15, 0);
         }
    
         //****************************************************//
    
        /* Start with a header message. */
        uartTxBufferOffset = snprintf(uartTxBuffer,
            UARTBUFFERSIZE - uartTxBufferOffset, "\r\nBuffer %u finished.",
            (unsigned int)buffersCompletedCounter++);
    
    //    /* Write raw adjusted values to the UART buffer if there is room. */
    //    uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
    //        UARTBUFFERSIZE - uartTxBufferOffset, "\r\nRaw Buffer: ");
    //
    //    for (i = 0; i < ADCBUFFERSIZE && uartTxBufferOffset < UARTBUFFERSIZE; i++) {
    //        uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
    //            UARTBUFFERSIZE - uartTxBufferOffset, "%u,",
    //        *(((uint16_t *)completedADCBuffer) + i));
    //    }
    
        /* Write microvolt values to the UART buffer if there is room. */
        if (uartTxBufferOffset < UARTBUFFERSIZE) {
            uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
                UARTBUFFERSIZE - uartTxBufferOffset, "\r\nMicrovolts: ");
    
            for (i = 0; i < ADCBUFFERSIZE && uartTxBufferOffset < UARTBUFFERSIZE; i++) {
                uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
                    UARTBUFFERSIZE - uartTxBufferOffset, "%u,",
                    (unsigned int)microVoltBuffer[i]);
            }
    
    //        for (i = 0; i < ADCBUFFERSIZE/50 && uartTxBufferOffset < UARTBUFFERSIZE/50; i++) {
    //                    uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
    //                        UARTBUFFERSIZE/50 - uartTxBufferOffset, " Max is %u,",
    //                        (unsigned int) max);
    //        }
        }
    
        /*
         * Ensure we don't write outside the buffer.
         * Append a newline after the data.
         */
        if (uartTxBufferOffset < UARTBUFFERSIZE) {
            uartTxBuffer[uartTxBufferOffset++] = '\n';
        }
        else {
            uartTxBuffer[UARTBUFFERSIZE-1] = '\n';
        }
    
        /* Display the data via UART */
        UART_write(uart, uartTxBuffer, uartTxBufferOffset);
    }
    
    /*
     * Callback function to use the UART in callback mode. It does nothing.
     */
    void uartCallback(UART_Handle handle, void *buf, size_t count) {
       return;
    }
    

    /*
     * Copyright (c) 2019, 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.
     */
    
    /***** Includes *****/
    /* Standard C Libraries */
    #include <stdlib.h>
    
    /* TI Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    #include <ti/drivers/PWM.h> // for PWM
    
    /* Driverlib Header files */
    #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
    
    /* Board Header files */
    #include "Board.h"
    
    /* Application Header files */
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    /***** Defines *****/
    /* Packet TX/RX Configuration */
    #define PAYLOAD_LENGTH      30
    /* Set packet interval to 1000ms */
    #define PACKET_INTERVAL     (uint32_t)(4000000*1.0f)
    /* Set Receive timeout to 500ms */
    #define RX_TIMEOUT          (uint32_t)(4000000*0.5f)
    /* NOTE: Only two data entries supported at the moment */
    #define NUM_DATA_ENTRIES    2
    /* The Data Entries data field will contain:
     * 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1)
     * Max 30 payload bytes
     * 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */
    #define NUM_APPENDED_BYTES  2
    
    /* Log radio events in the callback */
    //#define LOG_RADIO_EVENTS
    
    /***** Prototypes *****/
    static void echoCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    
    /***** Variable declarations *****/
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    /* Pin driver handle */
    static PIN_Handle ledPinHandle;
    static PIN_State ledPinState;
    
    /* Buffer which contains all Data Entries for receiving data.
     * Pragmas are needed to make sure this buffer is aligned to a 4 byte boundary
     * (requirement from the RF core)
     */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN(rxDataEntryBuffer, 4)
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)];
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)];
    #elif defined(__GNUC__)
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      PAYLOAD_LENGTH,
                                                      NUM_APPENDED_BYTES)]
                                                      __attribute__((aligned(4)));
    #else
    #error This compiler is not supported
    #endif //defined(__TI_COMPILER_VERSION__)
    
    /* Receive Statistics */
    static rfc_propRxOutput_t rxStatistics;
    
    /* Receive dataQueue for RF Core to fill in data */
    static dataQueue_t dataQueue;
    static rfc_dataEntryGeneral_t* currentDataEntry;
    static uint8_t packetLength;
    static uint8_t* packetDataPointer;
    
    static uint8_t txPacket[PAYLOAD_LENGTH];
    static uint8_t rxPacket[PAYLOAD_LENGTH + NUM_APPENDED_BYTES - 1];
    static uint16_t seqNumber;
    
    static volatile bool bRxSuccess = false;
    
    #ifdef LOG_RADIO_EVENTS
    static volatile RF_EventMask eventLog[32];
    static volatile uint8_t evIndex = 0;
    #endif // LOG_RADIO_EVENTS
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config pinTable[] =
    {
    #if defined(Board_CC1350_LAUNCHXL)
     Board_DIO30_SWPWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    #endif
     Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_PIN_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_DIO24_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     Board_DIO26_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     PIN_TERMINATE
    };
    
    /***** Function definitions *****/
    
    void *mainThread(void *arg0)
    {
        /******************** Setup for PWM code to create 40kHz square-wave burst for 1ms ********************/
    
        /* Period and duty */
        uint16_t   pwmPeriod = 25; // in microseconds (40kHz)
        uint32_t   duty;
    
        /* Sleep time in microseconds */
        PWM_Handle pwm2 = NULL;
        PWM_Params params;
    
        /* Call driver init functions. */
        PWM_init();
    
        PWM_Params_init(&params);
        params.dutyUnits = PWM_DUTY_FRACTION;
        params.dutyValue = 0;
        params.periodUnits = PWM_PERIOD_US;
        params.periodValue = pwmPeriod;
    
        // Board_PWM2 = CC2640R2_LAUNCHXL_PWM2 (in Board.h) which I assigned to CC2640R2_LAUNCHXL_DIO21 in CC2640R2_LAUNCHXL.h
        pwm2 = PWM_open(Board_PWM2, &params);
        if (pwm2 == NULL) {
            /* Board_PWM2 did not open */
            while (1);
        }
    
        PWM_start(pwm2);
    
        /******************** Setup for rfTx code to send RF signal and later receive echo (board 1)********************/
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, pinTable);
        if (ledPinHandle == NULL) {
            while(1);
        }
    
        uint32_t curtime;
        uint32_t Txtime;
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
    
        if(RFQueue_defineQueue(&dataQueue,
                               rxDataEntryBuffer,
                               sizeof(rxDataEntryBuffer),
                               NUM_DATA_ENTRIES,
                               PAYLOAD_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 1);
            while(1);
        }
    
        /* Modify CMD_PROP_TX and CMD_PROP_RX commands for application needs */
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = txPacket;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
        RF_cmdPropTx.startTrigger.pastTrig = 1;
        RF_cmdPropTx.startTime = 0;
        RF_cmdPropTx.pNextOp = (rfc_radioOp_t *)&RF_cmdPropRx;
        /* Only run the RX command if TX is successful */
        RF_cmdPropTx.condition.rule = COND_STOP_ON_FALSE;
    
        /* Set the Data Entity queue for received data */
        RF_cmdPropRx.pQueue = &dataQueue;
        /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;
        /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;
        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRx.maxPktLen = PAYLOAD_LENGTH;
        RF_cmdPropRx.pktConf.bRepeatOk = 0;
        RF_cmdPropRx.pktConf.bRepeatNok = 0;
        RF_cmdPropRx.pOutput = (uint8_t *)&rxStatistics;
        /* Receive operation will end RX_TIMEOUT ms after command starts */
        RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_PREVEND;
        RF_cmdPropRx.endTime = RX_TIMEOUT;
    
        /* Request access to the radio */
    #if defined(DeviceFamily_CC26X0R2)
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioSetup, &rfParams);
    #else
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    #endif// DeviceFamily_CC26X0R2
    
        /* Set the frequency */
        RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
    
        while(1)
        {
    
            _delay_cycles(47300000-1); // 1s delay between each cycle of RF & US bursts
    
            /*********** Delay transmission of RF packet to be after US signal
             * because both cannot happen at same time ************/
    
            curtime = RF_getCurrentTime();
            Txtime = curtime + (uint32_t)(4000000*0.005f); // (5ms but board cannot transmit RF and US at same time, so it sets RF to 1.75ms delay after US if Txtime is <=10ms)
            RF_cmdPropTx.startTime = Txtime; // delay RF packet transmission time by 5ms so US square-wave emitted first
    
            /* Loop forever incrementing the PWM duty */
            duty = (uint32_t) (((uint64_t) PWM_DUTY_FRACTION_MAX * 50) / 100); // set duty cycle to 50%
            PWM_setDuty(pwm2, duty);
            _delay_cycles(473000-1); // 10ms delay to sustain burst
            PWM_setDuty(pwm2, 0); // set duty cycle to 0 (no signal)
    
    
            /******************** RF loop ********************/
    
            /* Create packet with incrementing sequence number and random payload */
            txPacket[0] = (uint8_t)(seqNumber >> 8);
            txPacket[1] = (uint8_t)(seqNumber++);
            uint8_t i;
            for (i = 2; i < PAYLOAD_LENGTH; i++)
            {
                txPacket[i] = rand();
            }
    
    
            /* Transmit a packet and wait for its echo.
             * - When the first of the two chained commands (TX) completes, the
             * RF_EventCmdDone event is raised but not RF_EventLastCmdDone
             * - The RF_EventLastCmdDone in addition to the RF_EventCmdDone events
             * are raised when the second, and therefore last, command (RX) in the
             * chain completes
             * -- If the RF core successfully receives the echo it will also raise
             * the RF_EventRxEntryDone event
             * -- If the RF core times out while waiting for the echo it does not
             * raise the RF_EventRxEntryDone event
             */
            RF_EventMask terminationReason =
                    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal,
                              echoCallback, (RF_EventCmdDone | RF_EventRxEntryDone |
                              RF_EventLastCmdDone));
    
            /********** Mapping RF signals to GPIO for debugging **********/
            // Map RFC_GPO0 to IO 24
            PINCC26XX_setMux(ledPinHandle, IOID_24, PINCC26XX_MUX_RFC_GPO0); // LNA radio signal (high in Rx mode)
            // Map IO 26 to RFC_GPI1
            PINCC26XX_setMux(ledPinHandle, IOID_26, PINCC26XX_MUX_RFC_GPO3); // transmission initiation radio signal (high when transmission initiated)
    
    
            switch(terminationReason)
            {
                case RF_EventLastCmdDone:
                    // A stand-alone radio operation command or the last radio
                    // operation command in a chain finished.
                    break;
                case RF_EventCmdCancelled:
                    // Command cancelled before it was started; it can be caused
                // by RF_cancelCmd() or RF_flushCmd().
                    break;
                case RF_EventCmdAborted:
                    // Abrupt command termination caused by RF_cancelCmd() or
                    // RF_flushCmd().
                    break;
                case RF_EventCmdStopped:
                    // Graceful command termination caused by RF_cancelCmd() or
                    // RF_flushCmd().
                    break;
                default:
                    // Uncaught error event
                    while(1);
            }
    
            uint32_t cmdStatus = ((volatile RF_Op*)&RF_cmdPropTx)->status;
            switch(cmdStatus)
            {
                case PROP_DONE_OK:
                    // Packet transmitted successfully
                    break;
                case PROP_DONE_STOPPED:
                    // received CMD_STOP while transmitting packet and finished
                    // transmitting packet
                    break;
                case PROP_DONE_ABORT:
                    // Received CMD_ABORT while transmitting packet
                    break;
                case PROP_ERROR_PAR:
                    // Observed illegal parameter
                    break;
                case PROP_ERROR_NO_SETUP:
                    // Command sent without setting up the radio in a supported
                    // mode using CMD_PROP_RADIO_SETUP or CMD_RADIO_SETUP
                    break;
                case PROP_ERROR_NO_FS:
                    // Command sent without the synthesizer being programmed
                    break;
                case PROP_ERROR_TXUNF:
                    // TX underflow observed during operation
                    break;
                default:
                    // Uncaught error event - these could come from the
                    // pool of states defined in rf_mailbox.h
                    while(1);
            }
        }
    }
    
    static void echoCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
    #ifdef LOG_RADIO_EVENTS
        eventLog[evIndex++ & 0x1F] = e;
    #endif// LOG_RADIO_EVENTS
    
        if((e & RF_EventCmdDone) && !(e & RF_EventLastCmdDone))
        {
            /* Successful TX */
            /* Toggle LED1, clear LED2 to indicate TX */
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1,
                               !PIN_getOutputValue(Board_PIN_LED1));
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 0);
        }
        else if(e & RF_EventRxEntryDone)
        {
            /* Successful RX */
            bRxSuccess = true;
    
            /* Get current unhandled data entry */
            currentDataEntry = RFQueue_getDataEntry();
    
            /* Handle the packet data, located at &(currentDataEntry->data):
             * - Length is the first byte with the current configuration
             * - Data starts from the second byte
             */
            packetLength      = *(uint8_t *)(&(currentDataEntry->data));
            packetDataPointer = (uint8_t *)(&(currentDataEntry->data) + 1);
    
            /* Copy the payload + status byte to the rxPacket variable */
            memcpy(rxPacket, packetDataPointer, (packetLength + 1));
    
            /* Check the packet against what was transmitted */
            int16_t status = memcmp(txPacket, rxPacket, packetLength);
    
            if(status == 0)
            {
                /* Toggle LED1, clear LED2 to indicate RX */
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1,
                                   !PIN_getOutputValue(Board_PIN_LED1));
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 0);
            }
            else
            {
                /* Error Condition: set both LEDs */
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 1);
            }
    
            RFQueue_nextEntry();
        }
        else if((e & RF_EventLastCmdDone) && !(e & RF_EventRxEntryDone))
        {
            if(bRxSuccess == true)
            {
                /* Received packet successfully but RX command didn't complete at
                 * the same time RX_ENTRY_DONE event was raised. Reset the flag
                 */
                bRxSuccess = false;
            }
            else
            {
                /* RX timed out */
                /* Set LED2, clear LED1 to indicate TX */
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 0);
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 1);
            }
        }
        else
        {
            /* Error Condition: set both LEDs */
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 1);
        }
    }
    

  • Hi N-M,

    I would consider these lines in the RX side a bit more:

                    /* Start converting. */
                    if (ADCBuf_convert(adcBuf, &continuousConversion, 1) !=
                        ADCBuf_STATUS_SUCCESS) {
                        /* Did not start conversion process correctly. */
                        while(1);
                    }
    
                    /*
                     * Go to sleep in the foreground thread forever. The ADC hardware will
                     * perform conversions and invoke the callback function when a buffer is
                     * full.
                     */
                    while(1) {
                        sleep(1000);
                    }

    First of, you configure the ADCBuf to run continuously, you only need to start it once unless you stop it manually. The second part about the "foreground thread", this is basically a while forever with power saving, once you get in here you will never get out again (as the comment suggest). I don't get the logic behind this but it will also mean you stop RX/TX operations as you never call any RF_runCmd() again.

  • Thank you for taking a look at the code.

    To start ADCBuf only once, I am guessing I would have to change the following parameters:

    adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS;
    
    adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;

    to these:

    adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_ONE_SHOT;
    
    adcBufParams.returnMode = ADCBuf_RETURN_MODE_BLOCKING;

    However, will this interfere with the functionality of the ADC? Essentially what I am doing in adcCallback is sampling the data for a total time of 2.5ms at a 200kHz sampling frequency. And I loop through 10 "bins" (each 0.25ms) to find the average voltage in each bin and finally the max. average voltage across the 2.5ms. If the recurrence mode is ONE_SHOT then I think that it should call adcCallback once in the code (for each time board 2 has a reception) and sample for 2.5ms, then move onto the Tx operation. Which is what I want.

    However, I tried changing the above adcBuf parameters to ONE_SHOT and MODE_BLOCKING and the max. average is no longer being detected as it was before (rf is working though). Were you referring to some other method of only calling ADCBuf once?

     

  • Never mind, I just needed to add ADCBbuf_Cancel() to call it once. Thank you for all your help on this!