On a wedged (fully silent) board the receive loop sits in a pending
net48 serial read that ignores cancellation; awaiting the link before
closing the port hangs the tool at run end and loses the summary -
exactly what happened on the first real baseline run (the board wedged
at 0.62s and stayed dead, so no byte ever completed the read). Close
the port first (same order RioCoordinator.Teardown uses); applies to
both monitor and --mash modes. Selftest unaffected (its fake transport
honors cancellation, which is why it never caught this).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
make_patch.py gains --baud31250: one byte beyond the wedge patch — the SCI
init operand at $D62B ($30 -> $02). BAUD $30 = /13 prescale, /1 divider
(2MHz E / 208 = 9615); $02 = /1, /4 -> 31250 exactly, 3.3x faster. The
init write also confirms the 8MHz crystal, which is why 19200/38400 are
unreachable and why 62500/125k are left alone pending an ISR cycle count.
- 24 bytes changed vs original (sha256 9f866cf3...); re-disassembly diff
vs the classic patched image shows exactly the one operand line, and
the classic build still reproduces 3fc8170c... (script regression-safe).
- PC side: SerialPortTransport takes an optional baudRate (default 9600,
runtime untouched); RioSerialMonitor + --mash accept --baud 31250.
- Caveats documented in README/ANALYSIS: non-standard rate (FTDI-class
adapters only, no 16550s); native games still speak 9600 so this chip
is bench/RIOJoy-only; validate the wedge patch at 9600 first.
275 tests green; mash --selftest regression unchanged (FAIL/exit-1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New --mash mode (tools/RioSerialMonitor/MashTest.cs) mechanizes the
wedge-patch validation plan from RIOv4_2-ANALYSIS.md:
- Runs the live link with the app's >5s reset-recovery DISABLED so a
board wedge stays observable, and echoes lamps on every press
(lamp/reply collisions are the wedge trigger).
- Gap timing uses ANY AnalogReply packet (0xFE sentinels included -
a sentinel still proves the reply path is alive); logs a gap
histogram + top-10 longest gaps with timestamps.
- WEDGE detector: analog silent past the threshold (default 2s) ->
beep + banner; on resume, classifies self-recovered (patched
expectation) vs button-revived (button event within 300ms of resume,
the unpatched signature) vs unresolved at run end.
- Board self-reported RestartCount/AbandonCount/FullBufferCount
snapshotted before/after via CheckRequest, delta printed
(7-bit wrap-aware).
- Fixed-layout summary teed to riomash-<label>-<stamp>.log so
baseline-vs-patched runs diff directly. Exit 0 = no wedge, 1 = wedge.
--mash --selftest drives the whole instrument against a scripted
in-memory board (SelftestTransport) that goes silent at t=4.0s and
revives 200ms after a button at t=6.5s: verified end-to-end - alarm at
6.0s, wedge classified button-revived (2.75s), counter delta +4/+0/+1,
verdict FAIL, exit 1. Use it to sanity-check the alarm at the cabinet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prepares RioJoy.Core for the net40 (Windows XP) target, which has no
System.Memory, ValueTask, or System.Text.Json:
- IRioTransport and the whole protocol/framing layer now use byte[] +
Task (RioPacket.Payload, PacketParser/Builder, RioChecksum, replies,
AnalogReport, RioHidReport). At 9600 baud Span bought nothing; the
SerialPortTransport bridge copies disappear entirely.
- ConfigStore/OverlayTemplateStore switch to Newtonsoft 13 with the
same conventions (indented, PascalCase, string enums, null-skipping);
verified against the real STJ-written config.json and regions.json
(load + round-trip). System.Memory and System.Text.Json packages
dropped.
275 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documentation now describes the .NET Framework 4.8 stack (was .NET 8):
- README build prerequisites + framework-dependent/no-runtime-install note,
test count 136 -> 241.
- PLAN.md architecture diagram, stack decision (with PolySharp/shims note),
suite total 136 -> 241.
- deploy/README-DEPLOY.txt: app is net48 framework-dependent (4.8 is in-box on
Win10/11), and build prerequisites.
Also migrate the three tools (RioJoySmokeTest, RioSerialMonitor, XcfRegionExtract)
to net48 so they keep building against the now-net48 RioJoy.Core (a net8 project
cannot reference a net48 one). Added PolySharp + System.Memory/System.Text.Json
shims and replaced net-core-only APIs (string.Contains/IndexOf with comparison,
Array.Fill, generic Enum.IsDefined, int.TryParse(span)). All three build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A console diagnostic that opens the RIO COM port, runs the real serial link,
and logs every event (buttons, keypad, axis, version/check, control bytes,
framing). Flashes all lamps once to prove the PC->RIO path and echoes a lamp
on each button press. Verified end-to-end against a partial RIO on COM1
(firmware 4.2; MFD + keypad inputs and the throttle axis all decode).
dotnet run --project tools/RioSerialMonitor -- COM1 30
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>