feat: 工装配置功能 — 新增 0x4A~0x4E 协议解析、tb_fixture_param/tb_vechicle_base_test 表、SerialNet 响应匹配

- dg430.py: 新增 parse_4a_version, parse_flag_response, parse_4c_params, get_packet_cmd
- handlers.py: parse_loop 增加 0x4C/非B2 指令处理,0x4C 响应自动更新 tb_fixture_param
- handlers.py: 测试指令(B0/B1/BA/BB/BC)Flag 不匹配 serialnet,仅 B2 标记完成
- handlers.py: 新增 serialnet_response_loop 处理 dat_type=9
- models.py: 新增 tb_fixture_param + tb_vechicle_base_test 表 DDL + CRUD
- server.py: 注册 serialnet_response_loop
This commit is contained in:
wangfq
2026-05-29 17:25:54 +08:00
parent 43fd3e7be9
commit e7c20c69d2
4 changed files with 482 additions and 48 deletions

View File

@@ -57,6 +57,11 @@ def _le16(data: bytes, offset: int) -> int:
return data[offset] | (data[offset + 1] << 8)
def _be16(data: bytes, offset: int) -> int:
"""大端 2 字节 → int"""
return (data[offset] << 8) | data[offset + 1]
def verify_packet(data: bytes) -> bool:
"""校验数据包完整性"""
if len(data) < PKT_MIN_LEN:
@@ -217,3 +222,125 @@ def decode_relay_info(relay: int) -> str:
if relay & (1 << bit):
items.append(desc)
return "; ".join(items) if items else "无输出"
# ─── 0x4A 获取设备版本号响应 ──────────────────────────────────────
@dataclass
class DG430Version:
addr: int
hw_major: int
hw_minor: int
hw_patch: int
sw_major: int
sw_minor: int
sw_patch: int
def parse_4a_version(data: bytes) -> DG430Version | None:
"""解析 0x4A 版本号响应
格式: 7F | ADDR | 08 | 4A | 00 | HW(3B) | SW(3B) | XOR | SUM
"""
if not verify_packet(data):
return None
cmd = data[3]
if cmd != 0x4A:
return None
payload = data[4:3 + data[2]]
if len(payload) < 7:
return None
addr = data[1] & 0x7F
return DG430Version(
addr=addr,
hw_major=payload[1],
hw_minor=payload[2],
hw_patch=payload[3],
sw_major=payload[4],
sw_minor=payload[5],
sw_patch=payload[6],
)
# ─── 通用 Flag 响应 (0x4B/0x4D/0x4E) ─────────────────────────────
def parse_flag_response(data: bytes, expected_cmd: int) -> int | None:
"""解析 Flag 响应格式: STX | ADDR | 02 | CMD | Flag | XOR | SUM
Returns:
Flag 值 (0=正常, 1=故障), 或 None 表示解析失败
"""
if not verify_packet(data):
return None
cmd = data[3]
if cmd != expected_cmd:
return None
if data[2] < 2:
return None
return data[4] # Flag
# ─── 0x4C 查询设备测试参数响应 ────────────────────────────────────
@dataclass
class DG430FixtureParams:
addr: int
flag: int # 0=正常, 1=故障
dev_addr: int # 设备地址
dev_type: int # 设备型号
test_mode: int # 0 灵敏度, 1 模拟过车
reset_dis: int # 复位距离 cm
minus_dis: int # 皮距 cm
sens_min: int # 灵敏度最小值
sens_max: int # 灵敏度最大值
fre_min: int # 频率最小值 Hz
fre_max: int # 频率最大值 Hz
peak_min: int # 峰峰值最小值
peak_max: int # 峰峰值最大值
def parse_4c_params(data: bytes) -> DG430FixtureParams | None:
"""解析 0x4C 查询测试参数响应
格式: 7F | ADDR | 13 | 4C | Flag | Addr | DevType | TestMode |
ResetDis | MinusDis | SensMin(2) | SensMax(2) |
FreMin(2) | FreMax(2) | PeakMin(2) | PeakMax(2) | XOR | SUM
"""
if not verify_packet(data):
return None
cmd = data[3]
if cmd != 0x4C:
return None
payload = data[4:3 + data[2]]
if len(payload) < 18:
return None
addr = data[1] & 0x7F
# 0x4B/0x4C 多字节字段为小端序
return DG430FixtureParams(
addr=addr,
flag=payload[0],
dev_addr=payload[1],
dev_type=payload[2],
test_mode=payload[3],
reset_dis=payload[4],
minus_dis=payload[5],
sens_min=_le16(payload, 6),
sens_max=_le16(payload, 8),
fre_min=_le16(payload, 10),
fre_max=_le16(payload, 12),
peak_min=_le16(payload, 14),
peak_max=_le16(payload, 16),
)
# ─── 获取数据包 CMD用于匹配────────────────────────────────────
def get_packet_cmd(data: bytes) -> int | None:
"""从数据包中提取 CMD 字节"""
if len(data) < 4:
return None
return data[3]