Files
n_signer/firmware/teensy41/pq_one.py
T

88 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Test a single PQ verb on a fresh boot.
Usage:
python3 firmware/teensy41/pq_one.py <method> '<json params>'
Opens /dev/ttyACM0, drains boot output, sends ONE request, prints the
response (or timeout). Exit 0 if "result" present, 1 otherwise.
"""
import serial, struct, json, time, sys, argparse
DEFAULT_PORT = "/dev/ttyACM0"
BAUD = 115200
def send_request(ser, req):
payload = json.dumps(req).encode("utf-8")
ser.write(struct.pack(">I", len(payload)) + payload)
ser.flush()
h = b""
deadline = time.time() + 180.0
while len(h) < 4 and time.time() < deadline:
c = ser.read(4 - len(h))
if c:
h += c
else:
time.sleep(0.01)
if len(h) < 4:
raise TimeoutError("hdr timeout (no response in 60s)")
n = struct.unpack(">I", h)[0]
if n == 0 or n > 65536:
raise ValueError("bad len %d" % n)
p = b""
while len(p) < n:
c = ser.read(n - len(p))
if c:
p += c
else:
time.sleep(0.01)
return json.loads(p.decode())
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--port", default=DEFAULT_PORT)
ap.add_argument("method")
ap.add_argument("params", help="JSON array of params")
args = ap.parse_args()
params = json.loads(args.params)
ser = serial.Serial(args.port, BAUD, timeout=2.0)
# drain boot
time.sleep(6)
boot = b""
while ser.in_waiting:
boot += ser.read(ser.in_waiting)
if boot:
print("=== BOOT OUTPUT ===")
print(boot.decode("utf-8", errors="replace"))
print("=== END BOOT ===")
req = {"jsonrpc": "2.0", "id": 1, "method": args.method, "params": params}
print(f"-> {args.method} {json.dumps(params)}", flush=True)
try:
resp = send_request(ser, req)
except Exception as e:
print(f"!! CRASH/TIMEOUT: {e}", flush=True)
# try to read any trailing output
time.sleep(1)
tail = b""
while ser.in_waiting:
tail += ser.read(ser.in_waiting)
if tail:
print("=== TAIL OUTPUT ===")
print(tail.decode("utf-8", errors="replace"))
print("=== END TAIL ===")
ser.close()
return 2
ok = "result" in resp
print(f"<- {'OK' if ok else 'ERR'} {json.dumps(resp)[:400]}", flush=True)
ser.close()
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())