# DLD960 BLE 日志查询交互过程(实测示例) > 版本: V1.00(2026-08-12) > 适用: vd960DBN(CH32V208)+ 微信小程序 > 目的: 以**真实串口日志**为样例,完整描述"小程序发指令 → 设备处理 → 设备回包"的交互过程,供固件/小程序两端排查对照 --- ## 1 帧格式回顾(与 DLD960_BLE协议.md 一致) ``` Magic | Header | Data | CheckByte | Addr/Sub Len CMD | | Xor Sum 1 Byte | 1B 1B 1B | xx | 1B 1B ``` - `Len = len(CMD) + len(Data)`,即 `pkg[2] = 1 + data_len` - 校验:`Xor = XOR(pkg[1..Len+2])`,`Sum = SUM(pkg[1..Len+2])`(覆盖 header+cmd+data,不含 magic) - Magic = `0x8F`(MAGIC_BYTE_DBN_DEFAULT) - **Header 字节分包语义**:`(pkg_amount << 4) | pkg_seq` - 单包:`0x00`(amount=0, seq=0) - 分包:高 4 位 = 总包数,低 4 位 = 当前包序号(从 1 递增),最后一片 `amount == seq` - **单包数据上限(动态,V1.01+)**:`chunk = min(peripheralMTU - 9, 94)`(整包 = 帧头4 + dat + ckb2,须 ≤ MTU-3 且 ≤ 本地缓冲 100B) | 协商 MTU | chunk(单包最大 dat) | 整包最大长度 | |---------|----------------------|-------------| | 23(未协商) | 14 | 20 | | 96(本样例手机) | 87 | 93 | | 185(iOS 常见) | 94 | 100 | --- ## 2 命令码 | 命令码 | 名称 | 方向 | 说明 | |--------|------|------|------| | `0x25` | `OFFLOG_STAT` | APP→设备 | 查询脱机事件日志统计 | | `0x26` | `OFFLOG_QUERY` | APP→设备 | 按全局序号分页拉取日志记录 | | `0x27` | `OFFLOG_CLEAR` | APP→设备 | 清除日志(审计留痕) | --- ## 3 交互示例一:查询日志统计 OFFLOG_STAT (0x25) ### 3.1 小程序发送(请求帧) ``` 8F 00 01 25 24 26 ``` | 字节 | 值 | 含义 | |------|-----|------| | pkg[0] | `8F` | magic | | pkg[1] | `00` | header:单包(amount=0, seq=0) | | pkg[2] | `01` | Len = 0 data + 1 cmd = 1 | | pkg[3] | `25` | cmd = OFFLOG_STAT(查询统计,无 data) | | pkg[4..5] | `24 26` | ckb:Xor=0x24, Sum=0x26 | ### 3.2 设备处理日志 ``` [Rx][13:45:41.577] profile ChangeCB CHAR1?..:�, len:6 [Rx][13:45:41.577] 8F 00 01 25 24 26 [Rx][13:45:41.577] BLE: offlog_stat count=162 seq_first=1 seq_last=162 [Rx][13:45:41.588] BLE notify OK, len:25, MTU:96 ``` ### 3.3 设备响应(25B = 帧头4 + dat 19 + ckb 2,单包) ``` 8F 00 14 25 <19B data> ``` 响应 data(19B,全小端)与设备日志字段对照: | data 偏移 | 长度 | 字段 | 本次值 | 说明 | |-----------|------|------|--------|------| | 0 | 1 | `status` | `00` | OK | | 1 | 2 | `boot_seq` | 待补(需原始 hex) | 启动序号 | | 3 | 4 | `count` | `A2 00 00 00` = 162 | 有效记录条数 | | 7 | 4 | `capacity` | `80 1F 00 00` = 8064 | 容量上限 | | 11 | 4 | `seq_first` | `01 00 00 00` = 1 | 逻辑首条全局序号 | | 15 | 4 | `seq_last` | `A2 00 00 00` = 162 | 最新全局序号 | > 单包响应无分包,`notify OK len:25`(25 = 4+19+2),MTU=96 下 25 ≤ 93,正常。 --- ## 4 交互示例二:读取日志记录 OFFLOG_QUERY (0x26) ### 4.1 小程序发送(请求帧) ``` 8F 00 06 26 01 00 00 00 04 25 31 ``` | 字节 | 值 | 含义 | |------|-----|------| | pkg[0] | `8F` | magic | | pkg[1] | `00` | header:单包请求 | | pkg[2] | `06` | Len = 5 data + 1 cmd = 6 | | pkg[3] | `26` | cmd = OFFLOG_QUERY | | pkg[4..7] | `01 00 00 00` | start_seq = 1(LE32,含) | | pkg[8] | `04` | count = 4(≤ OFFLOG_MAX_QUERY_RECORDS=4) | | pkg[9..10] | `25 31` | ckb | ### 4.2 设备处理日志 ``` [Rx][13:45:47.827] profile ChangeCB CHAR1?..:�, len:11 [Rx][13:45:47.827] 8F 00 06 26 01 00 00 00 04 25 31 [Rx][13:45:47.827] BLE: offlog_query start_seq=1 req=4 fetched=4 [Rx][13:45:47.848] BLE notify OK, len:93, MTU:96 [Rx][13:45:47.848] 8F 21 58 26 00 04 A5 01 04 00 01 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 A5 01 04 00 02 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 A5 01 04 00 03 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 18 F3 E5 ``` ### 4.3 响应分包说明 响应 dat 总量 = status(1) + count(1) + 4×32B = **130B** > 单包上限 87B(MTU=96)→ **必须分包 2 包**: | 包 | header | 整包长 | dat 内容 | |----|--------|--------|----------| | 第 1 包 | `0x21`(amount=2, seq=1) | 93B | status+count + 记录1(32B) + 记录2(32B) + 记录3前21B = 87B | | 第 2 包 | `0x22`(amount=2, seq=2) | **49B(预期)** | 记录3剩余11B + 记录4(32B) = 43B | ### 4.4 第一包逐字段解析(93B) ``` 8F 21 58 26 00 04 <记录1 32B> <记录2 32B> <记录3 前21B> F3 E5 -- -- -- -- -- -- --------------------------------------- ---- | | | | | | | +-- ckb | | | | | | +-- dat: status(1)=00, count(1)=04, 然后记录 | | | | | +-- status=00 OK | | | | +-- cmd=0x26 | | | +-- Len=0x58=88 = 87 data + 1 cmd | | +-- header=0x21: amount=2, seq=1 | +-- magic=0x8F ``` 记录结构(OfflogEvt 32B,小端)——本次 3 条记录均为 `type=0x01 04 00`(事件类型,待对照 offlog.h 事件表): ``` 记录1: A5 01 04 00 | 01 00 00 00 | 00×12 | 01 00 00 00 | 18 00 00 00 记录2: A5 01 04 00 | 02 00 00 00 | 00×12 | 02 00 00 00 | 08 00 00 00 记录3: A5 01 04 00 | 03 00 00 00 | 00×12 | 03 00 00 00 | 18(截断于第 21B) ``` ### 4.5 第二包(预期,未收到——当前问题) ``` 8F 22 2C 26 <记录3剩余 11B> <记录4 32B> ``` - header `0x22`:amount=2, seq=2(最后一片) - Len = `0x2C` = 44 = 43 data + 1 cmd - 整包 49B ### 4.6 当前问题(2026-08-12 排查中) **现象**:设备只发出了第 1 包(93B),第 2 包(49B)未发出;小程序按 `amount=2` 等第 2 包永远等不到。 **已确认**: - MTU 分包粒度动态化已生效(93B ≤ 96-3=93,无 `Too large noti`) - `performPeriodicTask` 已加主动拉包逻辑(不依赖收包事件) - 已加 `BLE pull FAIL` 诊断打印,但本次日志**未出现** → 说明拉包时 `g_buf_ble_response.flag==0`(队列已被清)或 `_pull==1` 但发送周期未到/被阻塞 **下一步排查**: 1. 加 `performPeriodicTask` 周期心跳打印(每 500ms),确认 TMOS 周期事件是否持续执行 2. 核对 `SBP_PERIODIC_EVT_PERIOD=50` 的 TMOS 时间单位(tick vs ms) 3. 检查 `g_buf_ble_response` 在第 1 包发出后是否被意外 clear(`unpack_packs`/`set_response_buf` 调用路径) --- ## 5 交互示例三:清除日志 OFFLOG_CLEAR (0x27) ### 5.1 小程序发送 ``` 8F 00 01 27 XX XX ``` | 字节 | 值 | 含义 | |------|-----|------| | pkg[0] | `8F` | magic | | pkg[1] | `00` | header:单包 | | pkg[2] | `01` | Len = 1 | | pkg[3] | `27` | cmd = OFFLOG_CLEAR | | pkg[4..5] | `XX XX` | ckb | ### 5.2 设备响应 ``` 8F 00 02 27 00 XX XX ``` - dat:`status(1)=00`(OK) - **注意**:擦除 W25Q32 阻塞约 2.8s,期间 BLE 无响应、网络短时失服务(MQTT keepalive 60s 可吸收) --- ## 6 小程序端分包重组规则(伪代码) ```js // 订阅 onBLECharacteristicValueChange, 按 cmd 维护重组缓冲 let frag = { cmd: null, amount: 0, seq: 0, data: [] }; function onNotify(buf) { const magic = buf[0], header = buf[1], len = buf[2], cmd = buf[3]; const amount = header >> 4, seq = header & 0x0F; const data = buf.slice(4, 4 + (len - 1)); // 去掉 cmd 的净数据 const ckb = buf.slice(-2); // 校验可选 if (amount === 0) { // 单包 dispatch(cmd, data); } else { // 分包 if (seq === 1) { frag = { cmd, amount, seq, data: [] }; } if (frag.cmd !== cmd) return; // 乱序/新响应, 丢弃 frag.data = frag.data.concat(data); frag.seq = seq; if (seq === amount) { // 收齐 dispatch(cmd, frag.data); frag = null; } } } ``` > 关键点:收到第 1 包(seq=1, amount=2)后**必须继续等待** seq=2 的第二个通知,不要在第 1 包到达时判完成。 --- ## 7 排查时间线 | 时间 | 现象 | 结论 | |------|------|------| | 08:15 | `Too large noti, len:102, MTU:96` | 分包粒度写死 96B > MTU-3=93,丢包 | | 11:51 | 修复后第一包 93B 正常发出 | MTU 动态分包生效 | | 11:51~13:45 | 第二包 49B 未发出,无 pull FAIL 打印 | 分包续传/发送周期链路待查(见 §4.6) |