嵌入式物联网设备OTA全量、增量升级(bsdiff+Hdiffpatch+Xdelta)

文章探讨了全量升级和差分(增量)升级在嵌入式设备中的应用,重点介绍了Bsdiff、Xdelta和Hdiffpatch等差分算法,以及在资源受限的MCU中的实现策略,强调了低功耗、断电保护和异常处理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、全量升级

方案一:

在这里插入图片描述

升级包在APP或者boot中下载,flash中共有3个区,boot区,A区、B区。这种方案需要一个额外的分区用来存放下载的升级包,一般称为B区,A区存放APP程序,在升级包下载完成后对B区代码进行完整性校验,然后进入boot中进行B区代码向A区搬运,搬运完成进行校验,然后跳转。

方案二:

在这里插入图片描述

升级包在BOOT中下载,flash中只需要2个区,boot区,A区。A区存放APP代码,在有升级事件发生时直接跳转到boot中进行APP下载,直接下载到A区,下载完成后校验,然后进行跳转。

二、差分(增量)升级

1.差分/增量升级概述

在这里插入图片描述

借用网上的介绍:适合嵌入式的差分升级又叫增量升级,顾名思义就是通过差分算法将源版本与目标版本之间差异的部分提取出来制作成差分包,然后在设备通过还原算法将差异部分在源版本上进行还原从而升级成目标版本的过程。 差分升级方案不仅可以节省MCU内部的资源空间、还可以节省下载流程及下载和升级过程中的功耗、而且还可以减少数据包在空口的不稳定性。也就是说,差分升级是拿以前旧设备内的bin,和当前新版本的bin用某种算法算出他们的差异部分,然后在借助压缩算法,生产一个极其小的差分包,然后将这个差分包下载到设备中,设备在根据解压算法、差分还原算法,生产一个完整的新版本bin,然后将这个新版本bin刷到执行区执行代码。

2.差分/增量升级意义

差分升级一般来说,可以极大的减少下载量,特别是对于小资源的嵌入式单片机来说,可以极大的减少维护成本,因为嵌入式设备的升级维护一般都是空中ota升级,比如NB-IoT、LoraWan、蓝牙、红外等,下载速度受到波特率、包长、空口环境等限制,更新固件包非常的慢,而差分升级可以让下载的过程极大的缩小。正常的维护版本,生成的差分包bin理论上在原bin的%5左右,80K的文件小改动实测差分包仅有3K。对于像水表、燃气表、报警器、断路器、雷电流检测等应用程序维护有一定帮助意义。

3.差分算法

在构造差分增量包中,常见的算法有Bsdiff算法、Xdelta算法、Hdiffpatch算法等。

Bsdiff算法

在匹配新旧文件过程中,有部分源代码内容完全相同,有部分源代码相似度很高,只有部分字节作了稀疏改动,另有一些源代码内容相同,但是存储地址存在一个固定的偏移量,对于这一特性的源代码数据,具有高度的可压缩性。Bsdiff算法引入了diff string的概念,在新旧文件中找到这样的两部分内容,求出字节的差异,作为diff string进行压缩。而对于不符合要求的新文件源码中新增部分,作为extra string进行保存。
Bsdiff算法在匹配时,先对旧文件的所有字符进行后缀排序形成一个字典,然后使用二分查找算法找到最优的匹配长度,依次得到整个文档所有的diff string和extra string,把这些文件信息以bzib2的方式压缩成升级增量文件。
Bsdiff算法的增量文件中的数据由四部分组成:Header,ctrl block,diff block,extra block。
Header 头文件包含了目标文件的起始地址,新文件大小,控制长度等。
ctrl block提供控制部分信息,指示旧文件中保留的长度,以 及 需 要 从 diff block 和 extra block 中提取的信息,在旧文件中信息的地址偏移量等。
diff block,extra block 分别包含所有的 diff string和 extra string。
设备端在接收到patch文件后,解压文件,并根据差分文件的组成格式,通过bspatch算法,还原生成新文件。
由Bsdiff算法原理可知,它所生成的patch文件并不会比源文件小,但是文件结构压缩性强,导致传输的升级数据量比完整升级要小很多,有效减少了冗余数据传输量。Bsdiff 算法高度依赖压缩算法,当升级文件修改的内容小概率地满足稀疏变化时,差分文件的压缩效率降低,相比整包升级的优势不明显。

Xdelta算法

Xdelta 和其他的差分升级算法一样,也需要对新文件和旧文件进行比较匹配作差分。在产生 patch 包时,Xdelta 可采用 hash 或者 suffix trees 等算法来寻找最大的匹配长度的字符串。
Xdelta 差分算法的 patch文件中用到了 add、run 及 copy 三种命令。其中 add 用于将匹配到的指定长度的字符串从源文件拷到目标文件,run 用于在目标文件中加入新文件的增加部分,copy 将匹配到的文件成块的移动到目标文件中的目标地址上。
Xdelta 对增量文件采用 Vcdiff 格式的编码方式,用 128 进制的数据表示形式,经过重编码的字符,相较于原数据节省了存储空间,达到了高效压缩的目的。
Xdelta 算法的 patch 生成过程可通过其他算法来优化,考虑到设备端的内存消耗,patch 过程引入了Windows 块技术,随着 Windows 块变大,可达到的最长字符串的匹配结果越精确,产生的 patch 文件越小,但同时也会消耗更多的内存资源。因此,采用高效的匹配优化算法和适合的 Windows 块大小,是 Xdelta 算法的关键。

Hdiffpatch

Hdiffpatch是一种高效的增量算法,在运行时间复杂度及内存空间占用率上相较于前两种算法存在很大的优势。Hdiffpatch在差异文件生成阶段引入了覆盖线C的概念,用于标志新旧版本文件的匹配度。算法将两版本程序文件看成两个具有不同长度的数组,分别表示newData[m]和oldData[n]。
覆盖线C是点Ei.jj的集合,其中newData[i] = oldDta[j]。
如果C = {Ei,j,Ei+1,j+1,…,eI+K,J+K},表示该覆盖线的长度为k。
由此可知,经过匹配之后存在许多长度不等的覆盖线,根据差分包制作经验,当覆盖线长度大于7时,增量算法优势明显。
patch文件就是所有满足要求的覆盖线和newData[m]中没有被匹配上的数据组成的文档。
其中覆盖线表示信息结构包括:newPos,表示在新文档中的起始位置i;oldPos,表示在旧文件中的起始位置j;length,表示覆盖线长度k。
Hdiffpatch算法对匹配的覆盖线采取优化措施。其中包括:
覆盖线包含。如果覆盖线a被另外一条完全包含,则在C中删除a信息,以减小重复信息来简化差分文件。
覆盖线合并。对于在一条直线上的两段覆盖线,如果它们之间的间隔长度小于某一值,则把这两条覆盖线合并成一条,其中的延长部分数据作为patch文件的一部分。
覆盖线删除。对于某些单独的覆盖线,做扩展成本比较大,无法进一步优化,在patch文件生成时,对此进行直接删除,以减小存储及升级的控制代价。

4.差分升级方案

传统的升级方案都会有一个差分还原区来存放还原后的升级包,flash分区如图:
在这里插入图片描述

由于本应用MCU FLASH资源受限,无法有APP差分还原区,只能在差分还原过程中边还原边搬运到APP,分区如下图:
在这里插入图片描述

根据方案最后方案选择了Bsdiff算法+minilzo压缩算法。
本方案中采用使用瑞萨16位低功耗MCU,其具有 128K 的 FLASH,8KB RAM,boot中同时支持全量升级方案和差分(增量)升级方案,当差分升级出现异常时可以采用全量升级进行升级,bootloader 中还将包含 Bspatch 算法及与minilzo解压缩算法。升级过程中需要低电、掉电保护,考虑断电续升级;下载过程中需要考虑空口环境,加入断点续传等异常功能,保证系统的强壮性。

引用 https://www.niftyadmin.cn/n/4934614.html?action=onClick

### HDiffPatch 工具概述 HDiffPatch 是一种高效的差异算法工具,广泛应用于 OTA 升级场景中。它通过计算两个文件之间的差异生成补丁文件,并允许接收端利用该补丁文件恢复到最新的版本[^4]。 #### 安装下载 HDiffPatch 的源码和预编译二进制文件可以在其官方 GitHub 仓库或其他可信开源平台获取。以下是常见的安装方式: 1. **从源码构建** 需要先克隆项目仓库并按照 README 文件中的指导进行编译。通常依赖于 CMake 和其他开发库。 ```bash git clone https://github.com/quickfix/hdiffpatch.git cd hdiffpatch mkdir build && cd build cmake .. make ``` 2. **使用预编译包** 如果不想手动编译,可以直接下载适用于操作系统的可执行文件或动态链接库 (DLL/SO),具体地址可以通过搜索引擎查找最新发布的资源页面。 --- ### 基本用法 假设存在旧版程序 `program-1.0` 和新版程序 `program-2.0`,下面介绍如何创建以及应用补丁文件。 #### 创建补丁文件 运行以下命令会基于两份数据集制作一个名为 `program-2.0.patch` 的差分文件: ```bash hdiff program-1.0 program-2.0 program-2.0.patch ``` 此过程涉及复杂的字节级别对比分析,最终输出的是高度优化的小型更新包[^3]。 #### 应用补丁文件 当另一台机器上仅有原始副本而缺乏完整的新镜像时,则可通过如下指令实现同步升级: ```bash hpatch program-1.0 program-2.0.patch program-2.0 ``` 上述语句表明将以增量形式调整现有内容直至匹配目标状态为止[^1]。 --- ### 进阶参数解析 为了满足不同业务需求下的灵活性定制化选项众多,这里列举几个常用开关及其作用意义: | 参数名 | 描述 | |--------------|----------------------------------------------------------------------------------------| | `-l/--level` | 设置压缩等级,默认值为6,在速度体积之间寻找平衡点 | | `-t/--threads` | 并行处理线程数设定 | | `-s/--split-size` | 划分子块大小控制单位MB | 更多细节参见帮助文档或者直接调用内置手册查看全部可用配置项列表: ```bash hdiff --help ``` --- ### 实际案例分享 考虑到实际应用场景可能较为复杂多样,比如面对大规模分布式存储环境下的海量对象同步任务,此时可以借助脚本来批量自动化整个流程。例如 Python 脚本片段展示了一个简单例子来演示如何集成这些外部工具完成特定目的的功能扩展。 ```python import subprocess def generate_patch(old_file, new_file, patch_output): result = subprocess.run(['hdiff', old_file, new_file, patch_output], capture_output=True) if result.returncode != 0: raise Exception(f"Error generating patch: {result.stderr.decode()}") def apply_patch(base_file, patch_input, output_file): result = subprocess.run(['hpatch', base_file, patch_input, output_file], capture_output=True) if result.returncode != 0: raise Exception(f"Error applying patch: {result.stderr.decode()}") if __name__ == "__main__": try: generate_patch('old_version.bin', 'new_version.bin', 'update.patch') apply_patch('old_version.bin', 'update.patch', 'updated_version.bin') print("Operation completed successfully.") except Exception as e: print(e) ``` 以上代码展示了如何封装基础命令行为以便更好地融入现代软件工程实践当中去[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值