#!/usr/bin/env python3 # -*- coding: utf-8 -*- """dlpc_rs485 协议自检(无硬件): 对照上游 protocols.md 的实测帧向量做回归 用法: python selftest_rs485.py (全部通过退出码 0) """ import sys import dlpc_rs485 as d fails = [] def check(name, got, want): ok = got == want print(('PASS' if ok else 'FAIL'), name, '->', got, '' if ok else f'(期望 {want})') if not ok: fails.append(name) # 1) 帧构造: protocols.md 实测示例 M730S0T2000 f = d.build_frame('M730S0T2000') check('build_frame(M730S0T2000)', f.hex(' ').upper(), 'D5 01 0B 4D 37 33 30 53 30 54 32 30 30 30 8C') # 2) 增量解析: ok 应答跨两个半包喂入 p = d.FrameParser() r1 = p.feed(bytes.fromhex('B5 F0')) r2 = p.feed(bytes.fromhex('02 6F 6B CC')) check('split-feed frames', len(r1) + len(r2), 1) fr = (r1 + r2)[0] check('type_code', fr.type_code, 0xF0) check('payload', fr.payload, 'ok') check('describe(ok)', d.describe(fr), 'ok') # 3) 前导噪声 + 0xFD err:OL 译码(字符串标记, 不附 DLPC 释义) body = bytes.fromhex('FD 06 65 72 72 3A 4F 4C') # "err:OL" good = bytes([0xB5]) + body + bytes([d.sum_crc(body)]) frames = d.FrameParser().feed(b'\x01\x02' + good) check('noise+err-frame count', len(frames), 1) check('describe(err:OL)', d.describe(frames[0]), '参数越界/读回复核不一致 err:OL') # 4) 0xFA + 数字错误码 err:3 追加 DLPC 释义 body = bytes.fromhex('FA 05') + b'err:3' fa = bytes([0xB5]) + body + bytes([d.sum_crc(body)]) frames = d.FrameParser().feed(fa) check('describe(err:3)', d.describe(frames[0]), '开光机通信失败 err:3(I2C NACK(器件无应答))') # 5) CRC 坏帧被丢弃后继续同步到下一帧 bad = bytearray(good) bad[-1] ^= 0xFF frames = d.FrameParser().feed(bytes(bad) + good) check('bad-crc then good', len(frames), 1) check('recovered type', frames[0].type_code, 0xFD) # 6) 非法输入拒绝 for bad_cmd in ('', ' '): try: d.build_frame(bad_cmd) fails.append('empty-cmd-not-rejected') except ValueError: pass try: d.build_frame('M' * 40) fails.append('long-cmd-not-rejected') except ValueError: pass print('空/超长命令拒绝: PASS') # 7) 预设命令全部可组帧 for _name, cmd, _note in d.PRESETS: d.build_frame(cmd) print(f'预设 {len(d.PRESETS)} 条全部可组帧: PASS') print('RESULT:', 'FAIL:' + ','.join(fails) if fails else 'ALL PASS') sys.exit(1 if fails else 0)