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.

在 60 个设备的网络环境下对终端设备进行 OTA 升级返回“ZMemError(0x10)”。

Other Parts Discussed in Thread: Z-STACK, CC2538

协议栈:Z-Stack 3.0.2

协调器:CC2538

终端和路由:CC2538

问题描述:

1、网络中有 60 个设备,网络中流通的数据不大。此时对一个终端节点进行 OTA 升级,“Image Block Response”发送 64 个字节,调用“relayCnt”为2的“zcl_SrcRtgSendCommand()”函数发送“Image Block Response”命令时返回“ZMemError(0x10)”,即申请内存失败。而此时查看内存管理器发现内存并未满,请问这是哪里出了问题?

2、此时对另一个路由节点进行 OTA 升级,也是“Image Block Response”发送 64 个字节,此时却可以升级成功。

3、即发送带 64 个字节数据的“Image Block Response”命令给终端设备是一定会出现“ZMemError(0x10)”的,我单步调试发现是调用 “APSDE_DataReq()” 函数时返回的“ZMemError(0x10)”。但是发送给路由设备却可以成功。

{
    if (len > afDataReqMTU( &mtu ) )
    {
        if (apsfSendFragmented)
        {
            stat = (*apsfSendFragmented)( &req );
        }
        else
        {
            stat = afStatus_INVALID_PARAMETER;
        }
    }
    else
    {
        stat = APSDE_DataReq( &req );
    }
}

 

  • "zcl_SrcRtgSendCommand" 你在发送前添加了RTG_AddSrcRtgEntry_Guaranteed加了一个router source进去?

    但这个和APSDE_DataReq无关,能否贴出”zcl_SrcRtgSendCommand“ code
  • “zcl_SrcRtgSendCommand()”就只是在“zcl_SendCommand()”函数基础上添加了“uint8 relayCnt, uint16* pRelayList”形参,然后将函数里面的“AF_DataRequest()”改为“AF_DataRequestSrcRtg()”。

    ZStatus_t zcl_SrcRtgSendCommand( uint8 srcEP, afAddrType_t *destAddr,

                              uint16 clusterID, uint8 cmd, uint8 specific, uint8 direction,

                              uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum,

                              uint16 cmdFormatLen, uint8 *cmdFormat, uint8 relayCnt, uint16* pRelayList )

    {

     endPointDesc_t *epDesc;

     zclFrameHdr_t hdr;

     uint8 *msgBuf;

     uint16 msgLen;

     uint8 *pBuf;

     uint8 options;

     ZStatus_t status;

     epDesc = afFindEndPointDesc( srcEP );

     if ( epDesc == NULL )

     {

       return ( ZInvalidParameter ); // EMBEDDED RETURN

     }

    #if defined ( INTER_PAN )

     if ( StubAPS_InterPan( destAddr->panId, destAddr->endPoint ) )

     {

       options = AF_TX_OPTIONS_NONE;

     }

     else

    #endif

     {

       options = zclGetClusterOption( srcEP, clusterID );

       // The cluster might not have been defined to use security but if this message

       // is in response to another message that was using APS security this message

       // will be sent with APS security

       if ( !( options & AF_EN_SECURITY ) )

       {

         afIncomingMSGPacket_t *origPkt = zcl_getRawAFMsg();

         if ( ( origPkt != NULL ) && ( origPkt->SecurityUse == TRUE ) )

         {

           options |= AF_EN_SECURITY;

         }

       }

     }

     zcl_memset( &hdr, 0, sizeof( zclFrameHdr_t ) );

     // Not Profile wide command (like READ, WRITE)

     if ( specific )

     {

       hdr.fc.type = ZCL_FRAME_TYPE_SPECIFIC_CMD;

     }

     else

     {

       hdr.fc.type = ZCL_FRAME_TYPE_PROFILE_CMD;

     }

     if ( ( epDesc->simpleDesc == NULL ) ||

          ( zcl_DeviceOperational( srcEP, clusterID, hdr.fc.type,

                                   cmd, epDesc->simpleDesc->AppProfId ) == FALSE ) )

     {

       return ( ZFailure ); // EMBEDDED RETURN

     }

     // Fill in the Maufacturer Code

     if ( manuCode != 0 )

     {

       hdr.fc.manuSpecific = 1;

       hdr.manuCode = manuCode;

     }

     // Set the Command Direction

     if ( direction )

     {

       hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;

     }

     else

     {

       hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;

     }

     // Set the Disable Default Response field

     if ( disableDefaultRsp )

     {

       hdr.fc.disableDefaultRsp = 1;

     }

     else

     {

       hdr.fc.disableDefaultRsp = 0;

     }

     // Fill in the Transaction Sequence Number

     hdr.transSeqNum = seqNum;

     // Fill in the command

     hdr.commandID = cmd;

     // calculate the needed buffer size

     msgLen = zclCalcHdrSize( &hdr );

     msgLen += cmdFormatLen;

     // Allocate the buffer needed

     msgBuf = zcl_mem_alloc( msgLen );

     if ( msgBuf != NULL )

     {

       // Fill in the ZCL Header

       pBuf = zclBuildHdr( &hdr, msgBuf );

       // Fill in the command frame

       zcl_memcpy( pBuf, cmdFormat, cmdFormatLen );

       status = AF_DataRequestSrcRtg( destAddr, epDesc, clusterID, msgLen, msgBuf,

                                       &APS_Counter, options, zcl_radius, relayCnt, pRelayList );

       zcl_mem_free ( msgBuf );

     }

     else

     {

       status = ZMemError;

     }

     return ( status );

    }

  • Stack 自带的Image Block Response为32bit 也会出现相同问题?
    你这个code看上去没有什么问题。
  • 即使你的OTA_MAX_MTU=64也是小于128的,是你修改了zcl_SendCommand后才出现的吗
  • 我刚刚测试了,是的,将“zcl_SrcRtgSendCommand()”换回“zcl_SendCommand()”就可以发出去了。
  • ZStatus_t zcl_SrcRtgSendCommand( uint8 srcEP, afAddrType_t *destAddr,
    
                              uint16 clusterID, uint8 cmd, uint8 specific, uint8 direction,
    
                              uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum,
    
                              uint16 cmdFormatLen, uint8 *cmdFormat, uint8 relayCnt, uint16* pRelayList )
    
    {
    
     endPointDesc_t *epDesc;
    
     zclFrameHdr_t hdr;
    
     uint8 *msgBuf;
    
     uint16 msgLen;
    
     uint8 *pBuf;
    
     uint8 options;
    
     ZStatus_t status;
    //add by alvin 
     uint8 *Rtgbuf;
     zdoSrcRtg_t srcRtg;
     Rtgbuf=zcl_mem_alloc(sizeof(srcRtg)+relayCnt*sizeof(uint16))
     if( Rtgbuf != NULL)
     {
    	 srcRtg.srcAddr=destAddr.shortAddr;
    	 srcRtg.relayCnt=relayCnt;
    	 srcRtg.pRelayList=pRelayList;
     }
     else{
    	  status = ZMemError
     }
    	 
      epDesc = afFindEndPointDesc( srcEP );
     if ( epDesc == NULL )
    
     {
    
       return ( ZInvalidParameter ); // EMBEDDED RETURN
    
     }
    
    #if defined ( INTER_PAN )
    
     if ( StubAPS_InterPan( destAddr->panId, destAddr->endPoint ) )
    
     {
    
       options = AF_TX_OPTIONS_NONE;
    
     }
    
     else
    
    #endif
    
     {
    
       options = zclGetClusterOption( srcEP, clusterID );
    
       // The cluster might not have been defined to use security but if this message
    
       // is in response to another message that was using APS security this message
    
       // will be sent with APS security
    
       if ( !( options & AF_EN_SECURITY ) )
    
       {
    
         afIncomingMSGPacket_t *origPkt = zcl_getRawAFMsg();
    
         if ( ( origPkt != NULL ) && ( origPkt->SecurityUse == TRUE ) )
    
         {
    
           options |= AF_EN_SECURITY;
    
         }
    
       }
    
     }
    
     zcl_memset( &hdr, 0, sizeof( zclFrameHdr_t ) );
    
     // Not Profile wide command (like READ, WRITE)
    
     if ( specific )
    
     {
    
       hdr.fc.type = ZCL_FRAME_TYPE_SPECIFIC_CMD;
    
     }
    
     else
    
     {
    
       hdr.fc.type = ZCL_FRAME_TYPE_PROFILE_CMD;
    
     }
    
     if ( ( epDesc->simpleDesc == NULL ) ||
    
          ( zcl_DeviceOperational( srcEP, clusterID, hdr.fc.type,
    
                                   cmd, epDesc->simpleDesc->AppProfId ) == FALSE ) )
    
     {
    
       return ( ZFailure ); // EMBEDDED RETURN
    
     }
    
     // Fill in the Maufacturer Code
    
     if ( manuCode != 0 )
    
     {
    
       hdr.fc.manuSpecific = 1;
    
       hdr.manuCode = manuCode;
    
     }
    
     // Set the Command Direction
    
     if ( direction )
    
     {
    
       hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;
    
     }
    
     else
    
     {
    
       hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;
    
     }
    
     // Set the Disable Default Response field
    
     if ( disableDefaultRsp )
    
     {
    
       hdr.fc.disableDefaultRsp = 1;
    
     }
    
     else
    
     {
    
       hdr.fc.disableDefaultRsp = 0;
    
     }
    
     // Fill in the Transaction Sequence Number
    
     hdr.transSeqNum = seqNum;
    
     // Fill in the command
    
     hdr.commandID = cmd;
    
     // calculate the needed buffer size
    
     msgLen = zclCalcHdrSize( &hdr );
    
     msgLen += cmdFormatLen;
    
     // Allocate the buffer needed
    
     msgBuf = zcl_mem_alloc( msgLen );
    
     if ( msgBuf != NULL )
    
     {
    
       // Fill in the ZCL Header
    
       pBuf = zclBuildHdr( &hdr, msgBuf );
    
       // Fill in the command frame
    
       zcl_memcpy( pBuf, cmdFormat, cmdFormatLen );
    
       status = AF_DataRequestSrcRtg( destAddr, epDesc, clusterID, msgLen, msgBuf,
    
                                       &APS_Counter, options, zcl_radius, srcRtg.relayCnt, srcRtg.pRelayList );
    	//add by alvin 
       zcl_mem_free(Rtgbuf);  
       
       zcl_mem_free ( msgBuf );
     }
    
     else
    
     {
    
       status = ZMemError;
    
     }
    
     return ( status );
    
    }

    我大致写了一些code出来,就是申请srcRtg,你去试试看,不行的话改一下,还没有验证过。

  • 我将“uint16* pRelayList”形参单独申请内存保存之后就可以发送了,为什么会出现这个问题?有时候调用发送函数的时候也是会返回"ZMemError (0x10)",但是内存并没有满。

    之前的函数:

    ZStatus_t zcl_SrcRtgSendCommand( uint8 srcEP, afAddrType_t *destAddr,
                               uint16 clusterID, uint8 cmd, uint8 specific, uint8 direction,
                               uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum,
                               uint16 cmdFormatLen, uint8 *cmdFormat, uint8 relayCnt, uint16* pRelayList )
    {
      endPointDesc_t *epDesc;
      zclFrameHdr_t hdr;
      uint8 *msgBuf;
      uint16 msgLen;
      uint8 *pBuf;
      uint8 options;
      ZStatus_t status;
    
      epDesc = afFindEndPointDesc( srcEP );
      if ( epDesc == NULL )
      {
        return ( ZInvalidParameter ); // EMBEDDED RETURN
      }
    
    #if defined ( INTER_PAN )
      if ( StubAPS_InterPan( destAddr->panId, destAddr->endPoint ) )
      {
        options = AF_TX_OPTIONS_NONE;
      }
      else
    #endif
      {
        options = zclGetClusterOption( srcEP, clusterID );
    
        // The cluster might not have been defined to use security but if this message
        // is in response to another message that was using APS security this message
        // will be sent with APS security
        if ( !( options & AF_EN_SECURITY ) )
        {
          afIncomingMSGPacket_t *origPkt = zcl_getRawAFMsg();
    
          if ( ( origPkt != NULL ) && ( origPkt->SecurityUse == TRUE ) )
          {
            options |= AF_EN_SECURITY;
          }
        }
      }
    
      zcl_memset( &hdr, 0, sizeof( zclFrameHdr_t ) );
    
      // Not Profile wide command (like READ, WRITE)
      if ( specific )
      {
        hdr.fc.type = ZCL_FRAME_TYPE_SPECIFIC_CMD;
      }
      else
      {
        hdr.fc.type = ZCL_FRAME_TYPE_PROFILE_CMD;
      }
    
      if ( ( epDesc->simpleDesc == NULL ) ||
           ( zcl_DeviceOperational( srcEP, clusterID, hdr.fc.type,
                                    cmd, epDesc->simpleDesc->AppProfId ) == FALSE ) )
      {
        return ( ZFailure ); // EMBEDDED RETURN
      }
    
      // Fill in the Maufacturer Code
      if ( manuCode != 0 )
      {
        hdr.fc.manuSpecific = 1;
        hdr.manuCode = manuCode;
      }
    
      // Set the Command Direction
      if ( direction )
      {
        hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;
      }
      else
      {
        hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;
      }
    
      // Set the Disable Default Response field
      if ( disableDefaultRsp )
      {
        hdr.fc.disableDefaultRsp = 1;
      }
      else
      {
        hdr.fc.disableDefaultRsp = 0;
      }
    
      // Fill in the Transaction Sequence Number
      hdr.transSeqNum = seqNum;
    
      // Fill in the command
      hdr.commandID = cmd;
    
      // calculate the needed buffer size
      msgLen = zclCalcHdrSize( &hdr );
      msgLen += cmdFormatLen;
    
      // Allocate the buffer needed
      msgBuf = zcl_mem_alloc( msgLen );
      if ( msgBuf != NULL )
      {
        // Fill in the ZCL Header
        pBuf = zclBuildHdr( &hdr, msgBuf );
    
        // Fill in the command frame
        zcl_memcpy( pBuf, cmdFormat, cmdFormatLen );
        
        status = AF_DataRequestSrcRtg( destAddr, epDesc, clusterID, msgLen, msgBuf,
                                        &APS_Counter, options, zcl_radius, relayCnt, pRelayList );
        
        zcl_mem_free ( msgBuf );
      }
      else
      {
        status = ZMemError;
      }
    
      return ( status );
    }

    更改后的函数:

    ZStatus_t zcl_SrcRtgSendCommand( uint8 srcEP, afAddrType_t *destAddr,
                               uint16 clusterID, uint8 cmd, uint8 specific, uint8 direction,
                               uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum,
                               uint16 cmdFormatLen, uint8 *cmdFormat, uint8 relayCnt, uint16* pRelayList )
    {
      endPointDesc_t *epDesc;
      zclFrameHdr_t hdr;
      uint8 *msgBuf;
      uint16 msgLen;
      uint8 *pBuf;
      uint8 options;
      ZStatus_t status;
      zdoSrcRtg_t srcrtg = {0};
      
      srcrtg.srcAddr = destAddr->addr.shortAddr;
      srcrtg.relayCnt = relayCnt;
      srcrtg.pRelayList = NULL;
      if((relayCnt!=0)&&(pRelayList!=NULL))
      {
        srcrtg.pRelayList = zcl_mem_alloc(relayCnt * sizeof(uint16));
        if(srcrtg.pRelayList!=NULL)
        {
          osal_memcpy(srcrtg.pRelayList, pRelayList, relayCnt * sizeof(uint16));
        }
        else
        {
          status = ZMemError;
        }
      }
     
      epDesc = afFindEndPointDesc( srcEP );
      if ( epDesc == NULL )
      {
        return ( ZInvalidParameter ); // EMBEDDED RETURN
      }
    
    #if defined ( INTER_PAN )
      if ( StubAPS_InterPan( destAddr->panId, destAddr->endPoint ) )
      {
        options = AF_TX_OPTIONS_NONE;
      }
      else
    #endif
      {
        options = zclGetClusterOption( srcEP, clusterID );
    
        // The cluster might not have been defined to use security but if this message
        // is in response to another message that was using APS security this message
        // will be sent with APS security
        if ( !( options & AF_EN_SECURITY ) )
        {
          afIncomingMSGPacket_t *origPkt = zcl_getRawAFMsg();
    
          if ( ( origPkt != NULL ) && ( origPkt->SecurityUse == TRUE ) )
          {
            options |= AF_EN_SECURITY;
          }
        }
      }
    
      zcl_memset( &hdr, 0, sizeof( zclFrameHdr_t ) );
    
      // Not Profile wide command (like READ, WRITE)
      if ( specific )
      {
        hdr.fc.type = ZCL_FRAME_TYPE_SPECIFIC_CMD;
      }
      else
      {
        hdr.fc.type = ZCL_FRAME_TYPE_PROFILE_CMD;
      }
    
      if ( ( epDesc->simpleDesc == NULL ) ||
           ( zcl_DeviceOperational( srcEP, clusterID, hdr.fc.type,
                                    cmd, epDesc->simpleDesc->AppProfId ) == FALSE ) )
      {
        return ( ZFailure ); // EMBEDDED RETURN
      }
    
      // Fill in the Maufacturer Code
      if ( manuCode != 0 )
      {
        hdr.fc.manuSpecific = 1;
        hdr.manuCode = manuCode;
      }
    
      // Set the Command Direction
      if ( direction )
      {
        hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;
      }
      else
      {
        hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;
      }
    
      // Set the Disable Default Response field
      if ( disableDefaultRsp )
      {
        hdr.fc.disableDefaultRsp = 1;
      }
      else
      {
        hdr.fc.disableDefaultRsp = 0;
      }
    
      // Fill in the Transaction Sequence Number
      hdr.transSeqNum = seqNum;
    
      // Fill in the command
      hdr.commandID = cmd;
    
      // calculate the needed buffer size
      msgLen = zclCalcHdrSize( &hdr );
      msgLen += cmdFormatLen;
    
      // Allocate the buffer needed
      msgBuf = zcl_mem_alloc( msgLen );
      if ( msgBuf != NULL )
      {
        // Fill in the ZCL Header
        pBuf = zclBuildHdr( &hdr, msgBuf );
    
        // Fill in the command frame
        zcl_memcpy( pBuf, cmdFormat, cmdFormatLen );
    
        status = AF_DataRequestSrcRtg( destAddr, epDesc, clusterID, msgLen, msgBuf,
                                        &APS_Counter, options, zcl_radius, srcrtg.relayCnt, srcrtg.pRelayList );
    
        if(srcrtg.pRelayList!=NULL)
        {
          zcl_mem_free(srcrtg.pRelayList);
        }
        
        zcl_mem_free ( msgBuf );
      }
      else
      {
        status = ZMemError;
      }
    
      return ( status );
    }

  • 你好,
    uint16* pRelayList是一个指针,没有说明后面到底有多少个shortAddr,需要用到的空间有多大,所以建议根据relaycnt去开辟好空间去使用。
    那么这个帖子就可以close掉了。E2E英文也去结帖吧。
  • 请问“根据relaycnt开辟新的空间来使用”和直接引用形参的指针具体不同在哪里?
  • relaycnt可以知道pRelayList存了几个地址。直接引用我没有去看源码猜测依据relaycnt去对pRelayList地址为给某个要用的地址。

    直接引用可能存在一些泄露问题。开辟空间后相当于从一个已知buf里面取出来,而不是通过指针地址计算。大概是这样。
  • 这么隐秘的内存泄漏问题...这个函数“RTG_AddSrcRtgEntry_Guaranteed()”一没源码,二没说明,三没例程调用。还有别的函数要注意需要重新开辟内存来进行赋值的吗?
  • 你好,
    我发现你在E2E英文贴的程序有我的名字,如果你想贴出我给fix的code 请贴完整,谢谢。
    因为我们预想客户不需要维护SrcRtg。
  • 没删干净,不好意思
  • 你可以编辑掉吗?如果不能希望贴出我给的完整code或者说明你修改的code是参考了我给的建议。谢谢。

  • 删除掉了,不好意思。
  • 因为你上面那个直接没有malloc就去free了。 zcl_mem_free(srcrtg.pRelayList)
    我怕我们同事鄙视我的C语言功底。。。。。
  • 不好意思,更改前的代码贴错了...
x 出现错误。请重试或与管理员联系。