serial: pipe:vrio named-pipe transport, no com0com needed

NamedPipeTransport connects as a client to vRIO's \\.\pipe\vrio (the
DOSBox-X fork's role) and speaks the shared typed-frame contract
(PipeFraming: 0x00 data / 0x01 modem lines, null-modem crossed). The COM
path's DTR reset pulse is replayed in-band on connect. Peer disconnects
and framing violations surface as the 0-byte transport-closed read the
link already understands.

RioTransportFactory routes endpoint strings — pipe:name (vRIO's own
picker syntax) to the pipe transport, everything else to
SerialPortTransport — and is wired into RioCoordinator and all three
RioSerialMonitor modes, so profiles (RioComPort/DefaultRioComPort) and
the bench tools take pipe endpoints anywhere a COM name went.

Gotcha baked into the design: named pipes here have 0-byte buffers, so a
write blocks until the peer reads it, and vRIO also writes its lines
frame before reading — the on-connect pulse frames are therefore queued
as overlapped writes (pipe writes drain in issue order, preserving the
edge positions) instead of blocking the constructor into a mutual
write-first deadlock.

Verified end-to-end against the real VRioDevice + VRioPipeService over
\\.\pipe\vrio: version 4.2 + check replies, 137 analog polls, lamp
commands ACKed, zero framing errors. 322 tests green, both flavors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-30 10:14:13 -05:00
co-authored by Claude Fable 5
parent 3512c89dca
commit 9cca7c77bd
11 changed files with 670 additions and 9 deletions
+4 -2
View File
@@ -9,6 +9,8 @@ using RioJoy.Core.Serial;
// It flashes all lamps once to prove the PC -> RIO output path, then echoes a lamp
// on each button press so a physical press lights up.
// dotnet run --project tools/RioSerialMonitor -- [port] [seconds] [--baud rate]
// [port] is a COM name or a pipe endpoint: pipe:vrio connects to the vRIO
// emulator's \\.\pipe\vrio (no com0com pair; vRIO must have its pipe open).
// Firmware wedge-patch validation (RIO_TAP mash test, see MashTest.cs):
// dotnet run --project tools/RioSerialMonitor -- --mash [port] [seconds]
// [--label baseline|patched] [--no-lamps] [--wedge seconds] [--baud rate]
@@ -45,10 +47,10 @@ void Log(string msg)
Console.WriteLine($"== RIO serial monitor :: {port} @ {baud} 8N1 for {seconds}s ==");
SerialPortTransport transport;
IRioTransport transport;
try
{
transport = new SerialPortTransport(port, baud);
transport = RioTransportFactory.Open(port, baud);
}
catch (Exception ex)
{