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