docs: §6.9 补 BLE 分包承载与缓冲边界 + 4 条实现前置项 (V1.15)

- 核实 BLE 链路分包机制: 收/发双向对称, 分包头编码于 pkg[1] 高/低 4 位
  (高 4 位 = 总包数, 低 4 位 = 当前包序), 每包 dat <= 94B @MTU>=103,
  4 位总包数 => 最多 15 包; 发送侧先自增再编码, 线上首包 seq==1, 与接收侧
  low==1 起点 / high==low 收尾完全配对
- 修正 229B 载荷定性: 分包使 229B 确可送达 => 「载荷 > 131B 即越界写
  g_buf_ble_response.dat / tmp_ble_buf(132B)」属可达缺陷, 而非纸面能力
- §6.9.9 实施状态新增 4 条前置改造项: 缓冲扩 >= 260B / set_response_iot_net|topic
  补长度钳制 / 接收侧累加钳制(防 uint8 回绕) / unpack_packs 用起 len 形参
- devlog 归档本轮勘察, vd960DBN 源码零改动
This commit is contained in:
wangfq
2026-09-10 22:59:30 +08:00
parent 2044efe14f
commit 12618578d8
2 changed files with 87 additions and 1 deletions
+10 -1
View File
@@ -1594,13 +1594,17 @@ dld960/{dev_serial}/{direction}
| 载荷 | 典型长度 | 最坏长度 | 结论 |
|------|----------|----------|------|
| net | ≈ 59 B | 63+1+5+1+63+1+63+1+31 = **229 B** | 单帧可传( 260 B 上限) |
| net | ≈ 59 B | 63+1+5+1+63+1+63+1+31 = **229 B** | 单帧可传( 260 B 上限 **+ 缓冲扩容**,见下注 |
| topic | ≈ 51 B | 1+1+63+1+63 = **129 B** | 单帧可传 |
**必须拆成两条独立记录**`net` / `topic`):既与 BLE 两个命令的粒度对齐,也使 Air780 侧 fskv 单值(**≤ 255 B**`luat_fskv_set` 限制)安全:net 229 B < 255 B ✓,topic 129 B ✓。
Air780 侧建议**直接存原始载荷字节串(不转 JSON)**,加载时按 `0x00` 拆分 —— 与 DBN 侧构造器逐字节同源。
> ⚠️ **承载与缓冲前置条件(2026-09-10 补充)**229 B 经 BLE **分包**确可送达 —— 分包头编码于 `pkg[1]` 高/低 4 位(总包数 / 序号),每包 dat ≤ 94 B(MTU ≥ 103),4 位限制下最多 15 包。
> 但 DBN 侧 `g_buf_ble_response.dat` / `tmp_ble_buf` 仅 **132 B** 且 `set_response_iot_net()` / `set_response_iot_topic()` **无长度钳制** ⇒ 现版本载荷一旦 > 131 B 即**越界写**(可操作门槛:端口 4 位时 `host + clientid + username + password` 字符数 > 124)。
> 故本节的 229 B 能力**以完成 §6.9.9 前置改造项 1–4 为前提**,否则属纸面能力。
### 6.9.5 交互流程
**① 拉取(主:兜底一切不一致)**
@@ -1671,6 +1675,10 @@ DBN **不维护“待同步”状态位**:推送时链路不可用则不重试
|----|------|------|
| DBN | UART1 通道 + 0x8F 本机侧私有帧接入本机指令处理器(不转发) | **已实现**2026-09-10 |
| DBN | UART1 帧缓冲 70 B → 260 B 扩容 | 待实现 |
| DBN | ⚠️ **前置**`g_buf_ble_response.dat` / `tmp_ble_buf` 132 B → ≥ 260 B(与蓝牙小程序/MRS 工程**同步**扩容) | 待实现 |
| DBN | ⚠️ **前置**`set_response_iot_net/topic()` 补长度钳制(对齐 `set_response_buf()` @`dbn_ble_srv.c:288` | 待实现 |
| DBN | ⚠️ **前置**`unpack_packs()` 接收侧累加加钳制(`dat_len + (_len-1) > MAX_BLE_DAT_BUF_LEN` 即丢包清缓冲,防 `uint8_t` 回绕) | 待实现 |
| DBN | ⚠️ **前置**`unpack_packs()` 用起 `len` 形参(现全程未引用,memcpy 长度全取自 `pkg[2]` | 待实现 |
| DBN | 0x8F 配置请求应答 + BLE 写成功后主动推送 | 待实现 |
| DBN | `CMD_DBN_RW_UART_BAUD` 拒绝 `uart_num == 1` | 待实现 |
| Air780 | `frame_parser.lua` 支持 0x8F(本地消费,不转发)| 待实现 |
@@ -1692,6 +1700,7 @@ DBN **不维护“待同步”状态位**:推送时链路不可用则不重试
| V1.05 | 2026-07-15 | 增加**设备时钟同步**(§2.3,方案B):设备无 RTC,`initialize` 上线后平台经 `report_config` 命令下发 Unix `ts`,设备据此校准,之后上行 `ts` 为真实 Unix 时间;校准前为上电秒数 | wangfq |
| V1.06 | 2026-08-04 | 增加**脱机事件日志**命令:`log_stat`(统计/分页定位)、`log_query`(按全局序号分页,count≤4)、`log_clear`(清除+审计留痕);§2.3 补充日志双时间戳语义(`ts_ms` 相对 + `unix_ts` 已同步,0=未同步,锚点回算规则) | wangfq |
| V1.07 | 2026-08-18 | `log_stat` / `log_query` / `log_clear` 增加**快照流**支持(`stream=snapshot`,与 BLE 0x28/0x29/0x2A 同语义):快照统计 capacity 随芯片动态(48064~449472)、快照分页 count≤14 通道记录 JSON ~810B 超发送缓冲,实测修正;BLE 原始通道仍 ≤2)、快照清除审计留痕;`capacity`/`count` 类型修正为 uint32W25Q256 事件流 130944 超 16bit | wangfq |
| V1.15 | 2026-09-10 | §6.9 补充 **BLE 分包承载与缓冲边界**:核实 BLE 链路**分包机制存在且收发双向对称**(分包头编码于 `pkg[1]` 高/低 4 位 = 总包数/序号;每包 dat ≤ 94 B @MTU ≥ 103;4 位 ⇒ 最多 15 包)⇒ 229 B 载荷**确可送达**,故「载荷 > 131 B 即越界写 `g_buf_ble_response.dat` / `tmp_ble_buf`(132 B,构造器无钳制)」属**可达缺陷**而非纸面;§6.9.9 新增 4 条**实现前置改造项**(缓冲扩 ≥260 B / 构造器补钳制 / 接收侧累加钳制防 `uint8_t` 回绕 / `unpack_packs` 用起 `len` 形参);§6.9.4.3 补承载前置条件说明 | wangfq |
| V1.14 | 2026-09-10 | 新增 **§6.9 4G 配置同步(BLE → DBN → Air780**:明确配置权威源为 DBN flashAir780 侧 fskv 仅作启动缓存,**唯一写入者 = DBN 配置帧**,避免第二权威源);复用 **0x8F 本机侧私有帧**(与 BLE 同魔数 `MAGIC_BYTE_DBN_DEFAULT`,链路两端各自本地消费、均不转发),命令复用 `GET_IOT_NET(0x14)` / `GET_IOT_TOPIC(0x16)`,载荷与 BLE 读响应**逐字节同源**(复用 `set_response_iot_net()` / `set_response_iot_topic()`,零新增序列化)、拆 net/topic 两条(最坏 229B / 129B,均 ≤ fskv 单值 255B);**0x8F 帧长上限独立定为 260B**(Loop 业务帧 70B 上限不变,两侧帧缓冲需同步扩容);同步触发点补 `UPDATE_DEV_SERIAL(0x09)` / `SET_SUB_CODE``iot_enable` 位 / **禁改 UART1 波特率**V1.11 的 **0x7D 帧配置同步方案作废**`iot_net_info.mode` 实测无 BLE 写入路径、恒为 IP 模式,故不随载荷同步 | wangfq |
| V1.13 | 2026-08-31 | `initialize``extra_info` 增加可选字段 **`imei`** / **`iccid`**4G 模块 IMEI / 流量卡 ICCID;无 4G 模块时省略或空串;4G 通道由 Air780 填真实值,§6.2 说明) | wangfq |
| V1.12 | 2026-08-31 | **4G 通道适配修订:方案 B(hex 透传)改为方案 C(Air780 协议转换)**——Air780 解析 0x7F 帧并转换为**标准 JSON 命令**loop_data / event_report / initialize / heartbeat,与有线通道一致),平台零改动;V1.11 的 frame_report / frame_cmd 降级为**可选兜底**4G 事件面 = **仅线圈事件**car_enter/car_leave/loop_cut/loop_restore,不含 DBN 内部网络事件);命令响应链路 Air780 单命令状态机(超时回 code=5);link 对象保留;Air780 以 Lua 复刻 iot_event_report 逻辑(沿检测 + ACK + 5s×3 重发 + 16 深队列 + 跨重连同 msg_id),可行性已评估(2026-08-31 | wangfq |
+77
View File
@@ -4,6 +4,83 @@
>
> 项目定位: DLD960 通信板 — BLE 配网、TCP JSON 协议服务、Loop MCU 串口桥接
## 2026-09-10 — BLE 分包机制核实 + net 229B 载荷可达性修正(§6.9 前置改造项)
> 触发:用户 2026-09-10 两问 ——「net 的 229B 是怎么计算出来的?」「我记得蓝牙小程序有分包机制,看下是不是」。
> **性质:勘察 + 归档,本条目对 `vd960DBN` 源码零改动**;结论用于修订协议 §6.9 的落地前置条件。
### 1. BLE 分包机制 —— 确认存在,收发双向对称
分包头复用 **`pkg[1]`** 字段(原地是 Addr),把总包数与序号压进高/低 4 位:
| 位段 | 含义 |
|------|------|
| `pkg[1] >> 4` | 总包数 `pkg_amount` |
| `pkg[1] % 0x10` | 当前包序号 `pkg_seq` |
**接收**`dbn_ble_srv.c:466-504``unpack_packs()` 内):
- `high == 0` → 单包(不分包),整包直取 `_len - 1` 字节;
- `low == 1` → 第一包,重置缓冲与偏移;
- `low > 1` → 后续包,校验 `amount`/`cmd` 一致 + `seq` 连续,`dat_len += (_len - 1)``memcpy(&dat[_offset], ...)`
- `high == low` → 收包完成,进入命令处理。
**发送**`dbn_ble_srv.c:420-421 / 436-437`):`_pkg_seq += 1`(**先自增再编码**,故线上第一包即 `seq == 1`)→ `buf[1] = (pkg_amount << 4) | pkg_seq`;单包时 `buf[1] = 0``dat_offset += _remain_len` 推进;发完 `pkg_amount == pkg_seq` 清缓冲。
→ **与接收侧 `low == 1` 起点、`high == low` 收尾完全配对,设计自洽。**
**每包 dat 上限随 MTU 协商**`ble_notify_chunk_max()``_limit = peripheral_get_mtu() - 9`,再被 `MAX_BLE_Notify_Buf_LEN - 6` 夹住;`BLE_BUFF_MAX_LEN = 100` @ `BLE/HAL/include/config.h:115`):
| MTU | 每包 dat | 4 位总包数上限(≤15 包) |
|-----|----------|--------------------------|
| 23(默认) | 14 B | 210 B |
| 96 | 87 B | 1305 B |
| **≥103(现用)** | **94 B** | **1410 B** |
> `dbn_ble_srv.h:81``//24` 注释是 `BLE_BUFF_MAX_LEN` 的**过期旧值**(原 24,现 100),不可据此推算分块。
### 2. 关键修正:229B **真的可达** ⇒ 越界**真的可达**
上一轮结论「`dat[132]` 装不下 229B,实际硬上限 131B,现场跑不到」**是错的** —— 分包让 `dat_len` 跨包累加,229B = 3 包 × ≤94B **可以送达**
| 方向 | 代码事实 | 后果 |
|------|----------|------|
| 发送 | `set_response_iot_net()``dat[132]` 写最多 229B`i` 全程无钳制 | **越界写**(同文件 `set_response_buf()` 有守卫,这两个没有) |
| 接收 | `dat_len += (_len - 1)``memcpy(&dat[_offset], ...)` 全程无钳制 | 多包累加即越界 |
| 通用 | `dat_len` / `_offset` / `_len` / `i` 均为 `uint8_t` | >255 回绕,解析循环行为错乱 |
定性由「理论上限、跑不到」升级为「**可达缺陷**」。**先撞的永远是 132 那道墙**(`pkg_amount` 4 位 ⇒ 15 包 = 1410B 的上限在更远处)。
### 3. 自我纠错(两处)
1. ❌「实际硬上限 131B」→ ✅ 131B 只是**缓冲区**上限;分包使更长载荷**可达**,越界非纸面。
2. ❌ 曾疑「收方要求 `low == 1` 起、发方 `pkg_seq = 0` 起,序号基准不一致」→ ✅ 发送侧**先自增再编码**,线上第一包即 `seq = 1`,**配对正确,疑点作废**(不该写进文档)。
### 4. §6.9 落地前置改造项(新增,实现前必做)
| # | 项 | 依据 |
|---|-----|------|
| 1 | `g_buf_ble_response.dat` / `tmp_ble_buf` 由 132 B 扩至 **≥260 B** | 229B 载荷可达 ⇒ 现缓冲必越界(132B 当初为 offlog QUERY 129B 所定) |
| 2 | `set_response_iot_net()` / `set_response_iot_topic()` 补长度钳制 | 照抄 `dbn_ble_srv.c:288` `set_response_buf()` 的守卫 |
| 3 | `unpack_packs()` 接收侧累加加钳制 | `dat_len + (_len - 1) > MAX_BLE_DAT_BUF_LEN` 即丢包清缓冲,防 `uint8_t` 回绕 |
| 4 | `unpack_packs()` 用起 `len` 形参 | 该形参在 263 行函数体里从未被引用,memcpy 长度全取自 `pkg[2]` |
改动项 1 需**两侧(DBN 与蓝牙小程序/MRS 工程)同步**,漏改一边即越界踩 `g_notify_buftemp` 一类相邻全局。
### 5. 待现场验证
- **小程序侧源码不在本机**`find` 无命中)→ 其分包实现的**末包判定**与**是否同样按 MTU 协商 94 B 切包**无法核对,需上板抓包。
- 现场是否已出现「host 写长了 MQTT 参数就乱」:按门槛(端口 4 位时 `host + clientid + username + password` 字符数 > 124 即越界)**应已偶发,只是未归因到缓冲区**。
### 6. 文件改动(本条目)
| 文件 | 改动 |
|------|------|
| `vd960DBN` 源码 | **零改动**`TaskLoop.c` 等一律未动) |
| `docs/DLD960_IoT_MQTT协议.md` | §6.9.4.3 补分包承载说明;§6.9.9 加 4 条前置改造项;修订记录加 V1.15 |
| skill `payload-sizing-and-buffer-audit.md` | 修正 §0/§3 定性、新增「BLE 分包机制」节、§5 补第 4 项 |
| skill `dbn-air780-config-sync.md` | 补分包与缓冲边界指针 |
## 2026-09-10 — 4G 配置同步协议定稿(《DLD960_IoT_MQTT协议》§6.90x7D 作废)
> 用户需求 2026-09-10:蓝牙小程序读写网络配置指令,哪些需要同步/转发给 4G(服务器域名/IP、端口、MQTT 账号密码、主题等)。