4. 实现差分OTA更新

任务目标

在低功耗IoT终端中,完整固件包传输耗时长、功耗高。本案例使用bsdiff算法生成旧固件到新固件的二进制差分包,并在目标设备上应用该差分包完成固件升级,验证升级后固件与原始新固件完全一致。

环境与依赖

  • 开发机:Linux/macOS,安装bsdiff工具(Ubuntu: apt install bsdiff)
  • 目标设备:支持本地差分合并的嵌入式Linux或RTOS环境,需具备bspatch可执行文件
  • 本案例以PC模拟验证流程,实际设备移植时仅需交叉编译bspatch并确保存储空间足够

实现方案

差分OTA分为两个阶段:差分包生成(在开发机离线完成)与差分包应用(在设备端执行)。生成阶段使用bsdiff对比旧固件fw_v1.bin与新固件fw_v2.bin,产出update.patch;应用阶段设备端使用bspatch将本地旧固件与差分包合并,得到新固件。为验证合并结果,计算新旧固件的SHA256哈希值进行比对。

关键完整代码

以下脚本完整覆盖差分包生成、应用与验证全流程,可直接在开发机执行(设备端仅需将bspatch调用替换为交叉编译版本):

#!/bin/bash
# 差分OTA完整验证脚本
set -euo pipefail

# ---------- 1. 准备测试固件 ----------
# 生成两个不同内容的固件文件(模拟版本升级)
dd if=/dev/urandom of=fw_v1.bin bs=1024 count=64 status=none
cp fw_v1.bin fw_v2.bin
# 修改新固件部分字节,模拟代码变更
printf '\x55\xaa\x01\x02' | dd of=fw_v2.bin bs=1 seek=2048 conv=notrunc status=none
printf '\x11\x22\x33\x44' | dd of=fw_v2.bin bs=1 seek=40960 conv=notrunc status=none

# ---------- 2. 生成差分包 ----------
bsdiff fw_v1.bin fw_v2.bin update.patch
echo "差分包大小: $(stat -c%s update.patch) 字节"

# ---------- 3. 模拟设备端应用差分 ----------
# 设备端保留旧固件,接收update.patch后执行bspatch
bspatch fw_v1.bin fw_recovered.bin update.patch

# ---------- 4. 验证恢复固件与目标固件一致 ----------
hash_v2=$(sha256sum fw_v2.bin | awk '{print $1}')
hash_rec=$(sha256sum fw_recovered.bin | awk '{print $1}')

if [ "$hash_v2" = "$hash_rec" ]; then
    echo "✅ 差分更新成功:恢复固件与目标固件完全一致"
    echo "SHA256: $hash_rec"
else
    echo "❌ 差分更新失败:哈希不匹配"
    echo "目标: $hash_v2"
    echo "恢复: $hash_rec"
    exit 1
fi

# ---------- 5. 输出压缩率参考 ----------
orig_size=$(stat -c%s fw_v2.bin)
patch_size=$(stat -c%s update.patch)
echo "原始固件: ${orig_size} 字节, 差分包: ${patch_size} 字节, 节省: $(( (orig_size - patch_size) * 100 / orig_size ))%"

运行与验证

  1. 将上述脚本保存为diff_ota_demo.sh,执行chmod +x diff_ota_demo.sh。
  2. 运行./diff_ota_demo.sh,脚本自动完成固件生成、差分、合并与校验。
  3. 通过条件:终端输出✅ 差分更新成功且两行SHA256值完全一致。若输出❌,检查bsdiff/bspatch是否安装或固件文件权限。

设备端集成要点

实际IoT设备中,将bspatch交叉编译后放入根文件系统,应用层调用:bspatch /old_fw /new_fw /received.patch。需确保设备有足够RAM或临时存储(新旧固件各一份加差分包),升级完成后重启并从新分区启动。差分包传输可采用HTTP分块或BLE批量传输,本案例聚焦差分算法本身,传输协议不展开。

常见问题

  • bspatch报错“corrupt patch”:差分包传输损坏或生成时新旧固件顺序颠倒,重新生成并校验传输完整性。
  • 合并后固件无法启动:确认设备端旧固件与生成差分包时的旧固件完全一致(包括版本号和编译时间戳)。
  • 差分包过大:若新旧固件差异较大,差分收益降低,可考虑压缩差分包或改用全量升级。