136 lines
7.3 KiB
Markdown
136 lines
7.3 KiB
Markdown
# CAIIC BLE 通信协议 V1.1
|
||
|
||
适用于 mcm-ddc-ble 固件(N32WB031KEQ6-2,Cortex-M0 64MHz,512KB Flash)。
|
||
手机 APP(自研)或通用 BLE 调试工具(如 nRF Connect)通过本文协议与设备通信,
|
||
支持三类业务:**CLI 命令透传**、**设备信息查询**(温度/风扇转速等)、**BLE OTA 固件升级**。
|
||
|
||
## 1. GATT 服务
|
||
|
||
广播名:`CAIIC-MCM-20260902`
|
||
|
||
使用 SDK rdtss(raw data transfer server)自定义 128-bit UUID 服务:
|
||
|
||
| 项 | UUID | 属性 |
|
||
|---|---|---|
|
||
| Service | `00002760-08C2-11E1-9073-0E8AC72E1001` | Primary Service |
|
||
| 下行特征(手机→设备) | `00002760-08C2-11E1-9073-0E8AC72EE001` | Write Without Response |
|
||
| 上行特征(设备→手机) | `00002760-08C2-11E1-9073-0E8AC72EE002` | Notify(需写 CCCD=0x0001 使能) |
|
||
|
||
MTU:**设备在连接建立后主动发起 MTU 交换(请求 247)**;手机端也可自行发起。
|
||
一次 BLE 写入/通知的最大数据量 = att_mtu − 3(默认 MTU 23 时为 20B)。
|
||
**一个协议帧可以跨多次 BLE 写入传输,一次写入也可以携带多个帧**——设备侧按字节流重组。
|
||
设备上行每个 notify 固定 ≤20B(对端 MTU 未知时也能工作)。
|
||
|
||
## 2. 帧格式(小端)
|
||
|
||
| 偏移 | 字段 | 说明 |
|
||
|---|---|---|
|
||
| 0 | SOF = 0xCA | 帧起始 |
|
||
| 1 | TYPE | 帧类型(见第 3 节) |
|
||
| 2 | SEQ | 序号(模 256,发送方自增;应答帧回显请求帧 SEQ) |
|
||
| 3–4 | LEN | payload 长度(0–480),小端 |
|
||
| 5.. | PAYLOAD | LEN 字节 |
|
||
| 末尾 2B | CRC16 | CRC16-CCITT(poly 0x1021,初值 0xFFFF),覆盖 TYPE..PAYLOAD,小端 |
|
||
|
||
帧开销 = 7 字节(头 5 + CRC 2)。
|
||
|
||
- 设备单帧 payload 上限 480B;超出或 CRC 错误的帧被静默丢弃并重新找 SOF。
|
||
- 设备→手机的 CLI_RSP 分块大小 = 20 − 7 = 13B(固定按默认 MTU 分包)。
|
||
|
||
## 3. 帧类型
|
||
|
||
| TYPE | 方向 | 名称 | payload |
|
||
|---|---|---|---|
|
||
| 0x01 | 手机→设备 | CLI_REQ | 一行命令文本(无结束符,≤63B) |
|
||
| 0x02 | 设备→手机 | CLI_RSP | 应答文本分块(可多帧) |
|
||
| 0x03 | 设备→手机 | CLI_RSP_END | {status u8}:0=ok,1=未知命令/行超长 |
|
||
| 0x10 | 手机→设备 | OTA_BEGIN | {total_size u32, image_crc32 u32, version u32} |
|
||
| 0x11 | 手机→设备 | OTA_DATA | {offset u32, data…}(offset 必须严格连续) |
|
||
| 0x12 | 手机→设备 | OTA_END | {crc32 u32}(与 OTA_BEGIN 中一致) |
|
||
| 0x1F | 设备→手机 | OTA_RSP | {cmd_echo u8, status u8, offset u32} |
|
||
| 0x20 | 手机→设备 | INFO_QUERY | {item_id u8}×n;空 payload 或单个 0xFF = 查询全部 |
|
||
| 0x21 | 设备→手机 | INFO_RSP | TLV 序列 {id u8, len u8, value…}×n |
|
||
|
||
OTA_RSP status:0=ok,1=bad_frame,2=bad_state/offset 乱序(offset 字段=设备期望的下一字节偏移),
|
||
3=size_too_big,4=crc_fail,5=flash_fail。
|
||
|
||
## 4. CLI 透传流程
|
||
|
||
1. 手机:CLI_REQ,payload 如 `help`、`sysinfo`、`devinfo`、`led 1 toggle`(与 UART CLI 命令集一致)。
|
||
2. 设备:若干 CLI_RSP(命令输出的文本流分块)+ 最后一帧 CLI_RSP_END 带状态码。
|
||
3. 无命令执行中时可随时发下一条;命令是同步执行的,设备应答完毕前不要再发 CLI_REQ。
|
||
|
||
UART CLI 特有的交互功能(行编辑、Tab 补全、历史、Ctrl+Z)不适用于 BLE 通道。
|
||
|
||
自测示例(默认 MTU,写入下行特征):`help` 命令帧 =
|
||
`CA 01 00 04 00 68 65 6C 70 16 EC`
|
||
|
||
## 5. 设备信息查询流程
|
||
|
||
手机发 INFO_QUERY,设备回一帧 INFO_RSP,payload 为请求的各信息项的 TLV 序列
|
||
(每项 {id u8, len u8, value},数值均小端)。设备不认识的 id 直接跳过、不出现在应答中。
|
||
|
||
| item_id | 名称 | 类型 | 说明 |
|
||
|---|---|---|---|
|
||
| 0x01 | FW_VERSION | u32 | 固件版本号,如 0x00010001 = V1.00.01 |
|
||
| 0x02 | CHIP_TEMP | i16 | 芯片温度,单位 0.1°C(ADC 内置温度传感器 CH7,出厂 trim 校准) |
|
||
| 0x03 | FAN_RPM | u16 | 风扇转速 rpm;0xFFFF = 无此硬件/未接入 |
|
||
| 0x04 | VDD_MV | u16 | 电源电压,单位 mV(ADC CH6) |
|
||
| 0x05 | UPTIME_S | u32 | 系统运行时间,单位 s |
|
||
| 0x06 | FREE_HEAP | u32 | FreeRTOS 堆剩余,单位 B |
|
||
|
||
示例:查询温度+风扇 = INFO_QUERY payload `02 03`;
|
||
应答 INFO_RSP payload 形如 `02 02 0A 01 03 02 FF FF`(温度 26.6°C,风扇无硬件)。
|
||
|
||
数据来源约定:温度/电压由设备固件直接采 ADC;风扇转速由应用层注册的
|
||
数据源提供(`app_fan_get_rpm()`,弱符号默认返回 0xFFFF),产品板接上风扇
|
||
转速检测电路后重写该函数即可,协议不变。
|
||
|
||
## 6. OTA 升级流程(双 bank 直写,无中转区)
|
||
|
||
Flash 布局(512KB,官方 256KB DFU 布局每区加倍):
|
||
|
||
| 区域 | 地址 | 大小 |
|
||
|---|---|---|
|
||
| Bootloader | 0x01000000 | 16KB |
|
||
| bootsetting | 0x01004000 | 8KB(用 1 个 4KB 扇区) |
|
||
| APP_DATA(预留) | 0x01006000 | 8KB |
|
||
| APP1 | 0x01008000 | 224KB |
|
||
| APP2 | 0x01040000 | 224KB |
|
||
|
||
设备当前运行 APP1 则新固件写入 APP2,反之亦然。bank 上限 224KB(0x38000)。
|
||
镜像 = Keil 产物 bin(裸二进制,从 bank 基址开始的镜像)。
|
||
flash 擦除单位 = 4KB 扇区。设备侧**直写 flash,不做扇区级 RAM 缓存**:
|
||
数据首次落入某个未擦除的扇区时先擦除该扇区(惰性擦除),收到的数据立即编程写入,
|
||
仅保留 4 字节对齐暂存(Qflash 写要求 4 字节对齐),**不经过任何 flash 中转区**。
|
||
|
||
1. **OTA_BEGIN**:手机发送 {total_size, image_crc32, version}。
|
||
- image_crc32 = IEEE CRC32(poly 0xEDB88320,初值/异或出 0xFFFFFFFF,即 zlib crc32)
|
||
对整个镜像 bin 文件的校验值。
|
||
- version:u32,如 0x00010001 表示 V1.00.01。
|
||
- 设备回 OTA_RSP(0x10, ok, 0) 后开始接收。
|
||
2. **OTA_DATA**:从 offset=0 起严格顺序发送,每帧 {offset, data}。
|
||
- 单帧 data 建议 ≤ 233B(MTU 247 时一次写入 244B = 帧开销 7 + offset 4 + data 233);
|
||
MTU 23 时单帧总长度不得超过 20B。
|
||
- 设备收到即写入 flash;每写满一个 4KB 扇区回一帧 OTA_RSP(0x11, ok, 已写 offset)
|
||
——兼作流控与进度显示。
|
||
- 手机端节奏:可按扇区等 ack 发送,也可连续发送;若收到 status=2 的应答,
|
||
从应答中的 offset 处重发即可重新同步。
|
||
3. **OTA_END**:{crc32}。设备 flush 尾部(0xFF 补齐到 4 字节对齐后写最后一个扇区),
|
||
从 flash 回读整镜像复算 CRC32,与手机端比对:
|
||
- 失败 → OTA_RSP(0x12, crc_fail),会话中止,不复位;
|
||
- 成功 → 更新 bootsetting(active bank 指向新 bank,记录 size/crc32/version)
|
||
→ OTA_RSP(0x12, ok) → 200ms 后自动复位,bootloader 直接跳转到新固件
|
||
(跳转不做校验,校验已在 OTA 过程完成)。
|
||
4. 任何时刻 BLE 断连,OTA 会话中止,对侧 bank 数据作废(可重新 OTA_BEGIN 重来)。
|
||
|
||
注意:flash 擦写期间设备关中断数十 ms/扇区(Qflash 算法在 RAM 执行),BLE 链路靠
|
||
5s supervision timeout 维持,属正常现象;但请避免在 OTA 期间主动断开。
|
||
|
||
## 7. 首次烧录与恢复
|
||
|
||
- 出厂/首次:SWD 烧录整包(bootloader + bootsetting 缺省配置 + APP1),
|
||
由 `tools\merge_image.py` / `make_package.bat` 生成。
|
||
- OTA 失败变砖恢复:SWD 重烧即可(bootloader 不做串口 DFU)。
|
||
- Keil 调试下载必须用**扇区擦除**,整片擦除会删掉 bootloader。
|