Add stateful HD-rumble decoder with TinyUSB report normalization

Decode Nintendo HD-rumble words once in firmware into conventional low/high magnitudes and normalize stripped control SET_REPORT vs complete interrupt OUT reports through one path.
This commit is contained in:
Joey Yakimowich-Payne 2026-08-29 22:12:24 -06:00
commit bce94d38ce
21 changed files with 902 additions and 180 deletions

View file

@ -102,6 +102,18 @@ RUMBLE (force feedback)
-> [SDL3 haptics] -> [Any controller motors]
```
### HD rumble translation
Nintendo sends two stateful four-byte HD-rumble actuator words. Each word can carry full or relative high/low frequency and amplitude commands with up to three subsamples; amplitude uses a logarithmic curve. The Pico decodes both words once in `SwitchHapticsDecoder`, retains actuator state across packets, and reduces the result to conventional low/strong and high/weak motor magnitudes. SDL3 and Bluepad32 cannot reproduce the original linear-actuator frequencies or left/right spatial effects, but they receive the correct nonlinear band amplitudes.
The UART return frame carries the decoded result rather than raw HD-rumble bytes:
```text
0xBB, 0x02, low-frequency magnitude, high-frequency magnitude, checksum
```
The checksum is the sum of the first four bytes modulo 256. Firmware and Python bridge versions from before this change are not rumble-protocol compatible; controller input framing remains unchanged.
## Hardware wiring (Pico)
- UART1 pins (fixed in firmware):
- **TX**: GPIO4 (Pico pin 6) → RX of your USB-serial adapter.