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.

2-way communication between radio modules

Other Parts Discussed in Thread: CC1310

Hi Team,

I am looking for any documentation that shows how 2-way communication can be established between 2 CC1310 Development modules.

My purpose is the change the data rate or the frequency on fly and for that message sent by the transmitter has to get an acknowledgement from the receive before the changes are made.

Please provide some idea on this.

Thank you

Vikram

  • Yes, I believe it is possible to change the frequency on the fly. You need to modify the appropriate register during run-time. Use smart RF studio to find the register values for both frequencies.
  • Hi Chen, we have already purchased the SimpleLink CC1310 Evaluation Module Kit and I am using that along with the SmartRF06 Evaluation Board.
    Is there any way to establish the 2-way communication on this setup?
    Thank you
    Vikram
  • I am using the CC1310 Evaluation Module Kit with the SmartRF06 Evaluation Board.
    Have 2 CC1310 EM.
    And in order for communication to occur both boards need to be setup on same frequency and data rate.

    So until the other board sends ack signal over the action send by first board both the boards will not change the frequency in run time.
    And hence the issue is how to make the first board know that the frequency on second board is changed?

    Thank you
    Vikram
  • Hi Vikram,

    for two-way communication between two modules (that's what I understand), you can use the wireless sensor network examples (rfWsnNode/Concentrator).They use acknowledgement messages. If both sides can initiate a transmission, you would put both modules into RX state and just switch to TX when one side wants to transmit data. After that, the sending node would go immediately back into RX state and wait for a reply or otherwise, resend it, but use a random delay.

    For frequency hopping or data rate change, there are two ways of realizing such systems:

    1. Asynchronous: Make sure that all participants are informed about the switch. You must use 3-way hand-shaking here which costs a lot of bandwidth.
    2. Most implementations use synchronized clocks and hop on a predefined scheme with fixed time slots. The only difficulty here is, to do an initial synchronization. The coordination effort is much less after that.

  • Thank you Richard.

    I will try that one out.

    Vikram

  • Hi Richard,

    I tried using the concept that you have mentioned of putting both modules in receiver mode and then switching to Tx mode when it is ready to send the data.

    However, in my case once the board changes from Rx to Tx mode it stays stuck in that mode and the other board which was acting as Tx does not go into receive mode.

    I also tried to understand the code of LBT(Listen Before Talk) where the code initially makes the module in Rx mode and then switches to Tx mode. But unable to find where the interrupts are cleared in the callback function.

    Please can you suggest me or guide me to check where this clearing of interrupts is occuring or is there any document regarding the driver library for the RF driver library functions?

    Thank you in advance.

    Vikram

  • Hi Vikram,

    please post the application source code that you use then I can have a look at it. I don't know which interrupts you are talking about because the RF driver handles all RF-related interrupts.
  • Hi Richard,

    The purpose of the code is as below:

    At start up one board is Tx and another is Rx. On button press event (BUTTON_UP), on Tx board it sends packet to second board that is in Rx mode.

    Depending on which button is pressed both boards have to change the mode of operation. If BUTTON_UP is pressed that lights LED_4 the mode does not change. 

    If BUTTON_DOWN is pressed, the board sends the information to second board that was in Rx mode before the former board goes into Rx mode.

    The second board that was inf Rx state once if receives the packet and turns on LED_1 goes into Tx mode.

    So now pressing the BUTTON_UP on second board should transmit the data on the first board.

    This sequence should continue. 

    I am attaching both codes Tx side and Rx side for review.

    Hope to hear soon.

    Thank you

    Tx side.txt
    /*
     * Copyright (c) 2015-2016, 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.
     */
    
    /*
     *  ======== empty.c ========
     */
    /* XDCtools Header files */
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* TI-RTOS Header files */
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/rf/RF.h>
    
    /* Board Header files */
    #include "Board.h"
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    #define TX_TASKSTACKSIZE   1024
    #define TX_TASK_PRIORITY   3
    #define RX_TASK_PRIORITY   2
    
    /* TX Configuration */
    #define PAYLOAD_LENGTH      30
    #define PACKET_INTERVAL     (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
    #define NUM_APPENDED_BYTES     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_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
    
    /***** Prototypes *****/
    static void txTaskFunction(UArg arg0, UArg arg1);
    void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId);
    void TxTask_init(PIN_Handle inPinHandle);
    static void callbackRx(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    //static void rxTaskFunction(UArg arg0, UArg arg1);
    
    
    static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
    																 PAYLOAD_LENGTH,
                                                                     NUM_APPENDED_BYTES)];
    /* 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 boardLED1 = 0;
    static uint32_t currVal = 0;
    
    static Task_Params txTaskParams;
    Task_Struct task0Struct;
    static Char task0Stack[TX_TASKSTACKSIZE];
    
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    int32_t packVal = 0;
    uint32_t time;
    static uint8_t packet[PAYLOAD_LENGTH+1];
    static uint16_t seqNumber;
    
    /* Pin driver handle */
    static PIN_Handle ledPinHandle;
    static PIN_Handle buttonPinHandle;
    
    /* Global memory storage for a PIN_Config table */
    static PIN_State buttonPinState;
    static PIN_State ledPinState;
    
    /* TX Semaphore */
    static Semaphore_Struct txSemaphore;
    static Semaphore_Handle txSemaphoreHandle;
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config ledPinTable[] = {
        Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config buttonPinTable[] = {
        Board_BUTTON0  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        Board_BUTTON1  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        PIN_TERMINATE
    };
    
    /*
     *  ======== buttonCallbackFxn ========
     *  Pin interrupt Callback function board buttons configured in the pinTable.
      */
    void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId) {
    
        /* Debounce logic, only toggle if the button is still pushed (low) */
        CPUdelay(8000*50);
        if (!PIN_getInputValue(pinId)) {
            /* Toggle LED based on the button pressed */
            switch(pinId) {
                case Board_BUTTON0:
                    packVal = 123;
                    currVal =  PIN_getOutputValue(Board_LED0);
                    PIN_setOutputValue(ledPinHandle, Board_LED0, !currVal);
                    break;
    
                case Board_BUTTON1:
                    packVal = 321;
                    currVal =  PIN_getOutputValue(Board_LED1);
                    PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
                    boardLED1 = 1;
                    break;
    
                default:
                    /* Do nothing */
                	PIN_setOutputValue(ledPinHandle, Board_LED0, 1);
                	PIN_setOutputValue(ledPinHandle, Board_LED1, 1);
                    break;
            }
        }
        /* Post TX semaphore to TX task */
         Semaphore_post(txSemaphoreHandle);
    }
    
    /* Receive Callback Function */
    void callbackRx(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventRxEntryDone)
        {
            do
            {
    			/* 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 + the status byte to the packet variable */
    			memcpy(packet, packetDataPointer, (packetLength + 1));
    
    			if((*(packet+2)) == (uint8_t)123)
    			{
    				/* Toggle pin to indicate RX */
    				PIN_setOutputValue(ledPinHandle, Board_LED0,!PIN_getOutputValue(Board_LED0));
    			}
    			else if((*(packet+2)) == (uint8_t)321)
    			{
    				boardLED1 = 0;
    				PIN_setOutputValue(ledPinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
    				txTaskParams.priority = TX_TASK_PRIORITY;
    				//RF_cmdNop.pNextOp = (rfc_radioOp_t*)&RF_cmdPropTx;
    				RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);
    			}
    			else
    			{
    				PIN_setOutputValue(ledPinHandle, Board_LED0,!PIN_getOutputValue(Board_LED0));
    				PIN_setOutputValue(ledPinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
    			}
    
            }while(RFQueue_nextEntry() == DATA_ENTRY_FINISHED);
        }
    }
    
    
    /***** Function definitions *****/
    void TxTask_init(PIN_Handle inPinHandle)
    {
    	//pinHandle = inPinHandle;
        /* Initialize TX semaphore */
        Semaphore_construct(&txSemaphore, 0, NULL);
        txSemaphoreHandle = Semaphore_handle(&txSemaphore);
    
        Task_Params_init(&txTaskParams);
        txTaskParams.stackSize = TX_TASKSTACKSIZE;
        txTaskParams.priority = TX_TASK_PRIORITY;
        txTaskParams.stack = &task0Stack;
        txTaskParams.arg0 = (UInt)1000000;
    
        Task_construct(&task0Struct,txTaskFunction,&txTaskParams, NULL);
    }
    /*
     *  ======== txTaskFunction ========
     *  Transmit the data over RF radio.
     *  Blink LED when data is transmitted.
     */
    static void txTaskFunction(UArg arg0, UArg arg1)
    {
        uint32_t time;
    
        /* Setup callback for button pins */
        if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFxn) != 0) {
            System_abort("Error registering button callback function");
        }
    
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = packet;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
        RF_cmdPropTx.startTrigger.pastTrig = 1;
        RF_cmdPropTx.startTime = 0;
    
        if( RFQueue_defineQueue(&dataQueue,
                                 rxDataEntryBuffer,
                                 sizeof(rxDataEntryBuffer),
                                 NUM_DATA_ENTRIES,
     							PAYLOAD_LENGTH + NUM_APPENDED_BYTES))
         {
             /* Failed to allocate space for all data entries */
             while(1);
         }
    
        /* Modify CMD_PROP_RX command for application needs */
         RF_cmdPropRx.pQueue = &dataQueue;           /* Set the Data Entity queue for received data */
         RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;  /* Discard ignored packets from Rx queue */
         RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;   /* Discard packets with CRC error from Rx queue */
         RF_cmdPropRx.maxPktLen = PAYLOAD_LENGTH;        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
         RF_cmdPropRx.pktConf.bRepeatOk = 1;
         RF_cmdPropRx.pktConf.bRepeatNok = 1;
    
    
        /* Request access to the radio */
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        /* Set the frequency */
        RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
        /* Get current time */
        time = RF_getCurrentTime();
    
        while(1)
        {
            /* Wait for a button press */
            Semaphore_pend(txSemaphoreHandle, BIOS_WAIT_FOREVER);
    
            /* Create packet with incrementing sequence number and random payload */
            packet[0] = (uint8_t)(seqNumber >> 8);
            packet[1] = (uint8_t)(seqNumber++);
            uint8_t i;
            for (i = 2; i < PAYLOAD_LENGTH; i++)
            {
                //packet[i] = rand();
                packet[i] = packVal;
            }
    
            /* Set absolute TX time to utilize automatic power management */
            time += PACKET_INTERVAL;
            RF_cmdPropTx.startTime = time;
    
    
            /* Send packet */
            RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);
    
            if (!(result & RF_EventLastCmdDone))
            {
                /* Error */
                while(1);
            }
            while((currVal !=  PIN_getOutputValue(Board_LED1))&&(boardLED1 == 1))
            {
                /* Enter RX mode and stay forever in RX */
    
            	txTaskParams.priority = RX_TASK_PRIORITY;
            	RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callbackRx, IRQ_RX_ENTRY_DONE);
            	while(1);
            	//RF_pendCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callbackRx, IRQ_RX_ENTRY_DONE);
            }
    
        }
    }
    
    
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        //Task_Params taskParams;
    
        /* Call board init functions */
        Board_initGeneral();
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, ledPinTable);
        if(!ledPinHandle) {
            System_abort("Error initializing board LED pins\n");
        }
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
        if(!buttonPinHandle) {
            System_abort("Error initializing button pins\n");
        }
    
        /* Initialize task */
        TxTask_init(ledPinHandle);
    
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    
    Rx side.txt
    /*
     * Copyright (c) 2015-2016, 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.
     */
    
    /*
     *  ======== empty.c ========
     */
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <stdlib.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* TI-RTOS Header files */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <driverlib/rf_prop_mailbox.h>
    
    /* Board Header files */
    #include "Board.h"
    
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    #define TASKSTACKSIZE   1024
    #define RX_TASK_PRIORITY   2
    #define TX_TASK_PRIORITY   3
    
    /* TX Configuration */
    #define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
    #define MAX_LENGTH             30 /* Max length byte the radio will accept */
    #define NUM_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
    #define NUM_APPENDED_BYTES     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 PACKET_INTERVAL     (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config ledPinTable[] = {
        Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config buttonPinTable[] = {
        Board_BUTTON0  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        Board_BUTTON1  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        PIN_TERMINATE
    };
    
    /***** Prototypes *****/
    static void txTaskFunction(UArg arg0, UArg arg1);
    static void rxTaskFunction(UArg arg0, UArg arg1);
    static void callbackRx(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    void callbackTx(PIN_Handle handle, PIN_Id pinId);
    
    /* Pin driver handle */
    static PIN_Handle ledPinHandle;
    static PIN_State ledPinState;
    
    static PIN_Handle buttonPinHandle;
    static PIN_State buttonPinState;
    
    
    /***** Variable declarations *****/
    
    static Task_Params rxTaskParams;
    Task_Struct rxTask;
    static Char rxTaskStack[TASKSTACKSIZE];
    static Task_Params txTaskParams;
    Task_Struct txTask;    /* not static so you can see in ROV */
    static uint8_t txTaskStack[TASKSTACKSIZE];
    
    Semaphore_Struct semTxStruct;
    Semaphore_Handle semTxHandle;
    Semaphore_Struct semRxStruct;
    Semaphore_Handle semRxHandle;
    
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN (rxDataEntryBuffer, 4);
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    #endif
    
    static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                                     MAX_LENGTH,
                                                                     NUM_APPENDED_BYTES)];
    
    
    static Semaphore_Handle txSemaphoreHandle;
    
    int32_t packVal = 0;
    uint32_t currVal = 0;
    
    /* 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;
    uint32_t time;
    static uint8_t txPacket[MAX_LENGTH];
    static uint16_t seqNumber;
    static PIN_Handle pinHandle;
    static uint8_t packet[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */
    
    /***** Function definitions *****/
    void RxTask_init(PIN_Handle ledPinHandle) {
        pinHandle = ledPinHandle;
    
        Task_Params_init(&rxTaskParams);
        rxTaskParams.stackSize = TASKSTACKSIZE;
        rxTaskParams.stack = &rxTaskStack;
        rxTaskParams.priority = RX_TASK_PRIORITY;
        rxTaskParams.arg0 = (UInt)1000000;
    
        Task_construct(&rxTask, rxTaskFunction, &rxTaskParams, NULL);
    }
    
    static void rxTaskFunction(UArg arg0, UArg arg1)
    {
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        if( RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                MAX_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            while(1);
        }
    
        /* Modify CMD_PROP_RX command for application needs */
        RF_cmdPropRx.pQueue = &dataQueue;           /* Set the Data Entity queue for received data */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;  /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;   /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.maxPktLen = MAX_LENGTH;        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        //RF_cmdPropRx.pktConf.bRepeatOk = 0;			/* End operation after receiving packet correctly */
        //RF_cmdPropRx.pktConf.bRepeatNok = 0;		/* End operation after receiving packet with CRC error */
        RF_cmdPropRx.pktConf.bRepeatOk = 1;
        RF_cmdPropRx.pktConf.bRepeatNok = 1;
    
        if(!rfHandle)
        {
    		/* Request access to the radio */
    		rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
    		/* Set the frequency */
    		RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
        }
    
        while(1)
        {
    		/* Enter RX mode and stay forever in RX */
    		RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callbackRx, IRQ_RX_ENTRY_DONE);
    		Semaphore_pend(semRxHandle, BIOS_WAIT_FOREVER);
        }
    }
    
    /*
     *  ======== buttonCallbackFxn ========
     *  Pin interrupt Callback function board buttons configured in the pinTable.
      */
    void callbackTx(PIN_Handle handle, PIN_Id pinId) {
    
    
        /* Debounce logic, only toggle if the button is still pushed (low) */
        CPUdelay(8000*50);
        if (!PIN_getInputValue(pinId)) {
            /* Toggle LED based on the button pressed */
            switch (pinId) {
                case Board_BUTTON0:
                    packVal = 123;
                    currVal =  PIN_getOutputValue(Board_LED0);
                    PIN_setOutputValue(ledPinHandle, Board_LED0, !currVal);
                    break;
    
                case Board_BUTTON1:
                    packVal = 321;
                    currVal =  PIN_getOutputValue(Board_LED1);
                    PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
            		Semaphore_post(semRxHandle);
                    //RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, NULL, 0);
                    break;
    
                default:
                    /* Do nothing */
                	PIN_setOutputValue(ledPinHandle, Board_LED0, 1);
                	PIN_setOutputValue(ledPinHandle, Board_LED1, 1);
                    break;
            }
        }
        /* Post TX semaphore to TX task */
         Semaphore_post(txSemaphoreHandle);
    }
    
    /* Receive Callback Function */
    void callbackRx(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventRxEntryDone)
        {
            //do
            //{
    			/* 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 + the status byte to the packet variable */
    			memcpy(packet, packetDataPointer, (packetLength + 1));
    
    			if((*(packet+2)) == (uint8_t)123)
    			{
    				/* Toggle pin to indicate RX */
    				PIN_setOutputValue(pinHandle, Board_LED0,!PIN_getOutputValue(Board_LED0));
    			}
    			else if((*(packet+2)) == (uint8_t)321)
    			{
    				/* Toggle pin to indicate RX */
    				PIN_setOutputValue(pinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
    				Semaphore_post(semTxHandle);
    			}
    			else
    			{
    				PIN_setOutputValue(pinHandle, Board_LED0,!PIN_getOutputValue(Board_LED0));
    				PIN_setOutputValue(pinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
    			}
    
    			//Semaphore_post(semTxHandle);
    			RFQueue_nextEntry();
            //}while(RFQueue_nextEntry() == DATA_ENTRY_FINISHED);
        }
    }
    
        /***** Function definitions *****/
    void TxTask_init(PIN_Handle inPinHandle)
    {
    	pinHandle = inPinHandle;
    	Task_Params_init(&txTaskParams);
    	txTaskParams.stackSize = TASKSTACKSIZE;
    	txTaskParams.priority = TX_TASK_PRIORITY;
    	txTaskParams.stack = &txTaskStack;
    	txTaskParams.arg0 = (UInt)1000000;
    	Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL);
    }
    
    static void txTaskFunction(UArg arg0, UArg arg1)
    {
    	uint32_t time;
    
        /* Setup callback for button pins */
        if (PIN_registerIntCb(buttonPinHandle, &callbackTx) != 0) {
            System_abort("Error registering button callback function");
        }
    
    	RF_Params rfParams;
    	RF_Params_init(&rfParams);
    
    
    	RF_cmdPropTx.pktLen = MAX_LENGTH;
    	RF_cmdPropTx.pPkt = txPacket;
    	RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
    	RF_cmdPropTx.startTrigger.pastTrig = 1;
    	RF_cmdPropTx.startTime = 0;
        if (!rfHandle)
    	{
    		/* Request access to the radio */
    		rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
         		/* Set the frequency */
    		RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    	}
        	/* Get current time */
    	time = RF_getCurrentTime();
    	while(1)
    	{
    		/* Wait for a button press */
    		Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
            /* 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 < MAX_LENGTH; i++)
    		{
    			txPacket[i] = rand();
    		}
            	/* Set absolute TX time to utilize automatic power management */
    		time += PACKET_INTERVAL;
    		RF_cmdPropTx.startTime = time;
            	/* Send packet */
    		RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);
    		if (!(result & RF_EventLastCmdDone))
    		{
    			/* Error */
    			while(1);
    		}
    		Semaphore_post(semRxHandle);
    	}
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
    	Semaphore_Params semParams;
    
        /* Call board init functions */
        Board_initGeneral();
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, ledPinTable);
        if(!ledPinHandle) {
            System_abort("Error initializing board LED pins\n");
        }
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
        if(!buttonPinHandle) {
    	   System_abort("Error initializing button pins\n");
        }
    
    	/* Construct a Semaphore object to be used as a resource lock, inital count 0 */
    	Semaphore_Params_init(&semParams);
    	Semaphore_construct(&semTxStruct, 0, &semParams);
    	Semaphore_construct(&semRxStruct, 0, &semParams);
    
    	/* Obtain instance handle */
    	semTxHandle = Semaphore_handle(&semTxStruct);
    	semRxHandle = Semaphore_handle(&semRxStruct);
    
    	/* Initialize task */
    	RxTask_init(ledPinHandle);
    
    	/* Initialize task */
    	TxTask_init(ledPinHandle);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

  • Also would like to understand how does one changes the modes on Fly from Tx to Rx and vice versa.
  • Hi Richard,

    Thank you for the suggestion to use the rfWsnNode/Concentrator example. It has made the 2-way communication working for my project.
    Can you please make me understand about the frequency hoping concept as you have mentioned in 2nd method "Most implementations use synchronized clocks and hop on a predefined scheme with fixed time slots. The only difficulty here is, to do an initial synchronization. The coordination effort is much less after that.".

    Vikram
  • Hi Vikram,

    when you do synchronous frequency hopping, all participants need to know:

    • when to switch,
    • to which frequency to switch.

    Usually a "pseudo-random" hopping sequence is used. It looks random from outside, but in fact, all participants know the scheme. To be on time, all participants need to synchronize their clocks. This could be done once or constantly by having one single master node sending regular beacon messages. There are lots of possibilities how to implement frequency hopping. You can start reading here and then follow up on some good books if you want to know more.

  • Hi Richard,
    As per your suggestion, I had used the wireless sensor network examples to make 2-way communication working.
    But the issue is that one board has to always start as transmitter and another as always receiver.
    Once transmitter transmits the data it comes into receiving state and once the receiver receives data, it comes to transmit state.

    How, can I make the state to change willingly such that both the sides can initiate transmission any time.
    As you have mentioned in the earlier post make both boards in receiving and only switch to Tx when ready to transmit. I tried that but it seems that both boards are remaining in the receiver state and neither able to receive any thing (as they are not able to go in transmit state) nor transmit anything.
    Any suggestion would be helpful.

    Thank you
    Vikram
  • Hi Vikram,

    I'm not sure if I understand you correctly. You want both boards in RX and change to TX on one side to initiate a transfer. I guess that you have configured the RX command for infinite execution. In that case, you can cancel the RX command with RF_cancelCmd(). This function needs a command handle, so you must use RF_postCmd() for RX. Another way would be, to set a custom trigger command as end trigger for the RX command and then send the trigger command once you want to end the RX command. But this is unfortunately not well documented.

  • Good morning Richard,

    Thank you for the reply.

    Sorry for lack of communication that I created.

    You got it right. I want both the boards to be in RX mode and both boards can be changed to TX on either side to initiate a transfer at a given time.

    I have configured the RX_ADV command  as below :

    static rfc_CMD_PROP_RX_ADV_t EasyLink_cmdPropRxAdv = {
    .commandNo = 0x3804,
    .status = 0x0000,
    .pNextOp = 0,
    .startTime = 0x00000000,
    .startTrigger.triggerType = TRIG_NOW,
    .startTrigger.bEnaCmd = 0x0,
    .startTrigger.triggerNo = 0x0,
    .startTrigger.pastTrig = 0x0,
    .condition.rule = 0x1,
    .condition.nSkip = 0x0,
    .pktConf.bFsOff = 0x0,
    .pktConf.bRepeatOk = 0x0,
    .pktConf.bRepeatNok = 0x0,
    .pktConf.bUseCrc = 0x1,
    .pktConf.bCrcIncSw = 0x0,
    .pktConf.bCrcIncHdr = 0x1,
    .pktConf.endType = 0x0,
    .pktConf.filterOp = 0x1,
    .rxConf.bAutoFlushIgnored = 0x0,
    .rxConf.bAutoFlushCrcErr = 0x0,
    .rxConf.bIncludeHdr = 0x1,
    .rxConf.bIncludeCrc = 0x0,
    .rxConf.bAppendRssi = 0x0,
    .rxConf.bAppendTimestamp = 0x0,
    .rxConf.bAppendStatus = 0x0,
    .syncWord0 = 0x930b51de,
    .syncWord1 = 0,
    .maxPktLen = 0,
    .hdrConf.numHdrBits = 8,
    .hdrConf.lenPos = 0,
    .hdrConf.numLenBits = 8,
    .addrConf.addrType = 0,
    .addrConf.addrSize = 0,
    .addrConf.addrPos = 0,
    .addrConf.numAddr = 1,
    .lenOffset = 0,
    .endTrigger.triggerType = TRIG_NEVER,
    .endTrigger.bEnaCmd = 0x0,
    .endTrigger.triggerNo = 0x0,
    .endTrigger.pastTrig = 0x0,
    .endTime = 0x00000000,
    .pAddr = 0,
    .pQueue = 0,
    .pOutput = 0,
    };

    You mentioned to use the RF_post command followed by RF_cancel command.

    I will try that today and revert you on the status.

    But if I RF_cancel command is immediately followed by RF_post command will it not cancel the existing RF_post command also before even actually receiving the data if transmitted.

    Sorry if I misunderstood the idea.

    Also when will be the TI-RTOS version 2.21 will be available as mentioned in your other post.

    Regards,

    Vikram

  • Dear Vikram,

    TI-RTOS 2.21 is out since last week. I think that you misunderstood me a bit.

    1. Use RF_postCmd() to start RX on both boards. This will return a command handle.
    2. When you want to send on one board, you have to call RF_cancelCmd() and provide the command handle from step 1.
    3. Then you execute the TX command. You can either use RF_postCmd() or RF_runCmd() here, because you usually don't need the command handle.

  • Thanks Richard,
    It got clear now.
    Will try that now and get back.
    For the TI_RTOS 2.21 when I run the Check for updates in the CCS studio, it says no updates available. Seems I have to manually load the RTOS.

    Regards,
    Vikram
  • /*
     * Copyright (c) 2015, 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 *****/
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/knl/Event.h>
    
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <driverlib/rf_prop_mailbox.h>
    
    /* Board Header files */
    #include "Board.h"
    
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    #include <stdlib.h>
    
    /* Pin driver handle */
    static PIN_Handle ledPinHandle;
    static PIN_State ledPinState;
    
    static PIN_Handle buttonPinHandle;
    static PIN_State buttonPinState;
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config ledpinTable[] =
    {
        Board_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    PIN_Config buttonpinTable[] =
    {
    		   Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    		   Board_BUTTON1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    		   PIN_TERMINATE
    };
    /***** Defines *****/
    #define RX_TASK_STACK_SIZE 1024
    #define RX_TASK_PRIORITY   3
    
    /* TX Configuration */
    #define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
    #define MAX_LENGTH             30 /* Max length byte the radio will accept */
    #define NUM_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
    #define NUM_APPENDED_BYTES     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) */
    
    
    /***** Defines *****/
    #define TX_TASK_STACK_SIZE 1024
    #define TX_TASK_PRIORITY   3
    
    /***** Defines *****/
    #define KEYPRESS_TASK_STACK_SIZE 1024
    #define KEYPRESS_TASK_PRIORITY   3
    
    /* Events used in the application */
    typedef enum {
        KeyPressUp_Event = Event_Id_00,
        KeyPressDown_Event = Event_Id_01,
        KeyPressAll_Event = KeyPressUp_Event + KeyPressDown_Event,
    } KeyPressEvent;
    
    /* TX Configuration */
    #define PAYLOAD_LENGTH      30
    #define PACKET_INTERVAL     (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
    
    
    /***** Prototypes *****/
    static void txTaskFunction(UArg arg0, UArg arg1);
    static void rxTaskFunction(UArg arg0, UArg arg1);
    static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    static void keypressTaskFunction(UArg arg0, UArg arg1);
    void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId);
    
    /***** Variable declarations *****/
    static Task_Params rxTaskParams;
    Task_Struct rxTask;    /* not static so you can see in ROV */
    static uint8_t rxTaskStack[RX_TASK_STACK_SIZE];
    static Task_Params txTaskParams;
    Task_Struct txTask;    /* not static so you can see in ROV */
    static uint8_t txTaskStack[TX_TASK_STACK_SIZE];
    static Task_Params keypressTaskParams;
    Task_Struct keypressTask;    /* not static so you can see in ROV */
    static uint8_t keypressTaskStack[KEYPRESS_TASK_STACK_SIZE];
    
    Event_Struct keyPressEvent;  /* not static so you can see in ROV */
    static Event_Handle keyPressEventHandle;
    
    Semaphore_Struct semTxStruct;
    Semaphore_Handle semTxHandle;
    
    Semaphore_Struct semRxStruct;
    Semaphore_Handle semRxHandle;
    
    
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN (rxDataEntryBuffer, 4);
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    #endif
    static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                                     MAX_LENGTH,
                                                                     NUM_APPENDED_BYTES)];
    
    /* 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;
    uint32_t time;
    static uint8_t txPacket[PAYLOAD_LENGTH];
    static uint16_t seqNumber;
    
    static PIN_Handle pinHandle;
    
    static uint8_t packet[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */
    
    
    /***** Function definitions *****/
    void RxTask_init(PIN_Handle ledPinHandle) {
        pinHandle = ledPinHandle;
    
        Task_Params_init(&rxTaskParams);
        rxTaskParams.stackSize = RX_TASK_STACK_SIZE;
        rxTaskParams.priority = RX_TASK_PRIORITY;
        rxTaskParams.stack = &rxTaskStack;
        rxTaskParams.arg0 = (UInt)1000000;
    
        Task_construct(&rxTask, rxTaskFunction, &rxTaskParams, NULL);
    }
    
    static void rxTaskFunction(UArg arg0, UArg arg1)
    {
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        if( RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                MAX_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            while(1);
        }
    
        /* Modify CMD_PROP_RX command for application needs */
        RF_cmdPropRx.pQueue = &dataQueue;           /* Set the Data Entity queue for received data */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;  /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;   /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.maxPktLen = MAX_LENGTH;        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRx.pktConf.bRepeatOk = 0;
        RF_cmdPropRx.pktConf.bRepeatNok = 0;
    
        if (!rfHandle) {
        	/* Request access to the radio */
        	rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        	/* Set the frequency */
        	RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
        }
    
        while (1) {
            /* Enter RX mode and stay forever in RX */
        	RF_CmdHandle cmdHdl = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, IRQ_RX_ENTRY_DONE);
    
        	Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
    
        	RF_cancelCmd(rfHandle, cmdHdl, 0);
        }
    
    }
    
    void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventRxEntryDone)
        {
            /* Toggle pin to indicate RX */
            PIN_setOutputValue(pinHandle, Board_LED3,!PIN_getOutputValue(Board_LED3));
    
            /* 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 + the status byte to the packet variable */
            memcpy(packet, packetDataPointer, (packetLength + 1));
    
            Semaphore_post(semTxHandle);
    
            RFQueue_nextEntry();
        }
    }
    
    #if 1
    /***** Function definitions *****/
    void TxTask_init(PIN_Handle inPinHandle)
    {
        pinHandle = inPinHandle;
    
        Task_Params_init(&txTaskParams);
        txTaskParams.stackSize = TX_TASK_STACK_SIZE;
        txTaskParams.priority = TX_TASK_PRIORITY;
        txTaskParams.stack = &txTaskStack;
        txTaskParams.arg0 = (UInt)1000000;
    
        Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL);
    }
    
    
    static void txTaskFunction(UArg arg0, UArg arg1)
    {
        uint32_t time;
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = txPacket;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
        RF_cmdPropTx.startTrigger.pastTrig = 1;
        RF_cmdPropTx.startTime = 0;
    
        if (!rfHandle) {
        	/* Request access to the radio */
        	rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        	/* Set the frequency */
        	RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
        }
    
        /* Get current time */
        time = RF_getCurrentTime();
        while(1)
        {
            Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
    
            /* 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();
            }
    
            /* Set absolute TX time to utilize automatic power management */
            time += PACKET_INTERVAL;
            RF_cmdPropTx.startTime = time;
    
            /* Send packet */
    
            RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, RF_EventLastCmdDone);
    
            //RF_EventMask result = RF_pendCmd(rfHandle, cmdHdl,  (RF_EventLastCmdDone | RF_EventCmdError));
    
            if (!(result & RF_EventLastCmdDone))
            {
                /* Error */
                while(1);
            }
    
    
            if(result & RF_EventLastCmdDone)
            {
    			PIN_setOutputValue(pinHandle, Board_LED4,!PIN_getOutputValue(Board_LED4));
    			Semaphore_post(semRxHandle);
            }
        }
    }
    #endif
    
    void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId)
    {
        /* Simple debounce logic, only toggle if the button is still pushed (low) */
        CPUdelay((uint32_t)((48000000/3)*0.050f));
        if (!PIN_getInputValue(pinId))
        {
            switch(pinId)
            {
            	case Board_BUTTON0:
            		 PIN_setOutputValue(pinHandle, Board_LED1, (1^PIN_getOutputValue(Board_LED1)));
            		 Event_post(keyPressEventHandle, KeyPressUp_Event);
            		 break;
    
            	case Board_BUTTON1:
            		 PIN_setOutputValue(pinHandle, Board_LED2, (1^PIN_getOutputValue(Board_LED2)));
            		 Event_post(keyPressEventHandle, KeyPressDown_Event);
                     break;
    
            	default:
            		/* do nothing*/
            		break;
            }
        }
    }
    
    /***** Function definitions *****/
    void KeyPressTask_init()
    {
        Event_Params eventParam;
        Event_Params_init(&eventParam);
        Event_construct(&keyPressEvent, &eventParam);
        keyPressEventHandle = Event_handle(&keyPressEvent);
    
        /* Create the keypress task */
        Task_Params_init(&keypressTaskParams);
        keypressTaskParams.stackSize = KEYPRESS_TASK_STACK_SIZE;
        keypressTaskParams.priority = KEYPRESS_TASK_PRIORITY;
        keypressTaskParams.stack = &keypressTaskStack;
        Task_construct(&keypressTask, keypressTaskFunction, &keypressTaskParams, NULL);
    }
    
    static void keypressTaskFunction(UArg arg0, UArg arg1)
    {
    	while(1)
    	{
            /* Wait for event */
            uint32_t events = Event_pend(keyPressEventHandle, 0, KeyPressAll_Event, BIOS_WAIT_FOREVER);
    
            /* If new ADC value, send this data */
            if (events & (KeyPressUp_Event|KeyPressDown_Event))
            {
                /* Send ADC value to concentrator */
            	Semaphore_post(semTxHandle);
            }
        }
    }
    /*
     *  ======== main ========
     */
    int main(void)
    {
        Semaphore_Params semParams;
    
        /* Call board init functions. */
        Board_initGeneral();
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, ledpinTable);
        if(!ledPinHandle)
        {
            System_abort("Error initializing board LED pins\n");
        }
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonpinTable);
        if(!buttonPinHandle)
        {
            System_abort("Error initializing board Button pins\n");
        }
    
        if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFunction) != 0)
        {
            System_abort("Error registering button callback function");
        }
        /* Construct a Semaphore object to be used as a resource lock, inital count 0 */
        semParams.mode = ti_sysbios_knl_Semaphore_Mode_BINARY;
        Semaphore_Params_init(&semParams);
        Semaphore_construct(&semTxStruct, 0, &semParams);
        Semaphore_construct(&semRxStruct, 0, &semParams);
    
    
        /* Obtain instance handle */
        semTxHandle = Semaphore_handle(&semTxStruct);
        semRxHandle = Semaphore_handle(&semRxStruct);
    
        /* Initialize task */
        RxTask_init(ledPinHandle);
    
        /* Initialize task */
        TxTask_init(ledPinHandle);
    
        KeyPressTask_init();
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

    Hi Richard,

    I had used the same concept where you mentioned to use the RF_cancelCmd when either of the board is ready to transmit data while waiting in receiving mode.

    I have used 2 semaphores. "semTxHandle" for tranmit and "semRxHandle" for receive.

    Also I have used event concept which will trigger that any key press event has occurred to transmit data.

    The Event_post will release the event_pend which in turn releases the semTxHandle semaphore to execute the RF_cancelCmd that cancels the Rx command.

    Key_button Up/Key_button Down is pressed that releases the Event_pend, thereby posting the semTxHandle.

    The semTxHandle was pended in the Rxcallback function, which upon being posted calls the RF_cancelCmd for "RF_cmdPropRx" cmd executed in the Rxtask.

    The stuff works but not as the way it should.

    Below is the sequence observed:

    Board A receiving mode

    Board B receiving mode

    First time when key is pressed on Board A, the execution reaches the RF_cancel cmd but seems not executing it as a result the Tx Cmd is not executed.

    Next time when key is pressed, it executes the RF_cancel cmd and then executes the Tx cmd.

    This is the sequence followed every time key press event occurs.

    I have attached the code.

    If you can please check and let me know where the issue like would be greatful.

    Thank you in advance once again.

    Vikram

  • Hi Richard,

    I have managed to do 2-way communication on both sides of the boards.

    As per your suggestion, I did keep both boards in receiving modes continuously (in while loop).

    Once any key is pressed on either boards (event triggered), I call the RF_cancelCmd following the Semaphore_pend(RxHandle, 1000000).

    So this cancels the Rx command and jumps to TX command and once it is done it comes back in the while loop waiting for the Rx command.

    The problem is I am not able to utilise this concept along with the concept of Concentrator and Node example which sends an acknowledgement back once data is received.

    As we see in the Concentrator example we are waiting for packet to be received by calling the EasyLink_receiveAsyn function before the event_pend execution.

    Can find a way to cancel this receive command so as to trigger when key is pressed as to indicate to send a data.

    Will be handy for any suggestions.

    Have a great weekend.

    Thanks

    Vikram

  • Hi,

    this loop

    while (1) {
            /* Enter RX mode and stay forever in RX */
            RF_CmdHandle cmdHdl = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, IRQ_RX_ENTRY_DONE);
    
            Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
    
            RF_cancelCmd(rfHandle, cmdHdl, 0);
        }

    will restart RX immediately after cancelling. I think this is not want you want. You want RX -> TX -> RX for ack -> RX. I do not recommend using different tasks on a complex shared resource like the RF core. Better do RX and TX in the same task, drop all your semaphores and use the events module only. You need just one task and one central loop that processes events. Think of your application as a state machine that changes states based on incoming events. Maybe this message can help you a bit.

  • Demo code.zip

    /*
     * Event handle rxtx.c
     *
     *  Created on: Sep 26, 2016
     *      Author: VTrivedi
     */
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/knl/Event.h>
    
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <driverlib/rf_prop_mailbox.h>
    
    /* Board Header files */
    #include "Board.h"
    
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    #include <stdlib.h>
    
    /* Pin driver handle */
    static PIN_Handle ledPinHandle;
    static PIN_State ledPinState;
    
    static PIN_Handle buttonPinHandle;
    static PIN_State buttonPinState;
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config ledpinTable[] =
    {
        Board_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    PIN_Config buttonpinTable[] =
    {
    		   Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    		   Board_BUTTON1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    		   PIN_TERMINATE
    };
    /***** Defines *****/
    #define TX_RX_TASK_STACK_SIZE 1024
    #define TX_RX_TASK_PRIORITY   3
    
    /* TX Configuration */
    #define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
    #define MAX_LENGTH             30 /* Max length byte the radio will accept */
    #define NUM_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
    #define NUM_APPENDED_BYTES     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 DATA_PACKET_TYPE_DATA 	1
    #define DATA_PACKET_TYPE_ACK  	2
    
    /***** Defines *****/
    #define KEYPRESS_TASK_STACK_SIZE 1024
    #define KEYPRESS_TASK_PRIORITY   3
    
    /* Events used in the application */
    typedef enum {
    	Valid_Data_Received_Event = Event_Id_00,
    	Key_Presesed_Event = Event_Id_01,
    	Valid_Ack_Received_Event = Event_Id_02,
        KeyPressAll_Event = Valid_Data_Received_Event + Key_Presesed_Event,
    } KeyPressEvent;
    
    typedef enum {
    	ReceivingState,
    	IrqTxState,
    }ApplicationState;
    
    /* TX Configuration */
    #define PAYLOAD_LENGTH      30
    #define PACKET_INTERVAL     (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
    
    
    /***** Prototypes *****/
    static void txrxTaskFunction(UArg arg0, UArg arg1);
    static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId);
    void sendAck();
    void sendDataPacket();
    
    /***** Variable declarations *****/
    static Task_Params txrxTaskParams;
    Task_Struct txrxTask;    /* not static so you can see in ROV */
    static uint8_t txrxTaskStack[TX_RX_TASK_STACK_SIZE];
    Event_Struct txrxEvent;  /* not static so you can see in ROV */
    static Event_Handle Tx_Rx_Event;
    
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN (rxDataEntryBuffer, 4);
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    #endif
    static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                                     MAX_LENGTH,
                                                                     NUM_APPENDED_BYTES)];
    
    /* 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 packetType;
    static uint8_t* packetDataPointer;
    uint32_t time;
    static uint8_t txPacket[PAYLOAD_LENGTH];
    //static uint16_t seqNumber;
    static uint8_t data;
    static PIN_Handle pinHandle;
    
    static uint8_t packet[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */
    
    /* Variables */
    ApplicationState CurrentState = ReceivingState;
    
    /***** Function definitions *****/
    void TxRxTask_init(PIN_Handle ledPinHandle) {
        pinHandle = ledPinHandle;
    
        Event_Params eventParam;
        Event_Params_init(&eventParam);
        Event_construct(&txrxEvent, &eventParam);
        Tx_Rx_Event = Event_handle(&txrxEvent);
    
        Task_Params_init(&txrxTaskParams);
        txrxTaskParams.stackSize = TX_RX_TASK_STACK_SIZE;
        txrxTaskParams.priority = TX_RX_TASK_PRIORITY;
        txrxTaskParams.stack = &txrxTaskStack;
        txrxTaskParams.arg0 = (UInt)1000000;
    
        Task_construct(&txrxTask, txrxTaskFunction, &txrxTaskParams, NULL);
    }
    
    static void txrxTaskFunction(UArg arg0, UArg arg1)
    {
        uint32_t events = 0;
        ApplicationState nextState = CurrentState;
    
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
    
        RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
        RF_cmdPropTx.pPkt = txPacket;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
        RF_cmdPropTx.startTrigger.pastTrig = 1;
        RF_cmdPropTx.startTime = 0;
    
        if( RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                MAX_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            while(1);
        }
    
        /* Modify CMD_PROP_RX command for application needs */
        RF_cmdPropRx.pQueue = &dataQueue;           /* Set the Data Entity queue for received data */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;  /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;   /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.maxPktLen = MAX_LENGTH;        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRx.pktConf.bRepeatOk = 0;
        RF_cmdPropRx.pktConf.bRepeatNok = 0;
    
    
        while(true)
        {
        	switch(CurrentState)
        	{
    			case ReceivingState:
    				if (!rfHandle)
    				{
    					/* Request access to the radio */
    					rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
    					/* Set the frequency */
    					RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    				}
    				while(nextState == CurrentState)
    				{
    					RF_CmdHandle cmdHdl = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, IRQ_RX_ENTRY_DONE);
    					events = Event_pend(Tx_Rx_Event, 0, KeyPressAll_Event, BIOS_WAIT_FOREVER);
    					if(events & Valid_Data_Received_Event)
    					{
    						sendAck();
    						nextState = ReceivingState;
    					}
    					else if (events & Valid_Ack_Received_Event)
    					{
    						nextState = ReceivingState;
    					}
    					else
    					{
    						RF_cancelCmd(rfHandle, cmdHdl, 0);
    						nextState = IrqTxState;
    					}
    				};
    				//RF_close(rfHandle);
    				break;
    
    			case IrqTxState:
    				if (!rfHandle)
    				{
    					/* Request access to the radio */
    					rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
    					/* Set the frequency */
    					RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    				}
    				sendDataPacket();
    				nextState = ReceivingState;
    				//RF_close(rfHandle);
    				break;
        	}
        	CurrentState = nextState;
        }
    }
    
    void sendAck()
    {
    	txPacket[0] = DATA_PACKET_TYPE_ACK;
    	txPacket[1] = 0x3;
    	txPacket[1] = 0xAA;
    
    	RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, RF_EventLastCmdDone);
        if (!(result & RF_EventLastCmdDone))
        {
            /* Error */
            while(1);
        }
    
        if(result & RF_EventLastCmdDone)
        {
    		PIN_setOutputValue(pinHandle, Board_LED4,!PIN_getOutputValue(Board_LED4));
        }
    }
    
    void sendDataPacket()
    {
    	txPacket[0] = DATA_PACKET_TYPE_DATA;
    	//txPacket[1] = (uint8_t)(PAYLOAD_LENGTH >> 8);
    	txPacket[1]	= (PAYLOAD_LENGTH);
        uint8_t i;
        for (i = 2; i < PAYLOAD_LENGTH; i++)
        {
        	txPacket[i++] = data;
        	txPacket[i] = ((0x01)^(data));
        }
    	RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, RF_EventLastCmdDone);
        if (!(result & RF_EventLastCmdDone))
        {
            /* Error */
            while(1);
        }
    
    
        if(result & RF_EventLastCmdDone)
        {
    		PIN_setOutputValue(pinHandle, Board_LED2,!PIN_getOutputValue(Board_LED2));
        }
    
    }
    
    void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
    	if (e & RF_EventRxEntryDone)
    	{
    		/* Toggle pin to indicate RX */
    		PIN_setOutputValue(pinHandle, Board_LED3,!PIN_getOutputValue(Board_LED3));
    
    		/* 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 */
    		packetType 		  = *(uint8_t*)(&currentDataEntry->data + 1);
    		if(packetType == DATA_PACKET_TYPE_ACK)
    		{
    			Event_post(Tx_Rx_Event, Valid_Ack_Received_Event);
    		}
    		else
    		{
    			Event_post(Tx_Rx_Event, Valid_Data_Received_Event);
    		}
    		packetLength      = *(uint8_t*)(&currentDataEntry->data + 2);
    		packetDataPointer = (uint8_t*)(&currentDataEntry->data + 3);
    
    		/* Copy the payload + the status byte to the packet variable */
    		memcpy(packet, packetDataPointer, (packetLength + 1));
    
    		RFQueue_nextEntry();
    	}
    }
    
    void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId)
    {
        /* Simple debounce logic, only toggle if the button is still pushed (low) */
        CPUdelay((uint32_t)((48000000/3)*0.050f));
        if (!PIN_getInputValue(pinId))
        {
            switch(pinId)
            {
            	case Board_BUTTON0:
            		 PIN_setOutputValue(pinHandle, Board_LED1, (1^PIN_getOutputValue(Board_LED1)));
            		 data = 0xAA;
            		 Event_post(Tx_Rx_Event, Key_Presesed_Event);
            		 break;
    
            	case Board_BUTTON1:
            		 PIN_setOutputValue(pinHandle, Board_LED1, (1^PIN_getOutputValue(Board_LED1)));
            		 data = 0x55;
            		 Event_post(Tx_Rx_Event, Key_Presesed_Event);
                     break;
    
            	default:
            		/* do nothing*/
            		break;
            }
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions. */
        Board_initGeneral();
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, ledpinTable);
        if(!ledPinHandle)
        {
            System_abort("Error initializing board LED pins\n");
        }
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonpinTable);
        if(!buttonPinHandle)
        {
            System_abort("Error initializing board Button pins\n");
        }
    
        if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFunction) != 0)
        {
            System_abort("Error registering button callback function");
        }
        /* Initialize task */
        TxRxTask_init(ledPinHandle);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    
    
    

    Hi Richard,

    thank you for the feedback.

    You are right I need it each board as RX(waiting for data) -> TX (data to send) -> RX(ACK for data received) -> RX ( waiting for data).

    I implemented the concept. But it is not working as expected.

    As soon as key is pressed on one board, it transmits data (Board_LED2) and another board receives data(Board_LED3) and sends ack signal(Board_LED4).

    The board which transmitted data receives ack signal(Board_LED3).

    But after receiving ack signal it never breaks into the section of event which says (events & Valid_Ack_Received_Event) even though I post the event in the Rx call back function once I receive the ack signal.

    As a result of this the board that had transmitted the data never comes back in receiving mode after receiving the ACK signal.

    The another board that had received data and sent ACK signal is able to transmit data but but not able to receive ACK signal (ofcourse, as the first board has not gone back into receiving mode).

    Can't understand what is holding up the event.

    I am attaching the code if you can look into that and guide to let me know where I missing out the minute details.

    Board_LED1 : Toggles for key pressed

    Board_LED2 : Successful transmission of data

    Board_LED3 : Successful reception of data

    Board_LED4: Successful transmission of ack signal.

    Thank in advance.

    Vikram

  • Hi,

    you need to change the definition of KeyPressAll_Event to

    typedef enum {
    	Valid_Data_Received_Event = Event_Id_00,
    	Key_Presesed_Event = Event_Id_01,
    	Valid_Ack_Received_Event = Event_Id_02,
        KeyPressAll_Event = Valid_Data_Received_Event + Valid_Ack_Received_Event + Key_Presesed_Event,
    } KeyPressEvent;

    Otherwise, this line:

    events = Event_pend(Tx_Rx_Event, 0, KeyPressAll_Event, BIOS_WAIT_FOREVER);

    will not return on a Valid_Ack_Received_Event.

    The naming is a bit misleading here. These are application events, not only keypress events.

  • Good morning Richard,

    After I sent you the response last evening, I realized the same and had made the changes in the code.

    But the problem is it only happens one time and then the Transmitter after receiving the ACK signal is not able to go into receiving mode and hence never receives any thing.

    Thanks

    Vikram

  • Also, when I stop the execution to see where the task is halted, it shows task is preempted in the ROV where event showing no task pending.
  • Also Richard,
    Below is the observation that I found while doing debug:
    Initially, say key is pressed on Board A.
    Ideally every time it should be, whenever CurrentState = Receiving state and nextState == CurrentState, execution runs through RF_postcmd(RX) and Event_pend() lines and waits for any event to trigger (either key press to transmit or data received for ack received).
    In this case what I found that after receiving the ACK signal that was sent from Board B, when the execution goes through line RF_postcmd(RX) it does not run that and hence no event is made pending leading this this scenario.

    But say if say key is pressed on board B and board A is waiting for reception, after receiving the data and sending ACK signal back to Board B, when execution goes back through RF_postCmd(RX), it runs that command and waits for event_pend for any event to occur.

    So can't get it that what is the reason for this different behaviour.

    Thank you
    Vikram
  • Hi,

    in these lines:

        txPacket[1] = 0x3;
        txPacket[1] = 0xAA;

    you are writing 0xAA (170) to txPacket[1]. I guess that you want to write txPacket[2] instead. In your callback, you are reading

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

    and then you are copying

            memcpy(packet, packetDataPointer, (packetLength + 1));
    

    This will copy 0xAA + 1 = 171 bytes to "packet" which is a buffer of less than 40 bytes. Hence you overwrite all variables in memory following "packet". You overwrite for instance "CurrentState". Two comments here:

    • Always check application input that comes from the outside world before you use it. "packetLength" is an input value and you cannot trust it. Somebody could abuse it to temper your application. Congratulations: You have just implemented a classical buffer overflow bug. This can be found in many software systems implemented in C.
    • If your application doesn't work as expected, use the debugger. Set breakpoints and double check whether all variables contain expected values.
    • You are using variable packetLength. Hence, the packet length is encoded as first byte in the payload and you don't need to add it manually in this case.

  • Dear Richard,

    Thanks a ton.

    I now understood why they say, you always need a third eye to overlook the problem to be solved.

    The buffer overflow was the culprit and I was the one who introduced it.

    You correctly said I should have debugged the code, which I had done but never thought of checking the buffer values. Lesson learnt.

    "Do not overlook any thing while debugging"

    Appreciate for all the help and time and suggestions. Made my day.

    Regards,

    Vikram