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.

zigbee升级

Other Parts Discussed in Thread: CC2538, Z-STACK

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, &param.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。谢谢!