# CAIIC BLE 通信协议 V1.0 适用于 mcm-ddc-04 固件(N32WB031KEQ6-2,512KB Flash)。手机 APP(自研)或通用 BLE 调试工具(如 nRF Connect)通过本文协议与设备通信,支持 CLI 命令透传与 BLE OTA 固件升级。 ## 1. GATT 服务 广播名:`CAIIC-MCM`(连接参数:interval 15–30ms,latency 0,supervision timeout 5s) 自定义 128-bit UUID 服务(CLS): | 项 | UUID | 属性 | |---|---|---| | Service | `0000CA10-CA11-4B11-8000-CA11CA11CA11` | Primary Service | | 下行特征(手机→设备) | `0000CA11-CA11-4B11-8000-CA11CA11CA11` | Write Without Response | | 上行特征(设备→手机) | `0000CA12-CA11-4B11-8000-CA11CA11CA11` | Notify(需写 CCCD=0x0001 使能) | 建议手机端连接后立即协商 **MTU=247**(否则默认 23 字节 ATT MTU,OTA 会非常慢)。 一次 BLE 写入/通知的最大数据量 = att_mtu − 3。**一个协议帧可以跨多次 BLE 写入传输, 设备侧按字节流重组**;设备上行每帧不超过一次 notify 容量。 ## 2. 帧格式(小端) | 偏移 | 字段 | 说明 | |---|---|---| | 0 | SOF = 0xCA | 帧起始 | | 1 | TYPE | 帧类型(见下表) | | 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 分块大小 = min(att_mtu − 3, 244) − 7。 ## 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} | 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`、`log on`、`led 1 toggle`(与 UART CLI 命令集一致)。 2. 设备:若干 CLI_RSP(命令输出的文本流分块)+ 最后一帧 CLI_RSP_END 带状态码。 3. 无命令执行中时可随时发下一条;命令是同步执行的,设备应答完毕前不要再发 CLI_REQ。 UART CLI 特有的交互功能(行编辑、Tab 补全、历史、Ctrl+Z)不适用于 BLE 通道。 ## 5. OTA 升级流程(双 bank 直写,无中转区) 设备当前运行 APP1(0x01008000)则新固件写入 APP2(0x01040000),反之亦然。 bank 上限 224KB(0x38000)。镜像 = Keil 产物 bin(裸二进制,从 bank 基址开始的镜像)。 1. **OTA_BEGIN**:手机发送 {total_size, image_crc32, version}。 - image_crc32 = IEEE CRC32(poly 0xEDB88320,初值/异或出 0xFFFFFFFF,即 zlib crc32) 对整个镜像 bin 文件的校验值。 - version:u32,如 0x010001 表示 V1.00.01。 - 设备回 OTA_RSP(0x10, ok, 0) 后开始接收。 2. **OTA_DATA**:从 offset=0 起严格顺序发送,每帧 {offset, data}。 - 设备侧用 **4KB 扇区缓冲** 攒数据,攒满一个 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)→ OTA_RSP(0x12, ok) → 200ms 后自动复位,bootloader 校验并跳转到新固件。 4. 任何时刻 BLE 断连,OTA 会话中止,对侧 bank 数据作废(可重新 OTA_BEGIN 重来)。 注意:flash 擦写期间设备关中断数十 ms/扇区,BLE 链路靠 5s supervision timeout 维持, 属正常现象;但请避免在 OTA 期间主动断开。 ## 6. 首次烧录与恢复 - 出厂/首次:SWD 分别烧录 bootloader(`Boot/MDK-ARM` 工程,0x01000000)和 APP1 (mcm-ddc-04 工程,0x01008000)。bootsetting 空白时 bootloader 做向量合法性检查后 直接跳 APP1。 - OTA 失败变砖恢复:SWD 重烧即可(bootloader 不做串口 DFU)。 - 调试用 `bankinfo` 命令查看当前运行 bank 与 bootsetting 记录。