diff --git a/README.md b/README.md index 53da223..0f79c33 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,26 @@ To start the current emulator harness: The real-device bench helper uses `pyserial`; install repo dependencies with `.\.venv\Scripts\python.exe -m pip install -r requirements.txt` if needed. +## Real Bench Serial Format + +The real RCP serial link is `38400 8E1`, not `38400 8N1`. This is backed by the ROM SCI1 init: + +- `build/rom_decompiled.asm:437`: `SCI1_SMR = H'24`, async 8-bit, even parity, 1 stop. +- `build/rom_decompiled.asm:438`: `SCI1_SCR = H'3C`, RX/TX enabled. +- `build/rom_decompiled.asm:439`: `SCI1_BRR = H'07`. + +The traced board path is H8/536 SCI1 through the MAX202: H8 pin 66 `P95/TXD` to MAX202 pin 11, and MAX202 pin 12 to H8 pin 67 `P96/RXD`. + +Bench scripts default to even parity now. Keep `--parity E` explicit in important captures, and use `--parity N` only to reproduce older 8N1 captures. With the wrong 8N1 format, commands fall into the RX error/retry path instead of the normal command handlers; apparent `07...` frames from those captures should be treated as error/retry echoes until repeated under 8E1. + +Confirmed bench result under 8E1: the CONNECT path can reach `CONNECT: OK`, the CAM POWER lamp illuminates, and the numeric readouts illuminate as `----`. + +Minimal smoke-test shape: + +```powershell +.\.venv\Scripts\python.exe scripts\bench_connect_lcd_sequence.py --port COM5 --relay-port COM6 --parity E --prompt-screen --log captures\8e1-connect-ok-smoke.txt +``` + ## What It Does - Decodes the H8/500 instruction set used by the H8/536. @@ -102,7 +122,7 @@ The real-device bench helper uses `pyserial`; install repo dependencies with `.\ - Generates a separate C-like pseudocode view from the JSON, preserving labels, calls, branches, register names, inferred symbols, metadata comments, optional cycle notes, and simple structured `if`/`do while` patterns. - Provides an early H8/536 emulator harness with ROM/RAM/register memory mapping, reset-vector boot, SCI1 transmit capture, MOV condition-code updates, `SCB/F`, stack/call/return support, indirect `JMP/JSR @Rn` dispatch, scaffolded SCI1 RXI/ERI/TXI and interval timer scheduling, manual-derived FRT1/FRT2 OCIA cycle scheduling, a P9 bit-banged bus model, an X24164 two-wire EEPROM model on traced `P91/SCL` and `P97/SDA`, logical EEPROM image load/save/reporting, a 16x4 LCD bus/DDRAM model for `H'F200`/`H'F201`, and an opt-in P9 transfer fast path. - Includes an emulator probe that reports hot PCs, recent P9/SCI accesses, serial report queue/gate traces, RAM lifecycle watches, final SCI1/TXI state, and captured P9 byte candidates while running the real ROM. -- Includes an RX command probe that boots until SCI1 RXI is serviceable, injects host six-byte frames through RDR/RDRF, can optionally schedule 38400 8N1 byte arrivals at real UART spacing, listens for device TX frames, and reports serial latch/table/LCD-buffer and emulated-LCD effects. +- Includes an RX command probe that boots until SCI1 RXI is serviceable, injects host six-byte frames through RDR/RDRF, can optionally schedule bench-style UART byte arrivals at real spacing, listens for device TX frames, and reports serial latch/table/LCD-buffer and emulated-LCD effects. - Includes a bench helper for replaying the emulator-derived CONNECT LCD frame sequence against the real device through COM5, with optional COM6 relay power cycling and timestamped capture logs. - Includes a bench ACK probe that reproduces the `01 00 00...` -> `01 00 01...` visible retry burst, waits for `07 80 40 20 90 2D`, then sends a candidate command-5 ACK and reports whether the target keeps repeating. - Includes a checksum-resynchronizing bench receiver that scans RX byte streams for valid six-byte frames, avoids common shifted-heartbeat false locks, and can fall back to the old fixed six-byte slicer with `--sync fixed`. @@ -121,6 +141,7 @@ Current serial observations: - Emulator timing finding: the ROM initializes FRT2 with `TCR=H'02` and `OCRA=H'7A12`; using the manual's `phi/32` prescaler gives a 1,000,000-cycle OCIA period, so the default `--clock-hz 10000000` models that tick as 100 ms and the post-send `F9C4=H'07` heartbeat delay as about 700 ms. - Runtime-confirmed heartbeat path: `loc_4067` writes `H'0000` into the queue via a zero-extended word move, `loc_BAF2/loc_BB08` dequeue it, `loc_BB1C/loc_BB20/loc_BB2B` stage the TX bytes, and `loc_BA26` emits `00 00 00 00 80 DA`. - Emulator LCD finding: the ROM writes the boot/no-active-session message to the LCD bus as ` CONNECT:NOT ACT` on line 0 by the time SCI1 RX is serviceable. Valid and invalid six-byte host frames leave that display active while normal serial replies/heartbeats continue. +- Bench serial-format finding: real hardware talks `38400 8E1`. Earlier `8N1` captures primarily exercised SCI1 parity/error handling and retry echoes, not the normal command path. After switching bench scripts to even parity, the selector-zero CONNECT path can reach `CONNECT: OK`. - Board/P9 finding: traced MCU pin 62 `P91` reaches X24164 pin 6 `SCL`, and MCU pin 68 `P97` reaches the shared X24164 pin 5 `SDA` node. The emulator now treats the ROM's `C121/C08B/C0DB/C10C/C142` P9 routines as an X24164-style two-wire EEPROM bus, with ROM logical addresses `0x000-0x7FF` on the `H'A0/H'A1` control-byte family and `0x800-0xFFF` on `H'E0/H'E1`. - EEPROM role finding: `loc_40BB` checks `P7DR.7` and the `F402 == H'6B6F` signature before defaulting EEPROM/shadow tables; `loc_4103` writes ROM default words through `BFE0`, `loc_41D2` reads sixteen 8-byte records into `F7B0-F82F`, and the command-4 path at `BD2B-BD5F` can persist serial table writes when `F76E.7` is set. - EEPROM layout finding: `build\rom_eeprom_layout.txt` currently identifies the ROM factory table at `H'C964-H'CA63`, the F400 shadow defaults, page 0 offset `0x000-0x007` as the signature/options header (`00 00 6B 6F FE 00 00 00`), pages 1-F offset `0x00-0x07` as blank-by-default record slots, and 89 selector mappings from the `H'C564` table into F400/EEPROM offsets. `F404` defaults to `H'FE00` and is tested as option/feature bits, while `F76E` combines persistence enable, dispatch suppression, and low-nibble EEPROM page selection. @@ -258,10 +279,10 @@ python h8536_emulator_rx_divergence.py --help - `--trace-report-gates`, `--trace-report-queue`, and `--trace-ram-lifecycle`: inspect the serial report queue, `loc_4046`/`F9C4` gate, and watched RAM byte history. - `--target-frame "00 00 00 00 80 DA"`: compare staged/emitted TX bytes against an expected six-byte frame. - `h8536_emulator_rx_probe.py "04 00 00 80 00"`: append the checksum, inject the host frame through SCI1 RX, and summarize responses. -- `h8536_emulator_rx_probe.py --uart-timing --uart-baud 38400 "04 00 00 80 00"`: inject all six host bytes with 8N1 wire spacing of about 260 us per byte, letting RXI/TXI/timers interleave; if the ROM has not cleared `RDRF` before the next byte, the SCI model raises `ORER`. +- `h8536_emulator_rx_probe.py --uart-timing --uart-baud 38400 "04 00 00 80 00"`: inject all six host bytes with bench-style wire spacing of about 260 us per byte, letting RXI/TXI/timers interleave; if the ROM has not cleared `RDRF` before the next byte, the SCI model raises `ORER`. The real bench link is `8E1`. - `h8536_emulator_rx_probe.py --preset connect-lcd`: replay the current CONNECT LCD activation candidates. - `h8536_emulator_rx_divergence.py --default-frames --uart-timing --wait-heartbeats 2 --summary-only`: run the focused RX divergence trace for the bench mismatch. It flags whether a frame reached cmd0 `BC69`, cmd1 `BCD7`, retry echo, command-7 replay, autonomous `BAF2` report output, or the TX/RX overlap-collapse path. -- `scripts\serial_table_dump.py --port COM5 --relay-port COM6 --start 0x000 --count 0x200 --log captures\table-read.txt`: read-only command-1 sweep of the firmware-exposed serial table state for EEPROM/shadow inference. +- `scripts\serial_table_dump.py --port COM5 --relay-port COM6 --start 0x000 --count 0x200 --log captures\table-read.txt`: read-only command-1 sweep of the firmware-exposed serial table state for EEPROM/shadow inference. Bench serial scripts default to `8E1` because the ROM initializes SCI1 as async 8-bit even parity, 1 stop; pass `--parity N` only when reproducing older 8N1 captures. - `scripts\serial_scenario.py scenarios\ack-race-000-001.json --log captures\ack-race-000-001.txt --result-json captures\ack-race-000-001-result.json`: run the focused `0x000 -> 0x001` retry probe with immediate reactive ACK and a 2 ms poll interval, to test whether command 5 can arrive before the second `07 80 40 20 90 2D` retry. - `scripts\serial_scenario.py scenarios\early-ack-000-001.json --log captures\early-ack-000-001.txt --result-json captures\early-ack-000-001-result.json`: send the same command-1 pair, then send command-5 ACK immediately without waiting for the retry frame. - `scripts\serial_scenario.py scenarios\table-sweep-ack-000-07f.json --log captures\table-sweep-ack-000-07f.txt --result-json captures\table-sweep-ack-000-07f-result.json`: run a repeatable bench scenario that sweeps selectors `0x000-0x07F` and sends `05 00 40 00 00 1F` only after `07 80 40 20 90 2D` appears. The checked-in scenario stops if it reaches 8 ACKs or 32 target hits. Use `--sync fixed` only when comparing against the old non-resyncing receiver. @@ -306,7 +327,7 @@ python h8536_emulator_rx_divergence.py --help - `h8536/ccu_seed_hints.py`: ROM miner for likely fake-CCU state seed selectors and candidate command/readback frames. - `h8536/eeprom_layout.py`: ROM miner for X24164 EEPROM defaults, 8-byte record slots, and serial persistence mapping. - `h8536/consistency.py`: decompiler/pseudocode semantic consistency checks. -- `h8536/emulator/`: early H8/536 emulator package split into CPU state, memory map, SCI1 TX capture, 38400 8N1 UART injection timing, P9/X24164 EEPROM bus model, LCD model, manual-derived FRT timer scheduling, runner, probe, CLI, and peripheral scaffolding. +- `h8536/emulator/`: early H8/536 emulator package split into CPU state, memory map, SCI1 TX capture, bench-style UART injection timing, P9/X24164 EEPROM bus model, LCD model, manual-derived FRT timer scheduling, runner, probe, CLI, and peripheral scaffolding. - `h8536/emulator/eeprom_image.py`: logical EEPROM image dump/report helpers for emulator runs, including factory diffs and record-slot summaries. - `h8536/emulator/rx_probe.py`: host-frame injection and response/listener probe for SCI1 RX experiments. - `h8536/emulator/state_search.py`: bounded internal-state search for CONNECT LCD outcomes using ROM execution plus explicit RAM/table patches. @@ -322,6 +343,6 @@ python h8536_emulator_rx_divergence.py --help - `h8536_emulator.py`, `h8536_emulator_probe.py`, `h8536_emulator_rx_probe.py`, `h8536_emulator_rx_divergence.py`, `h8536_emulator_bench_replay.py`: emulator CLI wrappers. - `h8536_emulator_state_search.py`: emulator CONNECT state-search CLI wrapper. - `scripts/bench_connect_lcd_sequence.py`: real-device COM5/COM6 bench runner for the CONNECT LCD sequence. -- `scripts/serial_table_dump.py`: read-only COM5/COM6 command-1 table sweep for inferring live EEPROM-backed parameter state. +- `scripts/serial_table_dump.py`: read-only COM5/COM6 command-1 table sweep for inferring live EEPROM-backed parameter state. Bench scripts default to `38400 8E1`. - `scripts/serial_scenario.py`: JSON-driven COM5/COM6 bench scenario runner for chained probes, waits, read sweeps, and ACK-on-target experiments. - `scripts/state_map_runner.py`: COM5/COM6 PT2 state-map proof runner and offline bench-log analyzer. diff --git a/h8536/bench_connect_lcd.py b/h8536/bench_connect_lcd.py index 4b9c252..0a9d4c4 100644 --- a/h8536/bench_connect_lcd.py +++ b/h8536/bench_connect_lcd.py @@ -12,6 +12,7 @@ from typing import Iterable, TextIO CHECKSUM_SEED = 0x5A FRAME_LENGTH = 6 +SERIAL_PARITY_CHOICES = ("N", "E", "O") CONNECT_LCD_SEQUENCE = ( bytes.fromhex("04000040001E"), @@ -202,6 +203,7 @@ def build_arg_parser() -> argparse.ArgumentParser: ) parser.add_argument("--port", default="COM5", help="RS232 serial port connected to the RCP") parser.add_argument("--baud", type=int, default=38400, help="RCP serial baud rate") + add_serial_format_args(parser) parser.add_argument("--relay-port", default="COM6", help="Pico relay serial port") parser.add_argument("--relay-baud", type=int, default=115200, help="Pico relay serial baud rate") parser.add_argument("--no-power-cycle", action="store_true", help="do not send relay off/on before the test") @@ -233,7 +235,7 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: log_path = args.log or default_log_path() if args.dry_run: - print(f"device={args.port} {args.baud} 8N1", file=stdout) + print(f"device={args.port} {args.baud} {serial_format_label(args)}", file=stdout) print(f"relay={args.relay_port} {args.relay_baud}", file=stdout) print(f"power_cycle={int(not args.no_power_cycle)} off={args.power_off_command!r} on={args.power_on_command!r}", file=stdout) for index, frame in enumerate(frames, start=1): @@ -248,12 +250,15 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: detector = FrameDetector(sync_mode=args.sync) try: logger.emit("CONNECT LCD bench sequence") - logger.emit(f"device={args.port} {args.baud} 8N1 relay={args.relay_port} {args.relay_baud}") + logger.emit( + f"device={args.port} {args.baud} {serial_format_label(args)} " + f"relay={args.relay_port} {args.relay_baud}" + ) logger.emit(f"log={log_path}") for index, frame in enumerate(frames, start=1): logger.emit(f"plan frame[{index}]={format_frame(frame)} checksum_ok={int(frame_checksum_ok(frame))}") - with serial.Serial(args.port, args.baud, bytesize=8, parity="N", stopbits=1, timeout=0.05) as device: + with open_device_serial(serial, args) as device: relay = None try: if not args.no_power_cycle: @@ -319,6 +324,23 @@ def _import_serial(): return serial +def add_serial_format_args(parser: argparse.ArgumentParser) -> None: + parser.add_argument( + "--parity", + choices=SERIAL_PARITY_CHOICES, + default="E", + help="serial parity for the RCP link; ROM SCI1 setup uses even parity", + ) + + +def serial_format_label(args: argparse.Namespace) -> str: + return f"8{args.parity}1" + + +def open_device_serial(serial, args: argparse.Namespace): + return serial.Serial(args.port, args.baud, bytesize=8, parity=args.parity, stopbits=1, timeout=0.05) + + def _send_frame(device, frame: bytes, logger: BenchLogger, label: str) -> None: device.write(frame) device.flush() diff --git a/h8536/serial_ack_probe.py b/h8536/serial_ack_probe.py index 4aac130..43b6be5 100644 --- a/h8536/serial_ack_probe.py +++ b/h8536/serial_ack_probe.py @@ -11,7 +11,9 @@ from typing import TextIO from .bench_connect_lcd import ( BenchLogger, FrameDetector, + add_serial_format_args, _import_serial, + open_device_serial, _read_for, _relay_command, _relay_settle, @@ -20,6 +22,7 @@ from .bench_connect_lcd import ( format_frame, frame_checksum_ok, parse_frame, + serial_format_label, ) @@ -42,6 +45,7 @@ def build_arg_parser() -> argparse.ArgumentParser: ) parser.add_argument("--port", default="COM5", help="RS232 serial port connected to the RCP") parser.add_argument("--baud", type=int, default=38400, help="RCP serial baud rate") + add_serial_format_args(parser) parser.add_argument("--relay-port", default="COM6", help="Pico relay serial port") parser.add_argument("--relay-baud", type=int, default=115200, help="Pico relay serial baud rate") parser.add_argument("--no-power-cycle", action="store_true", help="do not send relay off/on before the test") @@ -79,11 +83,14 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: detector = FrameDetector() try: logger.emit("Serial ACK probe") - logger.emit(f"device={args.port} {args.baud} 8N1 relay={args.relay_port} {args.relay_baud}") + logger.emit( + f"device={args.port} {args.baud} {serial_format_label(args)} " + f"relay={args.relay_port} {args.relay_baud}" + ) logger.emit(f"log={log_path}") _emit_plan(args, logger) - with serial.Serial(args.port, args.baud, bytesize=8, parity="N", stopbits=1, timeout=0.05) as device: + with open_device_serial(serial, args) as device: relay = None try: if not args.no_power_cycle: @@ -169,7 +176,7 @@ def _emit_plan(args: argparse.Namespace, logger: BenchLogger) -> None: def _print_plan(args: argparse.Namespace, log_path: Path, stdout: TextIO) -> None: - print(f"device={args.port} {args.baud} 8N1", file=stdout) + print(f"device={args.port} {args.baud} {serial_format_label(args)}", file=stdout) print(f"relay={args.relay_port} {args.relay_baud}", file=stdout) print(f"power_cycle={int(not args.no_power_cycle)}", file=stdout) print(f"prime={format_frame(args.prime_frame)} checksum_ok={int(frame_checksum_ok(args.prime_frame))}", file=stdout) diff --git a/h8536/serial_scenario.py b/h8536/serial_scenario.py index 85c1b05..25e146d 100644 --- a/h8536/serial_scenario.py +++ b/h8536/serial_scenario.py @@ -12,7 +12,9 @@ from typing import Any, TextIO from .bench_connect_lcd import ( BenchLogger, FrameDetector, + add_serial_format_args, _import_serial, + open_device_serial, _read_for, _relay_command, _relay_settle, @@ -21,6 +23,7 @@ from .bench_connect_lcd import ( format_frame, frame_checksum_ok, parse_frame, + serial_format_label, ) from .serial_table_dump import build_read_frame, decode_table_read_response @@ -56,6 +59,7 @@ def build_arg_parser() -> argparse.ArgumentParser: parser.add_argument("scenario", type=Path, help="JSON scenario file") parser.add_argument("--port", default="COM5", help="RS232 serial port connected to the RCP") parser.add_argument("--baud", type=int, default=38400, help="RCP serial baud rate") + add_serial_format_args(parser) parser.add_argument("--relay-port", default="COM6", help="Pico relay serial port") parser.add_argument("--relay-baud", type=int, default=115200, help="Pico relay serial baud rate") parser.add_argument("--no-power-cycle", action="store_true", help="skip power_cycle actions") @@ -84,9 +88,12 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: try: logger.emit("Serial bench scenario") logger.emit(f"name={scenario.get('name', args.scenario.stem)}") - logger.emit(f"device={args.port} {args.baud} 8N1 relay={args.relay_port} {args.relay_baud} sync={args.sync}") + logger.emit( + f"device={args.port} {args.baud} {serial_format_label(args)} " + f"relay={args.relay_port} {args.relay_baud} sync={args.sync}" + ) logger.emit(f"log={log_path}") - with serial.Serial(args.port, args.baud, bytesize=8, parity="N", stopbits=1, timeout=0.05) as device: + with open_device_serial(serial, args) as device: ctx = ScenarioContext(args=args, logger=logger, detector=detector, device=device) try: for index, step in enumerate(_scenario_steps(scenario), start=1): @@ -438,7 +445,7 @@ def _ack_limit_reached(ctx: ScenarioContext, ack: dict[str, Any]) -> bool: def _print_dry_run(args: argparse.Namespace, scenario: dict[str, Any], log_path: Path, stdout: TextIO) -> None: print(f"scenario={scenario.get('name', args.scenario.stem)}", file=stdout) - print(f"device={args.port} {args.baud} 8N1", file=stdout) + print(f"device={args.port} {args.baud} {serial_format_label(args)}", file=stdout) print(f"relay={args.relay_port} {args.relay_baud}", file=stdout) print(f"sync={args.sync}", file=stdout) print(f"log={log_path}", file=stdout) diff --git a/h8536/serial_table_dump.py b/h8536/serial_table_dump.py index 860b9e5..b9558e1 100644 --- a/h8536/serial_table_dump.py +++ b/h8536/serial_table_dump.py @@ -11,7 +11,9 @@ from typing import TextIO from .bench_connect_lcd import ( BenchLogger, FrameDetector, + add_serial_format_args, _import_serial, + open_device_serial, _read_for, _relay_command, _relay_settle, @@ -19,6 +21,7 @@ from .bench_connect_lcd import ( format_frame, frame_checksum, frame_checksum_ok, + serial_format_label, ) @@ -68,6 +71,7 @@ def build_arg_parser() -> argparse.ArgumentParser: ) parser.add_argument("--port", default="COM5", help="RS232 serial port connected to the RCP") parser.add_argument("--baud", type=int, default=38400, help="RCP serial baud rate") + add_serial_format_args(parser) parser.add_argument("--relay-port", default="COM6", help="Pico relay serial port") parser.add_argument("--relay-baud", type=int, default=115200, help="Pico relay serial baud rate") parser.add_argument("--no-power-cycle", action="store_true", help="do not send relay off/on before the sweep") @@ -95,7 +99,7 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: log_path = args.log or default_log_path() if args.dry_run: - print(f"device={args.port} {args.baud} 8N1", file=stdout) + print(f"device={args.port} {args.baud} {serial_format_label(args)}", file=stdout) print(f"relay={args.relay_port} {args.relay_baud}", file=stdout) print(f"power_cycle={int(not args.no_power_cycle)}", file=stdout) for selector in selectors: @@ -115,11 +119,14 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: response_rows: list[tuple[int, bytes, tuple[int, int] | None]] = [] try: logger.emit("Read-only serial table sweep") - logger.emit(f"device={args.port} {args.baud} 8N1 relay={args.relay_port} {args.relay_baud}") + logger.emit( + f"device={args.port} {args.baud} {serial_format_label(args)} " + f"relay={args.relay_port} {args.relay_baud}" + ) logger.emit(f"log={log_path}") logger.emit(f"selectors={len(selectors)} command=01 write_frames=0") - with serial.Serial(args.port, args.baud, bytesize=8, parity="N", stopbits=1, timeout=0.05) as device: + with open_device_serial(serial, args) as device: relay = None try: if not args.no_power_cycle: diff --git a/h8536/state_map_runner.py b/h8536/state_map_runner.py index 7c1c771..fb72fb9 100644 --- a/h8536/state_map_runner.py +++ b/h8536/state_map_runner.py @@ -13,7 +13,9 @@ from typing import Any, Iterable, TextIO from .bench_connect_lcd import ( BenchLogger, FrameDetector, + add_serial_format_args, _import_serial, + open_device_serial, _relay_command, _relay_settle, _wait_for_ready, @@ -22,6 +24,7 @@ from .bench_connect_lcd import ( frame_checksum_ok, label_frame, parse_frame, + serial_format_label, ) @@ -78,6 +81,7 @@ def build_arg_parser() -> argparse.ArgumentParser: parser.add_argument("--expected-word", type=_int_arg, help="expected E000[0] readback word; default follows --preset") parser.add_argument("--port", default="COM5", help="RS232 serial port connected to the RCP") parser.add_argument("--baud", type=int, default=38400, help="RCP serial baud rate") + add_serial_format_args(parser) parser.add_argument("--relay-port", default="COM6", help="Pico relay serial port") parser.add_argument("--relay-baud", type=int, default=115200, help="Pico relay serial baud rate") parser.add_argument("--no-power-cycle", action="store_true", help="do not send relay off/on before the test") @@ -143,11 +147,14 @@ def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int: detector = FrameDetector(sync_mode=args.sync) try: logger.emit("PT2 state-map proof runner") - logger.emit(f"device={args.port} {args.baud} 8N1 relay={args.relay_port} {args.relay_baud} sync={args.sync}") + logger.emit( + f"device={args.port} {args.baud} {serial_format_label(args)} " + f"relay={args.relay_port} {args.relay_baud} sync={args.sync}" + ) logger.emit(f"log={log_path}") _emit_plan(logger, args, force_frame, expected_word, preset_note) - with serial.Serial(args.port, args.baud, bytesize=8, parity="N", stopbits=1, timeout=0.05) as device: + with open_device_serial(serial, args) as device: ctx = StateMapRunContext(args=args, logger=logger, detector=detector, device=device) try: _prepare_device(ctx) @@ -639,7 +646,7 @@ def _print_dry_run( stdout: TextIO, ) -> None: print("PT2 state-map proof runner", file=stdout) - print(f"device={args.port} {args.baud} 8N1", file=stdout) + print(f"device={args.port} {args.baud} {serial_format_label(args)}", file=stdout) print(f"relay={args.relay_port} {args.relay_baud}", file=stdout) print(f"power_cycle={int(not args.no_power_cycle)}", file=stdout) print(f"preset={args.preset} note={preset_note}", file=stdout)