当前位置:首页 > 芯闻号 > 充电吧
[导读]首先,在协议栈中应用层的事件处理函数都是通过 一个指向接收消息结构体的指针*MSGpkt(afIncomingMSGPacket_t )来传递消息的。在该结构体中有一个参数timestamp,其描述为

首先,在协议栈中应用层的事件处理函数都是通过 一个指向接收消息结构体的指针*MSGpkt(afIncomingMSGPacket_t )来传递消息的。在该结构体中有一个参数timestamp,其描述为:



uint32 timestamp;         /* receipt timestamp from MAC */


为了探索在无线数据包中这个参数到底是如何来的?我选择在整个工程文件中搜索该参数。然后在搜索结果中看到一个在AF.c文件中的函数:



/*********************************************************************
 * @fn          afBuildMSGIncoming
 *
 * @brief       Build the message for the app
 *
 * @param
 *
 * @return      pointer to next in data buffer
 */
static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
                 zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig,
                 uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp )
{
  afIncomingMSGPacket_t *MSGpkt;
  const uint8 len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;
  uint8 *asdu = aff->asdu;
  MSGpkt = (afIncomingMSGPacket_t *)osal_msg_allocate( len );

  if ( MSGpkt == NULL )
  {
    return;
  }

  MSGpkt->hdr.event = AF_INCOMING_MSG_CMD;
  MSGpkt->groupId = aff->GroupID;
  MSGpkt->clusterId = aff->ClusterID;
  afCopyAddress( &MSGpkt->srcAddr, SrcAddress );
  MSGpkt->srcAddr.endPoint = aff->SrcEndPoint;
  MSGpkt->endPoint = epDesc->endPoint;
  MSGpkt->wasBroadcast = aff->wasBroadcast;
  MSGpkt->LinkQuality = sig->LinkQuality;
  MSGpkt->correlation = sig->correlation;
  MSGpkt->rssi = sig->rssi;
  MSGpkt->SecurityUse = SecurityUse;
  MSGpkt->timestamp = timestamp;
  MSGpkt->nwkSeqNum = nwkSeqNum;
  MSGpkt->macDestAddr = aff->macDestAddr;
  MSGpkt->srcAddr.panId = SrcPanId;
  MSGpkt->cmd.TransSeqNumber = 0;
  MSGpkt->cmd.DataLength = aff->asduLength;

  if ( MSGpkt->cmd.DataLength )
  {
    MSGpkt->cmd.Data = (uint8 *)(MSGpkt + 1);
    osal_memcpy( MSGpkt->cmd.Data, asdu, MSGpkt->cmd.DataLength );
  }
  else
  {
    MSGpkt->cmd.Data = NULL;
  }

#if defined ( MT_AF_CB_FUNC )
  // If ZDO or SAPI have registered for this endpoint, dont intercept it here
  if (AFCB_CHECK(CB_ID_AF_DATA_IND, *(epDesc->task_id)))
  {
    MT_AfIncomingMsg( (void *)MSGpkt );
    // Release the memory.
    osal_msg_deallocate( (void *)MSGpkt );
  }
  else
#endif
  {
    // Send message through task message.
    osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );
  }
}


其中可以看到这个函数是一个为应用层事件处理函数生成消息的函数(第35行)。那么我再次在工程文件中搜索该函数,希望能够找到该函数的调用位置。然后发现其在同位于AF.c文件下的afIncomingData函数中被调用:



/*********************************************************************
 * @fn          afIncomingData
 *
 * @brief       Transfer a data PDU (ASDU) from the APS sub-layer to the AF.
 *
 * @param       aff  - pointer to APS frame format
 * @param       SrcAddress  - Source address
 * @param       SrcPanId  - Source PAN ID
 * @param       sig - incoming message's link quality
 * @param       nwkSeqNum - incoming network sequence number (from nwk header frame)
 * @param       SecurityUse - Security enable/disable
 * @param       timestamp - the MAC Timer2 timestamp at Rx.
 *
 * @return      none
 */
void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
                     NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp )
{
  endPointDesc_t *epDesc = NULL;
  epList_t *pList = epList;
#if !defined ( APS_NO_GROUPS )
  uint8 grpEp = APS_GROUPS_EP_NOT_FOUND;
#endif

  if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
  {
#if !defined ( APS_NO_GROUPS )
    // Find the first endpoint for this group
    grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );
    if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
      return;   // No endpoint found

    epDesc = afFindEndPointDesc( grpEp );
    if ( epDesc == NULL )
      return;   // Endpoint descriptor not found

    pList = afFindEndPointDescList( epDesc->endPoint );
#else
    return; // Not supported
#endif
  }
  else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
  {
    // Set the list
    if ( pList != NULL )
    {
      epDesc = pList->epDesc;
    }
  }
  else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )
  {
    pList = afFindEndPointDescList( epDesc->endPoint );
  }

  while ( epDesc )
  {
    uint16 epProfileID = 0xFFFF;  // Invalid Profile ID

    if ( pList->pfnDescCB )
    {
      uint16 *pID = (uint16 *)(pList->pfnDescCB(
                                 AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));
      if ( pID )
      {
        epProfileID = *pID;
        osal_mem_free( pID );
      }
    }
    else if ( epDesc->simpleDesc )
    {
      epProfileID = epDesc->simpleDesc->AppProfId;
    }

    if ( (aff->ProfileID == epProfileID) ||
         ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) )
    {
      {
        // Save original endpoint
        uint8 endpoint = aff->DstEndPoint;

        // overwrite with descriptor's endpoint
        aff->DstEndPoint = epDesc->endPoint;

        afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig,
                           nwkSeqNum, SecurityUse, timestamp );

        // Restore with original endpoint
        aff->DstEndPoint = endpoint;
      }
    }

    if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
    {
#if !defined ( APS_NO_GROUPS )
      // Find the next endpoint for this group
      grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );
      if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
        return;   // No endpoint found

      epDesc = afFindEndPointDesc( grpEp );
      if ( epDesc == NULL )
        return;   // Endpoint descriptor not found

      pList = afFindEndPointDescList( epDesc->endPoint );
#else
      return;
#endif
    }
    else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
    {
      pList = pList->nextDesc;
      if ( pList )
        epDesc = pList->epDesc;
      else
        epDesc = NULL;
    }
    else
      epDesc = NULL;
  }
}


在参数描述那里显示timestamp是Rx时的MAC时间(第12行、第84行)。那么,我开始探索afIncomingData函数在什么位置被调用,采用同样的搜索方法,然后发现其调用的位置被封装了,搜索不到。但是根据这个参数的表述,我们知道这个参数是Rx时的MAC时间。所以我在工程文件中找到了一个名叫mac_rx.c的文件,我有一种这个参数将在这得到其来由的预感。首先,我们看一下这个mac_rx.c文件中包含的.h头文件mac_rx.h:



MAC_INTERNAL_API void macRxInit(void);
MAC_INTERNAL_API void macRxRadioPowerUpInit(void);
MAC_INTERNAL_API void macRxTxReset(void);
MAC_INTERNAL_API void macRxHaltCleanup(void);
MAC_INTERNAL_API void macRxThresholdIsr(void);
MAC_INTERNAL_API void macRxFifoOverflowIsr(void);
MAC_INTERNAL_API void macRxAckTxDoneCallback(void);


对于这个头文件还是有点不明白,然后再去看mac_rx.c文件,从其中一个函数的函数描述,我判断这个函数可能就是和我们当前目的相近的函数:



/*=================================================================================================
 * @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.
   *
   *  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.
   */
  if (macChipVersion == REV_A)
  {
    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  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();
  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;
  }
}


这个函数特别长,也特别复杂,但是我们从其中标红的这段代码和其描述可以知道,这段代码的作用是接受到从硬件电路通过ISA层上传至更高层的无线数据包(第292行,第369行至395行,特别是第390行和391行)。那么我们对


pRxBuf进行分析,我们发现该参数在该文件中被声明:


static macRx_t  * pRxBuf;
/* Structure for internal data rx */
typedef struct
{
  macEventHdr_t     hdr;
  sData_t           msdu;
  macRxIntData_t    internal;
  macSec_t          sec;
  macDataInd_t      mac;
  sData_t           mhr;
} macRx_t;


然后这个参数在该函数被分配地址,并对其进行赋值。对于macDataInd_t有如下定义:



/* Data indication parameters type */
typedef struct
{
  sAddr_t   srcAddr;          /* The address of the sending device */
  sAddr_t   dstAddr;          /* The address of the destination device */
  uint32    timestamp;        /* The time, in backoffs, at which the data were received */
  uint16    timestamp2;       /* The time, in internal MAC timer units, at which the
                                 data were received */
  uint16    srcPanId;         /* The PAN ID of the sending device */
  uint16    dstPanId;         /* The PAN ID of the destination device */
  uint8     mpduLinkQuality;  /* The link quality of the received data frame */
  uint8     correlation;      /* The raw correlation value of the received data frame */
  int8      rssi;             /* The received RF power in units dBm */
  uint8     dsn;              /* The data sequence number of the received frame */
} macDataInd_t;


该定义后的注释告诉我们timestamp是收到数据时的回退(补偿)时间,而timestamp是收到数据时的内部定时器timer的值。通过对其赋值函数进行查询:



#define MAC_RADIO_BACKOFF_CAPTURE()                   macMcuOverflowCapture()
#define MAC_RADIO_TIMER_CAPTURE()                     macMcuTimerCapture()

其中macMcuTimerCapture()函数是对系统时钟timer2的16位定时器数值的读取:


/**************************************************************************************************
 * @fn          macMcuTimerCapture
 *
 * @brief       Returns the last timer capture.  This capture should have occurred at the
 *              receive time of the last frame (the last time SFD transitioned to active).
 *
 * @param       none
 *
 * @return      last capture of hardware timer (full 16-bit value)
 **************************************************************************************************
 */
MAC_INTERNAL_API uint16 macMcuTimerCapture(void)
{
  uint16         timerCapture;
  halIntState_t  s;

  HAL_ENTER_CRITICAL_SECTION(s);
  MAC_MCU_T2_ACCESS_CAPTURE_VALUE();
  timerCapture = T2M1 << 8;
  timerCapture |= T2M0;
  HAL_EXIT_CRITICAL_SECTION(s);

  return (timerCapture);
}



而macMucOverflowCapture()则是对定时器timer2的溢出计数器的捕获:


/**************************************************************************************************
 * @fn          macMcuOverflowCapture
 *
 * @brief       Returns the last capture of the overflow counter.  A special hardware feature
 *              captures the overflow counter when the regular hardware timer is captured.
 *
 * @param       none
 *
 * @return      last capture of overflow count
 **************************************************************************************************
 */
MAC_INTERNAL_API uint32 macMcuOverflowCapture(void)
{
  uint32         overflowCapture;
  halIntState_t  s;

  /* for efficiency, the 32-bit value is encoded using endian abstracted indexing */
  HAL_ENTER_CRITICAL_SECTION(s);
  MAC_MCU_T2_ACCESS_OVF_CAPTURE_VALUE();
  ((uint8 *)&overflowCapture)[UINT32_NDX0] = T2MOVF0;
  ((uint8 *)&overflowCapture)[UINT32_NDX1] = T2MOVF1;
  ((uint8 *)&overflowCapture)[UINT32_NDX2] = T2MOVF2;
  ((uint8 *)&overflowCapture)[UINT32_NDX3] = 0;
  HAL_EXIT_CRITICAL_SECTION(s);

  return (overflowCapture);
}


到目前,我们可以猜测这个afIncomingMSGPacket_t::timestamp是接受到数据包的时候系统定时器Timer2的溢出计数器的值。但这个我们也没有办法确认,那么我选择去看一看mac_tx.c和mac_tx.h文件,看在其中能否找到一些信息,对于mac_tx.h文件中对函数的声明:



MAC_INTERNAL_API void macTxInit(void);
MAC_INTERNAL_API void macTxHaltCleanup(void);
MAC_INTERNAL_API void macTxStartQueuedFrame(void);
MAC_INTERNAL_API void macTxChannelBusyCallback(void);
MAC_INTERNAL_API void macTxDoneCallback(void);
MAC_INTERNAL_API void macTxAckReceivedCallback(uint8 seqn, uint8 pendingFlag);
MAC_INTERNAL_API void macTxAckNotReceivedCallback(void);
MAC_INTERNAL_API void macTxTimestampCallback(void);
MAC_INTERNAL_API void macTxCollisionWithRxCallback(void);


我们对mac_tx.c文件中的函数作用有了一定的了解,然后我们去看mac_tx.c文件。当然我们的查看重点在于发送数据包的构建,对于该函数中有关timestamp的只有如下函数:



/**************************************************************************************************
 * @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();
}


这个函数的描述是“该回调函数记录时间戳到接受数据结构中”。到这我们可以非常清楚的知道afIncomingMSGPacket_t::timestamp是发送/接受数据包时系统定时器的溢出计数器的值。至于这个值到底是发送者的溢出计数器的值还是接受者的溢出计数器的值,我个人比较倾向于只是接受者接受到数据包时其系统定时器溢出计数器的值。我们可以通过发包含macMcuOverflowCapture()数据的数据包,然后在接受者接收时将3个数据显示出来查看。






本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

我们常常说到的操作系统有Linux、Windows、mac OS等等,手机的安卓系统就是基于Linux操作系统,这些操作系统从内核的角度分为宏内核和微内核,Linux是典型的宏内核的操作系统,Windows是典型的微内核...

关键字: Linux Windows mac

通过此次收购,Jellysmack扩展了其强大的内部AI技术套件,以更好地支持创作者。 洛杉矶2021年11月16日 /美通社/ -- 全球...

关键字: mac ck

cc2530和cc2430的比较

关键字: cc2430 cc2530

CC2530F256RHAR -RF收发器封装:QFN40

关键字: cc2530 封装

CC2530芯片的主要特性以及它的应用领域

关键字: cc2530 单片机

我想实现两个节点之间通信,不用Z-STACK,就用最简单的操作寄存器,实现节点1发送信息给节点2,节点2收到以后亮灯,节点1的代码如下:

关键字: cc2530 射频

【CC2530授课笔记】开发环境搭建 IAR 8.10 For 8051 安装教程

关键字: cc2530 教程

CC2530-最小系统搭建

关键字: cc2530 io口

CC2530 是用于2.4-GHz IEEE 802.15.4、ZigBee 和RF4CE 应用的一个真正的片上系统(SoC)解决方案。它能够以非常低的总的材料成本建立强大的网络节点。

关键字: cc2530 引脚

CC2530 是用于2.4-GHz IEEE 802.15.4、ZigBee 和RF4CE 应用的一个真正的片上系统(SoC)解决方案。它能够以非常低的总的材料成本建立强大的网络节点。

关键字: cc2530 单片机
关闭
关闭