# vd960 (DLD960) 开发计划 — V1.0.0 之后 > 制定日期:2026-07-17 · 基线:整机 V1.0.0(2026-07-16 发布) > 原则:先稳固、再上云、后算法深化;任何涉及继电器输出的改动,防砸车逻辑优先。 --- ## 0. 现状基线 | 项 | 状态 | |----|------| | 整机版本 | V1.0.0(首发),Loop/DBN 固件 1.0 配套 | | 协议 | Loop 串口 V1.05 / TTL 串口 V1.01 / TCP JSON V1.01 / IoT MQTT V1.05 | | 在途改动(未提交) | BLE 透传路径重构:`usart_biz.c` 0x7F→0x8F 帧改走 `set_response_tran_to_notify()`,原 `_report_flag` 保留机制移除 | | 已知约束 | 无 RTC(依赖平台下发 ts);CH32V208 栈紧张;Loop/DBN 固件禁止混刷 | --- ## P0 — 发布后稳固(目标 V1.1.0,约 2~4 周) ### P0.1 BLE 透传路径重构收尾 🔴(在途) 当前工作区改动把 0xC0 传感帧的 BLE 转发从"置 flag 延迟消费"改为"立即 notify"。收尾必须核对三件事: 1. **帧消费方真值表**:0xC0 帧现在有 **三个消费方**(TCP JSON 回调 / MQTT `iot_sensor_ingest` / BLE notify)。2026-07-15 的"陈旧快照 34 秒"事故根因就是消费路径数据源分裂——BLE 加入后必须重画一张"谁消费、谁清理(InitPkgUart)"的真值表,确保: - 每条路径都能拿到帧(同源汇聚不漏帧); - 帧最终一定被清理(无滞留 → 无假"新帧"); - BLE ACS 分支改 Magic 为 0x8F 后,MQTT/TCP 路径若还要读同一缓冲,读到的是被改过的帧头(**待确认是否有影响**)。 2. `set_response_tran_to_notify()` 新增返回值的语义与调用方检查。 3. 板上验证:BLE 小程序连上时,TCP/MQTT 上报不受影响;BLE 断开后无帧泄漏。 ### P0.2 代码 TODO 清剿 | 位置 | 问题 | 优先级 | |------|------|--------| | `iot_mqtt_srv.c:753` | `loop_ok[i] = 1` 硬编码,未取 Loop MCU 真实线圈状态 → 平台看到的线圈健康度是假的 | 🔴 高 | | `net_srv.c:528` | MQTT 接收长度未做溢出防护(`len-received` 越界风险)| 🔴 高 | | `storage.c:494`(DBN) | Flash_Model 读失败无停机/降级保护 | 中 | | `net_srv.c:1225` | 序列号修改命令未实现 | 中 | | `dbn_ble_srv.c:870` | ACS timeout `min→ms` 换算待确认(当前 ×60×100,疑似按 10ms tick,需对时钟源) | 中 | | `main.c`(Loop)多处 | "不整个设备复位,只复位蓝牙以外部分"——历史注释,评估后关闭或立项 | 低 | ### P0.3 回归验证清单(配合 vd_test_fixture 工装) - [ ] 长车双线圈场景复测:car_leave 事件后**下一条** loop_data 的 iscar 必须已翻 false(同源验证) - [ ] event_report 断网入队 → 重连补报闭环;5s 超时重发 ×3 后的放弃行为 - [ ] 时钟同步:校准前 ts=上电秒数的平台侧兼容;mstick 49.7 天回绕仿真(gcc 隔离单测) - [ ] MQTT 稳定性:>512B 帧、PINGREQ 保活、broker 主动踢线后的重连节奏 - [ ] 拨码/灵敏度/hold_time/relay_delay 全参数配置读写一致性(BLE 链路 + MQTT 链路交叉验证) **P0 出口条件**:以上全绿 → 两侧 `FIRMWARE_VER` 升 1.1 → 整机 tag v1.1.0。 --- ## P1 — 传感数据上云闭环(目标 V1.2.x,约 1~2 月,与 edc_server 平台侧并行) 这是你"传感数据云 + 业务平台"目标的主线,设备侧固件已基本就绪,重心在平台侧消费。 ### P1.1 平台侧对接(edc_server) - **event_report 消费契约**:平台先落库、后 ACK(code=0)——严禁先 ACK 后落库(设备出队后事件不可再生) - **loop_data 落库 + 可视化**:variation 有符号曲线(正=车/裕量,负=基线污染——免费的诊断维度)、频率漂移趋势图;锯齿波形态识别(5s 基线阶跃是正常形态,别当故障) - **流量/占用 API**:基于 car_enter/car_leave 事件 + 通过时间/车间距(50ms 单位)产出分通道流量计数、占用率、平均通过时间 - **设备台账**:initialize 上线登记、心跳离线判定(阈值=心跳间隔×3)、report_config 远程下发界面 ### P1.2 脱机日志子系统 🆕(W25Qxx SPI NOR) **硬件底子**:DBN 外挂 SPI NOR(SPI1)。默认 **W25Q32(32Mbit = 4MB,已确认)**;**兼容 W25Q64 / W25Q128 / W25Q256**,上电先读 JEDEC ID 识别存储类型,再按类型映射各分区容量。 **分区规划(顺序:参数区 → OTA 镜像暂存区 → 事件日志区 → 传感快照区)**: | 分区 | 容量策略 | 用途 | |------|---------|------| | 参数区 | **固定 64KB**(0x000000 起,现用 <1KB) | 现有配置,留余量 | | OTA 镜像暂存区 | **固定 512KB** | Loop 固件(64KB×2 版本回滚)+ 预留 DBN 镜像 | | 事件日志区 | **随存储类型**(见下表) | 环形,关键事件流,不被快照冲掉 | | 传感快照区 | **随存储类型**(= 总容量 − 参数区 − OTA − 事件日志区) | 环形,0xC0 帧原样落盘 | **存储类型 ↔ 容量映射表**(上电读 JEDEC ID 后选档): | JEDEC ID | 芯片 | 总容量 | 参数区 | OTA 暂存 | 事件日志区 | 传感快照区 | |----------|------|--------|--------|----------|-----------|-----------| | EF 40 16 | W25Q32(默认) | 4MB | 64KB | 512KB | **512KB**(~16000 条) | **~2.94MB** | | EF 40 17 | W25Q64 | 8MB | 64KB | 512KB | **1MB**(~32000 条) | **~6.44MB** | | EF 40 18 | W25Q128 | 16MB | 64KB | 512KB | **2MB**(~64000 条) | **~13.44MB** | | EF 40 19 | W25Q256 | 32MB | 64KB | 512KB | **4MB**(~128000 条) | **~27.44MB** | - 事件日志区容量随芯片**等比翻倍**(512KB→4MB),保证日志保留时长不随硬件降配而缩水 - 传感快照区吃剩余容量;**W25Q32(4MB)为最小可部署配置** - 分区边界在**上电初始化时**由 JEDEC ID 计算得出,offlog/快照代码按运行时分区表寻址,不写死 **两条日志流分开存**: 1. **事件流(必录,低速率)**:car_enter/car_leave(含时间量)、线圈断线/恢复、继电器动作、上电/复位(含复位原因)、MQTT/TCP 连接与断开、event_report ACK 超时/重发/放弃、配置变更(含来源:BLE/MQTT/TCP)、灵敏度换档、**时钟同步锚点**、固件升级开始/结果、日志清除操作(审计自记录)——**已实现(offlog)** 2. **快照流(环形可覆盖)**:0xC0 帧 4 线圈数据原样(12B/线圈)+ 头部(序号/boot_seq/mstick),64B/条,**记录节奏与上报同频**——直接挂在 `iot_sensor_ingest()` 同源出口。**已实现(snapshot,2026-08-12)**:中断只入 RAM 暂存(8 深满丢新),主循环 flush 落盘;BLE 新增 SNAP_STAT/QUERY/CLEAR(0x28/0x29/0x2A) **容量预算**(**以 W25Q32 为基准**:事件日志 512KB ≈ 16384 条 / 快照区 3008KB ≈ **4.8 万条** @64B): | 场景 | 落盘节奏 | 保留时长(W25Q32) | |------|---------|---------| | 最坏情况:快档 300ms 连续压满 | 3.3 条/s | **~4.0 小时** | | 繁忙出入口(日均 2000 车次,每车次 ~15 条突发 + 空闲 30s 底噪) | ~3.25 万条/天 | **~1.5 天** | | 一般车道(空闲 30s 为主) | ~2900 条/天 | **~16.7 天** | **各芯片快照保留时长对比**(同一落盘节奏下): | 芯片 | 快照区 | 快照条数 | 最坏 300ms 压满 | 繁忙出入口 | 一般车道 | |------|--------|----------|----------------|-----------|---------| | W25Q32(默认) | 3008KB | 48128 | ~4.0 小时 | ~1.5 天 | ~16.7 天 | | W25Q64 | 6592KB | 105472 | ~8.8 小时 | ~3.2 天 | ~36.6 天 | | W25Q128 | 13760KB | 220160 | ~18.3 小时 | ~6.8 天 | ~76.4 天 | | W25Q256 | 28096KB | 449536 | ~37.5 小时 | ~13.8 天 | ~156 天 | > 事件日志区独立于快照:512KB→4MB(16384→131072 条 @32B),**不受快照覆盖影响**。 若现场要求更长保留:把空闲档快照落盘间隔与上报解耦(如落盘固定 60s),或快照只存"有沿事件前后 ±N 条"(预触发环形),容量立刻翻数倍——**实施时按现场需求选**。 **⚠ 无 RTC 的时间戳设计(最容易踩的坑)**:断电后 mstick 归零,纯 Unix 时间戳不可行。方案:每条记录带 `(boot_seq, mstick)`;每次时钟同步成功时写一条**时间锚点事件**(boot_seq ↔ unix_ts 映射);导出时由平台/小程序用锚点回算绝对时间。从未同步过的 boot 段只有相对时间——协议文档里要写明这个语义。 **磨损与 RAM**:环形顺序写天然磨损均衡(4KB sector 顺序擦除,W25Q 10 万次擦写寿命无忧);**复用现有 `SPI_FLASH_BUF[4096]`,不新增大缓冲**(CH32V208 SRAM 紧张的教训)。 ### P1.3 日志导出与管理 🆕 **导出通道(三条,统一按序号分页,不按时间——时间不可靠)**: | 通道 | 机制 | 说明 | |------|------|------| | MQTT 自动补报 | 断网期间事件流落盘,重连后按序号续传 | 现有 16 深 RAM 队列扩展为 flash-backed,溢出转日志区;与 event_report ACK 闭环衔接 | | MQTT/TCP 命令拉取 | `log_query {stream, start_seq, count}` 分页 | 复用现有 cmd 分发框架;注意 Publish≤500B 分批(MSS=576 教训) | | BLE 小程序读取 | 复用 0x8F 通道新增日志读命令 | BLE MTU 分包(20~244B),小程序侧分页 UI | **管理命令**: - `log_stat`:各流的序号区间、条数、容量占用 - `log_clear {stream}`:**需鉴权**;分流清除;清除动作本身写入事件流(审计——谁在什么时候清了日志) - 自动管理:环形覆盖为常态,无需人工干预;满不停写 ### P1.4 远程 OTA 🆕(路线已定:先走现网 MQTT,底层复用 ISP 透传) **关键认知**:BLE 给 Loop MCU 升级 = "镜像经手机流式送到 CH32V208 → ISP 串口透传刷写"。远程 OTA 只是把"送镜像"的传输层从 BLE 换成 MQTT,**ISP 透传底层完全复用**——且 Loop MCU 的 OTA 根本不需要 CH32V208 做 A/B 分区,镜像只是路过。 **分两档,难度和节奏完全不同:** **① Loop MCU (AT32F421) 远程 OTA —— v1.2.x 落地** 采用**先存后刷**(优于流式直透): 1. 平台 MQTT 分片下发(每片带 offset+CRC,≤500B/片,支持断点续传)→ 写入 W25Qxx 暂存区 2. 全镜像 CRC 校验通过后,才启动 ISP 透传本地刷写(复用 BLE OTA 的透传状态机) 3. 抗网络抖动:下载阶段断网无所谓,续传即可;刷写阶段纯本地,窗口短 4. 暂存区保留上一版镜像 → 支持回滚重刷 **安全底线(会车产品,升级失败=继电器行为不可控)**: - 升级窗口检查:有车压线圈时告警/延迟启动——**待定策略** - ISP 期间 Loop MCU 停止检测,继电器处于什么状态?(复位后 GPIO 默认态应为断开=常开安全侧,**待板上验证**) - 刷写失败自动重试 ×3,仍失败 → event_report 告警 + 保持 ISP 可重入(AT32 ISP bootloader 兜底,不会真砖) - 升级开始/结果写入事件日志 **② DBN (CH32V208) 自身远程 OTA —— 方案评审先行,落地后置** 难点:128KB Flash 装不下 APP 双分区;现有 BLE OTA 走 WCH "OnlyUpdateApp" IAP 框架(bootloader 固定只认 BLE)。候选路线: - (a) 镜像下到 W25Qxx 暂存 + 校验 → 改 bootloader 支持从外部 Flash 搬运(**动 bootloader 风险高**,刷坏只能拆壳烧录) - (b) RAM 驻留搬运代码自刷写(掉电=砖,不推荐) - (c) 维持现状:DBN 升级仍走 BLE(现场人员),只有 Loop 支持远程——**最稳妥的过渡态** 先出方案评审文档比选,v1.2.x 期间不阻塞 ①。 **③ 4G 通道下的 OTA**:4G 模组(TTL 对接 UART1)跑 MQTT 后,①②的分片下载协议原样复用——传输层无关是这套设计的出发点。注意 4G 流量成本:64KB 镜像 + 重传开销可忽略,但快照流补报要设流量上限。 ### P1.5 设备侧其他补强 - **loop_data 增补字段**(若 P1.1 分析需要):如 Origin 绝对值上报,便于平台重建基线轨迹——走协议 V1.06 流程,两侧同版本配套 - **DBNMQTTool** 同步:日志拉取/OTA 分片下发的模拟与断言(工具先行,固件后到) ### P1.6 4G 上云通道(UART1 RFU 启用,可后置到 P3) - 模组选型(Cat.1 足够:EC800 系列/Air780 级别),AT 透传 vs 模组内置 MQTT 两条路线对比 - 网口 MQTT 与 4G MQTT 复用同一 `iot_mqtt_srv` 状态机,仅换传输层——架构上先留接口 --- ## P2 — 检测算法深化(Loop 侧,目标 V2.x,约 2~3 月) ### P2.1 抗变频器/电磁干扰 🎯(你的长期主目标) 1. **先取证再动手**:用工装+现场采集受扰线圈的 CAPVD 原始序列(10ms 粒度),确认干扰形态(周期性拍频 / 白噪 / 突发脉冲)——**待现场验证** 2. **频点错开**:4 路线圈两级调频电容(33nF/10nF)已有硬件基础,上电自检各路振荡频率,间距不足时自动切档,抑制相邻串扰 3. **算法层**:现有 IIR+斜率限幅+进入确认对突发脉冲已有基础免疫;针对周期性拍频评估陷波/中值预滤(注意 10ms tick 下的计算预算) 4. 产出:抗干扰测试报告(干扰源型号、距离、频谱、误检率前后对比) ### P2.2 双线圈测速 + 车型粗分类 - 利用现有 misc 时间量(通过时间/车间距,50ms 单位)+ 已知线圈间距 → 速度估计 - 信号长度(占用时间×速度)→ 车长 → 粗分类(小车/大车/拖挂) - 拖挂车"半截车"识别:单通道内 variation 双峰形态检测——直接服务会车防砸 - 输出通道:event_report 新增 speed/class 字段(协议升版) ### P2.3 方向判别 - 线圈 1→2 与 2→1 的触发时序 → 方向语义,供会车/双向流量使用 - Loop 侧输出还是平台侧算:**倾向 Loop 侧**(时序精度 50ms 内,平台侧受上报调度抖动影响) --- ## P3 — 会车控制与融合(依赖 P1/P2 产出) - **会车控制逻辑平台侧先行**:基于多台 DLD960 的 event_report(有 ACK 闭环,可靠交付)做单通道红绿灯会车状态机;业务逻辑只认 event_report,loop_data 仅做展示——两通道职责不混 - **异常分支优先设计**:设备离线(心跳超时)→ 会车灯降级策略;继电器粘连检测(relay_count 与命令数比对);车辆长时间停留(hold_time 超时全通道重启的平台侧感知) - **单机版会车评估**:DLD960 四通道 + 继电器本地联动能否覆盖小型场景(无平台依赖,可靠性更高)——出对比方案:纯平台 / 纯单机 / 混合 - **雷达/相机融合接口预留**:扩展 UART1 或网口接入目标列表,融合仲裁放平台侧 --- ## 版本映射与节奏 | 版本 | 内容 | 前置 | |------|------|------| | v1.1.0 | P0 全部(BLE 收尾 + TODO 清剿 + 回归全绿) | — | | v1.2.x | P1 设备侧(脱机日志 + Loop 远程 OTA + 协议 V1.06) | edc_server 对接联调 | | v2.0.0 | P2 算法深化(抗干扰 + 测速分类 + 方向) | 现场干扰数据采集 | | v2.x | P3 会车控制 | P1 平台 + P2 方向判别 | ## 风险与待现场验证 | # | 风险 | 应对 | |---|------|------| | 1 | BLE 重构改动帧消费时序,复发"不同源"类 bug | P0.1 真值表 + 长车复测强制过 | | 2 | 变频器干扰形态未知,算法方案可能推倒重来 | 先采数据后设计,不拍脑袋 | | 3 | DBN 自身远程 OTA 无安全落点(128KB 无 A/B、bootloader 只认 BLE) | 过渡态:DBN 走 BLE、Loop 走远程;bootloader 改造单独评审 | | 4 | 协议再升版(V1.06)又是双侧死绑定 | 沿用 Len 字节区分格式的兼容方案,发布走配套矩阵 | | 5 | 无 RTC,脱机日志绝对时间不可靠 | boot_seq+mstick+时钟锚点回算;协议明示"未同步段仅相对时间" | | 6 | 日志高频写与 MQTT/BLE 共抢主循环与 SPI 总线 | 快照落盘按 page 缓写、擦除放空闲窗口;实测不达标就降快照档频率 |