原则:代码未实现的功能,协议文档在相应指令旁如实标注"未实现",避免文档承诺≠固件实现。 - rs485-modbus-protocol.md V1.7→V1.8: §3.1 DI 0x0008 Init Flag 未实现(恒 0);§3.2 IR 0x0006/0x0007(Variation)/ 0x000A/0x000B/0x000C 未实现(改读全数据块 0x010A/0x010B);§3.3 保持寄存器 全部标注(FC 0x06 仅 0x0010/0x0011/0x0012 可写,0x00FE 无分支); §4.3/4.5/4.8 未实现横幅;§5 功能码矩阵 0x03/0x10/0x11 → ✗; §6.3 仅 0x06;§7 0x3D/Init_B 对照标注;§8 版本历史 V1.8 - rs485-700bs-protocol.md: §4.4 0x3D 未实现注记 + §5 速查表 + §6 兼容对照 - ble-protocol.md / product-manual.md / technical-spec.md: 版本 V3.04→V3.05 + 版本历史 - devlog.md: 置顶 2026-08-27 条目(减配清单 + 文档标注 + 保留能力 + 宏修复)
12 KiB
DLD154Pro 蓝牙小程序接口协议
依据源码整理:
BLE/DLD154Pro_Peripheral_28K/APP/dbn_ble_srv.c(主逻辑)、peripheral.c/Profile/gattprofile.c(BLE 服务)、include/storage.h(配置结构)、include/cmcng.h(常量) 固件版本:V3.05(cmcng.hFIRMWARE_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 | 1(CMD)+ N(Data 字节数) |
| CMD | 命令码,见 §4 |
| XOR | 异或校验:从 Header 到 Data 末尾逐字节 XOR |
| SUM | 和校验:从 Header 到 Data 末尾逐字节求和(低 8 位) |
校验示例(compute_ckb,dbn_ble_srv.c:168):
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_LEN−4,基于 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/SUB(V3.01 → 03 01) |
| 8-9 | 2 | 固件版本 MAIN/SUB(V3.05 → 03 05) |
| 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 设置车检器参数
Data(5B):
| 偏移 | 内容 |
|---|---|
| 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(03)索引灵敏度表。与 vd960Loop 的 03 不同,小程序发送 1~4。
direction_mode 解析(unpack_pkg_set_cjq_param,dbn_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。响应 Data(11B):
| 偏移 | 内容 |
|---|---|
| 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_BASE(3B LE,= 524288)(V3.04 追加) |
⚠ 偏移 8-10 用途(V3.04,2026-08-26 追加):variation 换算 ΔL/L 的归一化基数。 第三方应用连接后读一次 0x24 缓存该值:
Δf/f ≈ variation / LOOP_MEASURE_BASE,ΔL/L ≈ -2 × variation / LOOP_MEASURE_BASE。 背景:DLD154Pro 的 MEASUREMENT_BASE = 524288(2^19 @60MHz),与 DLD110S 相同、与 DLD154V4B 的 131072 不同。固件显式上报后第三方无需猜测(曾出现照搬 131072 导致百分比放大 4 倍的问题,DLD110S 2026-08-26 实测发现)。 向后兼容:老小程序只读前 8B 不受影响;新小程序读 11B。
5.5 0x31 读写 UART 参数
Data:[rw] [status] ...
读(rw=0):响应 Data(8B):
[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]
- enable:1=开启,0=关闭
- interval:上报间隔系数,实际
interval × 0x7F(127) - timeout_min:超时分钟数(0=不限时)
处理(dbn_ble_srv.c:830):开启时 timeout_counter = timeout_min × 60 × 100(源码 TODO 标注 min→ms,60×100=6000 疑应为 60000,若按 6000 则实际超时 = timeout_min 分钟 ÷ 10,注意现场验证)。关闭时 flag=0。
6. 主动上报 0xC0(芯片 → 小程序)
组包:usart_packet_processing_acs_loop()(dbn_ble_srv.c:452),type = 5(SENS_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 | 线圈断开次数(LE,power_up_state==0 时为 1) |
| 7-9 | 3 | 实际频率(LE,freq = sclk_freq/CAPVD×LPCNT + 360 补偿) |
| 10-12 | 3 | variation 变化量(3B 有符号补码 LE,正=车/金属进入方向) |
触发条件(report_sens_acs,dbn_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. 实现细节与坑(对照源码)
- sensitvity 1
4 vs 03:DLD154Pro 协议层 14,内部3)不一致,小程序需按产品区分**g_freq_sens = sensitvity-1。0x24 回读+1。**与 vd960Loop(0 - 分包粒度 14B 写死:
MAX_BLE_DAT_RESPONSE_LEN = BLE_BUFF_MAX_LEN - 4 = 14(基于 MTU 23);MTU 协商更大后不重新分包——正确但低效 - 0xC5 超时疑似 bug:
timeout_min × 60 × 100,若意图 ms 则应为 ×1000(待现场验证) - 0x8A 写灵敏度表不直接更新 RAM:依赖
para_store_init()重读 flash;写完立即读可能拿到旧值 - 0xC0 frequent +360 补偿:
_current_freq = freq_tmp + 360(经验补偿值,示波器标定用) - 0x1F/0x1E 无响应:复位/出厂类命令执行后设备重启,小程序不应等待响应帧
- notify 超限静默丢弃:
peripheralChar4Notify中len > (peripheralMTU-3)时返回 FAIL,不重发——长响应必须分包 - 密码命令未实现:0x1C/0x1D 已注释,小程序不应依赖加密鉴权
8. 交互示例
读取设备信息(无 Data,Len=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]=延时/输出/存在/方向模式