Files
TeslaRel410/emulator/RIO-NOTES.md
T
CydandClaude Opus 4.8 0bb493dd5f Phase 3e: live texturing + serial receive-latency fixes for the RIO
Texturing (validated live -- game-live-textured.png, the ravine's brown dirt
terrain): the wire model is Division's intensity+ramp scheme. action 26
uploads 8-bit intensity texels ([node][nbytes][w][h] + rows; type 13 =
texture); texmap (12) references the texture; material (11) references its
texmap and a ramp (14: lo/hi RGB); texel color = lerp(lo, hi, i/255). The
backend bakes RGBA per material, uploads to GL, maps with wire UVs
(stride-5: floats 3-4; stride-8/9: floats 6-7).

Serial (directserial fork options, tracked in vpx-device/serialport/):
- rxpollus:<us> -- receive poll tick (stock 1ms); 100us discovers inbound
  bytes ~10x sooner. Validated: sim advanced, camera moved with real RIO.
- rxburst:<n>  -- stock DOSBox re-serializes received bytes at emulated wire
  speed (~1ms/byte at 9600) though they already paid wire time on the real
  cable; a 15-byte analog reply gained ~14ms, blowing the RIO's few-ms ACK
  window and dropping the game into its 15-second retry fallback
  (L4CTRL.CPP limit=15.0 //0.2). rxburst:16 delivers buffered bytes 16x
  faster. game_rio.conf: realport:COM1 rxpollus:100 rxburst:16.

Crash-on-advance fixed: *_TSHD.BGF terrain shadows live only in arena
subdirs the search path misses; null shadow renderable was dereferenced once
the sim moved. All 11 copied into VIDEO/GEO in the working image; game now
runs sustained (560+ frames, textured, no crash). Details in RIO-NOTES.md.

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

4.7 KiB
Raw Blame History

RIO cockpit controls — passthrough tuning (Phase 5+)

The RIO (Remote Input/Output) is the cockpit control board on COM1 (the plasma display is COM2, handled later). DOSBox-X talks to a real RIO through serial1=directserial realport:COM1 (game_rio.conf). On this host the RIO is a Prolific USB-to-Serial adapter enumerated as COM1.

The analog-poll latency problem (solved)

The initial RIO check request tolerates latency and passed easily. But the runtime control loop (L4CTRL.CPP:1145) sends an analog request every cycle and, if the reply doesn't return inside its window, logs LBE4ControlsManager::Execute, lost RIO analog request and re-requests. The board itself refuses/drops comms if the ACK is late by more than a few milliseconds — a hard real-time deadline.

Empirical result (2026-07-03): a slower CPU made the RIO fail sooner. So the dominant latency was how fast the game processes the RIO packet and emits the ACK, not the serial wiring. The fix:

[cpu]
core=dynamic     ; recompiler — many x faster than the 'normal' interpreter
cputype=pentium
cycles=max       ; full host speed

With core=dynamic + cycles=max the RIO stays in sync (the user confirmed "the rio behaved"). Notes:

  • cycles=fixed 20000 / 150000 and core=normal were all too slow — the RIO dropped comms, faster at lower speeds.
  • The DOSBox-X serial path is already low-latency on transmit (directserial.cpp transmitByte calls SERIAL_sendchar immediately).
  • Prolific PL2303 has no adjustable LatencyTimer registry value (unlike FTDI); an FTDI adapter set to 1 ms latency would be the lowest-latency host option if ever needed.

Receive-latency fork options (2026-07-03)

Even with the fast CPU, intermittent timeouts remained and the game would drop into its 15-second analog retry fallback — the source shows limit = 15.0; // 0.2 in L4CTRL.CPP, so the shipped binary re-requests very slowly once replies stop arriving ("the polling is really slow"). Two emulator receive latencies were fixed with new directserial options:

  • rxpollus:<us> (501000, stock 1000): host-port receive poll tick. Stock DOSBox-X discovers inbound bytes on a 1 ms tick; 100 µs discovers them ~10× sooner. First validated result: the sim advanced and the camera moved in the render window.
  • rxburst:<n> (164): stock DOSBox re-serializes each received byte at emulated wire speed (~1 ms/byte at 9600) even though the bytes already paid their wire time on the physical cable and sit in the host buffer — a 15-byte analog reply gained ~14 ms of artificial latency, single-handedly blowing the RIO's few-ms ACK window. rxburst:16 delivers buffered bytes 16× faster.

game_rio.conf uses realport:COM1 rxpollus:100 rxburst:16.

Crash-on-advance fixed: arena terrain shadows

With the RIO in sync the sim advances and the game crashed dereferencing the mech terrain shadow renderable: *_TSHD.BGF live only in VIDEO/GEO/ARENA/ + …/POLAR/, which the object search path misses, so thr_tshd.bgf failed to load and left a null renderable that the moving sim eventually touched. Fix: the 11 *_TSHD.BGF files are copied from ARENA/ into VIDEO/GEO/ in the working image (reversible, one file each). After the fix the game runs sustained (500+ frames, no crash).

Next wall: mission content (a game-data issue, not protocol/RIO)

With the RIO feeding real input, the simulation advances — and then the game faults:

32loader runtime error: Unhandled exception
Exception 0E at 00FF:0040223B
Module 'BTL4OPT.EXE' section 'CODE' offset 0000123B
[..] 8B 4D 0C (mov ecx,[ebp+0C])  8B 11 (mov edx,[ecx])   ECX=2
The instruction referenced illegal address 00000002

A near-null pointer (2) dereference: a function got 2 where an object pointer was expected. This is downstream of the failed content load logged just before it:

Entity -1:63 class:42 couldn't figure out how to MakeEntityRenderables
L4VIDEO.cpp couldn't load object thr_tshd.bgf

thr_tshd.bgf exists in VIDEO/GEO/ARENA/ and VIDEO/GEO/POLAR/, but not the top VIDEO/GEO/. The game builds its object search path from objectpath entries in the mission notation file (L4VIDEO.CPP:1852), i.e. from the .egg. The shipped test.egg is only mission parameters and does not set up the arena object path, so arena-specific objects aren't found; the entity gets a broken renderable and the sim eventually dereferences it.

To progress past this needs a real mission/arena .egg (or an object path manually pointed at the selected arena's VIDEO/GEO/<ARENA> subdir). That is content/mission configuration, separate from the VPX protocol, the renderer, and the RIO — all of which now work.