The legacy joystick math left the output unchanged when the raw sample was
exactly 0 - a case a jittering pot never produces, so on real hardware the hold
was invisible. vRIO's pad deadzone produces it constantly: every release of the
bench gamepad shapes the residual to exactly 0.0 and holds it there, one sample
per 55 ms poll. The calibrator held the last in-motion output against that
stream indefinitely, so the virtual pad froze off-center at whatever the stick
commanded the instant before release.
Flown, that read as a Descent 3 pod drifting on yaw and pitch with the stick
centered, stopping only when the release was slow enough to land an
intermediate sample inside the +/-5 band. It survived a full day of suspects -
the game's deadzone, its axis map, its focus handling, com0com, the serial
protocol - because every layer below the calibrator was correct: the freeze was
visible in joy.cpl itself, and the game's own control trace showed heading
latched at -0.38 while the wire carried perfect zeros.
Same divergence from the legacy port, same reasoning, as the throttle detent
fix above it: zero means centered, not "no information". Both axes; regression
tests pin the fast-release case and center stability across repeated zero
polls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Faithful port of a legacy quirk made harmful by axis routing: _throttleLast
initialized to Center and the lT==0 hold path meant the first poll at rest
compounded 16383*32 -> clamped 32766 = FULL throttle until the lever moved
past the deadzone (under the old routing this held LeftTrigger at 255 -
fire-secondary - from power-on). lT==0 now zeroes like the deadzone branch
and _throttleLast initializes to 0, the sanctioned rest value ResetAll/
ResetThrottle already used. Three regression tests replace the one that
asserted the old behavior.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The editor's L/R gauges read Rx/Ry, but EnableZR (on in real profiles)
folds the pedals into Rz and pins Rx/Ry to center, so the bars never
moved with the physical pedals. AxisCalibrator now exposes
LeftPedalOutput/RightPedalOutput (the calibrated pre-mix positions) and
RioRuntime.AxesUpdated carries an AxisReadout (the six virtual axes +
both pedals); the strip draws L/R from the pedal readouts, Z/Rz/X/Y
from the axes. With ZR off the readouts equal Rx/Ry, so nothing
changes there. Verified by screenshot: Rx/Ry centered while L=75% and
R=25% render correctly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port the analog calibration math and the plasma/VFD command set:
- Calibration/: AxisCalibrator ports UpdateThrottle/UpdatePadal/UpdateJoystick
(riovjoy2.cpp#L1504+) — throttle deadzone + ratchet field, pedal deadzones,
joystick X/Y auto-ranging from observed min/max, rudder mixing (enableZR), and
the per-axis invert flags. Stateful (start positions, last outputs, observed
extremes) like the legacy globals, with the RIOcmd axis resets. Final outputs
clamp to the documented 0..32766 range (also guards a legacy compounding quirk).
AxisOutputs carries the six values; IJoystickSink gains SetAxis(JoyAxis,value)
so calibrated axes reach the HID feeder.
- Plasma/: PlasmaCommands builds the CPlasma ESC sequences (clear/cursor/font/
attr/box draw+fill/text) + GetFontSize + the PlasmaPosText auto-fit/centering;
PlasmaDisplay writes them over the secondary COM transport.
- tests: 21 new xUnit tests (105 total) for throttle proportional/saturation/
invert, pedal ZR mix vs. direct, joystick centering/direction/invert/reset, the
output clamp, and plasma byte sequences/font sizes/auto-fit positioning.
Hardware verification of axis feel + plasma output remains; the game-specific
PlasmaScoreDraw layout is deferred to profile content (Phase 5/7).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>