Commit Graph

5 Commits

Author SHA1 Message Date
b9cdc6a9b7 forza-trigger: stop per-packet writes between races (fix periodic clicks)
User reports periodic clicks and LED color changes on the controller
"between races". Theory: out-of-race, the run loop was calling
reset_triggers(controller) AND apply_lightbar(controller, ...) on
every Forza packet (60Hz). Even though both call sites land in
library code that nominally dedupes "same state" writes, in practice
any state change anywhere — including the lightbar dropping a green
channel value as RPM coasts down to idle — triggers a full HID OUT
report rewrite. The OUT report carries the trigger configuration too;
the controller firmware reacts on receipt and produces an audible
click each time.

Fix: out-of-race path becomes edge-triggered. On the in-race → menu
transition we run state.reset() + reset_all() once (turning both
triggers off and the lightbar to (0,0,0)). Subsequent menu packets
make no controller calls at all until in_race flips back to True.
First in-race packet then re-engages handlers and the RPM-driven
lightbar.

Side effect: the menu-mode car-class lightbar coloring is gone — the
bar stays black between races. If we want it back later, it should
be one-shot on the menu transition (NOT updated per-packet). For now
keep it simple: in-race only.

Build clean; tests unchanged (54/54 still pass — they exercise
handlers directly, not the run loop).
2026-05-07 15:00:59 -04:00
11d283585c forza-trigger: drop pedal-off early-returns (root cause of "no reaction")
Live diagnostic on yarn revealed the daemon was receiving 324-byte FH5
packets correctly (5.7MB on the systemd socket; strace showed steady
recvfrom + write to /dev/hidraw7) but writing trigger mode 0x05
(no-resistance) on nearly every tick. Cause: `accel` and `brake` are
0 most of the time during normal play (off-throttle on straight
sections, off-brake when not braking). Both handlers had:

  if accel/255 <= THROTTLE_INPUT_THRESHOLD: effect.off(); return
  if brake/255 <= BRAKE_INPUT_THRESHOLD:    effect.off(); return

Every off-pedal packet set the trigger to OFF. Brief pedal-on moments
set vibration. The result: rapidly oscillating off↔vibration state,
imperceptible at 60 Hz packet rate.

These early-returns were holdovers from the previous Race-Element 1:1
port (variant A), which IS designed to be silent unless slipping.
Variant D's whole point is "always feels something" — Cosmii has no
pedal-off gate, and its baseline branch produces feedback even at
brake=0/accel=0 with strength clamped to MIN.

Fix: remove both early-returns. Foot-off-pedal flows through the
baseline branch and produces feedback(strength=MIN_*_RESISTANCE). The
user feels light constant resistance instead of silence. Trigger only
returns to physical-rest when out-of-race (run-loop's reset_triggers).

Also drop the now-dead BRAKE_INPUT_THRESHOLD / THROTTLE_INPUT_THRESHOLD
constants. Two tests renamed and updated to assert MIN-strength
baseline feedback instead of effect.off() on zero pedal.

54/54 tests pass. Build clean.
2026-05-07 14:18:47 -04:00
03c3d01c66 forza-trigger: things 2026-05-07 01:27:49 -04:00
6501fe2ddb forza-trigger: rewrite 2026-05-04 14:47:00 -04:00
1fc2f995c7 yarn: forza dualsense adaptive trigger bridge 2026-05-03 22:47:41 -04:00