协议依据:《DLD960_IoT_MQTT协议》V1.13(4G 通道适配方案 C) 新增模块: - frame_parser.lua: 0x7F 帧解析状态机(Lua 版 lup_feed_byte, XOR+SUM 校验) - proto_conv.lua: 0xC0 传感帧 → loop_data + car_state/loop_state 沿检测(4 类线圈事件) - evt_queue.lua: event_report 队列 + ACK 状态机(16深/5s×3/跨重连同 msg_id,对齐 DBN) - clock.lua: report_config 时钟校准(协议 §2.3) - app_iot.lua: initialize(extra_info imei/iccid + link)/ heartbeat / poll 驱动 - tools/sim_frame_test.py: 帧协议参考验证(56B 帧/4 路解析/沿检测/JSON 格式,全过) 改造: - uart_app.lua: 0x7D 帧 → 0x7F 帧驱动;loop_data/event_report 组包 + link 注入 - mqtt_receiver.lua: 下行分发(ACK 路由 + 时钟校准) - mqtt_main.lua: 连接成功 → initialize + 未决事件重发 - config.lua/main.lua: 方案 C 配置与入口 MVP 范围: 上行(initialize/loop_data/event_report/heartbeat)+ report_config; 下行命令转换与 0x7D 配置同步列入 P1。
15 KiB
15 KiB
vd960Air — Air8781P(Air780EPM) 4G 通信模块 LuatOS 工程
vd960DBN 车检器在有线网络失效时的 4G 兜底通道: UART <-> MQTT 桥。
1 系统架构
┌─────────────────┐ UART1 (115200) ┌──────────────────────┐ MQTT 3.1.1 ┌──────────┐
│ vd960DBN │ 帧协议(0x7D) │ Air8781P 整板 │ JSON │ 云平台 │
│ CH32V208 │ ◄───────────────► │ Air780EPM (LuatOS) │ ─────────────► │ dld960 │
│ (车检器通信MCU) │ PB6=TX / PB7=RX │ vd960Air 应用 │ dld960/{sn}/ │ 主题族 │
└─────────────────┘ └──────────────────────┘ {dev,srv} └──────────┘
▲ 原有有线通道(UART2→Loop + ETH/MQTT) 仍保留, 4G 为兜底
- 上行: vd960DBN 组 JSON 帧 → UART1 → 4G 校验/拆帧 → MQTT publish
dld960/{sn}/dev - 下行: 4G 订阅
dld960/{sn}/srv→ 收到 JSON → 组帧 → UART1 → vd960DBN - JSON 命令面与《DLD960_IoT_MQTT协议》V1.10 完全一致,平台侧无感
2 协议设计决策(4G 是否需要单独协议?)
结论: 要,但以"适配协议"形式——命令面复用、网络类裁剪、4G 特有扩展,不出第二套业务协议。
| 层面 | 决策 | 理由 |
|---|---|---|
| 上行 JSON(initialize/loop_data/event_report/heartbeat/响应) | 100% 复用主协议 | 平台按《DLD960_IoT_MQTT协议》统一收,有线/4G 双通道无差别 |
| 核心下行(report_config/pwd_verify/loop_param_/log_/ota_*/device_reset) | 复用,4G 做 UART 透传 | 4G 只做桥,命令由 vd960DBN 处理,平台命令面不变 |
| 网络配置类(ssc_net_set/query、iot_net_set/query、iot_topic_set/query) | 4G 通道不适用,返回 code=4 | 4G 接入网是运营商 SIM 网络,APN/主题由 4G 侧管,与 DBN 有线网络参数无关 |
| 4G 特有状态(SIM/信号/注册/IMEI/固件版本/链路状态) | 新增命令(4G 侧自答,不进 UART) | 平台需要区分"有线通/4G 通/都不通",4G 状态是兜底通道健康度关键 |
| 通道切换策略 | 新增 | 有线优先 / 4G 兜底 / 心跳超时切换,由 vd960DBN 侧决策(4G 上报自身可用性) |
落地方式: 并入《DLD960_IoT_MQTT协议》主协议(用户决策 2026-08-31),新增 "4G 通道适配"章节,标注:
- 不支持的命令清单(ssc_net_* / iot_net_* / iot_topic_* 等,4G 通道返回
code=4) - 新增 4G 特有命令(如
4g_status_query/link_status_report) - 4G 特有字段(link 对象): 上行 JSON 顶层附加
link字段,老平台忽略、新平台可管理 4G 通道 - UART 链路帧格式(本工程 §3)
- 与主协议共享的 JSON 结构,平台侧零改动
2.1 数据透传方案(方案 B,用户 2026-08-31 提出,列入 vd960DBN 计划)
核心思路: vd960DBN 做纯转发,不参与 4G 通道的 MQTT 协议解析。
上行: vd960Loop --0x7F帧(UART2)--> vd960DBN --原样转发(UART1)--> Air780 --MQTT--> 平台
下行: 平台 --MQTT--> Air780 --原样(UART1)--> vd960DBN --0x7F帧(UART2)--> vd960Loop
- 魔数分流(现成规则): UART1 收到
0x7F帧 → 转发 UART2(Loop);0x8F帧 → DBN 本地处理 - Air780 职责: 0x7F 帧解析状态机(Lua 版 lup_feed_byte,只切包不懂内容)+ MQTT 收发 + 帧封装
- vd960DBN 职责: UART2↔UART1 双向转发(复用 manage_dbn_ble_transparent 透传模式)
- 地感指令(0x7F 配置命令)下行零改造,协议原样
已定稿(用户决策 2026-08-31):
- ✅ 方案 B(原始帧透传)正式采用
- ✅ 4G 上报格式 = hex 封装(平台友好,参照 log_query records hex 风格)
- ✅ 0x7D 帧去留: 数据面走 0x7F 帧字节流透传(不需要 0x7D);0x7D 帧仅保留给"配置同步下发/握手"
待确认(影响定稿):
- 上行双通道策略: 默认 4G / 有线失效才走 4G / 双通道并存(呼应 §6 通道切换讨论)
2.1.1 hex 封装报文格式(协议更新说明 — 并入《DLD960_IoT_MQTT协议》4G 适配章节)
上行 frame_report(Air780 → 平台,每个 0x7F 帧一条):
{
"msg_id": 123,
"cmd": "frame_report",
"ts": 1719000000,
"data": { "frame": "7f00c0060102030405aabb" },
"link": { "imei": "860012345678901", "iccid": "89860012345678901234", "csq": 23, "net": "4G" }
}
data.frame: 0x7F 帧完整字节 hex(含魔数 0x7F/校验字节),小写- 平台按《DLD960Loop_串口通信协议》解析 frame 内容(0xC0 传感 / 0x0C 响应 / 事件等)
link: 4G 特有字段(§2.3),每条上行携带
下行 frame_cmd(平台 → Air780):
{
"msg_id": 456,
"cmd": "frame_cmd",
"ts": 1719000100,
"data": { "frame": "7f000809010203040506" }
}
data.frame: 0x7F 帧(→ vd960Loop 地感指令)或 0x8F 帧(→ vd960DBN 本地配置)hex- Air780 收到 → hex 解码 → 原始字节 → UART1 → vd960DBN 魔数分流(0x7F→UART2 / 0x8F→本地)
- 地感/设备响应仍经
frame_report上行
协议更新说明清单(并入主协议时逐条落实):
- 新增上行
frame_report+ 下行frame_cmd两个命令(4G 通道专用) - 平台双通道格式差异说明: 有线通道 = 标准 JSON 业务命令(loop_data/event_report);4G 通道 = frame_report/frame_cmd(hex 帧透传)——平台须按通道区分解析
- 4G 通道网络配置类命令不适用(ssc_net_* / iot_net_* / iot_topic_*,返回 code=4 或文档标注)
- 链路层: 数据面 0x7F 帧字节流;0x7D 帧仅 DBN↔Air780 配置同步/握手(§2.2)
- 平台侧新增《DLD960Loop_串口通信协议》解析依赖(hex → 帧)
与方案 A(JSON 桥)对比:
| 对比项 | 方案 A: JSON 桥(此前设计) | 方案 B: 原始帧透传(本次) |
|---|---|---|
| DBN 侧开发量 | 需 UART1 通道 + JSON 组包/解析 + MQTT 语义 | 纯转发,最小 |
| Air780 侧职责 | MQTT 壳 + JSON 透传 | 0x7F 帧切包 + MQTT + 封装 |
| 平台侧 | 收标准 JSON(与有线一致) | 收 0x7F 帧/hex 封装(需解析《DLD960Loop_串口通信协议》) |
| 地感指令下行 | 经 JSON 命令中转 | 原样透传,零改造 |
| 链路帧 | 0x7D 帧(2B LEN 装 JSON) | 0x7F 帧字节流(不需要 0x7D,或仅配置用) |
2.2 服务器参数配置链路(用户决策 2026-08-31,列入 vd960DBN 开发计划)
服务器参数(地址/端口/ClientID/账号密码/Topic)当前由小程序 BLE 蓝牙设置。 规划:
小程序 → BLE → vd960DBN(CH32V208) → UART1(0x7D 帧) → Air780 存储(LuatOS fskv/luadb)
- vd960DBN 更新版本(列入计划): 小程序设置服务器/topic 相关参数(BLE 0x13/0x15 等)时,同步经 UART1 组帧下发 Air780
- Air780 侧: 新增"配置下发"UART 命令处理——收到后更新本地配置存储;
config.lua值降级为出厂默认(运行时优先读存储) - 协议面: 在《DLD960_IoT_MQTT协议》4G 适配章节新增"配置同步下发"命令(方向 srv 语义,经 DBN 透传或 DBN 主动下发)
- 好处: 现场换 4G 模块/重新配对时,参数随 BLE 一次配好,不依赖 Air780 单独刷脚本
2.3 4G 特有字段: link 对象(用户决策 2026-08-31)
上行 JSON(initialize / loop_data / event_report / heartbeat / 命令响应)注入:
{
"msg_id": 1,
"cmd": "loop_data",
"ts": 1719000000,
"data": { "...": "主协议原样" },
"link": {
"imei": "860012345678901",
"iccid": "89860012345678901234",
"imsi": "460001234567890",
"msisdn": "",
"csq": 23,
"net": "4G"
}
}
| 字段 | 来源 | 说明 |
|---|---|---|
imei |
mobile.imei() | 4G 模块 IMEI,设备唯一标识 |
iccid |
mobile.iccid() | 流量卡卡号,物联网卡管理识别用(卡商未写入 → 空串) |
imsi |
mobile.imsi() | IMSI(部分卡返回空) |
msisdn |
mobile.msisdn() | 手机号(物联网卡通常拿不到 → 空串) |
csq |
mobile.csq() | 信号强度 0-31(31 最强,99/255 无信号) |
net |
固定 "4G" | 网络制式(预留扩展) |
- 实现:
link_info.lua采集 +uart_app.lua上行 json.decode → 注入link→ encode - JSON 解析失败时原样转发,不阻塞上行
- 开关:
config.luaCFG_LINK_ENABLE
3 UART 链路帧协议(设计稿 v0.2,校验已定稿)
帧 = [HEAD 0x7D] [LEN_H] [LEN_L] [PAYLOAD...] [XOR] [SUM]
- HEAD: 0x7D(避开 0x7F DBN↔Loop / 0x8F DBN 专有 / 0x9F OTA 已占用魔数)
- LEN: uint16 大端, PAYLOAD(JSON) 字节数, ≤2048
- XOR: XOR 校验,从 LEN_H 起到 PAYLOAD 末字节(不含 HEAD)
- SUM: 累加和校验,范围同上
- 双向对称
3.1 与 DBN↔Loop 0x7F 帧的对比(2026-08-31 代码核实)
vd960DBN 与地感 MCU 的串口逻辑(loop_uart_proto.c,UART2,0x7F 帧):
[7F][Addr][LEN(1B)][CMD][Value: LEN-1B][XOR][SUM]
状态机: IDLE(找0x7F) → HEADER → VALUE → CHECK → COMPLETE
接收: UART2 RX DMA(uart2_dma_poll) 批量喂 lup_feed_byte()
校验: XOR+SUM,从 Addr 起(不含 magic)
| 对比项 | DBN↔Loop (0x7F) | Air780↔DBN (0x7D 本工程) |
|---|---|---|
| LEN 字段 | 1B,Value 0~64B(协议明确上限) | 2B,≤2048B |
| 魔数 | 0x7F | 0x7D |
| 校验 | XOR + SUM(从 Addr 起) | XOR + SUM(从 LEN_H 起,用户决策 2026-08-31) |
| 状态机 | IDLE→HEADER→VALUE→CHECK | 同构(IDLE→HEAD→LEN→DATA→XOR→SUM) |
| 用途 | 命令-响应短帧 | JSON 报文流(loop_data 数百字节) |
- 为什么不用 0x7F 帧: LEN 1B 上限 64B,装不下 MQTT JSON
- 状态机同构 + 校验统一 → vd960DBN 侧 UART1 通道可直接复用
lup_feed_byte解析骨架 - ✅ 校验已定稿为 XOR+SUM(2026-08-31 用户确认),与 0x7F 完全一致
4 文件结构
vd960Air/
├── main.lua # 入口: 加载 config/看门狗/4G网卡/uart_app/app_iot/mqtt_main
├── config.lua # 配置: MQTT 服务器/序列号/主题/UART/上报节奏/link 开关
├── frame_parser.lua # ★ 0x7F 帧解析状态机(Lua 版 lup_feed_byte,IDLE→HEADER→VALUE→CHECK)
├── proto_conv.lua # ★ 0xC0 传感帧 → loop_data + car_state/loop_state 沿检测
├── evt_queue.lua # ★ event_report 队列 + ACK 状态机(16深/5s×3/跨重连同 msg_id)
├── clock.lua # 设备时钟: report_config 校准 → 真实 Unix 秒(协议 §2.3)
├── app_iot.lua # initialize(extra_info imei/iccid + link)/ heartbeat / poll 驱动
├── uart_app.lua # UART1 接收 → frame_parser → 上行 JSON 发布;ACK 路由
├── link_info.lua # 4G 链路信息采集(IMEI/ICCID/IMSI/MSISDN/CSQ)
├── netdrv_device.lua # 网卡: 仅 4G(官方 netdrv_4g)
├── network_watchdog.lua # 网络看门狗(官方原样)
├── tools/
│ └── sim_frame_test.py # 帧协议参考验证(Python 1:1 复刻解析公式,字节级断言)
└── mqtt/
├── mqtt_main.lua # MQTT 客户端(连接成功 → initialize + 未决事件重发)
├── mqtt_receiver.lua # 下行分发: event_report ACK 路由 + report_config 时钟校准
└── mqtt_sender.lua # 上行队列 + publish(官方改造)
5 vd960DBN 对接要点
- vd960DBN 串口1: CH32V208 PB6(PB6=TX?)、PB7(RX),TTL 电平
- 波特率: 115200(官方 demo 默认;vd960DBN UART1 预留口速率待确认)
- vd960DBN 侧需要新增: UART1 帧收发 + JSON 组包/解析的"4G 通道"适配(与现有 TCP/MQTT 双栈并列的第三通道,见《DLD960_IoT_MQTT协议》4G 适配章节)
- 8N1,无流控(帧协议自带长度+校验,无需硬件流控)
6 决策记录 & 待确认清单
已决策(用户 2026-08-31)
- 波特率: UART1 默认 115200,后续如需再调(config.lua)
- dev_serial: 采用与有线通道同一序列号(Topic 族一致,平台认同一台设备);config.lua 配置,部署时与 vd960DBN 保持一致
- 4G 特有字段: 上行注入
link对象(IMEI/ICCID/IMSI/MSISDN/CSQ),平台按 §2.3 解析 - 协议并入主协议: 4G 适配作为《DLD960_IoT_MQTT协议》章节,4G 特有部分(link 字段/不支持命令/4G 状态命令)单独标注
- 服务器参数配置链路: 当前由小程序 BLE 设置;vd960DBN 后续版本(列入计划)将 BLE 设置的服务器/topic 参数同步经 UART1 下发 Air780,Air780 存储更新配置(§2.2)
- 通道切换策略(暂定): 默认 4G 无线作为上报通道
- 方案 B(原始帧透传)采用 + 4G 上报格式 = hex 封装(frame_report/frame_cmd,§2.1.1;协议更新说明已列)
待讨论(通道切换策略,2026-08-31 用户提出)
- 动态自动切换 vs 人工设置: 有线通道失效时自动切 4G?还是由人工(拨码/小程序)指定通道?
- 动态自动: 需 vd960DBN 检测有线通断(MQTT/TCP 心跳超时)→ 切 4G;回切策略(有线恢复后自动回切?)
- 人工设置: 拨码/小程序固定通道,简单可控但现场需有人干预
- 影响面: vd960DBN 侧决策逻辑 + Air780 侧角色(常驻 4G 上报 vs 备用唤醒)+ 平台侧通道标识
- 待后续讨论定稿后更新本节
待确认(等开发文档/板级验证)
- vd960DBN UART1 帧格式是否按 §3 设计稿(0x7D 帧),或用户文档另有规定
- dev_serial 获取方式: config 写死 vs UART 握手动态下发(当前 config 写死)
- MQTT 服务器地址/端口/TLS、鉴权方式(平台为准)
- 4G 特有命令清单(如
4g_status_query/link_status_report)是否纳入主协议 4G 章节 - 通道切换策略: 有线失效判定、4G 启用条件、回切策略
- 心跳: 4G 通道 heartbeat 间隔/内容是否与有线一致
- OTA: 4G 通道是否需要支持 Loop/DBN OTA(4G 下行分片经 UART 转发可行性)
7 开发计划(基于官方 demo/mqtt 骨架)
| 阶段 | 内容 | 状态 |
|---|---|---|
| P0 | 工程骨架 + 帧协议 + MQTT 桥接 + link 注入 | ✅ 完成 |
| P0.5 | 方案 C MVP: 0x7F 帧解析 + 0xC0→loop_data + 沿检测→event_report + ACK 状态机 + initialize/heartbeat + 时钟校准(2026-08-31) | ✅ 代码完成,待板级 |
| P1 | 下行命令转换(loop_param_/log_/ota_* 转 0x7F)+ 0x7D 配置同步下发 + vd960DBN UART1 通道联调 | ⏳ 待板/待 vd960DBN 版本 |
| P2 | 板级联调: 帧校验、背压、掉线重连、看门狗 | ⏳ 待板 |
| P3 | 通道切换(策略待讨论)+ 脱机日志/OTA 走 4G | ⏳ 规划 |
vd960DBN 侧开发计划(2026-08-31 用户确认列入):
- UART1(PB6/PB7)通道: 帧收发 + 0x7F 帧魔数分流(0x7F → UART2 透传 / 0x8F → 本地)
- UART2↔UART1 双向透传(方案 B): Loop 传感数据(0xC0)转发 Air780;4G 下行地感指令转发 Loop(复用 manage_dbn_ble_transparent 模式)
- BLE 设置服务器/topic 参数时(0x13/0x15 等),同步经 UART1 下发 Air780 配置
- 通道切换策略(待讨论: 动态自动 vs 人工设置;暂定默认 4G)
基底来源: 合宙官方 Air780EPM demo/mqtt(main.lua / uart_app.lua / mqtt/* / network_watchdog / netdrv_device),MIT 许可。