feat(DLPilot): M303/M304 SQ52205 电源实测协议对接(规则先行, 按钮后续排版)

This commit is contained in:
2026-09-18 00:41:09 +08:00
parent 9772a2bf83
commit 8e6107b490
5 changed files with 62 additions and 3 deletions
+39 -1
View File
@@ -7,7 +7,9 @@ DLPC3421 光机 RS485 控制链路(板上 GD32E230 作 RS485→I2C 网关)
响应语义/错误码/就绪门禁与实测帧示例):
物理层 RS485 半双工 115200 8N1(PC 经 USB-RS485 转换器接板, DE 由 MCU 硬件换向)
命令帧 D5 01 LEN <ASCII命令> CRC 01=板类型, LEN=命令字节数
响应帧 B5 TYPE LEN <payload> CRC payload 为 ASCII(ok / err:OL / okTL:246 ...)
响应帧 B5 TYPE LEN <payload> CRC payload 为 ASCII(ok / err:OL / okTL:246 ...),
例外: M303/M304 载荷为 2 字节大端二进制
(SQ52205 电源实测, 见 POWER_COMMANDS)
CRC 帧内第 2 字节(板类型)起累加到最后一个 payload 字节, 取低 8 位
帧长 最小 6 字节, 最大 32 字节
就绪门禁: DLPC3421 启动完成前 M730/M731/M732 被拒(回 0xFF), 属预期。
@@ -81,6 +83,42 @@ PRESETS = (
Frame = collections.namedtuple('Frame', 'type_code payload raw')
# --- M303/M304(SQ52205 电源实测值查询): 成功载荷为 2 字节原始二进制(非 ASCII) ---
# M303 母线电压: u16 大端, 单位 mV; 12V 轨正常窗口 11400~12600(标称 ±5%)
# M304 负载电流: s16 大端补码, 单位 mA; 正=正向, 负=反向(固件原样上总线,
# 上位机必须按有符号解析)。例: 载荷 FF 06 = -250 mA
# 错误时 TYPE=0xFF, 载荷为错误信息字节串(走通用译码路径)
POWER_COMMANDS = ('M303', 'M304')
def payload_bytes(fr):
"""响应帧的原始载荷字节(Frame.payload 是 ASCII 解码视图, 二进制载荷请用本函数)"""
return fr.raw[3:-1]
def payload_u16_be(raw):
return (raw[0] << 8) | raw[1]
def payload_s16_be(raw):
v = payload_u16_be(raw)
return v - 0x10000 if v & 0x8000 else v
def format_power(cmd, fr):
"""M303/M304 成功应答 -> 人读文本; 非 POWER 命令/失败/载荷异常返回 None"""
if cmd not in POWER_COMMANDS:
return None
raw = payload_bytes(fr)
if fr.type_code != 0xF0 or len(raw) != 2:
return None
if cmd == 'M303':
mv = payload_u16_be(raw)
return f'{mv} mV ({mv / 1000:.2f} V)'
ma = payload_s16_be(raw)
return f'{ma:+d} mA'
def sum_crc(data):
"""帧内第 2 字节(板类型)起累加到末 payload 字节, 取低 8 位(不含包头与 CRC)"""
return sum(data) & 0xFF
+14
View File
@@ -73,5 +73,19 @@ for _name, cmd, _note in d.PRESETS:
d.build_frame(cmd)
print(f'预设 {len(d.PRESETS)} 条全部可组帧: PASS')
# 8) M303/M304(SQ52205 电源实测)回归向量: 上游真机抓取帧
check('build_frame(M303)', d.build_frame('M303').hex(' ').upper(),
'D5 01 04 4D 33 30 33 E8')
check('build_frame(M304)', d.build_frame('M304').hex(' ').upper(),
'D5 01 04 4D 33 30 34 E9')
frames = d.FrameParser().feed(bytes.fromhex('B5 F0 02 2E F4 14'))
check('M303 应答帧', len(frames), 1)
check('M303 电压(0x2EF4=12020mV)', d.format_power('M303', frames[0]),
'12020 mV (12.02 V)')
frames = d.FrameParser().feed(bytes.fromhex('B5 F0 02 00 34 26'))
check('M304 应答帧', len(frames), 1)
check('M304 电流(0x0034=+52mA)', d.format_power('M304', frames[0]), '+52 mA')
check('M304 负值(FF06=-250mA 补码)', d.payload_s16_be(bytes.fromhex('FF 06')), -250)
print('RESULT:', 'FAIL:' + ','.join(fails) if fails else 'ALL PASS')
sys.exit(1 if fails else 0)