feat: 完善Mesh继电器OTA升级闭环

This commit is contained in:
十七
2026-11-04 15:41:29 +08:00
parent be8bd7eaec
commit df1aad3d16
27 changed files with 1372 additions and 243 deletions
+99 -31
View File
@@ -54,7 +54,7 @@ F1 DD 09 00 0A | SRC_H SRC_L | BUSINESS | 0D 0A
JDY-28M完整Mesh帧最大20字节。当前业务帧最大DATA长度为4字节:
```text
BUSINESS = SRC_H SRC_L CMD LEN DATA CRC16_L CRC16_H
BUSINESS = SRC_H SRC_L CMD LEN DATA CRC16_H CRC16_L
```
业务帧长度为`6 + LEN`,完整外层发送帧长度为`16 + LEN`,因此`LEN`最大为4。
@@ -62,7 +62,7 @@ BUSINESS = SRC_H SRC_L CMD LEN DATA CRC16_L CRC16_H
## 2. 业务帧格式
```text
SRC_H SRC_L | CMD | LEN | DATA[0..LEN-1] | CRC16_L CRC16_H
SRC_H SRC_L | CMD | LEN | DATA[0..LEN-1] | CRC16_H CRC16_L
```
### 2.1 CRC16规则
@@ -74,7 +74,7 @@ SRC_H SRC_L | CMD | LEN | DATA[0..LEN-1] | CRC16_L CRC16_H
输入反射:是
输出反射:是
计算范围:SRC_H、SRC_L、CMD、LEN和DATA
发送顺序:CRC低字节在前,高字节在后
发送顺序:CRC高字节在前,低字节在后
```
CRC错误时设备直接丢弃整帧,不执行命令,也不返回错误应答。
@@ -87,6 +87,11 @@ CRC错误时设备直接丢弃整帧,不执行命令,也不返回错误应
应答CMD = 请求CMD | 0x80
```
当请求通过 Mesh 广播地址 `FFFF` 发送时,设备不会立即同时回复。设备会
根据本机短地址和系统时间生成约20~170ms、按10ms分档的随机延时,然后向业务帧中的
发送方 `SRC_H SRC_L` 单播回复,以降低多个设备同时应答造成的网络拥塞。
单播请求仍然直接回复。
错误应答:
```text
@@ -104,6 +109,54 @@ DATA[0] = 错误码
0x06:未知命令
```
## 3.1 `0x07` 设备上线广播
设备在本次上电完成基础初始化、蓝牙进入可通信状态后,向 Mesh 广播一次:
```text
CMD = 07
LEN = 00
```
发送方短地址位于业务帧的 `SRC_H SRC_L` 字段中,因此该命令不需要 DATA,
其他设备收到后不回复。主机或其他设备可据此更新在线状态;如果后续长期
未收到该设备的上线或业务消息,可以结合应用层超时判断设备是否离线。
## 3.2 `0x10` 固件版本发现广播
主机发现服务器存在新固件后,向Mesh广播最新版本和固件长度。该命令只用于
设备发现,不会直接启动OTA。
```text
CMD = 10
LEN = 04
DATA[0] = 最新版本高字节
DATA[1] = 最新版本低字节
DATA[2] = 固件长度高字节
DATA[3] = 固件长度低字节
```
设备收到后比较:
```text
最新版本 > 当前版本:随机延时后回复
最新版本 <= 当前版本:静默丢弃,不回复
```
需要升级的设备返回:
```text
CMD = 90
LEN = 04
DATA[0] = 当前版本高字节
DATA[1] = 当前版本低字节
DATA[2] = 需要升级的版本高字节
DATA[3] = 需要升级的版本低字节
```
设备短地址位于响应业务帧的`SRC_H SRC_L`字段中。主机收到多个`0x90`后,
生成待升级设备列表,由人工选择设备,再对选中的短地址执行后续OTA流程。
## 4. 主机下发的普通命令
### 4.1 `0x01` 继电器控制
@@ -120,7 +173,7 @@ DATA[0] = 01:继电器吸合
业务帧结构示例:
```text
SRC_H SRC_L 01 01 01 CRC16_L CRC16_H
SRC_H SRC_L 01 01 01 CRC16_H CRC16_L
```
设备执行后返回:
@@ -170,14 +223,14 @@ LEN = 00
```text
CMD = 83
LEN = 02
DATA[0] = 电流低字节
DATA[1] = 电流高字节
DATA[0] = 电流高字节
DATA[1] = 电流低字节
```
单位为mA,无符号整数,低字节在前。例如实际电流为`1000mA = 0x03E8`:
单位为mA,无符号整数,高字节在前。例如实际电流为`1000mA = 0x03E8`:
```text
DATA = E8 03
DATA = 03 E8
```
### 4.4 `0x05` 查询设备短地址
@@ -211,14 +264,14 @@ DATA = 00 0C
```text
CMD = 06
LEN = 02
DATA[0] = 阈值低字节
DATA[1] = 阈值高字节
DATA[0] = 阈值高字节
DATA[1] = 阈值低字节
```
单位为mA,默认值为100mA,设备保存到内部EEPROM。例如设置100mA:
```text
DATA = 64 00
DATA = 00 64
```
设备成功返回:
@@ -245,8 +298,8 @@ LEN = 00
```text
CMD = 8E
LEN = 02
DATA[0] = 版本低字节
DATA[1] = 版本高字节
DATA[0] = 版本高字节
DATA[1] = 版本低字节
```
当前版本在主程序`include/app_config.h`中定义:
@@ -303,17 +356,17 @@ DATA[0] = 被确认的故障码或恢复码
```text
CMD = 08
LEN = 04
DATA[0] = 固件长度低字节
DATA[1] = 固件长度高字节
DATA[2] = 版本号低字节
DATA[3] = 版本号高字节
DATA[0] = 固件长度高字节
DATA[1] = 固件长度低字节
DATA[2] = 版本号高字节
DATA[3] = 版本号低字节
```
设备收到后擦除:
```text
OTA固件区:0x020000~0x02FFFF
OTA元数据:0x030000~0x030FFF
OTA固件区:0x003000~0x004FFF
OTA元数据:0x005000~0x005FFF
```
成功应答:
@@ -364,8 +417,8 @@ DATA[2] = 下一期待偏移低字节
```text
CMD = 0A
LEN = 02
DATA[0] = 完整固件CRC16低字节
DATA[1] = 完整固件CRC16高字节
DATA[0] = 完整固件CRC16高字节
DATA[1] = 完整固件CRC16低字节
```
CRC16使用CRC-16/MODBUS,计算范围是整个裸二进制固件文件。
@@ -390,12 +443,12 @@ LEN = 00
设备从W25Q64重新读取完整固件并计算CRC16。校验成功后写入OTA元数据:
```text
0x030000:魔数
0x030004:固件长度
0x030008:固件版本
0x03000A:CRC16
0x03000E:镜像有效标志0xA5
0x03000F:升级请求0xA5
0x005000:魔数
0x005004:固件长度
0x005008:固件版本
0x00500A:CRC16
0x00500E:镜像有效标志0xA5
0x00500F:升级请求0xA5
```
设备返回:
@@ -407,7 +460,10 @@ DATA[0] = 00:校验成功,已提交升级
DATA[0] = 01:校验失败
```
之后设备复位,由Bootloader把OTA固件搬运到内部Flash的`0x8800`区域。
当`DATA[0]=00`时,设备已经完成外部Flash固件校验并写入升级元数据。
设备会先发送`0x8B`应答,随后自动触发MCU复位,由Bootloader把OTA固件
搬运到内部Flash的`0x8800`区域。`0x8B`不代表Bootloader已经搬运完成,
主机必须继续等待设备重新启动后主动上报的`0x0D`。
### 7.5 `0x0C` 取消OTA
@@ -437,14 +493,24 @@ DATA[0] = 00:取消成功
发送完整CRC16:0A
请求校验提交:0B
等待校验结果:8B
设备复位并升级
设备发送8B后自动复位并升级
主程序启动后主动上报升级结果:0D
主机确认升级结果:8D
```
主机等待最终升级结果的建议规则:
```text
收到 0x8B=00 后,继续等待 0x0D,默认超时时间为20秒;
收到 0x0D 且 DATA[0]=0x01:升级成功;
收到 0x0D 且 DATA[0]不是0x01:升级失败;
超过20秒没有收到0x0D:升级失败;
收到升级结果后,主机向该设备短地址发送0x8D确认。
```
## 8. OTA升级结果上报
设备启动后从`0x030010`读取升级结果,蓝牙初始化成功后主动广播:
设备启动后从`0x005010`读取升级结果,蓝牙初始化成功后主动广播:
```text
CMD = 0D
@@ -472,4 +538,6 @@ LEN = 01
DATA[0] = 对应的升级结果码
```
设备收到确认后清除`0x030010`。
设备收到确认后清除`0x005010`。
如果主机没有发送`0x8D`,设备不会清除结果记录,后续启动时可能再次上报,
便于主机发现升级结果确认丢失。