123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- /**************************************************************************************************
- Filename: mac_tx.c
- Revised: $Date: 2007-10-15 14:56:36 -0700 (Mon, 15 Oct 2007) $
- Revision: $Revision: 15687 $
- Description: Describe the purpose and contents of the file.
- Copyright 2006-2010 Texas Instruments Incorporated. All rights reserved.
- IMPORTANT: Your use of this Software is limited to those specific rights
- granted under the terms of a software license agreement between the user
- who downloaded the software, his/her employer (which must be your employer)
- and Texas Instruments Incorporated (the "License"). You may not use this
- Software unless you agree to abide by the terms of the License. The License
- limits your use, and you acknowledge, that the Software may not be modified,
- copied or distributed unless embedded on a Texas Instruments microcontroller
- or used solely and exclusively in conjunction with a Texas Instruments radio
- frequency transceiver, which is integrated into your product. Other than for
- the foregoing purpose, you may not use, reproduce, copy, prepare derivative
- works of, modify, distribute, perform, display or sell this Software and/or
- its documentation for any purpose.
- YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
- PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
- INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
- NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
- TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
- NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
- LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
- INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
- OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
- OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
- (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
- Should you have any questions regarding your right to use this Software,
- contact Texas Instruments Incorporated at www.TI.com.
- **************************************************************************************************/
- /* ------------------------------------------------------------------------------------------------
- * Includes
- * ------------------------------------------------------------------------------------------------
- */
- /* hal */
- #include "hal_types.h"
- #include "hal_defs.h"
- #include "hal_mcu.h"
- #include "hal_mac_cfg.h"
- /* high-level */
- #include "mac_spec.h"
- #include "mac_pib.h"
- /* exported low-level */
- #include "mac_low_level.h"
- /* low-level specific */
- #include "mac_tx.h"
- #include "mac_backoff_timer.h"
- #include "mac_rx.h"
- #include "mac_rx_onoff.h"
- #include "mac_radio.h"
- #include "mac_sleep.h"
- /* target specific */
- #include "mac_radio_defs.h"
- /* debug */
- #include "mac_assert.h"
- /* ------------------------------------------------------------------------------------------------
- * Defines
- * ------------------------------------------------------------------------------------------------
- */
- #define MFR_LEN MAC_FCS_FIELD_LEN
- #define PREPENDED_BYTE_LEN 1
- /* ------------------------------------------------------------------------------------------------
- * Global Constants
- * ------------------------------------------------------------------------------------------------
- */
- /*
- * This is the time, in backoffs, required to set up a slotted transmit.
- * It is exported to high level so that code can schedule enough time
- * for slotted transmits.
- *
- * A default is provided if a value is not specified. If the default
- * is not appropriate, a #define should be added within hal_mac_cfg.h.
- */
- #ifndef HAL_MAC_TX_SLOTTED_DELAY
- #define HAL_MAC_TX_SLOTTED_DELAY 3
- #endif
- uint8 const macTxSlottedDelay = HAL_MAC_TX_SLOTTED_DELAY;
- /* ------------------------------------------------------------------------------------------------
- * Global Variables
- * ------------------------------------------------------------------------------------------------
- */
- uint8 macTxActive;
- uint8 macTxType;
- uint8 macTxBe;
- uint8 macTxCsmaBackoffDelay;
- /* ------------------------------------------------------------------------------------------------
- * Local Variables
- * ------------------------------------------------------------------------------------------------
- */
- static uint8 nb;
- static uint8 txSeqn;
- static uint8 txAckReq;
- static uint8 txRetransmitFlag;
- /* ------------------------------------------------------------------------------------------------
- * Local Prototypes
- * ------------------------------------------------------------------------------------------------
- */
- static void txCsmaPrep(void);
- static void txGo(void);
- static void txCsmaGo(void);
- static void txComplete(uint8 status);
- /**************************************************************************************************
- * @fn macTxInit
- *
- * @brief Initialize variables for tx module.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxInit(void)
- {
- macTxActive = MAC_TX_ACTIVE_NO_ACTIVITY;
- txRetransmitFlag = 0;
- }
- /**************************************************************************************************
- * @fn macTxHaltCleanup
- *
- * @brief -
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxHaltCleanup(void)
- {
- MAC_RADIO_TX_RESET();
- macTxInit();
- }
- /**************************************************************************************************
- * @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();
- }
- 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.
- *
- * 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 txCsmaPrep
- *
- * @brief Prepare/initialize for a CSMA transmit.
- *
- * @param none
- *
- * @return none
- *=================================================================================================
- */
- static void txCsmaPrep(void)
- {
- macTxCsmaBackoffDelay = macRadioRandomByte() & ((1 << macTxBe) - 1);
- if (macTxType == MAC_TX_TYPE_SLOTTED_CSMA)
- {
- MAC_RADIO_TX_PREP_CSMA_SLOTTED();
- }
- else
- {
- MAC_RADIO_TX_PREP_CSMA_UNSLOTTED();
- }
- }
- /*=================================================================================================
- * @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();
- }
- else
- {
- txCsmaGo();
- }
- }
- /*=================================================================================================
- * @fn txCsmaGo
- *
- * @brief Start a CSMA transmit going.
- *
- * @param none
- *
- * @return none
- *=================================================================================================
- */
- static void txCsmaGo(void)
- {
- /* The CSMA needs to be performed at normal CCA threshold.
- * Turn off the CC2591 compression workaround.
- */
- COMPRESSION_WORKAROUND_OFF();
- if (macTxType == MAC_TX_TYPE_SLOTTED_CSMA)
- {
- if (macTxCsmaBackoffDelay >= macDataTxTimeAvailable())
- {
- txComplete(MAC_NO_TIME);
- return;
- }
- MAC_RADIO_TX_GO_SLOTTED_CSMA();
- }
- else
- {
- MAC_RADIO_TX_GO_CSMA();
- }
- }
- /**************************************************************************************************
- * @fn macTxFrameRetransmit
- *
- * @brief Retransmit the last frame.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxFrameRetransmit(void)
- {
- txRetransmitFlag = 1;
- macTxFrame(macTxType);
- }
- /**************************************************************************************************
- * @fn macTxStartQueuedFrame
- *
- * @brief See if there is a queued frame waiting to transmit. If so, initiate
- * the transmit now.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxStartQueuedFrame(void)
- {
- halIntState_t s;
- MAC_ASSERT(!macRxActive && !macRxOutgoingAckFlag); /* queued frames should not transmit in middle of a receive */
- /*
- * Critical sections around the state change prevents any sort of race condition
- * with macTxFrame(). This guarantees function txGo() will only be be called once.
- */
- HAL_ENTER_CRITICAL_SECTION(s);
- if (macTxActive == MAC_TX_ACTIVE_QUEUED)
- {
- macTxActive = MAC_TX_ACTIVE_GO;
- HAL_EXIT_CRITICAL_SECTION(s);
- txGo();
- }
- else
- {
- 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 > macPib.maxCsmaBackoffs)
- {
- txComplete(MAC_CHANNEL_ACCESS_FAILURE);
- }
- else
- {
- macTxBe = MIN(macTxBe+1, macPib.maxBe);
- txCsmaPrep();
- macTxActive = MAC_TX_ACTIVE_GO;
- txCsmaGo();
- }
- }
- /**************************************************************************************************
- * @fn macTxDoneCallback
- *
- * @brief This callback is executed when transmit completes.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxDoneCallback(void)
- {
- halIntState_t s;
- /*
- * There is a small chance this function could be called twice for a single transmit.
- * To prevent logic from executing twice, the state variable macTxActive is used as
- * a gating mechanism to guarantee single time execution.
- */
- HAL_ENTER_CRITICAL_SECTION(s);
- if (macTxActive == MAC_TX_ACTIVE_GO)
- {
- /* see if ACK was requested */
- if (!txAckReq)
- {
- macTxActive = MAC_TX_ACTIVE_DONE;
- HAL_EXIT_CRITICAL_SECTION(s);
- /* 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 macTxAckNotReceivedCallback() is called.
- */
- macTxActive = MAC_TX_ACTIVE_LISTEN_FOR_ACK;
- MAC_RADIO_TX_REQUEST_ACK_TIMEOUT_CALLBACK();
- HAL_EXIT_CRITICAL_SECTION(s);
- }
- }
- else
- {
- HAL_EXIT_CRITICAL_SECTION(s);
- }
- }
- /**************************************************************************************************
- * @fn macTxAckReceivedCallback
- *
- * @brief This function is called by the receive logic when an ACK is received and
- * transmit logic is listening for an ACK.
- *
- * @param seqn - sequence number of received ACK
- * @param pendingFlag - set if pending flag of ACK is set, cleared otherwise
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxAckReceivedCallback(uint8 seqn, uint8 pendingFlag)
- {
- halIntState_t s;
- /* only process if listening for an ACK; critical section prevents race condition problems */
- HAL_ENTER_CRITICAL_SECTION(s);
- if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK)
- {
- macTxActive = MAC_TX_ACTIVE_POST_ACK;
- MAC_RADIO_TX_CANCEL_ACK_TIMEOUT_CALLBACK();
- HAL_EXIT_CRITICAL_SECTION(s);
- /* see if the sequence number of received ACK matches sequence number of packet just sent */
- if (seqn == txSeqn)
- {
- /*
- * Sequence numbers match so transmit is successful. Return appropriate
- * status based on the pending flag of the received ACK.
- */
- if (pendingFlag)
- {
- txComplete(MAC_ACK_PENDING);
- }
- else
- {
- txComplete(MAC_SUCCESS);
- }
- }
- else
- {
- /* sequence number did not match; per spec, transmit failed at this point */
- txComplete(MAC_NO_ACK);
- }
- }
- else
- {
- HAL_EXIT_CRITICAL_SECTION(s);
- }
- }
- /**************************************************************************************************
- * @fn macTxAckNotReceivedCallback
- *
- * @brief This function is called by the receive logic when transmit is listening
- * for an ACK but something else is received. It is also called if the
- * listen-for-ACK timeout is reached.
- *
- * @brief
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxAckNotReceivedCallback(void)
- {
- halIntState_t s;
- /* only process if listening for an ACK; critical section prevents race condition problems */
- HAL_ENTER_CRITICAL_SECTION(s);
- if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK)
- {
- macTxActive = MAC_TX_ACTIVE_POST_ACK;
- MAC_RADIO_TX_CANCEL_ACK_TIMEOUT_CALLBACK();
- HAL_EXIT_CRITICAL_SECTION(s);
- /* a non-ACK was received when expecting an ACK, per spec transmit is over at this point */
- txComplete(MAC_NO_ACK);
- }
- else
- {
- HAL_EXIT_CRITICAL_SECTION(s);
- }
- }
- /*=================================================================================================
- * @fn txComplete
- *
- * @brief Transmit has completed. Perform needed maintenance and return status of
- * the transmit via callback function.
- *
- * @param status - status of the transmit that just went out
- *
- * @return none
- *=================================================================================================
- */
- static void txComplete(uint8 status)
- {
- /* reset the retransmit flag */
- txRetransmitFlag = 0;
- /* update tx state; turn off receiver if nothing is keeping it on */
- macTxActive = MAC_TX_ACTIVE_NO_ACTIVITY;
- /* turn off receive if allowed */
- macRxOffRequest();
- /* update transmit power in case there was a change */
- macRadioUpdateTxPower();
- /*
- * Channel cannot change during transmit so update it here. (Channel *can* change during
- * a receive. The update function resets receive logic and any partially received
- * frame is purged.)
- */
- macRadioUpdateChannel();
- /* return status of transmit via callback function */
- macTxCompleteCallback(status);
- }
- /**************************************************************************************************
- * @fn macTxTimestampCallback
- *
- * @brief This callback function records the timestamp into the receive data structure.
- * It should be called as soon as possible after there is a valid timestamp.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxTimestampCallback(void)
- {
- MAC_ASSERT(pMacDataTx != NULL); /* transmit structure must be there */
- pMacDataTx->internal.timestamp = macBackoffTimerCapture();
- pMacDataTx->internal.timestamp2 = MAC_RADIO_TIMER_CAPTURE();
- }
- /**************************************************************************************************
- * @fn macTxCollisionWithRxCallback
- *
- * @brief Function called if transmit strobed on top of a receive.
- *
- * @param none
- *
- * @return none
- **************************************************************************************************
- */
- MAC_INTERNAL_API void macTxCollisionWithRxCallback(void)
- {
- macRxHaltCleanup();
- }
- /**************************************************************************************************
- * Compile Time Integrity Checks
- **************************************************************************************************
- */
- #if (MAC_TX_ACTIVE_NO_ACTIVITY != 0x00)
- #error "ERROR! Zero is reserved value of macTxActive. Allows boolean operations, e.g !macTxActive."
- #endif
- /**************************************************************************************************
- */
|