二、修改了负载启动的顺序,先开启辅助继电器使地相通,再开启D+D-继电器 feat: 发布V1.1.23版本,优化负载初始化继电器时序 - 更新所有头文件版本号至V1.1.21~V1.1.23,协议板固件版本更新为0x0127 - 新增纹波滤波相关宏定义与函数,实现继电器闭合后纹波过滤 - 调整负载初始化流程:先下发辅助继电器,等待回码后延迟30ms再打开北向继电器 - 优化D+/D-寄存器上位机显示单位,适配0.001V解析格式 - 补充YMODEM升级文档说明,完善传输校验与重发规则 - 清理冗余调试打印与Allegro工程日志文件
100 lines
4.8 KiB
Markdown
100 lines
4.8 KiB
Markdown
# 协议板 Boot:UPK 打包规则
|
||
|
||
## 1. 适用范围
|
||
|
||
本文用于实现协议板 App 固件的 `.upk` 打包和解析工具,适配 `apps/boot` 当前 Boot。传输层 YMODEM 规则见[协议板Boot_YMODEM上位机实现规则.md](协议板Boot_YMODEM上位机实现规则.md)。
|
||
|
||
## 2. 1K 文件布局
|
||
|
||
当前 Boot 收到第一个文件数据帧时,只取其中前 96 字节作为 UPK 头,**会忽略该帧其余数据**。因此打包文件必须使用固定 1024 字节首数据块:
|
||
|
||
```text
|
||
输出 .upk 文件
|
||
偏移 0x000 ~ 0x05F : 96 字节 UPK 逻辑头
|
||
偏移 0x060 ~ 0x3FF : 928 字节 0x00 填充
|
||
偏移 0x400 起 : package body(未加密 BIN 或 AES 加密后的 body)
|
||
```
|
||
|
||
- `.upk` 实际文件大小:`1024 + pkg_size`。
|
||
- YMODEM 元数据包的文件大小必须为上述实际文件大小。
|
||
- 上位机必须从偏移 0 开始以 `STX/1024` 发送;第一个 STX 是头区,真正 body 从第二个 STX 开始。
|
||
- YMODEM 最后一帧的 `0x1A` 补齐仅属于传输层,不能计入文件大小、`raw_size` 或 `pkg_size`。
|
||
|
||
### YMODEM 1K 帧字节数
|
||
|
||
`STX/1024` 中的 `1024` 指数据区长度,不是串口线上完整帧长度。每个完整 STX 数据帧固定为 **1029 字节**:
|
||
|
||
```text
|
||
STX 1 字节
|
||
PacketNo 1 字节
|
||
~PacketNo 1 字节
|
||
Data 1024 字节
|
||
CRC16 2 字节
|
||
总计 1029 字节
|
||
```
|
||
|
||
因此,UPK 首数据块和后续固件数据块的有效数据均为 1024 字节,实际串口发送时均应连续发送 1029 字节。YMODEM 元数据使用 SOH 帧,完整帧为 133 字节(128 字节数据区 + 5 字节控制/校验字段)。
|
||
|
||
界面中的“表头尺寸 `1024 (ymodem1k)`”应改名为“YMODEM 首数据块/头区尺寸”,并固定为 1024;UPK 逻辑头固定为 96,不能让用户修改。
|
||
|
||
## 3. 输入、分区与版本
|
||
|
||
| 项目 | 规则 |
|
||
| --- | --- |
|
||
| 输入文件 | 仅协议板 App 裸 `bin`,例如 `apps/chrg/build/chrg.bin`;拒绝 `.hex`、`.elf`、已有 `.upk`。 |
|
||
| `name[4]` | 固定 ASCII `upk\0`。 |
|
||
| `part_name[16]` | 仅允许 `app`、`download`、`factory`,ASCII NUL 结尾;协议板常规升级默认 `app`,Boot 会修正为 `download` 后安装到 `app`。 |
|
||
| `fw_old_ver[16]` | 目标设备当前版本,前 4 字节为数值 `major, minor, fix, build`,其余 `0x00`。 |
|
||
| `fw_new_ver[16]` | 新固件版本,编码同上。 |
|
||
| 版本输入 | 界面应分别提供“当前/旧版本”与“新版本”;不能只保留一个版本号,且不得写 ASCII 版本字符串。 |
|
||
| `user_string[16]` | ASCII 水印最多 15 字节,NUL 结尾,其余 `0x00`。 |
|
||
| `timestamp` | 当前 Unix 时间戳,`uint32` 小端。 |
|
||
| 大小限制 | `raw_size <= 262144` 且 `pkg_size <= 262144`,即 App/download 分区各 256KB。 |
|
||
|
||
## 4. 加密、大小与 CRC
|
||
|
||
1. `raw_body` 为原始 `.bin`:`raw_size = len(raw_body)`,`raw_crc = crc32_boot(raw_body)`。
|
||
2. 未加密:`package_body = raw_body`,`pkg_size = raw_size`,`pkg_crc = raw_crc`,`config[1]=0x00`。
|
||
3. AES:`config[1]=0x01`,使用 AES-256-CBC;Key=`0123456789ABCDEF0123456789ABCDEF`,IV=`0123456789ABCDEF`。加密前 body 必须补齐到 16 字节整数倍;`pkg_size`、`pkg_crc`对应加密后的 body。Key、IV 必须与 Boot 编译配置一致。
|
||
4. `config[0]`、`config[2]`、`config[3]` 固定 `0x00`。
|
||
5. `head_crc = crc32_boot(逻辑头前 92 字节)`;最后 4 字节按小端写入 `head_crc`。
|
||
6. 所有 `uint32` 字段按 STM32 小端序写入。
|
||
|
||
`crc32_boot()` 必须与 `apps/boot/application/func/utils.c` 的 `crc32_step(0xFFFFFFFF, data, size)` 完全一致;不能直接使用未校验的库默认 CRC32。
|
||
|
||
## 5. 96 字节逻辑头字段
|
||
|
||
```text
|
||
0x00 name[4]
|
||
0x04 config[4]
|
||
0x08 fw_old_ver[16]
|
||
0x18 fw_new_ver[16]
|
||
0x28 user_string[16]
|
||
0x38 part_name[16]
|
||
0x48 raw_size uint32 little-endian
|
||
0x4C pkg_size uint32 little-endian
|
||
0x50 timestamp uint32 little-endian
|
||
0x54 raw_crc uint32 little-endian
|
||
0x58 pkg_crc uint32 little-endian
|
||
0x5C head_crc uint32 little-endian
|
||
```
|
||
|
||
## 6. 打包完成前的强制自检
|
||
|
||
1. 重新解析刚生成的 `.upk`。
|
||
2. 校验总长度是否为 `1024 + pkg_size`,并检查 `0x60~0x3FF` 全部为 `0x00`。
|
||
3. 校验 `name`、分区名、版本字段、大小限制和 `head_crc`。
|
||
4. 校验 `pkg_crc`;未加密时还必须校验 `raw_crc`。加密时使用相同 Key/IV 解密后校验 `raw_crc`。
|
||
5. 解析页显示 `raw_size`、`pkg_size`、全部 CRC、加密状态、分区、旧/新版本和时间戳;任一项异常时禁止输出成功文件。
|
||
|
||
## 7. 当前样本
|
||
|
||
工程中的 `apps/chrg/chrg.upk` 已验证:实际长度 `155816`,`pkg_size=154792`,两者相差 1024,符合本规则。
|
||
|
||
## 8. 代码依据
|
||
|
||
- `apps/boot/application/include/firmware.h`
|
||
- `apps/boot/application/func/firmware.c`
|
||
- `apps/boot/application/func/app.c`
|
||
- `apps/boot/application/func/utils.c`
|