实例介绍
硬件是STM32+W5500 ,使用http通信协议时间iap OTA 空中升级,文档讲的比较详细,也是我见过的比较好以及比较详细的IAP讲解了。我这边顺便说说为什么要用http 通信协议,因为http通讯协议协议头里面有个body 长度字段,这样就可以采用断点续传的方式,这一点很重要。
112KB固件储存区 112 KB APP程序运行区 ×8008000 32 KB BOOT程序运行区 0x08000000 图2内存空间分配 区域 地址范围 大小 作用 BOOT区0x08000000~0XO80O7FFF32KB系统引导 APP区0X08008000-0X08023FF112KB主程序 Backup区0x08024000~0x0803FFF112KB存放更新的程序 了解了空间分配之后,我们再来看一下我们这个演示中各部分的主要功能 1.BOOT区 ●空APP区,为新APP写入做准备 把暂存在 Backup区的新版本程序拷贝到APP区; 2.APP区 APP区是应用程序运行区域,实现正常的网络连接,并更新固件。 ●配置网络参数 ●在线固件升级 每次上电都会从Boot区引导,若判断上层APP区载入程序是否成功,成功则直接从 Boot区跳转到APP区,正常运行主程序。 3. Backup区 从服务器接收并备份需要更新的新App,也就是固件存烤区域 备注白于BaCk区的大小为112k,所以意着APP的大小最大为112K; 2.程序流程设计 我门完成了对 Flash的分区规划后,就要设计我们程序的流程,图3是程序执行的流程图。 03 (02) Backup 05 APP 04 (01) 06 Boot 从起始地址开始执行程序 图3嵌入式设备固件更新流程图 每次启动嵌入式设备,均从首地址开始执行程序 ①启动进入BOOT区,若BOOT检测APP区的不为空,则跳转到APP区的首地址执行主程序 ②APP内的代码主娶实现 配置网络参数:配置IP地址,MAC地圠,建立网络连接。 远程更新固件:客户端向服务器发送固件版本查询报文。条件符合设定则进入步骤③ ③当APP将新版本的司件下载完成后,进入步骤④ ④跳转到BOOT区,执行更新操作; ⑤BOOT将APP区擦陰,并将新APP从 Backup区写入到APP区,写入完毕后擦除 Backup区 的固件; ⑥重启,重新执行程序。 我们将程序主要分为两个部分,分别为BOOT程序和APP程序。APP栏序即是我们的固件下载 程序对应流程图的①②③步,BOOT程序既是固件更新程序对应流程图的④⑤⑥步: 3.APP程序设计(固件验证与下载) APP代码程序初始化网络配置参数,实现嵌入式设备与服务器的正常连接,下载司件到 Backup区,图4描述约为嵌入式设备与服务器的通信过程 固件服务器 嵌入式设备 打开端口 打开端口 建立连接请求/应答 侦听 连接 建立 建立 HTTP请求/应答 应答 请求 断开 断开 断开连接请求/应答 关闭端口 关闭端口 图4服务器嵌入式设备通信过程示意图 固件服务器嵌入式设备的通信过程大致分为三步 1.连接:嵌入式设备分配 socket并连接刭服务器。 2.通信:连接建立后。服务器在接收到来自嵌入式设备的请求后发送应答。 3.关闭:请求/应答完成后关闭连接。 我们APP区的函数主要做的就是下或件,在程序旦我们是通过w5500 version0和 w5500 update0两个函数来实现的,w5500 version0来验证当前的版本号与服务器上的版本 号是否相同,如果当前版本号小于服务器上的版本号就进行更新。 01 void w5500 version(void) uint8 recv buffer[20481 04 nt8 version L_0」; switch (getSn SR(W550O UPDATE))( 06 case SOCK ESTABlIsheD 07 if (getsn IR(W5.500 UPDATE)& Sn IR CON) t setsn IR(W5500 UPDATE, Sn IR CON) 09 send(W55C0 UPDATE,(const uint8 *)postH, sizeof(postH));//Ris 验证 11 De ay ms(5000)i 12 if ((le getsn RX RSR(W5500 UPDATE))>0)( 13 len recv(5500 UPDATE, (uint8*recv buffer, len);//t 收数据 14 if( strstr(( charx) recv buffer,"\" error\""))(//报文内包含 err,就结束函数 printf("upload error\r\r:") 16 return 17 18 printf("s\r\n", recy buffer);//打印服务器响应报文 mid((cnar+) recy buffer,"\" version\":",",",(char*) version);//可以获取路 20 读取版本号******为大*★/ if (strncmp(ver num, version,7)<0)i 22 date flac=l 3 mid((char*)recybuffer,""http://n5500.com./fwupdate/uplcad/","","i char) bin name);//可以获取路径 24 snprintf(post msg, sizeof (oost msg) 25 PosT/fw update/upload/%s Http/1.1\Rin"\ 26 Host: 5500. com\r\n "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"\ 27 no-cache \r\n'n 8 cept-Encoding: gzip, deflate\r\n"\ 29 ""Connection: keep-alive\r\n"\ n name) printf(" The version is是s、rn", ver num) 32 else t printf("The version is s\r\n", version)i 34 printf( The version is ro need to updater")i 35 retur 36 38 close(w5500 UPDATE ); 39 break 40 case socK○sEA工: break 42 case socK closed 43 socket(w5500 UPDATE, Sn MR TCP, 30000, Sn MR nD)i 44 break 45 case sock工N工T 46 connect(w5500 UPDATE, server ip server port) 47 break 48 上述函数中W5500先与固件服务器建立 TCP Socket连接,然后通过send函数发送固件 查询报文“" posth”,该报文主要功能是把W5500的MAC地址发送给服务器 01 char posth[]=( 02 PosT /ew update/2.php Http1. 1\r\n"\ "Host: w5500. conmr\n"\ 04 e/gif age/ipe e/pipe 05 "User-Agent: Mozilla/4.0(compatible; MSTE 5.5; Windows 98)\r\n"\ eng 07 Contert-Type: application/x-www-form-urlencoded\r\n"\ 08 Cache-Control: no-Cache\r\n"\ 09 "Connection: close\r\n"\ 10 An\ 11 "mac=00:08:DC:11:12:13" 2} 服务器端会根据传送的MAC地址检查设备是否注册以及是否有相关类型的固件。如果验证 不通过固件服务器就会向嵌入式设备发送 error信息。如果验证通过服务器会向嵌入式设备同复 如图5所示的报文,报文中包含最新的版本号、下载路径、固件大小、文件Hash校验值等4 个关键信息:{" version”"ⅩⅩX"””"path”:”…”;”size”:”XX”,”hash”;”…”},客户 端收到这4个关键信息后,先提取版本号与当前版本号比较如果比当前版本号新则置位更新标 志位并且拼接下载固件的报文。 Http/1.1 Date: Tue, 13 Jun 2017 01: 41: 50 GMT Server: Apache/2. 4.23 CWin32)OpenSSL/1.0. 2h PHP/5. 6. 24 x-Powered-By: PHP/ 5.6.24 Content-Length: 177 Connection: close Content-Trpe: text/ html: charset=utf-8 I"version":1.0.1path:http://w5500.comfwupdateyuploade9564fe altbd5b8ebd195b2c8948088834ca45ce. binsize:11 hash:e9564 feal Tbd5baebd195b2ca94a08aa34ca45ce"I 图5查询报文 通过检查固件更新标志位,当发现此标志位置位后就运行W5500upae0函数进行固件的 下载,首先我们要为嵌入式设备分配一个 Socket w5500 UPDATE,这个 Socket初始状态为 SOCK CLOSED,我们通过调用函数 socket(W5500 UPDATE, Sn mr tcp30000, Sn mr nd), 打开 Socket, Socket状态改变为SOCKⅠNT,打开 Socket后调用 connect(W5500 UPDATE, server_ip server_port)连接服务器, server__ip和 server_port分别为 服务器的IP地址和端口号,连接建立之后 Socke状态变为 SOCK ESTABLISHED,在此状态下 我们调用函数 Firmware download0进行固件的下载,具体代码如 01 void Firmware download(void) 02{ 03 if(getsn IR(W5500 UPDATE)& Sn IR CON)! 04 setsn IR(W5500 UPDATE, Sn IR CON) 05 06 send (W5500 UPDATE,(const uint.8 *)post msg, sizeof(post. msg))i// 发送验证 Delay ms(3000)i 08 if ((len =getSn RX RSR (W5500 UFDATE))>0)i 1en=recv(W5500 UPDATE,(uint8为) Buffer,ien);//接收数据 10 id(char大) Buffer;" Content- Length:","\x\n",sub);//获取字符串 长度 11 p=strstr((char*)Buffer, rn\r\n")i 12 tmp1e=1en-(p-(char*) Buffer)-4;//第个包内的数据长度 13 content len=ATOI32(sub, 10)i 14 write f1ag( content1en);//将国件长度写入 eepr oit 15 while (rxlen!=content len) i 16 if (rxlen ==0)1 17 Erase Page();//擦除fash内的数据 18 if( tmplen2)!=0)(//如果是奇数个数据 20 tai=Bu=er[1en-1;//侏留最后一字节的数据 22 for(i=0;i< tmplen-1;i=i+2)//半字写入 23 data=*(p+4+i+1); 24 data=(data<<8)+(*(p+4+i)); 25 FLASH PragramHalfWord(flashiest, data)i 26 recv count++i flashiest + 2: rxlen tmpleni tmp len=0 3 else if (rxlen>0) 32 memset(Buffer, oxff, 2048) tmplen= getSn RX RSR (WS500 UPDATE if (tmplen>0)( if(fg=1){//判断上个包是否有数据 36 tinplen=recv(W5500 UPDATE (uinta)(Buftertl),tmplen) 3 uffer0]=-ai1;//拼接数据 38 if((( tmplen+1)号2)!=0){/总字节数是奇数,fg置位, 取出最后一个字节 40 tail-Bufferlcmplen] 41 data1en= tmplen+1;//总字节数 12 }e1se【//总字节数为偶数 43 flg=0;//清除标忐位 44 七ai1=0 data len tmplen+1 46 47 }e1se【//上个包为偶数个数据 49 tmplen-recv(W55C0 UPDATE, (uint8*) Buffer, tmplen)i if((tmp1en号2)!=0)://本次数据包为奇数个 f1g=1;//标志位置位 七ai1= Buffer[mp1en-1];//保存最后一个数据 54 data len =tmpleni 56 f((rx1en+ tmplen)== content1en)(//判断是否为最后一个包 data len data len +2 58 for (i=0; i<data len-l; 1+=2), data= Buffer li+1」; (data<<8)+ Buffer[i] 62 FLASH ProgramHalfWord(lasadest, data)i flashdest +=2 recv count++i 66 axle 70 FLASH Lock(i 71 date flag=2 72 在 Firmware download0函数中,向服务器发送请求下載亘件的报文 post_msg,服务器在牧到 报文以后,会向嵌入式设备发如图5所示的下载送响应报文,并开始传送固件,我们通过下载 响应报文中 Content-Length获取待传送固件的长度 content len然后根据文件长度去获取数据 并将数据写入fash的 Backup区。通过以上的函数操作,我们已经从服务器成功的获取了固仁 文件即完成我们的APP下载的步骤。 【实例截图】
【核心代码】
标签:
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论