Files
mobile_comm/luatos/air780epm/module/Air780EPM/demo/vd960Air/frame_parser.lua
T
wangfq 3ad7ae8f09 feat(vd960Air): 方案 C MVP — 0x7F 帧解析 + 标准 JSON 上报(2026-08-31)
协议依据:《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。
2026-08-31 15:47:43 +08:00

126 lines
3.2 KiB
Lua

--[[
@module frame_parser
@summary 0x7F 帧解析状态机(Lua 版 lup_feed_byte)
@version 0.1
@date 2026.08.31
@usage
解析 vd960DBN 经 UART1 转发的 0x7F 帧(Loop 地感协议),只切包不懂内容:
- 帧格式: [7F][Addr][LEN][CMD][Value: LEN-1B][XOR][SUM]
- LEN = 1 + data_len(含 CMD 字节)
- 校验: XOR + SUM,从 Addr 起(不含 magic 0x7F),与 DBN↔Loop 完全一致
- 状态机: IDLE → HEADER(Addr/LEN/CMD) → VALUE(LEN-1B) → CHECK(XOR/SUM) → COMPLETE
- 完整帧通过回调 on_frame(cmd, payload) 交付;校验失败/超长帧回 IDLE 丢弃
用法:
local fp = require "frame_parser"
fp.init(function(cmd, payload)
-- cmd: 命令码(number)
-- payload: 除 CMD 外的数据字节(string, 可为空)
end)
-- UART 收到字节流逐字节喂入:
fp.feed(string.byte(s, i))
]]
local frame_parser = {}
-- 状态
local ST_IDLE, ST_ADDR, ST_LEN, ST_CMD, ST_VALUE, ST_CHECK_X, ST_CHECK_S =
0, 1, 2, 3, 4, 5, 6
-- 常量(与 DLD960Loop 协议一致)
local MAGIC_0x7F = 0x7F
local MAX_FRAME_VALUE = 64 -- 协议约定 Value 上限(防御)
local state = ST_IDLE
local cmd = 0
local value_len = 0 -- LEN - 1(除 CMD 外的数据字节数)
local value_buf = "" -- 数据缓冲
local chk_xor = 0 -- 从 Addr 起累计
local chk_sum = 0
local on_frame = nil -- 回调
local function reset()
state = ST_IDLE
cmd = 0
value_len = 0
value_buf = ""
chk_xor = 0
chk_sum = 0
end
-- 完整帧校验通过 → 回调
local function complete()
if on_frame then
on_frame(cmd, value_buf)
end
reset()
end
-- 逐字节喂入
function frame_parser.feed(b)
if state == ST_IDLE then
if b == MAGIC_0x7F then
state = ST_ADDR
end
elseif state == ST_ADDR then
chk_xor = b
chk_sum = b
state = ST_LEN
elseif state == ST_LEN then
chk_xor = chk_xor ~ b
chk_sum = (chk_sum + b) % 256
if b < 1 then
reset() -- LEN=0 非法
else
value_len = b - 1 -- 减 CMD 字节
if value_len > MAX_FRAME_VALUE then
reset() -- 超长帧丢弃
else
value_buf = ""
state = ST_CMD
end
end
elseif state == ST_CMD then
chk_xor = chk_xor ~ b
chk_sum = (chk_sum + b) % 256
cmd = b
if value_len == 0 then
state = ST_CHECK_X
else
state = ST_VALUE
end
elseif state == ST_VALUE then
chk_xor = chk_xor ~ b
chk_sum = (chk_sum + b) % 256
value_buf = value_buf .. string.char(b)
if value_buf:len() >= value_len then
state = ST_CHECK_X
end
elseif state == ST_CHECK_X then
if b ~= chk_xor then
reset()
else
state = ST_CHECK_S
end
elseif state == ST_CHECK_S then
if b == chk_sum then
complete()
else
reset()
end
end
end
-- 初始化回调
function frame_parser.init(cb)
on_frame = cb
reset()
end
-- 复位(链路异常/切换时调用)
function frame_parser.reset()
reset()
end
return frame_parser