DF-5725 / drive_ddb.py
#!/usr/bin/env python3 """DF-5725/5726/5727 — scripted driver for the guest's socket-backed serial console (verbatim mechanism of the proven DF-5721 rig). One persistent connection; lines sent in <=8-byte chunks with pacing (guest UART RX FIFO is 16 bytes). All console output is additionally captured by the chardev logfile (see serial_vm.sh BOOTLOG); this driver's drain log is the fine-grained session transcript. Session commands are supplied on the command line: drive_ddb.py "cmd1" wait1 "cmd2" wait2 ... Format: alternating command string, wait seconds (float). """ import os, socket, sys, threading, time SOCK = os.environ.get("DF5725_SOCK", "/tmp/opencode/df-5725-ser.sock") DRAIN = os.environ.get("DF5725_DRAIN", "/tmp/opencode/df-5725-drain.log") def connect(): while True: try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.connect(SOCK) return s except (FileNotFoundError, ConnectionRefusedError) as e: print(f"connect failed: {e}; retrying...", flush=True) time.sleep(2) _drained = threading.Event() def drainer(s): with open(DRAIN, "ab", buffering=0) as d: _drained.set() while True: try: b = s.recv(65536) except OSError: return if not b: return d.write(b) def send_line(s, line): data = (line if line.endswith("\n") else line + "\n").encode() for i in range(0, len(data), 8): s.sendall(data[i:i+8]) time.sleep(0.15) def main(): args = sys.argv[1:] if not args or len(args) % 2 != 0: print("usage: drive_ddb.py \"cmd\" wait \"cmd\" wait ...", file=sys.stderr) return 2 s = connect() t = threading.Thread(target=drainer, args=(s,), daemon=True) t.start(); _drained.wait() print("connected; drain ->", DRAIN, flush=True) time.sleep(2) for i in range(0, len(args), 2): cmd, wait = args[i], float(args[i+1]) print(f">>> {cmd} (wait {wait}s)", flush=True) send_line(s, cmd) time.sleep(wait) print("session script complete", flush=True) time.sleep(2) return 0 if __name__ == "__main__": sys.exit(main()) |