/************************************************************************************************** * @fn MRFI_SetLogicalChannel * * @brief Set logical channel. * * @param chan - logical channel number * * @return none ************************************************************************************************** */ void MRFI_SetLogicalChannel(uint8_t chan) { uint8_t phyChannel; /* logical channel is not valid */ MRFI_ASSERT( chan < MRFI_NUM_LOGICAL_CHANS ); /* make sure radio is off before changing channels */ Mrfi_RxModeOff(); /* convert logical channel number into physical channel number */ phyChannel = mrfiLogicalChanTable[chan]; /* write frequency value of new channel */ mrfiSpiWriteReg(FREQCTRL, (FREQCTRL_BASE_VALUE + (FREQCTRL_FREQ_2405MHZ + 5 * ((phyChannel) - 11)))); /* remember this. need it when waking up. */ mrfiCurrentLogicalChannel = chan; /* Put the radio back in RX state, if it was in RX before channel change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_RxOn * * @brief Turn on the receiver. No harm is done if this function * is called when receiver is already on. * * @param none * * @return none ************************************************************************************************** */ void MRFI_RxOn(void) { /* radio must be powered ON before we can move it to RX state */ MRFI_ASSERT( mrfiRadioState != MRFI_RADIO_STATE_OFF ); /* Put the radio in RX state, if not already */ if(mrfiRadioState != MRFI_RADIO_STATE_RX) { mrfiRadioState = MRFI_RADIO_STATE_RX; Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetRFPwr * * @brief Set RF output power. * * @param level - Power level * * @return none ************************************************************************************************** */ void MRFI_SetRFPwr(uint8_t level) { /* make sure radio is off before changing power level */ Mrfi_RxModeOff(); TXPOWER = mrfiRFPowerTable[level]; /* Put the radio back in RX state, if it was in RX before channel change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetLogicalChannel * * @brief Set logical channel. * * @param chan - logical channel number * * @return none ************************************************************************************************** */ void MRFI_SetLogicalChannel(uint8_t chan) { /* logical channel is not valid? */ MRFI_ASSERT( chan < MRFI_NUM_LOGICAL_CHANS ); /* make sure radio is off before changing channels */ Mrfi_RxModeOff(); MRFI_WRITE_REGISTER( CHANNR, mrfiLogicalChanTable[chan] ); /* turn radio back on if it was on before channel change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetRFPwr * * @brief Set RF Output power level. * * @param idx - index into power table. * * @return none ************************************************************************************************** */ void MRFI_SetRFPwr(uint8_t idx) { /* is power level specified valid? */ MRFI_ASSERT( idx < MRFI_NUM_POWER_SETTINGS ); /* make sure radio is off before changing power levels */ Mrfi_RxModeOff(); MRFI_WRITE_REGISTER( PA_TABLE0, mrfiRFPowerTable[idx] ); /* turn radio back on if it was on before power level change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetRFPwr * * @brief Set RF pwoer level. * * @param idx - index into power level table * * @return none ************************************************************************************************** */ void MRFI_SetRFPwr(uint8_t idx) { /* is power level specified valid? */ MRFI_ASSERT( idx < MRFI_NUM_POWER_SETTINGS ); /* make sure radio is off before changing power levels */ Mrfi_RxModeOff(); /* write value of new power level */ TXCTRLL = mrfiRFPowerTable[idx]; /* Put the radio back in RX state, if it was in RX before change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetRFPwr * * @brief Set RF power level. * * @param idx - index into power level table * * @return none ************************************************************************************************** */ void MRFI_SetRFPwr(uint8_t idx) { /* is power level specified valid? */ MRFI_ASSERT( idx < MRFI_NUM_POWER_SETTINGS ); /* make sure radio is off before changing power level */ Mrfi_RxModeOff(); /* write value of new power level */ mrfiSpiWriteReg(TXPOWER, mrfiRFPowerTable[idx]); /* remember this. need it when waking up. */ mrfiCurrentPowerLevel = idx; /* Put the radio back in RX state, if it was in RX before change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_SetLogicalChannel * * @brief Set logical channel. * * @param chan - logical channel number * * @return none ************************************************************************************************** */ void MRFI_SetLogicalChannel(uint8_t chan) { uint8_t phyChannel; /* logical channel is not valid */ MRFI_ASSERT( chan < MRFI_NUM_LOGICAL_CHANS ); /* make sure radio is off before changing channels */ Mrfi_RxModeOff(); /* convert logical channel number into physical channel number */ phyChannel = mrfiLogicalChanTable[chan]; /* write frequency value of new channel */ FREQCTRL = FREQ_2405MHZ + (5 * (phyChannel - 11)); /* Put the radio back in RX state, if it was in RX before channel change */ if(mrfiRadioState == MRFI_RADIO_STATE_RX) { Mrfi_RxModeOn(); } }
/************************************************************************************************** * @fn MRFI_Transmit * * @brief Transmit a packet. * * @param pPacket - pointer to packet to transmit * txType - FORCED or CCA * * @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) { uint8_t txResult = MRFI_TX_RESULT_SUCCESS; static uint8_t dsn = 0; /* radio must be awake to transmit */ MRFI_ASSERT( mrfiRadioState != MRFI_RADIO_STATE_OFF ); /* TX_DONE line status must be low. If high, some state logic problem. */ MRFI_ASSERT(!MRFI_TX_DONE_STATUS()); /* Turn off reciever. We ignore/drop incoming packets during transmit. */ Mrfi_RxModeOff(); /* -------------------------------------- * Populate the IEEE fields in frame * ------------------------------------ */ /* set the sequence number, also known as DSN (Data Sequence Number) */ pPacket->frame[MRFI_DSN_OFFSET] = dsn++; 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 frameLen; uint8_t *p; /* flush FIFO of any previous transmit that did not go out */ MRFI_RADIO_FLUSH_TX_BUFFER(); /* 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. */ frameLen = txBufLen + MRFI_RX_METRICS_SIZE; mrfiSpiWriteTxFifo(&frameLen, 1); /* skip the length field which we already sent to FIFO. */ p++; /* write packet bytes to FIFO */ mrfiSpiWriteTxFifo(p, txBufLen); } /* Forced transmit */ if(txType == MRFI_TX_TYPE_FORCED) { /* NOTE: Bug (#1) described in the errata swrz024.pdf for CC2520: * We never strobe TXON when the radio is in receive state. * If this is changed, must implement the bug workaround as described in the * errata (flush the Rx FIFO). */ /* strobe transmit */ mrfiSpiCmdStrobe(STXON); /* wait for transmit to complete */ while (!MRFI_TX_DONE_STATUS()); /* Clear the TX_FRM_DONE exception flag register in the radio. */ mrfiSpiBitClear(EXCFLAG0, 1); } else /* CCA Transmit */ { /* set number of CCA retries */ uint8_t ccaRetries = MRFI_CCA_RETRIES; MRFI_ASSERT( txType == MRFI_TX_TYPE_CCA ); /* ====================================================================== * CCA Algorithm Loop * ====================================================================== */ while(1) { /* Turn ON the receiver to perform CCA. Can not call Mrfi_RxModeOn(), * since that will enable the rx interrupt, which we do not want. */ mrfiSpiCmdStrobe(SRXON); /* Wait for RSSI to be valid. */ MRFI_RSSI_VALID_WAIT(); /* Request transmit on cca */ mrfiSpiCmdStrobe(STXONCCA); /* If sampled CCA is set, transmit has begun. */ if(MRFI_SAMPLED_CCA()) { /* wait for transmit to complete */ while( !MRFI_TX_DONE_STATUS() ); /* Clear the TX_FRM_DONE exception flag register in the radio. */ mrfiSpiBitClear(EXCFLAG0, 1); /* transmit is done. break out of CCA algorithm loop */ break; } else { /* ------------------------------------------------------------------ * Clear Channel Assessment failed. * ------------------------------------------------------------------ */ /* Retry ? */ if(ccaRetries != 0) { /* turn off reciever to conserve power during backoff */ Mrfi_RxModeOff(); /* delay for a random number of backoffs */ Mrfi_RandomBackoffDelay(); /* decrement CCA retries before loop continues */ ccaRetries--; } else /* No CCA retries left, abort */ { /* set return value for failed transmit and break */ txResult = MRFI_TX_RESULT_FAILED; break; } } } /* 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 ); }
/************************************************************************************************** * @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 ); }