/************************************************************************************************** * @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 ); } } }
/****************************************************************************** * @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; }
// 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; }
/**************************************************************************************************** * @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--); } }
/* 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 } }
/************************************************************************************************** * @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); }
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; }
/**************************************************************************************************** * @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; }
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; }
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 }
/****************************************************************************** * @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 */ }
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 }
/**************************************************************************************************** * @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; }
// 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; }
/****************************************************************************** * @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 */ }
/************************************************************************************************** * @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; }
/****************************************************************************** * @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); } }
// ************************************************************************************************* // @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; } } } }
/************************************************************************************************** * @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(); } }
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); } } }
/****************************************************************************** * @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; } } } }
/***************************************************************************** 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 }
/************************************************************************************************** * @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 ); }