TI中文支持网
TI专业的中文技术问题搜集分享网站

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

协议栈: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 );
    }
}

 

Alvin Chen:

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

但这个和APSDE_DataReq无关,能否贴出”zcl_SrcRtgSendCommand“ code

Jesse Huang:

回复 Alvin Chen:

“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 );

}

Alvin Chen:

回复 Jesse Huang:

Stack 自带的Image Block Response为32bit 也会出现相同问题?
你这个code看上去没有什么问题。

Alvin Chen:

回复 Alvin Chen:

即使你的OTA_MAX_MTU=64也是小于128的,是你修改了zcl_SendCommand后才出现的吗

Jesse Huang:

回复 Alvin Chen:

我刚刚测试了,是的,将“zcl_SrcRtgSendCommand()”换回“zcl_SendCommand()”就可以发出去了。

Alvin Chen:

回复 Jesse Huang:

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 alvinuint8 *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 securityif ( !( 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 Codeif ( manuCode != 0 ){hdr.fc.manuSpecific = 1;hdr.manuCode = manuCode;}// Set the Command Directionif ( direction ){hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;}else{hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;}// Set the Disable Default Response fieldif ( disableDefaultRsp ){hdr.fc.disableDefaultRsp = 1;}else{hdr.fc.disableDefaultRsp = 0;}// Fill in the Transaction Sequence Numberhdr.transSeqNum = seqNum;// Fill in the commandhdr.commandID = cmd;// calculate the needed buffer sizemsgLen = zclCalcHdrSize( &hdr );msgLen += cmdFormatLen;// Allocate the buffer neededmsgBuf = zcl_mem_alloc( msgLen );if ( msgBuf != NULL ){// Fill in the ZCL HeaderpBuf = zclBuildHdr( &hdr, msgBuf );// Fill in the command framezcl_memcpy( pBuf, cmdFormat, cmdFormatLen );status = AF_DataRequestSrcRtg( destAddr, epDesc, clusterID, msgLen, msgBuf,&APS_Counter, options, zcl_radius, srcRtg.relayCnt, srcRtg.pRelayList );//add by alvinzcl_mem_free(Rtgbuf);zcl_mem_free ( msgBuf );}else{status = ZMemError;}return ( status );}

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

Jesse Huang:

回复 Alvin Chen:

我将“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 securityif ( !( 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 Codeif ( manuCode != 0 ){hdr.fc.manuSpecific = 1;hdr.manuCode = manuCode;}// Set the Command Directionif ( direction ){hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;}else{hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;}// Set the Disable Default Response fieldif ( disableDefaultRsp ){hdr.fc.disableDefaultRsp = 1;}else{hdr.fc.disableDefaultRsp = 0;}// Fill in the Transaction Sequence Numberhdr.transSeqNum = seqNum;// Fill in the commandhdr.commandID = cmd;// calculate the needed buffer sizemsgLen = zclCalcHdrSize( &hdr );msgLen += cmdFormatLen;// Allocate the buffer neededmsgBuf = zcl_mem_alloc( msgLen );if ( msgBuf != NULL ){// Fill in the ZCL HeaderpBuf = zclBuildHdr( &hdr, msgBuf );// Fill in the command framezcl_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 securityif ( !( 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 Codeif ( manuCode != 0 ){hdr.fc.manuSpecific = 1;hdr.manuCode = manuCode;}// Set the Command Directionif ( direction ){hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;}else{hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;}// Set the Disable Default Response fieldif ( disableDefaultRsp ){hdr.fc.disableDefaultRsp = 1;}else{hdr.fc.disableDefaultRsp = 0;}// Fill in the Transaction Sequence Numberhdr.transSeqNum = seqNum;// Fill in the commandhdr.commandID = cmd;// calculate the needed buffer sizemsgLen = zclCalcHdrSize( &hdr );msgLen += cmdFormatLen;// Allocate the buffer neededmsgBuf = zcl_mem_alloc( msgLen );if ( msgBuf != NULL ){// Fill in the ZCL HeaderpBuf = zclBuildHdr( &hdr, msgBuf );// Fill in the command framezcl_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 );
}

Jesse Huang:

回复 Alvin Chen:

请问“根据relaycnt开辟新的空间来使用”和直接引用形参的指针具体不同在哪里?

Alvin Chen:

回复 Jesse Huang:

relaycnt可以知道pRelayList存了几个地址。直接引用我没有去看源码猜测依据relaycnt去对pRelayList地址为给某个要用的地址。

直接引用可能存在一些泄露问题。开辟空间后相当于从一个已知buf里面取出来,而不是通过指针地址计算。大概是这样。

赞(0)
未经允许不得转载:TI中文支持网 » 在 60 个设备的网络环境下对终端设备进行 OTA 升级返回“ZMemError(0x10)”。
分享到: 更多 (0)