当前位置:首页 > 芯闻号 > 充电吧
[导读]首先,在协议栈中应用层的事件处理函数都是通过 一个指向接收消息结构体的指针*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个数据显示出来查看。






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

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭