/*================================================================================================= * @fn txGo * * @brief Start a transmit going. * * @param none * * @return none *================================================================================================= */ static void txGo(void) { /* * If execution has reached this point, any transmitted ACK has long since completed. It is * possible though that there is still a pending callback. If so, it is irrelevant and needs to * be canceled at this point. */ MAC_RADIO_CANCEL_ACK_TX_DONE_CALLBACK(); macRxOutgoingAckFlag = 0; /* based on type of transmit, call the correct "go" functionality */ if (macTxType == MAC_TX_TYPE_SLOTTED) { MAC_RADIO_TX_GO_SLOTTED(); } #ifdef FEATURE_GREEN_POWER else if (macTxType == MAC_TX_TYPE_GREEN_POWER) { MAC_RADIO_TX_GO_GREEN_POWER(); } #endif /* #ifdef FEATURE_GREEN_POWER */ else { txCsmaGo(); } }
/************************************************************************************************** * @fn macTxDoneCallback * * @brief - * * @param - * * @return none ************************************************************************************************** */ void macTxDoneCallback(uint8 status) { if (status == MAC_TXDONE_SUCCESS) { /* see if ACK was requested */ if (!txAckReq) { /* ACK was not requested, transmit is complete */ txComplete(MAC_SUCCESS); } else { /* * ACK was requested - must wait to receive it. A timer is set * to expire after the timeout duration for waiting for an ACK. * If an ACK is received, the function macTxAckReceived() is called. * If an ACK is not received within the timeout period, * the function macTxAckTimeoutCallback() is called. */ macTxListenForAck = TRUE; MAC_RADIO_TX_REQUEST_ACK_TIMEOUT_CALLBACK(); } } else if (status == MAC_TXDONE_CHANNEL_BUSY) { MAC_ASSERT((macTxType == MAC_TX_TYPE_SLOTTED_CSMA) || (macTxType == MAC_TX_TYPE_UNSLOTTED_CSMA)); /* clear channel assement failed, follow through with CSMA algorithm */ nb++; if (nb > macPib.maxCsmaBackoffs) { txComplete(MAC_CHANNEL_ACCESS_FAILURE); } else { macTxBe = MIN(macTxBe+1, macPib.maxBe); txCsmaPrep(); txCsmaGo(); } } else { MAC_ASSERT(status == MAC_TXDONE_INSUFFICIENT_TIME); txComplete(MAC_NO_TIME); } }
/************************************************************************************************** * @fn macTxStartQueuedFrame * * @brief - * * @param none * * @return none ************************************************************************************************** */ void macTxStartQueuedFrame(void) { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); if (macTxFrameInQueueFlag) { macTxFrameInQueueFlag = FALSE; HAL_EXIT_CRITICAL_SECTION(s); if (macTxType == MAC_TX_TYPE_SLOTTED) { MAC_RADIO_TX_GO_SLOTTED(); } else { txCsmaGo(); } } HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macTxChannelBusyCallback * * @brief This callback is executed if a CSMA transmit was attempted but the channel * was busy. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macTxChannelBusyCallback(void) { MAC_ASSERT((macTxType == MAC_TX_TYPE_SLOTTED_CSMA) || (macTxType == MAC_TX_TYPE_UNSLOTTED_CSMA)); /* turn off receiver if allowed */ macTxActive = MAC_TX_ACTIVE_CHANNEL_BUSY; macRxOffRequest(); /* clear channel assement failed, follow through with CSMA algorithm */ nb++; if (nb > pMacPib->maxCsmaBackoffs) { txComplete(MAC_CHANNEL_ACCESS_FAILURE); } else { macTxBe = MIN(macTxBe+1, pMacPib->maxBe); txCsmaPrep(); macTxActive = MAC_TX_ACTIVE_GO; txCsmaGo(); } }
/************************************************************************************************** * @fn macTxFrame * * @brief Transmit the frame pointed to by pMacDataTx with unslotted CSMA. * NOTE! It is not legal to call this function from interrupt context. * * @param none * * @return none ************************************************************************************************** */ void macTxFrame(uint8 txType) { MAC_ASSERT(!macTxActive); /* transmit on top of transmit */ MAC_ASSERT(!macTxFrameInQueueFlag); /* already a queued transmit */ MAC_ASSERT(macSleepState == MAC_SLEEP_STATE_AWAKE); /* radio must be awake */ /* initialize */ macTxActive = TRUE; macTxType = txType; /*------------------------------------------------------------------------------- * Prepare for transmit. */ if (macTxType == MAC_TX_TYPE_SLOTTED) { MAC_RADIO_TX_PREP_SLOTTED(); } else { MAC_ASSERT((macTxType == MAC_TX_TYPE_SLOTTED_CSMA) || (macTxType == MAC_TX_TYPE_UNSLOTTED_CSMA)); nb = 0; macTxBe = (pMacDataTx->internal.txOptions & MAC_TXOPTION_ALT_BE) ? macPib.altBe : macPib.minBe; if ((macTxType == MAC_TX_TYPE_SLOTTED_CSMA) && (macPib.battLifeExt)) { macTxBe = MIN(2, macTxBe); } txCsmaPrep(); } /*------------------------------------------------------------------------------- * Load transmit FIFO unless this is a retransmit. No need to write * the FIFO again in that case. */ if (!txRetransmitFlag) { uint8 * p; uint8 lenMhrMsdu; MAC_ASSERT(pMacDataTx != NULL); /* must have data to transmit */ /* save needed parameters */ txAckReq = MAC_ACK_REQUEST(pMacDataTx->msdu.p); txSeqn = MAC_SEQ_NUMBER(pMacDataTx->msdu.p); /* set length of frame (note: use of term msdu is a misnomer, here it's actually mhr + msdu) */ lenMhrMsdu = pMacDataTx->msdu.len; /* calling code guarantees an unused prepended byte */ p = pMacDataTx->msdu.p - PREPENDED_BYTE_LEN; /* first byte of buffer is length of MPDU */ *p = lenMhrMsdu + MFR_LEN; /* * Flush the TX FIFO. This is necessary in case the previous transmit was never * actually sent (e.g. CSMA failed without strobing TXON). If bytes are written to * the FIFO but not transmitted, they remain in the FIFO to be transmitted whenever * a strobe of TXON does happen. */ MAC_RADIO_FLUSH_TX_FIFO(); /* write bytes to FIFO, prepended byte is included, MFR is not (it's generated by hardware) */ MAC_RADIO_WRITE_TX_FIFO(p, PREPENDED_BYTE_LEN + lenMhrMsdu); } /*------------------------------------------------------------------------------- * If not receiving, start the transmit. If receive is active * queue up the transmit. */ { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); if (!macRxActive) { HAL_EXIT_CRITICAL_SECTION(s); if (macTxType == MAC_TX_TYPE_SLOTTED) { MAC_RADIO_TX_GO_SLOTTED(); } else { txCsmaGo(); } } else { macTxFrameInQueueFlag = TRUE; HAL_EXIT_CRITICAL_SECTION(s); } } }