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: "AF_DataRequest" with "Success" returning could not trigger "afDataConfirm" everytime.

Part Number: CC2652P
Other Parts Discussed in Thread: SIMPLELINK-CC13XX-CC26XX-SDK, Z-STACK, CC1352P

SDK Version: simplelink_cc13xx_cc26xx_sdk_6_30_01_03

I have marked the executing counter in "AF_DataRequest" and "afDataConfirm". I force my coordinate and router send Application-Data to each other. The sending is triggered very 10ms. 10-minutes after, the counter of AF_DataRequest is not equal to  the counter of "afDataConfirm".

  • Hello Aries,

    Thank you for sharing your findings.  Are you evaluating the SIMPLELINK-CC13XX-CC26XX-SDK v6.30 and did this issue exist on previous SDK versions?  What changes are necessary to the default application to recreate this issue?  Do you have any sniffer or debugger logs to share as well?  In what way are the counters no longer equal?

    Regards,
    Ryan

    1. I find this issue when debug my code. I have set two variables each in  "AF_DataRequest" and "afDataConfirm". And run debugging for long time.  Then stop transmiting and debugging, I have find that the variable in "AF_DataRequest" is more than variable in  "afDataConfirm".
  • I have test my code on SDK 5.40, it have no this issue.

    I have update it to SDK 620, this issue have not appeared too.

  • How much more is AF_DataRequest than afDataConfirm?  Z-Stack did upgrade from TI-RTOS in the v6.20 SDK to TI-RTOS7 in the v6.30 SDK, but otherwise there are no substantial updates to the AF layer (TI is currently focusing efforts on updating Z-Stack to the next upcoming Zigbee protocol revision) so this reported bug is surprising.  Can I replicate this behavior by setting a continuous timer which calls Zstackapi_AfDataReq on the ZR every 10 ms?  Are AF ACKs enabled?

    Regards,
    Ryan

  • In SDK 6.30, my coordinate sends AF-packet per 20ms, and receives AF-packet form one router per 10ms. When AF_DataRequest counter reachs more than 3000,it 256 more than afDataConfirm counter. 

    But in SDK 6.20, my coordinate sends AF-packet per 1ms, and receives AF-packet form one router per 1ms, the AF_DataRequest counter and afDataConfirm counter keep equal though both of them are more than 65535.

  • In my testing, coordinate send to router without APS-ACK-Enabled, but router send to coordinate will enabled APS-Ack and ZCL-Default-Rsp. 

  • Is the timer-system of TI-RTOS7 different from TI-RTOS? Can afDataConfirm be triggered by timer(such as timeout)? Sometimes AF_DATA_CONFIRM_MSG can be used as a timeout-timer by Application.

  • Thanks Aries, I will try to recreate the problem and further investigate its root cause.  I do not currently know of a difference between RTOS timer systems.  I will let you know when I have updates.

    Regards,
    Ryan

  • Hi Aries,

    I have not been able to replicate mismatched AF_DataRequest/afDataConfirm counters on the scale mentioned.  Results are also the exact same for both v6.20 and v6.30 SDKs.  Can you please review my implementation and let me know whether anything should be changed to recreate the behavior?

    8206.af.c
    /**************************************************************************************************
      Filename:       af.c
      Revised:        $Date: 2014-11-04 10:53:36 -0800 (Tue, 04 Nov 2014) $
      Revision:       $Revision: 40974 $
    
      Description:    Application Framework - Device Description helper functions
    
    
      Copyright 2004-2014 Texas Instruments Incorporated.
    
      All rights reserved not granted herein.
      Limited License.
    
      Texas Instruments Incorporated grants a world-wide, royalty-free,
      non-exclusive license under copyrights and patents it now or hereafter
      owns or controls to make, have made, use, import, offer to sell and sell
      ("Utilize") this software subject to the terms herein. With respect to the
      foregoing patent license, such license is granted solely to the extent that
      any such patent is necessary to Utilize the software alone. The patent
      license shall not apply to any combinations which include this software,
      other than combinations with devices manufactured by or for TI ("TI
      Devices"). No hardware patent is licensed hereunder.
    
      Redistributions must preserve existing copyright notices and reproduce
      this license (including the above copyright notice and the disclaimer and
      (if applicable) source code license limitations below) in the documentation
      and/or other materials provided with the distribution.
    
      Redistribution and use in binary form, without modification, are permitted
      provided that the following conditions are met:
    
        * No reverse engineering, decompilation, or disassembly of this software
          is permitted with respect to any software provided in binary form.
        * Any redistribution and use are licensed by TI for use only with TI Devices.
        * Nothing shall obligate TI to provide you with source code for the software
          licensed and provided to you in object code.
    
      If software source code is provided to you, modification and redistribution
      of the source code are permitted provided that the following conditions are
      met:
    
        * Any redistribution and use of the source code, including any resulting
          derivative works, are licensed by TI for use only with TI Devices.
        * Any redistribution and use of any object code compiled from the source
          code and any resulting derivative works, are licensed by TI for use
          only with TI Devices.
    
      Neither the name of Texas Instruments Incorporated nor the names of its
      suppliers may be used to endorse or promote products derived from this
      software without specific prior written permission.
    
      DISCLAIMER.
    
      THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS
      OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
      OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
      EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    **************************************************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    
    #include "ti_zstack_config.h"
    #include "rom_jt_154.h"
    #include "af.h"
    #include "nwk_globals.h"
    #include "nwk_util.h"
    #include "aps_groups.h"
    #include "zd_profile.h"
    #include "aps_frag.h"
    #include "rtg.h"
    
    #if defined ( MT_AF_CB_FUNC )
      #include "mt_af.h"
    #endif
    
    #if defined ( INTER_PAN ) || defined ( BDB_TL_INITIATOR ) || defined ( BDB_TL_TARGET )
      #include "stub_aps.h"
    #endif
    
    #include "bdb.h"
    #if ( BDB_TOUCHLINK_CAPABILITY_ENABLED == TRUE)
      #include "bdb_tl_commissioning.h"
    #endif
    
    uint32_t afDataReqCount = 0;
    uint32_t afDataCnfCount = 0;
    uint32_t afDataDifCount = 0;
    
    /*********************************************************************
     * MACROS
     */
    
    /*********************************************************************
     * @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 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 );
    
    /*********************************************************************
     * 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 < 5; 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;
    
      // 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;
    
    #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 );
        }
        afDataCnfCount++;
        afDataDifCount = afDataReqCount - afDataCnfCount;
      }
    }
    
    /*********************************************************************
     * @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;
    
      // 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;
    
    #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.
     *
     * 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_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                               uint16_t cID, uint16_t len, uint8_t *buf, uint8_t *transID,
                               uint8_t options, uint8_t radius )
    {
      pDescCB pfnDescCB;
      ZStatus_t stat;
      APSDE_DataReq_t req;
      afDataReqMTU_t mtu;
      epList_t *pList;
    
      // Verify source end point
      if ( srcEP == 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
    
      // 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 );
        }
      }
    
      /*
       * 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()) )
      {
        afDataConfirm( srcEP->endPoint, *transID, cID, stat );
      }
    
      if ( stat == afStatus_SUCCESS )
      {
        (*transID)++;
        afDataReqCount++;
      }
    
      return (afStatus_t)stat;
    }
    
    /*********************************************************************
     * @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.
     */
    
    afStatus_t AF_DataRequestSrcRtg( 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 )
    {
      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_DataRequest( dstAddr, srcEP, cID, len, buf, transID, options, radius );
      }
      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 );
    }
    
    /**************************************************************************************************
    */
    
    6558.zcl_samplesw.c

    Regards,
    Ryan

  •  Coordinate send AF-Packet to router per 10ms and router send  AF-Packet to coordinate per 10ms.

    run this sending for 5~10minutes.

    My sending is controlled by UART-Software, which input data to coordinate and router per 10ms.

  • I am observing very similar AF_DataRequest/afDataConfirm counters when testing the v6.30 SDK using 10 ms packet intervals.  The coordinator displays exactly identical values and the router will drift slightly after several minutes of operation.  However this same behavior is also displayed on the v6.20 SDK.  My tests rely on a timer instead of UART control to send the messages, do you believe the UART interface has a direct affect on the behavior you are observing?

    Regards,
    Ryan

  • Can you speed up the transmiting? coordinate send to router while router send to coordinate too.

  • In my coordinate, it config like this

    -DMAC_CFG_APP_PENDING_QUEUE=TRUE
    -DMAC_CFG_TX_DATA_MAX=20
    -DMAC_CFG_TX_MAX=32
    -DMAC_CFG_RX_MAX=20
    
    -DNWK_MAX_DATABUFS_WAITING=32
    -DNWK_MAX_DATABUFS_SCHEDULED=20
    -DNWK_MAX_DATABUFS_CONFIRMED=20
    -DNWK_MAX_DATABUFS_TOTAL=48
    -DNWK_INDIRECT_MSG_MAX_PER=6

    On SDK 6.20, HEAPMGR_SIZE is 40960 KB(0xA000)

    On SDK 6.30, HEAP size is automatic allocation.

  • The coordinator is sending every 10 ms with APS ACK disabled, the router is also sending every 10 ms with APS ACK enabled.  Changing the definitions inside nwk_globals.c and f8wcoord.opts does not appear to affect behavior.  Reducing the packet interval below 10 ms could result in bottlenecking, AF count differences, and thus poor application performance as I have noticed with the router on both v6.20 and v6.30 SDKs.  Your application could remove AF ACK requests, reduce packet intervals, or rely on receiving AF_DATA_CONFIRM_MSG to confirm that a message has been confirmed before queueing the next packet.

    Regards,
    Ryan

  • My testing is to make a bottlenecking, the counter of AF-Request will be more than the counter of AF-Confirm. But When I stop transmiting for a moment, on SDK 6.20  the counter of AF-Confirm will be equal with counter of AF-Request. But on SDK6.30, counter of AF-Confirm could not be equal with counter of AF-Request.

    My testing project is based on zc_genericapp_CC1352P_2_LAUNCHXL_tirtos7_ticlang

  • Part Number: CC2652P

    Not only SDK6.30 But also other SDK, this issue will happen in such condition. When coordinate and routers are transmiting busily, some of AF-Send with APS-Ack-Request-Enabled will not trigger "afDataConfirm". But the sending's record in "nwkDataBufQueue" can be freed. So I suggest that the "afDataConfirm" with "ZApsNoAck" should be trigger when the record of APS-Ack-Request-Enabled sending is delete.

  • I have new found. Whatever version of SDK, when APS-Request is enabled, the AF_DataRequest has probability to can't trigger afDataConfirm. Includes SDK 5.40 and SDK 6.20.

    I have saw the source-code of APS-Ack-Retry sending in Z-stack 3.0.2. Retry-sending is transmitted by "APSDE_DataReq" in functoun "NLDE_DataIndication" in "NLMEDE_CB.c" .  But there is no reserve plan to deal with  APSDE_DataReq not success. 

    I have saw that the retry-sending is also transmitted by "APSDE_DataReq", that means the old messages will be given up and a new send-buffer will be allocated. If APSDE_DataReq for retrying is unsuccess, the af-Confirm event will be lost.

  • Thanks Aries.  Your findings align with my own and I was able to confirm that your suggested fix improves the behavior observed.  I've passed your recommendation to the Z-Stack Software Development Team for further analysis.

    Regards,
    Ryan

  • TI had better to publish the solution for both TI-RTOS7 and older TI-RTOS.  Z-Stack Software Development Team should publish the lib files or update pack before Christmas Holiday

  • I've reached out through private messaging to provide you with a solution.

    Regards,
    Ryan