Files
TeslaRel410/emulator/vpx-device/README.md
T
CydandClaude Opus 4.8 844c11f792 emulator: in-fork plasma display (serial2=plasma) window in the explode layout
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>
2026-07-24 12:48:07 -05:00

191 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 base
`0x150`), 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_draw` rings 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 from `serialrio`'s `RIO_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_wndproc`
hit-tests a click against the bezel and presses that RIO address (thread-safe
via serialrio's queued `RIO_HostButton`); head windows are `WS_EX_NOACTIVATE`
so a click never pulls foreground off DOSBox (which would demote the emu
thread and stop the SDL pad poll). No-op when no `serial=rio` port is present.
- **`serialplasma.cpp` / `serialplasma.h`** — `serial<n>=plasma` backend
(2026-07-24): the pod's 128×32 dot-matrix plasma readout on COM2, emulated
in-fork like `serial=rio` (no vPLASMA process, no pipe). The game
(`L4PLASMA.CPP`) renders into its own 1bpp buffer and streams changed rows
with a single `ESC P` graphics command — receive-only, no replies — so the
device is just that parser filling a 128×32 framebuffer (transcribed from
vPLASMA `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). `vpxlog` draws it as
an amber-on-black window in the **explode** layout (seam `PLASMA_GetFrame`),
lazily created once the port exists, parked centered under the lower-left MFD
(`VPX_PLASMA="x,y,w,h"` overrides). Real pods keep `directserial
realport:COM2`; the vPLASMA app keeps `namedpipe 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`) via `VWE_AWE_ROM` or SoundFont
uploads are refused (banks declare `irom=1MGM`). See
`emulator/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 directserial `rxpollus`/`rxburst`/`rxdelay`
low-latency knobs. Smoke-tested end-to-end 2026-07-12.
- **`serialrio.cpp` / `serialrio.h`** — `serial<n>=rio` backend (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\vrio`
VRio.Core: `VRioDevice`, the `Protocol` codec, `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 (same `rxpollus`/`rxburst` knobs), draining a
queue the board itself fills.
**Keyboard field (B1):** sdlmain offers every SDL key to `RIO_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, F1F12 = 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_HostFocusLost` in
`GFX_LosingFocus`). A bindings file in vRIO's grammar REPLACES the default
profile (conf `bindings:<path>`, else env `VWE_RIO_BINDINGS`; key-axis
modes `deflect|slew|rate|set`, sign may be a separate token; vRIO's .NET
key names are aliased so a vRIO `bindings.txt` ports over).
Conf: `serial1=rio [pad:<n>] [inverty] [bindings:<path>]
[togglekey:<key>] [rxpollus:<us>] [rxburst:<n>]`. **Additive** — real pods keep `directserial realport:COM1`;
vRIO-over-pipe keeps `namedpipe 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.
1. 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/
```
2. Add them to the hardware build — in `src/src/hardware/Makefile.am`, append
`vpxlog.cpp emu8k.cpp vweawe.cpp` to `libhardware_a_SOURCES` (we inserted
them after `glide.cpp`; if you edit the generated `Makefile`/`Makefile.in`
by hand instead of re-running automake, also mirror the `$(OBJEXT)` list,
the `.Po` depfile list, and the depfile include markers — grep for how
`vpxlog` appears and copy the pattern).
3. Call the inits — in `src/src/gui/sdlmain.cpp`, declare `void VPXLOG_Init();`
and `void VWEAWE_Init();` next to the other `*_Init()` prototypes; call
`VPXLOG_Init();` right after `GLIDE_Init();` and `VWEAWE_Init();` right
after `SBLASTER_Init();` (it needs the mixer initialized).
3b. The namedpipe serial backend:
```
cp emulator/vpx-device/serialnamedpipe.cpp emulator/src/src/hardware/serialport/
cp emulator/vpx-device/serialnamedpipe.h emulator/src/src/hardware/serialport/
```
plus four small stock edits:
- `src/src/hardware/serialport/Makefile.am`: append
`serialnamedpipe.cpp serialnamedpipe.h` to `libserial_a_SOURCES`
(same generated-Makefile caveat as step 2).
- `src/include/serialport.h`: add `SERIAL_TYPE_NAMED_PIPE` to
`SerialTypesE` under `#if defined(WIN32)` (before
`SERIAL_TYPE_DIRECT_SERIAL`).
- `src/src/hardware/serialport/serialport.cpp`: `#include
"serialnamedpipe.h"`; add the `type=="namedpipe"` case to BOTH dispatch
switches (SERIALPORTS ctor + the SERIAL command) and `"namedpipe"` to
the `serialTypes[]` string table — grep for how `"file"` appears and
copy the pattern.
- `src/src/dosbox.cpp`: add `"namedpipe"` to the `serials[]` allowed-values
list (without this the config parser silently falls back to `dummy`).
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):
```
cp emulator/vpx-device/serialrio.cpp emulator/src/src/hardware/serialport/
cp emulator/vpx-device/serialrio.h emulator/src/src/hardware/serialport/
```
plus the same four stock edits as the namedpipe backend:
- `src/src/hardware/serialport/Makefile.am`: append
`serialrio.cpp serialrio.h` to `libserial_a_SOURCES` (same generated-
Makefile caveat as step 2).
- `src/include/serialport.h`: add `SERIAL_TYPE_RIO` to `SerialTypesE`
(UNguarded — SDL is cross-platform, unlike the WIN32-only namedpipe;
placed right after `SERIAL_TYPE_MOUSE`).
- `src/src/hardware/serialport/serialport.cpp`: `#include "serialrio.h"`;
add the `type=="rio"` case to BOTH dispatch switches and `"rio"` to the
`serialTypes[]` string table (copy the `namedpipe` pattern; keep it
unguarded).
- `src/src/dosbox.cpp`: add `"rio"` to the `serials[]` allowed-values list.
- `src/src/gui/sdlmain.cpp` (the B1 keyboard field, three small edits):
(a) declare the hooks above `GFX_LosingFocus`:
`bool RIO_HostKeyEvent(int sdl_scancode, bool pressed, bool repeat,
unsigned int sdl_mods); void RIO_HostFocusLost(void);`
(b) call `RIO_HostFocusLost();` inside `GFX_LosingFocus` right after
`MAPPER_LosingFocus();`
(c) in GFX_Events' SDL2 `case SDL_KEYDOWN: case SDL_KEYUP:` block, right
after the SCREEN_GAMELINK early-out, offer the event to
`RIO_HostKeyEvent((int)event.key.keysym.scancode, event.type ==
SDL_KEYDOWN, event.key.repeat != 0, event.key.keysym.mod)` and `break;`
when it returns true (consumed keys must never reach the mapper).
3d. The in-fork plasma serial backend (same seam pattern as RIO):
```
cp emulator/vpx-device/serialplasma.cpp emulator/src/src/hardware/serialport/
cp emulator/vpx-device/serialplasma.h emulator/src/src/hardware/serialport/
```
plus the four stock edits (copy the `rio` pattern exactly):
- `src/src/hardware/serialport/Makefile.am`: append
`serialplasma.cpp serialplasma.h` to `libserial_a_SOURCES`.
- `src/include/serialport.h`: add `SERIAL_TYPE_PLASMA` right after
`SERIAL_TYPE_RIO` (unguarded).
- `src/src/hardware/serialport/serialport.cpp`: `#include "serialplasma.h"`;
add the `type=="plasma"` case to BOTH dispatch switches and `"plasma"` to
`serialTypes[]`.
- `src/src/dosbox.cpp`: add `"plasma"` to the `serials[]` allowed-values list.
(The plasma WINDOW is drawn by `vpxlog.cpp` via the `PLASMA_GetFrame` extern
— already in this dir's `vpxlog.cpp`, so it lands with step 1.)
4. Build:
```
cd emulator/src
./build-mingw-sdl2 --enable-debug=heavy
```
Output: `src/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.