📄 mac_rx.c
字号:
/* indicate rx is active */
macRxActive = MAC_RX_ACTIVE_STARTED;
/*
* For bullet proof functionality, need to see if the receiver was just turned off.
* The logic to request turning off the receiver, disables interrupts and then checks
* the value of macRxActive. If it is TRUE, the receiver will not be turned off.
*
* There is a small hole though. It's possible to attempt turning off the receiver
* in the window from when the receive interrupt fires and the point where macRxActive
* is set to TRUE. To plug this hole, the on/off status must be tested *after*
* macRxActive has been set. If the receiver is off at this point, there is nothing
* in the RX fifo and the receive is simply aborted.
*
* Also, there are some considerations in case a hard disable just happened. Usually,
* the receiver will just be off at this point after a hard disable. The check described
* above will account for this case too. However, if a hard disable were immediately
* followed by an enable, the receiver would be on. To catch this case, the receive
* FIFO is also tested to see if it is empty. Recovery is identical to the other cases.
*/
if (!macRxOnFlag || MAC_RADIO_RX_FIFO_IS_EMPTY())
{
/* reset active flag */
macRxActive = MAC_RX_ACTIVE_NO_ACTIVITY;
/*
* To be absolutely bulletproof, must make sure no transmit queue'ed up during
* the tiny, tiny window when macRxActive was not zero.
*/
rxPostRxUpdates();
/* return immediately from here */
return;
}
/*
* If interrupts are held off for too long it's possible the previous "transmit done"
* callback is pending. If this is the case, it needs to be completed before
* continuing with the receive logic.
*/
MAC_RADIO_FORCE_TX_DONE_IF_PENDING();
/*
* It's possible receive logic is still waiting for confirmation of an ACK that went out
* for the previous receive. This is OK but the callback needs to be canceled at this point.
* That callback execute receive cleanup logic that will run at the completion
* of *this* receive. Also, it is important the flag for the outgoing ACK to be cleared.
*/
MAC_RADIO_CANCEL_ACK_TX_DONE_CALLBACK();
macRxOutgoingAckFlag = 0;
/*
* Make a module-local copy of macRxFilter. This prevents the selected
* filter from changing in the middle of a receive.
*/
rxFilter = macRxFilter;
/*-------------------------------------------------------------------------------
* Read initial frame information from FIFO.
*
* This code is not triggered until the following are in the RX FIFO:
* frame length - one byte containing length of MAC frame (excludes this field)
* frame control field - two bytes defining frame type, addressing fields, control flags
* sequence number - one byte unique sequence identifier
* additional two bytes - these bytes are available in case the received frame is an ACK,
* if so, the frame can be verified and responded to immediately,
* if not an ACK, these bytes will be processed normally
*/
/* read frame length, frame control field, and sequence number from FIFO */
MAC_RADIO_READ_RX_FIFO(rxBuf, MAC_PHY_PHR_LEN + MAC_FCF_FIELD_LEN + MAC_SEQ_NUM_FIELD_LEN);
/* bytes to read from FIFO equals frame length minus length of MHR fields just read from FIFO */
rxUnreadLen = (rxBuf[0] & PHY_PACKET_SIZE_MASK) - MAC_FCF_FIELD_LEN - MAC_SEQ_NUM_FIELD_LEN;
/*
* Workaround for chip bug. The receive buffer can sometimes be corrupted by hardware.
* This usually occurs under heavy traffic. If a corrupted receive buffer is detected
* the entire receive buffer is flushed.
*
* In the case that this workaround is not needed, an assert is used to make sure the
* receive length field is not corrupted. This is important because a corrupted receive
* length field is utterly fatal and, if not caught here, extremely hard to track down.
*/
#ifdef MAC_RADIO_RXBUFF_CHIP_BUG
if ((rxUnreadLen > (MAC_A_MAX_PHY_PACKET_SIZE - MAC_FCF_FIELD_LEN - MAC_SEQ_NUM_FIELD_LEN)) ||
(MAC_FRAME_TYPE(&rxBuf[1]) > MAC_FRAME_TYPE_MAX_VALID))
{
MAC_RADIO_FLUSH_RX_FIFO();
rxDone();
return;
}
#else
/* radio supplied a corrupted receive buffer length */
MAC_ASSERT(rxUnreadLen <= (MAC_A_MAX_PHY_PACKET_SIZE - MAC_FCF_FIELD_LEN - MAC_SEQ_NUM_FIELD_LEN));
#endif
/*-------------------------------------------------------------------------------
* Process ACKs.
*
* If this frame is an ACK, process it immediately and exit from here.
* If this frame is not an ACK and transmit is listening for an ACK, let
* the transmit logic know an non-ACK was received so transmit can complete.
*
* In promiscuous mode ACKs are treated like any other frame.
*/
if ((MAC_FRAME_TYPE(&rxBuf[1]) == MAC_FRAME_TYPE_ACK) && (rxPromiscuousMode == PROMISCUOUS_MODE_OFF))
{
uint8 fcsBuf[MAC_FCF_FIELD_LEN];
/*
* There are guaranteed to be two unread bytes in the FIFO. By defintion, for ACK frames
* these two bytes will be the FCS.
*/
/* read FCS from FIFO (threshold set so bytes are guaranteed to be there) */
MAC_RADIO_READ_RX_FIFO(fcsBuf, MAC_FCS_FIELD_LEN);
/* see if transmit is listening for an ACK */
if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK)
{
/*
* An ACK was received so transmit logic needs to know. If the FCS failed,
* the transmit logic still needs to know. In that case, treat the frame
* as a non-ACK to complete the active transmit.
*/
if (PROPRIETARY_FCS_CRC_OK(fcsBuf))
{
/* call transmit logic to indicate ACK was received */
macTxAckReceivedCallback(MAC_SEQ_NUMBER(&rxBuf[1]), MAC_FRAME_PENDING(&rxBuf[1]));
}
else
{
macTxAckNotReceivedCallback();
}
}
/* receive is done, exit from here */
rxDone();
return;
}
else if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK)
{
macTxAckNotReceivedCallback();
}
/*-------------------------------------------------------------------------------
* Apply filtering.
*
* For efficiency, see if filtering is even 'on' before processing. Also test
* to make sure promiscuous mode is disabled. If promiscuous mode is enabled,
* do not apply filtering.
*/
if ((rxFilter != RX_FILTER_OFF) && !rxPromiscuousMode)
{
if (/* filter all frames */
(rxFilter == RX_FILTER_ALL) ||
/* filter non-beacon frames */
((rxFilter == RX_FILTER_NON_BEACON_FRAMES) &&
(MAC_FRAME_TYPE(&rxBuf[1]) != MAC_FRAME_TYPE_BEACON)) ||
/* filter non-command frames */
((rxFilter == RX_FILTER_NON_COMMAND_FRAMES) &&
((MAC_FRAME_TYPE(&rxBuf[1]) != MAC_FRAME_TYPE_COMMAND))))
{
/* discard rest of frame */
rxDiscardFrame();
return;
}
}
/*-------------------------------------------------------------------------------
* Compute length of addressing fields. Compute payload length.
*/
/* decode addressing modes */
dstAddrMode = MAC_DEST_ADDR_MODE(&rxBuf[1]);
srcAddrMode = MAC_SRC_ADDR_MODE(&rxBuf[1]);
/*
* Workaround for chip bug. The receive buffer can sometimes be corrupted by hardware.
* This usually occurs under heavy traffic. If a corrupted receive buffer is detected
* the entire receive buffer is flushed.
*/
#ifdef MAC_RADIO_RXBUFF_CHIP_BUG
if ((srcAddrMode == ADDR_MODE_RESERVERED) || (dstAddrMode == ADDR_MODE_RESERVERED))
{
MAC_RADIO_FLUSH_RX_FIFO();
rxDone();
return;
}
#endif
/*
* Compute the addressing field length. A lookup table based on addressing
* mode is used for efficiency. If the source address is present and the
* frame is intra-PAN, the PAN Id is not repeated. In this case, the address
* length is adjusted to match the smaller length.
*/
addrLen = macRxAddrLen[dstAddrMode] + macRxAddrLen[srcAddrMode];
if ((srcAddrMode != SADDR_MODE_NONE) && MAC_INTRA_PAN(&rxBuf[1]))
{
addrLen -= MAC_PAN_ID_FIELD_LEN;
}
/*
* If there are not enough unread bytes to include the computed address
* plus FCS field, the frame is corrupted and must be discarded.
*/
if ((addrLen + MAC_FCS_FIELD_LEN) > rxUnreadLen)
{
/* discard frame and exit */
rxDiscardFrame();
return;
}
/* payload length is equal to unread bytes minus address length, minus the FCS */
rxPayloadLen = rxUnreadLen - addrLen - MAC_FCS_FIELD_LEN;
/*-------------------------------------------------------------------------------
* Allocate memory for the incoming frame.
*/
pRxBuf = (macRx_t *) MEM_ALLOC(sizeof(macRx_t) + rxPayloadLen);
if (pRxBuf == NULL)
{
/* buffer allocation failed, discard the frame and exit*/
rxDiscardFrame();
return;
}
/*-------------------------------------------------------------------------------
* Set up to process ACK request. Do not ACK if in promiscuous mode.
*/
ackWithPending = 0;
if (!rxPromiscuousMode)
{
macRxOutgoingAckFlag = MAC_ACK_REQUEST(&rxBuf[1]);
}
/*-------------------------------------------------------------------------------
* Process any ACK request.
*/
if (macRxOutgoingAckFlag)
{
halIntState_t s;
/*
* This critical section ensures that the callback ISR is initiated within time
* to guarantee correlation with the strobe.
*/
HAL_ENTER_CRITICAL_SECTION(s);
if ((MAC_FRAME_TYPE(&rxBuf[1]) == MAC_FRAME_TYPE_COMMAND) && macRxCheckPendingCallback())
{
MAC_RADIO_TX_ACK_PEND();
ackWithPending = MAC_RX_FLAG_ACK_PENDING;
}
else
{
/* send ACK */
MAC_RADIO_TX_ACK();
}
/* request a callback to macRxAckTxDoneCallback() when the ACK transmit has finished */
MAC_RADIO_REQUEST_ACK_TX_DONE_CALLBACK();
HAL_EXIT_CRITICAL_SECTION(s);
}
/*-------------------------------------------------------------------------------
* Populate the receive buffer going up to high-level.
*/
/* configure the payload buffer */
pRxBuf->msdu.p = (uint8 *) (pRxBuf + 1);
pRxBuf->msdu.len = rxPayloadLen;
/* set internal values */
pRxBuf->mac.srcAddr.addrMode = srcAddrMode;
pRxBuf->mac.dstAddr.addrMode = dstAddrMode;
pRxBuf->mac.timestamp = MAC_RADIO_BACKOFF_CAPTURE();
pRxBuf->mac.timestamp2 = MAC_RADIO_TIMER_CAPTURE();
pRxBuf->internal.frameType = MAC_FRAME_TYPE(&rxBuf[1]);
pRxBuf->mac.dsn = MAC_SEQ_NUMBER(&rxBuf[1]);
pRxBuf->internal.flags = INTERNAL_FCF_FLAGS(&rxBuf[1]) | ackWithPending;
pRxBuf->sec.securityLevel = MAC_SEC_LEVEL_NONE;
/*-------------------------------------------------------------------------------
* If the processing the addressing fields does not require more bytes from
* the FIFO go directly address processing function. Otherwise, configure
* interrupt to jump there once bytes are received.
*/
if (addrLen == 0)
{
/* no addressing fields to read, prepare for payload interrupts */
pFuncRxState = &rxPayloadIsr;
rxPrepPayload();
}
else
{
/* need to read and process addressing fields, prepare for address interrupt */
rxNextLen = addrLen;
MAC_RADIO_SET_RX_THRESHOLD(rxNextLen);
pFuncRxState = &rxAddrIsr;
}
}
/*=================================================================================================
* @fn rxAddrIsr
*
* @brief Receive ISR state for decoding address. Reads and stores the address information
* from the incoming packet.
*
* @param none
*
* @return none
*=================================================================================================
*/
static void rxAddrIsr(void)
{
uint8 buf[MAX_ADDR_FIELDS_LEN];
uint8 dstAddrMode;
uint8 srcAddrMode;
uint8 * p;
MAC_ASSERT(rxNextLen != 0); /* logic assumes at least one address byte in buffer */
/* read out address fields into local buffer in one shot */
MAC_RADIO_READ_RX_FIFO(buf, rxNextLen);
/* set pointer to buffer with addressing fields */
p = buf;
/* destination address */
dstAddrMode = MAC_DEST_ADDR_MODE(&rxBuf[1]);
if (dstAddrMode != SADDR_MODE_NONE)
{
pRxBuf->mac.srcPanId = pRxBuf->mac.dstPanId = BUILD_UINT16(p[0], p[1]);
p += MAC_PAN_ID_FIELD_LEN;
if (dstAddrMode == SADDR_MODE_EXT)
{
sAddrExtCpy(pRxBuf->mac.dstAddr.addr.extAddr, p);
p += MAC_EXT_ADDR_FIELD_LEN;
}
else
{
pRxBuf->mac.dstAddr.addr.shortAddr = BUILD_UINT16(p[0], p[1]);
p += MAC_SHORT_ADDR_FIELD_LEN;
}
}
/* sources address */
srcAddrMode = MAC_SRC_ADDR_MODE(&rxBuf[1]);
if (srcAddrMode != SADDR_MODE_NONE)
{
if (!(pRxBuf->internal.flags & MAC_RX_FLAG_INTRA_PAN))
{
pRxBuf->mac.srcPanId = BUILD_UINT16(p[0], p[1]);
p += MAC_PAN_ID_FIELD_LEN;
}
if (srcAddrMode == SADDR_MODE_EXT)
{
sAddrExtCpy(pRxBuf->mac.srcAddr.addr.extAddr, p);
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -