协议栈: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里面取出来,而不是通过指针地址计算。大概是这样。