Skip to content

Commit 7247166

Browse files
author
mescon
committed
Auto-restore the rotation range after the SDK's launch-time 90-degree reset
Closes the '90 degrees on game launch' saga with an automatic fix, built on the usbmon root cause (games' SDK sessions push an operating range of 90 via a TrueForce interface-2 packet once at session start, invisible to HID++) and verified end-to-end against a faithful reproduction of the game traffic: detection to restore in under 100 ms, and the restored range holds while the session streams. Mechanism: the 20 s range poll already detects the silent change; when the external value is exactly 90 and the previous value was not, a pending restore is recorded and retried on every poll tick until it lands, strikes out, or becomes moot. Safety gates, each earned from a real incident during development: - only the known pathology (external change landing exactly on 90) is restored; any other externally-set value is a game applying its configured steering lock and is respected; - desktop mode only, never an automatic mode switch (mode churn under load is what historically desynced the centre); - the wheel must be stationary, measured with two on-demand HID++ encoder reads 50 ms apart (the cached position only updates when the wheel emits input reports, and the raw encoder's centre is wherever calibration put it, so only deltas are compared - both discovered the hard way when earlier gates deferred forever); - restores only ever widen the range, which cannot snap the wheel against new soft stops; - at most 3 restores per session, then log and yield; an explicit wheel_range write supersedes everything. New sysfs attribute wheel_range_restore (default 1; 0 = the previous detect-and-report-only behaviour). Also extracted rs50_set_range_hw from wheel_range_store for shared use, and added gate-visibility hid_dbg lines used to verify the mechanism live.
1 parent 55c5f7e commit 7247166

3 files changed

Lines changed: 304 additions & 41 deletions

File tree

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,15 @@ All effects are routed to the wheel's single direct-drive motor
146146

147147
> **Caveats:**
148148
> - Some sims (AC EVO observed) reset the wheel's rotation range to
149-
> **90° once at session start**, via the game's own SDK path. The
150-
> driver detects this within 20 seconds, corrects the reported
151-
> `wheel_range`, and logs `rotation range changed externally` in
152-
> dmesg. Recover by re-applying it from the game's pause menu:
153-
> `wheel_profile=0` then `wheel_range=<degrees>` - the re-applied
154-
> range sticks for the rest of the session (verified through full
155-
> laps). The in-game FFB gain is the master force control;
149+
> **90° once at session start**, via the game's own SDK path (a
150+
> TrueForce operating-range packet, usbmon-verified). The driver
151+
> detects this within 20 seconds and **restores your range
152+
> automatically** (`wheel_range_restore`, default on, heavily
153+
> safety-gated - see `docs/SYSFS_API.md`), logging both the
154+
> external change and the restore in dmesg. Also check the game's
155+
> own steering-rotation setting (AC EVO: "Steering lock") - once
156+
> touched and re-applied, the game pushes its configured value
157+
> itself. The in-game FFB gain is the master force control;
156158
> `wheel_strength` is the wheel-side multiplier.
157159
> - AC EVO's **map-load centring force** has once been observed ringing
158160
> the wheel into its over-torque failsafe (the base shuts itself off;

docs/SYSFS_API.md

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,40 @@ stall the force stream; it catches up within one interval of the
123123
effects stopping); if it changed externally,
124124
the reported `wheel_range` value is updated to the real one, the
125125
change is logged in dmesg (`rotation range changed externally`), and
126-
`poll()`ers on the attribute are notified via `sysfs_notify()`. The
127-
driver deliberately does NOT write the old range back on its own:
128-
re-applying range or mode while a game holds active FFB desyncs the
129-
centre on a direct-drive wheel. To recover, write `0` to
130-
`wheel_profile` and re-set `wheel_range` yourself (safe once FFB is
131-
idle, e.g. in the game's menus).
126+
`poll()`ers on the attribute are notified via `sysfs_notify()`.
127+
When the external value is exactly 90 (the known SDK session-init
128+
pathology - see `wheel_range_restore` below), the driver also
129+
restores the previous range automatically.
130+
131+
### wheel_range_restore
132+
**Access**: Read/Write
133+
**Values**: `0` or `1`
134+
**Default**: `1`
135+
136+
Automatic recovery from the launch-time 90-degree reset. Root cause
137+
(usbmon-verified): some games' SDK sessions push an operating range
138+
of 90 degrees once at session start via a TrueForce interface-2
139+
packet, invisible to HID++. With this enabled, the driver restores
140+
the pre-reset range automatically. Verified end-to-end against a
141+
faithful reproduction of the game traffic: detection to restore in
142+
under 100 ms once the poll samples the change.
143+
144+
Safety gates, each earned from a real incident:
145+
- fires only for an EXTERNAL silent change landing exactly on 90;
146+
any other externally-set value (a game applying its configured
147+
steering lock: 540, 850, ...) is respected as legitimate intent;
148+
- desktop mode only, and never an automatic mode switch;
149+
- the wheel must be stationary (two encoder reads 50 ms apart);
150+
restores only ever widen the range, which cannot snap the wheel;
151+
- at most 3 restores per session, then the driver logs and yields
152+
(`an external writer keeps changing the rotation range`);
153+
- an explicit `wheel_range` write supersedes any pending restore
154+
and resets the strike counter.
155+
156+
`0` = detect-and-report only (the pre-2026-07-03 behaviour): the
157+
change is still logged and `wheel_range` stays honest, but recovery
158+
is manual (`wheel_profile=0` then `wheel_range=<degrees>` once FFB
159+
is idle).
132160

133161
### wheel_strength
134162
**Access**: Read/Write

0 commit comments

Comments
 (0)