Files
DLD110SV4B/docs/ble-protocol.md
T

10 KiB
Raw Blame History

DLD110SV4 蓝牙小程序接口协议

依据源码整理:BLE/DLD110S_Peripheral_28K/APP/dbn_ble_srv.c(主逻辑)、peripheral.c/Profile/gattprofile.cBLE 服务)、peripheral_main.c(灵敏度/检测)、include/storage.h(配置结构)、include/cmcng.h(常量) 固件版本:V4.20cmcng.h FIRMWARE_VER)| 硬件版本:V4.01 | 产品型号:DLD110SBLE 单线圈)


⚠ 与 DLD154Pro 协议的三处关键差异(先读这节)

# 差异 DLD110SV4 DLD154Pro
1 灵敏度来源 硬件拨码 KEY_SA1/SA2 决定poll_sens_keyperipheral_main.c:263),协议 0x23 设置的 sensitvity 不参与检测 BLE 配置(无拨码),sensitvity 1~4 直接生效
2 灵敏度档数 3 档 {108,54,28} / {81,32,16}sens_in/sens_out 4 档 {108,54,28,14} / {81,32,16,12}
3 命令 0x31 (无 RS485 有(读写波特率/地址)

灵敏度拨码映射poll_sens_key,每周期刷新 g_freq_sens,检测阈值 = g_loop_sens_list.sens[g_freq_sens]):

KEY_SA1 KEY_SA2 g_freq_sens 档位 检测阈值 sens_in
1 1 0 最低 1080.165% Δf/f
0 1 1 540.082%
1 0 2 最高 280.043%
0 0 保持上次

DEBUG 编译时固定 g_freq_sens = 2


1. BLE 服务与特征

服务/特征 UUID 属性 长度 用途
服务 SIMPLEPROFILE 0xFFE0 广播服务 UUID
Char1 0xFFE1 读写 (RW) 64B 小程序 → 芯片:命令下发
Char2 0xFFE2 1B 预留
Char3 0xFFE3 8B 预留
Char4 0xFFE4 通知 (Notify) 32B 芯片 → 小程序:命令响应 + 主动上报
Char5 0xFFE5 5B 预留
  • 设备名:DLD110S(广播 + GATT Device Name
  • MTU:默认 23,连接后协商(ATT_MTU_UPDATED_EVENT)。notify 单包 payload ≤ peripheralMTU 3
  • 交互模型:写 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_seqseq 从 1
Len 1CMD+ NData 字节数)
XOR 从 Header 到 Data 末尾逐字节异或
SUM 从 Header 到 Data 末尾逐字节求和(低 8 位)

校验算法(dbn_ble_srv.c compute_ckb/check_pkg)与 DLD154Pro 完全一致:最小帧长 6,XOR/SUM 任一不符丢弃。


3. 分包机制

与 DLD154Pro 相同(同一模板):

  • 发送MAX_BLE_DAT_RESPONSE_LEN = 14= BLE_BUFF_MAX_LEN4MTU=23 旧假设),多包 Header = (amount<<4)|seq
  • 接收unpack_packs() 支持重组(当前仅 0x1C/0x1D 使用,已注释)
  • ⚠ 分包粒度写死 14B,MTU 协商更大后不重新分包

4. 命令总览

CMD 名称 方向 说明
0x10 GET_DEV_INFO 小程序→芯片 读设备信息(MAC/版本/型号)
0x1F RESET_DEV 小程序→芯片 复位设备(SYS_ResetExecute
0x23 SET_CJQ_PARAM 小程序→芯片 设置车检器参数(灵敏度不生效,见 §5.3
0x24 GET_CJQ_PARAM 小程序→芯片 读车检器参数
0x8A LOOP_SENS_LIST 小程序→芯片 读写灵敏度表(sens_in/sens_out
0x92 SET_CJQ_FACTORY 小程序→芯片 恢复出厂
0xC5 SENS_ACS_ENABLE 小程序→芯片 主动上报使能
0xC0 SUB_SENS_REPORT 芯片→小程序 主动上报线圈动态(不可下发)

不存在0x31DLD154Pro 有,本产品无 RS485)。 未实现(注释)0x1C/0x1D/0x1E/0x20-0x22/0x6D/0x87/0x88/0x89。


5. 命令详述

5.1 0x10 读设备信息

无 Data。响应 Data

偏移 字节 内容
0-5 6 MAC 地址
6-7 2 硬件版本 MAIN/SUBV4.01 → 04 01
8-9 2 固件版本 MAIN/SUBV4.20 → 04 14
10 1 产品型号长度
11.. N 产品型号 ASCII"DLD110S"
.. 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(有限存在时长)
4 direction_mode(高 4 位 = g_function_mode

⚠ 灵敏度字段不生效g_loop_cng_unit.sensitvity 仅写入 flash 存档,检测阈值由拨码 g_freq_sens 决定(见开头差异表)。小程序设置灵敏度无效,现场改灵敏度必须拨码。

内部换算(unpack_pkg_set_cjq_param):

g_function_mode = direction_mode >> 4
g_hold_time     = exist_mode * 30 * 20   (600 tick ≈ 30s × exist_mode, @50ms tick)

处理:更新全局 → write_cfg_to_store(4, tmp, 7)para_store_init()。响应:1B status=0。

5.4 0x24 读车检器参数

无 Data。响应 Data11B):

偏移 内容
0 (g_freq_sens + 1) | (loopFreq_Level << 4)(灵敏度回读 = 拨码档位 + 1,值域 1~3
1 delay_time
2 output_mode | (loopSafe_Timeout << 3)
3 exist_mode
4 sens_list.total << 4= 3,高 4 位)
5 线圈断开次数低字节
6 线圈断开次数高字节
7 g_function_mode(注意:DLD154Pro 此处是 direction_mode
8-10 归一化基数 LOOP_MEASURE_BASE3B LE= 524288V1.1 追加)

偏移 8-10 用途(协议 V1.12026-08-26 追加)variation 换算 ΔL/L 的归一化基数。 第三方应用连接后读一次 0x24 缓存该值:Δf/f ≈ variation / LOOP_MEASURE_BASEΔL/L ≈ -2 × variation / LOOP_MEASURE_BASE背景DLD110S 的 MEASUREMENT_BASE = 5242882^19 @60MHz),与 DLD154V4B 的 131072 不同——小程序曾照搬 131072 导致所有百分比放大 4 倍。固件显式上报后第三方无需猜测。 向后兼容:老小程序只读前 8B 不受影响;新小程序读 11B。

5.5 0x8A 读写灵敏度表

读(pkg[4]=0:响应 Data[0x10] [total=3] [sens0_in LE2 | sens0_out LE2] [sens1...]

写(pkg[4]≠0Data 从 pkg[5] 起:[total] [表...]。写 flash Addr_Loop_Sens_List_Offset(0x20) + para_store_init()。不直接更新 RAM,依赖重读生效。

出厂默认 3 档:sens_in {108, 54, 28} / sens_out {81, 32, 16}peripheral_main.c:187,滞回 ~75/59/57%)。

5.6 0x92 恢复出厂

set_factory_param() + factory_dev()para_store_init()。响应:1B status=0。

5.7 0xC5 主动上报使能

Data[enable] [interval] [timeout_min]

  • enable1=开启,0=关闭
  • interval:间隔系数,实际 interval × 0x7F127
  • timeout_min:超时分钟数(0=不限时)

处理:开启时 timeout_counter = timeout_min × 60 × 100源码 TODO 标注 min→ms60×100=6000 疑应为 60000,待现场验证)。关闭时 flag=0。


6. 主动上报 0xC0(芯片 → 小程序)

与 DLD154Pro 相同模板(type = 5 SENS_LOOP_DYNAMIC):

偏移 字节 内容
0 1 0x05SENS_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,上电未连时为 1
7-9 3 实际频率(LEfreq = sclk_freq/CAPVD×LPCNT + 360 补偿)
10-12 3 variation3B 有符号补码 LE,正=车/金属进入方向)

触发:事件(flag_event)立即上报;周期 report_counter >= 120120 × 50ms ≈ 6s);前提 0xC5 开启。 variation 接收端注意3B 有符号,负值需符号扩展(if (v & 0x800000) v |= 0xFF000000)。 condition:环境评估 0~15g_env_activity/10,>150 取 15;线圈断开强制 15)。


7. 实现细节与坑(对照源码)

  1. ⚠ 灵敏度是拨码的不是协议的:检测阈值 = g_loop_sens_list.sens[g_freq_sens]peripheral_main.c:609),g_freq_sens 由 poll_sens_key() 读 KEY_SA1/SA2 每周期刷新。0x23 的 sensitvity 只存档不生效,0x24 回读的是拨码档位+1
  2. 3 档灵敏度MAX_LOOP_SENS_AMOUNT=3),0x8A 写表 total 上限 3
  3. 无 0x31DLD110SV4 无 RS485,小程序不应下发 0x31
  4. 0xC5 超时疑似 bugtimeout_min × 60 × 100(若意图 ms 应为 ×1000,待现场验证)
  5. 0x8A 写表不直接更新 RAM:依赖 para_store_init() 重读
  6. 0xC0 frequent +360 补偿:经验值,示波器标定用
  7. 0x1F/0x92 无响应帧:复位/出厂类命令执行后设备重启
  8. notify 超限静默丢弃len > (peripheralMTU-3) 返回 FAIL 不重发,长响应必须分包
  9. 0x24 偏移 7 是 g_function_mode(非 direction_mode)——与 DLD154Pro 不同,解析别混
  10. g_hold_time 换算差异exist_mode × 600 tick(≈30s/单位,DLD154Pro 为 ×100 tick ≈5s/单位)——产品差异,协议层语义一致

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][04 01][04 14][07 "DLD110S"][dev_no6][00 00][00 00] [XOR] [SUM]

设置参数(如延时/输出,灵敏度不生效)

下发: 8F 00 06 23 20 00 00 00 00 [XOR] [SUM]
      Len=6: CMD(0x23)+Data5
      Data[0]=0x20: sensitvity=2(仅存档) | freq_level=0
      Data[1..4]=延时/输出/存在/方向模式