Files
STM8_Mesh_Control/docs/HOST_PROTOCOL_SPEC.md
T
十七 ebef6a8694 feat: complete assembly mesh relay control path
- synchronize STM8 application and external flash layout updates\n- add assembly bootloader and assembly application test projects\n- add UART1 interrupt receive ring buffer\n- parse JDY-28M Mesh outer frames and source addresses\n- add CRC-16/MODBUS validation\n- implement relay control command 0x01 and response 0x81\n- support unicast and broadcast relay control frames\n- update host protocol, OTA documents, and serial tools
2026-11-05 16:12:51 +08:00

598 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# STM8 Mesh 继电器主机通信协议
本文档供主机、网关和上位机开发人员使用。通信分为两层:JDY-28M Mesh外层和设备业务内层。
## 1. Mesh外层帧
### 1.1 主机发送给设备
```text
41 54 2B AA A1 | DST_H DST_L | A0 | BUSINESS | 0D 0A
```
字段说明:
| 字段 | 长度 | 说明 |
|---|---:|---|
| `41 54 2B AA A1` | 5 | JDY-28M Mesh发送固定帧头 |
| `DST_H DST_L` | 2 | 目标短地址,高字节在前 |
| `A0` | 1 | Mesh数据通信标志,固定值 |
| `BUSINESS` | 变长 | 本文档第2节定义的业务帧 |
| `0D 0A` | 2 | Mesh帧尾,固定值 |
广播地址:
```text
FFFF
```
单播到短地址`000C`:
```text
DST_H = 00
DST_L = 0C
```
### 1.2 接收端串口收到的 Mesh 数据格式
```text
F1 DD 09 | SRC_H SRC_L | DST_H DST_L | BUSINESS | 0A
```
这是接收方 UART 侧看到的接收格式,不是设备或主机发送时使用的格式。
其中前两字节是发送方短地址,后两字节是接收方短地址;业务帧中不再重复
嵌入发送方或接收方地址。部分模块/串口工具可能显示为`0D 0A`,设备解析器
兼容`0A`和`0D 0A`两种接收表现。
无论发送方是主机还是设备,发送时都统一使用第1.1节的格式:
```text
41 54 2B AA A1 | DST_H DST_L | A0 | BUSINESS | 0D 0A
```
### 1.3 长度限制
JDY-28M完整Mesh帧最大20字节。当前业务帧最大DATA长度为4字节:
```text
BUSINESS = CMD LEN DATA CRC16_H CRC16_L
```
业务帧长度为`4 + LEN`,完整外层发送帧长度为`14 + LEN`,按20字节限制计算,
`LEN`最大为6;当前继电器控制命令使用`LEN=1`。
## 2. 业务帧格式
```text
CMD | LEN | DATA[0..LEN-1] | CRC16_H CRC16_L
```
### 2.1 CRC16规则
```text
算法:CRC-16/MODBUS
多项式:0xA001
初始值:0xFFFF
输入反射:是
输出反射:是
计算范围:CMD、LEN和DATA
发送顺序:CRC高字节在前,低字节在后
```
CRC错误时设备直接丢弃整帧,不执行命令,也不返回错误应答。
## 3. 通用应答规则
普通请求的应答命令通常为:
```text
应答CMD = 请求CMD | 0x80
```
当请求通过 Mesh 广播地址 `FFFF` 发送时,设备不会立即同时回复。设备会
根据本机短地址和系统时间生成约20~170ms、按10ms分档的随机延时,然后向外层
接收帧中的发送方地址单播回复,以降低多个设备同时应答造成的网络拥塞。
单播请求仍然直接回复。
错误应答:
```text
CMD = E0
LEN = 01
DATA[0] = 错误码
```
当前常用错误码:
```text
0x02:DATA长度错误
0x03:DATA参数错误
0x05:EEPROM或配置写入失败
0x06:未知命令
```
## 3.1 `0x07` 设备上线广播
设备在本次上电完成基础初始化、蓝牙进入可通信状态后,向 Mesh 广播一次:
```text
CMD = 07
LEN = 00
```
发送方短地址由JDY-28M外层提供,因此该命令不需要 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] = 需要升级的版本低字节
```
设备短地址由JDY-28M外层提供。主机收到多个`0x90`后,
生成待升级设备列表,由人工选择设备,再对选中的短地址执行后续OTA流程。
## 4. 主机下发的普通命令
### 4.1 `0x01` 继电器控制
主机发送:
```text
CMD = 01
LEN = 01
DATA[0] = 00:继电器断开
DATA[0] = 01:继电器吸合
```
业务帧结构示例:
```text
01 01 01 CRC16_H CRC16_L
```
设备执行后返回:
```text
CMD = 81
LEN = 01
DATA[0] = 当前继电器控制状态
```
```text
00:断开
01:吸合
```
注意:当前没有继电器触点反馈,设备只能确认PA1控制输出已经设置,不能确认触点机械动作是否真实成功。电流异常由故障检测功能另行上报。
以主机地址`34FA`向设备地址`35FA`发送吸合命令为例,主机串口发送:
```text
41 54 2B AA A1 35 FA A0 01 01 01 50 E0 0D 0A
```
设备接收侧看到:
```text
F1 DD 09 34 FA 35 FA 01 01 01 50 E0 0A
```
设备向主机地址`34FA`回复:
```text
41 54 2B AA A1 34 FA A0 81 01 01 B8 E1 0D 0A
```
广播吸合时,将目标地址改为`FFFF`:
```text
41 54 2B AA A1 FF FF A0 01 01 01 50 E0 0D 0A
```
设备收到广播后执行控制,并向发送方地址回复`0x81`。正式多设备版本应对广播
应答增加随机错峰延时,避免多个设备同时发送。
### 4.2 `0x02` 查询继电器状态
主机发送:
```text
CMD = 02
LEN = 00
```
设备返回:
```text
CMD = 82
LEN = 01
DATA[0] = 00:断开
DATA[0] = 01:吸合
```
### 4.3 `0x03` 查询实际电流
主机发送:
```text
CMD = 03
LEN = 00
```
设备返回:
```text
CMD = 83
LEN = 02
DATA[0] = 电流高字节
DATA[1] = 电流低字节
```
单位为mA,无符号整数,高字节在前。例如实际电流为`1000mA = 0x03E8`:
```text
DATA = 03 E8
```
### 4.4 `0x05` 查询设备短地址
主机发送:
```text
CMD = 05
LEN = 00
```
设备返回:
```text
CMD = 85
LEN = 02
DATA[0] = 短地址高字节
DATA[1] = 短地址低字节
```
例如设备短地址为`000C`:
```text
DATA = 00 0C
```
### 4.5 `0x06` 配置电流阈值
主机发送:
```text
CMD = 06
LEN = 02
DATA[0] = 阈值高字节
DATA[1] = 阈值低字节
```
单位为mA,默认值为100mA,设备保存到内部EEPROM。例如设置100mA:
```text
DATA = 00 64
```
设备成功返回:
```text
CMD = 86
LEN = 02
DATA = 原样返回设置的阈值
```
## 5. 固件版本查询
### 5.1 `0x0E` 查询当前固件版本
主机发送:
```text
CMD = 0E
LEN = 00
```
设备返回:
```text
CMD = 8E
LEN = 02
DATA[0] = 版本高字节
DATA[1] = 版本低字节
```
当前版本在主程序`include/app_config.h`中定义:
```c
#define FIRMWARE_VERSION 0x0001u
```
例如版本`0x0001`返回:
```text
DATA = 01 00
```
## 6. 故障与恢复上报
故障上报由设备主动发送:
```text
CMD = 04
LEN = 01
DATA[0] = 故障码或恢复码
```
故障码:
```text
0x00:继电器吸合但持续无有效电流
0x01:继电器断开但仍存在持续电流
0x02:ACS712采样异常
0x03:蓝牙初始化异常,仅LED指示,不通过Mesh上报
0x04:电流故障恢复
0x05:蓝牙故障恢复
0x06:采样异常恢复
0x07:继电器控制失败预留码
```
主机确认故障或恢复上报:
```text
CMD = 84
LEN = 01
DATA[0] = 被确认的故障码或恢复码
```
故障产生和恢复都需要持续至少10秒确认。故障恢复上报未收到主机确认时,设备每10秒重复上报,直到收到确认。
## 7. OTA命令
主机发送的OTA固件是`mesh_relay.bin`裸二进制文件,不是HEX文本文件,也不包含Bootloader。
### 7.1 `0x08` 进入OTA
```text
CMD = 08
LEN = 04
DATA[0] = 固件长度高字节
DATA[1] = 固件长度低字节
DATA[2] = 版本号高字节
DATA[3] = 版本号低字节
```
设备收到后擦除:
```text
OTA固件区:0x003000~0x004FFF
OTA元数据:0x005000~0x005FFF
```
成功应答:
```text
CMD = 88
LEN = 01
DATA[0] = 00
```
### 7.2 `0x09` 固件分包
正常数据包:
```text
CMD = 09
LEN = 04
DATA[0] = OFFSET高字节
DATA[1] = OFFSET低字节
DATA[2] = 固件数据1
DATA[3] = 固件数据2
```
最后只有1字节固件数据时:
```text
CMD = 09
LEN = 03
DATA[0] = OFFSET高字节
DATA[1] = OFFSET低字节
DATA[2] = 固件数据1
```
设备只接受等于当前期待偏移的分包。成功后返回:
```text
CMD = 89
LEN = 03
DATA[0] = 00:写入成功
DATA[1] = 下一期待偏移高字节
DATA[2] = 下一期待偏移低字节
```
如果偏移错误、Flash写入失败或OTA状态错误,返回非0状态码。主机应根据返回的期待偏移重传。
### 7.3 `0x0A` 发送完整固件CRC16
```text
CMD = 0A
LEN = 02
DATA[0] = 完整固件CRC16高字节
DATA[1] = 完整固件CRC16低字节
```
CRC16使用CRC-16/MODBUS,计算范围是整个裸二进制固件文件。
设备接收后返回:
```text
CMD = 8A
LEN = 01
DATA[0] = 00:接收成功
```
### 7.4 `0x0B` 请求校验并提交升级
主机发送:
```text
CMD = 0B
LEN = 00
```
设备从W25Q64重新读取完整固件并计算CRC16。校验成功后写入OTA元数据:
```text
0x005000:魔数
0x005004:固件长度
0x005008:固件版本
0x00500A:CRC16
0x00500E:镜像有效标志0xA5
0x00500F:升级请求0xA5
```
设备返回:
```text
CMD = 8B
LEN = 01
DATA[0] = 00:校验成功,已提交升级
DATA[0] = 01:校验失败
```
当`DATA[0]=00`时,设备已经完成外部Flash固件校验并写入升级元数据。
设备会先发送`0x8B`应答,随后自动触发MCU复位,由Bootloader把OTA固件
搬运到内部Flash的`0x8500`区域。`0x8B`不代表Bootloader已经搬运完成,
主机必须继续等待设备重新启动后主动上报的`0x0D`。
### 7.5 `0x0C` 取消OTA
主机发送:
```text
CMD = 0C
LEN = 00
```
设备返回:
```text
CMD = 8C
LEN = 01
DATA[0] = 00:取消成功
```
### 7.6 OTA传输顺序
```text
查询版本:0E
进入OTA:08
等待应答:88
发送分包:09
每包等待应答:89
发送完整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升级结果上报
设备启动后从`0x005010`读取升级结果,蓝牙初始化成功后主动广播:
```text
CMD = 0D
LEN = 01
DATA[0] = 升级结果码
```
结果码:
```text
0x00:无结果
0x01:升级成功
0x02:固件CRC错误
0x03:内部Flash写入失败
0x04:写入后校验失败
0x05:固件长度非法
0x06:W25Q64读取失败
```
主机确认:
```text
CMD = 8D
LEN = 01
DATA[0] = 对应的升级结果码
```
设备收到确认后清除`0x005010`。
如果主机没有发送`0x8D`,设备不会清除结果记录,后续启动时可能再次上报,
便于主机发现升级结果确认丢失。
## 9. 整片初次烧录
整片初次烧录使用合并固件,不用于OTA:
```bash
make full
```
生成文件:
```text
build/stm8_mesh_full.hex:带绝对地址的完整HEX
build/stm8_mesh_full.bin:从0x8000开始的连续BIN
```
合并地址范围为:
```text
0x8000~0x84FF:Bootloader
0x8500~0x9FFF:主程序
```
使用ST-LINK V2/SWIM烧录时优先使用HEX文件;OTA升级仍只发送
`build/mesh_relay.bin`,不能发送合并固件。