/*******************************************************************************
 * @fn          cc115LTxIdle
 *
 * @brief       Radio state is switched from TX to IDLE
 *
 * input parameters
 *
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */ 
static void cc115LTxIdle(void)
{
  /* Disable pin interrupt */
  trxDisableInt();
  /* Strobe IDLE */
  trxSpiCmdStrobe(CC115L_SIDLE); 
  /* Wait until chip is in IDLE */
  while(trxSpiCmdStrobe(CC115L_SNOP) & 0xF0);
  /* Flush the TX FIFO */
  trxSpiCmdStrobe(CC110L_SFTX);
  /* Clear pin interrupt flag */
  trxClearIntFlag();
  return;
}
/******************************************************************************
 * @fn          cc120x_sniffModeRegConfig
 *
 * @brief       Writes packet and modem settings to registers
 *
 * input parameters
 *              
 * output parameters
 *
 * @return      void
*/
void cc120x_sniffModeRegConfig(uint16_t deviceName) {
  uint8 writeByte;
  
  // Reset radio
  trxSpiCmdStrobe(CC120X_SRES);
  
  // Write registers to radio
  for(uint16 i = 0; i < (sizeof(simpleLinkTestSniffCC120x)/sizeof(radioSetting_t)); i++) {
    writeByte =  simpleLinkTestSniffCC120x[i].data;
    cc120xSpiWriteReg( simpleLinkTestSniffCC120x[i].addr, &writeByte, 1);
  }  
    // Put radio in powerdown to save power
    trxSpiCmdStrobe(CC120X_SPWD);
}
/*******************************************************************************
 * @fn          cc1120cc1190RxIdle
 *
 * @brief       Radio state is switched from RX to IDLE
 *
 * input parameters
 *
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */ 
static void cc1120cc1190RxIdle(void)
{
  /* Disable pin interrupt */
  trxDisableInt();
  /* Strobe IDLE */
  trxSpiCmdStrobe(CC112X_SIDLE); 
  /* Wait until chip is in IDLE */
  while(trxSpiCmdStrobe(CC112X_SNOP) & 0xF0);
  //Disable LNA
  perCC1120CC1190LnaDisable();
  /* Flush the Receive FIFO */
  trxSpiCmdStrobe(CC112X_SFRX);
  /* Clear pin interrupt flag */
  trxClearIntFlag();
  return;
}
Exemple #4
0
static void runTX(char c1, char c2, char c3, char c4)
{
  // Initialize packet buffer of size PKTLEN + 1
  uint8 txBuffer[PKTLEN+1] = {0};

   P2SEL &= ~0x40; // P2SEL bit 6 (GDO0) set to one as default. Set to zero (I/O)
  // connect ISR function to GPIO0, interrupt on falling edge
  trxIsrConnect(GPIO_0, FALLING_EDGE, &radioRxTxISR);

  // enable interrupt from GPIO_0
  trxEnableInt(GPIO_0);

	// create a random packet with PKTLEN + 2 byte packet counter + n x random bytes
	createPacket(txBuffer, c1, c2, c3, c4);

  // write packet to tx fifo
  cc11xLSpiWriteTxFifo(txBuffer,sizeof(txBuffer));

  // strobe TX to send packet
  trxSpiCmdStrobe(CC110L_STX);

	// wait for interrupt that packet has been sent.
	// (Assumes the GPIO connected to the radioRxTxISR function is set
	// to GPIOx_CFG = 0x06)
	while(!packetSemaphore);

	// clear semaphore flag
	packetSemaphore = ISR_IDLE;

  halLedToggle(LED1);
   __delay_cycles(250000);
   halLedToggle(LED1);
}
/******************************************************************************
 * @fn          perCC115LEnterSleep
 *
 * @brief       Enters Sleep. Function is used to abstract the cc11xLRadioTxIdle
 *              functionality away from the lower-level radio interface.
 *              Note: assumes chip is ready
 *
 * input parameters
 *
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */
void perCC115LEnterSleep(void)
{
  cc115LTxIdle();
  trxSpiCmdStrobe(CC115L_SPWD);
  /* Only important to differ between TX and IDLE */
  cc115LRadioTxIdle = CC115L_STATE_IDLE;
  return;
}
/******************************************************************************
 * @fn          perCC1120CC1190EnterSleep
 *
 * @brief       Enters Sleep. Function is used to abstract the cc1120cc1190RadioTxRx
 *              functionality away from the lower-level radio interface.
 *              Note: assumes chip is ready
 *
 * input parameters
 *
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */
void perCC1120CC1190EnterSleep(void)
{
  cc1120cc1190RxIdle();
  trxSpiCmdStrobe(CC112X_SPWD);
  /* Only important to differ between RX/TX and IDLE */
  cc1120cc1190RadioTxRx = CC112X_STATE_IDLE;
  return;
}
/*******************************************************************************
 * @fn          cc1120cc1190IdleRx
 *
 * @brief       Radio state is switched from Idle to RX. Function assumes that
 *              radio is in IDLE when called. 
 * 
 * input parameters
 *
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */ 
static void cc1120cc1190IdleRx(void)
{
  trxClearIntFlag();
  //perCC1190HgmEnable();
  perCC1120CC1190PaDisable();
  perCC1120CC1190LnaEnable();
  trxSpiCmdStrobe(CC112X_SRX);
  trxEnableInt();
  return;
}
/*******************************************************************************
* @fn          registerConfig
*
* @brief       Write register settings as given by SmartRF Studio found in
*              cc120x_easy_link_reg_config.h
*
* @param       none
*
* @return      none
*/
static void registerConfig(void){
  
  uint8 writeByte;
  
  // Reset radio
  trxSpiCmdStrobe(CC120X_SRES);
  
  // Write registers to radio
  for(uint16 i = 0; i < (sizeof  preferredSettings/sizeof(registerSetting_t)); i++) {
    writeByte =  preferredSettings[i].data;
    cc120xSpiWriteReg( preferredSettings[i].addr, &writeByte, 1);
  }
}
/******************************************************************************
* @fn          cc120x_FreqConfig
*
* @brief       Writes frequency word depending on user input
*
* input        index
*              
* output       none
*
* @return      void
*/
uint8 cc120x_FreqConfig(uint16 index) {
  // Set frequency
  cc120xSpiWriteReg(CC120X_FS_CFG,&cc120xFsCfgs[index],1);
  cc120xSpiWriteReg(CC120X_FREQ2,freqSettings40Mhz[index],3);
  
  // Put radio in powerdown to save power
  trxSpiCmdStrobe(CC120X_SPWD);
  
  //Insert Carrier Sense threshold warning in Sniff Test Menu
  drawInfo();
  
  return SNIFF_RETURN_SUCCESS;
}
/*******************************************************************************
*   @fn         syncReceivedISR
*
*   @brief      Function running every time a sync word has been received
*
*   @param      none
*
*   @return     none
*/
static void syncReceivedISR(void) {

    uint8 numRxBytes;
    uint8 writeByte;

    // After the sync word is received one needs to wait for the two
    // length bytes to be put in the RX FIFO
    do {
        cc112xSpiReadReg(CC112X_NUM_RXBYTES, &numRxBytes, 1);
    } while (numRxBytes < 2);

    // Read the length byte and store it in the packetLength variable
    cc112xSpiReadRxFifo(rxBuffer, 2);
    pBufferIndex += 2;
    packetLength =  (uint16)(((uint16)(rxBuffer[0] << 8)) | rxBuffer[1]);

    // Make sure that the packet length is in the correct range, update
    // variables and enable interrupt on falling edge of GPIO3 (PKT_SYNC_RXTX)
    if ((packetLength > MAX_VARIABLE_LENGTH) 
        && (packetLength <= PACKET_LENGTH)) {
        bytesLeft = packetLength + 2;
        fixedPacketLength = bytesLeft  % (MAX_VARIABLE_LENGTH + 1);
        writeByte = fixedPacketLength;
        cc112xSpiWriteReg(CC112X_PKT_LEN, &writeByte, 1);

        // Clear interrupt flag and enable GPIO3
        ioPinIntClear(IO_PIN_PORT_1, GPIO3);
        ioPinIntEnable(IO_PIN_PORT_1, GPIO3);

    } else { // Exit RX and flush RX FIFO due to length byte being out of range
        trxSpiCmdStrobe(CC112X_SIDLE);
        trxSpiCmdStrobe(CC112X_SFRX);
        state = RX_START;
    }
  
    // Clear ISR flag
    ioPinIntClear(IO_PIN_PORT_1, GPIO2);
}
Exemple #11
0
static void registerConfig(void) {
  uint8 writeByte;
  uint16 i;
#ifdef PA_TABLE
  uint8 paTable[] = PA_TABLE;
#endif

  // reset radio
  trxSpiCmdStrobe(CC110L_SRES);
  // write registers to radio
  for(i = 0; i < (sizeof  preferredSettings/sizeof(registerSetting_t)); i++) {
    writeByte =  preferredSettings[i].data;
    cc11xLSpiWriteReg( preferredSettings[i].addr, &writeByte, 1);
  }
#ifdef PA_TABLE
  // write PA_TABLE
  cc11xLSpiWriteReg(CC11xL_PA_TABLE0,paTable, sizeof(paTable));
#endif
}
/******************************************************************************
 * @fn          perCC1120CC1190SendPacket
 *
 * @brief       Sends the contents that pData points to which has the 
 *              following structure:
 *
 *              txArray[0] = length byte
 *              txArray[n] = payload[n]
 *              | n<[sizeOf(RXFIFO)-2], variable packet length is assumed.
 * 
 *              The radio state after completing TX is dependant on the 
 *              CC112X_RFEND_CFG0 register setting. For PG10 this register 
 *              dictates IDLE after TX. For PG.0 this function must be 
 *              re-implemented since the 2way PER test relies on RX after TX.
 *              This function enables SYNC interrupt. This means that 
 *              an interrupt will fire when a packet has been sent, i.e sync 
 *              signal transitions from high to low. 
 *             
 *              The One-Way PER test disables the sync pin interrupt when TX
 *              finishes, while the Two-Way PER test doesn't to enable quick
 *              reception of Slave ACK.
 *
 *              Note: Assumes chip is ready
 *
 * input parameters
 *              
 * @param       *pData - pointer to data array that starts with length byte
 *                       and followed by payload.
 * output parameters
 *
 * @return      void
 */
void perCC1120CC1190SendPacket(uint8 *pData)
{
  uint8 len = *pData;
  /* PG1.0 errate fix: Before entering TX, the frequency word must be altered from that of RX */
  /* This means in general that TX from Idle is the only option, not TX from RX */
  perCC1120CC1190EnterIdle();
  /* Will only try to transmit if the whole packet can fit i RXFIFO 
   * and we're not currently sending a packet.
   */
  if(!(len > (PER_MAX_DATA-2)) && (cc1120cc1190RadioTxRx != CC112X_STATE_TX) )
  {
    cc112xSpiWriteTxFifo(pData,(len+1));
    /* Indicate state to the ISR and issue the TX strobe */
    trxEnableInt();
    /* Enable PA on CC1190 and be sure LNA is off */
    //perCC1190HgmEnable();
    perCC1120CC1190LnaDisable();
    perCC1120CC1190PaEnable();
    cc1120cc1190RadioTxRx = CC112X_STATE_TX; 
    trxSpiCmdStrobe(CC112X_STX);
    /* Wait until packet is sent before doing anything else */
    __low_power_mode_3();

    /* This function will not return before the complete packet
     * is sent and the radio is back in IDLE. The MSP will be 
     * be sleeping while the packet is beeing sent unless waken
     * by button presses.
     */
    while(cc1120cc1190RadioTxRx == CC112X_STATE_TX);
    
    if(perSettings.linkTopology == LINK_1_WAY)
    {
      /* Back in Idle*/
      trxDisableInt();
      /* Turn off PA on CC1190 */
      perCC1120CC1190PaDisable();
    }
  }
  return;
}
/******************************************************************************
 * @fn          perCC115LSendPacket
 *
 * @brief       Sends the contents that pData points to. pData has the 
 *              following structure:
 *
 *              txArray[0] = length byte
 *              txArray[n] = payload[n]
 *              | n<[sizeOf(RXFIFO)-2], variable packet length is assumed.
 * 
 *              The radio state after completing TX is dependant on the 
 *              MCSM1 register setting. This function enables SYNC interrupt. 
 *              This means that an interrupt will go off when a packet 
 *              has been sent, i.e sync signal transitions from high to low.
 *              MSP will be in low power mode until packet has been sent given
 *              that no other interrupts go off.
 *             
 *              The One-Way PER test disables the sync pin interrupt when TX
 *              finishes, while the Two-Way PER test doesn't to enable quick
 *              reception of Slave ACK.
 *
 *              Note: Assumes chip is ready
 *
 * input parameters
 *             
 * @param       *pData - pointer to data array that starts with length byte
 *                       and followed by payload.
 * output parameters
 *
 * @return      void
 */
void perCC115LSendPacket(uint8 *pData)
{
  uint8 len = *pData;
  /* Will only try to transmit if the whole packet can fit i TXFIFO 
   * and we're not currently sending a packet.
   */
  if(!(len > (PER_MAX_DATA-2)) && (cc115LRadioTxIdle != CC115L_STATE_TX) )
  {
    cc11xLSpiWriteTxFifo(pData,(len+1));
    /* Indicate state to the ISR and issue the TX strobe */
    trxEnableInt();
    cc115LRadioTxIdle = CC115L_STATE_TX; 
    trxSpiCmdStrobe(CC115L_STX);
    /* Wait until packet is sent before doing anything else */
    __low_power_mode_3();
    while(cc115LRadioTxIdle == CC115L_STATE_TX);
    if(perSettings.linkTopology == LINK_1_WAY)
    {
      /* Back in Idle*/
      trxDisableInt();
    }
  }
  return;
}
/******************************************************************************   
 * @fn          trxDetectCC1101Crystal()                                    
 *                                                                                
 * @brief       This function estimates the crystal frequency if a NextGen 
 *              radio is detected.
 *              SPI init must be applied before this function   
 *              can be called.
 *
 * @param       none
 *          
 * @return      none
 */
static uint8 trxDetectCC1101Crystal()
{
  
 // Write CLOCK_XOSC/192 to GDO2
  uint8 writeByte = 0x3F;
  trx8BitRegAccess(CC1101_WRITE_BURST, CC1101_IOCFG2, &writeByte, 1);
  
  //Wait for crystal to be stable (CHIP_RDYn)
  while((trxSpiCmdStrobe(CC1101_SNOP)& 0xF0) != 0x00);
  
  //Get current system clock frequency
  uint32_t systemClockBak = bspSysClockSpeedGet();
  
  //set system clock frequency up to 25 MHz for accurate sampling
  bspSysClockSpeedSet(BSP_SYS_CLK_25MHZ);
  
  // initialize timerA to capture rising edges on CLOCK XOSC
  cc1101InitTimerA();
  
  // Setting up time out in case we hang wating for capture interrupt
  halTimer32kIntConnect(&timeOutISR);
  halTimer32kSetIntFrequency(1);  // 1 sec timeout
  halTimer32kIntEnable();
  
  // wait for interrupt on timer capture or timeout
  while((!timerSemaphore) && (!timeoutSemaphore));
  
  // stop timeuot timer
  halTimer32kIntDisable();
    
  // stop timer
  disableTimerA();
 
  if(timerSemaphore)
  {
     // assuming 50% duty cycle. Period time = time between rising and
    // falling edge x 2
    capturePeriod = (captureTable[1]  - captureTable[0])*2;
  
    //check for negative number and set absolute value
    capturePeriod= (capturePeriod<0)?(0-capturePeriod):capturePeriod;
  
    // Claculate XOSC frequency in  MHz:
    // system clock frequency / capturePeriod
    // times clock xosc divider (192)
    floatingEstimate = (((25.0*192.0)/capturePeriod));
  
    //Round up/down estimated frequency and truncate to int
    xoscFreqEstimate = (uint8) (floatingEstimate + 0.5);
  }
  else
  {
    xoscFreqEstimate =  XOSC_FREQ_NONE;
  }
  
  //set system clock frequency back to standard
  bspSysClockSpeedSet(systemClockBak);
    
  //reset radio
  trxSpiCmdStrobe(CC1101_SRES);
  
  return xoscFreqEstimate;
}
/******************************************************************************
* @fn          cc120x_masterStartApp
*
* @brief       
*
* input parameters
*
* @param       pDummy  - pointer to pointer to void. Not used
*
* output parameters
*
* @return      SNIFF_RETURN_SUCCESS
*/
uint8 cc120x_masterStartApp(void)
{ 
  static uint8 marcState;
  // Set first packet number
  pkt = 1;
  
  // Set up GPIO pins. For debug
  cc112xSpiWriteReg(CC120X_IOCFG3,&cc120x_gpioConfigMaster[0],4);
  
  //Display while configuring radios*
  lcdBufferClear(0);
  lcdBufferPrintString(0,"    RX Sniff Test    ",0,eLcdPage0);
  lcdBufferSetHLine(0,0,LCD_COLS-1,eLcdPage7);
  lcdBufferPrintString(0,"     Radio in TX     ",0,eLcdPage2);
  lcdBufferPrintString(0,"                 ",0,eLcdPage3);
  lcdBufferPrintString(0,"  Press right button  ",0,eLcdPage4);
  lcdBufferPrintString(0,"    to send packet  ",0,eLcdPage5);
  lcdBufferPrintString(0," 1 Abort Master Mode ",0,eLcdPage7);
  lcdBufferSetHLine(0,0,LCD_COLS-1,55);
  lcdBufferInvertPage(0,0,LCD_COLS,eLcdPage7);
  lcdSendBuffer(0);
  
  // Calibrate radio
  trxSpiCmdStrobe(CC120X_SCAL);
  
  // Wait for calibration to be done (radio back in IDLE state)
  do {
    cc120xSpiReadReg(CC120X_MARCSTATE, &marcState, 1);
  } while (marcState != 0x41);
  // Put MCU to sleep
  __low_power_mode_3();
  while(1)
  {
    if(buttonPressed = bspKeyPushed(BSP_KEY_ALL))
    {
      if(buttonPressed == BSP_KEY_LEFT)
      {
        // Left button pressed. Abort function
        // Put radio in powerdown to save power
        trxSpiCmdStrobe(CC120X_SPWD);
        //Insert Carrier Sense threshold warning in Sniff Test Menu
        drawInfo();
        
        return SNIFF_RETURN_FAILURE;
      }
      else if (buttonPressed == BSP_KEY_RIGHT)
      {        
        //Right button pressed, send packet
        lcdBufferClear(0);
        // build packet
        comArray[0] = PKTLEN;   // length field
        comArray[1] = 0x00;     // address field
        comArray[2] = pkt>>24;  // payload
        comArray[3] = pkt>>16;
        comArray[4] = pkt>>8;
        comArray[5] = pkt;
        // Update LCD
        lcdBufferPrintString(0,"    RX Sniff Test    ",0,eLcdPage0);
        lcdBufferSetHLine(0,0,LCD_COLS-1,eLcdPage7);
        lcdBufferPrintString(0,"Sent Pkt number:",0,eLcdPage3);
        lcdBufferPrintInt(0,pkt,70,eLcdPage4);
        lcdBufferPrintString(0," 1 Abort Master Mode ",0,eLcdPage7);
        lcdBufferSetHLine(0,0,LCD_COLS-1,55);
        lcdBufferInvertPage(0,0,LCD_COLS,eLcdPage7);
        lcdSendBuffer(0);
        // Update packet counter
        pkt++;
        // Strobe IDLE and fill TX FIFO
        trxSpiCmdStrobe(CC120X_SIDLE);
        // wait for radio to enter IDLE state
        while((trxSpiCmdStrobe(CC112X_SNOP)& 0xF0) != 0x00);
        cc112xSpiWriteTxFifo(comArray,PKTLEN+1);
        // Send packet
        trxSpiCmdStrobe(CC120X_STX);
        // Wait for radio to finish sending packet
        while((trxSpiCmdStrobe(CC120X_SNOP)& 0xF0) != 0x00);
        // Put radio in powerdown to save power
        trxSpiCmdStrobe(CC120X_SPWD);
        //Put MCU to sleep
        __low_power_mode_3(); 
      }
    }
  }
/*******************************************************************************
*   @fn         runRX
*
*   @brief      Puts radio in RX and waits for packets. Function assumes
*               that status bytes are appended in the RX_FIFO
*               Update packet counter and display for each packet received.
*
*   @param      none
*
*   @return     none
*/
static void runRX(void) {

    uint8 rxBuffer[128] = {0};
    uint8 rxBytes;
    uint8 marcState;

    // Connect ISR function to GPIO2
    ioPinIntRegister(IO_PIN_PORT_1, GPIO2, &radioRxISR);

    // Interrupt on falling edge
    ioPinIntTypeSet(IO_PIN_PORT_1, GPIO2, IO_PIN_FALLING_EDGE);

    // Clear ISR flag
    ioPinIntClear(IO_PIN_PORT_1, GPIO2);

    // Enable interrupt
    ioPinIntEnable(IO_PIN_PORT_1, GPIO2);

    // Update LCD
    updateLcd();

    // Set radio in RX
    trxSpiCmdStrobe(CC120X_SRX);

    // Infinite loop
    while(TRUE) {

        // Wait for packet received interrupt
        if(packetSemaphore == ISR_ACTION_REQUIRED) {

            // Read number of bytes in RX FIFO
            cc120xSpiReadReg(CC120X_NUM_RXBYTES, &rxBytes, 1);

            // Check that we have bytes in FIFO
            if(rxBytes != 0) {

                // Read MARCSTATE to check for RX FIFO error
                cc120xSpiReadReg(CC120X_MARCSTATE, &marcState, 1);

                // Mask out MARCSTATE bits and check if we have a RX FIFO error
                if((marcState & 0x1F) == RX_FIFO_ERROR) {

                    // Flush RX FIFO
                    trxSpiCmdStrobe(CC120X_SFRX);
                } else {

                    // Read n bytes from RX FIFO
                    cc120xSpiReadRxFifo(rxBuffer, rxBytes);

                    // Check CRC ok (CRC_OK: bit7 in second status byte)
                    // This assumes status bytes are appended in RX_FIFO
                    // (PKT_CFG1.APPEND_STATUS = 1)
                    // If CRC is disabled the CRC_OK field will read 1
                    if(rxBuffer[rxBytes - 1] & 0x80) {

                        // Update packet counter
                        packetCounter++;
                    }
                }
            }

            // Update LCD
            updateLcd();

            // Reset packet semaphore
            packetSemaphore = ISR_IDLE;

            // Set radio back in RX
            trxSpiCmdStrobe(CC120X_SRX);
        }
    }
}
/******************************************************************************
 * @fn          runRX
 *
 * @brief       puts radio in RX and waits for packets. Function assumes
 *              that status bytes are appended in the RX_FIFO
 *              Update packet counter and display for each packet received.
 *                
 * @param       none
 *
 * @return      none
 */
void cc120xRunRX(void){
  
  uint8 rxBuffer[128] = {0};
  uint8 rxBytes;
  uint8 marcStatus;
  
    // Write radio registers
  registerConfig();
  
  // Connect ISR function to GPIO0, interrupt on falling edge
  trxIsrConnect(&radioRxTxISR);
  
  // Enable interrupt from GPIO_0
  trxEnableInt();
   
  // Update LCD
  updateLcd();

  // Set radio in RX
  trxSpiCmdStrobe(CC120X_SRX);

  // Loop until left button is pushed (exits application)
  while(BSP_KEY_LEFT != bspKeyPushed(BSP_KEY_ALL)){
    
    // Wait for packet received interrupt 
    if(packetSemaphore == ISR_ACTION_REQUIRED){
      
      // Read number of bytes in rx fifo
      cc120xSpiReadReg(CC120X_NUM_RXBYTES, &rxBytes, 1);
      
      // Check that we have bytes in fifo
      if(rxBytes != 0){
        
        // Read marcstate to check for RX FIFO error
        cc120xSpiReadReg(CC120X_MARCSTATE, &marcStatus, 1);
        
        // Mask out marcstate bits and check if we have a RX FIFO error
        if((marcStatus & 0x1F) == RX_FIFO_ERROR){
          
          // Flush RX Fifo
          trxSpiCmdStrobe(CC120X_SFRX);
        }
        else{
        
          // Read n bytes from rx fifo
          cc120xSpiReadRxFifo(rxBuffer, rxBytes);  
          
          // Check CRC ok (CRC_OK: bit7 in second status byte)
          // This assumes status bytes are appended in RX_FIFO
          // (PKT_CFG1.APPEND_STATUS = 1.)
          // If CRC is disabled the CRC_OK field will read 1
          if(rxBuffer[rxBytes-1] & 0x80){
            
            // Update packet counter
            packetCounter++;
          }
        }
      }
      
      // Update LCD
      updateLcd();
      
      // Reset packet semaphore
      packetSemaphore = ISR_IDLE;
      
      // Set radio back in RX
      trxSpiCmdStrobe(CC120X_SRX);
      
    }
  }
  // Reset packet counter
  packetCounter = 0;
  // Put radio to sleep and exit application
  trxSpiCmdStrobe(CC120X_SPWD);
}
/*******************************************************************************
*   @fn         main
*
*   @brief      Runs the main routine
*
*   @param      none
*
*   @return     none
*/
void main(void) {

    uint8 writeByte;

    // Initialize MCU and peripherals
    initMCU();

    // Write radio registers (preferred settings from SmartRF Studio)
    registerConfig();

    // Application specific registers
    // FIFO_THR = 120
    // GPIO0 = RXFIFO_THR
    // GPIO2 = PKT_SYNC_RXTX
    // GPIO3 = PKT_SYNC_RXTX
    writeByte = INFINITE_PACKET_LENGTH_MODE;
    cc112xSpiWriteReg(CC112X_PKT_CFG0, &writeByte, 1);
    writeByte = 0x78; cc112xSpiWriteReg(CC112X_FIFO_CFG, &writeByte, 1);
    writeByte = 0x00; cc112xSpiWriteReg(CC112X_IOCFG0,   &writeByte, 1);
    writeByte = 0x06; cc112xSpiWriteReg(CC112X_IOCFG2,   &writeByte, 1);
    writeByte = 0x06; cc112xSpiWriteReg(CC112X_IOCFG3,   &writeByte, 1);

    bspLedSet(BSP_LED_ALL);
    
    // Calibrate the radio according to the errata note
    manualCalibration();

    // Connect ISR function to GPIO0
    ioPinIntRegister(IO_PIN_PORT_1, GPIO0, &rxFifoAboveThresholdISR);

    // Interrupt on falling edge
    ioPinIntTypeSet(IO_PIN_PORT_1, GPIO0, IO_PIN_RISING_EDGE);

    // Clear interrupt
    ioPinIntClear(IO_PIN_PORT_1, GPIO0);

    // Enable interrupt
    ioPinIntEnable(IO_PIN_PORT_1, GPIO0);

    // Connect ISR function to GPIO2
    ioPinIntRegister(IO_PIN_PORT_1, GPIO2, &syncReceivedISR);

    // Interrupt on falling edge
    ioPinIntTypeSet(IO_PIN_PORT_1, GPIO2, IO_PIN_RISING_EDGE);

    // Clear interrupt
    ioPinIntClear(IO_PIN_PORT_1, GPIO2);

    // Enable interrupt
    ioPinIntEnable(IO_PIN_PORT_1, GPIO2);

    // Set up interrupt on GPIO3 (PKT_SYNC_RXTX)
    ioPinIntRegister(IO_PIN_PORT_1, GPIO3, &packetReceivedISR);

    // Interrupt on falling edge
    ioPinIntTypeSet(IO_PIN_PORT_1, GPIO3, IO_PIN_FALLING_EDGE);

    printWelcomeMessage();

    while (TRUE) {
        switch (state) {

            //------------------------------------------------------------------
            case RX_START:
            //------------------------------------------------------------------
            trxSpiCmdStrobe(CC112X_SRX);
            pBufferIndex = rxBuffer;

            // Disable interrupt on GPIO3
            ioPinIntDisable(IO_PIN_PORT_1, GPIO3);

            state = RX_WAIT;

            //------------------------------------------------------------------
            case RX_WAIT:
            //------------------------------------------------------------------
            if (packetReceived) {
                packetReceived = FALSE;

                // Check CRC and update LCD if CRC OK
                if ((rxBuffer[packetLength + 3]) & CRC_OK)
                    updateLcd();

                // Change to infinite packet length mode
                pktFormat = INFINITE;
                writeByte = INFINITE_PACKET_LENGTH_MODE;
                cc112xSpiWriteReg(CC112X_PKT_CFG0, &writeByte, 1);

                state = RX_START;
            }
            break;

            //------------------------------------------------------------------
            default:
            //------------------------------------------------------------------

            break;
        }
    }
}
/******************************************************************************
 *
 *  @fn       cc1101GetRxStatus(void)
 *
 *  @brief
 *            This function transmits a No Operation Strobe (SNOP) with the
 *            read bit set to get the status of the radio and the number of
 *            available bytes in the RXFIFO.
 *
 *            Status byte:
 *
 *            --------------------------------------------------------------------------------
 *            |          |            |                                                      |
 *            | CHIP_RDY | STATE[2:0] | FIFO_BYTES_AVAILABLE (available bytes in the RX FIFO |
 *            |          |            |                                                      |
 *            --------------------------------------------------------------------------------
 *
 *            NOTE:
 *            When reading a status register over the SPI interface while the
 *            register is updated by the radio hardware, there is a small, but
 *            finite, probability that the result is corrupt. This also applies
 *            to the chip status byte. The CC1100 and CC1101 errata notes explain
 *            the problem and propose several work arounds.
 *
 * input parameters
 *
 * @param     none
 *
 * output parameters
 *
 * @return    rfStatus_t
 *
 */
rfStatus_t cc1101GetRxStatus(void)
{
    return(trxSpiCmdStrobe(CC1101_SNOP | RADIO_READ_ACCESS));
}
/******************************************************************************
 * @fn      cc1101GetTxStatus(void)
 *
 * @brief   This function transmits a No Operation Strobe (SNOP) to get the
 *          status of the radio and the number of free bytes in the TX FIFO.
 *
 *          Status byte:
 *
 *          ---------------------------------------------------------------------------
 *          |          |            |                                                 |
 *          | CHIP_RDY | STATE[2:0] | FIFO_BYTES_AVAILABLE (free bytes in the TX FIFO |
 *          |          |            |                                                 |
 *          ---------------------------------------------------------------------------
 *
 *          NOTE:
 *          When reading a status register over the SPI interface while the
 *          register is updated by the radio hardware, there is a small, but
 *          finite, probability that the result is corrupt. This also applies
 *          to the chip status byte. The CC1100 and CC1101 errata notes explain
 *          the problem and propose several work arounds.
 *
 * input parameters
 *
 * @param   none
 *
 * output parameters
 *
 * @return  rfStatus_t
 *
 */
rfStatus_t cc1101GetTxStatus(void)
{
    return(trxSpiCmdStrobe(CC1101_SNOP));
}
/*******************************************************************************
* @fn          manualCalibration
*
* @brief       Perform manual calibration according to the errata note
* @param       none
*
* @return      none
*/
static void manualCalibration(void) {
  uint8 original_fs_cal2;
  uint8 calResults_for_vcdac_start_high[3];
  uint8 calResults_for_vcdac_start_mid[3];
  uint8 marcstate;
  uint8 writeByte;

  // 1) Set VCO cap-array to 0 (FS_VCO2 = 0x00)
  writeByte = 0x00;
  cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1);

  // 2) Start with high VCDAC (original VCDAC_START + 2):
  cc112xSpiReadReg(CC112X_FS_CAL2, &original_fs_cal2, 1);
  writeByte = original_fs_cal2 + VCDAC_START_OFFSET;
  cc112xSpiWriteReg(CC112X_FS_CAL2, &writeByte, 1);

  // 3) Calibrate and wait for calibration to be done (radio back in IDLE state)
  trxSpiCmdStrobe(CC112X_SCAL);
  do {
    cc112xSpiReadReg(CC112X_MARCSTATE, &marcstate, 1);
  } while (marcstate != 0x41);

  // 4) Read FS_VCO2, FS_VCO4 and FS_CHP register obtained with high VCDAC_START value
  cc112xSpiReadReg(CC112X_FS_VCO2, &calResults_for_vcdac_start_high[FS_VCO2_INDEX], 1);
  cc112xSpiReadReg(CC112X_FS_VCO4, &calResults_for_vcdac_start_high[FS_VCO4_INDEX], 1);
  cc112xSpiReadReg(CC112X_FS_CHP, &calResults_for_vcdac_start_high[FS_CHP_INDEX], 1);

  // 5) Set VCO cap-array to 0 (FS_VCO2 = 0x00)
  writeByte = 0x00;
  cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1);

  // 6) Continue with mid VCDAC (original VCDAC_START):
  writeByte = original_fs_cal2;
  cc112xSpiWriteReg(CC112X_FS_CAL2, &writeByte, 1);

  // 7) Calibrate and wait for calibration to be done (radio back in IDLE state)
  trxSpiCmdStrobe(CC112X_SCAL);
  do {
    cc112xSpiReadReg(CC112X_MARCSTATE, &marcstate, 1);
  } while (marcstate != 0x41);

  // 8) Read FS_VCO2, FS_VCO4 and FS_CHP register obtained with mid VCDAC_START value
  cc112xSpiReadReg(CC112X_FS_VCO2, &calResults_for_vcdac_start_mid[FS_VCO2_INDEX], 1);
  cc112xSpiReadReg(CC112X_FS_VCO4, &calResults_for_vcdac_start_mid[FS_VCO4_INDEX], 1);
  cc112xSpiReadReg(CC112X_FS_CHP, &calResults_for_vcdac_start_mid[FS_CHP_INDEX], 1);

  // 9) Write back highest FS_VCO2 and corresponding FS_VCO and FS_CHP result
  if (calResults_for_vcdac_start_high[FS_VCO2_INDEX] > calResults_for_vcdac_start_mid[FS_VCO2_INDEX]) {
    writeByte = calResults_for_vcdac_start_high[FS_VCO2_INDEX];
    cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1);
    writeByte = calResults_for_vcdac_start_high[FS_VCO4_INDEX];
    cc112xSpiWriteReg(CC112X_FS_VCO4, &writeByte, 1);
    writeByte = calResults_for_vcdac_start_high[FS_CHP_INDEX];
    cc112xSpiWriteReg(CC112X_FS_CHP, &writeByte, 1);
  }
  else {
    writeByte = calResults_for_vcdac_start_mid[FS_VCO2_INDEX];
    cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1);
    writeByte = calResults_for_vcdac_start_mid[FS_VCO4_INDEX];
    cc112xSpiWriteReg(CC112X_FS_VCO4, &writeByte, 1);
    writeByte = calResults_for_vcdac_start_mid[FS_CHP_INDEX];
    cc112xSpiWriteReg(CC112X_FS_CHP, &writeByte, 1);
  }
}
/******************************************************************************   
 * @fn          trxDetectCC112xCrystal()                                     
 *                                                                                
 * @brief       This function estimates the crystal frequency if a CC112x 
 *              is detected.
 *              SPI init must be applied before this function   
 *              can be called.
 *
 * @param       none
 *          
 * @return      none
 */
static uint8 trxDetectCC112xCrystal()
{  
  // Write EXT CLOCK to IOCFG3 and IOCFG2
  uint8 writeBytes1[2] = {0x31, 0x31};
  trx8BitRegAccess(CC112X_WRITE_BURST, CC112X_IOCFG3, writeBytes1, 2);
  // set external clock divider to 32
  writeBytes1[0] = 0x00;
  trx16BitRegAccess(CC112X_WRITE_BURST,CC112X_EXT_MEM_ACCESS,CC112X_ECG_CFG,writeBytes1,1);
  
  //wait for crystal to be stable (CHIP_RDYn)
  while((trxSpiCmdStrobe(CC112X_SNOP)& 0xF0) != 0x00);
  
  //get system clock frequency
  uint32_t systemClockBak = bspSysClockSpeedGet();
  
  //set system clock frequency up to 25 MHz for accurate sampling
  bspSysClockSpeedSet(BSP_SYS_CLK_25MHZ);
  
  // initialize timerA to capture rising and falling edges on EXT CLOCK
  cc112xInitTimerA();
  
  // Setting up time out in case we hang wating for capture interrupt
  halTimer32kIntConnect(&timeOutISR);
  halTimer32kSetIntFrequency(1); // 1 sec timeout
  halTimer32kIntEnable();
  
  // wait for interrupt on timer capture or timeout
  while((!timerSemaphore) && (!timeoutSemaphore));
  
  // stop timeuot timer
  halTimer32kIntDisable();
  
  // stop timer
  disableTimerA();
 
  if(timerSemaphore)
  {
    // assuming 50% duty cycle. Period time = time between rising and
    // falling edge x 2
    capturePeriod = (captureTable[1]  - captureTable[0])*2;
  
    //check for negative number and set absolute value
    capturePeriod= (capturePeriod<0)?(0-capturePeriod):capturePeriod;
  
    // Claculate XOSC frequency in  MHz: 
    // system clock frequency / capturePeriod
    // times external clock divider (32)
    // times digital clock divider (2)
    floatingEstimate = (((25.0*32.0*2.0)/capturePeriod));
  
    //Round up/down estimated frequency and truncate to int
    xoscFreqEstimate = (uint8) (floatingEstimate + 0.5);
  }
  else
  {
    xoscFreqEstimate =  XOSC_FREQ_NONE;
  }
  
  //set system clock frequency back to standard
  bspSysClockSpeedSet(systemClockBak);
  
  //reset radio
  trxSpiCmdStrobe(CC112X_SRES);
  
  return xoscFreqEstimate;
}