/******************************************************************************
 * @fn          cc115LRxTxISR
 *
 * @brief       ISR that's called when sync signal goes low. 
 *              In RX State: Filters incoming data. The global rxData pointer
 *              always points to this functions static rxData_tmp(struct of
 *              same kind). The validnes of rxData fields is indicated by the
 *              the global flag packetSemaphore.
 *              In TX State: Nothing is done except it facilitates power 
 *              consumption reduction when TX since the program doesn't need
 *              to wait until TX is done before re-enabling sync pin interrupt.
 *              cc11xLRadioTxRx is also set to CC115L_STATE_IDLE to be consistent with
 *              program.
 * 
 * input parameters
 *             
 * @param       none
 *
 * output parameters 
 *
 * @return      void
 */
void perCC115LRxTxISR(void)
{
  /* This variable stores the data locally. Access is given to per_test by 
   * assigning this instance to the global rxData pointer
   */
  static rxData_t rxData_tmp;
  
  rxData = &rxData_tmp;

  
  packetSemaphore |= SYNC_FOUND;
  /* Only relevant for 1-way PER test. In case of receiver not finding sync, 
   * the MSP will sample the RSSI value right after the instant where the packet
   * was supposed to be received. By setting the 32k timer at this point, the 
   * sample instant will be very close to the end of the wanted packet. The RSSI
   * value will hence hold lot of the signal power from the packet.
   */
  if((perSettings.masterSlaveLinked == PER_DEVICE_LINKED) && (perSettings.deviceMode == MASTER_DEVICE) && (perSettings.testRunning == PER_TRUE))
  {
  	if(perSettings.linkTopology == LINK_1_WAY)
  	{
  	  /* Read timer value and set the perSettings.packetRate valu(adjustment for temperature drift */
      halTimer32kSetIntFrequency(perSettings.packetRate);
      halTimer32kIntEnable();
    }
  }

  cc115LRadioTxIdle = CC115L_STATE_IDLE;
  
  return;
}
/******************************************************************************
 * @fn          halTimer32kMcuSleepTicks
 *
 * @brief       This function uses Timer B to sleep for a specfied number of
 *              ACLK ticks, that is less than 2^15 tics(1s).
 *              Assumes that the only interrupt source is
 *              generated by Timer B.
 *
 *              NOTE: When called, this function will assign NO ISR to the
 *              TIMERB0_VECTOR interrupt(NULL pointer). When interrupt triggers
 *              it will just wake up the MCU. Conflicts are possible if not
 *              used carefully since other parts of a program might use the
 *              TIMER B.
 *
 * input parameters
 *
 * @param       ticks  - Number of ACLK(32768Hz) ticks that the MCU will sleep
 *
 * output parameters
 *
 * @return      void
 */
void halTimer32kMcuSleepTicks(uint16 ticks)
{
  halTimer32kIntConnect(NULL);
  halTimer32kInit(ticks);
  halTimer32kIntEnable();
  __low_power_mode_3();
  halTimer32kAbort();
}
Exemple #3
0
/***********************************************************************************
* @fn          main
*
* @brief       This is the main entry of the RF Modem application. It sets
*              distinct short addresses for the nodes, initalises and runs
*              receiver and sender tasks sequentially in an endless loop.
*
* @return      none
*/
void main(void)
{

    char *szTitle= "MRFI RF modem";
    appUartRxIdle = FALSE;

    // Initialise board peripherals
    halBoardInit();

    halUartInit(HAL_UART_BAUDRATE_38400, 0);

    // 100 ms RX idle timeout
    appConfigTimer(1000/UART_RX_IDLE_TIME);

    // Indicate that the application has been initialised
    halLcdClear();
    halLcdWriteLine(HAL_LCD_LINE_1, szTitle);
    halLedSet(1);

    // Select application role (Device 1, Device 2 or Loopback)
    appSelectRole();

    if (appRole != DEVICE_LOOPBACK) {
        // Initialize the MRFI RF link layer
        mrfiLinkInit(appLocalAddr,appRemoteAddr,MRFI_CHANNEL);
    }

    // Indicate that the modem is operating
    halLcdWriteLine(HAL_LCD_LINE_1, szTitle);

    // Initialise error counters
    nTxErr= nRxErr= 0;

    // Enable RX idle timeout interrupt
    halTimer32kIntEnable();

    //  Main processing loop
    while(TRUE) {

        // On-board device processing (UART etc.)
        HAL_PROCESS();

        if (appRole == DEVICE_LOOPBACK) {

            // Loopback processing
            appLoopbackTask();

        } else {

            // RF transmitter processing
            appRfSenderTask();

            // RF receiver processing
            appRfReceiverTask();
        }

    }
}
Exemple #4
0
/***********************************************************************************
* @fn          appRfSenderTask
*
* @brief       Checks if new bytes have arrived from the UART. If there
*              are enough bytes to fill a maximal sized packet, or if the UART
*              is idle, the  bytes are transmitted on the air.
*
* @param       none
*
* @return      none
*/
static void appRfSenderTask(void)
{
    uint8 nBytes;
    uint8 payloadLength;
    uint8 bytesToRead;

    nBytes = halUartGetNumRxBytes();
    payloadLength= 0;
    bytesToRead= 0;

    if(nBytes >= APP_PAYLOAD_LENGTH || (appUartRxIdle && nBytes>0) ) {
        // Signal PC not to send on UART, while sending on air.
        halUartEnableRxFlow(FALSE);
        // Wait for PC to respond
        halMcuWaitUs(1000);

        bytesToRead = MIN(nBytes, APP_PAYLOAD_LENGTH);
        halUartRead(pTxData,bytesToRead);
        payloadLength+= bytesToRead;

        halLedToggle(3);
        if( (mrfiLinkSend(pTxData, payloadLength,N_RETRIES)) != MRFI_TX_RESULT_SUCCESS) {
            nTxErr++;
            appUpdateDisplay();
        }

        // Signal RX flow on
        halUartEnableRxFlow(TRUE);

        // Restart idle timer
        halTimer32kRestart();
        halTimer32kIntEnable();
        // Reset idle fimer flag
        appUartRxIdle = FALSE;
    }
}
/******************************************************************************
 * @fn          perCC1120CC1190RxTxISR
 *
 * @brief       ISR that's called when sync signal goes low. 
 *              In RX State: Filters incoming data. The global rxData pointer
 *              always points to this functions static rxData_tmp(struct of
 *              same kind). The validnes of rxData fields is indicated by the
 *              the global flag packetSemaphore.
 *              In TX State: Nothing is done except it facilitates power 
 *              consumption reduction when TX since the program doesn't need
 *              to wait until TX is done before re-enabling sync pin interrupt.
 *              cc1120cc1190RadioTxRx is also set to CC112X_STATE_IDLE to be consistent 
 *              with program.
 * 
 * input parameters
 *             
 * @param       none
 *
 * output parameters
 *
 * @return      void
 */
void perCC1120CC1190RxTxISR(void)
{
  uint8 rxBytes,rxLength,rssiIndex,lqiIndex;
  /* This variable stores the data locally. Access is given to per_test by 
   * assigning this instance to the global rxData pointer
   */
  static rxData_t rxData_tmp;
            
  rxData = &rxData_tmp;
  
  /* Checking if the chip is in RX state:  */
  if(cc1120cc1190RadioTxRx != CC112X_STATE_RX)
  {
    /* Transmission finished */
    if((perSettings.deviceMode == MASTER_DEVICE) && (perSettings.linkTopology == LINK_2_WAY) && (perSettings.masterSlaveLinked ==PER_DEVICE_LINKED))
    {
      /* Only applicable when master in 2-way test */
      cc1120cc1190RadioTxRx=CC112X_STATE_RX;
    }
    else
    {
      cc1120cc1190RadioTxRx  = CC112X_STATE_IDLE;
    }
    return;
  }
  
  packetSemaphore |= SYNC_FOUND;
  
  if(((perSettings.masterSlaveLinked == PER_DEVICE_LINKED)||(perSettings.masterSlaveLinked == PER_DEVICE_LINK_BYPASS)) && (perSettings.deviceMode == MASTER_DEVICE) && (perSettings.testRunning == PER_TRUE))
  {
  	if(perSettings.linkTopology == LINK_1_WAY)
  	{
  	  /* Read timer value and set the perSettings.packetRate valu(adjustment for temperature drift */
      halTimer32kSetIntFrequency(perSettings.packetRate);
      halTimer32kIntEnable();
    }
    else
    {
    	/* LINK_2_WAY */ 
    	
    	/* Timeout interrupt configuring is handled by the 2-way Per test */
      timer32kValue = halTimer32kReadTimerValue();
    	halTimer32kAbort();
    }
  }
    
  cc112xSpiReadReg(CC112X_NUM_RXBYTES,&rxBytes,1);
  /* Checking if the FIFO is empty */
  if(rxBytes == PER_FALSE)
  {
    /* The packet was removed by HW due to addr or length filtering -> Do nothing */
    /* Report that a sync was detected */ 
    rxData_tmp.rssi = perCC1120CC1190Read8BitRssi();
    return;
  }
  else
  {
    /* The RX FIFO is not empty, process contents */    
    cc112xSpiReadRxFifo(&rxLength, 1);  
    /* Check that the packet length just read + FCS(2B) + length byte match the RXBYTES */
    /* If these are not equal:
     * - RXFIFO overflow: Received packets not processed while beeing in RX. 
     */
    if(rxBytes != (rxLength+3))
    {
      /* This is a fault FIFO condition -> clean FIFO and register a sync detection */
      /* IDLE -> FLUSH RX FIFO -> RX */
      cc1120cc1190RxIdle();     
      perCC1120CC1190EnterRx(); 
      /* Report that a sync was detected */
      rxData_tmp.rssi = perCC1120CC1190Read8BitRssi();
      return;
    }
    else
    {
      /* We don't have a FIFO error condition -> get packet */
      
      /* Length Field */
      rxData_tmp.data[0] = rxLength;
      rssiIndex = rxLength+1;
      lqiIndex  = rssiIndex +1;
      
      /* Payload(ADDR + DATA + FCS) */
      cc112xSpiReadRxFifo(&rxData_tmp.data[1], lqiIndex);
      
      /* The whole packet has been read from the FIFO.
       * Check if the CRC is correct and that the packet length is as expected.
       * If not correct: report sync found and do not update RSSI or LQI.
       */
      if((!(rxData_tmp.data[lqiIndex] & CC112X_LQI_CRC_OK_BM)) || (perSettings.payloadLength != rxLength ))
      {
        rxData_tmp.rssi = perCC1120CC1190Read8BitRssi();
        return;
      }
      /* A complete error-free packet has arrived  */
      
      /* Measured data */
      rxData_tmp.length  = rxLength;
      rxData_tmp.lqi     = rxData_tmp.data[lqiIndex] & CC112X_LQI_EST_BM;
      rxData_tmp.addr    = rxData_tmp.data[1]; 
      
      /* Convert RSSI value from 2's complement to decimal value accounting for offset value */
      rxBytes = rxData_tmp.data[rssiIndex];        
      rxData_tmp.rssi = (int8)((int8)rxBytes) - cc1120cc1190RssiOffset;
      /* Signal a good packet is received */
      packetSemaphore |= PACKET_RECEIVED;
      return;
    } 
  }   
}     
Exemple #6
0
int main(void)
{

#error "Hi, Currently not working, still to be tested! - I didn't find time to debug it! "

	//halIntOn();
	unsigned long pktsSent = 0;
	perConfig.mode = PER_MODE_TX;
	    perConfig.state = PER_IDLE;
	    perConfig.channel = 26;
	    perConfig.txPower = 0;          // Index 0. Max output
	    perConfig.burstSize = 1000000;  // Max value
	    perConfig.pktRate   = 20;       // 20 pkts per second
	    perConfig.gainMode = PER_GAIN_MODE_NONE; // No PA/LNA

	    //
	        // Config basicRF
	        //
	        basicRfConfig.panId = PAN_ID;
	        basicRfConfig.ackRequest = false;



	    if(basicRfInit(&basicRfConfig) == FAILED)
	    {
	    while(1);
	    }

	    basicRfReceiveOff();
	    halRfSetTxPower(0);
	   // appTimerConfig(20);
	    halTimer32kInit(32768/20);
	    halTimer32kIntConnect(&appTimerIsr);    // Connect ISR
	    halTimer32kIntEnable();                 // Enable interrupts

	    while(1)
	       {
	    	if(perConfig.state == PER_TRANSMIT)
	    	        {
	    	            if(pktsSent < perConfig.burstSize) {
	    	                //
	    	                // Make sure sequence number has network byte order
	    	                //
	    	                UINT32_HTON(tTxPacket.seqNumber);

	    	                basicRfSendPacket(RX_ADDR, (unsigned char*)&tTxPacket, PACKET_SIZE);

	    	                //
	    	                // Change byte order back to host order before increment
	    	                //
	    	                UINT32_NTOH(tTxPacket.seqNumber);

	    	                //
	    	                // Update variables
	    	                //
	    	                tTxPacket.seqNumber++;
	    	                pktsSent++;
	    	                perConfig.state = PER_PACKET_RECEIVED;

	    	                //
	    	                // Update LED
	    	                //
	    	           //     bspLedToggle(BSP_LED_1);

	    	   }
	    	            else {
	    	                //
	    	                // Done sending packets, exit TX loop
	    	                //
	    	                break;
	    	            }
	    	        }
	       }
}
/******************************************************************************   
 * @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;
}
/******************************************************************************   
 * @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;
}