forza-trigger: things
This commit is contained in:
@@ -5,12 +5,20 @@
|
||||
username,
|
||||
...
|
||||
}:
|
||||
# Forza Horizon 4 / 5 → DualSense adaptive trigger bridge.
|
||||
# Forza Horizon 4 / 5 → DualSense adaptive trigger bridge (variant D, "Cosmii"
|
||||
# port). The daemon listens for Forza's fixed-format UDP "Data Out" telemetry
|
||||
# stream at 60 Hz, parses each packet via fdp (nettrom/forza_motorsport, MIT),
|
||||
# and drives the PS5 DualSense's adaptive triggers and lightbar via
|
||||
# dualsense-controller (PyPI, MIT) over hidraw.
|
||||
#
|
||||
# Forza emits a fixed-format UDP telemetry stream ("Data Out") at 60 Hz on a
|
||||
# user-configured port. We listen on that port, parse each packet via fdp
|
||||
# (nettrom/forza_motorsport, MIT), and drive the PS5 DualSense's adaptive
|
||||
# triggers via dualsense-controller (PyPI, MIT) which talks HID over hidraw.
|
||||
# Reference design: cosmii02/ForzaDSXlegacy (variant D in our taxonomy):
|
||||
# - Continuous baseline resistance on both triggers (always feels)
|
||||
# - Vibration overlay on slip events (both triggers)
|
||||
# - RPM-reactive lightbar in-race; car-class color in menus
|
||||
# - EWMA smoothing per channel
|
||||
# - No body LRA (avoids the "shakes my whole hand" complaint)
|
||||
# See forza_trigger.py module docstring for the full reference table and
|
||||
# divergences from upstream.
|
||||
#
|
||||
# Setup on the user side, once enabled here:
|
||||
# - plug the DualSense in over USB and disable Steam Input for the
|
||||
@@ -20,12 +28,20 @@
|
||||
# - in Forza, HUD options → set Data Out: ON, Data Out IP: 127.0.0.1,
|
||||
# Data Out IP Port: 5300, and (FM7 only) Data Out Packet Format: CAR DASH.
|
||||
#
|
||||
# Tuning env vars (read by the daemon at startup; values clamp to [0, 1]):
|
||||
# FORZA_L2_INTENSITY=<0..1> global L2 (brake) feel scale. default 1.0
|
||||
# FORZA_R2_INTENSITY=<0..1> global R2 (throttle) feel scale. default 1.0
|
||||
# FORZA_LIGHTBAR=<0|1> enable lightbar feedback. default 1
|
||||
# Set them in `services.forzaTrigger.environment` (an Environment= block on
|
||||
# the systemd unit) to override.
|
||||
let
|
||||
cfg = config.services.forzaTrigger;
|
||||
pythonPackages = import ./python-packages.nix { inherit lib pkgs; };
|
||||
inherit (pythonPackages) dualsense-controller fdp;
|
||||
|
||||
forzaTrigger = pkgs.writers.writePython3Bin "forza-trigger" {
|
||||
forzaTriggerSrc = ./forza_trigger.py;
|
||||
|
||||
forzaTriggerBin = pkgs.writers.writePython3Bin "forza-trigger" {
|
||||
libraries = [
|
||||
dualsense-controller
|
||||
fdp
|
||||
@@ -33,7 +49,36 @@ let
|
||||
# The wrapped binary doesn't need style enforcement — readability of
|
||||
# the source file is what matters, and that lives in forza_trigger.py.
|
||||
doCheck = false;
|
||||
} (builtins.readFile ./forza_trigger.py);
|
||||
} (builtins.readFile forzaTriggerSrc);
|
||||
|
||||
# Build-time unit tests for the haptic computation. Failure here breaks the
|
||||
# NixOS build, so deploys can't ship a daemon whose pure-function logic has
|
||||
# regressed. Tests use stdlib unittest + a FakeController; no hardware needed.
|
||||
forzaTriggerTests =
|
||||
pkgs.runCommand "forza-trigger-tests"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (_: [
|
||||
dualsense-controller
|
||||
fdp
|
||||
]))
|
||||
];
|
||||
}
|
||||
''
|
||||
cp ${forzaTriggerSrc} forza_trigger.py
|
||||
cp ${./test_forza_trigger.py} test_forza_trigger.py
|
||||
python -m unittest discover -p 'test_*.py' -v
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# The binary the system actually depends on. overrideAttrs adds the test
|
||||
# derivation as a build dependency: if the tests fail, forzaTriggerTests
|
||||
# fails to build, forzaTriggerBin's buildInputs can't be satisfied, and
|
||||
# the system build fails. This is the standard nixpkgs idiom for build-time
|
||||
# gating without ceremony around system.checks / passthru.tests.
|
||||
forzaTrigger = forzaTriggerBin.overrideAttrs (old: {
|
||||
buildInputs = (old.buildInputs or [ ]) ++ [ forzaTriggerTests ];
|
||||
});
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user