/*================================================================================================= * @fn rxHaltCleanupFinalStep * * @brief Required cleanup if receiver is halted in the middle of a receive. * * @param none * * @return none *================================================================================================= */ static void rxHaltCleanupFinalStep(void) { /* cancel any upcoming ACK transmit complete callback */ MAC_RADIO_CANCEL_ACK_TX_DONE_CALLBACK(); /* set start of frame threshold */ MAC_RADIO_SET_RX_THRESHOLD(RX_THRESHOLD_START_LEN); /* flush the receive FIFO */ MAC_RADIO_FLUSH_RX_FIFO(); /* clear any receive interrupt that happened to squeak through */ MAC_RADIO_CLEAR_RX_THRESHOLD_INTERRUPT_FLAG(); /* if data buffer has been allocated, free it */ if (pRxBuf != NULL) { MEM_FREE((uint8 **)&pRxBuf); } /* MEM_FREE() sets parameter to NULL. */ pFuncRxState = &rxStartIsr; /* if receive was active, perform the post receive updates */ if (macRxActive || macRxOutgoingAckFlag) { macRxActive = MAC_RX_ACTIVE_NO_ACTIVITY; macRxOutgoingAckFlag = 0; rxPostRxUpdates(); } }
/************************************************************************************************** * @fn macRxOff * * @brief Turn off the receiver if it's not already off. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRxOff(void) { halIntState_t s; DBG_PRINT1(DBGSYS, "macRxOff(): macRxOnFlag = 0x%X", macRxOnFlag); HAL_ENTER_CRITICAL_SECTION(s); if (macRxOnFlag) { macRxOnFlag = 0; DBG_PRINT0(DBGSYS, "MAC_RADIO_RXTX_OFF()"); MAC_RADIO_RXTX_OFF(); /* Wait till RX is completely off before issuing another RX related * command which may fail if issued beforehand. */ macCheckCommnadDone(&macRxEdScan.rxCmd.rfOpCmd); /* Wait till all FG commands are done */ macCheckCommnadDone(&macCsmaCaCmd.rfOpCmd); macCheckCommnadDone(&macTxCmd.rfOpCmd); macCheckCommnadDone(&macRxAckCmd.rfOpCmd); MAC_DEBUG_TURN_OFF_RX_LED(); /* just in case a receive was about to start, flush the receive FIFO */ MAC_RADIO_FLUSH_RX_FIFO(); /* clear any receive interrupt that happened to squeak through */ MAC_RADIO_CLEAR_RX_THRESHOLD_INTERRUPT_FLAG(); } HAL_EXIT_CRITICAL_SECTION(s); }
/*================================================================================================= * @fn rxDone * * @brief Common exit point for receive. * * @param none * * @return none *================================================================================================= */ static void rxDone(void) { /* if the receive FIFO has overflowed, flush it here */ if (MAC_RADIO_RX_FIFO_HAS_OVERFLOWED()) { MAC_RADIO_FLUSH_RX_FIFO(); } /* mark receive as inactive */ macRxActive = MAC_RX_ACTIVE_NO_ACTIVITY; /* if there is no outgoing ACK, run the post receive updates */ if (!macRxOutgoingAckFlag) { rxPostRxUpdates(); } }
/************************************************************************************************** * @fn macSleep * * @brief Puts radio into the selected sleep mode. * * @param sleepState - selected sleep level, see #defines in .h file * * @return TRUE if radio was successfully put into selected sleep mode. * FALSE if it was not safe for radio to go to sleep. ************************************************************************************************** */ BOOL macSleep(void) { BOOL s; /* disable interrupts until macSleepState can be set */ HAL_ENTER_CRITICAL_SECTION(s); /* assert checks */ //MAC_ASSERT(macSleepState == MAC_SLEEP_STATE_AWAKE); /* radio must be awake to put it to sleep */ //MAC_ASSERT(macRxFilter == RX_FILTER_OFF); /* do not sleep when scanning or in promiscuous mode */ if (macSleepState != MAC_SLEEP_STATE_AWAKE) { HAL_EXIT_CRITICAL_SECTION(s); return(FALSE); } /* if either RX or TX is active or any RX enable flags are set, it's not OK to sleep */ if (macTXBusy()) { HAL_EXIT_CRITICAL_SECTION(s); return(FALSE); } /* turn off the receiver */ MAC_RADIO_RXTX_OFF(); MAC_RADIO_FLUSH_RX_FIFO(); /* update sleep state variable */ macSleepState = MAC_SLEEP_STATE_RADIO_OFF; /* macSleepState is now set, re-enable interrupts */ HAL_EXIT_CRITICAL_SECTION(s); /* put MAC timer to sleep */ /* MAC timer 关闭时, T2THD:T2TLD自动保存到T2CAPHPH:T2CAPLPL,T2OF2:T2OF1:T2OF0自动保存到T2PEROF2:T2PEROF1:T2PEROF0 */ MAC_RADIO_TIMER_SLEEP(); /* put radio in selected sleep mode */ MAC_RADIO_TURN_OFF_POWER(); /* radio successfully entered sleep mode */ return(TRUE); }
/************************************************************************************************** * @fn macRxHardDisable * * @brief Clear all enable flags and turn off receiver. * * @param none * * @return none ************************************************************************************************** */ void macRxHardDisable(void) { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); macRxEnableFlags = 0; macRxOnFlag = 0; /* force receiver off */ MAC_RADIO_RXTX_OFF(); MAC_RADIO_FLUSH_RX_FIFO(); MAC_DEBUG_TURN_OFF_RX_LED(); HAL_EXIT_CRITICAL_SECTION(s); /* clean up after being forced off */ macRxHaltCleanup(); }
/************************************************************************************************** * @fn macRxOff * * @brief Turn off the receiver if it's not already off. * * @param none * * @return none ************************************************************************************************** */ void macRxOff(void) { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); if (macRxOnFlag) { macRxOnFlag = 0; MAC_RADIO_RXTX_OFF(); MAC_DEBUG_TURN_OFF_RX_LED(); /* just in case a receive was about to start, flush the receive FIFO */ MAC_RADIO_FLUSH_RX_FIFO(); /* clear any receive interrupt that happened to squeak through */ MAC_RADIO_CLEAR_RX_THRESHOLD_INTERRUPT_FLAG(); } HAL_EXIT_CRITICAL_SECTION(s); }
/*================================================================================================= * @fn rxStartIsr * * @brief First ISR state for receiving a packet - compute packet length, allocate * buffer, initialize buffer. Acknowledgements are handled immediately without * allocating a buffer. * * @param none * * @return none *================================================================================================= */ static void rxStartIsr(void) { uint8 addrLen; uint8 ackWithPending; uint8 dstAddrMode; uint8 srcAddrMode; uint8 mhrLen = 0; MAC_ASSERT(!macRxActive); /* receive on top of receive */ /* 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 #1547. 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. */ 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; } /*------------------------------------------------------------------------------- * 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)) { halIntState_t s; 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); /* * This critical section ensures that the ACK timeout won't be triggered in the * middle of receiving the ACK frame. */ HAL_ENTER_CRITICAL_SECTION(s); /* see if transmit is listening for an ACK */ if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK) { MAC_ASSERT(pMacDataTx != NULL); /* transmit buffer must be present */ /* record link quality metrics for the receive ACK */ { int8 rssiDbm; uint8 corr; rssiDbm = PROPRIETARY_FCS_RSSI(fcsBuf) + MAC_RADIO_RSSI_OFFSET; MAC_RADIO_RSSI_LNA_OFFSET(rssiDbm); corr = PROPRIETARY_FCS_CORRELATION_VALUE(fcsBuf); pMacDataTx->internal.mpduLinkQuality = macRadioComputeLQI(rssiDbm, corr); pMacDataTx->internal.correlation = corr; pMacDataTx->internal.rssi= rssiDbm; } /* * It's okay if the ACK timeout is triggered here. The callbacks for ACK received * or ACK not received will check "macTxActive" flag before taking any actions. */ HAL_EXIT_CRITICAL_SECTION(s); /* * 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(); } } else { HAL_EXIT_CRITICAL_SECTION(s); } /* 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 #1547. 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. */ if (macChipVersion == REV_A) { if ((srcAddrMode == ADDR_MODE_RESERVERED) || (dstAddrMode == ADDR_MODE_RESERVERED)) { MAC_RADIO_FLUSH_RX_FIFO(); rxDone(); return; } } /* * 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; } /* aux security header plus 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. */ if (MAC_SEC_ENABLED(&rxBuf[1])) { /* increase the allocation size of MAC header for security */ mhrLen = MAC_MHR_LEN; } pRxBuf = (macRx_t *) MEM_ALLOC(sizeof(macRx_t) + mhrLen + rxPayloadLen); if (pRxBuf == NULL) { /* Cancel the outgoing TX ACK */ MAC_RADIO_CANCEL_TX_ACK(); /* 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); /* Do not ack data packet with pending more data */ if( MAC_FRAME_TYPE(&rxBuf[1]) == MAC_FRAME_TYPE_COMMAND ) { if( macRxCheckMACPendingCallback()) { /* Check is any mac data pending for end devices */ ackWithPending = MAC_RX_FLAG_ACK_PENDING; } else { if( macSrcMatchIsEnabled ) { /* When autopend is enabled, check if allpending is set to true */ if( MAC_SrcMatchCheckAllPending() == MAC_AUTOACK_PENDING_ALL_ON ) { ackWithPending = MAC_RX_FLAG_ACK_PENDING; } } else { /* When autopend is disabled, check the application pending callback */ if( macRxCheckPendingCallback() ) { ackWithPending = MAC_RX_FLAG_ACK_PENDING; } } } } if( ackWithPending == MAC_RX_FLAG_ACK_PENDING ) { MAC_RADIO_TX_ACK_PEND(); } else { 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 * save MAC header pointer regardless of security status. */ pRxBuf->mhr.p = pRxBuf->msdu.p = (uint8 *) (pRxBuf + 1); pRxBuf->mhr.len = pRxBuf->msdu.len = rxPayloadLen; if (MAC_SEC_ENABLED(&rxBuf[1])) { /* Copy FCF and sequence number to RX buffer */ pRxBuf->mhr.len = MAC_FCF_FIELD_LEN + MAC_SEQ_NUM_FIELD_LEN; osal_memcpy(pRxBuf->mhr.p, &rxBuf[1], pRxBuf->mhr.len); pRxBuf->mhr.p += pRxBuf->mhr.len; } /* 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(); /* Special Case for Enhanced Beacon Request which has a different * frame version */ #ifdef FEATURE_ENHANCED_BEACON if( MAC_FRAME_VERSION(&rxBuf[1]) == 2 ) { pRxBuf->internal.frameType = MAC_FRAME_TYPE_INTERNAL_MAC_VERSION_E | \ MAC_FRAME_TYPE(&rxBuf[1]); } else #endif { 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; /*------------------------------------------------------------------------------- * 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; if (MAC_SEC_ENABLED(&rxBuf[1])) { /* When security is enabled, read off security control field as well */ MAC_RADIO_SET_RX_THRESHOLD(rxNextLen + MAC_SEC_CONTROL_FIELD_LEN); } else { MAC_RADIO_SET_RX_THRESHOLD(rxNextLen); } pFuncRxState = &rxAddrIsr; } }