/************************************************************************************************** * @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 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 the specified type. * NOTE! It is not legal to call this function from interrupt context. * * @param txType - type of transmit * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macTxFrame(uint8 txType) { MAC_ASSERT(!macTxActive); /* transmit on top of transmit */ /* mark transmit as active */ macTxActive = MAC_TX_ACTIVE_INITIALIZE; /* * The MAC will not enter sleep mode if there is an active transmit. However, if macSleep() is * ever called from interrupt context, it possible to enter sleep state after a transmit is * intiated but before macTxActive is set. To recover from this, the transmit must be aborted * and proper notificiation given to high-level. */ if (macSleepState != MAC_SLEEP_STATE_AWAKE) { /* notify high-level that transmit had to be aborted */ txComplete(MAC_TX_ABORTED); /* exit from transmit logic */ return; } /* save transmit type */ macTxType = txType; /*------------------------------------------------------------------------------- * Prepare for transmit. */ if (macTxType == MAC_TX_TYPE_SLOTTED) { MAC_RADIO_TX_PREP_SLOTTED(); } #ifdef FEATURE_GREEN_POWER else if (macTxType == MAC_TX_TYPE_GREEN_POWER) { txGreenPowerPrep(); } #endif /* #ifdef FEATURE_GREEN_POWER */ 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) ? pMacPib->altBe : pMacPib->minBe; if ((macTxType == MAC_TX_TYPE_SLOTTED_CSMA) && (pMacPib->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. * * Critical sections around the state change prevents any sort of race condition * with macTxStartQueuedFrame(). This guarantees function txGo() will only be * called once. */ { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); if (!macRxActive && !macRxOutgoingAckFlag) { macTxActive = MAC_TX_ACTIVE_GO; HAL_EXIT_CRITICAL_SECTION(s); txGo(); } else { macTxActive = MAC_TX_ACTIVE_QUEUED; HAL_EXIT_CRITICAL_SECTION(s); } } }
/************************************************************************************************** * @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); } } }