Files
BT411/context/pod-hardware.md
arcattackandClaude Opus 4.8 3792a04661 Fix throttle-detent Abs() macro bug + KB analog-throttle + slide diagnostics (task #50)
Uncommitted work from the speed-model + peer-motion investigation:
 - btl4mppr.cpp: the L4MechControlsMapper full-throttle detent used the
   unparenthesized Abs() macro (STYLE.H:118) on an expression -- Abs(throttlePos
   - 1.0f) mis-expands to -(throttlePos + 1.0f), always <= 0.05, so the detent
   snapped throttle to full EVERY frame.  Diff into a temp first (same class as
   the 7615ecd angular-resync Abs fix).
 - context/pod-hardware.md: document the decomp-verified analog-continuous pod
   throttle path (RIO Ranger 0-800 counts, 0.05 deadband, no notching; '5 speeds'
   is false) from workflow w0odszxro.
 - mech4.cpp: BT_SLIDE/[mslide] per-frame slide diagnostics (peer position moving
   while legs in stand; master decel profile) -- used to prove the stop-slide is a
   peer leg-SM-winds-down-early desync, not master momentum.  Env-gated.

The 'pretty good' coupled-motion gameplay state is already shipped (a9ab3db).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:13:56 -05:00

81 lines
5.3 KiB
Markdown
Raw Permalink 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.
---
id: pod-hardware
title: "Pod Hardware — the fixed target (7 monitors, D3D9, RIO)"
status: established
source_sections: "PROGRESS_LOG.md §3; the PLATFORM PROFILE + GAUGE DEV-COMPOSITE notes"
related_topics: [gauges-hud, rendering, project-overview]
key_terms: [pod, RIO, MFD, IG-board, SVGA16]
---
# Pod Hardware (the fixed target)
The port must run on (a) a dev box and (b) the fixed arcade pod. The pod is a hard constraint that
bounds the graphics API. Full detail: `docs/PROGRESS_LOG.md §3`.
## Displays
- **2 video cards → 7 monitors:** main 3D view **800×600**; radar **640×480**; five monochrome MFDs
driven as one **1280×480** horizontally-spanned surface. [T1]
- Requires **old NVIDIA drivers** for the MFD horizontal spanning — a hard constraint that bounds
the graphics API → **Target Direct3D 9** (lowest common denominator that runs on old-driver pods
AND modern cards; one codepath). NOT Vulkan/D3D11+. CUDA is irrelevant (compute, not display). [T1]
## Cockpit I/O (RIO)
Joystick X/Y, throttle, pedals, buttons over **serial COM** (`L4RIO`, `L4SERIAL`). Must be remapped
to keyboard/gamepad on a dev box; real wiring is a pod bring-up task (Phase 8). The engine is a PUSH
model — `LBE4ControlsManager` groups are fed by all devices (RIO on the pod, DirectInput on dev);
the `MechControlsMapper` interprets them ([[locomotion]]). [T2]
### The pod throttle is ANALOG-CONTINUOUS, not notched (verified end-to-end) [T1]
The authentic pod throttle path — traced 2026-07 (task #50 throttle-fidelity question):
1. **Hardware → RIO:** serial `AnalogReply` packet → `Ranger("Throttle", 0, 800, .05)` — raw counts
0800, 5% deadband, auto-ranging offset, output a CONTINUOUS Scalar; the sign is inverted
("Throttle counts BACKWARDS", `engine/MUNGA_L4/L4RIO.cpp:1374-1377`, Ranger @L4RIO.cpp:461-701).
No quantization/notching anywhere in `Ranger::Update`.
2. **Manager:** `LBE4ControlsManager::Execute` → `scalarGroup[ScalarThrottle].Update(&rioPointer->
Throttle, mode_mask)` on every AnalogReply (`L4CTRL.cpp:1379-1382`). ScalarThrottle = index 0 →
manager+0x24 (scalarGroup base 0x24, 0x20/entry; buttonGroup base 0x1c0, keyboardGroup 0x160).
3. **Streamed `.CTL` mapping (the "handled elsewhere"):** `MechRIOMapper`'s ctor @004d266c binds NO
throttle — the bind comes from the type-19 `ControlMappingStream` resource named **"L4"** (child
of the per-mech type-6 `ControlMappingsList`; installed by `BTL4APP MakeViewpointEntity` via
`CreateStreamedMappings` @0047703c). BTL4.RES "L4" record [1]:
`Scalar Throttle → subsystemID 0 (ControlsMapper slot), DirectMapping, attr 4, mask 0xffffffff`.
Attr 4 = "ThrottlePosition" @ mapper+0x11c (binary IndexEntry table @0050efd8: id 4 → offset
0x11d-1 = 0x11c, name "ThrottlePosition" @0050f28f). Reverse = record [2]: `Button Throttle1
(0x3F, on the throttle handle) → attr 6 ReverseThrust@0x124`. Turn = pedals value-bound in the
ctor (manager+0x44/+0x64 → mapper+0x1b4/+0x1b8).
4. **Interpretation:** `L4MechControlsMapper::InterpretControls` @004d196c applies the ONLY software
detent — snap to 1.0 when |t1.0| ≤ 0.05 — then `MechControlsMapper::InterpretControls` @004afd10
computes `speedDemand@0x128 = maxSpeed(mech+0x34c) × throttlePosition(0x11c) × scale(mech+0x5c0)`
(forward) or `maxSpeed × throttlePosition` (reverse flag 0x124).
**Consequence:** the original pod produced a continuously varying speedDemand while the lever moved
(updated per serial AnalogReply, NOT per render frame). There are NO "5 throttle notches" anywhere
in the software path. (Keyboard keys '1'-'5' in @004d1bf0 set controls-manager MODE masks; the
'+'/'-' pair steps a [0,5] value that drives `pow(2,x)` into mech+0x404 = HUD zoom 1×–32× — neither
is a speed setting.) The mech's `throttleState@0x4a4` writer remains un-exported (likely in the
0x4a9b5a0x4ab188 gap) — [[open-questions]].
## Multi-surface gauge path (intact, pod-only by default)
The pod multi-surface path EXISTS and is intact: `DPLRenderer::FindBestAdapterIndices` (multi-
adapter selector, honors PRIMGAUGE/SECGAUGE/MFDGAUGE/SPANDISABLE), `SVGA16::BuildWindows` (a
fullscreen D3D device + window per gauge/MFD surface, MFD span = width×2), `L4GaugeRenderer` (gated
on `L4GAUGE`). `content/SETENV.BAT` is the authentic pod env preset (L4CONTROLS=RIO,KEYBOARD;
L4GAUGE=640x480x16; L4PLASMA=com2). [T2]
## Platform profile switch
`-platform pod|dev` (or `BT_PLATFORM` env; default DEV) selects a runtime env preset WITHOUT forking
the codepath. **DEV** = keyboard + single 800×600 window. **POD** = RIO input (keyboard fallback off
serial) + multi-surface gauges (from SETENV.BAT/L4GAUGE on real hardware). `-platform pod` does NOT
auto-enable L4GAUGE (each surface needs its own fullscreen device on the pod's 2 cards). Off-pod, the
6 MFD surfaces render in a dev window via `BT_DEV_GAUGES` ([[gauges-hud]]). [T2]
## MFD surface model
All cockpit surfaces are bit-plane MASKS over ONE shared `SVGA16` pixelBuffer: `sec`=palette low
byte; `Heat`=0x4000, `Mfd2`=0x0400, `Comm`=0x8000, `Mfd1`=0x0100, `Mfd3`=0x1000; `Eng1-3` =
engineering-mode alt planes; `overlay`=0x00C0 (shares the sec surface). See [[gauges-hud]]. [T2]
## Key Relationships
- Renders: [[gauges-hud]] (the MFD surfaces), [[rendering]] (the main 3D view).
- Input: [[locomotion]] (the mapper).
- Bring-up: Phase 8 (get pod specifics from Nick — [[open-questions]]).