687 lines
21 KiB
C
687 lines
21 KiB
C
|
/**************************************************************************************************
|
|||
|
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 <EFBFBD>AS IS<EFBFBD> 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
|
|||
|
|
|||
|
/**************************************************************************************************
|
|||
|
*/
|