协议依据:《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。
126 lines
3.2 KiB
Lua
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
|