SMARTWATCH 学习手册有 C 基础 · 嵌入式从零开始
五 B / 无线固件升级 / 02

接收到一半断开,为什么旧程序必须还在

从失败场景反推暂存和状态记录。用两个普通文件实际收一份候选内容,每次命令结束后都可以重新读取进度。

接续上一篇:固件文件怎样变成可以执行的镜像

1 · 先看直接覆盖的后果

若接收一块就覆盖当前应用,第一块写入以后旧应用已不完整,新应用又还没收全。此时断连或掉电,可能没有任何一份可启动内容。升级的第一项要求是:接收失败时仍保留一条可恢复路径。

普通文件模拟分工;实际 Flash 与启动分区需要另行实现和验证。
普通文件模拟分工;实际 Flash 与启动分区需要另行实现和验证。 · 教学示意

2 · 先启动一份普通文件实验

在独立练习目录运行 · 文件内容是 12 字节人工文本

python -c "from pathlib import Path; Path('new.bin').write_bytes(b'new-demo-app')"
python ota_files.py --root update_practice init
python ota_files.py --root update_practice begin new.bin
python ota_files.py --root update_practice chunk new.bin --offset 0 --length 4
python ota_files.py --root update_practice status

init 创建旧文件和初始状态,begin 选择非当前确认槽并登记大小、摘要和目标,chunk 只写本次四字节,status 从磁盘重新读取。每条命令都是一次独立进程,不依赖上一个 Python 进程内的变量。

3 · 重复块和错序块怎样处理

示例采用顺序传输,只接受当前进度处的新块,或已收范围内内容完全一致的重复块。未来位置的块被拒绝,重复数据不再增加进度。这个约定使停止等待和超时重传容易推理,和主线逐片确认的思想相接。

真实无线分片还要带事务编号和对应确认,不能把旧升级的重试块放进新升级。样例从同一输入文件取块并检查摘要,演示内容一致性;完整无线协议仍需根据项目三端实现。

4 · 进度记录和内容谁先持久化

示例先把候选槽标为无效,再复用候选文件;每块先写内容并刷新,再保存进度。若进程恰在内容写入后、进度更新前停止,重发同一偏移可安全重写。状态文件通过临时文件替换,避免把半段 JSON 当完整记录。

这只模拟进程重启边界。实际掉电还涉及文件系统、Flash 编程与元数据的物理原子性,普通文件的 os.replace 和 fsync 不构成芯片掉电保护证明。

5 · 只有收全,才进入下一阶段

补齐剩余八字节并检查

python ota_files.py --root update_practice chunk new.bin --offset 4 --length 8
python ota_files.py --root update_practice finish

finish 需要进度等于预期大小、实际文件长度正确、摘要一致。检查失败时旧确认槽仍保留;成功只标记待试运行,还没有永久采用新内容。

动手观察

收到四字节后退出终端,再运行 status 和后续命令。重复第一块、尝试未来偏移、删去尾部内容,分别观察拒绝结果及旧槽是否完整。

资料与代码

配套文件

先复制到独立练习目录;用法见 支线示例说明。