Exemple #1
0
/**************************************************************************************************
 * @fn          MRFI_Sleep
 *
 * @brief       Request radio go to sleep.
 *
 * @param       none
 *
 * @return      zero : if successfully went to sleep
 *              non-zero : if sleep was not entered
 **************************************************************************************************
 */
uint8_t MRFI_Sleep(void)
{
  /* if radio is already asleep just indicate radio went to sleep successfully */
  if (mrfiRadioIsSleeping)
  {
    /* return value of zero indicates sleep state was entered */
    return( 0 );
  }

  /* determine if sleep is possible and return the corresponding code */
  {
    bspIState_t s;

    /* critical section necessary for watertight testing and setting of state variables */
    BSP_ENTER_CRITICAL_SECTION(s);
    if (!mrfiTxActive && !mrfiRxActive)
    {
      mrfiRadioIsSleeping = 1;
      MRFI_DISABLE_SYNC_PIN_INT();
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SIDLE);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SPWD);
      BSP_EXIT_CRITICAL_SECTION(s);
      /* return value of zero indicates sleep state was entered */
      return( 0 );
    }
    else
    {
      BSP_EXIT_CRITICAL_SECTION(s);
      /* return value of non-zero indicates sleep state was *not* entered */
      return( 1 );
    }
  }
}
Exemple #2
0
/******************************************************************************
 * @fn          nwk_QadjustOrder
 *
 * @brief       Adjusts the age of everyone in the queue newer than the frame
 *              being removed.
 *
 * input parameters
 * @param   which   - INQ or OUTQ to adjust
 * @param   stamp   - value of frame being removed
 *
 * output parameters
 *
 * @return      void
 */
void nwk_QadjustOrder(uint8_t which, uint8_t stamp)
{
  frameInfo_t *pFI;
  uint8_t      i, num;
  bspIState_t  intState;

  if (INQ == which)
  {
    pFI  = sInFrameQ;
    num  = SIZE_INFRAME_Q;
  }
  else
  {
/*    pFI  = sOutFrameQ; */
/*    num  = SIZE_OUTFRAME_Q; */
    return;
  }

  BSP_ENTER_CRITICAL_SECTION(intState);

  for (i=0; i<num; ++i, ++pFI)
  {
    if ((pFI->fi_usage != FI_AVAILABLE) && (pFI->orderStamp > stamp))
    {
      pFI->orderStamp--;
    }
  }

  BSP_EXIT_CRITICAL_SECTION(intState);

  return;
}
Exemple #3
0
// the isr's...
static void uart_tx_irq( void )
  {    
  unsigned char c;
    {
    uart_get_tx_data_type handler;
    BSP_CRITICAL_STATEMENT( handler = uart_tx_handler );

    // if not currently in suspend mode and a handler exists
    if( uart_tx_suspend == false && handler != NULL )
      {
      if( (*handler)( &c ) != false ) // if data available, reset the interrupt
        {
        UART_SEND( UART_NUMBER, UART_LOCATION, c ); // send the byte
        }
      else // if no data suspend transmission
        {
        uart_tx_message_suspend( handler );
        UART_IRQ_FLAG_SET( UART_NUMBER, UART_LOCATION, TX );
        }
      }
    else
      {
      bspIState_t istate;
      BSP_ENTER_CRITICAL_SECTION( istate );
      // if we are in suspended mode or we just sent an xon or xoff character
      // while transmits were disabled or the message has been completely sent,
      // then simply disable irq's so we don't get stuck in an infinite loop
      UART_IRQ_DISABLE( UART_NUMBER, UART_LOCATION, TX );
      UART_IRQ_FLAG_SET( UART_NUMBER, UART_LOCATION, TX );
      BSP_EXIT_CRITICAL_SECTION( istate );
      }
    }
  return;
}
/******************************************************************************
 * @fn          uart1_tx_irq
 *
 * @brief       TX interrupt service routine
 *
 * input parameters
 *
 * output parameters
 *
 * @return
 */
void uart0_tx_irq( void )
  {
  unsigned char c;
  uart_get_tx_data_type handler;

  BSP_CRITICAL_STATEMENT( handler = uart0_tx_handler );

  /* if a handler exists */
  if( handler != NULL )
    {
    if( (*handler)( &c ) != false ) /* if this is not the last byte to send */
      {
      bspIState_t intState;
      BSP_ENTER_CRITICAL_SECTION( intState );

      /* only reset the interrupt flag if we have additional data to send
       * that way, if we are done then the interrupt is still pending and
       * will be immediately entered upon re-enabling it.*/
      UART_IRQ_FLAG_CLR( UART_NUMBER_0, UART0_LOCATION, TX ); /* eset the interrupt */

      BSP_EXIT_CRITICAL_SECTION( intState );
      }
    else
      {
      bspIState_t intState;
      BSP_ENTER_CRITICAL_SECTION( intState );

      /* we're done sending data.  since we left the interrupt pending,
       * disable it so we don't re-enter the isr.  the interrupt will be
       * re-enabled when there is another message to send. */
      UART_IRQ_DISABLE( UART_NUMBER_0, UART0_LOCATION, TX );

      /* no more data to send, reset the handler to flag not busy */
      uart0_tx_handler = NULL;

      BSP_EXIT_CRITICAL_SECTION( intState );
      }

    UART_SEND( UART_NUMBER_0, UART0_LOCATION, c ); /* send the byte */
    }
  else /* if no handler exists?!?!?!? */
    /* something went wrong, disable interrupts so we don't get stuck here */
    UART_IRQ_DISABLE( UART_NUMBER_0, UART0_LOCATION, TX );

  return;
}
linkID_t nwk_getLocalLinkID(void)
{
    linkID_t lid = 0;

#if NUM_CONNECTIONS > 0
    uint8_t i;
    bspIState_t intState;


    BSP_ENTER_CRITICAL_SECTION(intState);
    if (sNumLinkers)
    {
        sNumLinkers--;
        BSP_EXIT_CRITICAL_SECTION(intState);

        nwk_setListenContext(LINK_LISTEN_OFF);
        lid = sServiceLinkID[0];

        /* If more than one Link frame has been processed without an intervening
         * Listen assume that there will be another Link Listen call that will
         * poll for completion which has already occurred. Age any existing entries.
         * This code was added to deal with the possibility of mulitple EDs being
         * activated simultaneously in the AP-as-data-hub example. This opens a
         * window of opportunity for a "typical" scenario to get hosed. But for
         * a "typical" scenario to get hosed a number of improbable events have to
         * occur. These are deemed far less likely than the multiple-ED-activation
         * scenario in the AP-as-dat-hub case.
         */
        for (i = 0; i < sNumLinkers; ++i)
        {
            sServiceLinkID[i] = sServiceLinkID[i + 1];
        }
    }
    else
    {
        BSP_EXIT_CRITICAL_SECTION(intState);
    }
#endif  /* NUM_CONNECTIONS */

    return lid;
}
Exemple #6
0
/****************************************************************************************************
 * @fn          wbsl_DelayUsec
 *
 * @brief       Execute a delay loop using HW timer. The macro actually used to do the delay
 *              is not thread-safe. This routine makes the delay execution thread-safe by breaking
 *              up the requested delay up into small chunks and executing each chunk as a critical
 *              section. The chunk size is chosen to be the smallest value used by the radio. The delay
 *              is only approximate because of the overhead computations. It errs on the side of
 *              being too long.
 *
 * input parameters
 * @param   howLong - number of microseconds to delay
 *
 * @return      none
 ****************************************************************************************************
 */
static void wbsl_DelayUsec(u16 howLong)
{
    bspIState_t s;
    u16 count = howLong/WBSL_MAX_DELAY_US;

    if (howLong)
    {
        do
        {
            BSP_ENTER_CRITICAL_SECTION(s);
            BSP_DELAY_USECS(WBSL_MAX_DELAY_US);
            BSP_EXIT_CRITICAL_SECTION(s);
         }while (count--);
     }
}
Exemple #7
0
/* State machine for co-ordinator is not relevant
 * The coordinator replies all requests */
static void mac_proc_pkt(frame802154_t *frame)
{
    if((frame->fcf.frame_type == MAC_CMD) &&
            (frame->payload[0] == MAC_ASSOC_REQ))
    {
        bspIState_t x;
        BSP_ENTER_CRITICAL_SECTION(x);
        mac_send_assoc_rsp(&frame->dest_addr);
        BSP_EXIT_CRITICAL_SECTION(x);
    }
    else if(frame->fcf.frame_type == MAC_DATA)
    {
        //route it appropriately
    }
}
Exemple #8
0
/**************************************************************************************************
 * @fn          MRFI_ReplyDelay
 *
 * @brief       Delay number of milliseconds scaled by data rate. Check semaphore for
 *              early-out. Run in a separate thread when the reply delay is
 *              invoked. Cleaner then trying to make MRFI_DelayMs() thread-safe
 *              and reentrant.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
void MRFI_ReplyDelay()
{
  bspIState_t s;
  uint16_t    milliseconds = sReplyDelayScalar;

  BSP_ENTER_CRITICAL_SECTION(s);
  sReplyDelayContext = 1;
  BSP_EXIT_CRITICAL_SECTION(s);

  while (milliseconds)
  {
    Mrfi_DelayUsecSem( 1000 );
    if (sKillSem)
    {
      break;
    }
    milliseconds--;
  }

  BSP_ENTER_CRITICAL_SECTION(s);
  sKillSem           = 0;
  sReplyDelayContext = 0;
  BSP_EXIT_CRITICAL_SECTION(s);
}
Exemple #9
0
bool uart_tx_message_suspend( uart_get_tx_data_type handler )
  {
  bool status = false; // assume failure initially
  bspIState_t intState;
  BSP_ENTER_CRITICAL_SECTION( intState );
  
  if( uart_tx_handler == handler )
    {
    uart_tx_suspend = true; // indicate we are in suspended status
    status = true; // indicate success
    }
  
  BSP_EXIT_CRITICAL_SECTION( intState );
  return status;
  }
Exemple #10
0
/****************************************************************************************************
 * @fn          Mrfi_DelayUsec
 *
 * @brief       Execute a delay loop using HW timer. The macro actually used to do the delay
 *              is not thread-safe. This routine makes the delay execution thread-safe by breaking
 *              up the requested delay into small chunks and executing each chunk as a critical
 *              section. The chunk size is choosen to be the smallest value used by MRFI. The delay
 *              is only approximate because of the overhead computations. It errs on the side of
 *              being too long.
 *
 * input parameters
 * @param   howLong - number of microseconds to delay
 *
 * @return      none
 ****************************************************************************************************
 */
static void Mrfi_DelayUsec(uint16_t howLong)
{
  bspIState_t intState;
  uint16_t    count = howLong/MRFI_MAX_DELAY_US;

  if (howLong)
  {
    do
    {
      BSP_ENTER_CRITICAL_SECTION(intState);
      BSP_DELAY_USECS(MRFI_MAX_DELAY_US);
      BSP_EXIT_CRITICAL_SECTION(intState);
    } while (count--);
  }
  return;
}
Exemple #11
0
bool uart_tx_message_resume( uart_get_tx_data_type handler )
  {
  bool status = false; // assume failure initially
  bspIState_t intState;
  BSP_ENTER_CRITICAL_SECTION( intState );
  
  if( uart_tx_handler == handler )
    {
    uart_tx_suspend = false; // indicate we are no longer suspended
    UART_IRQ_ENABLE( UART_NUMBER, UART_LOCATION, TX ); // enable interrupt
    status = true; // indicate success
    }
  
  BSP_EXIT_CRITICAL_SECTION( intState );
  return status;
  }
Exemple #12
0
bool uart_tx_message_end( uart_get_tx_data_type handler )
  {
  bspIState_t intState;
  bool status = false; // assume failure initially

  BSP_ENTER_CRITICAL_SECTION( intState );

  if( uart_tx_handler == handler )
    {
    // no more data to send, reset the handler to flag not busy
    uart_tx_handler = NULL;
    uart_tx_suspend = false;
    status = true; // indicate success
    }
    
  BSP_EXIT_CRITICAL_SECTION( intState );
  
  return status; // indicate status
  }
Exemple #13
0
/******************************************************************************
 * @fn          uart_rx_message
 *
 * @brief       Installs receive handler if no message currently being received
 *
 * input parameters
 * @param   handler - UART receive handler
 *
 * @return   Status of the operation.
 *           true                 Receive handler successfully installed
 *           false                Message being received or handler is invalid
 *
 */
bool uart_rx_message( uart_put_rx_data_type handler )
  {
  bspIState_t intState;
  bool status = false;  /* assume failure initially */

  /* updates required, store interrupt state and disable interrupts */
  BSP_ENTER_CRITICAL_SECTION(intState);

  /* if no message is being received and the handler looks valid */
  if( uart_rx_handler == NULL && handler != NULL )
    {
    uart_rx_handler = handler; /* install the handler */

    status = true; /* indicate success */
    }

  BSP_EXIT_CRITICAL_SECTION(intState); /* restore interrupt state */

  return status; /* indicate status */
  }
Exemple #14
0
bool uart_rx_message_end( uart_put_rx_data_type handler )
  {
  bspIState_t intState;
  bool status = false; // assume failure initially
    
  BSP_ENTER_CRITICAL_SECTION(intState);
    
  // if it appears that the current receiver client is terminating the message
  if( uart_rx_handler == handler )
    {
    // clear the handler to indicate the driver is free for acquisition
    uart_rx_handler = NULL;

    status = true;
    }
   
  BSP_EXIT_CRITICAL_SECTION(intState);

  return status; // return result
  }
Exemple #15
0
/****************************************************************************************************
 * @fn          Mrfi_DelayUsecSem
 *
 * @brief       Execute a delay loop using a HW timer. See comments for Mrfi_DelayUsec().
 *              Delay specified number of microseconds checking semaphore for
 *              early-out. Run in a separate thread when the reply delay is
 *              invoked. Cleaner then trying to make MRFI_DelayUsec() thread-safe
 *              and reentrant.
 *
 * input parameters
 * @param   howLong - number of microseconds to delay
 *
 * @return      none
 ****************************************************************************************************
 */
static void Mrfi_DelayUsecSem(uint16_t howLong)
{
  bspIState_t s;
  uint16_t count = howLong/MRFI_MAX_DELAY_US;

  if (howLong)
  {
    do
    {
      BSP_ENTER_CRITICAL_SECTION(s);
      BSP_DELAY_USECS(MRFI_MAX_DELAY_US);
      BSP_EXIT_CRITICAL_SECTION(s);
      if (sKillSem)
      {
        break;
      }
    } while (count--);
  }

  return;
}
Exemple #16
0
// user interface functions
void uart_init( void )
  {
  volatile unsigned int i;
  bspIState_t istate;
  BSP_ENTER_CRITICAL_SECTION( istate );

  // disable the receive and transmit interrupts for the moment
  UART_IRQ_DISABLE( UART_NUMBER, UART_LOCATION, TX ); 
  UART_IRQ_DISABLE( UART_NUMBER, UART_LOCATION, RX ); 

  BSP_EXIT_CRITICAL_SECTION( istate );

  // make sure the handler functions are cleared in case we are re-initialized
  uart_tx_handler = NULL;
  uart_rx_handler = NULL;

  // clear transmit suspend semaphore
  uart_tx_suspend = false;
  
  // initialize the uart interface for operations
  UART_INIT( UART_NUMBER,
             UART_LOCATION,
             UART_FLOW_CONTROL,    // enable/disable flow control
             UART_PARITY_MODE,     // enable/disable parity
             UART_STOP_BITS,       // number of stop bits
             UART_BAUD_RATE );     // baud rate to use

  i = UART_BAUD_RATE >> 5; // delay approximately 1 bit time
  while( --i != 0 ) // give the uart some time to initialize
      ; // null statement

  // enable receive interrupts, they are always welcome.
  UART_IRQ_ENABLE( UART_NUMBER, UART_LOCATION, RX ); 

  return;
  }
Exemple #17
0
/******************************************************************************
 * @fn          uart_tx_message
 *
 * @brief       Installs transmit handler if no message currently being sent
 *
 * input parameters
 * @param   handler - UART transmit handler
 *
 * @return   Status of the operation.
 *           true                 Transmit handler successfully installed
 *           false                Message being sent or handler is invalid
 *
 */
bool uart0_tx_message( uart_get_tx_data_type handler )
  {
  bspIState_t  intState;
  bool status = false; /* assume failure initially */

  /* updates required, store interrupt state and disable interrupts */
  BSP_ENTER_CRITICAL_SECTION(intState);

  /* if no message is currently being sent and handler looks valid */
  if( uart0_tx_handler == NULL && handler != NULL )
    {
    uart0_tx_handler = handler; /* install the handler */

    /* once the handler has been setup, enable the interrupt.
     * this will cause the message to begin transmission */
    UART_IRQ_ENABLE( UART_NUMBER_0, UART0_LOCATION, TX );

    status = true; /* indicate success */
    }

  BSP_EXIT_CRITICAL_SECTION(intState); /* restore interrupt state */

  return status; /* indicate status */
  }
Exemple #18
0
/**************************************************************************************************
 * @fn          MRFI_SyncPinRxIsr
 *
 * @brief       This interrupt is called when the SYNC signal transition from high to low. 
 *              The sync signal is routed to the sync pin which is a GPIO pin.  This high-to-low
 *              transition signifies a receive has completed.  The SYNC signal also goes from
 *              high to low when a transmit completes.   This is protected against within the
 *              transmit function by disabling sync pin interrupts until transmit completes.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void MRFI_SyncPinRxIsr(void)
{
  uint8_t frameLen;
  uint8_t rxBytes;

  /* ------------------------------------------------------------------
   *    Abort if asleep
   *   -----------------
   */
 
  /*
   *  If radio is asleep, abort immediately.  Nothing further is required.
   *  If radio is awake, set "receive active" flag and continue processing the receive.
   */
  {
    bspIState_t s;
    
    /* critical section necessary for watertight testing and setting of state variables */
    BSP_ENTER_CRITICAL_SECTION(s);

    /* if radio is asleep, just abort from here */
    if (mrfiRadioIsSleeping)
    {
      BSP_EXIT_CRITICAL_SECTION(s);
      return;
    }
    
    /* radio is not asleep, set flag that indicates receive is active */
    mrfiRxActive = 1;
    BSP_EXIT_CRITICAL_SECTION(s);
  }

  
  /* ------------------------------------------------------------------
   *    Get RXBYTES
   *   -------------
   */

  /*
   *  Read the RXBYTES register from the radio.
   *  Bit description of RXBYTES register:
   *    bit 7     - RXFIFO_OVERFLOW, set if receive overflow occurred
   *    bits 6:0  - NUM_BYTES, number of bytes in receive FIFO
   *
   *  Due a chip bug, the RXBYTES register must read the same value twice
   *  in a row to guarantee an accurate value.
   */
  {
    uint8_t rxBytesVerify;
    
    rxBytesVerify = mrfiSpiReadReg(MRFI_CC2500_SPI_REG_RXBYTES);

    do 
    {
      rxBytes = rxBytesVerify;
      rxBytesVerify = mrfiSpiReadReg(MRFI_CC2500_SPI_REG_RXBYTES);
    }
    while (rxBytes != rxBytesVerify);
  }

  
  /* ------------------------------------------------------------------
   *    FIFO empty?
   *   -------------
   */

  /*
   *  See if the receive FIFIO is empty before attempting to read from it.
   *  It is possible nothing the FIFO is empty even though the interrupt fired.
   *  This can happen if address check is enabled and a non-matching packet is
   *  received.  In that case, the radio automatically removes the packet from
   *  the FIFO.
   */
  if (rxBytes == 0)
  {
    /* receive FIFO is empty - do nothing, skip to end */
  }
  else
  {
    /* receive FIFO is not empty, continue processing */

    /* ------------------------------------------------------------------
     *    Process frame length
     *   ----------------------
     */
    
    /* read the first byte from FIFO - the packet length */
    mrfiSpiReadRxFifo(&frameLen, MRFI_LENGTH_FIELD_SIZE);

    /*
     *  Make sure that the frame length just read corresponds to number of bytes in the buffer.
     *  If these do not match up something is wrong.
     *
     *  This can happen for several reasons:
     *   1) Incoming packet has an incorrect format or is corrupted.
     *   2) The receive FIFO overflowed.  Overflow is indicated by the high
     *      bit of rxBytes.  This guarantees the value of rxBytes value will not
     *      match the number of bytes in the FIFO for overflow condition.
     *   3) Interrupts were blocked for an abnormally long time which
     *      allowed a following packet to at least start filling the
     *      receive FIFO.  In this case, all received and partially received
     *      packets will be lost - the packet in the FIFO and the packet coming in.
     *      This is the price the user pays if they implement a giant
     *      critical section.
     *   4) A failed transmit forced radio to IDLE state to flush the transmit FIFO.
     *      This could cause an active receive to be cut short.
     */
    if (rxBytes != (frameLen + MRFI_LENGTH_FIELD_SIZE + MRFI_RX_METRICS_SIZE))
    {
      bspIState_t s;

      /* mismatch between bytes-in-FIFO and frame length */

      /*
       *  Flush receive FIFO to reset receive.  Must go to IDLE state to do this.
       *  The critical section guarantees a transmit does not occur while cleaning up.
       */
      BSP_ENTER_CRITICAL_SECTION(s);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SIDLE);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SFRX);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SRX);
      BSP_EXIT_CRITICAL_SECTION(s);
      
      /* flush complete, skip to end */
    }
    else
    {
      /* bytes-in-FIFO and frame length match up - continue processing */
      
      /* ------------------------------------------------------------------
       *    Get packet
       *   ------------
       */

      /* set length field */
      mrfiIncomingPacket.frame[MRFI_LENGTH_FIELD_OFS] = frameLen;
  
      /* get packet from FIFO */
      mrfiSpiReadRxFifo(&(mrfiIncomingPacket.frame[MRFI_FRAME_BODY_OFS]), frameLen);
  
      /* get receive metrics from FIFO */
      mrfiSpiReadRxFifo(&(mrfiIncomingPacket.rxMetrics[0]), MRFI_RX_METRICS_SIZE);


      /* ------------------------------------------------------------------
       *    CRC check
       *   ------------
       */

      /*
       *  Note!  Automatic CRC check is not, and must not, be enabled.  This feature
       *  flushes the *entire* receive FIFO when CRC fails.  If this feature is
       *  enabled it is possible to be reading from the FIFO and have a second
       *  receive occur that fails CRC and automatically flushes the receive FIFO.
       *  This could cause reads from an empty receive FIFO which puts the radio
       *  into an undefined state.
       */
      
      /* determine if CRC failed */
      if (!(mrfiIncomingPacket.rxMetrics[MRFI_RX_METRICS_CRC_LQI_OFS] & MRFI_RX_METRICS_CRC_OK_MASK))
      {
        /* CRC failed - do nothing, skip to end */
      }
      else
      {
        /* CRC passed - continue processing */

      /* ------------------------------------------------------------------
       *    Filtering 
       *   -----------
       */

        /* see if filtering is enabled and, if so, determine if address is a match */
        if (mrfiRxFilterEnabled && memcmp(MRFI_P_DST_ADDR(&mrfiIncomingPacket), &mrfiRxFilterAddr[0], MRFI_ADDR_SIZE))
        {
          /* packet filtered out - do nothing, skip to end */
        }
        else
        {
          /* packet not filtered out - receive successful */
          
          /* ------------------------------------------------------------------
           *    Receive succeeded
           *   -------------------
           */

          /* call external, higher level "receive complete" processing routine */
          MRFI_RxCompleteISR();
        }
      }
    }
  }

  /* ------------------------------------------------------------------
   *    End of function
   *   -------------------
   */
  
  /* clear "receive active" flag and exit */
  mrfiRxActive = 0;
}
Exemple #19
0
/******************************************************************************
 * @fn          SMPL_SendOpt
 *
 * @brief       Send a message to a peer application.
 *
 * input parameters
 * @param   lid     - Link ID (port) from application
 * @param   msg     - pointer to message from app to be sent
 * @param   len     - length of enclosed message
 * @param   options - Transmit options (bit map)
 *
 * output parameters
 *
 * @return   Status of operation. On a filaure the frame buffer is discarded
 *           and the Send call must be redone by the app.
 *             SMPL_SUCCESS
 *             SMPL_BAD_PARAM    No valid Connection Table entry for Link ID
 *                               Data in Connection Table entry bad
 *                               No message or message too long
 *             SMPL_NOMEM        No room in output frame queue
 *             SMPL_TX_CCA_FAIL  CCA failure.
 *             SMPL_NO_ACK       If application auto acknowledgement enabled
 *                               and no acknowledgement is received
 */
smplStatus_t SMPL_SendOpt(linkID_t lid, uint8_t *msg, uint8_t len, txOpt_t options)
{
  frameInfo_t  *pFrameInfo;
  connInfo_t   *pCInfo     = nwk_getConnInfo(lid);
  smplStatus_t  rc         = SMPL_BAD_PARAM;
  uint8_t       radioState;
  uint8_t       ackreq     = 0;
#if defined(ACCESS_POINT)
  uint8_t  loc;
#endif
  radioState = MRFI_GetRadioState();
  /* we have the connection info for this Link ID. make sure it is valid. */
   if (!pCInfo || ((rc=nwk_checkConnInfo(pCInfo, CHK_TX)) != SMPL_SUCCESS))
  {
    return rc;
  }

  /* parameter sanity check... */
  if (!msg || (len > MAX_APP_PAYLOAD))
  {
    return rc;
  }

  /* Build an outgoing message frame destined for the port from the
   * connection info using the destination address also from the
   * connection info.
   */
  if (SMPL_TXOPTION_NONE == options)
  {
    pFrameInfo = nwk_buildFrame(pCInfo->portTx, msg, len, pCInfo->hops2target);
  }
#if defined(APP_AUTO_ACK)
  else if (options & SMPL_TXOPTION_ACKREQ)
  {
    if (SMPL_LINKID_USER_UUD != lid)
    {
      pFrameInfo = nwk_buildAckReqFrame(pCInfo->portTx, msg, len, pCInfo->hops2target, &pCInfo->ackTID);
      ackreq     = 1;
    }
    else
    {
      /* can't request an ack on the UUD link ID */
      return SMPL_BAD_PARAM;
    }
  }
#endif  /* APP_AUTO_ACK */
  else
  {
    return SMPL_BAD_PARAM;
  }

  if (!pFrameInfo)
  {
    return SMPL_NOMEM;
  }
  memcpy(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), pCInfo->peerAddr, NET_ADDR_SIZE);

#if defined(SMPL_SECURE)
  {
    uint32_t *pUL = 0;

    if (pCInfo->thisLinkID != SMPL_LINKID_USER_UUD)
    {
      pUL = &pCInfo->connTxCTR;
    }
    nwk_setSecureFrame(&pFrameInfo->mrfiPkt, len, pUL);
  }
#endif  /* SMPL_SECURE */

#if defined(ACCESS_POINT)
  /* If we are an AP trying to send to a polling device, don't do it.
   * See if the target is a store-and-forward client.
   */
  if (nwk_isSandFClient(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), &loc))
  {
     pFrameInfo->fi_usage = FI_INUSE_UNTIL_FWD;
     return SMPL_SUCCESS;
  }
  else
#endif  /* ACCESS_POINT */
  {
    rc = nwk_sendFrame(pFrameInfo, MRFI_TX_TYPE_CCA);
  }

#if !defined(APP_AUTO_ACK)
  /* save a little code space with this #if */
  (void) ackreq;    /* keep compiler happy */
  return rc;
#else
  /* we're done if the send failed or no ack requested. */
  if (SMPL_SUCCESS != rc || !ackreq)
  {
    return rc;
  }

  NWK_CHECK_FOR_SETRX(radioState);
  NWK_REPLY_DELAY();
  NWK_CHECK_FOR_RESTORE_STATE(radioState);

  {
    bspIState_t intState;

    /* If the saved TID hasn't been reset then we never got the ack. */
    BSP_ENTER_CRITICAL_SECTION(intState);
    if (pCInfo->ackTID)
    {
      pCInfo->ackTID = 0;
      rc = SMPL_NO_ACK;
    }
    BSP_EXIT_CRITICAL_SECTION(intState);
  }

  return rc;
#endif  /* APP_AUTO_ACK */
}
void main (void)
{
  bspIState_t intState;

#ifdef FREQUENCY_AGILITY
  memset(sSample, 0x0, sizeof(sSample));
#endif

  BSP_Init();

  /* If an on-the-fly device address is generated it must be done before the
   * call to SMPL_Init(). If the address is set here the ROM value will not
   * be used. If SMPL_Init() runs before this IOCTL is used the IOCTL call
   * will not take effect. One shot only. The IOCTL call below is conformal.
   */
#ifdef I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE
  {
    addr_t lAddr;

    createRandomAddress(&lAddr);
    SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &lAddr);
  }
#endif /* I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE */

  SMPL_Init(sCB);

  /* green and red LEDs on solid to indicate waiting for a Join. */
  if (!BSP_LED2_IS_ON())
  {
    toggleLED(2);
  }
  if (!BSP_LED1_IS_ON())
  {
    toggleLED(1);
  }

  /* main work loop */
  while (1)
  {
    /* manage FHSS schedule if FHSS is active */
    FHSS_ACTIVE( nwk_pllBackgrounder( false ) );
    
    /* Wait for the Join semaphore to be set by the receipt of a Join frame from a
     * device that supports an End Device.
     *
     * An external method could be used as well. A button press could be connected
     * to an ISR and the ISR could set a semaphore that is checked by a function
     * call here, or a command shell running in support of a serial connection
     * could set a semaphore that is checked by a function call.
     */
    if (sJoinSem && (sNumCurrentPeers < NUM_CONNECTIONS))
    {
      /* listen for a new connection */
      while (1)
      { /* SMPL_LinkListen will call nwk_PllBackgrounder for us if FHSS active */
        if (SMPL_SUCCESS == SMPL_LinkListen(&sLID[sNumCurrentPeers]))
        {
          break;
        }
        /* Implement fail-to-link policy here. otherwise, listen again. */
      }

      sNumCurrentPeers++;

      BSP_ENTER_CRITICAL_SECTION(intState);
      sJoinSem--;
      BSP_EXIT_CRITICAL_SECTION(intState);
    }

    /* Have we received a frame on one of the ED connections?
     * No critical section -- it doesn't really matter much if we miss a poll
     */
    if (sPeerFrameSem)
    {
      uint8_t     msg[MAX_APP_PAYLOAD], len, i;

      /* process all frames waiting */
      for (i=0; i<sNumCurrentPeers; ++i)
      {
        if (SMPL_SUCCESS == SMPL_Receive(sLID[i], msg, &len))
        {
          processMessage(sLID[i], msg, len);

          BSP_ENTER_CRITICAL_SECTION(intState);
          sPeerFrameSem--;
          BSP_EXIT_CRITICAL_SECTION(intState);
        }
      }
    }
    if (BSP_BUTTON1())
    {
      SPIN_ABOUT_A_QUARTER_SECOND;  /* debounce */
      changeChannel();
    }
    else
    {
      checkChangeChannel();
    }
    BSP_ENTER_CRITICAL_SECTION(intState);
    if (sBlinky)
    {
      if (++sBlinky >= 0xF)
      {
        sBlinky = 1;
        toggleLED(1);
        toggleLED(2);
      }
    }
    BSP_EXIT_CRITICAL_SECTION(intState);
  }

}
Exemple #21
0
// *************************************************************************************************
// @fn          wbsl_RfIsr
// @brief       called when a packet has been received. In this function we check for RX Overflow and set the corresponding
//              flags to inform the application a packet is ready on the RxBuffer
// @param       none
// @return      none
// *************************************************************************************************
void wbsl_RfIsr(void)
{
    u8 rxBytes;
    u8 IncomingPacket[RX_BUFFER_SIZE]={0};


   /* We should only be here in RX mode, not in TX mode, nor if RX mode was turned on during CCA */
    if (wbsl_rxtxMode != WBSL_RX_MODE)
    {
        return;
    }

   /* ------------------------------------------------------------------
    *    Get RXBYTES
    *   -------------
    */

   /*
    *  Read the RXBYTES register from the radio.
    *  Bit description of RXBYTES register:
    *    bit 7     - RXFIFO_OVERFLOW, set if receive overflow occurred
    *    bits 6:0  - NUM_BYTES, number of bytes in receive FIFO
    *
    *  Due a chip bug, the RXBYTES register must read the same value twice
    *  in a row to guarantee an accurate value.
    */
    {
       uint8_t rxBytesVerify;

       rxBytes = wbsl_SpiReadReg( RXBYTES );

       do
       {
           rxBytes = rxBytesVerify;
           rxBytesVerify = wbsl_SpiReadReg( RXBYTES ); //NUM_RXBYTES
       }while (rxBytes != rxBytesVerify);

     }

     /* ------------------------------------------------------------------
      *    FIFO empty?
      *   -------------
      */

     /*
      *  See if the receive FIFIO is empty before attempting to read from it.
      *  It is possible nothing the FIFO is empty even though the interrupt fired.
      *  This can happen if address check is enabled and a non-matching packet is
      *  received.  In that case, the radio automatically removes the packet from
      *  the FIFO.
      */
      if (rxBytes == 0)
      {
          /* receive FIFO is empty - do nothing, skip to end */
      }
      else
      {
	      /* receive FIFO is not empty, continue processing */

	      /* ------------------------------------------------------------------
	       *    Process frame length
	       *   ----------------------
	       */
	      /* get packet from FIFO */
	      wbsl_SpiReadRxFifo(IncomingPacket, rxBytes);


	      /*
	       *  Make sure that the frame length just read corresponds to number of bytes in the buffer.
	       *  If these do not match up something is wrong.
	       *
	       *  This can happen for several reasons:
	       *   1) Incoming packet has an incorrect format or is corrupted.
	       *   2) The receive FIFO overflowed.  Overflow is indicated by the high
	       *      bit of rxBytes.  This guarantees the value of rxBytes value will not
	       *      match the number of bytes in the FIFO for overflow condition.
	       *   3) Interrupts were blocked for an abnormally long time which
	       *      allowed a following packet to at least start filling the
	       *      receive FIFO.  In this case, all received and partially received
	       *      packets will be lost - the packet in the FIFO and the packet coming in.
	       *      This is the price the user pays if they implement a giant
	       *      critical section.
	       *   4) A failed transmit forced radio to IDLE state to flush the transmit FIFO.
	       *      This could cause an active receive to be cut short.
	       *
	       *  Also check the sanity of the length to guard against rogue frames.
	       */
	      if ((rxBytes>WBSL_TOTAL_LENGTH + WBSL_RX_METRICS_SIZE) ||
	    		 (rxBytes != (IncomingPacket[WBSL_LENGTH_FIELD_OFS] + WBSL_LENGTH_FIELD_SIZE + WBSL_RX_METRICS_SIZE)))
	      {
	          bspIState_t s;

	          /* mismatch between bytes-in-FIFO and frame length */

	          /*
	           *  Flush receive FIFO to reset receive.  Must go to IDLE state to do this.
	           *  The critical section guarantees a transmit does not occur while cleaning up.
	           */
	           BSP_ENTER_CRITICAL_SECTION(s);
	           WBSL_STROBE_IDLE_AND_WAIT();
	           wbsl_SpiCmdStrobe( SFRX );
	           wbsl_SpiCmdStrobe( SRX );
	           BSP_EXIT_CRITICAL_SECTION(s);

	           /* flush complete, skip to end */
	      }
	      else
	      {
	          /* bytes-in-FIFO and frame length match up - continue processing */

	          /* ------------------------------------------------------------------
	           *    CRC check
	           *   ------------
	           */

	          /*
	           *  Note!  Automatic CRC check is not, and must not, be enabled.  This feature
	           *  flushes the *entire* receive FIFO when CRC fails.  If this feature is
	           *  enabled it is possible to be reading from the FIFO and have a second
	           *  receive occur that fails CRC and automatically flushes the receive FIFO.
	           *  This could cause reads from an empty receive FIFO which puts the radio
	           *  into an undefined state.
	           */

	           /* determine if CRC failed */
	    	   /* CRC Status is appended as the MSB of the 2nd byte of the status bytes */
	          if (!(IncomingPacket[IncomingPacket[WBSL_LENGTH_FIELD_OFS] + WBSL_CRC_STATUS_OFFSET] & CRC_STATUS))
	          {
	              /* CRC failed - do nothing, skip to end */

	          }
	          else
	          {
	              /* CRC passed - continue processing */
	              /* ------------------------------------------------------------------
	               *    Receive successful
	               *   --------------------
	               */

	    	       memcpy(RxBuffer, IncomingPacket, rxBytes);
	    	       rxtx_flag = WBSL_RXTX_RECEIVED;

	           }

	        }
	  }
   }
Exemple #22
0
/**************************************************************************************************
 * @fn          MRFI_Transmit
 *
 * @brief       Transmit a packet using CCA algorithm.
 *
 * @param       pPacket - pointer to packet to transmit
 *
 * @return      Return code indicates success or failure of transmit:
 *                  MRFI_TX_RESULT_SUCCESS - transmit succeeded
 *                  MRFI_TX_RESULT_FAILED  - transmit failed because CCA failed
 **************************************************************************************************
 */
uint8_t MRFI_Transmit(mrfiPacket_t * pPacket, uint8_t txType)
{
  static uint8_t dsn = 0;
  uint8_t txResult = MRFI_TX_RESULT_SUCCESS;

  /* radio must be awake to transmit */
  MRFI_ASSERT( mrfiRadioState != MRFI_RADIO_STATE_OFF );


  /* ------------------------------------------------------------------
   *    Initialize hardware for transmit
   *   -----------------------------------
   */

  /* turn off reciever */
  Mrfi_RxModeOff();

  /* clear 'transmit done' interrupt flag, this bit is tested to see when transmit completes */
  RFIRQF1 &= ~IRQ_TXDONE;


  /* ------------------------------------------------------------------
   *    Populate the IEEE fields in frame
   *   ------------------------------------
   */

  /* set the sequence number, also known as DSN (Data Sequence Number) */
  pPacket->frame[MRFI_DSN_OFFSET] = dsn;

  /* increment the sequence number, value is retained (static variable) for use in next transmit */
  dsn++;

  /*
   *  Populate the FCF (Frame Control Field) with the following settings.
   *
   *    bits    description                         setting
   *  --------------------------------------------------------------------------------------
   *      0-2   Frame Type                          001 - data frame
   *        3   Security Enabled                      0 - security disabled
   *        4   Frame Pending                         0 - no pending data
   *        5   Ack Request                           0 - no Ack request
   *        6   PAN ID Compression                    0 - no PAN ID compression
   *        7   Reserved                              0 - reserved
   *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   *      8-9   Reserved                             00 - reserved
   *    10-11   Destination Addressing Mode          10 - PAN ID + 16-bit short address
   *    12-13   Frame Version                        00 - IEEE Std 802.15.4-2003
   *    14-15   Source Addressing Mode               10 - PAN ID + 16-bit short address
   *
   */
  pPacket->frame[MRFI_FCF_OFFSET]   = MRFI_FCF_0_7;
  pPacket->frame[MRFI_FCF_OFFSET+1] = MRFI_FCF_8_15;


  /* ------------------------------------------------------------------
   *    Write packet to transmit FIFO
   *   --------------------------------
   */
  {
    uint8_t txBufLen;
    uint8_t * p;
    uint8_t i;

    /* flush FIFO of any previous transmit that did not go out */
    RFST = ISFLUSHTX;

    /* set point at beginning of outgoing frame */
    p = &pPacket->frame[MRFI_LENGTH_FIELD_OFFSET];

    /* get number of bytes in the packet (does not include the length byte) */
    txBufLen = *p;

    /*
     *  Write the length byte to the FIFO.  This length does *not* include the length field
     *  itself but does include the size of the FCS (generically known as RX metrics) which
     *  is generated automatically by the radio.
     */
    RFD = txBufLen + MRFI_RX_METRICS_SIZE;

    /* write packet bytes to FIFO */
    for (i=0; i<txBufLen; i++)
    {
      p++;
      RFD = *p;
    }
  }

  /* ------------------------------------------------------------------
   *    Immediate transmit
   *   ---------------------
   */
  if (txType == MRFI_TX_TYPE_FORCED)
  {
    /* strobe transmit */
    RFST = ISTXON;

    /* wait for transmit to complete */
    while (!(RFIRQF1 & IRQ_TXDONE));

    /* transmit is done */
  }
  else
  {
    /* ------------------------------------------------------------------
     *    CCA transmit
     *   ---------------
     */
    MRFI_ASSERT( txType == MRFI_TX_TYPE_CCA );

    {
      bspIState_t s;
      uint8_t txActive;
      uint8_t ccaRetries;

      /* set number of CCA retries */
      ccaRetries = MRFI_CCA_RETRIES;


      /* ===============================================================================
       *    CCA Algorithm Loop
       *   ====================
       */
      for (;;)
      {
        /* Turn ON the receiver to perform CCA. Can not call Mrfi_RxModeOn(),
         * since that will enable the rx interrupt, which we do not want.
         */
        RFST = ISRXON;

        /*
         *  Wait for CCA to be valid.
         */
        MRFI_RSSI_VALID_WAIT();

        /*
         *  Initiate transmit with CCA.  Command is strobed and then status is
         *  immediately checked.  If status shows transmit is active, this means
         *  that CCA passed and the transmit has gone out.  A critical section
         *  guarantees timing status check happens immediately after strobe.
         */
        BSP_ENTER_CRITICAL_SECTION(s);
        RFST = ISTXONCCA;
        txActive = FSMSTAT1 & SAMPLED_CCA;
        BSP_EXIT_CRITICAL_SECTION(s);

        /* see transmit went out */
        if (txActive)
        {
          /* ----------|  CCA Passed |---------- */

          /* wait for transmit to complete */
          while (!(RFIRQF1 & IRQ_TXDONE));

          /* transmit is done. break out of CCA algorithm loop */
          break;
        }
        else
        {
          /* ----------|  CCA Failed |---------- */

          /* if no CCA retries are left, transmit failed so abort */
          if (ccaRetries == 0)
          {
            /* set return value for failed transmit */
            txResult = MRFI_TX_RESULT_FAILED;

            /* break out of CCA algorithm loop */
            break;
          }

          /* decrement CCA retries before loop continues */
          ccaRetries--;

          /* turn off reciever to conserve power during backoff */
          Mrfi_RxModeOff();

          /* delay for a random number of backoffs */
          Mrfi_RandomBackoffDelay();
        }
      }
      /*
       *  ---  end CCA Algorithm Loop ---
       * =============================================================================== */
    }
  }


  /* turn radio back off to put it in a known state */
  Mrfi_RxModeOff();

  /* If the radio was in RX state when transmit was attempted,
   * put it back in RX state.
   */
  if(mrfiRadioState == MRFI_RADIO_STATE_RX)
  {
    Mrfi_RxModeOn();
  }

  /* return the result of the transmit */
  return( txResult );
}
void main (void)
{
  addr_t lAddr;
  bspIState_t intState;
  char *Flash_Addr;                         // Initialize radio address location
  Flash_Addr = (char *)0x10F0;

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  // delay loop to ensure proper startup before SimpliciTI increases DCO
  // This is typically tailored to the power supply used, and in this case
  // is overkill for safety due to wide distribution.
  __delay_cycles(65000);

  if( CALBC1_8MHZ == 0xFF && CALDCO_8MHZ == 0xFF )// Do not run if cal values
  {
    P1DIR |= 0x03;
    BSP_TURN_ON_LED1();
    BSP_TURN_OFF_LED2();
    while(1)
    {
      __delay_cycles(65000);
      BSP_TOGGLE_LED2();
      BSP_TOGGLE_LED1();
    }
  }

  BSP_Init();

  if( Flash_Addr[0] == 0xFF &&
      Flash_Addr[1] == 0xFF &&
      Flash_Addr[2] == 0xFF &&
      Flash_Addr[3] == 0xFF )
    {
      createRandomAddress();                // Create Random device address at
    }                                       // initial startup if missing
  lAddr.addr[0]=Flash_Addr[0];
  lAddr.addr[1]=Flash_Addr[1];
  lAddr.addr[2]=Flash_Addr[2];
  lAddr.addr[3]=Flash_Addr[3];

  //SMPL_Init();
  SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &lAddr);

  MCU_Init();
  //Transmit splash screen and network init notification
  TXString( (char*)splash, sizeof splash);
  TXString( "\r\nInitializing Network....", 26 );

  SMPL_Init(sCB);

  // network initialized
  TXString( "Done\r\n", 6);

  // main work loop
  while(1)
  {
    // Wait for the Join semaphore to be set by the receipt of a Join frame from a
    // device that supports and End Device.

    if (sJoinSem && (sNumCurrentPeers < NUM_CONNECTIONS))
    {
      // listen for a new connection
      SMPL_LinkListen(&sLID[sNumCurrentPeers]);
      sNumCurrentPeers++;
      BSP_ENTER_CRITICAL_SECTION(intState);
      if (sJoinSem)
      {
        sJoinSem--;
      }
      BSP_EXIT_CRITICAL_SECTION(intState);
    }

    // if it is time to measure our own temperature...
    if(sSelfMeasureSem)
    {
//    	TXString("\r\n...", 5);
      BSP_TOGGLE_LED1();
      sSelfMeasureSem = 0;
    }

    // Have we received a frame on one of the ED connections?
    // No critical section -- it doesn't really matter much if we miss a poll
    if (sPeerFrameSem)
    {
    	  uint8_t  msg[MESSAGE_LENGTH], len, i;

      // process all frames waiting
      for (i=0; i<sNumCurrentPeers; ++i)
      {
        if (SMPL_Receive(sLID[i], msg, &len) == SMPL_SUCCESS)
        {
          ioctlRadioSiginfo_t sigInfo;
          sigInfo.lid = sLID[i];
          SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SIGINFO, (void *)&sigInfo);
          transmitData( i, (signed char)sigInfo.sigInfo.rssi, (char*)msg );
          BSP_TURN_ON_LED2();               // Toggle LED2 when received packet
          BSP_ENTER_CRITICAL_SECTION(intState);
          sPeerFrameSem--;
          BSP_EXIT_CRITICAL_SECTION(intState);
          __delay_cycles(10000);
          BSP_TURN_OFF_LED2();
        }
      }
    }
  }
}
//*****************************************************************************
//
// Main application entry function.
//
//*****************************************************************************
int
main(void)
{
    tBoolean bRetcode;
    bspIState_t intState;
    uint8_t ucLastChannel;

    //
    // Set the system clock to run at 50MHz from the PLL
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    //
    // NB: We don't call PinoutSet() in this testcase since the EM header
    // expansion board doesn't currently have an I2C ID EEPROM.  If we did
    // call PinoutSet() this would configure all the EPI pins for SDRAM and
    // we don't want to do this.
    //
    g_eDaughterType = DAUGHTER_NONE;

    //
    // Enable peripherals required to drive the LCD.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);

    //
    // Configure SysTick for a 10Hz interrupt.
    //
    ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / TICKS_PER_SECOND);
    ROM_SysTickEnable();
    ROM_SysTickIntEnable();

    //
    // Initialize the display driver.
    //
    Kitronix320x240x16_SSD2119Init();

    //
    // Initialize the touch screen driver.
    //
    TouchScreenInit();

    //
    // Set the touch screen event handler.
    //
    TouchScreenCallbackSet(WidgetPointerMessage);

    //
    // Add the compile-time defined widgets to the widget tree.
    //
    WidgetAdd(WIDGET_ROOT, (tWidget *)&g_sHeading);

    //
    // Initialize the status string.
    //
    UpdateStatus(true, "Initializing...");

    //
    // Paint the widget tree to make sure they all appear on the display.
    //
    WidgetPaint(WIDGET_ROOT);

    //
    // Initialize the SimpliciTI BSP.
    //
    BSP_Init();

    //
    // Set the SimpliciTI device address using the current Ethernet MAC address
    // to ensure something like uniqueness.
    //
    bRetcode = SetSimpliciTIAddress();

    //
    // Did we have a problem with the address?
    //
    if(!bRetcode)
    {
        //
        // Yes - make sure the display is updated then hang the app.
        //
        WidgetMessageQueueProcess();
        while(1)
        {
            //
            // MAC address is not set so hang the app.
            //
        }
    }

    //
    // Turn on both our LEDs
    //
    SetLED(1, true);
    SetLED(2, true);

    UpdateStatus(true, "Waiting for a device...");

    //
    // Initialize the SimpliciTI stack and register our receive callback.
    //
    SMPL_Init(ReceiveCallback);

    //
    // Tell the user what's up.
    //
    UpdateStatus(true, "Access point active.");

    //
    // Do nothing after this - the SimpliciTI stack code handles all the
    // access point function required.
    //
    while(1)
    {
        //
        // Wait for the Join semaphore to be set by the receipt of a Join
        // frame from a device that supports an end device.
        //
        // An external method could be used as well. A button press could be
        // connected to an ISR and the ISR could set a semaphore that is
        // checked by a function call here, or a command shell running in
        // support of a serial connection could set a semaphore that is
        // checked by a function call.
        //
        if (g_ucJoinSem && (g_ucNumCurrentPeers < NUM_CONNECTIONS))
        {
            //
            // Listen for a new incoming connection.
            //
            while (1)
            {
                if (SMPL_SUCCESS == SMPL_LinkListen(&g_sLID[g_ucNumCurrentPeers]))
                {
                    //
                    // The connection attempt succeeded so break out of the
                    // loop.
                    //
                    break;
                }

                //
                // Process our widget message queue.
                //
                WidgetMessageQueueProcess();

                //
                // A "real" application would implement its fail-to-link
                // policy here.  We go back and listen again.
                //
            }

            //
            // Increment our peer counter.
            //
            g_ucNumCurrentPeers++;

            //
            // Decrement the join semaphore.
            //
            BSP_ENTER_CRITICAL_SECTION(intState);
            g_ucJoinSem--;
            BSP_EXIT_CRITICAL_SECTION(intState);

            //
            // Tell the user how many devices we are now connected to.
            //
            UpdateStatus(false, "%d devices connected.", g_ucNumCurrentPeers);
        }

        //
        // Have we received a frame on one of the ED connections? We don't use
        // a critical section here since it doesn't really matter much if we
        // miss a poll.
        //
        if (g_ucPeerFrameSem)
        {
            uint8_t     pucMsg[MAX_APP_PAYLOAD], ucLen, ucLoop;

            /* process all frames waiting */
            for (ucLoop = 0; ucLoop < g_ucNumCurrentPeers; ucLoop++)
            {
                //
                // Receive the message.
                //
                if (SMPL_SUCCESS == SMPL_Receive(g_sLID[ucLoop], pucMsg,
                                                 &ucLen))
                {
                    //
                    // ...and pass it to the function that processes it.
                    //
                    ProcessMessage(g_sLID[ucLoop], pucMsg, ucLen);

                    //
                    // Decrement our frame semaphore.
                    //
                    BSP_ENTER_CRITICAL_SECTION(intState);
                    g_ucPeerFrameSem--;
                    BSP_EXIT_CRITICAL_SECTION(intState);
                }
            }
        }

        //
        // Have we been asked to change channel?
        //
        ucLastChannel = g_ucChannel;
        if (g_bChangeChannel)
        {
            //
            // Yes - go ahead and change to the next radio channel.
            //
            g_bChangeChannel = false;
            ChangeChannel();
        }
        else
        {
            //
            // No - check to see if we need to automatically change channel
            // due to interference on the current one.
            //
            CheckChangeChannel();
        }

        //
        // If the channel changed, update the display.
        //
        if(g_ucChannel != ucLastChannel)
        {
            UpdateStatus(false, "Changed to channel %d.", g_ucChannel);
        }

        //
        // If required, blink the "LEDs" to indicate we are waiting for a
        // message following a channel change.
        //
        BSP_ENTER_CRITICAL_SECTION(intState);
        if (g_ulBlinky)
        {
            if (++g_ulBlinky >= 0xF)
            {
                g_ulBlinky = 1;
                ToggleLED(1);
                ToggleLED(2);
            }
        }
        BSP_EXIT_CRITICAL_SECTION(intState);

        //
        // Process our widget message queue.
        //
        WidgetMessageQueueProcess();
    }
}
Exemple #25
0
static void linkTo()
{
  uint8_t     msg[2];
  uint8_t     button, misses, done;

  /* Keep trying to link... */
  while (SMPL_SUCCESS != SMPL_Link(&sLinkID1))
  {
    toggleLED(1);
    toggleLED(2);
    SPIN_ABOUT_A_SECOND;
  }

  /* Turn off LEDs. */
  if (BSP_LED2_IS_ON())
  {
    toggleLED(2);
  }
  if (BSP_LED1_IS_ON())
  {
    toggleLED(1);
  }

  /* sleep until button press... */
  SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SLEEP, 0);

  while (1)
  {
    button = 0;
    /* Send a message when either button pressed */
    if (BSP_BUTTON1())
    {
      SPIN_ABOUT_A_QUARTER_SECOND;  /* debounce... */
      /* Message to toggle LED 1. */
      button = 1;
    }
    else if (BSP_BUTTON2())
    {
      SPIN_ABOUT_A_QUARTER_SECOND;  /* debounce... */
      /* Message to toggle LED 2. */
      button = 2;
    }
    if (button)
    {
      /* get radio ready...awakens in idle state */
      SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE, 0);

      /* Set TID and designate which LED to toggle */
      msg[1] = ++sTid;
      msg[0] = (button == 1) ? 1 : 2;
      done = 0;
      while (!done)
      {
        for (misses=0; misses < MISSES_IN_A_ROW; ++misses)
        {
          if (SMPL_SUCCESS == SMPL_Send(sLinkID1, msg, sizeof(msg)))
          {
#if defined( FREQUENCY_AGILITY )
            /* If macro is defined we're supporting Frequency Agility. In this case
             * the peer will acknowledge the message sent. It is the only way we can
             * tell if we are on the right channel. Wait for ack.
             */
            {
              bspIState_t intState;

              SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);
              NWK_REPLY_DELAY();
              SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXIDLE, 0);

              if (!sPeerFrameSem)
              {
                /* Try again if we havn't received anything. */
                continue;
              }
              else
              {
                uint8_t len;

                BSP_ENTER_CRITICAL_SECTION(intState);
                sPeerFrameSem--;
                BSP_EXIT_CRITICAL_SECTION(intState);

                /* We got something. Go get it. */
                SMPL_Receive(sLinkID1, msg, &len);
                if (len && (*msg & NWK_APP_REPLY_BIT))
                {
                  toggleLED(*msg & ~NWK_APP_REPLY_BIT);
                  break;
                }
              }
            }
#else
            /* Not supporting Frequency agility. Just break out since there
             * will be no ack.
             */
            break;
#endif
          }
        }
        if (misses == MISSES_IN_A_ROW)
        {
          /* This can only happen if we are supporting Frequency Agility and we
           * appear not to have received an acknowledge. Do a scan.
           */
          ioctlScanChan_t scan;
          freqEntry_t     freq[NWK_FREQ_TBL_SIZE];

          scan.freq = freq;
          SMPL_Ioctl(IOCTL_OBJ_FREQ, IOCTL_ACT_SCAN, &scan);
          /* If we now know the channel (number == 1) change to it. In any case
           * try it all again. If we changed channels we should get an ack now.
           */
          if (1 == scan.numChan)
          {
            SMPL_Ioctl(IOCTL_OBJ_FREQ, IOCTL_ACT_SET, freq);
          }
        }
        else
        {
          /* Got the ack. We're done. */
          done = 1;
        }
      }

      /* radio back to sleep */
      SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SLEEP, 0);
    }
  }
}
Exemple #26
0
/******************************************************************************
 * @fn          nwk_QfindOldest
 *
 * @brief       Look through frame queue and find the oldest available frame
 *              in the context in question. Supports connection-based (user),
 *              non-connection based (NWK applications), and the special case
 *              of store-and-forward.
 *
 * input parameters
 * @param   which      - INQ or OUTQ to adjust
 * @param   rcvContext - context information for finding the oldest
 * @param   usage      - normal usage or store-and-forward usage
 *
 * output parameters
 *
 * @return      Pointer to frame that is the oldsest on the requested port, or
 *              0 if there are none.
 */
frameInfo_t *nwk_QfindOldest(uint8_t which, rcvContext_t *rcv, uint8_t fi_usage)
{
  uint8_t      i, oldest, num, port;
  uint8_t      uType, addr12Compare;
  bspIState_t  intState;
  frameInfo_t *fPtr = 0, *wPtr;
  connInfo_t  *pCInfo = 0;
  uint8_t     *pAddr1, *pAddr2, *pAddr3 = 0;

  if (INQ == which)
  {
    wPtr   = sInFrameQ;
    num    = SIZE_INFRAME_Q;
    oldest = SIZE_INFRAME_Q+1;
  }
  else
  {
/*    pFI  = sOutFrameQ; */
/*    num  = SIZE_OUTFRAME_Q; */
    return 0;
  }

  if (RCV_APP_LID == rcv->type)
  {
    pCInfo = nwk_getConnInfo(rcv->t.lid);
    if (!pCInfo)
    {
      return (frameInfo_t *)0;
    }
    port   = pCInfo->portRx;
    pAddr2 = pCInfo->peerAddr;
  }
  else if (RCV_NWK_PORT == rcv->type)
  {
    port = rcv->t.port;
  }
#ifdef ACCESS_POINT
  else if (RCV_RAW_POLL_FRAME == rcv->type)
  {
    port   = *(MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_PORT_OS);
    pAddr2 = MRFI_P_SRC_ADDR(rcv->t.pkt);
    pAddr3 = MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_ADDR_OS;
  }
#endif
  else
  {
    return (frameInfo_t *)0;
  }

  uType = (USAGE_NORMAL == fi_usage) ? FI_INUSE_UNTIL_DEL : FI_INUSE_UNTIL_FWD;

  for (i=0; i<num; ++i, ++wPtr)
  {

    BSP_ENTER_CRITICAL_SECTION(intState);   /* protect the frame states */

    /* only check entries in use and waiting for this port */
    if (uType == wPtr->fi_usage)
    {
      wPtr->fi_usage = FI_INUSE_TRANSITION;

      BSP_EXIT_CRITICAL_SECTION(intState);  /* release hold */
      /* message sent to this device? */
      if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&wPtr->mrfiPkt), F_PORT_OS) == port)
      {
        /* Port matches. If the port of interest is a NWK applicaiton we're a
         * match...the NWK applications are not connection-based. If it is a
         * NWK application we need to check the source address for disambiguation.
         * Also need to check source address if it's a raw frame lookup (S&F frame)
         */
        if (RCV_APP_LID == rcv->type)
        {
          if (SMPL_PORT_USER_BCAST == port)
          {
            /* guarantee a match... */
            pAddr1 = pCInfo->peerAddr;
          }
          else
          {
            pAddr1 = MRFI_P_SRC_ADDR(&wPtr->mrfiPkt);
          }
        }
#ifdef ACCESS_POINT
        else if (RCV_RAW_POLL_FRAME == rcv->type)
        {
          pAddr1 = MRFI_P_DST_ADDR(&wPtr->mrfiPkt);
        }
#endif

        addr12Compare = memcmp(pAddr1, pAddr2, NET_ADDR_SIZE);
        if (  (RCV_NWK_PORT == rcv->type) ||
              (!pAddr3 && !addr12Compare) ||
              (pAddr3 && !memcmp(pAddr3, MRFI_P_SRC_ADDR(&wPtr->mrfiPkt), NET_ADDR_SIZE))
           )
        {
          if (wPtr->orderStamp < oldest)
          {
            if (fPtr)
            {
              /* restore previous oldest one */
              fPtr->fi_usage = uType;
            }
            oldest = wPtr->orderStamp;
            fPtr   = wPtr;
            continue;
          }
          else
          {
            /* not oldest. restore state */
            wPtr->fi_usage = uType;
          }
        }
        else
        {
          /* not a match. restore state */
          wPtr->fi_usage = uType;
        }
      }
      else
      {
        /* wrong port. restore state */
        wPtr->fi_usage = uType;
      }
    }
    else
    {
      BSP_EXIT_CRITICAL_SECTION(intState);
    }
  }

  return fPtr;
}
// AP main routine
void simpliciti_main(void)
{
  bspIState_t intState;
  uint8_t j;
  uint8_t len;
  uint32_t led_toggle = 0;
  uint8_t   pwr;

  // Init variables  
  simpliciti_flag = SIMPLICITI_STATUS_LINKING;

  // Init SimpliciTI
  SMPL_Init(sCB);
  
  // Set output power to +1.1dBm (868MHz) / +1.3dBm (915MHz)
  pwr = IOCTL_LEVEL_2;
  SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SETPWR, &pwr);
  
   // LED off
  BSP_TURN_OFF_LED1();
    
  /* main work loop */
  while (1)
  {
    // Wait for the Join semaphore to be set by the receipt of a Join frame from a
    //device that supports an End Device.
    if (sJoinSem && !sNumCurrentPeers)
    {
      /* listen for a new connection */
      while (1)
      {
        if (SMPL_SUCCESS == SMPL_LinkListen(&linkID0))
        {
          // We have a connection
          simpliciti_flag = SIMPLICITI_STATUS_LINKED;
          BSP_TURN_ON_LED1();
          break;
        }
        /* Implement fail-to-link policy here. otherwise, listen again. */
      }

      sNumCurrentPeers++;

      BSP_ENTER_CRITICAL_SECTION(intState);
      sJoinSem--;
      BSP_EXIT_CRITICAL_SECTION(intState);
    }

    /* Have we received a frame on one of the ED connections?
     * No critical section -- it doesn't really matter much if we miss a poll
     */
    if (sPeerFrameSem)
    {
      // Continuously try to receive end device packets
      if (SMPL_SUCCESS == SMPL_Receive(linkID0, ed_data, &len))
      {
        // Acceleration / ppt data packets are 4 byte long
        if (len == 4)
        {
          BSP_TOGGLE_LED1();
          memcpy(simpliciti_data, ed_data, 4);
          setFlag(simpliciti_flag, SIMPLICITI_TRIGGER_RECEIVED_DATA);

#ifdef EMBEDDED_UART        
          uart_analyze_packet(simpliciti_data[0],simpliciti_data[1],simpliciti_data[2],simpliciti_data[3]);
#endif              
        }        
        // Sync packets are either R2R (2 byte) or data (19 byte) long
        else if ((len == 2) || (len == 19))
        {
          // Indicate received packet
          BSP_TOGGLE_LED1();

          // Decode end device packet
          switch (ed_data[0])
          {
              case SYNC_ED_TYPE_R2R: 
                                    // Send reply
                                    if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_SEND_CMD))
                                    {
                                      // Clear flag
                                      clearFlag(simpliciti_flag, SIMPLICITI_TRIGGER_SEND_CMD);
                                      // Command data was set by USB buffer previously
                                      len = BM_SYNC_DATA_LENGTH;
                                    }
                                    else // No command currently available
                                    {
                                      simpliciti_data[0] = SYNC_AP_CMD_NOP;
                                      simpliciti_data[1] = 0x55;
                                      len = 2;
                                    }
                
                                    // Send reply packet to end device
                                    SMPL_Send(linkID0, simpliciti_data, len);
                                    break;
                                 
            case SYNC_ED_TYPE_MEMORY: 
            case SYNC_ED_TYPE_STATUS:
                                    // If buffer is empty, copy received end device data to intermediate buffer
                                    if (!simpliciti_sync_buffer_status)
                                    {
                                      for (j=0; j<BM_SYNC_DATA_LENGTH; j++) simpliciti_data[j] = ed_data[j];
                                      simpliciti_sync_buffer_status = 1;
                                    }
                                    // Set buffer status to full
                                    break;

          }
        }
      }
    }
    
    // Exit function if SIMPLICITI_TRIGGER_STOP flag bit is set in USB driver    
    if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_STOP)) 
    {
      // Immediately turn off RF interrupt
      IEN2 &= ~BIT0;
      RFIM = 0;
      RFIF = 0;
      // Clean up after SimpliciTI and enable restarting the stack
      linkID0 = 0;
      sNumCurrentPeers = 0;
      sJoinSem = 0;
      sPeerFrameSem = 0;
      sInit_done = 0;
      // LED off
      BSP_TURN_OFF_LED1();
      return;
    }
    
    // Blink slowly to indicate that access point is on
    if (!sNumCurrentPeers)
    {
      if (led_toggle++>150000)
      {
        BSP_TOGGLE_LED1();
        led_toggle = 0;
      }
    }
  }
}
Exemple #28
0
/*****************************************************************************
  Function:
	static void GetTickCopy(void)

  Summary:
	Reads the tick value.

  Description:
	This function performs an interrupt-safe and synchronized read of the 
	48-bit Tick value.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	None
  ***************************************************************************/
static void GetTickCopy(void)
{
	// Perform an Interrupt safe and synchronized read of the 48-bit 
	// tick value
#if defined(__18CXX)
	do
	{
		INTCONbits.TMR0IE = 1;		// Enable interrupt
		Nop();
		INTCONbits.TMR0IE = 0;		// Disable interrupt
		vTickReading[0] = TMR0L;
		vTickReading[1] = TMR0H;
		*((DWORD*)&vTickReading[2]) = dwInternalTicks;
	} while(INTCONbits.TMR0IF);
	INTCONbits.TMR0IE = 1;			// Enable interrupt
#elif defined(__C30__)
	do
	{
		DWORD dwTempTicks;
		
		IEC0bits.T1IE = 1;			// Enable interrupt
		Nop();
		IEC0bits.T1IE = 0;			// Disable interrupt

		// Get low 2 bytes
		((WORD*)vTickReading)[0] = TMR1;
		
		// Correct corner case where interrupt increments byte[4+] but 
		// TMR1 hasn't rolled over to 0x0000 yet
		dwTempTicks = dwInternalTicks;
		if(((WORD*)vTickReading)[0] == 0xFFFFu)
			dwTempTicks--;
		
		// Get high 4 bytes
		vTickReading[2] = ((BYTE*)&dwTempTicks)[0];
		vTickReading[3] = ((BYTE*)&dwTempTicks)[1];
		vTickReading[4] = ((BYTE*)&dwTempTicks)[2];
		vTickReading[5] = ((BYTE*)&dwTempTicks)[3];
	} while(IFS0bits.T1IF);
	IEC0bits.T1IE = 1;				// Enable interrupt

#elif defined(__STM32F10X__)

	DWORD dwTempTicks;

	BSP_ENTER_CRITICAL_SECTION();
	dwTempTicks = dwInternalTicks;
	*((DWORD*)&vTickReading[0]) = ((SysTick->VAL & 0xFFFFFF) >> 8) ^ 0xFFFF;
	BSP_EXIT_CRITICAL_SECTION();
	*((DWORD*)&vTickReading[2]) = dwTempTicks;

#else	// PIC32
	do
	{
		DWORD dwTempTicks;
		
		IEC0SET = _IEC0_T1IE_MASK;	// Enable interrupt
		Nop();
		IEC0CLR = _IEC0_T1IE_MASK;	// Disable interrupt
		
		// Get low 2 bytes
		((volatile WORD*)vTickReading)[0] = TMR1;

		// Correct corner case where interrupt increments byte[4+] but 
		// TMR1 hasn't rolled over to 0x0000 yet
		dwTempTicks = dwInternalTicks;

		// PIC32MX3XX/4XX devices trigger the timer interrupt when TMR1 == PR1 
		// (TMR1 prescalar is 0x00), requiring us to undo the ISR's increment 
		// of the upper 32 bits of our 48 bit timer in the special case when 
		// TMR1 == PR1 == 0xFFFF.  For other PIC32 families, the ISR is 
		// triggered when TMR1 increments from PR1 to 0x0000, making no special 
		// corner case.
		#if __PIC32_FEATURE_SET__ <= 460
			if(((WORD*)vTickReading)[0] == 0xFFFFu)
				dwTempTicks--;
		#elif !defined(__PIC32_FEATURE_SET__)
			#error __PIC32_FEATURE_SET__ macro must be defined.  You need to download a newer C32 compiler version.
		#endif
		
		// Get high 4 bytes
		vTickReading[2] = ((BYTE*)&dwTempTicks)[0];
		vTickReading[3] = ((BYTE*)&dwTempTicks)[1];
		vTickReading[4] = ((BYTE*)&dwTempTicks)[2];
		vTickReading[5] = ((BYTE*)&dwTempTicks)[3];
	} while(IFS0bits.T1IF);
	IEC0SET = _IEC0_T1IE_MASK;		// Enable interrupt
#endif
}
Exemple #29
0
/**************************************************************************************************
 * @fn          MRFI_Transmit
 *
 * @brief       Transmit a packet using CCA algorithm.
 *
 * @param       pPacket - pointer to packet to transmit
 *
 * @return      Return code indicates success or failure of transmit:
 *                  MRFI_TRANSMIT_SUCCESS - transmit succeeded
 *                  MRFI_TRANSMIT_CCA_FAILED - transmit failed because of CCA check(s)
 *                  MRFI_TRANSMIT_RADIO_ASLEEP - transmit failed because radio was asleep
 **************************************************************************************************
 */
uint8_t MRFI_Transmit(mrfiPacket_t * pPacket)
{
  uint8_t ccaRetries;
  uint8_t txBufLen;
  uint8_t savedSyncIntState;
  uint8_t returnValue;

  /* abort transmit if radio is asleep */
  {
    bspIState_t s;

    /* critical section necessary for watertight testing and setting of state variables */
    BSP_ENTER_CRITICAL_SECTION(s);

    /* if radio is asleep, abort transmit and return reason for failure */
    if (mrfiRadioIsSleeping)
    {
      BSP_EXIT_CRITICAL_SECTION(s);
      return( MRFI_TRANSMIT_RADIO_ASLEEP );
    }
    
    /* radio is not asleep, set flag that indicates transmit is active */
    mrfiTxActive = 1;
    BSP_EXIT_CRITICAL_SECTION(s);
  }
  
  /* set number of CCA retries */
  ccaRetries = MRFI_CCA_RETRIES;
  
  /* compute number of bytes to write to transmit FIFO */
  txBufLen = pPacket->frame[MRFI_LENGTH_FIELD_OFS] + MRFI_LENGTH_FIELD_SIZE;
  
  /* write packet to transmit FIFO */
  mrfiSpiWriteTxFifo(&(pPacket->frame[0]), txBufLen);
  
  /* ===============================================================================
   *    Main Loop 
   *  =============
   */
  for (;;)
  {
    /* CCA delay */
    MRFI_DELAY(2000);

    /* disable sync pin interrupts, necessary because both transmit and receive affect sync signal */
    MRFI_DISABLE_SYNC_PIN_INT();

    /* store the sync pin interrupt flag, important so original state can be restored */
    savedSyncIntState = MRFI_SYNC_PIN_INT_FLAG_IS_SET();
      
    /*
     *  Clear the PA_PD pin interrupt flag.  This flag, not the interrupt itself,
     *  is used to capture the transition that indicates a transmit was started.
     *  The pin level cannot be used to indicate transmit success as timing may
     *  prevent the transition from being detected.  The interrupt latch captures
     *  the event regardless of timing.
     */
    MRFI_CLEAR_PAPD_PIN_INT_FLAG();
    
    /* send strobe to initiate transmit */
    mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_STX);
    
    /*  delay long enough for the PA_PD signal to indicate a successful transmit */
    MRFI_DELAY(250);

    /* if the interrupt flag of the PA_PD pin is set, CCA passed and the transmit has started */
    if (MRFI_PAPD_INT_FLAG_IS_SET())
    {
      /* ------------------------------------------------------------------
       *    Clear Channel Assessment passed.
       *   ----------------------------------
       */

      /* wait for transmit to complete */
      while (!MRFI_PAPD_PIN_IS_HIGH());

      /*
       *  Restore the original sync interrupt state.  The successful transmit just
       *  caused a transition on the sync signal that set the flag (if not already
       *  set).  To restore the original state, the flag is simply cleared if it
       *  was clear earlier.
       */
      if (!savedSyncIntState)
      {
        MRFI_CLEAR_SYNC_PIN_INT_FLAG();
      }
      
      /* transmit complete, enable sync pin interrupts */
      MRFI_ENABLE_SYNC_PIN_INT();

      /* set return value for successful transmit and break */      
      returnValue = MRFI_TRANSMIT_SUCCESS;
      break;
    }

    /* ------------------------------------------------------------------
     *    Clear Channel Assessment failed.
     *   ----------------------------------
     */
    
    /* CCA failed, safe to enable sync pin interrupts */
    MRFI_ENABLE_SYNC_PIN_INT();

    /* if no CCA retries are left, transmit failed so abort */    
    if (ccaRetries == 0)
    {
      bspIState_t s;

      /*
       *  Flush the transmit FIFO.  It must be flushed so that
       *  the next transmit can start with a clean slate.
       *  Critical section prevents receive interrupt from
       *  occurring in the middle of clean-up.
       */
      BSP_ENTER_CRITICAL_SECTION(s);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SIDLE);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SFTX);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SRX);
      BSP_EXIT_CRITICAL_SECTION(s);

      /* set return value for failed transmit and break */      
      returnValue = MRFI_TRANSMIT_CCA_FAILED;
      break;
    }

    /* decrement CCA retries before loop continues */
    ccaRetries--;
  }
  /*
   * =============================================================================== */

  mrfiTxActive = 0;
  return( returnValue );
}