A console tool for validating the hardware replica against vPLASMA and the
real panel by feeding all three identical byte streams.
- synth — build a repeatable command stream (selftest/demo/banner/charset).
- render — feed a stream through the vPLASMA engine and save the resulting
128x32 frame as a PNG: the pixel-exact golden image.
- replay — send a stream to any target port: the real panel (RS-232, self-
pacing), the Matrix Portal replica (USB-CDC), or a virtual port
(--paced).
- capture — log live traffic to a file, with --tee to forward it on to the
real display so capture is non-intrusive.
Reuses VPlasma.Core (same parser/fonts as the emulator and the ported
firmware). The replica README documents the differential-test workflow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Plasma display replica — Adafruit Matrix Portal S3 + HUB75
A hardware replacement for the failing Babcock PD01D221 cockpit plasma display (../README.md, ../FIRMWARE.md). A modern microcontroller reads the same serial command stream the game sends and renders it to a modern LED matrix — a drop-in from the host's point of view, with none of the plasma physics or high voltage.
The firmware's command parser and fonts are ported verbatim from vRIO's
vPLASMA emulator (src/VPlasma.Core), which is the reference oracle. Feed
the replica and vPLASMA the same byte stream and they produce the same frame.
Bill of materials
| Part | Notes |
|---|---|
| Adafruit Matrix Portal S3 | ESP32-S3 controller; plugs into the HUB75 header; native USB-C = the virtual COM port |
| 2 × Adafruit 64×32 RGB LED Matrix (P-pitch to taste; 1/16 scan) | chained → 128×32, the panel's native resolution |
| 5 V power supply, ≥ 4 A | the panels are the load; USB cannot power them |
| USB-C cable | data (and logic power) from the host PC |
An amber-leaning pitch and diffuser best mimic the neon-orange plasma; the
firmware already renders in orange (255,96,0 full / 110,40,0 half).
Wiring
- Chain the panels: panel A
OUT→ panel BIN, left-to-right, so the pair reads as one 128-wide canvas (x 0–63 = panel A, 64–127 = panel B). If the image comes out swapped, reverse the chain order. - Mount the Matrix Portal S3 onto panel A's
INHUB75 header. - Power: 5 V ≥ 4 A into the Matrix Portal's screw terminals; run the panels' power pigtails from the same 5 V. USB-C carries data (and powers the S3 logic) — do not rely on USB for panel current.
Build & flash
Arduino IDE (or arduino-cli):
- Boards Manager → install esp32 (Espressif). Select board "Adafruit
Matrix Portal S3". Set USB CDC On Boot: Enabled (so
Serialis the USB port the game opens). - Library Manager → install Adafruit Protomatter (pulls in Adafruit GFX / BusIO).
- Open
MatrixPortalPlasma/MatrixPortalPlasma.ino(keepPlasmaDisplay.*,plasma_fonts.h,demo_screens.hbeside it) and Upload.
The HUB75 pin arrays at the top of the .ino are Adafruit's published Matrix
Portal S3 values; if the panel garbles, verify them against your installed
Protomatter version.
Using it with the game
The Matrix Portal enumerates as a USB CDC COM port. In Windows Device Manager you can pin it to the COM number the host expects. Point the game's plasma output at it — under the DOSBox-X fork:
serial2 = directserial realport:COMx
Baud is cosmetic over USB CDC (the 9600 line-coding is accepted as a no-op),
so the display keeps up regardless. The link is one-way (the game writes, the
display listens), exactly as the cockpit drove the real panel.
No-host testing (onboard buttons)
- UP — toggle the built-in firmware demonstration (the real 10-screen
PLASMADOT demo,
demo_screens.h, extracted from the ROM). - DOWN — toggle the panel test: cycles diagnostic patterns (solid, border+grid, horizontal/vertical stripes, checkerboard) to expose dead dots and addressing faults — the multi-pattern sequence the real firmware runs.
- Power-on briefly lights every dot (confirms both panels), then clears.
Files
| File | |
|---|---|
MatrixPortalPlasma/MatrixPortalPlasma.ino |
sketch: Protomatter init, USB serial, render loop, buttons |
MatrixPortalPlasma/PlasmaDisplay.h/.cpp |
the PD01D221 parser + 128×32 framebuffer — a C++ port of VPlasmaDevice |
MatrixPortalPlasma/plasma_fonts.h |
the 8 real ROM fonts (PROGMEM), generated from tms27pc512.BIN |
MatrixPortalPlasma/demo_screens.h |
the 10 firmware demo screens (PROGMEM) |
Keeping it faithful — the differential test
PlasmaDisplay is a line-for-line port of VPlasmaDevice; keep the two in
sync (same commands, fonts, orientation/plot mapping). Validate the replica
by sending identical byte streams to the replica, to vPLASMA, and to the
real panel, then comparing the glass.
The VPlasma.Wire tool (tools/VPlasma.Wire, dotnet run --project tools/VPlasma.Wire -- …) drives this:
# 1) Build a repeatable stream (or capture a real one — see below).
VPlasma.Wire synth --kind demo --out demo.bin
# 2) The vPLASMA golden image (pixel-exact reference PNG).
VPlasma.Wire render --in demo.bin --out demo-golden.png --scale 8
# 3) Replay the SAME bytes to each target, and photograph the glass:
VPlasma.Wire replay --in demo.bin --port COM3 # the real panel (RS-232)
VPlasma.Wire replay --in demo.bin --port COM7 # the Matrix Portal (USB-CDC)
Compare the two photos against demo-golden.png. synth kinds: selftest,
demo, banner, charset. render takes --orient v for vertical.
Capture a real session to build a test corpus non-intrusively — insert the
tool in the path (point the game at COM12, tool tees on to the real display
on COM3):
VPlasma.Wire capture --port COM12 --out session.bin --tee COM3
Then render/replay session.bin like any other stream.
Still deferred (as in vPLASMA, documented in ../FIRMWARE.md): the 10
double-buffered pages (ESC I/ESC i are consumed but single-page) and the
vector-graphics primitives (ESC A–F).