From 2d6c9f03ddaab2e985ab701ed02124b7e25e6b71 Mon Sep 17 00:00:00 2001 From: wangfq Date: Tue, 2 Jun 2026 18:06:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20DG430=20V2.0.3=20=E2=80=94=20=E6=B3=A2?= =?UTF-8?q?=E5=8A=A8=E6=B5=8B=E8=AF=95=E6=A8=A1=E5=BC=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dg430.py: 新增 DG430WaveStatus + parse_b4_wave_status() 0xB4解析 - dg430.py: 0x4C 扩展6字段(向后兼容旧版长度) - models.py: tb_fixture_param DDL + upsert 新增6个波动参数 - handlers.py: parse_loop 添加0xB4处理; 0x4C传参扩展 - TestMode=1 模拟过车→波动测试 (注释) --- src/dg430.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++--- src/handlers.py | 29 +++++++++++++++ src/models.py | 9 ++++- 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/src/dg430.py b/src/dg430.py index b3d7710..39dbe8b 100644 --- a/src/dg430.py +++ b/src/dg430.py @@ -19,7 +19,7 @@ class DG430Status: """解析后的 DG430 状态数据""" addr: int # 地址 dev_model: int # 1 PD132, 2 DLD110 - test_mode: int # 0 灵敏度, 1 模拟过车 + test_mode: int # 0 灵敏度, 1 波动测试 is_finished: bool # 是否正常完成 finish_code: int # 0 正常, 1 未完成, 2 地感死机 fault: int # bitmask @@ -150,7 +150,7 @@ def parse_b2_status(data: bytes) -> DG430Status | None: # 设备型号 dev_model = payload[0] # 1=PD132, 2=DLD110 - test_mode = payload[1] # 0=灵敏度, 1=模拟过车 + test_mode = payload[1] # 0=灵敏度, 1=波动测试 finish_code = payload[2] # 0=正常, 1=未完成, 2=死机 fault = payload[3] # bitmask relay_out = payload[4] # bitmask @@ -191,6 +191,70 @@ def parse_b2_status(data: bytes) -> DG430Status | None: ) +# ─── 0xB4 波动测试上报 ────────────────────────────────────────── + +@dataclass +class DG430WaveStatus: + """波动测试状态上报数据""" + addr: int # 地址 + remain_count: int # 剩余波动次数 + relay_out: int # 继电器输出 bitmask + work_freq: float # 工作频率 Hz + curr_dist: int # 当前距离 mm + speed: int # 当前速度 dm/s + near_dist: int # 波动最近距离 mm + far_dist: int # 波动最远距离 mm + enter_dist: int # 进入高度 mm + leave_dist: int # 离开高度 mm + + +def parse_b4_wave_status(data: bytes) -> DG430WaveStatus | None: + """解析 0xB4 波动测试状态上报包 + + 格式: STX | ADDR | 11 | B4 | DATA(16B) | XOR | SUM + DATA: RemainCount(1) | Relay(1) | WorkFreq(2 LE) | CurrDist(2 LE) | + Speed(2 LE) | NearDist(2 LE) | FarDist(2 LE) | + EnterDist(2 LE) | LeaveDist(2 LE) + """ + if not verify_packet(data): + logger.warning("DG430 B4 数据包校验失败") + return None + + cmd = data[3] + if cmd != 0xB4: + logger.debug(f"非 B4 指令: 0x{cmd:02X}") + return None + + payload = data[4:3 + data[2]] + if len(payload) < 16: + logger.warning(f"B4 数据长度不足: {len(payload)} < 16") + return None + + addr = data[1] & 0x7F + remain_count = payload[0] + relay_out = payload[1] + work_freq = _le16(payload, 2) * 10.0 + curr_dist = _le16(payload, 4) + speed = _le16(payload, 6) + near_dist = _le16(payload, 8) + far_dist = _le16(payload, 10) + enter_dist = _le16(payload, 12) + leave_dist = _le16(payload, 14) + + return DG430WaveStatus( + addr=addr, + remain_count=remain_count, + relay_out=relay_out, + work_freq=round(work_freq, 1), + curr_dist=curr_dist, + speed=speed, + near_dist=near_dist, + far_dist=far_dist, + enter_dist=enter_dist, + leave_dist=leave_dist, + ) + + # ─── 故障解码 ─────────────────────────────────────────────────────── FAULT_BITS = { @@ -290,7 +354,7 @@ class DG430FixtureParams: flag: int # 0=正常, 1=故障 dev_addr: int # 设备地址 dev_type: int # 设备型号 - test_mode: int # 0 灵敏度, 1 模拟过车 + test_mode: int # 0 灵敏度, 1 波动测试 reset_dis: int # 复位距离 cm minus_dis: int # 皮距 cm sens_min: int # 灵敏度最小值 @@ -299,14 +363,22 @@ class DG430FixtureParams: fre_max: int # 频率最大值 Hz peak_min: int # 峰峰值最小值 peak_max: int # 峰峰值最大值 + far_tol: int # 最远容差 cm + near_tol: int # 最近容差 cm + step_tol: int # 步进容差 cm + back_forth: int # 来回次数 + near_stay: int # 最近停留时间 ms + far_stay: int # 最远停留时间 ms def parse_4c_params(data: bytes) -> DG430FixtureParams | None: - """解析 0x4C 查询测试参数响应 + """解析 0x4C 查询测试参数响应 (V2.0.3 扩展) - 格式: 7F | ADDR | 13 | 4C | Flag | Addr | DevType | TestMode | + 格式: 7F | ADDR | 1B | 4C | Flag | Addr | DevType | TestMode | ResetDis | MinusDis | SensMin(2) | SensMax(2) | - FreMin(2) | FreMax(2) | PeakMin(2) | PeakMax(2) | XOR | SUM + FreMin(2) | FreMax(2) | PeakMin(2) | PeakMax(2) | + FarTol(1) | NearTol(1) | StepTol(1) | BackForth(1) | + NearStay(2) | FarStay(2) | XOR | SUM """ if not verify_packet(data): return None @@ -320,6 +392,14 @@ def parse_4c_params(data: bytes) -> DG430FixtureParams | None: addr = data[1] & 0x7F # 0x4B/0x4C 多字节字段为小端序 + # V2.0.3 新增6个波动参数字段,兼容旧版(长度不足时默认为0) + far_tol = payload[18] if len(payload) >= 19 else 0 + near_tol = payload[19] if len(payload) >= 20 else 0 + step_tol = payload[20] if len(payload) >= 21 else 0 + back_forth = payload[21] if len(payload) >= 22 else 0 + near_stay = _le16(payload, 22) if len(payload) >= 24 else 0 + far_stay = _le16(payload, 24) if len(payload) >= 26 else 0 + return DG430FixtureParams( addr=addr, flag=payload[0], @@ -334,6 +414,12 @@ def parse_4c_params(data: bytes) -> DG430FixtureParams | None: fre_max=_le16(payload, 12), peak_min=_le16(payload, 14), peak_max=_le16(payload, 16), + far_tol=far_tol, + near_tol=near_tol, + step_tol=step_tol, + back_forth=back_forth, + near_stay=near_stay, + far_stay=far_stay, ) diff --git a/src/handlers.py b/src/handlers.py index 152b028..dd07bcb 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -34,6 +34,7 @@ from src.dg430 import ( parse_4a_version, parse_flag_response, parse_4c_params, + parse_b4_wave_status, get_packet_cmd, hex_str_to_bytes, split_packets, @@ -322,6 +323,12 @@ async def parse_loop(): FreMax=params.fre_max, PeakMin=params.peak_min, PeakMax=params.peak_max, + FarTol=params.far_tol, + NearTol=params.near_tol, + StepTol=params.step_tol, + BackForth=params.back_forth, + NearStay=params.near_stay, + FarStay=params.far_stay, ) logger.info( f"0x4C 工装参数已更新 dnt_id={dnt_id} " @@ -332,6 +339,28 @@ async def parse_loop(): has_valid = True all_failed = False + # ── 0xB4 波动测试上报 ── + elif cmd == 0xB4: + if not verify_packet(pkt): + logger.debug(f"0xB4 数据包校验失败: {device_id}") + continue + + wave = parse_b4_wave_status(pkt) + if wave is None: + logger.warning(f"0xB4 解析失败: {device_id}") + continue + + relay_info = decode_relay_info(wave.relay_out) + logger.info( + f"B4波动上报: {device_id} 剩余={wave.remain_count} " + f"当前距离={wave.curr_dist}mm 速度={wave.speed}dm/s " + f"最近={wave.near_dist}mm 最远={wave.far_dist}mm " + f"进入={wave.enter_dist}mm 离开={wave.leave_dist}mm " + f"继电器={relay_info}" + ) + has_valid = True + all_failed = False + # ── 测试指令 Flag 响应(不匹配 serialnet,等待 B2 完成)── elif cmd in (0xB0, 0xB1, 0xBA, 0xBB, 0xBC): if not verify_packet(pkt): diff --git a/src/models.py b/src/models.py index 5e8bae8..ae5c08c 100644 --- a/src/models.py +++ b/src/models.py @@ -154,7 +154,7 @@ async def _create_tables(pool: aiomysql.Pool): `dnt_id` INT NOT NULL COMMENT 'FK → dnt_info.id', `Addr` TINYINT DEFAULT 1 COMMENT '工装设备地址', `DevType` TINYINT DEFAULT 0 COMMENT '被检设备型号类型编码', - `TestMode` TINYINT DEFAULT 0 COMMENT '0 灵敏度测试, 1 模拟过车', + `TestMode` TINYINT DEFAULT 0 COMMENT '0 灵敏度测试, 1 波动测试', `RestDis` INT DEFAULT 0 COMMENT '复位距离 cm', `MinusDis` INT DEFAULT 0 COMMENT '皮距/开始距离 cm', `SensMin` INT DEFAULT 0 COMMENT '灵敏度最小值', @@ -163,6 +163,12 @@ async def _create_tables(pool: aiomysql.Pool): `FreMax` INT DEFAULT 0 COMMENT '频率最大值 Hz', `PeakMin` INT DEFAULT 0 COMMENT '峰峰值最小值', `PeakMax` INT DEFAULT 0 COMMENT '峰峰值最大值', + `FarTol` INT DEFAULT 0 COMMENT '最远容差 cm (V2.0.3)', + `NearTol` INT DEFAULT 0 COMMENT '最近容差 cm (V2.0.3)', + `StepTol` INT DEFAULT 0 COMMENT '步进容差 cm (V2.0.3)', + `BackForth` INT DEFAULT 0 COMMENT '来回次数 (V2.0.3)', + `NearStay` INT DEFAULT 0 COMMENT '最近停留时间 ms (V2.0.3)', + `FarStay` INT DEFAULT 0 COMMENT '最远停留时间 ms (V2.0.3)', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE INDEX `idx_dnt_id` (`dnt_id`) @@ -479,6 +485,7 @@ async def upsert_fixture_param(dnt_id: int, **kwargs): fields = [ "Addr", "DevType", "TestMode", "RestDis", "MinusDis", "SensMin", "SensMax", "FreMin", "FreMax", "PeakMin", "PeakMax", + "FarTol", "NearTol", "StepTol", "BackForth", "NearStay", "FarStay", ] if existing: sets = ", ".join(f"`{f}`=%s" for f in fields)