This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CC2652P:在SDK 5.40 中,如果终止APS-ACK时终端设备丢失父级,则AF_DATA_CONFIRM事件不会触发。 解决办法就是这样

Guru**** 2467600 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/wireless-connectivity/zigbee-thread-group/zigbee-and-thread/f/zigbee-thread-forum/1092052/cc2652p-in-sdk-5-40-if-end-device-lose-parent-when-waitting-aps-ack-af_data_confirm-event-will-not-trigger-the-solution-is-this

部件号:CC2652P

GitHub:  https://github.com/zigbee-luo/z_stack_2022.git

修复af.c.

/*********************************************************************
 * MACROS
 */
#ifndef NWK_MAX_DATABUFS_TOTAL
#define NWK_MAX_DATABUFS_TOTAL      24    // same with nwk_global.c, luoyiming 2022-04-08
#endif

/*********************************************************************
 * TYPEDEF
 */

typedef struct
{
  void* next;
  uint8_t endpoint;
  uint8_t transID;
  uint16_t clusterID;
  bool  apsAck;
  void* cnfParam;
  pfnAfCnfCB afCnfCB;
} afDataCnfList_t;

typedef struct
{
  uint8_t  endPoint;
  uint8_t  transID;
  uint16_t clusterID;
} afDataConfirmParam_t;

/*********************************************************************
 * @fn      afSend
 *
 * @brief   Helper macro for V1 API to invoke V2 API.
 *
 * input parameters
 *
 * @param  *dstAddr - Full ZB destination address: Nwk Addr + End Point.
 * @param   srcEP - Origination (i.e. respond to or ack to) End Point.
 * @param   cID - A valid cluster ID as specified by the Profile.
 * @param   len - Number of bytes of data pointed to by next param.
 * @param  *buf - A pointer to the data bytes to send.
 * @param   options - Valid bit mask of AF Tx Options as defined in af.h.
 * @param  *transID - A pointer to a byte which can be modified and which will
 *                    be used as the transaction sequence number of the msg.
 *
 * output parameters
 *
 * @param  *transID - Incremented by one if the return value is success.
 *
 * @return  afStatus_t - See previous definition of afStatus_... types.
 */
#define afSend( dstAddr, srcEP, cID, len, buf, transID, options, radius ) \
        AF_DataRequest( (dstAddr), afFindEndPointDesc( (srcEP) ), \
                          (cID), (len), (buf), (transID), (options), (radius) )

/*********************************************************************
 * GLOBAL VARIABLES
 */

epList_t *epList;

/*********************************************************************
 * LOCAL VARIABLES
 */

afDataCnfList_t *afDataCnfList;

/*********************************************************************
 * LOCAL FUNCTIONS
 */

static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
                zAddrType_t *SrcAddress, uint16_t SrcPanId, NLDE_Signal_t *sig,
                uint8_t nwkSeqNum, uint8_t SecurityUse, uint32_t timestamp, uint8_t radius );

static epList_t *afFindEndPointDescList( uint8_t EndPoint );

static pDescCB afGetDescCB( endPointDesc_t *epDesc );

static bool afAddCnfItem(afDataCnfList_t* cnfItem);

static afDataCnfList_t* afGetCnfItem(uint8_t endpoint, uint8_t transID);

static afDataCnfList_t* afFindCnfItem(uint8_t endpoint, uint8_t transID);

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      afInit
 *
 * @brief   Initialization function for the AF.
 *
 * @param   none
 *
 * @return  none
void afInit( void )
{
}
 */

/*********************************************************************
 * @fn      afRegisterExtended
 *
 * @brief   Register an Application's EndPoint description.
 *
 * @param   epDesc - pointer to the Application's endpoint descriptor.
 * @param   descFn - pointer to descriptor callback function
 * @param   applFn - pointer to the Application callback function
 *
 * NOTE:  The memory that epDesc is pointing to must exist after this call.
 *
 * @return  Pointer to epList_t on success, NULL otherwise.
 */
epList_t *afRegisterExtended( endPointDesc_t *epDesc, pDescCB descFn, pApplCB applFn )
{
  epList_t *ep = OsalPort_malloc(sizeof(epList_t));

  if (ep != NULL)
  {
    ep->nextDesc = epList;
    epList = ep;
    ep->epDesc = epDesc;
    ep->pfnDescCB = descFn;
    ep->apsfCfg.frameDelay = APSF_DEFAULT_INTERFRAME_DELAY;
    ep->apsfCfg.windowSize = APSF_DEFAULT_WINDOW_SIZE;
    ep->flags = eEP_AllowMatch;  // Default to allow Match Descriptor.
    ep->pfnApplCB = applFn;

  #if (BDB_FINDING_BINDING_CAPABILITY_ENABLED==1)
    //Make sure we add at least one application endpoint
    if ((epDesc->endPoint != 0)  && (epDesc->endPoint < BDB_ZIGBEE_RESERVED_ENDPOINTS_START))
    {
      bdb_HeadEpDescriptorList = epList;
      ep->epDesc->epType = bdb_zclFindingBindingEpType(ep->epDesc);
    }

  #endif
#if defined ( BDB_TL_INITIATOR ) || defined ( BDB_TL_TARGET )
    // find the first empty entry in the device info table
    for ( uint8_t i = 0; i < TOUCHLINK_NUM_DEVICE_INFO_ENTRIES; i++ )
    {
      if ( touchLinkSubDevicesTbl[i] == NULL )
      {
        touchLinkSubDevicesTbl[i] = OsalPort_malloc(sizeof(bdbTLDeviceInfo_t));
        if ( touchLinkSubDevicesTbl[i] != NULL )
        {
          touchLinkSubDevicesTbl[i]->deviceID = epDesc->simpleDesc->AppDeviceId;
          touchLinkSubDevicesTbl[i]->endpoint = epDesc->simpleDesc->EndPoint;
          touchLinkSubDevicesTbl[i]->profileID = epDesc->simpleDesc->AppProfId;
          touchLinkSubDevicesTbl[i]->version = epDesc->simpleDesc->AppDevVer;
          break;
        }
      }
    }
#endif  // BDB_TL_INITIATOR || BDB_TL_TARGET
  }

  return ep;
}

/*********************************************************************
 * @fn      afRegister
 *
 * @brief   Register an Application's EndPoint description.
 *
 * @param   epDesc - pointer to the Application's endpoint descriptor.
 *
 * NOTE:  The memory that epDesc is pointing to must exist after this call.
 *
 * @return  afStatus_SUCCESS - Registered
 *          afStatus_MEM_FAIL - not enough memory to add descriptor
 *          afStatus_INVALID_PARAMETER - duplicate endpoint
 */
afStatus_t afRegister( endPointDesc_t *epDesc )
{
  if (afFindEndPointDescList(epDesc->endPoint))  // Look for duplicate endpoint.
  {
    return afStatus_INVALID_PARAMETER;
  }

  return ((NULL == afRegisterExtended(epDesc, NULL, NULL)) ? afStatus_MEM_FAIL : afStatus_SUCCESS);
}

/*********************************************************************
 * @fn      afDelete
 *
 * @brief   Delete an Application's EndPoint descriptor and frees the memory
 *
 * @param   EndPoint - Application Endpoint to delete
 *
 * @return  afStatus_SUCCESS - endpoint deleted
 *          afStatus_INVALID_PARAMETER - endpoint not found
 *          afStatus_FAILED - endpoint list empty
 */
afStatus_t afDelete( uint8_t EndPoint )
{
  epList_t *epCurrent;
  epList_t *epPrevious;

  if ( epList != NULL )
  {
    epPrevious = epCurrent = epList;

    // first element of the list matches
    if ( epCurrent->epDesc->endPoint == EndPoint )
    {
      epList = epCurrent->nextDesc;
      OsalPort_free( epCurrent );

      return ( afStatus_SUCCESS );
    }
    else
    {
      // search the list
      for ( epCurrent = epPrevious->nextDesc;
            epCurrent != NULL;
            epCurrent = epCurrent->nextDesc )
      {
        if ( epCurrent->epDesc->endPoint == EndPoint )
        {
          epPrevious->nextDesc = epCurrent->nextDesc;
          OsalPort_free( epCurrent );

          // delete the entry and free the memory
          return ( afStatus_SUCCESS );
        }
        epPrevious = epCurrent;
      }
    }

    // no endpoint found
    return ( afStatus_INVALID_PARAMETER );
  }
  else
  {
    // epList is empty
    return ( afStatus_FAILED );
  }
}

/*********************************************************************
 * @fn          afDataConfirm
 *
 * @brief       This function will generate the Data Confirm back to
 *              the application.
 *
 * @param       endPoint - confirm end point
 * @param       transID - transaction ID from APSDE_DATA_REQUEST
 * @param       status - status of APSDE_DATA_REQUEST
 *
 * @return      none
 */
void afDataConfirm( uint8_t endPoint, uint8_t transID, uint16_t clusterID, ZStatus_t status )
{
  endPointDesc_t *epDesc;
  afDataConfirm_t *msgPtr;
  
  //get the confirm callbakck and run
  pfnAfCnfCB afCnfCB = NULL;
  void* cnfParam = NULL;
  afDataCnfList_t* cnfItem = afGetCnfItem( endPoint, transID );
  if(cnfItem)
  {
    afCnfCB = cnfItem->afCnfCB;
    cnfParam = cnfItem->cnfParam;
    OsalPort_free(cnfItem);
  }

  // Find the endpoint description
  epDesc = afFindEndPointDesc( endPoint );
  if ( epDesc == NULL )
    return;

  // Determine the incoming command type
  msgPtr = (afDataConfirm_t *)OsalPort_msgAllocate( sizeof(afDataConfirm_t) );
  if ( msgPtr )
  {
    // Build the Data Confirm message
    msgPtr->hdr.event = AF_DATA_CONFIRM_CMD;
    msgPtr->hdr.status = status;
    msgPtr->endpoint = endPoint;
    msgPtr->clusterID = clusterID;
    msgPtr->transID = transID;
    //add new menber for confirm
    msgPtr->afCnfCB = afCnfCB;
    msgPtr->cnfParam = cnfParam;

#if defined ( MT_AF_CB_FUNC )
    /* If MT has subscribed for this callback, don't send as a message. */
    if ( AFCB_CHECK(CB_ID_AF_DATA_CNF,*(epDesc->task_id)) )
    {
      /* Send callback if it's subscribed */
      MT_AfDataConfirm ((void *)msgPtr);
      /* Release the memory. */
      OsalPort_msgDeallocate( (void *)msgPtr );
    }
    else
#endif
    {
      /* send message through task message */
      OsalPort_msgSend( *(epDesc->task_id), (uint8_t *)msgPtr );
    }
  }
}

/*********************************************************************
 * @fn          afReflectError
 *
 * @brief       This function will generate the Reflect Error message to
 *              the application.
 *
 * @param       srcEP - Source Endpoint
 * @param       dstAddrMode - mode of dstAdd - 0 - normal short addr, 1 - group Address
 * @param       dstAddr - intended destination
 * @param       dstEP - Destination Endpoint
 * @param       transID - transaction ID from APSDE_DATA_REQUEST
 * @param       status - status of APSDE_DATA_REQUEST
 *
 * @return      none
 */
void afReflectError( uint8_t srcEP, uint8_t dstAddrMode, uint16_t dstAddr, uint8_t dstEP,
                     uint8_t transID, ZStatus_t status )
{
  endPointDesc_t *epDesc;
  afReflectError_t *msgPtr;

  //get the confirm param
  void* cnfParam = NULL;
  afDataCnfList_t* cnfFind = afFindCnfItem(srcEP, transID);
  if(cnfFind)
  {
    cnfParam = cnfFind->cnfParam;
  }

  // Find the endpoint description
  epDesc = afFindEndPointDesc( srcEP );
  if ( epDesc == NULL )
    return;

  // Determine the incoming command type
  msgPtr = (afReflectError_t *)OsalPort_msgAllocate( sizeof(afReflectError_t) );
  if ( msgPtr )
  {
    // Build the Data Confirm message
    msgPtr->hdr.event = AF_REFLECT_ERROR_CMD;
    msgPtr->hdr.status = status;
    msgPtr->endpoint = srcEP;       //As the error is internal the dst endpoint is the endpoint generating the frame (srcEp)
    msgPtr->transID = transID;
    msgPtr->dstAddrMode = dstAddrMode;
    msgPtr->dstAddr = dstAddr;
    msgPtr->dstEP = dstEP;
    msgPtr->cnfParam = cnfParam;

#if defined ( MT_AF_CB_FUNC )
    /* If MT has subscribed for this callback, don't send as a message. */
    if ( AFCB_CHECK( CB_ID_AF_REFLECT_ERROR, *(epDesc->task_id) ) )
    {
      /* Send callback if it's subscribed */
      MT_AfReflectError( (void *)msgPtr );
      /* Release the memory. */
      OsalPort_msgDeallocate( (void *)msgPtr );
    }
    else
#endif
    {
      /* send message through task message */
      OsalPort_msgSend( *(epDesc->task_id), (uint8_t *)msgPtr );
    }
  }
}

/*********************************************************************
 * @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.
 * @param       radius - incoming messages received radius
 *
 * @return      none
 */
void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16_t SrcPanId,
                     NLDE_Signal_t *sig, uint8_t nwkSeqNum, uint8_t SecurityUse,
                     uint32_t timestamp, uint8_t radius )
{
  endPointDesc_t *epDesc = NULL;
  epList_t *pList = epList;
#if !defined ( APS_NO_GROUPS )
  uint8_t 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_t epProfileID = 0xFFFE;  // Invalid Profile ID

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

    // First part of verification is to make sure that:
    // the local Endpoint ProfileID matches the received ProfileID OR
    // the message is specifically send to ZDO (this excludes the broadcast endpoint) OR
    // if the Wildcard ProfileID is received the message should not be sent to ZDO endpoint
    if ( (aff->ProfileID == epProfileID) ||
         ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) ||
         ((epDesc->endPoint != ZDO_EP) && ( aff->ProfileID == ZDO_WILDCARD_PROFILE_ID )) )
    {
      // Save original endpoint
      uint8_t endpoint = aff->DstEndPoint;

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

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

      // 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;
  }
}

/*********************************************************************
 * @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_t SrcPanId, NLDE_Signal_t *sig,
                 uint8_t nwkSeqNum, uint8_t SecurityUse, uint32_t timestamp, uint8_t radius )
{
  afIncomingMSGPacket_t *MSGpkt;
  const uint8_t len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;
  uint8_t *asdu = aff->asdu;
  MSGpkt = (afIncomingMSGPacket_t *)OsalPort_msgAllocate( 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->macSrcAddr = aff->macSrcAddr;
  MSGpkt->macDestAddr = aff->macDestAddr;
  MSGpkt->srcAddr.panId = SrcPanId;
  MSGpkt->cmd.DataLength = aff->asduLength;
  MSGpkt->radius = radius;

  if ( MSGpkt->cmd.DataLength )
  {
    MSGpkt->cmd.Data = (uint8_t *)(MSGpkt + 1);
    OsalPort_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.
    OsalPort_msgDeallocate( (void *)MSGpkt );
  }
  else
#endif
  {
    // Send message through task message.
    OsalPort_msgSend( *(epDesc->task_id), (uint8_t *)MSGpkt );
  }
}

/*********************************************************************
 * @fn      AF_DataRequest
 *
 * @brief   Common functionality for invoking APSDE_DataReq() for both
 *          SendMulti and MSG-Send.
 *
 * input parameters
 *
 * @param  *dstAddr - Full ZB destination address: Nwk Addr + End Point.
 * @param  *srcEP - Origination (i.e. respond to or ack to) End Point Descr.
 * @param   cID - A valid cluster ID as specified by the Profile.
 * @param   len - Number of bytes of data pointed to by next param.
 * @param  *buf - A pointer to the data bytes to send.
 * @param  *transID - A pointer to a byte which can be modified and which will
 *                    be used as the transaction sequence number of the msg.
 * @param   options - Valid bit mask of Tx options.
 * @param   radius - Normally set to AF_DEFAULT_RADIUS.
 * @param   afCnfCB - Callback function for data confirm
 * @param   cnfParam - Parameter of data confirm callback function
 *
 * output parameters
 *
 * @param  *transID - Incremented by one if the return value is success.
 *
 * @return  afStatus_t - See previous definition of afStatus_... types.
 */
uint8_t AF_DataRequestDiscoverRoute = DISC_ROUTE_NETWORK;
afStatus_t AF_DataRequestExt( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                              uint16_t cID, uint16_t len, uint8_t *buf, uint8_t *transID,
                              uint8_t options, uint8_t radius, pfnAfCnfCB afCnfCB, void* cnfParam )
{
  pDescCB pfnDescCB;
  ZStatus_t stat;
  APSDE_DataReq_t req;
  afDataReqMTU_t mtu;
  epList_t *pList;
  //confirm param
  afDataCnfList_t* cnfItem = NULL;

  // Verify source end point
  if ( srcEP == NULL )
  {
    return afStatus_INVALID_PARAMETER;
  }
  
  // Match end point and trans ID if are busy, luoyiming fixed at 2021-09-02
  if ( afFindCnfItem( srcEP->endPoint, *transID ) != NULL )
  {
    return afStatus_INVALID_PARAMETER;
  }

  // copy the addressing mode, to get the length of the packet
  mtu.aps.addressingMode = dstAddr->addrMode;

  // Check if route is available before sending data
  if ( options & AF_LIMIT_CONCENTRATOR  )
  {
    if ( dstAddr->addrMode != afAddr16Bit )
    {
      return ( afStatus_INVALID_PARAMETER );
    }

    // First, make sure the destination is not its self, then check for an existing route.
    if ( (dstAddr->addr.shortAddr != NLME_GetShortAddr())
        && (RTG_CheckRtStatus( dstAddr->addr.shortAddr, RT_ACTIVE, (MTO_ROUTE | NO_ROUTE_CACHE) ) != RTG_SUCCESS) )
    {
      // A valid route to a concentrator wasn't found
      return ( afStatus_NO_ROUTE );
    }
  }

  // Validate broadcasting
  if ( ( dstAddr->addrMode == afAddr16Bit     ) ||
       ( dstAddr->addrMode == afAddrBroadcast )    )
  {
    // Check for valid broadcast values
    if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr )  )
    {
      // Force mode to broadcast
      dstAddr->addrMode = afAddrBroadcast;
    }
    else
    {
      // Address is not a valid broadcast type
      if ( dstAddr->addrMode == afAddrBroadcast )
      {
        return afStatus_INVALID_PARAMETER;
      }
    }
  }
  else if ( dstAddr->addrMode != afAddr64Bit &&
            dstAddr->addrMode != afAddrGroup &&
            dstAddr->addrMode != afAddrNotPresent )
  {
    return afStatus_INVALID_PARAMETER;
  }

  // Set destination address
  req.dstAddr.addrMode = dstAddr->addrMode;
  if ( dstAddr->addrMode == afAddr64Bit )
  {
    osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr );
  }
  else
  {
    req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr;
  }

  // This option is to use Wildcard ProfileID in outgoing packets
  if ( options & AF_WILDCARD_PROFILEID )
  {
    req.profileID = ZDO_WILDCARD_PROFILE_ID;
  }
  else
  {
    req.profileID = ZDO_PROFILE_ID;

    if ( (pfnDescCB = afGetDescCB( srcEP )) )
    {
      uint16_t *pID = (uint16_t *)(pfnDescCB(
                                   AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint ));
      if ( pID )
      {
        req.profileID = *pID;
        OsalPort_free( pID );
      }
    }
    else if ( srcEP->simpleDesc )
    {
      req.profileID = srcEP->simpleDesc->AppProfId;
    }
  }

  req.txOptions = 0;

  if ( ( options & AF_ACK_REQUEST              ) &&
       ( req.dstAddr.addrMode != AddrBroadcast ) &&
       ( req.dstAddr.addrMode != AddrGroup     )    )
  {
    req.txOptions |=  APS_TX_OPTIONS_ACK;
  }

  if ( options & AF_SKIP_ROUTING )
  {
    req.txOptions |=  APS_TX_OPTIONS_SKIP_ROUTING;
  }

  if ( options & AF_EN_SECURITY )
  {
    req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE;
    mtu.aps.secure = TRUE;
  }
  else
  {
    mtu.aps.secure = FALSE;
  }

  if ( options & AF_PREPROCESS )
  {
    req.txOptions |=  APS_TX_OPTIONS_PREPROCESS;
  }

  mtu.kvp = FALSE;

  if ( options & AF_SUPRESS_ROUTE_DISC_NETWORK )
  {
    req.discoverRoute = DISC_ROUTE_INITIATE;
  }
  else
  {
    req.discoverRoute = AF_DataRequestDiscoverRoute;
  }

  req.transID       = *transID;
  req.srcEP         = srcEP->endPoint;
  req.dstEP         = dstAddr->endPoint;
  req.clusterID     = cID;
  req.asduLen       = len;
  req.asdu          = buf;
  req.radiusCounter = radius;
#if defined ( INTER_PAN ) || defined ( BDB_TL_INITIATOR ) || defined ( BDB_TL_TARGET )
  req.dstPanId      = dstAddr->panId;
#endif // INTER_PAN || BDB_TL_INITIATOR || BDB_TL_TARGET

  //set confirm callback and confirm param before send, add by luoyiming
  if( ( afCnfCB ) || ( cnfParam ) )
  {
    cnfItem = OsalPort_malloc( sizeof(afDataCnfList_t) );
    if( cnfItem == NULL )
    {
      return afStatus_MEM_FAIL;
    }
    //add confirm callback and param into queue, fix by luoyiming 2019-3-11
    cnfItem->endpoint = req.srcEP;
    cnfItem->transID  = req.transID;
    cnfItem->clusterID = req.clusterID;
    cnfItem->afCnfCB  = afCnfCB;
    cnfItem->cnfParam = cnfParam;
    if( req.txOptions &  APS_TX_OPTIONS_ACK )
    {
      cnfItem->apsAck = true;
    }
    afAddCnfItem( cnfItem );
  }

  // Look if there is a Callback function registered for this endpoint
  // The callback is used to control the AF Transaction ID used when sending messages
  pList = afFindEndPointDescList( srcEP->endPoint );

  if ( ( pList != NULL ) && ( pList->pfnApplCB != NULL ) )
  {
    pList->pfnApplCB( &req );
  }

#if defined ( INTER_PAN ) || defined ( BDB_TL_INITIATOR ) || defined ( BDB_TL_TARGET )
  if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) )
  {
    if ( len > INTERP_DataReqMTU() )
    {
      stat = afStatus_INVALID_PARAMETER;
    }
    else
    {
      stat = INTERP_DataReq( &req );
    }
  }
  else
#endif // INTER_PAN || BDB_TL_INITIATOR || BDB_TL_TARGET
  {
    if (len > afDataReqMTU( &mtu ) )
    {
      if (apsfSendFragmented)
      {
        stat = (*apsfSendFragmented)( &req );
      }
      else
      {
        stat = afStatus_INVALID_PARAMETER;
      }
    }
    else
    {
      stat = APSDE_DataReq( &req );
    }
  }

  //release confirm message if send fail
  if( stat!= afStatus_SUCCESS )
  {
    afDataCnfList_t* item = afGetCnfItem( req.srcEP, req.transID );
    if( item != NULL ) //only free for valid pointer, fix by luoyiming 2019-05-14.
    {
      OsalPort_free( item );
    }
  }

  /*
   * If this is an EndPoint-to-EndPoint message on the same device, it will not
   * get added to the NWK databufs. So it will not go OTA and it will not get
   * a MACCB_DATA_CONFIRM_CMD callback. Thus it is necessary to generate the
   * AF_DATA_CONFIRM_CMD here. Note that APSDE_DataConfirm() only generates one
   * message with the first in line TransSeqNumber, even on a multi message.
   * Also note that a reflected msg will not have its confirmation generated
   * here.
   */
  if ( (req.dstAddr.addrMode == Addr16Bit) &&
       (req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) &&
       (stat == afStatus_SUCCESS) ) //if APSDE_DataReq return not success, don't trigger afDataComfirm, add by luoyiming 2019-10-27.
  {
    afDataConfirm( srcEP->endPoint, *transID, cID, stat );
  }

  if ( stat == afStatus_SUCCESS )
  {
    (*transID)++;
  }

  return (afStatus_t)stat;
}

/**************************************************************************************************
 * @fn          afStopConfirmWaitting
 *
 * @brief       stop confirm waitting when orphan. luoyiming add at 2022-04-08
 *
 * input parameters
 *
 * @param       none
 *
 * None.
 *
 * @return      none
 */
void afStopConfirmWaitting( void )
{
  afDataConfirmParam_t tmpBuf[NWK_MAX_DATABUFS_TOTAL] = {0};
  uint8_t num = 0;
  uint8_t n;
  afDataCnfList_t* find = afDataCnfList;

  // find the aps-ack enabled item, luoyiming 2022-04-08
  while( find )
  {
    if( find->apsAck )
    {
      tmpBuf[num].endPoint = find->endpoint;
      tmpBuf[num].transID = find->transID;
      tmpBuf[num].clusterID = find->transID;
      num ++;
    }
    find = find->next;
  }

  // call aps-ack enabled item, luoyiming 2022-04-08
  for( n = 0; n < num; n++ )
  {
    afDataConfirm(tmpBuf[n].endPoint, tmpBuf[n].transID, tmpBuf[n].clusterID, ZNwkNoNetworks);
  }
}

/**************************************************************************************************
 * @fn          afAddCnfItem
 *
 * @brief       add a data confirm callback function into data confirm list.
 *
 * input parameters
 *
 * @param       cbItem - a callback function with its parameter.
 *
 * output parameters
 *
 * None.
 *
 * @return      TRUE if success, FALSE if add list fail
 */
static bool afAddCnfItem( afDataCnfList_t* cnfItem )
{
  if( NULL != cnfItem )
  {
    cnfItem->next = NULL;
    if( NULL == afDataCnfList )
    {
      afDataCnfList = cnfItem;
    }
    else
    {
      afDataCnfList_t* findEnd = afDataCnfList;
      while( findEnd->next )
      {
        findEnd = findEnd->next;
      }
      findEnd->next = cnfItem;
    }
    return TRUE;
  }
  return FALSE;
}

/**************************************************************************************************
 * @fn          afGetCnfItem
 *
 * @brief       get the callback fuction from confirm list with transID an Endpoint, the found item
 *              will be removed from list.
 *
 * input parameters
 *
 * @param       endpoint - filt callback function by endpoint.
 * @param       transID - filt callback function by transID.
 *
 * output parameters
 *
 * None.
 *
 * @return      callback function item form data confirm list
 */
static afDataCnfList_t* afGetCnfItem( uint8_t endpoint, uint8_t transID )
{
  afDataCnfList_t* find = afDataCnfList;
  afDataCnfList_t* pre = NULL;
  while(find)
  {
    if( (endpoint == find->endpoint) && (transID == find->transID) )
    {
      if(pre)
      {
        pre->next = find->next;
      }
      else
      {
        afDataCnfList = afDataCnfList->next;
      }
      break;
    }
    pre = find;
    find = pre->next;
  }
  return find;
}

/**************************************************************************************************
 * @fn          afFindCnfItem
 *
 * @brief       find the param pointer in confirm list with transID an Endpoint, the found item 
 *              won't be removed.
 *
 * input parameters
 *
 * @param       endpoint - filt callback function by endpoint.
 * @param       transID - filt callback function by transID.
 *
 * output parameters
 *
 * None.
 *
 * @return      confirm callback & param item form data confirm list
 */
static afDataCnfList_t* afFindCnfItem( uint8_t endpoint, uint8_t transID )
{
  afDataCnfList_t* find = afDataCnfList;
  while(find)
  {
    if( (endpoint == find->endpoint) && (transID == find->transID) )
    {
      return find;
    }
    find = find->next;
  }
  return NULL;
}

/*********************************************************************
 * @fn      AF_DataRequestSrcRtg
 *
 * @brief   Common functionality for invoking APSDE_DataReq() for both
 *          SendMulti and MSG-Send.
 *
 * input parameters
 *
 * @param  *dstAddr - Full ZB destination address: Nwk Addr + End Point.
 * @param  *srcEP - Origination (i.e. respond to or ack to) End Point Descr.
 * @param   cID - A valid cluster ID as specified by the Profile.
 * @param   len - Number of bytes of data pointed to by next param.
 * @param  *buf - A pointer to the data bytes to send.
 * @param  *transID - A pointer to a byte which can be modified and which will
 *                    be used as the transaction sequence number of the msg.
 * @param   options - Valid bit mask of Tx options.
 * @param   radius - Normally set to AF_DEFAULT_RADIUS.
 * @param   relayCnt - Number of devices in the relay list
 * @param   pRelayList - Pointer to the relay list
 * @param   afCnfCB - Callback function for data confirm
 * @param   cnfParam - Parameter of data confirm callback function
 *
 * output parameters
 *
 * @param  *transID - Incremented by one if the return value is success.
 *
 * @return  afStatus_t - See previous definition of afStatus_... types.
 */

afStatus_t AF_DataRequestSrcRtgExt( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16_t cID,
                                   uint16_t len, uint8_t *buf, uint8_t *transID, uint8_t options, uint8_t radius,
                                   uint8_t relayCnt, uint16_t* pRelayList, pfnAfCnfCB afCnfCB, void* cnfParam )
{
  uint8_t status;

  /* Add the source route to the source routing table */
  status = RTG_AddSrcRtgEntry_Guaranteed( dstAddr->addr.shortAddr, relayCnt,
                                         pRelayList );

  if( status == RTG_SUCCESS)
  {
    /* Call AF_DataRequest to send the data */
    status = AF_DataRequestExt( dstAddr, srcEP, cID, len, buf, transID, options, radius, afCnfCB, cnfParam );
  }
  else if( status == RTG_INVALID_PATH )
  {
    /* The source route relay count is exceeding the network limit */
    status = afStatus_INVALID_PARAMETER;
  }
  else
  {
    /* The guaranteed adding entry fails due to memory failure */
    status = afStatus_MEM_FAIL;
  }
  return status;
}

/*********************************************************************
 * @fn      afFindEndPointDescList
 *
 * @brief   Find the endpoint description entry from the endpoint
 *          number.
 *
 * @param   EndPoint - Application Endpoint to look for
 *
 * @return  the address to the endpoint/interface description entry
 */
static epList_t *afFindEndPointDescList( uint8_t EndPoint )
{
  epList_t *epSearch;

  for (epSearch = epList; epSearch != NULL; epSearch = epSearch->nextDesc)
  {
    if (epSearch->epDesc->endPoint == EndPoint)
    {
      break;
    }
  }

  return epSearch;
}

/*********************************************************************
 * @fn      afFindEndPointDesc
 *
 * @brief   Find the endpoint description entry from the endpoint
 *          number.
 *
 * @param   EndPoint - Application Endpoint to look for
 *
 * @return  the address to the endpoint/interface description entry
 */
endPointDesc_t *afFindEndPointDesc( uint8_t EndPoint )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( EndPoint );

  if ( epSearch )
    return ( epSearch->epDesc );
  else
    return ( (endPointDesc_t *)NULL );
}

/*********************************************************************
 * @fn      afFindSimpleDesc
 *
 * @brief   Find the Simple Descriptor from the endpoint number.
 *
 * @param   EP - Application Endpoint to look for.
 *
 * @return  Non-zero to indicate that the descriptor memory must be freed.
 */
uint8_t afFindSimpleDesc( SimpleDescriptionFormat_t **ppDesc, uint8_t EP )
{
  epList_t *epItem = afFindEndPointDescList( EP );
  uint8_t rtrn = FALSE;

  if ( epItem )
  {
    if ( epItem->pfnDescCB )
    {
      *ppDesc = epItem->pfnDescCB( AF_DESCRIPTOR_SIMPLE, EP );
      rtrn = TRUE;
    }
    else
    {
      *ppDesc = epItem->epDesc->simpleDesc;
    }
  }
  else
  {
    *ppDesc = NULL;
  }

  return rtrn;
}

/*********************************************************************
 * @fn      afGetDescCB
 *
 * @brief   Get the Descriptor callback function.
 *
 * @param   epDesc - pointer to the endpoint descriptor
 *
 * @return  function pointer or NULL
 */
static pDescCB afGetDescCB( endPointDesc_t *epDesc )
{
  epList_t *epSearch;

  // Start at the beginning
  epSearch = epList;

  // Look through the list until the end
  while ( epSearch )
  {
    // Is there a match?
    if ( epSearch->epDesc == epDesc )
    {
      return ( epSearch->pfnDescCB );
    }
    else
      epSearch = epSearch->nextDesc;  // Next entry
  }

  return ( (pDescCB)NULL );
}

/*********************************************************************
 * @fn      afDataReqMTU
 *
 * @brief   Get the Data Request MTU(Max Transport Unit).
 *
 * @param   fields - afDataReqMTU_t
 *
 * @return  uint8_t(MTU)
 */
uint8_t afDataReqMTU( afDataReqMTU_t* fields )
{
  uint8_t len;
  uint8_t hdr;

  if ( fields->kvp == TRUE )
  {
    hdr = AF_HDR_KVP_MAX_LEN;
  }
  else
  {
    hdr = AF_HDR_V1_1_MAX_LEN;
  }

  len = (uint8_t)(APSDE_DataReqMTU(&fields->aps) - hdr);

  return len;
}

/*********************************************************************
 * @fn      afGetMatch
 *
 * @brief   Set the allow response flag.
 *
 * @param   ep - Application Endpoint to look for
 * @param   action - true - allow response, false - no response
 *
 * @return  TRUE allow responses, FALSE no response
 */
uint8_t afGetMatch( uint8_t ep )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( ep );

  if ( epSearch )
  {
    if ( epSearch->flags & eEP_AllowMatch )
      return ( TRUE );
    else
      return ( FALSE );
  }
  else
    return ( FALSE );
}

/*********************************************************************
 * @fn      afSetMatch
 *
 * @brief   Set the allow response flag.
 *
 * @param   ep - Application Endpoint to look for
 * @param   action - true - allow response, false - no response
 *
 * @return  TRUE if success, FALSE if endpoint not found
 */
uint8_t afSetMatch( uint8_t ep, uint8_t action )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( ep );

  if ( epSearch )
  {
    if ( action )
    {
      epSearch->flags |= eEP_AllowMatch;
    }
    else
    {
      epSearch->flags &= (eEP_AllowMatch ^ 0xFFFF);
    }
    return ( TRUE );
  }
  else
    return ( FALSE );
}

/*********************************************************************
 * @fn      afNumEndPoints
 *
 * @brief   Returns the number of endpoints defined (including 0)
 *
 * @param   none
 *
 * @return  number of endpoints
 */
uint8_t afNumEndPoints( void )
{
  epList_t *epSearch;
  uint8_t endpoints;

  // Start at the beginning
  epSearch = epList;
  endpoints = 0;

  while ( epSearch )
  {
    endpoints++;
    epSearch = epSearch->nextDesc;
  }

  return ( endpoints );
}

/*********************************************************************
 * @fn      afEndPoints
 *
 * @brief   Fills in the passed in buffer with the endpoint (numbers).
 *          Use afNumEndPoints to find out how big a buffer to supply.
 *
 * @param   epBuf - pointer to mem used
 *
 * @return  void
 */
void afEndPoints( uint8_t *epBuf, uint8_t skipZDO )
{
  epList_t *epSearch;
  uint8_t endPoint;

  // Start at the beginning
  epSearch = epList;

  while ( epSearch )
  {
    endPoint = epSearch->epDesc->endPoint;

    if ( !skipZDO || endPoint != 0 )
      *epBuf++ = endPoint;

    epSearch = epSearch->nextDesc;
  }
}

/*********************************************************************
 * @fn      afCopyAddress
 *
 * @brief   Fills in the passed in afAddrType_t parameter with the corresponding information
 *          from the zAddrType_t parameter.
 *
 * @param   epBuf - pointer to mem used
 *
 * @return  void
 */
void afCopyAddress( afAddrType_t *afAddr, zAddrType_t *zAddr )
{
  afAddr->addrMode = (afAddrMode_t)zAddr->addrMode;
  if ( zAddr->addrMode == Addr64Bit )
  {
    (void)osal_cpyExtAddr( afAddr->addr.extAddr, zAddr->addr.extAddr );
  }
  else
  {
    afAddr->addr.shortAddr = zAddr->addr.shortAddr;
  }

  // Since zAddrType_t has no INTER-PAN information, set the panId member to zero.
  afAddr->panId = 0;
}

/**************************************************************************************************
 * @fn          afAPSF_ConfigGet
 *
 * @brief       This function ascertains the fragmentation configuration that corresponds to
 *              the specified EndPoint.
 *
 * input parameters
 *
 * @param       endPoint - The source EP of a Tx or destination EP of a Rx fragmented message.
 *
 * output parameters
 *
 * @param       pCfg - A pointer to an APSF configuration structure to fill with values.
 *
 * @return      None.
 */
void afAPSF_ConfigGet(uint8_t endPoint, afAPSF_Config_t *pCfg)
{
  epList_t *pList = afFindEndPointDescList(endPoint);

  if (pList == NULL)
  {
    pCfg->frameDelay = APSF_DEFAULT_INTERFRAME_DELAY;
    pCfg->windowSize = APSF_DEFAULT_WINDOW_SIZE;
  }
  else
  {
    (void)OsalPort_memcpy(pCfg, &pList->apsfCfg, sizeof(afAPSF_Config_t));
  }
}

/**************************************************************************************************
 * @fn          afAPSF_ConfigSet
 *
 * @brief       This function attempts to set the fragmentation configuration that corresponds to
 *              the specified EndPoint.
 *
 * input parameters
 *
 * @param       endPoint - The specific EndPoint for which to set the fragmentation configuration.
 * @param       pCfg - A pointer to an APSF configuration structure to fill with values.
 *
 * output parameters
 *
 * None.
 *
 * @return      afStatus_SUCCESS for success.
 *              afStatus_INVALID_PARAMETER if the specified EndPoint is not registered.
 */
afStatus_t afAPSF_ConfigSet(uint8_t endPoint, afAPSF_Config_t *pCfg)
{
  epList_t *pList = afFindEndPointDescList(endPoint);

  if (pList == NULL)
  {
    return afStatus_INVALID_PARAMETER;
  }

  (void)OsalPort_memcpy(&pList->apsfCfg, pCfg, sizeof(afAPSF_Config_t));
  return afStatus_SUCCESS;
}

/**************************************************************************************************
 * @fn          afSetApplCB
 *
 * @brief       Sets the pointer to the Application Callback function for a
 *              specific EndPoint.
 *
 * input parameters
 *
 * @param       endPoint - The specific EndPoint for which to set Application Callback.
 * @param       pApplFn - A pointer to the Application Callback function.
 *
 * output parameters
 *
 * None.
 *
 * @return      TRUE if success, FALSE if endpoint not found
 */
uint8_t afSetApplCB( uint8_t endPoint, pApplCB pApplFn )
{
  if ( pApplFn != NULL )
  {
    epList_t *epSearch;

    // Look for the endpoint
    epSearch = afFindEndPointDescList( endPoint );

    if ( epSearch )
    {
      epSearch->pfnApplCB = pApplFn;

      return ( TRUE );
    }
  }

  return ( FALSE );
}

修复af.h

#define AF_BROADCAST_ENDPOINT              0xFF

#define AF_WILDCARD_PROFILEID              0x02   // Will force the message to use Wildcard ProfileID
#define AF_PREPROCESS                      0x04   // Will force APS to callback to preprocess before calling NWK layer
#define AF_LIMIT_CONCENTRATOR              0x08
#define AF_ACK_REQUEST                     0x10
#define AF_SUPRESS_ROUTE_DISC_NETWORK      0x20   // Supress Route Discovery for intermediate routes
                                                  // (route discovery preformed for initiating device)
#define AF_EN_SECURITY                     0x40
#define AF_SKIP_ROUTING                    0x80

#define AF_DISCV_ROUTE                     0x00   // This option is no longer available, and is included for backwards compatibility

// Backwards support for afAddOrSendMessage / afFillAndSendMessage.
#define AF_TX_OPTIONS_NONE                 0
#define AF_MSG_ACK_REQUEST                 AF_ACK_REQUEST

// Default Radius Count value
#define AF_DEFAULT_RADIUS                  DEF_NWK_RADIUS

/*********************************************************************
 * Node Descriptor
 */
#define AF_MAX_USER_DESCRIPTOR_LEN         16
#define AF_USER_DESCRIPTOR_FILL          0x20
typedef struct
{
  uint8_t len;     // Length of string descriptor
  uint8_t desc[AF_MAX_USER_DESCRIPTOR_LEN];
} UserDescriptorFormat_t;

// Node Logical Types
#define NODETYPE_COORDINATOR    0x00
#define NODETYPE_ROUTER         0x01
#define NODETYPE_DEVICE         0x02

// Node Frequency Band - bit map
#define NODEFREQ_800            0x01    // 868 - 868.6 MHz
#define NODEFREQ_900            0x04    // 902 - 928 MHz
#define NODEFREQ_2400           0x08    // 2400 - 2483.5 MHz

// Node MAC Capabilities - bit map
//   Use CAPINFO_ALTPANCOORD, CAPINFO_DEVICETYPE_FFD,
//       CAPINFO_DEVICETYPE_RFD, CAPINFO_POWER_AC,
//       and CAPINFO_RCVR_ON_IDLE from nl_mede.h

// Node Descriptor format structure
typedef struct
{
  uint8_t LogicalType:3;
  uint8_t ComplexDescAvail:1;  /* AF_V1_SUPPORT - reserved bit. */
  uint8_t UserDescAvail:1;     /* AF_V1_SUPPORT - reserved bit. */
  uint8_t Reserved:3;
  uint8_t APSFlags:3;
  uint8_t FrequencyBand:5;
  uint8_t CapabilityFlags;
  uint8_t ManufacturerCode[2];
  uint8_t MaxBufferSize;
  uint8_t MaxInTransferSize[2];
  uint16_t ServerMask;
  uint8_t MaxOutTransferSize[2];
  uint8_t DescriptorCapability;
} NodeDescriptorFormat_t;

// Bit masks for the ServerMask.
#define PRIM_TRUST_CENTER        0x01
#define BKUP_TRUST_CENTER        0x02
#define PRIM_BIND_TABLE          0x04
#define BKUP_BIND_TABLE          0x08
#define PRIM_DISC_TABLE          0x10
#define BKUP_DISC_TABLE          0x20
#define NETWORK_MANAGER          0x40


/*********************************************************************
 * Node Power Descriptor
 */

// Node Current Power Modes (CURPWR)
// Receiver permanently on or sync with coordinator beacon.
#define NODECURPWR_RCVR_ALWAYS_ON   0x00
// Receiver automatically comes on periodically as defined by the
// Node Power Descriptor.
#define NODECURPWR_RCVR_AUTO        0x01
// Receiver comes on when simulated, eg by a user pressing a button.
#define NODECURPWR_RCVR_STIM        0x02

// Node Available Power Sources (AVAILPWR) - bit map
//   Can be used for AvailablePowerSources or CurrentPowerSource
#define NODEAVAILPWR_MAINS          0x01  // Constant (Mains) power
#define NODEAVAILPWR_RECHARGE       0x02  // Rechargeable Battery
#define NODEAVAILPWR_DISPOSE        0x04  // Disposable Battery

// Power Level
#define NODEPOWER_LEVEL_CRITICAL    0x00  // Critical
#define NODEPOWER_LEVEL_33          0x04  // 33%
#define NODEPOWER_LEVEL_66          0x08  // 66%
#define NODEPOWER_LEVEL_100         0x0C  // 100%

// Node Power Descriptor format structure
typedef struct
{
  unsigned int PowerMode:4;
  unsigned int AvailablePowerSources:4;
  unsigned int CurrentPowerSource:4;
  unsigned int CurrentPowerSourceLevel:4;
} NodePowerDescriptorFormat_t;

/*********************************************************************
 * Simple Descriptor
 */

// AppDevVer values
#define APPDEVVER_1               0x01

// AF_V1_SUPPORT AppFlags - bit map
#define APPFLAG_NONE                0x00  // Backwards compatibility to AF_V1.

// AF-AppFlags - bit map
#define AF_APPFLAG_NONE             0x00
#define AF_APPFLAG_COMPLEXDESC      0x01  // Complex Descriptor Available
#define AF_APPFLAG_USERDESC         0x02  // User Descriptor Available

typedef uint16_t  cId_t;
// Simple Description Format Structure
typedef struct
{
  uint8_t          EndPoint;
  uint16_t         AppProfId;
  uint16_t         AppDeviceId;
  uint8_t          AppDevVer:4;
  uint8_t          Reserved:4;             // AF_V1_SUPPORT uses for AppFlags:4.
  uint8_t          AppNumInClusters;
  cId_t         *pAppInClusterList;
  uint8_t          AppNumOutClusters;
  cId_t         *pAppOutClusterList;
} SimpleDescriptionFormat_t;

/*********************************************************************
 * AF Message Format
 */

// Frame Types
#define FRAMETYPE_KVP          0x01     // 0001
#define FRAMETYPE_MSG          0x02     // 0010

#define ERRORCODE_SUCCESS               0x00

#define AF_HDR_KVP_MAX_LEN   0x08  // Max possible AF KVP header.
#define AF_HDR_V1_0_MAX_LEN  0x03  // Max possible AF Ver 1.0 header.
#define AF_HDR_V1_1_MAX_LEN  0x00  // Max possible AF Ver 1.1 header.

// Generalized MSG Command Format
typedef struct
{
  uint16_t  DataLength;              // Number of bytes in TransData
  uint8_t  *Data;
} afMSGCommandFormat_t;

typedef enum
{
  noLatencyReqs,
  fastBeacons,
  slowBeacons
} afNetworkLatencyReq_t;

/*********************************************************************
 * Endpoint  Descriptions
 */

typedef enum
{
  afAddrNotPresent = AddrNotPresent,
  afAddr16Bit      = Addr16Bit,
  afAddr64Bit      = Addr64Bit,
  afAddrGroup      = AddrGroup,
  afAddrBroadcast  = AddrBroadcast
} afAddrMode_t;

typedef struct
{
  union
  {
    uint16_t      shortAddr;
    ZLongAddr_t extAddr;
  } addr;
  afAddrMode_t addrMode;
  uint8_t endPoint;
  uint16_t panId;  // used for the INTER_PAN feature
}  afAddrType_t;


typedef struct
{
  OsalPort_EventHdr hdr;     /* OSAL Message header */
  uint16_t groupId;           /* Message's group ID - 0 if not set */
  uint16_t clusterId;         /* Message's cluster ID */
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                               it's an InterPAN message */
  uint16_t macDestAddr;       /* MAC header destination short address */
  uint8_t endPoint;           /* destination endpoint */
  uint8_t wasBroadcast;       /* TRUE if network destination was a broadcast address */
  uint8_t LinkQuality;        /* The link quality of the received data frame */
  uint8_t correlation;        /* The raw correlation value of the received data frame */
  int8_t  rssi;               /* The received RF power in units dBm */
  uint8_t SecurityUse;        /* deprecated */
  uint32_t timestamp;         /* receipt timestamp from MAC */
  uint8_t nwkSeqNum;          /* network header frame sequence number */
  afMSGCommandFormat_t cmd; /* Application Data */
  uint16_t macSrcAddr;        /* MAC header source short address */
  uint8_t radius;
} afIncomingMSGPacket_t;

//Typedef for callback function to control the AF Data Confirm
typedef void (*pfnAfCnfCB)(uint8_t status, uint8_t endpoint, uint8_t transID, uint16_t clusterID, void* cnfParam);

typedef struct
{
  OsalPort_EventHdr hdr;
  uint8_t endpoint;
  uint8_t transID;
  uint16_t clusterID;
  pfnAfCnfCB afCnfCB;
  void* cnfParam;
} afDataConfirm_t;

// Reflect Error Message - sent when there is an error occurs
// during a reflected message.
typedef struct
{
  OsalPort_EventHdr hdr;  // hdr.status contains the error indication (ie. ZApsNoAck)
  uint8_t endpoint;        // source endpoint
  uint8_t transID;         // transaction ID of sent message
  uint8_t dstAddrMode;     // destination address type: 0 - short address, 1 - group address
  uint16_t dstAddr;        // destination address - depends on dstAddrMode
  uint8_t dstEP;           // destination endpoint
  void* cnfParam;           // cnfParam pointer filled when AF_DataRequest
} afReflectError_t;

// Endpoint Table - this table is the device description
// or application registration.
// There will be one entry in this table for every
// endpoint defined.
typedef struct
{
  uint8_t endPoint;
  uint8_t epType;
  uint8_t *task_id;  // Pointer to location of the Application task ID.
  SimpleDescriptionFormat_t *simpleDesc;
  afNetworkLatencyReq_t latencyReq;
} endPointDesc_t;

// Typedef for callback function to retrieve an endpoints
//   descriptors, contained in the endpoint descriptor.
//   This will allow an application to dynamically change
//   the descriptor and not use the RAM/ROM.
typedef void *(*pDescCB)( uint8_t type, uint8_t endpoint );

// Typedef for callback function to control the AF transaction ID
//   used when sending messages.
//   This allows the application to verify if the transaction ID
//   is not duplicated of a pending message.
typedef void (*pApplCB)( APSDE_DataReq_t *req );

// Descriptor types used in the above callback
#define AF_DESCRIPTOR_SIMPLE            1
#define AF_DESCRIPTOR_PROFILE_ID        2

// Bit definitions for epList_t flags.
typedef enum
{
  eEP_AllowMatch = 1,
  eEP_NotUsed
} eEP_Flags;

typedef struct {
  uint8_t frameDelay;
  uint8_t windowSize;
} afAPSF_Config_t;

typedef struct _epList_t {
  struct _epList_t *nextDesc;
  endPointDesc_t *epDesc;
  pDescCB  pfnDescCB;     // Don't use if this function pointer is NULL.
  afAPSF_Config_t apsfCfg;
  eEP_Flags flags;
  pApplCB pfnApplCB;    // Don't use it if it has not been set to a valid function pointer by the application
} epList_t;

/*********************************************************************
 * TYPEDEFS
 */

#define afStatus_SUCCESS            ZSuccess           /* 0x00 */
#define afStatus_FAILED             ZFailure           /* 0x01 */
#define afStatus_INVALID_PARAMETER  ZInvalidParameter  /* 0x02 */
#define afStatus_MEM_FAIL           ZMemError          /* 0x10 */
#define afStatus_NO_ROUTE           ZNwkNoRoute        /* 0xCD */

typedef ZStatus_t afStatus_t;

typedef struct
{
  uint8_t              kvp;
  APSDE_DataReqMTU_t aps;
} afDataReqMTU_t;

/*********************************************************************
 * Globals
 */

extern epList_t *epList;

/*********************************************************************
 * FUNCTIONS
 */

 /*
  * afInit - Initialize the AF.
  */
  //extern void afInit( void );
  #define afInit()  // No work to do for now.

 /*
  * afRegisterExtended - Register an Application's EndPoint description
  *           with a callback function for descriptors and
  *           with an Application callback function to control
  *           the AF transaction ID.
  *
  */
  extern epList_t *afRegisterExtended( endPointDesc_t *epDesc, pDescCB descFn, pApplCB applFn );

 /*
  * afRegister - Register an Application's EndPoint description.
  *
  */
  extern afStatus_t afRegister( endPointDesc_t *epDesc );

 /*
  * afDelete - Delete an Application's EndPoint descriptor and frees the memory.
  *
  */
  extern afStatus_t afDelete( uint8_t EndPoint );

 /*
  * afDataConfirm - APS will call this function after a data message
  *                 has been sent.
  */
  extern void afDataConfirm( uint8_t endPoint, uint8_t transID, uint16_t clusterID, ZStatus_t status );

 /*
  * afReflectError - APS will call this function for an error with a reflected data message.
  */
  extern void afReflectError( uint8_t srcEP, uint8_t dstAddrMode, uint16_t dstAddr, uint8_t dstEP,
                              uint8_t transID, ZStatus_t status );

 /*
  * afIncomingData - APS will call this function when an incoming
  *                   message is received.
  */
  extern void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16_t SrcPanId,
                       NLDE_Signal_t *sig, uint8_t nwkSeqNum, uint8_t SecurityUse, uint32_t timestamp, uint8_t radius );

#define  AF_DataRequest( dstAddr, srcEP, cID, len, buf, transID, options, radius ) \
  AF_DataRequestExt( dstAddr, srcEP, cID, len, buf, transID, options, radius, NULL, NULL )
  
  afStatus_t AF_DataRequestExt( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                                uint16_t cID, uint16_t len, uint8_t *buf, uint8_t *transID,
                                uint8_t options, uint8_t radius, pfnAfCnfCB afCnfCB, void* cnfParam );

  /*
  * afStopConfirmWaitting - stop APS-ack waitting when orphan
  */
  extern void afStopConfirmWaitting( void );  

/*********************************************************************
 * @fn      AF_DataRequestSrcRtg
 *
 * @brief   Common functionality for invoking APSDE_DataReq() for both
 *          SendMulti and MSG-Send.
 *
 * input parameters
 *
 * @param  *dstAddr - Full ZB destination address: Nwk Addr + End Point.
 * @param  *srcEP - Origination (i.e. respond to or ack to) End Point Descr.
 * @param   cID - A valid cluster ID as specified by the Profile.
 * @param   len - Number of bytes of data pointed to by next param.
 * @param  *buf - A pointer to the data bytes to send.
 * @param  *transID - A pointer to a byte which can be modified and which will
 *                    be used as the transaction sequence number of the msg.
 * @param   options - Valid bit mask of Tx options.
 * @param   radius - Normally set to AF_DEFAULT_RADIUS.
 * @param   relayCnt - Number of devices in the relay list
 * @param   pRelayList - Pointer to the relay list
 *
 * output parameters
 *
 * @param  *transID - Incremented by one if the return value is success.
 *
 * @return  afStatus_t - See previous definition of afStatus_... types.
 */

#define AF_DataRequestSrcRtg( dstAddr, srcEP, cID, len, buf, transID, options, radius, relayCnt, pRelayList )\
  AF_DataRequestSrcRtgExt( dstAddr, srcEP, cID, len, buf, transID, options, radius, relayCnt, pRelayList, NULL, NULL )

afStatus_t AF_DataRequestSrcRtgExt( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16_t cID,
                                   uint16_t len, uint8_t *buf, uint8_t *transID, uint8_t options, uint8_t radius,
                                   uint8_t relayCnt, uint16_t* pRelayList, pfnAfCnfCB afCnfCB, void* cnfParam );

/*********************************************************************
 * Direct Access Functions - ZigBee Device Object
 */

 /*
  *	afFindEndPointDesc - Find the endpoint description entry from the
  *                      endpoint number.
  */
  extern endPointDesc_t *afFindEndPointDesc( uint8_t endPoint );

 /*
  *	afFindSimpleDesc - Find the Simple Descriptor from the endpoint number.
  *   	  If return value is not zero, the descriptor memory must be freed.
  */
  extern uint8_t afFindSimpleDesc( SimpleDescriptionFormat_t **ppDesc, uint8_t EP );

 /*
  *	afDataReqMTU - Get the Data Request MTU(Max Transport Unit)
  */
  extern uint8_t afDataReqMTU( afDataReqMTU_t* fields );

 /*
  *	afGetMatch - Get the action for the Match Descriptor Response
  *             TRUE allow match descriptor response
  */
  extern uint8_t afGetMatch( uint8_t ep );

 /*
  *	afSetMatch - Set the action for the Match Descriptor Response
  *             TRUE allow match descriptor response
  */
  extern uint8_t afSetMatch( uint8_t ep, uint8_t action );

 /*
  *	afNumEndPoints - returns the number of endpoints defined.
  */
  extern uint8_t afNumEndPoints( void );

 /*
  *	afEndPoints - builds an array of endpoints.
  */
  extern void afEndPoints( uint8_t *epBuf, uint8_t skipZDO );

 /*
  * afCopyAddress
  */
extern void afCopyAddress (afAddrType_t *afAddr, zAddrType_t *zAddr);

 /*
  *	afAPSF_ConfigGet - ascertain the fragmentation configuration for the specified EndPoint.
  */
void afAPSF_ConfigGet(uint8_t endPoint, afAPSF_Config_t *pCfg);

 /*
  *	afAPSF_ConfigSet - set the fragmentation configuration for the specified EndPoint.
  */
afStatus_t afAPSF_ConfigSet(uint8_t endPoint, afAPSF_Config_t *pCfg);

 /*
  *	afSetApplCB - Sets the pointer to the Application Callback function for a
  *               specific EndPoint.
  */
uint8_t afSetApplCB( uint8_t endPoint, pApplCB pApplFn );

修复ZD_APP.c

void ZDO_SyncIndicationCB( uint8_t type, uint16_t shortAddr )
{
  (void)shortAddr;  // Remove this line if this parameter is used.

  if ( ZSTACK_END_DEVICE_BUILD
    || (ZSTACK_ROUTER_BUILD && BUILD_FLEXABLE && ((_NIB.CapabilityFlags & ZMAC_ASSOC_CAPINFO_FFD_TYPE) == 0)))
  {
    if ( type == 1 && retryCnt == 0 )
    {
      // We lost contact with our parent.  Clear the neighbor Table.
      nwkNeighborInitTable();

      //If we are Factory new, then report fail on association
      if(!bdb_isDeviceNonFactoryNew())
      {
        bdb_nwkAssocAttemt(FALSE);
      }
#if (ZG_BUILD_ENDDEVICE_TYPE)
      else
      {
        //We lost our parent
        bdb_parentLost();
        afStopConfirmWaitting();
      }
#endif
    }
  }
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,Aries:

    感谢您与社区分享您的解决方案!

    此致,
    Ryan