Beispiel #1
0
/*=================================================================================================
 * @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);
}
Beispiel #3
0
/*=================================================================================================
 * @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();
  }
}
Beispiel #4
0
/**************************************************************************************************
 * @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);
}
Beispiel #5
0
/**************************************************************************************************
 * @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();
}
Beispiel #6
0
/**************************************************************************************************
 * @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);
}
Beispiel #7
0
/*=================================================================================================
 * @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;
  }
}