LWIP实现网络远程IAP下载更新

  最近需要实现通过TCP/IP远程IAP在线更新功能,忙了2周终于在原有嵌入式服务器的基础上实现了该功能,这里就记录下实现的过程。  IAP又称在应用编程,其实说简单点就是实现不需要jlink,仅通过芯片自带接口如CAN,USB,Ethernet即可实现下载功能.以我用过的stm32f207芯片为例,就有三种启动方式,SRAM启动,User boot(即flash地址启动,用户应用执行),System boot(即系统地址启动,用于串口下载),看到这是否明白点什么,System boot模式下载实现的过程就是IAP应用编程,不过这段程序一般都是芯片公司烧好在内部固定地址的(一般不允许修改)。而本例中的网络远程下载更新也是实现这个过程,不过执行将完全在user boot(即flash)中。
    上面讲的都是IAP的概念,下面进入正题:
    第一步:了解ARM的启动过程(这个网上有很清晰的说明,这里就粗略讲下),上电,复位,STM32芯片根据boot引脚将中断向量表地址(起始地址)置于0x80000000,同时将PC指针置于该地址0x80000000处(这里的0x80000000是由flash地址0x08000000映射的),即起始是跳转到flash首地址,之后完成的就是建立堆栈,最后跳转到_main函数(启动文件中,当然stm32f2xx的头文件是先跳到SystemInit),此时程序正式执行。
其实了解了上面的知识,IAP的实现就比较好理解了(因为我实际操作与STM32提供的方案(见STM32F2x7_ETH_IAP)有区别,这里先以stm32提供的方案做介绍),首先肯定要有能够实现下载的程序(也就是所谓的引导guidance程序)和用户实际执行的程序,经过初步设计,在flash中结构如下图:

  其中guidance区域用于实现升级引导,user application就是用户实际运行的代码。规划好代码在整个flash中的地址,下面就是具体的实现了。由上可知guidance程序就是整个IAP实现的核心程序,它需要实现两个功能:

  (1)一般情况下跳转user application, 执行用户代码

  (2)特殊情况下进入IAP模式,可以更新用户代码(一般是按键,当然也可接收外部指令进入IAP模式)

 1. 跳转代码

  官方例程有标准代码可以直接使用,以上图为例,它实现的就是将PC指针跳转到0x08008000,此时user application处代码开始执行,注意在user application程序的main函数中需要将中断向量表重新定位到user application首地址,即需要添加NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x08008000);(一般NVIC初始化时会重定义到0x0,注意注释掉)否则应用代码的中断会不响应,这与中断响应的机制有关,默认地址为0x0,此时中断产生时查找向量表获得的地址是guidance程序中断对应地址,执行就会出错。

2.远程网络IAP实现

  远程网络IAP的实现是基于lwip的,因为lwip中网络接口层,IP,TCP层的配置与正常的网络通信并没有区别,且知识复杂,这里不在赘述,主要讲述http层代码的处理.http层代码处理包含两部分,

 1.http首部的处理

 2.正文代码的处理(即接收数据的处理)

以官方例程为例,上面两部分的处理都是在http_recv函数中实现的,想了解http发送的实际过程,那么通过抓包分析就是最简洁的方式,这里使用的就是WireShark软件。

1.上图是浏览器执行升级时发送的http首部,既然知道首部格式,那么在服务器中就可以对接收数据进行处理,上面框中数据就是需要处理的字段。首先将TCP层接收的数据存储data中,Post/upload.cgi为http包含了http的方式,url,则通过比较strncmp(data,“Post /upload.cgi”,16) == 0即可判断是否进入升级(cgi)模式。Content-Length为正文的长度,因为传输的时候都是以字符传输的,因此将接收到的字符还要转化成数字,例程中是通过Parse_Content_Length实现的。
当然也可以利用strstr函数获得正文长度,代码如下:
/*读取Content-Length的首地址*/
if((ContentLengthStart= strstr(data, "Content-Length: ")) != NULL)
{
       ptr = &ContentLengthStart[16];
}
获得ptr即为Content-Length: 后数字字符首地址,后续即可将字符数组转换成数字,见示例程序,不在赘述。
  2.首部处理完毕后,下面便是http正文的处理。
处理http正文,当然也需要对浏览器发送的包进行分析,以下图为例
http发送起始包(728字节)

http发送起始包实际内容

与上面的首部做比较即可知第一个接收到的数据包728字节仅包含http首部,其中结尾的0d 0a 0d 0a即\r\n\r\n(休止符),即确定为upload.cgi时,修改标志位(UploadSymbol),解锁flash,擦除指定地址的flash(本例中擦除sector2,3,4),获得正文长度后即可跳出,等待下个数据包的接收,下面真正开始正文的处理。

如何处理正文,还是以发送的实际数据包为准判断,其中首页和尾页要特殊处理,当然这也是根据实际传输的数据包得出的,如下。

正文首页:

正文尾页:

看到上面两段数据报文,就可以清晰的知晓,真正的程序起始是从87.I那一行开始的,程序的结尾到community那一行结束,当然红色部分整个都包含在正文数据中,这就需要我们写入flash时要去掉数据中附加的信息,因为这里比较重要,我就贴上我的处理代码:

char   *httpHeadEndStart; //首部末地址
char   *postContent;      //正文首地址
char   *pstr;
int    TotalReceived = 0;    //接收到的数据包
int    len;                 //实际接收到数据包的长度
TotalReceived+= p->tot_len;//后面参数为每一次接收到的数据包总长度
len= p->tot_len;
if((httpHeadEndStart= strstr(data, "\r\n\r\n"))!= NULL)
{
     if(httpHeadEndStart[4])
{
   postContent = & httpHeadEndStart[4];//获得正文首地址
}
}
Pstr= postContent;
if(UploadSymbol== 1) //正文接收的第一个数据包
{
    if((pstr = strstr(pstr,"\r\n\r\n"))!= NULL)//去除http附加信息
    {
       pstr = &pstr[4];            //87.行首地址
       len = len - (pstr - psl);    //减去附加信息长度,即实际数据长度
    }
}
if(TotalReceived== ContentLength)   //末尾去除http附加信息,正文接收的最后一个包
{
    if((psl = strstr(psl, "\r\n--"))!=NULL)
    {
       len = psl - pstr;
    }
   If(len)
   {
   IAP_HTTP_writedata (pstr,len); //将数据写入flash中
     TotalReceived = 0;
     UploadDateSymbol = 0;
     FLASH_Lock();
   }
}
 else
 {
     If(len)
    IAP_HTTP_writedata (pstr, len); //将数据写入flash中
  }
  UploadSymbol++;
如上,就将整个数据完整的写入flash中,当然实际工作远不只如此,如flash的解锁,写入和加锁,其中如果按照4字节即word写入,还要考虑接收到的数据包不是4的倍数的情况,这时需要从后续数据包里拿出数据凑足4字节,这部分的代码都是由IAP_HTTP_writedata函数实现,方法很巧妙,想了解的人也可以自己去解读这部分代码。
上面主要都是正常操作数据怎么处理,但有一句话说,好的代码是错误操作时也要给予合适的应对,那么客户如果没上传文件就点升级按钮了怎么办,当然了,还是老办法,先抓包分析,在给出解决办法,抓包图如下:

看到和上面有什么区别没,filename=””中间为空,那么就好办了,这里我就不给出我自己的处理办法了,例程中有:
for (i=0;i<len;i++)
{
    if (strncmp ((char*)(data+i),"filename=", 9)==0)
    {
       FilenameOffset = i+10; //获得filename=“后字符偏移量
       break;
     }
 }
i =0;
if (FilenameOffset)
{
   while((*(data+FilenameOffset + i)!=0x22)&&(i<13)) //去查ASCII表很容易就知晓0x22代表字符“
   {
     filename[i] = *(data+FilenameOffset + i);
      i++;
}
  filename[i] = ‘\0’;
}

若i == 0则跳出,表示没有接收到文件,发送出错文件,或者直接跳回当前网页都可以(具体看例程)。这只是例程中的代码,其实这段还可以延伸为只能上传指定文件名以及类型的文件,通过将i==0修改为strncmp(”filename”,”LandTiger.bin”,14)!=0就指定只能上传LandTiger.bin文件,同时上面长度也可以限定,使上传文件只能在不能超过指定的大小,这些都需要自己去亲身体会才能有收获。

时间: 2024-08-28 17:47:11

LWIP实现网络远程IAP下载更新的相关文章

Android实现网络多线程断点续传下载(转)

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是:  (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 R

Android实现网络多线程断点续传下载

本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多线程断点需要什么功能? 1.多线程下载, 2.支持断点. 使用多线程的好处:使用多线程下载会提升文件下载的速度.那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度. HttpURLConnection.getContentLength();//获取下载文件的长度 Ra

版本更新之模拟数据下载更新

在tomact服务器中自定义web服务,模拟数据下载更新 1.开启tomcat 目录apache-tomcat-7.0.68\bin\startup.bat 2.将apache-tomcat-7.0.68\webapps目录下的WEB-INF拷贝到自定义的目录中,这样就可以访问自定义内容 如:拷贝到apache-tomcat-7.0.68\myApp目录,就可以在浏览器中访问该目录下的text.txt文件 text.txt中写自定义数据: 如  版本2.0 3.开启网络下载数据, 注意:最好使用

通常所说的网络远程监控系统是什么?

通常所说的远程监控系统是一款远程监控软件,是由一台主电脑控制端远程监控另一台被控电脑端,而所谓的远程一般是指通过局域网远程监控. 当操作者使用主控制端电脑监控被控端电脑时,就如同自己在使用被控端电脑一样,清晰看到被控端电脑当前屏幕操作,可以启动被控端电脑的程序.限制访问网址.限制聊天.上网.玩游戏.禁止U盘读取以及文件传输等操作,利用网络远程监控系统,被控端电脑操作行为皆掌握在自己手中.  有什么用途? 网络远程监控系统一般是用于正当用途,比如用于企业单位对上班员工电脑的管理.规范员工上班的不良

cordova 下载更新

function UpdateForAndroid(downloadUrl) { $ionicLoading.show({ template: "已经下载:0%" }); var targetPath ="file:///storage/sdcard0/Download/yuetui.apk"; var trustHosts = true; var options = {}; $cordovaFileTransfer.download(downloadUrl, ta

[MFC] MFC音乐播放器 傻瓜级教程 网络 搜索歌曲 下载

>目录< >----------------------< 1.建立工程  1.建立一个MFC工程,命名为Tao_Music 2.选择为基本对话框 3.包含Windows Sockts 4.使用静态链接库 [方便一会直接生成的exe文件单独可以发布] 2. 搭建界面  1. 拖入控件: 2. 控件拖入并摆好 3. 控件属性设置: 3. 写代码实现功能  1.变量绑定: 2.加入图片资源 3.新建mp3类: 4.修改Tao_MusicDlg.h 5.修改Tao_Music.cpp 6

获取远程仓库的更新

如果需要同步远程仓库的分支,或者说是远程仓库有新的分支了,你需要查看,可以使用fetch来获取远程仓库的更新信息. 1.右键项目text->Team->Remote->Fetch From... 2.上图中默认配置不变,Next> 3.上图中是默认获取全部分支的更新情况,如只需获取指定分支的更新情况,按下图操作 获取远程仓库的更新,布布扣,bubuko.com

android sdk manager无法下载更新解决办法

ping ad.doubleclick.net 查看下谷歌广告域名所指向的ip,即可获取谷歌google最新可IP,这个IP也可以用于sdk manager下载更新! 获取到新IP,修改hosts文件,添加 74.125.107.89 www.google.com 74.125.113.121 developer.android.com 74.125.107.89 dl.google.com 74.125.107.89 dl-ssl.google.com 127.0.0.1 activate.a

在Centos6.6中如何配置软件下载更新源地址

一. yum是什么yum是(Yellow dog Updater, Modified)主要功能是更方便的添加/删除/更新RPM包.它能自动解决包的依赖性问题.它能便于管理大量系统的更新问题 二. yum特点1)可以同时配置多个资源库(Repository)2)简洁的配置文件(/etc/yum.conf)3)自动解决增加或删除rpm包时遇到的倚赖性问题4)使用方便5)保持与RPM数据库的一致性 三. yum安装[[email protected] ~]# yum -y install yum-3.