zigbee升级
cc2538出厂的时候自带uart升级boot吗?
好像没有,我这边最近也在做CC2538 OTA升级开发,遇到很多问题,其中多次升级同一个固件之后变砖就是致命的一个,目前还没有解决,@VV还在想办法帮忙分析原因,之前我在也在e2e上问了,TI工程师JasonB也还没给回复。
我的OTA升级,最多同时10个升级,多了升级不了,你用的是哪个版本的固件?
应该不止是十个,十个以上也是能升级的,因为每次只是请求offset,每次都不同,主机端负责读取文件,然后返回。
如果说设备多了,很可能会导致ota server 端处理不过来,这是有可能的。
源码里面定义的最大节点数是20个,我用ota同时更新2个cc2538都不行,感觉是znp的串口处理数据太慢导致的。
不是串口慢,而是znp自身处理速度慢,每次每个节点block request最多只有32byte,20个同时请求才多少数据,没多少;
我测试了3个节点同时block request OTA升级,是可以同时进行的,只是偶尔某个会卡一下又继续了,估计是znp处理没有响应block response,但是也没有超时失败。
你应该是用修改后的程序测试的吧,我用源码测试,同时ota2个,其中一个卡死,一个可以ota。
你需要分析zcl_otaserver_lnx.c文件里面的zclOTA_Srv_QueryNextImageReq函数,这里面处理版本判断是最佳位置;
说实话,server端的源码我都没看过,每次测试出现问题我们都怀疑是server端的问题,老大就是一口咬定server没问题,翻来覆去的改linux gateway的代码。日了狗了,浪费了好多时间。谢谢大神指导。
有个问题请教一下:zclOTA_Srv_QueryNextImageReq()函数中获取的filed应该是client传递过来的(也就是在sample_app_ota.cfg中写入的zigbee文件),从而可以获取field.version;改version跟cc2538中version(默认0x00000001)对比,但是我不知道这个值怎么获取。
在zcl_otaserver_linux.c中的zclOTA_Srv_QueryNextImageReq()中修改代码如上截图,测试发现不能避免重复ota,我这样改有什么问题?谢谢!
由于IAR编译出来的OTA firmware是BEBE-2538-AAAA0000.zigbee和BEBE-2538-BBBB1000.zigbee,对应的版本号分别是0xAAAA0000,和0xBBBB1000,所以不要修改,直接拿其做判断就可以了,参考下我的代码:
zclOTA_FileID_t remoteFileId; memset(&remoteFileId,0x00,sizeof(remoteFileId)); memcpy(&remoteFileId,&pParam->fileId,sizeof(pParam->fileId)); dbg_print(PRINT_LEVEL_INFO,"zclOTA_Srv_QueryNextImageReq: remote manufacturer: 0x%x type 0x%x file version 0x%x\n", remoteFileId.manufacturer, remoteFileId.type, remoteFileId.version); // Request the next image for this device from image database status = OtaServer_GetImage(&pParam->fileId, &imageSize, pParam->hardwareVersion, NULL, options, pSrcAddr); dbg_print(PRINT_LEVEL_INFO,"zclOTA_Srv_QueryNextImageReq: Match image for manufacturer: 0x%x type 0x%x file version 0x%x returned with status 0x%x\n", pParam->fileId.manufacturer, pParam->fileId.type, pParam->fileId.version, status); //sanity check remote and will upgrade firmware version(Image A or Image B) prevent incorrect firmware if((remoteFileId.version == 0x1 && pParam->fileId.version == 0xAAAA0000)|| (remoteFileId.version == 0xAAAA0000 && pParam->fileId.version == 0xAAAA0000) || (remoteFileId.version == 0xBBBB1000 && pParam->fileId.version == 0xBBBB1000)) { //if remote version equal current version,we must be not upgrade firmware(ping-ponging for CC2538 soc) queryRsp.status = ZOtaImageInvalid; dbg_print(PRINT_LEVEL_INFO,"zclOTA_Srv_QueryNextImageReq: current firmware not suitable 0x%X ,upgrade abort\n",pSrcAddr->addr.shortAddr); goto Ended; }else{ //perfect }
2个问题:
1、memcpy(&remoteFileId,&pParam->fileId,sizeof(pParam->fileId)); 这样可以获取remoteFileID吗?
2、对于版本判断的逻辑,有个小错误,spec中规定ota本地更新版本必须要大于远程版本,假如更新版本为0xAAAABBBB,其值介于0xAAAA0000和0xBBBB1000之间,你的逻辑判断是可以进行ota的,但却与spec规定相悖;相当于人为引入了错误。
最后,非常感谢大神的无私分享!
1、首先,spec规定是死的,人是活的。CC2538由于使用了ping-ponging这种OTA升级方式,如果严格按照spec的来,每个新的版本号必须大于旧的,那么就会出现Image A 版本00,版本01,版本02..... 同样Image B也会出现版本01,版本02,版本03......,这给firmware的管理带来很大的难度,一定会出现这一次必须用Image B的02版本,下一次必须用Image A的03版本,02版本是不行的。
2、可能TI也认识到了这一点,所以在client接收“image response”的处理函数zclOTA_ProcessQueryNextImageRsp里面,并没有判断version版本号,而是只判断了type和manufacturer,这里的type无非是0x2538或者0x2530,manufacturer无非定义好的0xBEBE。
// verify manufacturer id and image type if ( ( param.fileId.type == zclOTA_ImageType ) && ( param.fileId.manufacturer == zclOTA_ManufacturerId ) ) { // store file version and image size zclOTA_DownloadedFileVersion = param.fileId.version; zclOTA_DownloadedImageSize = param.imageSize; // initialize other variables zclOTA_FileOffset = 0; zclOTA_ClientPdState = ZCL_OTA_PD_MAGIC_0_STATE; // set state to 'in progress' zclOTA_ImageUpgradeStatus = OTA_STATUS_IN_PROGRESS; // store server address zclOTA_serverAddr = pInMsg->msg->srcAddr; // Store the file ID osal_memcpy ( &zclOTA_CurrentDlFileId, ¶m.fileId, sizeof ( zclOTA_FileID_t ) ); // send image block request osal_start_timerEx ( zclOTA_TaskID, ZCL_OTA_IMAGE_BLOCK_REQ_DELAY_EVT, zclOTA_MinBlockReqDelay ); status = ZCL_STATUS_CMD_HAS_RSP; // Request the IEEE address of the server to put into the // ATTRID_UPGRADE_SERVER_ID attribute ZDP_IEEEAddrReq ( pInMsg->msg->srcAddr.addr.shortAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 ); osal_stop_timerEx ( zclOTA_TaskID, ZCL_OTA_IMAGE_QUERY_TO_EVT ); } }
3.能不能获取到remoteFileID,我们随便找一个Z-Stack 3.0的 OTA dongle工程分析一下,找到MT_OTA.c文件,可以看到,OTA client发送给OTA server的“image request”一定让MT_OtaGetImage函数来处理,这个函数里面是添加了fileID这一项的,最后把请求发送Z-Tool控制台,这里我们认为Linux gateway扮演了控制台的角色,只是由于2014年释出的zigbee Linux geteway并不适应最新的Z-Stack 3.0 ZNP工程,所以我做了两件事情,一、不得不把OTA dongle里面的OTA移植到最新的Z-Stack 3.0 ZNP工程里面,而且让它工作,另外添加了“image notify”功能,默认是不带的;二、把zigbee Linux gateway里面的OTA server源码单独移植出来使用,这样就脱离了复杂且容易出bug的gateway代码。目前测试下来没有问题,已经实现了OTA server升级各个client。
uint8 MT_OtaGetImage(afAddrType_t *pAddr, zclOTA_FileID_t *pFileId, uint16 hwVer, uint8 *ieee, uint8 options) { uint8 msgLen; uint8 *pBuf; uint8 *p; // Get length msgLen = MT_OTA_GET_IMG_MSG_LEN; // Allocate a buffer if ((p = pBuf = MT_TransportAlloc(0, msgLen)) != NULL) { // build header *p++ = msgLen; *p++ = (uint8) MT_RPC_CMD_AREQ | (uint8) MT_RPC_SYS_OTA; *p++ = MT_OTA_NEXT_IMG_REQ; // Add the file ID p = OTA_FileIdToStream(pFileId, p); // Add the device address p = OTA_AfAddrToStream(pAddr, p); // Add the options *p++ = options; // Add the hardware ID (optional) *p++ = LO_UINT16(hwVer); *p = HI_UINT16(hwVer); if (ieee) osal_memcpy(p, ieee, Z_EXTADDR_LEN); // Send command to server MT_TransportSend(pBuf); return ZSuccess; } return ZMemError; }
4.也许正如@VV所说,TI还在开发新的zigbee Linux gateway以适应最新的Z-Stack 3.0协议栈,但至少到目前为止,还没有释出任何代码,所以基本上还得依赖旧的版本来开发,或者使用简单的znp-host-framework代替多进程且容易出问题的zigbee Linux gateway,最后,理解了整个zigbee端的代码和gateway端的代码,做起来都得心应手。
1、仔细思考了下,感觉你这个设计思路很赞!本质就是固定2个更新版本,AAAA0000和BBBB1000,排除同一个版本重复更新的干扰,反复更新即可;相比于spec的规定,确实减少了很多版本命名方面的麻烦,perfect!
2、我还没有用Z-Stack 3.0,沿用老版本Z-Stack Home 1.2.2a.44539
3、对于获取remoteFileID问题,说一下我的理解:首先定位到zcl_otaserverlnc.c中zclOTA_Srv_QueryNextImageReq(),当app端没有执行“O”(OTA update)操作前,pParam->fileID.version获取的是远程clien端固件默认version(0x00000001),将值保存到remotefileID.version,当执行“O”操作时,pParam->fileID.version获取的是本地image database里面的固件version(0xAAAA0000或者0xBBBB1000);不知我这样理解是否正确?
另:你第3条中说的移植ota_dongle的ota到znp以及移植otaserver,不是太明白。
因为我想在最新的Z-Stack 3.0 ZNP工程上支持OTA更新,但是ZNP工程本身不带任何OTA的成分,所以需要移植,另外也要配置host的OTA server,我想让代码都放在ZNP端简单一些,如果都把AF过来的消息送到host端处理代码太繁琐。
我在zcl_otaserver_lnx.c中的zclOTA_Srv_QueryNextImageReq()函数里面,参考你的代码,添加对版本判断的内容,为什么编译后,重新执行./zigbeeHAgw,还是不能规避重复更新。
我是编译整个源码包,然后tar解包,使用新生成的zigbeeHAgw脚本。
ZStatus_t zclOTA_Srv_QueryNextImageReq(afAddrType_t *pSrcAddr,
zclOTA_QueryNextImageReqParams_t *pParam)
{
uint8 options = 0;
uint8 status;
uint32 imageSize;
zclOTA_QueryImageRspParams_t queryRsp;
/********************************************************************************/
//获取remotefileID.version
zclOTA_FileID_t remotefileID;
memset(&remotefileID, 0, sizeof(remotefileID));
memcpy(&remotefileID, &pParam->fileId, sizeof(pParam->fileId));
uiPrintfEx(trDEBUG,"zclOTA_Srv_QueryNextImageReq: Remote image for manu 0x%x"
" type 0x%x file version 0x%x",
remotefileID.manufacturer, remotefileID.type, remotefileID.version);
/********************************************************************************/
//Respond to a "Query Next" only if Permit set to 0
if (zclOTA_Permit == OTA_ENABLE_MODES__DOWNLOAD_ENABLE)
{
if (pParam->fieldControl)
{
options |= MT_OTA_HW_VER_PRESENT_OPTION; //0x01
}
// Request the next image for this device from image database
//获取Image,同时pImage->imageData->header.fileId.version给到 pParam->fileID.version
status = OtaServer_GetImage(&pParam->fileId, &imageSize, pParam->hardwareVersion, NULL, options, pSrcAddr);
uiPrintfEx(trDEBUG,"zclOTA_Srv_QueryNextImageReq: Match image for manu 0x%x"
" type 0x%x file version 0x%x returned with status 0x%x\n",
pParam->fileId.manufacturer, pParam->fileId.type,
pParam->fileId.version, status);
if (status == OTASERVER_SUCCESS)
{
//Fill in the response parameters
memcpy(&queryRsp.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
queryRsp.status = ZSuccess;
queryRsp.imageSize = imageSize; //Get Filesize using fileId ?!
uiPrintfEx(trDEBUG,"zclOTA_Srv_QueryNextImageReq: File size 0x%x\n", imageSize);
// Send a success response to the client
//zclOTA_SendQueryNextImageRsp(pSrcAddr, &queryRsp, ++zclOTA_SeqNo);
/****************************************************************************************/
//版本判断
if((remotefileID.version = 0x01 && pParam->fileId.version == 0x1A) ||
(remotefileID.version == 0x0B && pParam->fileId.version == 0x0B) ||
(remotefileID.version == 0x1A && pParam->fileId.version == 0x1A))
{
queryRsp.status = ZOtaImageInvalid;
printf("zclOTA_Srv_QueryNextImageReq: current firmware is not suitable 0x%x, upgrade abort\n", pSrcAddr->addr.shortAddr);
}
else
{
zclOTA_SendQueryNextImageRsp(pSrcAddr, &queryRsp, ++zclOTA_SeqNo);
}
//判断版本
//0x0000000B > 0x01, 0x0000001A > 0x0000000B...
//if(queryRsp.fileId.version > remotefileID.version)
//{
// zclOTA_SendQueryNextImageRsp(pSrcAddr, &queryRsp, ++zclOTA_SeqNo);
//}
/****************************************************************************************/
return ZCL_STATUS_CMD_HAS_RSP;
}
else
queryRsp.status = ZOtaNoImageAvailable;
}
else
{
//No image available, and not authorized. What should I use in case of
//abort ?
//queryRsp.status = ZOtaAbort;
queryRsp.status = ZOtaNoImageAvailable;
//Download status sent only on Upgrade End Req
//sendDownloadStatus(appConnectionHandle, pSrcAddr, OTA_STATUS__ABORT);
}
// Fill in the response parameters
memcpy(&queryRsp.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
queryRsp.imageSize = 0;
//Send failure response
zclOTA_SendQueryNextImageRsp(pSrcAddr, &queryRsp, ++zclOTA_SeqNo);
return ZCL_STATUS_CMD_HAS_RSP;
}
Hi,
1、OTA调试又遇到了问题:2538原始固件为版本为0x01,我打算更新的固件版本为BEBE-2538-0000000B.zigbee,client端会发送request请求更新BEBE-2538-0000000B.zigbee,但是server端给client端的response却是BEBE-2538-0000001A.zigbee,这个通过sniffer已经抓到了解析的数据包;百思不得其解,求大神帮忙看看。
2、OTA重复更新问题,我参照你提供的代码进行修改,测试还是不行,这个也不知道原因在哪里。谢谢了!
问题已解决。不是代码问题,是源码有问题,编译生成的可执行文件的数目不够,重新换了干净的源码,测试ok。谢谢!