Files
DLD154Pro/docs/ble-protocol.md
T

248 lines
12 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.
# DLD154Pro 蓝牙小程序接口协议
> 依据源码整理:`BLE/DLD154Pro_Peripheral_28K/APP/dbn_ble_srv.c`(主逻辑)、`peripheral.c`/`Profile/gattprofile.c`BLE 服务)、`include/storage.h`(配置结构)、`include/cmcng.h`(常量)
> 固件版本:V3.04cmcng.h `FIRMWARE_VER`| 硬件版本:V3.01 | 产品型号:DLD154Pro
---
## 1. BLE 服务与特征
| 服务/特征 | UUID | 属性 | 长度 | 用途 |
|-----------|------|------|------|------|
| 服务 SIMPLEPROFILE | 0xFFE0 | — | — | 广播服务 UUID |
| Char1 | 0xFFE1 | 读写 (RW) | 64B | **小程序 → 芯片:命令下发** |
| Char2 | 0xFFE2 | 读 | 1B | 预留 |
| Char3 | 0xFFE3 | 写 | 8B | 预留 |
| Char4 | 0xFFE4 | **通知 (Notify)** | 32B | **芯片 → 小程序:命令响应 + 主动上报** |
| Char5 | 0xFFE5 | 读 | 5B | 预留 |
- 设备名:`DLD154Pro`(广播 + GATT Device Name
- **MTU**:默认 23,连接后协商(`ATT_MTU_UPDATED_EVENT``peripheralMTU = clientRxMTU`)。notify 单包 payload ≤ `peripheralMTU 3`peripheral.c:677 强制检查,超限返回 FAIL 不发送)
- **交互模型**:小程序写 Char1 下发命令帧 → 芯片处理 → Char4 notify 返回响应帧;芯片主动上报也走 Char4
---
## 2. 帧格式与校验
```
| Magic 1B | Header 1B | Len 1B | CMD 1B | Data N B | XOR 1B | SUM 1B |
```
| 字段 | 说明 |
|------|------|
| Magic | `0x8F` = 车检器默认协议;`0x7F` = 透传(显示屏/地感/探头协议) |
| Header | 单包 = `0x00`;分包 = `(pkg_amount << 4) \| pkg_seq`(高 4 位总包数,低 4 位当前序号,seq 从 1 起) |
| Len | `1CMD+ NData 字节数)` |
| CMD | 命令码,见 §4 |
| XOR | 异或校验:从 Header 到 Data 末尾逐字节 XOR |
| SUM | 和校验:从 Header 到 Data 末尾逐字节求和(低 8 位) |
**校验示例**`compute_ckb`dbn_ble_srv.c:168):
```c
dxor = Header ^ Len ^ CMD ^ Data[0] ^ ... ^ Data[N-1];
dsum = Header + Len + CMD + Data[0] + ... + Data[N-1]; // 取低 8 位
// 发送顺序: [dxor] [dsum & 0xFF]
```
**接收校验**`check_pkg`dbn_ble_srv.c:75):最小帧长 6`Len + 5 < 实际长度` 判非法;XOR/SUM 任一不符丢弃。
---
## 3. 分包机制
- **发送(响应/上报)**`set_response_buf()``MAX_BLE_DAT_RESPONSE_LEN = 14`= BLE_BUFF_MAX_LEN4,基于 MTU=23 的旧假设)计算 `pkg_amount = ceil(dat_len / 14)`。多包时 Header = `(amount<<4)|seq`seq 从 1 递增,最后一包 `amount == seq` 后清除响应缓冲。
- **接收(命令)**`unpack_packs()` 支持按 `(amount<<4)|seq` 重组分包,校验 amount/cmd/seq 连续性,异常时清空缓冲。DLD154Pro 当前仅 0x1C/0x1D 使用(已注释),其余命令单包即可。
- **⚠ 分包粒度写死 14**:即使 MTU 协商到更大(如 96/185),分包仍按 14B 切——不丢包但效率低。小程序侧按 Header 分包重组即可。
---
## 4. 命令总览
| CMD | 名称 | 方向 | 说明 |
|-----|------|------|------|
| 0x10 | GET_DEV_INFO | 小程序→芯片 | 读设备信息(MAC/版本/型号) |
| 0x1F | RESET_DEV | 小程序→芯片 | 复位设备(SYS_ResetExecute |
| 0x23 | SET_CJQ_PARAM | 小程序→芯片 | 设置车检器参数(灵敏度/频率/延时/输出等) |
| 0x24 | GET_CJQ_PARAM | 小程序→芯片 | 读车检器参数 |
| 0x31 | RW_UART_BAUD | 小程序→芯片 | 读写 RS485 波特率/地址/蓝牙空闲超时 |
| 0x8A | LOOP_SENS_LIST | 小程序→芯片 | 读写灵敏度表(sens_in/sens_out |
| 0x92 | SET_CJQ_FACTORY | 小程序→芯片 | 恢复出厂 |
| 0xC5 | SENS_ACS_ENABLE | 小程序→芯片 | 主动上报使能 |
| 0xC0 | SUB_SENS_REPORT | 芯片→小程序 | 主动上报线圈动态(不可下发) |
**未实现(源码已注释)**0x1C 校验密码 / 0x1D 修改密码 / 0x1E 出厂 / 0x20-0x22 notify 与子功能 / 0x6D 复位 / 0x87 采样参数 / 0x88 平衡参数 / 0x89 释放参数。小程序不应下发,芯片无响应。
---
## 5. 命令详述
### 5.1 0x10 读设备信息
无 Data。响应 Data
| 偏移 | 字节 | 内容 |
|------|------|------|
| 0-5 | 6 | MAC 地址(MACAddr[6] |
| 6-7 | 2 | 硬件版本 MAIN/SUBV3.01 → 03 01 |
| 8-9 | 2 | 固件版本 MAIN/SUBV3.04 → 03 04 |
| 10 | 1 | 产品型号长度 |
| 11.. | N | 产品型号 ASCII"DLD154Pro" |
| .. | 6 | 设备编号(g_dev_number[6] |
| .. | 2 | sub_code(固定 0 |
| .. | 2 | 总线设备数(固定 0) |
### 5.2 0x1F 复位设备
无 Data。芯片执行 `SYS_ResetExecute()`(整机冷复位),**无响应帧**。
### 5.3 0x23 设置车检器参数
Data5B):
| 偏移 | 内容 |
|------|------|
| 0 | `sensitvity(低4位) \| loopFreq_Level(高4位)` |
| 1 | delay_time(离开延时) |
| 2 | `output_mode(低2位) \| loopSafe_Timeout(高5位)` |
| 3 | exist_mode(有限存在时长,单位 10s) |
| 4 | direction_mode(低 4 位=输出融合模式;高 4 位=功能模式) |
**sensitvity 语义(DLD154Pro 特有)**:协议层 **1~4**1=最低灵敏度,4=最高),内部 `g_freq_sens = sensitvity 1`(0~3)索引灵敏度表。与 vd960Loop 的 0~3 不同,**小程序发送 1~4**。
**direction_mode 解析**unpack_pkg_set_cjq_paramdbn_ble_srv.c:431):
```
g_function_mode = direction_mode >> 4 (功能模式)
g_fm_700bs_disable = g_function_mode & 0x01 (0=700BS协议, 1=Modbus)
g_output_radar_mode = direction_mode & 0x0F (输出融合模式, 见 DLD_OUTPUT_MODE)
g_hold_time = exist_mode * 20 * 5 (tick)
```
处理:更新全局 → `write_cfg_to_store(4, tmp, 7)` 写 flash → `para_store_init()` 重载。响应:1B status(固定 0)。
### 5.4 0x24 读车检器参数
无 Data。响应 Data11B):
| 偏移 | 内容 |
|------|------|
| 0 | `(g_freq_sens + 1) \| (loopFreq_Level << 4)`sensitvity 回读为 1~4 |
| 1 | delay_time |
| 2 | `output_mode \| (loopSafe_Timeout << 3)` |
| 3 | exist_mode |
| 4 | `sens_list.total << 4`(灵敏度档数,高 4 位) |
| 5 | 线圈断开次数低字节(g_loop_cut_amount,上电持续累计) |
| 6 | 线圈断开次数高字节 |
| 7 | direction_mode |
| 8-10 | **归一化基数 LOOP_MEASURE_BASE3B LE= 524288**V3.04 追加) |
> ⚠ **偏移 8-10 用途(V3.042026-08-26 追加)**variation 换算 ΔL/L 的归一化基数。
> 第三方应用连接后读一次 0x24 缓存该值:`Δf/f ≈ variation / LOOP_MEASURE_BASE``ΔL/L ≈ -2 × variation / LOOP_MEASURE_BASE`。
> **背景**DLD154Pro 的 MEASUREMENT_BASE = 5242882^19 @60MHz),与 DLD110S 相同、与 DLD154V4B 的 131072 不同。固件显式上报后第三方无需猜测(曾出现照搬 131072 导致百分比放大 4 倍的问题,DLD110S 2026-08-26 实测发现)。
> 向后兼容:老小程序只读前 8B 不受影响;新小程序读 11B。
### 5.5 0x31 读写 UART 参数
Data`[rw] [status] ...`
**读(rw=0**:响应 Data8B):
```
[0] rw=0
[1] status=0
[2] 蓝牙空闲超时(分钟, g_max_counter_bt_min)
[3-5] RS485 波特率 3B LE (g_storage_uart_baud)
[6] RS485 从机地址 (g_rs485_id)
[7-9] Reserved 3B
```
**写(rw≠0**Data 后续:`[bt_timeout] [baud 3B LE] [rs485_id] [3B reserved]`,共 5B 有效写入 `write_cfg_to_store(0x10, 5B)`。响应回读当前值(同读格式)。
### 5.6 0x8A 读写灵敏度表
**读(pkg[4]=0**:响应 Data
```
[0] 0x10 (读标志)
[1] total (灵敏度档数)
[2..] total × [sens_in 2B LE | sens_out 2B LE]
```
**写(pkg[4]≠0**Data 从 pkg[5] 起:`[total] [sens0_in LE2 | sens0_out LE2] [sens1...]`。写 flash `Addr_Loop_Sens_List_Offset(0x20)` + `para_store_init()` 重载。**注意:写路径不直接改 RAM 的 g_loop_sens_list,依赖 para_store_init 从 flash 重读生效**。
出厂默认 4 档(storage.c):`{108,54,28,14}`sens_in/ `{81,32,16,12}`sens_out,滞回 ~75/59/57/86%)。
### 5.7 0x92 恢复出厂
无 Data。执行 `set_factory_param() + factory_dev()` → flash 重写出厂配置 → `para_store_init()` 重载。响应:1B status=0。
### 5.8 0xC5 主动上报使能
Data`[enable] [interval] [timeout_min]`
- enable1=开启,0=关闭
- interval:上报间隔系数,实际 `interval × 0x7F`127
- timeout_min:超时分钟数(0=不限时)
处理(dbn_ble_srv.c:830):开启时 `timeout_counter = timeout_min × 60 × 100`**源码 TODO 标注 min→ms60×100=6000 疑应为 60000**,若按 6000 则实际超时 = timeout_min 分钟 ÷ 10,注意现场验证)。关闭时 flag=0。
---
## 6. 主动上报 0xC0(芯片 → 小程序)
组包:`usart_packet_processing_acs_loop()`dbn_ble_srv.c:452),type = 5SENS_LOOP_DYNAMIC)。
| 偏移 | 字节 | 内容 |
|------|------|------|
| 0 | 1 | `0x05`SENS_LOOP_DYNAMIC 线圈动态) |
| 1 | 1 | `loop_num<<6 \| freq_level<<4 \| condition&0x0F` |
| 2 | 1 | `relay2_state<<6 \| relay2_cng<<4 \| relay1_state<<2 \| relay1_cng&0x3` |
| 3 | 1 | `loop1_FLAG_CUT<<7 \| car_state<<4 \| direction&0x0F` |
| 4-6 | 3 | 线圈断开次数(LEpower_up_state==0 时为 1 |
| 7-9 | 3 | 实际频率(LE`freq = sclk_freq/CAPVD×LPCNT + 360` 补偿) |
| 10-12 | 3 | variation 变化量(**3B 有符号补码 LE**,正=车/金属进入方向) |
**触发条件**report_sens_acsdbn_ble_srv.c:531):
- 事件:`flag_event` 置位(车进出等事件)立即上报
- 周期:`report_counter >= 120` 周期上报(120 × 50ms ≈ 6s
- 前提:`g_dbn_ble_state_acs_enable.enable == 1`0xC5 开启)
**variation 接收端注意**:int32_t 截断 3B,负值需符号扩展(`if (v & 0x800000) v |= 0xFF000000`),与 vd960Loop V1.05 同口径。
**condition**:环境状态评估值 0~15`g_env_activity/10`,>150 取 15;线圈断开强制 15),值越大干扰越大。
---
## 7. 实现细节与坑(对照源码)
1. **sensitvity 1~4 vs 0~3**DLD154Pro 协议层 1~4,内部 `g_freq_sens = sensitvity-1`。0x24 回读 `+1`。**与 vd960Loop(0~3)不一致,小程序需按产品区分**
2. **分包粒度 14B 写死**`MAX_BLE_DAT_RESPONSE_LEN = BLE_BUFF_MAX_LEN - 4 = 14`(基于 MTU 23);MTU 协商更大后不重新分包——正确但低效
3. **0xC5 超时疑似 bug**`timeout_min × 60 × 100`,若意图 ms 则应为 ×1000(待现场验证)
4. **0x8A 写灵敏度表不直接更新 RAM**:依赖 `para_store_init()` 重读 flash;写完立即读可能拿到旧值
5. **0xC0 frequent +360 补偿**`_current_freq = freq_tmp + 360`(经验补偿值,示波器标定用)
6. **0x1F/0x1E 无响应**:复位/出厂类命令执行后设备重启,小程序不应等待响应帧
7. **notify 超限静默丢弃**`peripheralChar4Notify``len > (peripheralMTU-3)` 时返回 FAIL,不重发——长响应必须分包
8. **密码命令未实现**:0x1C/0x1D 已注释,小程序不应依赖加密鉴权
---
## 8. 交互示例
**读取设备信息**(无 DataLen=1):
```
下发: 8F 00 01 10 11 11
│ │ │ │ │ └ SUM = 0x00+0x01+0x10 = 0x11
│ │ │ │ └─ XOR = 0x00^0x01^0x10 = 0x11
│ │ │ └─ CMD = 0x10
│ │ └─ Len = 1 (CMD only)
│ └─ Header = 0 (单包)
└─ Magic = 0x8F
芯片 → Char4 notify: 8F 00 10 XX [MAC6][03 01][03 04][0A "DLD154Pro"][dev_no6][00 00][00 00] [XOR] [SUM]
Len=0x10(16): CMD + 15B Data
```
**设置灵敏度为 2 档(协议值 2)**
```
下发: 8F 00 06 23 20 00 00 00 00 [XOR] [SUM]
Len=6: CMD(0x23)+Data5
Data[0]=0x20: sensitvity=2(低4位) | freq_level=0(高4位)
Data[1..4]=延时/输出/存在/方向模式
```