Bring the pod's 128x32 plasma readout in-fork, completing the self-contained
glass cockpit -- no vPLASMA process, no pipe.
- serialplasma.{cpp,h}: CSerialPlasma, a serial<n>=plasma backend that parses
the game's ESC P graphics stream (L4PLASMA streams whole changed rows;
receive-only, no replies) into a 128x32 1bpp framebuffer. Transcribed from
vPLASMA's PlasmaProtocol + VPlasmaDevice (graphics path); the factory
text-mode/fonts aren't used by the game and aren't rendered, but their escape
operands are still consumed so the parser can't desync. Seam PLASMA_GetFrame()
for the renderer.
- vpxlog.cpp: draw the framebuffer as an amber-on-black window in the explode
layout, lazily created once a plasma port exists, parked centered under the
lower-left MFD (VPX_PLASMA="x,y,w,h" overrides); WS_EX_NOACTIVATE so it can't
steal DOSBox focus.
- Register SERIAL_TYPE_PLASMA (serialport.h/.cpp, dosbox.cpp -- documented in
the vpx-device README step 3d, since those stock files live in the git-ignored
src tree).
- Confs: serial2 in the _rio confs + deploy templates switches from
namedpipe pipe:vplasma to the in-fork plasma.
Live-validated 2026-07-24. Real pods keep directserial realport:COM2; the
standalone vPLASMA app keeps namedpipe pipe:vplasma.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VPX + AWE32 devices — DOSBox-X integration
Our original source for the emulated pod hardware. Kept here under
version control because the DOSBox-X source tree itself
(emulator/src/, ~490 MB) is git-ignored.
vpxlog.cpp— the Division VPX link adapter (INMOS C012 at I/O base0x150), grown through Phase 3: iserver handshake responder, FIFO scene decode, GL Division renderer (gallery shading model), VDB video-head splitter windows. RIO lamp/button bezel (B2, 2026-07-24, explode layout):pal_drawrings each mono-MFD head with its 8 RIO buttons (red, 4 top / 4 bottom, tucked under a 640x500 display so a 10px lip shows) and the radar with the amber Secondary/Screen side columns + a centered bottom indicator strip, lit fromserialrio'sRIO_GetPanelState(off/dim/bright + white-hot press; flashing lamps blink at the RioLampState rate). No labels -- the display shows each button's function. Click-to-press:rt_wndprochit-tests a click against the bezel and presses that RIO address (thread-safe via serialrio's queuedRIO_HostButton); head windows areWS_EX_NOACTIVATEso a click never pulls foreground off DOSBox (which would demote the emu thread and stop the SDL pad poll). No-op when noserial=rioport is present.serialplasma.cpp/serialplasma.h—serial<n>=plasmabackend (2026-07-24): the pod's 128×32 dot-matrix plasma readout on COM2, emulated in-fork likeserial=rio(no vPLASMA process, no pipe). The game (L4PLASMA.CPP) renders into its own 1bpp buffer and streams changed rows with a singleESC Pgraphics command — receive-only, no replies — so the device is just that parser filling a 128×32 framebuffer (transcribed from vPLASMAPlasmaProtocol+VPlasmaDevice, graphics path; the factory text-mode/fonts aren't used by the game and aren't rendered, but their escape operands are still consumed so the parser can't desync).vpxlogdraws it as an amber-on-black window in the explode layout (seamPLASMA_GetFrame), lazily created once the port exists, parked centered under the lower-left MFD (VPX_PLASMA="x,y,w,h"overrides). Real pods keepdirectserial realport:COM2; the vPLASMA app keepsnamedpipe pipe:vplasma.vweawe.cpp— the dual-AWE32 sound device: two vendored EMU8000 cores at 0x620/0x640 (+0x400/+0x800 triplets), rear-card DSP/mixer stub at 0x240, autonomous render thread with direct winmm output. Needs the GM ROM (emulator/roms/awe32.raw) viaVWE_AWE_ROMor SoundFont uploads are refused (banks declareirom=1MGM). Seeemulator/SOUND-NOTES.md.emu8k.cpp/emu8k.h/emu8k_shim.h— EMU8000 wavetable core vendored from 86Box (GPL-2.0-or-later, same license as DOSBox-X), with a minimal shim; local changes are listed in the emu8k.cpp header.serialnamedpipe.cpp/serialnamedpipe.h—serial<n>=namedpipe pipe:<name>backend (2026-07-12): serial-over-named-pipe for vRIO/vPLASMA, replacing com0com. DOSBox is the pipe CLIENT with 500ms background retry; typed frames carry data (0x00 len bytes) and DTR/RTS line state (0x01 bits); the full wire contract is in the header comment (pinned with the vRIO session). Supports the directserialrxpollus/rxburst/rxdelaylow-latency knobs. Smoke-tested end-to-end 2026-07-12.serialrio.cpp/serialrio.h—serial<n>=riobackend (2026-07-21, keyboard field 2026-07-22): the cockpit RIO board emulated in-fork. It speaks the device side of the RIO 9600-8N1 protocol straight to the game's UART (no external process, no pipe) and sources pilot input from an SDL game controller + the host keyboard inside the emulator. Because the game↔board round trip is in-process at the emulated UART's own cadence — like the real ISA UART on a pod — the serial round-trip dropouts (livelock,TXMAXIDLE,rxburst, 15s retry) can't occur. The protocol state machine + input mapping are transcribed from the validated vRIO app (C:\VWE\vrioVRio.Core:VRioDevice, theProtocolcodec,Input/InputRouter+BindingProfileFormat); the transport, wire pacer, panel UI and thread locks are dropped (single emulator thread). RX byte pacing reuses directserial's state machine (samerxpollus/rxburstknobs), draining a queue the board itself fills. Keyboard field (B1): sdlmain offers every SDL key toRIO_HostKeyEvent()first; while capture is ON (default) bound keys press RIO addresses or drive axes and are swallowed; unbound keys and Ctrl/Alt/Gui chords pass through (host hotkeys keep working; modifier keys BOUND as inputs are exempt from the chord rule). Default field: number/QWERTY rows = upper MFD bank, home/bottom rows = lower bank, F1–F12 = Secondary/Screen, arrows+Space = hat+main, and keyboard FLIGHT controls (operator 2026-07-22): numpad 8/2/4/6 = stick, 7/9 = pedals, LShift/LCtrl = throttle slew ±0.7/s, numpad-5 = throttle zero; the internal keypad is unbound (mission-review plumbing only). PAUSE or SCROLL LOCK toggles capture panel↔DOS (toggling off releases everything; needed at the netnub loop / DOS prompts);togglekey:<sdl-name>adds a third toggle key for keyboards lacking both. Focus loss releases held keys (RIO_HostFocusLostinGFX_LosingFocus). A bindings file in vRIO's grammar REPLACES the default profile (confbindings:<path>, else envVWE_RIO_BINDINGS; key-axis modesdeflect|slew|rate|set, sign may be a separate token; vRIO's .NET key names are aliased so a vRIObindings.txtports over). Conf:serial1=rio [pad:<n>] [inverty] [bindings:<path>] [togglekey:<key>] [rxpollus:<us>] [rxburst:<n>]. Additive — real pods keepdirectserial realport:COM1; vRIO-over-pipe keepsnamedpipe pipe:vrio. Confs:net_loop_rio.conf/net_rp_rio.conf;pod-launch --rio. B0 (pad) LIVE-CONFIRMED 2026-07-22 from the repacked dist; keyboard-field live test pending.
Applying to a DOSBox-X source checkout
Tested against DOSBox-X v2026.06.02, MSYS2 mingw64.
- Copy the devices in:
cp emulator/vpx-device/vpxlog.cpp emulator/src/src/hardware/ cp emulator/vpx-device/emu8k.cpp emulator/src/src/hardware/ cp emulator/vpx-device/emu8k.h emulator/src/src/hardware/ cp emulator/vpx-device/emu8k_shim.h emulator/src/src/hardware/ cp emulator/vpx-device/vweawe.cpp emulator/src/src/hardware/ - Add them to the hardware build — in
src/src/hardware/Makefile.am, appendvpxlog.cpp emu8k.cpp vweawe.cpptolibhardware_a_SOURCES(we inserted them afterglide.cpp; if you edit the generatedMakefile/Makefile.inby hand instead of re-running automake, also mirror the$(OBJEXT)list, the.Podepfile list, and the depfile include markers — grep for howvpxlogappears and copy the pattern). - Call the inits — in
src/src/gui/sdlmain.cpp, declarevoid VPXLOG_Init();andvoid VWEAWE_Init();next to the other*_Init()prototypes; callVPXLOG_Init();right afterGLIDE_Init();andVWEAWE_Init();right afterSBLASTER_Init();(it needs the mixer initialized). 3b. The namedpipe serial backend:plus four small stock edits:cp emulator/vpx-device/serialnamedpipe.cpp emulator/src/src/hardware/serialport/ cp emulator/vpx-device/serialnamedpipe.h emulator/src/src/hardware/serialport/src/src/hardware/serialport/Makefile.am: appendserialnamedpipe.cpp serialnamedpipe.htolibserial_a_SOURCES(same generated-Makefile caveat as step 2).src/include/serialport.h: addSERIAL_TYPE_NAMED_PIPEtoSerialTypesEunder#if defined(WIN32)(beforeSERIAL_TYPE_DIRECT_SERIAL).src/src/hardware/serialport/serialport.cpp:#include "serialnamedpipe.h"; add thetype=="namedpipe"case to BOTH dispatch switches (SERIALPORTS ctor + the SERIAL command) and"namedpipe"to theserialTypes[]string table — grep for how"file"appears and copy the pattern.src/src/dosbox.cpp: add"namedpipe"to theserials[]allowed-values list (without this the config parser silently falls back todummy). 3c. The in-fork RIO serial backend (needs SDL2 — the whole-program link already pulls SDL2 in, and the vendored SDL2 include dir is on the global compile flags, so no per-subdir cflag edits):
plus the same four stock edits as the namedpipe backend:cp emulator/vpx-device/serialrio.cpp emulator/src/src/hardware/serialport/ cp emulator/vpx-device/serialrio.h emulator/src/src/hardware/serialport/src/src/hardware/serialport/Makefile.am: appendserialrio.cpp serialrio.htolibserial_a_SOURCES(same generated- Makefile caveat as step 2).src/include/serialport.h: addSERIAL_TYPE_RIOtoSerialTypesE(UNguarded — SDL is cross-platform, unlike the WIN32-only namedpipe; placed right afterSERIAL_TYPE_MOUSE).src/src/hardware/serialport/serialport.cpp:#include "serialrio.h"; add thetype=="rio"case to BOTH dispatch switches and"rio"to theserialTypes[]string table (copy thenamedpipepattern; keep it unguarded).src/src/dosbox.cpp: add"rio"to theserials[]allowed-values list.src/src/gui/sdlmain.cpp(the B1 keyboard field, three small edits): (a) declare the hooks aboveGFX_LosingFocus:bool RIO_HostKeyEvent(int sdl_scancode, bool pressed, bool repeat, unsigned int sdl_mods); void RIO_HostFocusLost(void);(b) callRIO_HostFocusLost();insideGFX_LosingFocusright afterMAPPER_LosingFocus();(c) in GFX_Events' SDL2case SDL_KEYDOWN: case SDL_KEYUP:block, right after the SCREEN_GAMELINK early-out, offer the event toRIO_HostKeyEvent((int)event.key.keysym.scancode, event.type == SDL_KEYDOWN, event.key.repeat != 0, event.key.keysym.mod)andbreak;when it returns true (consumed keys must never reach the mapper). 3d. The in-fork plasma serial backend (same seam pattern as RIO):
plus the four stock edits (copy thecp emulator/vpx-device/serialplasma.cpp emulator/src/src/hardware/serialport/ cp emulator/vpx-device/serialplasma.h emulator/src/src/hardware/serialport/riopattern exactly):src/src/hardware/serialport/Makefile.am: appendserialplasma.cpp serialplasma.htolibserial_a_SOURCES.src/include/serialport.h: addSERIAL_TYPE_PLASMAright afterSERIAL_TYPE_RIO(unguarded).src/src/hardware/serialport/serialport.cpp:#include "serialplasma.h"; add thetype=="plasma"case to BOTH dispatch switches and"plasma"toserialTypes[].src/src/dosbox.cpp: add"plasma"to theserials[]allowed-values list. (The plasma WINDOW is drawn byvpxlog.cppvia thePLASMA_GetFrameextern — already in this dir'svpxlog.cpp, so it lands with step 1.)
- Build:
Output:
cd emulator/src ./build-mingw-sdl2 --enable-debug=heavysrc/src/dosbox-x.exe.
Running
set VPXLOG=C:\VWE\TeslaRel410\emulator\vpxlog.txt
emulator\src\src\dosbox-x.exe -conf emulator\capture.conf
python emulator\analyze_capture.py
With VPXLOG unset the device is inert and the build behaves like stock
DOSBox-X.