diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index bc10f5b587c74..b44d9d1758d31 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -16,6 +16,8 @@ - [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable). +- [tiltfive](https://www.tiltfive.com/), drivers for the Tilt Five™ Glasses. + ## Backward Incompatibilities {#sec-release-23.11-incompatibilities} - `writeTextFile` now requires `executable` to be boolean, values like `null` or `""` will now fail to evaluate. diff --git a/nixos/modules/hardware/tiltfive.nix b/nixos/modules/hardware/tiltfive.nix new file mode 100644 index 0000000000000..909d319e25a43 --- /dev/null +++ b/nixos/modules/hardware/tiltfive.nix @@ -0,0 +1,94 @@ +{ pkgs, lib, config, ... }: + +with lib; +let + cfg = config.hardware.tiltfive; +in +{ + options.hardware.tiltfive = { + enable = mkEnableOption (lib.mdDoc "tiltfive driver and service"); + + user = mkOption { + type = types.str; + default = "tiltfive"; + description = lib.mdDoc "User account under which the Tilt Five driver service will run."; + }; + + group = mkOption { + type = types.str; + default = "tiltfive"; + description = lib.mdDoc "Group under which the Tilt Five driver service will run."; + }; + + dataDirectory = mkOption { + type = types.path; + default = "/var/lib/tiltfive"; + description = lib.mdDoc '' + Directory where the Tilt Five service will store persistent data, eg. + settings. Make sure it is writable. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.tiltfive = { + description = "Tilt Five Service"; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.tiltfive-driver}/bin/tiltfive-service"; + Restart = "always"; + RestartSec = 5; + + User = cfg.user; + Group = cfg.group; + + Environment = [ + # The service does not run with telemetry enabled by default, but it + # always attempts to create a telemetry database anyway. + # + # When not specified, the telemetry database defaults to being + # installation-relative, so in our case it attempts to create the + # telemetry database in the nix store. This will naturally fail. + # Setting this environment variable makes it use a different location + # for the database, leading to ugly startup errors. + "TILTFIVE_TELEMDB=${cfg.dataDirectory}/telemdb" + + # Same deal for logs. + "TILTFIVE_LOG=${cfg.dataDirectory}/log" + ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + + # We don't use udev rules from the driver package as we want to be able to + # customize the group which has access to the tiltfive devices (ie. the + # group under which the driver service runs). + services.udev.extraRules = '' + # Tilt Five glasses + SUBSYSTEMS=="usb", ATTRS{idVendor}=="32f8", ATTRS{idProduct}=="9200", GROUP="${cfg.group}" + + # Tilt Five glasses (wrong speed) + SUBSYSTEMS=="usb", ATTRS{idVendor}=="32f8", ATTRS{idProduct}=="2510", GROUP="${cfg.group}" + + # Tilt Five glasses bootloader + SUBSYSTEMS=="usb", ATTRS{idVendor}=="32f8", ATTRS{idProduct}=="424c", GROUP="${cfg.group}" + ''; + + users.users = mkIf (cfg.user == "tiltfive") { + tiltfive = { + group = cfg.group; + home = cfg.dataDirectory; + createHome = true; + isSystemUser = true; + }; + }; + + users.groups = mkIf (cfg.user == "tiltfive") { + tiltfive = {}; + }; + + environment.systemPackages = [ + pkgs.tiltfive-control-panel + ]; + }; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 83b2a45dbd3b1..0d2b436f899b4 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -86,6 +86,7 @@ ./hardware/sensor/iio.nix ./hardware/steam-hardware.nix ./hardware/system-76.nix + ./hardware/tiltfive.nix ./hardware/tuxedo-keyboard.nix ./hardware/ubertooth.nix ./hardware/uinput.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index e597a26f31bbf..2df4a2dbe2411 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -765,6 +765,7 @@ in { tigervnc = handleTest ./tigervnc.nix {}; timescaledb = handleTest ./timescaledb.nix {}; promscale = handleTest ./promscale.nix {}; + tiltfive = handleTestOn ["x86_64-linux"] ./tiltfive.nix {}; timezone = handleTest ./timezone.nix {}; tinc = handleTest ./tinc {}; tinydns = handleTest ./tinydns.nix {}; diff --git a/nixos/tests/tiltfive.nix b/nixos/tests/tiltfive.nix new file mode 100644 index 0000000000000..ff980f0318b62 --- /dev/null +++ b/nixos/tests/tiltfive.nix @@ -0,0 +1,42 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: { + name = "tiltfive"; + meta.maintainers = with lib.maintainers; [ q3k ]; + + nodes.machine = { nodes, ... }: + let user = nodes.machine.users.users.alice; + in { + imports = [ ./common/user-account.nix ./common/x11.nix ]; + + hardware.tiltfive.enable = true; + nixpkgs.config.allowUnfree = true; + + test-support.displayManager.auto.user = user.name; + environment.systemPackages = [ pkgs.xdotool ]; + }; + + enableOCR = true; + + testScript = { nodes, ... }: + let user = nodes.machine.users.users.alice; + in '' + machine.wait_for_x() + machine.wait_for_file("${user.home}/.Xauthority") + machine.succeed("xauth merge ${user.home}/.Xauthority") + + # Start the control panel without the service running and expect error + # message. This ensures that this test exercises connectivity between the + # service and the control panel. + machine.execute("systemctl stop tiltfive") + + machine.execute("su - alice -c tiltfive-control-panel >&2 &") + machine.wait_for_text("Service disconnected") + machine.screenshot("controlpanel1") + + # Now start the service and expect the wizard to start up. + machine.execute("systemctl start tiltfive") + machine.wait_for_text("Gameboard not set") + machine.screenshot("controlpanel2") + + # This is is the best we can do without emulating Tilt Five glasses :). + ''; +}) diff --git a/pkgs/games/tiltfive/control-panel.nix b/pkgs/games/tiltfive/control-panel.nix new file mode 100644 index 0000000000000..bc071158bf065 --- /dev/null +++ b/pkgs/games/tiltfive/control-panel.nix @@ -0,0 +1,67 @@ +{ stdenv +, lib +, autoPatchelfHook +, fetchurl +, nixosTests +, gtk3 +, glfw +}: + +let srcs = import ./srcs.nix { inherit fetchurl; }; in +stdenv.mkDerivation rec { + pname = "tiltfive-control-panel"; + version = srcs.version; + src = srcs.driver; + + buildInputs = [ + gtk3 glfw + ]; + + nativeBuildInputs = [ + autoPatchelfHook + ]; + + installPhase = '' + runHook preInstall + + cd tiltfive-control-panel_${version}_amd64/files/ + + dest=$out/opt/tiltfive/control-panel + pushd opt/tiltfive/control-panel + + mkdir -p $dest/data + cp -r data/* $dest/data/ + + mkdir -p $dest/lib + install -Dm755 lib/* $dest/lib/ + + install -Dm755 control_panel $dest/ + + + popd + + mkdir -p $out/share/applications + install -Dm644 usr/share/applications/${pname}.desktop -t $out/share/applications + substituteInPlace $out/share/applications/${pname}.desktop \ + --replace '/opt/tiltfive/control-panel/' "$dest/" + + mkdir -p $out/bin + ln -s $dest/control_panel $out/bin/${pname} + + cp opt/tiltfive/LICENSE* $out/ + + runHook postInstall + ''; + + passthru.tests.tiltfive = nixosTests.tiltfive; + + meta = with lib; { + description = "Tilt Five™ Glasses control panel"; + homepage = "https://docs.tiltfive.com/index.html"; + # Non-redistributable. See: LICENSE.control-panel.txt, 2.1.2. + license = with licenses; unfree; + sourceProvenance = with sourceTypes; [ binaryNativeCode ]; + maintainers = with maintainers; [ q3k ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/games/tiltfive/driver.nix b/pkgs/games/tiltfive/driver.nix new file mode 100644 index 0000000000000..349d3dac81d20 --- /dev/null +++ b/pkgs/games/tiltfive/driver.nix @@ -0,0 +1,57 @@ +{ stdenv +, lib +, autoPatchelfHook +, fetchurl +, nixosTests + +, glfw +, udev +}: + +let srcs = import ./srcs.nix { inherit fetchurl; }; in +stdenv.mkDerivation { + pname = "tiltfive-driver"; + version = srcs.version; + + srcs = srcs.driver; + + buildInputs = [ + glfw + ]; + + nativeBuildInputs = [ + autoPatchelfHook + ]; + + runtimeDependencies = [ + udev + ]; + + installPhase = '' + runHook preInstall + + cd tiltfive-service_${srcs.version}_amd64/files/ + + mkdir -p $out/bin + install -Dm755 opt/tiltfive/bin/* -t $out/bin/ + + mkdir -p $out/var/opt/tiltfive/firmware/ + install -Dm644 var/opt/tiltfive/firmware/* -t $out/var/opt/tiltfive/firmware/ + + cp opt/tiltfive/LICENSE* $out/ + + runHook postInstall + ''; + + passthru.tests.tiltfive = nixosTests.tiltfive; + + meta = with lib; { + description = "Tilt Five™ Glasses driver / userspace service"; + homepage = "https://docs.tiltfive.com/index.html"; + # Non-redistributable. See: LICENSE.service.txt, 2.1.2. + license = with licenses; unfree; + sourceProvenance = with sourceTypes; [ binaryNativeCode ]; + maintainers = with maintainers; [ q3k ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/games/tiltfive/sdk.nix b/pkgs/games/tiltfive/sdk.nix new file mode 100644 index 0000000000000..f0bf732e5daa4 --- /dev/null +++ b/pkgs/games/tiltfive/sdk.nix @@ -0,0 +1,45 @@ +{ stdenv +, lib +, autoPatchelfHook +, fetchurl +, glfw +}: + +let srcs = import ./srcs.nix { inherit fetchurl; }; in +stdenv.mkDerivation { + pname = "tiltfive-sdk"; + version = srcs.version; + + srcs = srcs.sdk; + + buildInputs = [ + glfw + ]; + + nativeBuildInputs = [ + autoPatchelfHook + ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out + + cp -rv * $out/ + + chmod 755 $out/Native/lib/linux/x86_64/libTiltFiveNative.so + chmod 755 $out/Utils/Linux/gameboard_transform + + runHook postInstall + ''; + + meta = with lib; { + description = "Tilt Five™ Glasses SDK"; + homepage = "https://docs.tiltfive.com/index.html"; + # Non-redistributable. See: license_sdk_en.txt, 2.1.2. + license = with licenses; unfree; + sourceProvenance = with sourceTypes; [ binaryNativeCode ]; + maintainers = with maintainers; [ q3k ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/games/tiltfive/srcs.nix b/pkgs/games/tiltfive/srcs.nix new file mode 100644 index 0000000000000..66ea7fc0cea74 --- /dev/null +++ b/pkgs/games/tiltfive/srcs.nix @@ -0,0 +1,14 @@ +{ fetchurl }: +rec { + version = "1.3.2"; + + driver = fetchurl { + url = "https://files.tiltfive.com/tiltfive_driver_${version}_amd64.unpacked_debs.tar.xz"; + sha256 = "sha256-MWxKqFEM6Q3gf8ik6OZk2aSFe6piTGljPOLpstJh0vA="; + }; + + sdk = fetchurl { + url = "https://files.tiltfive.com/tiltfive_sdk_${version}.tar.xz"; + sha256 = "sha256-LC3DxOOHulgYO266LdHfAS6kiOzcnG7fEON4SJkMQlU="; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e78a7e4b30fc2..5bd8fa4c14c01 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -37317,6 +37317,12 @@ with pkgs; tibia = pkgsi686Linux.callPackage ../games/tibia { }; + tiltfive-driver = callPackage ../games/tiltfive/driver.nix { }; + + tiltfive-control-panel = callPackage ../games/tiltfive/control-panel.nix { }; + + tiltfive-sdk = callPackage ../games/tiltfive/sdk.nix { }; + tintin = callPackage ../games/tintin { }; tinyfugue = callPackage ../games/tinyfugue { };