#!/usr/bin/env python3 """Ch340 byte-exact parser gate. Regenerates the synthetic fixture and asserts gs_parse decodes it into the EXACT expected normalized event stream (container header + every GIF mode). No board, no real dump needed. Exit non-zero on any mismatch.""" import os, sys, subprocess HERE = os.path.dirname(__file__) sys.path.insert(0, HERE) import gs_parse def main(): subprocess.run([sys.executable, os.path.join(HERE, "gs_make_synthetic.py")], check=True) fix = os.path.join(HERE, "..", "captures", "gs", "synthetic", "mini.gs") h, ev = gs_parse.parse_dump(fix) fail = 0 def check(cond, msg): nonlocal fail print((" ok " if cond else " FAIL ") + msg) if not cond: fail = 1 check(h.serial == "SYNTH001", f"serial == SYNTH001 (got {h.serial!r})") check(h.crc == 0x12345678, f"crc == 0x12345678 (got 0x{h.crc:08x})") check(h.state_size == 16, f"state_size == 16 (got {h.state_size})") # The expected ordered (kind, reg, value) skeleton of the event stream. got = [(e.kind, e.reg, e.value) for e in ev] exp = [ ("TRANSFER","",0), ("GIFTAG","",0), ("GSREG","FRAME_1",0x0000_0000_0C00_1807), ("TRANSFER","",0), ("GIFTAG","",0), ("GSREG","PRIM", 3 | (1<<4) | (1<<6)), # via PRE ("GSREG","RGBAQ", 0xFF | (0<<8) | (0<<16) | (0x80<<24)), # vtx0 red ("GSREG","XYZ2", (100<<4) | ((50<<4)<<16) | (0x5000<<32)), ("GSREG","RGBAQ", 0x00 | (0xFF<<8) | (0<<16) | (0x80<<24)),# vtx1 green ("GSREG","XYZ2", (200<<4) | ((50<<4)<<16) | (0x5000<<32)), ("GSREG","RGBAQ", 0x00 | (0<<8) | (0xFF<<16) | (0x80<<24)),# vtx2 blue ("GSREG","XYZ2", (100<<4) | ((150<<4)<<16) | (0x5000<<32)), ("TRANSFER","",0), ("GIFTAG","",0), ("IMAGE","",0), ("FRAME_BOUNDARY","",0), ] check(len(got)==len(exp), f"event count == {len(exp)} (got {len(got)})") for i,(g,e) in enumerate(zip(got,exp)): # compare kind always; reg+value only where the expected has them if e[0] in ("GSREG",): check(g==e, f"event[{i}] {e} (got {g})") else: check(g[0]==e[0], f"event[{i}] kind {e[0]} (got {g[0]})") # IMAGE qwc + no malformed img=[e for e in ev if e.kind=="IMAGE"] check(len(img)==1 and img[0].info.get("qwc")==2, f"one IMAGE qwc==2 (got {[e.info for e in img]})") check(all(e.kind!="MALFORMED" for e in ev), "no MALFORMED events") # Ch342 — PACKED ST must expose the STQ Q lane as info["q_stq"] (don't drop RGBAQ.Q). h2, ev2 = gs_parse.parse_dump(os.path.join(HERE, "..", "captures", "gs", "synthetic", "mini_st.gs")) sts = [e for e in ev2 if e.kind=="GSREG" and e.reg=="ST"] check(len(sts)==1, f"mini_st: one ST event (got {len(sts)})") if sts: e=sts[0] check((e.value & 0xFFFFFFFF)==0x11111111, "mini_st: ST.S == 0x11111111") check(((e.value>>32)&0xFFFFFFFF)==0x22222222, "mini_st: ST.T == 0x22222222") check(e.info.get("q_stq")==0x33333333, f"mini_st: q_stq == 0x33333333 (got {e.info.get('q_stq')})") print("RESULT:", "PASS" if not fail else "FAIL") return fail if __name__ == "__main__": sys.exit(main())