Files
VRIO/PlasmaNew/replica
CydandClaude Opus 4.8 68e3d1f367 VPlasma.Wire: add diff + TeslaSuite plasma authoring tools
- diff — compare two frames/images/encodings (.bin ESC P / .png / .txt
  bitmap=), each reduced to 128x32; reports differing dots and match %, writes
  a red-on-mismatch image, exits 1 if they differ. Closes the differential-test
  loop: diff a cropped panel/replica photo against the vPLASMA golden image.
- text / encode / decode — ported from TeslaSuite's three plasma tools (Plasma
  Font Tool, Bitmap Decoder, Editor) via PlasmaBitmap.cs:
    * text   — render text in an auto-sized Windows font to a plasma bitmap.
    * encode — an image → plasma bitmap.
    * decode — the game's bitmap= hex encoding → a preview PNG.
  Each bridges to an ESC P wire stream (and/or the bitmap= hex encoding), so
  authored content replays straight to vPLASMA, the replica, or the real panel.

Verified: text "ALERT 12" → ESC P → vPLASMA renders it; the ESC P and hex
paths diff as byte-identical (504/504 lit, 100% match).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:20:50 -05:00
..

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

  1. Chain the panels: panel A OUT → panel B IN, left-to-right, so the pair reads as one 128-wide canvas (x 063 = panel A, 64127 = panel B). If the image comes out swapped, reverse the chain order.
  2. Mount the Matrix Portal S3 onto panel A's IN HUB75 header.
  3. 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):

  1. Boards Manager → install esp32 (Espressif). Select board "Adafruit Matrix Portal S3". Set USB CDC On Boot: Enabled (so Serial is the USB port the game opens).
  2. Library Manager → install Adafruit Protomatter (pulls in Adafruit GFX / BusIO).
  3. Open MatrixPortalPlasma/MatrixPortalPlasma.ino (keep PlasmaDisplay.*, plasma_fonts.h, demo_screens.h beside 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.

Auto-compare a photo (cropped to the glass) against the golden image, or two streams against each other — each is reduced to 128×32 and diffed:

VPlasma.Wire diff --a demo-golden.png --b panel-photo.png --out delta.png
# prints "differing dots=N/4096  match=XX%", writes a red-on-mismatch image,
# exits 1 if they differ. Inputs may be .bin (ESC P) / .png / .txt (bitmap=).

Authoring plasma content (from TeslaSuite's plasma tools)

Generate display content from text or images and push it over the wire:

# Text in a Windows font, auto-sized to the panel → preview PNG + ESC P + hex:
VPlasma.Wire text --text "ALERT 12" --font "Arial" --png a.png --bin a.bin --hex a.txt
VPlasma.Wire replay --in a.bin --port COM7          # show it on the replica

# An image → the ESC P wire stream (and/or the game's bitmap= encoding):
VPlasma.Wire encode --in logo.png --bin logo.bin --hex logo.txt

# A bitmap= encoding → a preview PNG (and/or ESC P):
VPlasma.Wire decode --in logo.txt --png logo.png

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 AF).