Named-pipe transport for the DOSBox-X fork's namedpipe backend

Both devices now serve \.\pipe\vrio and \.\pipe\vplasma for the whole
app lifetime alongside the COM rows — the com0com-free path. Framing per
the pinned contract (0x00 len data / 0x01 DTR+RTS lines, one lines frame
on connect, unknown type = log + drop): PipeFraming/PipeFrameDecoder and
VRioPipeService (TX paced at the wire rate, peer DTR edges feed
HostHandshake) in VRio.Core, listener-only VPlasmaPipeService twin in
VPlasma.Core. Busy pipe names retry, so vRIO's built-in glass and the
standalone vPLASMA coexist. README documents the transport and the fork
conf lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-12 23:03:02 -05:00
co-authored by Claude Fable 5
parent 0674cf5ba4
commit e507f1740c
8 changed files with 1247 additions and 0 deletions
+10
View File
@@ -7,6 +7,9 @@ namespace VPlasma.App;
/// device end is hardwired to <see cref="PortName"/> (the plasma side of the
/// second com0com pair) and opened automatically — a retry timer keeps
/// trying while the port is missing or busy, and reopens it if it dies. The
/// DOSBox-X fork's named-pipe transport (<c>\\.\pipe\vplasma</c>) is served
/// permanently alongside it (if vRIO's built-in glass already holds the
/// pipe name, the server just retries until it frees up). The
/// title bar carries the port status; double-clicking the glass cycles the
/// self-test pages (banner, charset, graphics) through the wire parser, and
/// a right-click resets the display to its power-on state.
@@ -18,6 +21,7 @@ internal sealed class MainForm : Form
private readonly VPlasmaDevice _device = new();
private readonly VPlasmaSerialService _service;
private readonly VPlasmaPipeService _pipeService;
private readonly PlasmaCanvas _canvas = new();
private readonly System.Windows.Forms.Timer _reconnectTimer = new() { Interval = 3000 };
@@ -32,6 +36,7 @@ internal sealed class MainForm : Form
StartPosition = FormStartPosition.CenterScreen;
_service = new VPlasmaSerialService(_device);
_pipeService = new VPlasmaPipeService(_device);
_canvas.Location = new Point(0, 0);
Controls.Add(_canvas);
@@ -39,6 +44,7 @@ internal sealed class MainForm : Form
// Device / service events arrive on the serial reader thread; marshal to the UI.
_device.Updated += () => RunOnUi(() => _canvas.UpdateFrom(_device));
_service.ConnectionChanged += _ => RunOnUi(UpdateTitle);
_pipeService.ClientChanged += _ => RunOnUi(UpdateTitle);
_canvas.DoubleClick += (_, _) => RunSelfTest();
_canvas.MouseClick += (_, e) =>
@@ -55,10 +61,12 @@ internal sealed class MainForm : Form
{
_reconnectTimer.Dispose();
_service.Dispose();
_pipeService.Dispose();
};
_canvas.UpdateFrom(_device);
EnsureOpen();
_pipeService.Start();
}
private void EnsureOpen()
@@ -82,6 +90,8 @@ internal sealed class MainForm : Form
string status = _service.IsOpen
? $"{PortName} @ 9600 8N1"
: $"{PortName} unavailable — retrying";
if (_pipeService.IsClientConnected)
status += " • pipe host connected";
Text = $"vPLASMA v{Application.ProductVersion} — {status}";
}