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