Compare commits

...

37 Commits

Author SHA1 Message Date
Luke D Jones bc46fa2b1e Prep new release 2021-03-21 21:52:30 +13:00
Luke Jones 759ddeb270 Merge branch 'fluke/vm-mode' into 'main'
Fluke/vm mode

See merge request asus-linux/asus-nb-ctrl!38
2021-03-21 08:50:23 +00:00
Luke D Jones 538e111e78 VFIO mode enabled 2021-03-21 21:50:03 +13:00
Luke D Jones 45ab568f7a Changelog update 2021-03-20 21:41:22 +13:00
Luke Jones b32089843a Merge branch 'profile_remove' into 'main'
Added --remove ability to profile subcommand

See merge request asus-linux/asus-nb-ctrl!37
2021-03-20 08:40:04 +00:00
Luke Jones d960aacf4f Merge branch 'fluke/optimising' into 'main'
Massive refactor of led control

Closes #53 and #63

See merge request asus-linux/asus-nb-ctrl!36
2021-03-20 08:30:39 +00:00
Tony Dwire 1c48ab227d Added --remove ability to profile subcommand 2021-03-19 22:24:59 -05:00
Luke D Jones 6528ec95c2 Massive refactor of led control
- Write brightness to kernel LED class path

Closes #63, #53
2021-03-20 11:58:47 +13:00
Luke Jones 53ee6015d0 Merge branch 'main' into 'main'
Added --list for profiles

See merge request asus-linux/asus-nb-ctrl!35
2021-03-17 01:50:16 +00:00
Tony ad150903af Forwarded error from ProfileProxy::profile_names instead of 'expecting' there. Handled error up in main by logging. Reorganized code in ctrl_fan_cpu to keep consistent code structure 2021-03-17 01:50:16 +00:00
Luke Jones c29afaf751 Merge branch 'fluke/optimising' into 'main'
Fluke/optimising

See merge request asus-linux/asus-nb-ctrl!34
2021-03-16 08:12:01 +00:00
Luke D Jones cec4016862 Refactored gfx switch session monitor 2021-03-16 21:09:17 +13:00
Luke Jones c697d94a00 Merge branch 'main' into 'main'
added fish completion

See merge request asus-linux/asus-nb-ctrl!32
2021-03-14 08:30:39 +00:00
Luke D Jones 35438e2e77 Move logind-zbus to own crate and publish 2021-03-13 22:07:31 +13:00
alenpaul2001 716b524d70 updated Makefile 2021-03-13 01:01:22 +05:30
alenpaul2001 cffd5672b2 added fish completion 2021-03-13 00:40:46 +05:30
Luke D Jones 82bb032336 Bump crate deps 2021-03-12 22:09:40 +13:00
Luke D Jones ae4f7f9949 Buildup of logind dbus methods 2021-03-12 22:00:31 +13:00
Luke D Jones 875ff6d354 Begin implementing logind dbus crate 2021-03-12 16:55:52 +13:00
Luke D Jones 842fa48fac Refresh sessions list every 3rd active check 2021-03-12 15:04:37 +13:00
Luke D Jones 8a63dce85f Bugfix: destroy the deref clone stackoverflow 2021-03-11 23:42:38 +13:00
Luke Jones 01386599f4 Merge branch 'fluke/hotfixing' into 'main'
Graphics switching now waits for user sessions to end

See merge request asus-linux/asus-nb-ctrl!31
2021-03-11 08:17:41 +00:00
Luke D Jones 4310b4b742 Graphics switching now waits for user sessions to end 2021-03-11 21:13:41 +13:00
Luke D Jones 89f4dd6ec4 Prep release 2021-03-11 12:32:34 +13:00
Luke Jones 85e0b79fb9 Merge branch 'fluke/testing-gfx-switch' into 'main'
More verbose and thorough checks for gfx switching

See merge request asus-linux/asus-nb-ctrl!30
2021-03-10 23:28:02 +00:00
Luke D Jones fba5f26f7e More verbose and thorough checks for gfx switching
- Small fixes
- Cleanup bios help
- g-sync warnings on toggling
2021-03-11 12:24:01 +13:00
Luke D Jones 90b0fc434d Hotfix: graphics help display 2021-03-10 21:23:35 +13:00
Luke D Jones 6743d5bc78 Add display-manager restart check 2021-03-10 18:42:44 +13:00
Luke D Jones def0259d24 Bump version 2021-03-10 16:47:22 +13:00
Luke D Jones a678f54f59 :sadface: 2021-03-10 16:45:06 +13:00
Luke D Jones ebe7e61355 Slightly change how module load error is reported 2021-03-10 16:30:42 +13:00
Luke D Jones bda58c9695 Trial of logging for gfx switch 2021-03-10 16:21:53 +13:00
Luke D Jones e335133bf8 refactor help again 2021-03-10 16:17:22 +13:00
Luke D Jones 47432524e1 Further improve CLI feedback 2021-03-10 16:01:04 +13:00
Luke D Jones 707b3bcc2d Notify on manually select profile 2021-03-10 15:24:24 +13:00
Luke D Jones 60014b8a40 Customise initial help for laptop 2021-03-10 14:43:48 +13:00
Luke D Jones 2e4ce27f6b Hotfix: try to handle module remove gracefully
Try to handle module remove more gracefully if in-use when the
display manager is shutting down
2021-03-10 14:07:08 +13:00
44 changed files with 2295 additions and 1421 deletions
+36
View File
@@ -6,6 +6,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
# [3.2.0] - 2021-03-21
### Changed
- Refactor keyboard LED handling
- Added --list for profiles (Thanks @aqez)
- Added --remove for profiles (Thanks @aqez)
- Added a graphics mode: vfio. This attaches Nvidia devices to vfio module.
### Broken
- Per-key LED modes, which need thinking about how to go ahead with for future
# [3.1.7] - 2021-03-11
### Changed
- Refactor many parts of daemon
- Switch out session monitoring to logind-zbus
# [3.1.6] - 2021-03-11
### Changed
- Graphics switching will now wait until all users logged out before switching
### Changed
- Further tweaks to gfx switching
- More logging on gfx switching
- Filter bios help according to supported modes
- Prevent gfx mode switching if in dedicated/G-Sync mode
# [3.1.4] - 2021-03-10
### Changed
- Notify through dbus if user changes profile manually
- Better help on CLI, show help only for supported items
- Bugfix to gfx switcher
# [3.1.3] - 2021-03-10
### Changed
- Hotfix: gracefully handle removing modules in use caused by display-manager not
fully shutdown at the time of trying to remove modules. It will now retry every
250ms per module
# [3.1.2] - 2021-03-10 # [3.1.2] - 2021-03-10
### Changed ### Changed
- Test and create /etc/X11/xorg.conf.d/ if it doesn't exist - Test and create /etc/X11/xorg.conf.d/ if it doesn't exist
Generated
+232 -110
View File
@@ -33,8 +33,9 @@ dependencies = [
[[package]] [[package]]
name = "asusctl" name = "asusctl"
version = "3.1.0" version = "3.1.4"
dependencies = [ dependencies = [
"daemon",
"gumdrop", "gumdrop",
"rog_dbus", "rog_dbus",
"rog_types", "rog_types",
@@ -63,6 +64,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "async-lock"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb"
dependencies = [
"event-listener",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -117,9 +127,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.2" version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "cache-padded" name = "cache-padded"
@@ -175,23 +185,23 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bae8f328835f8f5a6ceb6a7842a7f2d0c03692adb5c889347235d59194731fe3" checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"lazy_static", "lazy_static",
"loom",
] ]
[[package]] [[package]]
name = "daemon" name = "daemon"
version = "3.1.2" version = "3.2.0"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"intel-pstate", "intel-pstate",
"log", "log",
"logind-zbus",
"rog_dbus", "rog_dbus",
"rog_fan_curve", "rog_fan_curve",
"rog_types", "rog_types",
@@ -202,7 +212,7 @@ dependencies = [
"sysfs-class", "sysfs-class",
"toml", "toml",
"udev", "udev",
"zbus", "zbus 2.0.0-beta.3",
"zvariant", "zvariant",
] ]
@@ -214,7 +224,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
@@ -246,7 +256,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
@@ -272,10 +282,16 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"rustversion", "rustversion",
"syn 1.0.60", "syn 1.0.64",
"synstructure", "synstructure",
] ]
[[package]]
name = "event-listener"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.4.0" version = "1.4.0"
@@ -287,9 +303,9 @@ dependencies = [
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -302,9 +318,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@@ -312,15 +328,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@@ -329,9 +345,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
[[package]] [[package]]
name = "futures-lite" name = "futures-lite"
@@ -350,36 +366,33 @@ dependencies = [
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7"
dependencies = [ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -395,19 +408,6 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "generator"
version = "0.6.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9fed24fd1e18827652b4d55652899a1e9da8e54d91624dc3437a5bc3a9f9a9c"
dependencies = [
"cc",
"libc",
"log",
"rustversion",
"winapi",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.16" version = "0.1.16"
@@ -419,6 +419,17 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1", "wasi 0.9.0+wasi-snapshot-preview1",
] ]
[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]] [[package]]
name = "gumdrop" name = "gumdrop"
version = "0.8.0" version = "0.8.0"
@@ -436,7 +447,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
@@ -448,6 +459,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "humantime" name = "humantime"
version = "2.1.0" version = "2.1.0"
@@ -487,9 +504,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.86" version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
[[package]] [[package]]
name = "libudev-sys" name = "libudev-sys"
@@ -523,14 +540,17 @@ dependencies = [
] ]
[[package]] [[package]]
name = "loom" name = "logind-zbus"
version = "0.4.0" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d44c73b4636e497b4917eb21c33539efa3816741a2d3ff26c6316f1b529481a4" checksum = "6671f6cf88b63e9d63009f4f6f8826fcc265c51a9977e4c7dc1263d743e0dfbb"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "serde",
"generator", "serde_json",
"scoped-tls", "zbus 2.0.0-beta.3",
"zbus_macros 2.0.0-beta.3",
"zvariant",
"zvariant_derive",
] ]
[[package]] [[package]]
@@ -583,6 +603,18 @@ dependencies = [
"void", "void",
] ]
[[package]]
name = "nix"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
dependencies = [
"bitflags 1.2.1",
"cc",
"cfg-if 1.0.0",
"libc",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "5.1.2" version = "5.1.2"
@@ -595,14 +627,14 @@ dependencies = [
[[package]] [[package]]
name = "notify-rust" name = "notify-rust"
version = "4.2.2" version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a3a5dd7b4b415b112ce0fae1988f3e6dee90a96918bf3950b5f2289b19a04b" checksum = "00c16afe17474a42a59062f3409a63160c63d41985b25e9e613400685b839cb6"
dependencies = [ dependencies = [
"mac-notification-sys", "mac-notification-sys",
"serde", "serde",
"winrt-notification", "winrt-notification",
"zbus", "zbus 1.8.0",
"zvariant", "zvariant",
"zvariant_derive", "zvariant_derive",
] ]
@@ -663,9 +695,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.5.2" version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]] [[package]]
name = "parking" name = "parking"
@@ -675,9 +707,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.4" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@@ -704,6 +736,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.5" version = "0.1.5"
@@ -722,7 +760,7 @@ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
"version_check", "version_check",
] ]
@@ -773,6 +811,46 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [
"getrandom 0.2.2",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.1.57" version = "0.1.57"
@@ -785,28 +863,27 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.1.16",
"redox_syscall", "redox_syscall",
"rust-argon2", "rust-argon2",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.4.3" version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax", "regex-syntax",
"thread_local",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.22" version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]] [[package]]
name = "rog_dbus" name = "rog_dbus"
@@ -815,23 +892,23 @@ dependencies = [
"rog_fan_curve", "rog_fan_curve",
"rog_types", "rog_types",
"serde_json", "serde_json",
"zbus", "zbus 1.8.0",
"zbus_macros", "zbus_macros 1.8.0",
"zvariant", "zvariant",
] ]
[[package]] [[package]]
name = "rog_fan_curve" name = "rog_fan_curve"
version = "0.1.7" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71cfe91a717104796aeefea4e98ce5cefb11f2bb5dd10bba865dd4ae86273cb" checksum = "d083149d6e2681d05882e7ff557dec07211a6349f6de9446073b2c7dfd81e2f2"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "rog_types" name = "rog_types"
version = "3.0.0" version = "3.1.0"
dependencies = [ dependencies = [
"gumdrop", "gumdrop",
"rog_fan_curve", "rog_fan_curve",
@@ -883,29 +960,29 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.123" version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.123" version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.62" version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -920,15 +997,30 @@ checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]]
name = "sha1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "slotmap"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "smart-default" name = "smart-default"
version = "0.6.0" version = "0.6.0"
@@ -937,7 +1029,7 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
[[package]] [[package]]
@@ -980,9 +1072,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.60" version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
@@ -1006,7 +1098,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
"unicode-xid 0.2.1", "unicode-xid 0.2.1",
] ]
@@ -1028,23 +1120,13 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.44" version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi", "winapi",
] ]
@@ -1103,9 +1185,9 @@ checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]] [[package]]
name = "void" name = "void"
@@ -1127,9 +1209,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.0+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wepoll-sys" name = "wepoll-sys"
@@ -1224,13 +1306,41 @@ dependencies = [
"fastrand", "fastrand",
"futures", "futures",
"nb-connect", "nb-connect",
"nix", "nix 0.17.0",
"once_cell", "once_cell",
"polling", "polling",
"scoped-tls", "scoped-tls",
"serde", "serde",
"serde_repr", "serde_repr",
"zbus_macros", "zbus_macros 1.8.0",
"zvariant",
]
[[package]]
name = "zbus"
version = "2.0.0-beta.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e1e656194618d167524f97e88ff9bf87f2b1e8bf58f357b2a7abfdff8cc85c9"
dependencies = [
"async-io",
"async-lock",
"byteorder",
"derivative",
"enumflags2",
"event-listener",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"nix 0.19.1",
"once_cell",
"rand",
"scoped-tls",
"serde",
"serde_repr",
"sha1",
"slotmap",
"zbus_macros 2.0.0-beta.3",
"zvariant", "zvariant",
] ]
@@ -1243,14 +1353,26 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
]
[[package]]
name = "zbus_macros"
version = "2.0.0-beta.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcd4cb372bc2cade3f2323e4104112dceb6819f5dd9afa98515b4e821d232932"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
] ]
[[package]] [[package]]
name = "zvariant" name = "zvariant"
version = "2.5.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fc67d552ac18ccd9e440f062f5b32c46776f96073122a8da2fe0c533833a213" checksum = "678e7262502a135f49b1ece65010526649be7ee68acb80e1fc5377fc71fef878"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"enumflags2", "enumflags2",
@@ -1260,12 +1382,12 @@ dependencies = [
[[package]] [[package]]
name = "zvariant_derive" name = "zvariant_derive"
version = "2.5.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaee686340b5bff077d52423d8cc4f0f7cb323fe3f31ef676b8a3a2810bc53c5" checksum = "27d7c34325a35020b94343389cc9391e0f8ac245cca9155429c4022d93141241"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.60", "syn 1.0.64",
] ]
+2
View File
@@ -54,6 +54,7 @@ install:
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" $(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" $(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
$(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl" $(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl"
$(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
uninstall: uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)" rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
@@ -70,6 +71,7 @@ uninstall:
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
rm -f "$(DESTDIR)$(zshcpl)/_asusctl" rm -f "$(DESTDIR)$(zshcpl)/_asusctl"
rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
update: update:
cargo update cargo update
+5 -2
View File
@@ -30,7 +30,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if let Some(notif) = last_gfx_notif.take() { if let Some(notif) = last_gfx_notif.take() {
notif.close(); notif.close();
} }
let x = do_notif(&format!("Graphics mode changed to {}", vendor))?; let x = do_notif(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))?;
last_gfx_notif = Some(x); last_gfx_notif = Some(x);
} }
} }
@@ -67,7 +70,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
let x = do_notif(&format!( let x = do_notif(&format!(
"Keyboard LED mode changed to {}", "Keyboard LED mode changed to {}",
<&str>::from(&ledmode) ledmode.mode_name()
))?; ))?;
last_led_notif = Some(x); last_led_notif = Some(x);
} }
+2 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "asusctl" name = "asusctl"
version = "3.1.0" version = "3.1.4"
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018" edition = "2018"
@@ -11,6 +11,7 @@ edition = "2018"
serde_json = "^1.0" serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rog_types = { path = "../rog-types" } rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
gumdrop = "^0.8" gumdrop = "^0.8"
yansi-term = "^0.1" yansi-term = "^0.1"
+1 -1
View File
@@ -1,5 +1,5 @@
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout}; use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
use std::collections::LinkedList; use std::collections::LinkedList;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
+1 -1
View File
@@ -1,5 +1,5 @@
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout}; use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = AuraDbusClient::new()?;
+1 -1
View File
@@ -1,5 +1,5 @@
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout}; use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = AuraDbusClient::new()?;
+1 -1
View File
@@ -1,5 +1,5 @@
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::fancy::{Key, KeyColourArray}; use rog_types::aura_perkey::{Key, KeyColourArray};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = AuraDbusClient::new()?;
+1 -1
View File
@@ -1,5 +1,5 @@
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout}; use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = AuraDbusClient::new()?;
+330
View File
@@ -0,0 +1,330 @@
use gumdrop::Options;
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
error::AuraError,
};
use std::str::FromStr;
#[derive(Options)]
pub struct LedBrightness {
level: Option<u8>,
}
impl LedBrightness {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u8> {
self.level
}
}
impl FromStr for LedBrightness {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"off" => Ok(LedBrightness { level: Some(0x00) }),
"low" => Ok(LedBrightness { level: Some(0x01) }),
"med" => Ok(LedBrightness { level: Some(0x02) }),
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
print!("Invalid argument, must be one of: off, low, med, high");
Err(AuraError::ParseBrightness)
}
}
}
}
impl ToString for LedBrightness {
fn to_string(&self) -> String {
let s = match self.level {
Some(0x00) => "low",
Some(0x01) => "med",
Some(0x02) => "high",
_ => "unknown",
};
s.to_string()
}
}
#[derive(Debug, Clone, Options, Default)]
pub struct SingleSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Options, Default)]
pub struct SingleSpeedDirection {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the direction: up, down, left, right")]
pub direction: Direction,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Default, Options)]
pub struct SingleColour {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour: Colour,
}
#[derive(Debug, Clone, Default, Options)]
pub struct SingleColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Options, Default)]
pub struct TwoColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the first RGB value e.g, ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "", help = "set the second RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Default, Options)]
pub struct MultiColour {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour4: Colour,
}
#[derive(Debug, Clone, Default, Options)]
pub struct MultiColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour4: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
/// Byte value for setting the built-in mode.
///
/// Enum corresponds to the required integer value
#[derive(Options)]
pub enum SetAuraBuiltin {
#[options(help = "set a single static colour")]
Static(SingleColour),
#[options(help = "pulse between one or two colours")]
Breathe(TwoColourSpeed),
#[options(help = "strobe through all colours")]
Strobe(SingleSpeed),
#[options(help = "rainbow cycling in one of four directions")]
Rainbow(SingleSpeedDirection),
#[options(help = "rain pattern mimicking raindrops")]
Star(TwoColourSpeed),
#[options(help = "rain pattern of three preset colours")]
Rain(SingleSpeed),
#[options(help = "pressed keys are highlighted to fade")]
Highlight(SingleColourSpeed),
#[options(help = "pressed keys generate horizontal laser")]
Laser(SingleColourSpeed),
#[options(help = "pressed keys ripple outwards like a splash")]
Ripple(SingleColourSpeed),
#[options(help = "set a rapid pulse")]
Pulse(SingleColour),
#[options(help = "set a vertical line zooming from left")]
Comet(SingleColour),
#[options(help = "set a wide vertical line zooming from left")]
Flash(SingleColour),
#[options(help = "4-zone multi-colour")]
MultiStatic(MultiColour),
#[options(help = "4-zone multi-colour breathing")]
MultiBreathe(MultiColourSpeed),
}
impl Default for SetAuraBuiltin {
fn default() -> Self {
SetAuraBuiltin::Static(SingleColour::default())
}
}
impl From<&SingleColour> for AuraEffect {
fn from(aura: &SingleColour) -> Self {
Self {
colour1: aura.colour,
..Default::default()
}
}
}
impl From<&SingleSpeed> for AuraEffect {
fn from(aura: &SingleSpeed) -> Self {
Self {
speed: aura.speed,
..Default::default()
}
}
}
impl From<&SingleColourSpeed> for AuraEffect {
fn from(aura: &SingleColourSpeed) -> Self {
Self {
colour1: aura.colour,
speed: aura.speed,
..Default::default()
}
}
}
impl From<&TwoColourSpeed> for AuraEffect {
fn from(aura: &TwoColourSpeed) -> Self {
Self {
colour1: aura.colour,
colour2: aura.colour2,
..Default::default()
}
}
}
impl From<&SingleSpeedDirection> for AuraEffect {
fn from(aura: &SingleSpeedDirection) -> Self {
Self {
speed: aura.speed,
direction: aura.direction,
..Default::default()
}
}
}
impl From<&SetAuraBuiltin> for AuraEffect {
fn from(aura: &SetAuraBuiltin) -> Self {
match aura {
SetAuraBuiltin::Static(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Static;
data
}
SetAuraBuiltin::Breathe(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Breathe;
data
}
SetAuraBuiltin::Strobe(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Strobe;
data
}
SetAuraBuiltin::Rainbow(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Rainbow;
data
}
SetAuraBuiltin::Star(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Star;
data
}
SetAuraBuiltin::Rain(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Rain;
data
}
SetAuraBuiltin::Highlight(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Highlight;
data
}
SetAuraBuiltin::Laser(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Laser;
data
}
SetAuraBuiltin::Ripple(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Ripple;
data
}
SetAuraBuiltin::Pulse(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Pulse;
data
}
SetAuraBuiltin::Comet(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Comet;
data
}
SetAuraBuiltin::Flash(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Flash;
data
}
_ => AuraEffect::default(),
}
}
}
impl From<&SetAuraBuiltin> for Vec<AuraEffect> {
fn from(aura: &SetAuraBuiltin) -> Vec<AuraEffect> {
let mut zones = vec![AuraEffect::default(); 4];
match aura {
SetAuraBuiltin::MultiStatic(data) => {
zones[0].mode = AuraModeNum::Static;
zones[0].zone = AuraZone::One;
zones[0].colour1 = data.colour1;
zones[1].mode = AuraModeNum::Static;
zones[1].zone = AuraZone::Two;
zones[1].colour1 = data.colour2;
zones[2].mode = AuraModeNum::Static;
zones[2].zone = AuraZone::Three;
zones[2].colour1 = data.colour3;
zones[3].mode = AuraModeNum::Static;
zones[3].zone = AuraZone::Four;
zones[3].colour1 = data.colour4;
}
SetAuraBuiltin::MultiBreathe(data) => {
zones[0].mode = AuraModeNum::Breathe;
zones[0].zone = AuraZone::One;
zones[0].colour1 = data.colour1;
zones[0].speed = data.speed;
zones[1].mode = AuraModeNum::Breathe;
zones[1].zone = AuraZone::Two;
zones[1].colour1 = data.colour2;
zones[1].speed = data.speed;
zones[2].mode = AuraModeNum::Breathe;
zones[2].zone = AuraZone::Three;
zones[2].colour1 = data.colour3;
zones[2].speed = data.speed;
zones[3].mode = AuraModeNum::Breathe;
zones[3].zone = AuraZone::Four;
zones[3].colour1 = data.colour4;
zones[3].speed = data.speed;
}
_ => {}
}
zones
}
}
+282 -130
View File
@@ -1,8 +1,16 @@
mod aura_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use daemon::{
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
};
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use rog_dbus::AuraDbusClient; use rog_dbus::AuraDbusClient;
use rog_types::{ use rog_types::{
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN}, anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin}, aura_modes::{AuraEffect, AuraModeNum},
cli_options::{AniMeActions, AniMeStatusValue},
gfx_vendors::GfxVendors, gfx_vendors::GfxVendors,
profile::{FanLevel, ProfileCommand, ProfileEvent}, profile::{FanLevel, ProfileCommand, ProfileEvent},
}; };
@@ -93,19 +101,22 @@ struct AniMeCommand {
struct BiosCommand { struct BiosCommand {
#[options(help = "print help message")] #[options(help = "print help message")]
help: bool, help: bool,
#[options(meta = "", no_long, help = "toggle bios POST sound")] #[options(meta = "", no_long, help = "set bios POST sound <true/false>")]
post_sound_set: Option<bool>, post_sound_set: Option<bool>,
#[options(no_long, help = "read bios POST sound")] #[options(no_long, help = "read bios POST sound")]
post_sound_get: bool, post_sound_get: bool,
#[options(meta = "", no_long, help = "toggle GPU to/from dedicated mode")] #[options(
meta = "",
no_long,
help = "activate dGPU dedicated/G-Sync <true/false>"
)]
dedicated_gfx_set: Option<bool>, dedicated_gfx_set: Option<bool>,
#[options(no_long, help = "get GPU mode")] #[options(no_long, help = "get GPU mode")]
dedicated_gfx_get: bool, dedicated_gfx_get: bool,
} }
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut args: Vec<String> = args().collect(); let args: Vec<String> = args().skip(1).collect();
args.remove(0);
let parsed: CLIStart; let parsed: CLIStart;
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k')); let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
@@ -125,65 +136,28 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
if parsed.help_requested() { let (dbus, _) = AuraDbusClient::new()?;
// As help option don't work with `parse_args_default`
// we will call `parse_args_default_or_exit` instead let supported_tmp = dbus.proxies().supported().get_supported_functions()?;
CLIStart::parse_args_default_or_exit(); let supported = serde_json::from_str::<SupportedFunctions>(&supported_tmp)?;
if parsed.help {
print_supported_help(&supported, &parsed);
std::process::exit(1);
} }
if parsed.version { if parsed.version {
println!(" asusctl version {}", env!("CARGO_PKG_VERSION")); println!(" asusctl v{}", env!("CARGO_PKG_VERSION"));
println!(" rog-dbus version {}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!("rog-types version {}", rog_types::VERSION); println!("rog-types v{}", rog_types::VERSION);
println!(" daemon v{}", daemon::VERSION);
return Ok(());
} }
let (dbus, _) = AuraDbusClient::new()?;
match parsed.command { match parsed.command {
Some(CliCommand::LedMode(mode)) => { Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?,
if (mode.command.is_none() && !mode.prev_mode && !mode.next_mode) || mode.help { Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?,
println!("Missing arg or command\n\n{}", mode.self_usage()); Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?,
if let Some(lst) = mode.self_command_list() {
println!("\n{}", lst);
}
println!("\nHelp can also be requested on modes, e.g: static --help");
}
if mode.next_mode && mode.prev_mode {
println!("Please specify either next or previous")
}
if mode.next_mode {
dbus.proxies().led().next_led_mode()?;
} else if mode.prev_mode {
dbus.proxies().led().prev_led_mode()?;
} else if let Some(command) = mode.command {
dbus.proxies().led().set_led_mode(&command.into())?
}
}
Some(CliCommand::Profile(cmd)) => {
if (!cmd.next
&& !cmd.create
&& cmd.curve.is_none()
&& cmd.max_percentage.is_none()
&& cmd.min_percentage.is_none()
&& cmd.preset.is_none()
&& cmd.profile.is_none()
&& cmd.turbo.is_none())
|| cmd.help
{
println!("Missing arg or command\n\n{}", cmd.self_usage());
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
}
if cmd.next {
dbus.proxies().profile().next_fan()?;
} else {
dbus.proxies()
.profile()
.write_command(&ProfileEvent::Cli(cmd))?
}
}
Some(CliCommand::Graphics(cmd)) => do_gfx(cmd, &dbus)?,
Some(CliCommand::AniMe(cmd)) => { Some(CliCommand::AniMe(cmd)) => {
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help { if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help {
println!("Missing arg or command\n\n{}", cmd.self_usage()); println!("Missing arg or command\n\n{}", cmd.self_usage());
@@ -207,43 +181,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
} }
Some(CliCommand::Bios(cmd)) => { Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?,
if (cmd.dedicated_gfx_set.is_none()
&& !cmd.dedicated_gfx_get
&& cmd.post_sound_set.is_none()
&& !cmd.post_sound_get)
|| cmd.help
{
println!("Missing arg or command\n\n{}", cmd.self_usage());
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
}
if let Some(opt) = cmd.post_sound_set {
dbus.proxies().rog_bios().set_post_sound(opt)?;
}
if cmd.post_sound_get {
let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 {
true
} else {
false
};
println!("Bios POST sound on: {}", res);
}
if let Some(opt) = cmd.dedicated_gfx_set {
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?;
}
if cmd.dedicated_gfx_get {
let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
true
} else {
false
};
println!("Bios dedicated GPU on: {}", res);
println!("You must reboot your system to activate dedicated Nvidia mode");
}
}
None => { None => {
if (!parsed.show_supported if (!parsed.show_supported
&& parsed.kbd_bright.is_none() && parsed.kbd_bright.is_none()
@@ -264,13 +202,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let level = dbus.proxies().led().get_led_brightness()?; let level = dbus.proxies().led().get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string()); println!("Current keyboard led brightness: {}", level.to_string());
} }
Some(level) => dbus.proxies().led().set_brightness(level)?, Some(level) => dbus.proxies().led().set_led_brightness(level)?,
} }
} }
if parsed.show_supported { if parsed.show_supported {
let dat = dbus.proxies().supported().get_supported_functions()?; let dat = dbus.proxies().supported().get_supported_functions()?;
println!("Supported laptop functions:\n{}", dat.to_string()); println!("Supported laptop functions:\n{}", dat);
} }
if let Some(fan_level) = parsed.fan_mode { if let Some(fan_level) = parsed.fan_mode {
@@ -282,52 +220,266 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
fn do_gfx( fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) {
command: GraphicsCommand, // As help option don't work with `parse_args_default`
dbus_client: &AuraDbusClient, // we will call `parse_args_default_or_exit` instead
) -> Result<(), Box<dyn std::error::Error>> { let usage: Vec<String> = parsed.self_usage().lines().map(|s| s.to_string()).collect();
if let Some(mode) = command.mode { for line in usage.iter().filter(|line| {
println!("Changing graphics modes..."); if line.contains("--fan-mode") && !supported.fan_cpu_ctrl.stock_fan_modes {
println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`"); return false;
if do_gfx_action(
command.force,
"This will restart your display-manager. Please save all work!",
"Setting graphics mode...",
) {
dbus_client.proxies().gfx().gfx_write_mode(mode.into())?;
let res = dbus_client.gfx_wait_changed()?;
println!("{}", res);
std::process::exit(1)
} }
std::process::exit(-1) if line.contains("--chg-limit") && !supported.charge_ctrl.charge_level_set {
return false;
}
true
}) {
println!("{}", line);
}
// command strings are in order of the struct
let commands: Vec<String> = CliCommand::usage().lines().map(|s| s.to_string()).collect();
println!("\nCommands available");
for line in commands.iter().filter(|line| {
if line.contains("profile")
&& !supported.fan_cpu_ctrl.stock_fan_modes
&& !supported.fan_cpu_ctrl.fan_curve_set
{
return false;
}
if line.contains("led-mode") && supported.keyboard_led.stock_led_modes.is_none() {
return false;
}
if line.contains("bios")
&& (!supported.rog_bios_ctrl.dedicated_gfx_toggle
|| !supported.rog_bios_ctrl.post_sound_toggle)
{
return false;
}
if line.contains("anime") && !supported.anime_ctrl.0 {
return false;
}
true
}) {
println!("{}", line);
}
if !supported.fan_cpu_ctrl.stock_fan_modes {
println!("Note: Fan mode control is not supported by this laptop");
}
if !supported.charge_ctrl.charge_level_set {
println!("Note: Charge control is not supported by this laptop");
}
}
fn do_gfx(
dbus: &AuraDbusClient,
supported: &RogBiosSupportedFunctions,
command: GraphicsCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help {
println!("{}", command.self_usage());
}
if let Some(mode) = command.mode {
if supported.dedicated_gfx_toggle && dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
println!("You can not change modes until you turn dedicated/G-Sync off and reboot");
std::process::exit(-1);
}
println!("If anything fails check `journalctl -b -u asusd`\n");
dbus.proxies().gfx().gfx_write_mode(&mode).map_err(|err|{
println!("Graphics mode change error. You may be in an invalid state.");
println!("Check mode with `asusctl graphics -g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n");
err
})?;
let res = dbus.gfx_wait_changed()?;
println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
std::process::exit(0)
} }
if command.get { if command.get {
let res = dbus_client.proxies().gfx().gfx_get_mode()?; let res = dbus.proxies().gfx().gfx_get_mode()?;
println!("Current graphics mode: {}", res); println!("Current graphics mode: {}", <&str>::from(res));
} }
if command.pow { if command.pow {
let res = dbus_client.proxies().gfx().gfx_get_pwr()?; let res = dbus.proxies().gfx().gfx_get_pwr()?;
if res.contains("active") { if res.contains("active") {
println!("Current power status: {}", Red.paint(&format!("{}", res))); println!("Current power status: {}", Red.paint(&res));
} else { } else {
println!("Current power status: {}", Green.paint(&format!("{}", res))); println!("Current power status: {}", Green.paint(&res));
} }
} }
Ok(()) Ok(())
} }
fn do_gfx_action(no_confirm: bool, ask_msg: &str, ok_msg: &str) -> bool { fn handle_led_mode(
println!("{}", Red.paint(&format!("{} Continue?", ask_msg))); dbus: &AuraDbusClient,
supported: &LedSupportedFunctions,
mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if mode.command.is_none() && !mode.prev_mode && !mode.next_mode {
if !mode.help {
println!("Missing arg or command\n");
}
println!("{}\n", mode.self_usage());
println!("Commands available");
let mut buf = String::new(); let commands: Vec<String> = LedModeCommand::command_list()
.unwrap()
.lines()
.map(|s| s.to_string())
.collect();
for command in commands.iter().filter(|mode| {
if let Some(modes) = supported.stock_led_modes.as_ref() {
return modes.contains(&<AuraModeNum>::from(mode.as_str()));
}
if supported.multizone_led_mode {
return true;
}
false
}) {
println!("{}", command);
}
std::io::stdin().read_line(&mut buf).expect("Input failed"); println!("\nHelp can also be requested on modes, e.g: static --help");
let input = buf.chars().next().unwrap() as char; return Ok(());
if input == 'Y' || input == 'y' || no_confirm {
println!("{}", Green.paint(&format!("{}", ok_msg)));
return true;
} }
false
if mode.next_mode && mode.prev_mode {
println!("Please specify either next or previous");
return Ok(());
}
if mode.next_mode {
dbus.proxies().led().next_led_mode()?;
} else if mode.prev_mode {
dbus.proxies().led().prev_led_mode()?;
} else if let Some(mode) = mode.command.as_ref() {
if mode.help_requested() {
println!("{}", mode.self_usage());
return Ok(());
}
match mode {
SetAuraBuiltin::MultiStatic(_) | SetAuraBuiltin::MultiBreathe(_) => {
let zones = <Vec<AuraEffect>>::from(mode);
for eff in zones {
dbus.proxies().led().set_led_mode(&eff)?
}
}
_ => dbus
.proxies()
.led()
.set_led_mode(&<AuraEffect>::from(mode))?,
}
}
Ok(())
}
fn handle_profile(
dbus: &AuraDbusClient,
supported: &FanCpuSupportedFunctions,
cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if !cmd.next
&& !cmd.create
&& !cmd.list
&& cmd.remove.is_none()
&& cmd.curve.is_none()
&& cmd.max_percentage.is_none()
&& cmd.min_percentage.is_none()
&& cmd.fan_preset.is_none()
&& cmd.profile.is_none()
&& cmd.turbo.is_none()
{
if !cmd.help {
println!("Missing arg or command\n");
}
let usage: Vec<String> = ProfileCommand::usage()
.lines()
.map(|s| s.to_string())
.collect();
for line in usage
.iter()
.filter(|line| !line.contains("--curve") || supported.fan_curve_set)
{
println!("{}", line);
}
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
std::process::exit(1);
}
if cmd.next {
dbus.proxies().profile().next_fan()?;
} else if cmd.list {
let profile_names = dbus.proxies().profile().profile_names()?;
println!("Available profiles are {}", profile_names);
} else if let Some(profile) = &cmd.remove {
dbus.proxies().profile().remove(profile)?
} else {
dbus.proxies()
.profile()
.write_command(&ProfileEvent::Cli(cmd.clone()))?
}
Ok(())
}
fn handle_bios_option(
dbus: &AuraDbusClient,
supported: &RogBiosSupportedFunctions,
cmd: &BiosCommand,
) -> Result<(), Box<dyn std::error::Error>> {
{
if (cmd.dedicated_gfx_set.is_none()
&& !cmd.dedicated_gfx_get
&& cmd.post_sound_set.is_none()
&& !cmd.post_sound_get)
|| cmd.help
{
println!("Missing arg or command\n");
let usage: Vec<String> = BiosCommand::usage()
.lines()
.map(|s| s.to_string())
.collect();
for line in usage.iter().filter(|line| {
!(line.contains("sound") && !supported.post_sound_toggle)
|| !(line.contains("GPU") && !supported.dedicated_gfx_toggle)
}) {
println!("{}", line);
}
}
if let Some(opt) = cmd.post_sound_set {
dbus.proxies().rog_bios().set_post_sound(opt)?;
}
if cmd.post_sound_get {
let res = dbus.proxies().rog_bios().get_post_sound()? == 1;
println!("Bios POST sound on: {}", res);
}
if let Some(opt) = cmd.dedicated_gfx_set {
println!("Rebuilding initrd to include drivers");
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?;
println!("The mode change is not active until you reboot, on boot the bios will make the required change");
if opt {
println!(
"NOTE: on reboot your display manager will be forced to use Nvidia drivers"
);
} else {
println!("NOTE: after reboot you can then select regular graphics modes");
}
}
if cmd.dedicated_gfx_get {
let res = dbus.proxies().rog_bios().get_dedicated_gfx()? == 1;
println!("Bios dedicated GPU on: {}", res);
}
}
Ok(())
} }
+4 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "daemon" name = "daemon"
version = "3.1.2" version = "3.2.0"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
@@ -27,8 +27,9 @@ udev = "^0.6"
log = "^0.4" log = "^0.4"
env_logger = "^0.8" env_logger = "^0.8"
zbus = "^1.8" zbus = "^2.0.0-beta.3"
zvariant = "^2.4" zvariant = "^2.5"
logind-zbus = "*"
# serialisation # serialisation
serde = "^1.0" serde = "^1.0"
+18 -42
View File
@@ -1,6 +1,6 @@
use log::{error, info, warn}; use log::{error, info, warn};
use rog_fan_curve::Curve; use rog_fan_curve::Curve;
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors}; use rog_types::gfx_vendors::GfxVendors;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
@@ -10,6 +10,7 @@ use crate::config_old::*;
use crate::VERSION; use crate::VERSION;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Config { pub struct Config {
@@ -20,9 +21,6 @@ pub struct Config {
#[serde(skip)] #[serde(skip)]
pub curr_fan_mode: u8, pub curr_fan_mode: u8,
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraModes>,
pub power_profiles: BTreeMap<String, Profile>, pub power_profiles: BTreeMap<String, Profile>,
} }
@@ -40,9 +38,6 @@ impl Default for Config {
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()], toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0, curr_fan_mode: 0,
bat_charge_limit: 100, bat_charge_limit: 100,
kbd_led_brightness: 1,
kbd_backlight_mode: 0,
kbd_backlight_modes: Vec::new(),
power_profiles: pwr, power_profiles: pwr,
} }
} }
@@ -50,23 +45,30 @@ impl Default for Config {
impl Config { impl Config {
/// `load` will attempt to read the config, and panic if the dir is missing /// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(supported_led_modes: &[u8]) -> Self { pub fn load() -> Self {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.open(&CONFIG_PATH) .open(&CONFIG_PATH)
.expect(&format!( .unwrap_or_else(|_| {
"The file {} or directory /etc/asusd/ is missing", panic!(
CONFIG_PATH "The file {} or directory /etc/asusd/ is missing",
)); // okay to cause panic here CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new(); let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) { if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 { if read_len == 0 {
return Config::create_default(&mut file, &supported_led_modes); return Config::create_default(&mut file);
} else { } else {
if let Ok(data) = serde_json::from_str(&buf) { if let Ok(data) = serde_json::from_str(&buf) {
return data; return data;
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) { } else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) {
let config = data.into_current(); let config = data.into_current();
config.write(); config.write();
@@ -87,17 +89,11 @@ impl Config {
panic!("Please remove {} then restart asusd", CONFIG_PATH); panic!("Please remove {} then restart asusd", CONFIG_PATH);
} }
} }
Config::create_default(&mut file, &supported_led_modes) Config::create_default(&mut file)
} }
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self { fn create_default(file: &mut File) -> Self {
// create a default config here let config = Config::default();
let mut config = Config::default();
for n in supported_led_modes {
config.kbd_backlight_modes.push(AuraModes::from(*n))
}
// Should be okay to unwrap this as is since it is a Default // Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string_pretty(&config).unwrap(); let json = serde_json::to_string_pretty(&config).unwrap();
file.write_all(json.as_bytes()) file.write_all(json.as_bytes())
@@ -139,26 +135,6 @@ impl Config {
file.write_all(json.as_bytes()) file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err)); .unwrap_or_else(|err| error!("Could not write config: {}", err));
} }
pub fn set_mode_data(&mut self, mode: AuraModes) {
let byte: u8 = (&mode).into();
for (index, n) in self.kbd_backlight_modes.iter().enumerate() {
if byte == u8::from(n) {
// Consume it, OMNOMNOMNOM
self.kbd_backlight_modes[index] = mode;
break;
}
}
}
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
for mode in &self.kbd_backlight_modes {
if u8::from(mode) == num {
return Some(mode);
}
}
None
}
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
+124
View File
@@ -0,0 +1,124 @@
use crate::laptops::LaptopLedData;
use log::{error, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
#[derive(Deserialize, Serialize)]
pub struct AuraConfig {
pub brightness: u8,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl Default for AuraConfig {
fn default() -> Self {
AuraConfig {
brightness: 1,
current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(),
multizone: None,
}
}
}
impl AuraConfig {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(supported_led_modes: &LaptopLedData) -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
AURA_CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return AuraConfig::create_default(&mut file, &supported_led_modes);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
}
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
}
}
AuraConfig::create_default(&mut file, &supported_led_modes)
}
fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self {
// create a default config here
let mut config = AuraConfig::default();
for n in &support_data.standard {
config
.builtins
.insert(*n, AuraEffect::default_with_mode(*n));
}
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string(&config).unwrap();
file.write_all(json.as_bytes())
.unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("File is empty {}", AURA_CONFIG_PATH);
} else {
let x: AuraConfig = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH));
*self = x;
}
}
}
pub fn write(&self) {
let mut file = File::create(AURA_CONFIG_PATH).expect("Couldn't overwrite config");
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
/// Multipurpose, will accecpt AuraEffect with zones and put in the correct store
pub fn set_builtin(&mut self, effect: AuraEffect) {
match effect.zone() {
AuraZone::None => {
self.builtins.insert(*effect.mode(), effect);
}
_ => {
if let Some(multi) = self.multizone.as_mut() {
multi.set(effect)
}
}
}
}
pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> {
if let Some(multi) = &self.multizone {
if aura_type == AuraModeNum::Static {
return Some(multi.static_());
} else if aura_type == AuraModeNum::Breathe {
return Some(multi.breathe());
}
}
None
}
}
+38 -13
View File
@@ -1,10 +1,11 @@
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors}; use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::config::{Config, Profile}; use crate::config::{Config, Profile};
/// for parsing old v2.1.2 config /// for parsing old v2.1.2 config
#[allow(dead_code)]
#[derive(Deserialize)] #[derive(Deserialize)]
pub(crate) struct ConfigV212 { pub(crate) struct ConfigV212 {
gfx_managed: bool, gfx_managed: bool,
@@ -15,7 +16,7 @@ pub(crate) struct ConfigV212 {
power_profile: u8, power_profile: u8,
kbd_led_brightness: u8, kbd_led_brightness: u8,
kbd_backlight_mode: u8, kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>, kbd_backlight_modes: Vec<AuraEffect>,
} }
impl ConfigV212 { impl ConfigV212 {
@@ -27,15 +28,13 @@ impl ConfigV212 {
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile, curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness,
kbd_backlight_mode: self.kbd_backlight_mode,
kbd_backlight_modes: self.kbd_backlight_modes,
power_profiles: self.power_profiles, power_profiles: self.power_profiles,
} }
} }
} }
/// for parsing old v2.2.2 config /// for parsing old v2.2.2 config
#[allow(dead_code)]
#[derive(Deserialize)] #[derive(Deserialize)]
pub(crate) struct ConfigV222 { pub(crate) struct ConfigV222 {
gfx_managed: bool, gfx_managed: bool,
@@ -46,7 +45,7 @@ pub(crate) struct ConfigV222 {
power_profile: u8, power_profile: u8,
kbd_led_brightness: u8, kbd_led_brightness: u8,
kbd_backlight_mode: u8, kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>, kbd_backlight_modes: Vec<AuraEffect>,
} }
impl ConfigV222 { impl ConfigV222 {
@@ -58,14 +57,12 @@ impl ConfigV222 {
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile, curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness,
kbd_backlight_mode: self.kbd_backlight_mode,
kbd_backlight_modes: self.kbd_backlight_modes,
power_profiles: self.power_profiles, power_profiles: self.power_profiles,
} }
} }
} }
/// for parsing old v3.0.1 config
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV301 { pub(crate) struct ConfigV301 {
pub gfx_managed: bool, pub gfx_managed: bool,
@@ -78,7 +75,7 @@ pub(crate) struct ConfigV301 {
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
pub kbd_led_brightness: u8, pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8, pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraModes>, pub kbd_backlight_modes: Vec<AuraEffect>,
pub power_profiles: BTreeMap<String, Profile>, pub power_profiles: BTreeMap<String, Profile>,
} }
@@ -91,9 +88,37 @@ impl ConfigV301 {
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode, curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
kbd_led_brightness: self.kbd_led_brightness, power_profiles: self.power_profiles,
kbd_backlight_mode: self.kbd_backlight_mode, }
kbd_backlight_modes: self.kbd_backlight_modes, }
}
/// for parsing old v3.1.7 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV317 {
pub gfx_mode: GfxVendors,
pub gfx_managed: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
#[serde(skip)]
pub kbd_backlight_modes: Option<bool>,
pub power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV317 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles, power_profiles: self.power_profiles,
} }
} }
+2 -3
View File
@@ -21,7 +21,6 @@ use rog_types::{
error::AuraError, error::AuraError,
}; };
use rusb::{Device, DeviceHandle}; use rusb::{Device, DeviceHandle};
use std::convert::TryInto;
use std::error::Error; use std::error::Error;
use std::time::Duration; use std::time::Duration;
use zbus::dbus_interface; use zbus::dbus_interface;
@@ -30,7 +29,7 @@ use crate::GetSupported;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct AnimeSupportedFunctions(bool); pub struct AnimeSupportedFunctions(pub bool);
impl GetSupported for CtrlAnimeDisplay { impl GetSupported for CtrlAnimeDisplay {
type A = AnimeSupportedFunctions; type A = AnimeSupportedFunctions;
@@ -60,7 +59,7 @@ pub trait Dbus {
impl crate::ZbusAdd for CtrlAnimeDisplay { impl crate::ZbusAdd for CtrlAnimeDisplay {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/Anime".try_into().unwrap(), self) .at("/org/asuslinux/Anime", self)
.map_err(|err| { .map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err); warn!("CtrlAnimeDisplay: add_to_server {}", err);
err err
+1 -2
View File
@@ -2,7 +2,6 @@ use crate::{config::Config, error::RogError, GetSupported};
//use crate::dbus::DbusEvents; //use crate::dbus::DbusEvents;
use log::{info, warn}; use log::{info, warn};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
@@ -64,7 +63,7 @@ impl CtrlCharge {
impl crate::ZbusAdd for CtrlCharge { impl crate::ZbusAdd for CtrlCharge {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/Charge".try_into().unwrap(), self) .at("/org/asuslinux/Charge", self)
.map_err(|err| { .map_err(|err| {
warn!("CtrlCharge: add_to_server {}", err); warn!("CtrlCharge: add_to_server {}", err);
err err
+58 -5
View File
@@ -6,13 +6,12 @@ use crate::{
use log::{info, warn}; use log::{info, warn};
use rog_types::profile::{FanLevel, ProfileEvent}; use rog_types::profile::{FanLevel, ProfileEvent};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use zbus::dbus_interface; use zbus::{dbus_interface, fdo::Error};
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode"; static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
@@ -62,7 +61,12 @@ impl DbusFanAndCpu {
cfg.read(); cfg.read();
ctrl.handle_profile_event(&event, &mut cfg) ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
self.notify_profile(&cfg.active_profile).unwrap_or(()); if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
} }
} }
} }
@@ -72,6 +76,7 @@ impl DbusFanAndCpu {
fn next_profile(&mut self) { fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.do_next_profile(&mut cfg) ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) { if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
@@ -122,6 +127,54 @@ impl DbusFanAndCpu {
"Failed".to_string() "Failed".to_string()
} }
fn profile_names(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
let profile_names: String = cfg
.power_profiles
.keys()
.cloned()
.collect::<Vec<String>>()
.join(", ");
return profile_names;
}
}
"Failed".to_string()
}
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if !cfg.power_profiles.contains_key(profile) {
return Err(Error::Failed("Invalid profile specified".to_string()));
}
if cfg.power_profiles.keys().len() == 1 {
return Err(Error::Failed("Cannot delete the last profile".to_string()));
}
if cfg.active_profile == *profile {
return Err(Error::Failed(
"Cannot delete the active profile".to_string(),
));
}
cfg.power_profiles.remove(profile);
cfg.write();
return Ok(());
}
}
return Err(Error::Failed("Failed to lock configuration".to_string()));
}
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {} fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
} }
@@ -129,7 +182,7 @@ impl DbusFanAndCpu {
impl crate::ZbusAdd for DbusFanAndCpu { impl crate::ZbusAdd for DbusFanAndCpu {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self) .at("/org/asuslinux/Profile", self)
.map_err(|err| { .map_err(|err| {
warn!("DbusFanAndCpu: add_to_server {}", err); warn!("DbusFanAndCpu: add_to_server {}", err);
err err
@@ -258,7 +311,7 @@ impl CtrlFanAndCPU {
if let Some(max_perc) = command.max_percentage { if let Some(max_perc) = command.max_percentage {
profile.max_percentage = max_perc; profile.max_percentage = max_perc;
} }
if let Some(ref preset) = command.preset { if let Some(ref preset) = command.fan_preset {
profile.fan_preset = preset.into(); profile.fan_preset = preset.into();
} }
if let Some(ref curve) = command.curve { if let Some(ref curve) = command.curve {
+14 -3
View File
@@ -1,5 +1,5 @@
use std::error;
use std::fmt; use std::fmt;
use std::{error, process::ExitStatus};
use crate::error::RogError; use crate::error::RogError;
@@ -7,7 +7,9 @@ use crate::error::RogError;
pub enum GfxError { pub enum GfxError {
ParseVendor, ParseVendor,
Bus(String, std::io::Error), Bus(String, std::io::Error),
DisplayManager(String), DisplayManagerAction(String, ExitStatus),
DisplayManagerTimeout(String),
GsyncModeActive,
} }
impl fmt::Display for GfxError { impl fmt::Display for GfxError {
@@ -16,7 +18,16 @@ impl fmt::Display for GfxError {
match self { match self {
GfxError::ParseVendor => write!(f, "Could not parse vendor name"), GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error), GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
GfxError::DisplayManager(detail) => write!(f, "Display manager: {}", detail), GfxError::DisplayManagerAction(action, status) => {
write!(f, "Display-manager action {} failed: {}", action, status)
}
GfxError::DisplayManagerTimeout(state) => {
write!(f, "Timed out waiting for display-manager {} state", state)
}
GfxError::GsyncModeActive => write!(
f,
"Can not switch gfx modes when dedicated/G-Sync mode is active"
),
} }
} }
} }
+363 -135
View File
@@ -1,18 +1,25 @@
use ctrl_gfx::error::GfxError; use ctrl_gfx::error::GfxError;
use ctrl_gfx::*; use ctrl_gfx::*;
use ctrl_rog_bios::CtrlRogBios;
use log::{error, info, warn}; use log::{error, info, warn};
use rog_types::gfx_vendors::GfxVendors; use logind_zbus::{
use std::iter::FromIterator; types::{SessionClass, SessionInfo, SessionType},
use std::process::Command; ManagerProxy, SessionProxy,
use std::str::FromStr; };
use std::{io::Write, ops::Add, path::Path}; use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::mpsc;
use std::{io::Write, ops::Add, path::Path, time::Instant};
use std::{iter::FromIterator, thread::JoinHandle};
use std::{process::Command, thread::sleep, time::Duration};
use std::{sync::Arc, sync::Mutex}; use std::{sync::Arc, sync::Mutex};
use sysfs_class::{PciDevice, SysClass}; use sysfs_class::{PciDevice, SysClass};
use system::{GraphicsDevice, PciBus}; use system::{GraphicsDevice, PciBus};
use zbus::dbus_interface; use zbus::{dbus_interface, Connection};
use crate::*; use crate::*;
const THREAD_TIMEOUT_MSG: &str = "GFX: thread time exceeded 3 minutes, exiting";
pub struct CtrlGraphics { pub struct CtrlGraphics {
bus: PciBus, bus: PciBus,
_amd: Vec<GraphicsDevice>, _amd: Vec<GraphicsDevice>,
@@ -21,62 +28,56 @@ pub struct CtrlGraphics {
#[allow(dead_code)] #[allow(dead_code)]
other: Vec<GraphicsDevice>, other: Vec<GraphicsDevice>,
config: Arc<Mutex<Config>>, config: Arc<Mutex<Config>>,
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
} }
trait Dbus { trait Dbus {
fn vendor(&self) -> String; fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
fn power(&self) -> String; fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String); fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>; fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>; fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
} }
use std::convert::TryInto;
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics { impl Dbus for CtrlGraphics {
fn vendor(&self) -> String { fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
self.get_gfx_mode() self.get_gfx_mode().map_err(|err| {
.map(|gfx| gfx.into()) error!("GFX: {}", err);
.unwrap_or_else(|err| format!("Get vendor failed: {}", err)) zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
})
} }
fn power(&self) -> String { fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err)) Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
} }
fn set_vendor(&mut self, vendor: String) { fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
if let Ok(tmp) = GfxVendors::from_str(&vendor) { info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
info!("Switching gfx mode to {}", vendor); let msg = self.set_gfx_config(vendor).map_err(|err| {
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| { error!("GFX: {}", err);
error!("{}", err); zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
format!("Failed: {}", err.to_string()) })?;
}); self.notify_gfx(&vendor)
self.notify_gfx(&vendor) .unwrap_or_else(|err| warn!("GFX: {}", err));
.unwrap_or_else(|err| warn!("{}", err)); self.notify_action(&msg)
self.notify_action(&msg) .unwrap_or_else(|err| warn!("GFX: {}", err));
.unwrap_or_else(|err| warn!("{}", err)); Ok(msg)
}
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()> {} fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()> {} fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
} }
impl ZbusAdd for CtrlGraphics { impl ZbusAdd for CtrlGraphics {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at( .at("/org/asuslinux/Gfx", self)
&"/org/asuslinux/Gfx"
.try_into()
.expect("Couldn't add to zbus"),
self,
)
.map_err(|err| { .map_err(|err| {
warn!("CtrlGraphics: add_to_server {}", err); warn!("GFX: CtrlGraphics: add_to_server {}", err);
err err
}) })
.ok(); .ok();
@@ -86,7 +87,7 @@ impl ZbusAdd for CtrlGraphics {
impl Reloadable for CtrlGraphics { impl Reloadable for CtrlGraphics {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
self.auto_power()?; self.auto_power()?;
info!("Reloaded gfx mode: {:?}", self.get_gfx_mode()?); info!("GFX: Reloaded gfx mode: {:?}", self.get_gfx_mode()?);
Ok(()) Ok(())
} }
} }
@@ -95,7 +96,7 @@ impl CtrlGraphics {
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> { pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
let bus = PciBus::new()?; let bus = PciBus::new()?;
info!("Rescanning PCI bus"); info!("GFX: Rescanning PCI bus");
bus.rescan()?; bus.rescan()?;
let devs = PciDevice::all()?; let devs = PciDevice::all()?;
@@ -106,7 +107,7 @@ impl CtrlGraphics {
for func in devs.iter() { for func in devs.iter() {
if let Some(func_slot) = func.id().split('.').next() { if let Some(func_slot) = func.id().split('.').next() {
if func_slot == parent_slot { if func_slot == parent_slot {
info!("{}: Function for {}", func.id(), parent.id()); info!("GFX: {}: Function for {}", func.id(), parent.id());
functions.push(func.clone()); functions.push(func.clone());
} }
} }
@@ -124,19 +125,19 @@ impl CtrlGraphics {
if 0x03 == (c >> 16) & 0xFF { if 0x03 == (c >> 16) & 0xFF {
match dev.vendor()? { match dev.vendor()? {
0x1002 => { 0x1002 => {
info!("{}: AMD graphics", dev.id()); info!("GFX: {}: AMD graphics", dev.id());
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev))); amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
} }
0x10DE => { 0x10DE => {
info!("{}: NVIDIA graphics", dev.id()); info!("GFX: {}: NVIDIA graphics", dev.id());
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev))); nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
} }
0x8086 => { 0x8086 => {
info!("{}: Intel graphics", dev.id()); info!("GFX: {}: Intel graphics", dev.id());
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev))); intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
} }
vendor => { vendor => {
info!("{}: Other({:X}) graphics", dev.id(), vendor); info!("GFX: {}: Other({:X}) graphics", dev.id(), vendor);
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev))); other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
} }
} }
@@ -150,23 +151,31 @@ impl CtrlGraphics {
nvidia, nvidia,
other, other,
config, config,
thread_kill: Arc::new(Mutex::new(None)),
}) })
} }
fn save_gfx_mode(&self, vendor: GfxVendors) -> Result<(), RogError> { pub fn bus(&self) -> PciBus {
if let Ok(mut config) = self.config.lock() { self.bus.clone()
config.gfx_mode = vendor.clone(); }
pub fn devices(&self) -> Vec<GraphicsDevice> {
self.nvidia.clone()
}
/// Save the selected `Vendor` mode to config
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
if let Ok(mut config) = config.lock() {
config.gfx_mode = vendor;
config.write(); config.write();
return Ok(());
} }
// TODO: Error here // TODO: Error here
Ok(())
} }
/// Associated method to get which vendor mode is set /// Associated method to get which vendor mode is set
pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> { pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
if let Ok(config) = self.config.lock() { if let Ok(config) = self.config.lock() {
return Ok(config.gfx_mode.clone()); return Ok(config.gfx_mode);
} }
// TODO: Error here // TODO: Error here
Ok(GfxVendors::Hybrid) Ok(GfxVendors::Hybrid)
@@ -180,10 +189,10 @@ impl CtrlGraphics {
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> { fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
let action = if vendor == GfxVendors::Nvidia { let action = if vendor == GfxVendors::Nvidia {
info!("Enabling nvidia-fallback.service"); info!("GFX: Enabling nvidia-fallback.service");
"enable" "enable"
} else { } else {
info!("Disabling nvidia-fallback.service"); info!("GFX: Disabling nvidia-fallback.service");
"disable" "disable"
}; };
@@ -216,7 +225,7 @@ impl CtrlGraphics {
} }
let file = XORG_PATH.to_string().add(XORG_FILE); let file = XORG_PATH.to_string().add(XORG_FILE);
info!("Writing {}", file); info!("GFX: Writing {}", file);
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.create(true) .create(true)
.truncate(true) .truncate(true)
@@ -230,8 +239,40 @@ impl CtrlGraphics {
Ok(()) Ok(())
} }
fn write_modprobe_conf() -> Result<(), RogError> { fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
info!("Writing {}", MODPROBE_PATH); let mut vifo = MODPROBE_VFIO.to_vec();
for (d_count, dev) in devices.iter().enumerate() {
for (f_count, func) in dev.functions().iter().enumerate() {
let vendor = func.vendor().unwrap();
let device = func.device().unwrap();
unsafe {
vifo.append(format!("{:x}", vendor).as_mut_vec());
}
vifo.append(&mut vec![b':']);
unsafe {
vifo.append(format!("{:x}", device).as_mut_vec());
}
if f_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
if d_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
let mut conf = MODPROBE_INTEGRATED.to_vec();
conf.append(&mut vifo);
conf
}
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
info!("GFX: Writing {}", MODPROBE_PATH);
let content = match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => MODPROBE_BASE.to_vec(),
GfxVendors::Vfio => Self::get_vfio_conf(devices),
// GfxVendors::Compute => {}
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
};
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.create(true) .create(true)
@@ -240,54 +281,77 @@ impl CtrlGraphics {
.open(MODPROBE_PATH) .open(MODPROBE_PATH)
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?; .map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
file.write_all(MODPROBE_BASE) file.write_all(&content)
.and_then(|_| file.sync_all()) .and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?; .map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
Ok(()) Ok(())
} }
fn unbind_remove_nvidia(&self) -> Result<(), RogError> { fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> {
// Unbind NVIDIA graphics devices and their functions // Unbind NVIDIA graphics devices and their functions
let unbinds = self.nvidia.iter().map(|dev| dev.unbind()); let unbinds = devices.iter().map(|dev| dev.unbind());
// Remove NVIDIA graphics devices and their functions // Remove NVIDIA graphics devices and their functions
let removes = self.nvidia.iter().map(|dev| dev.remove()); let removes = devices.iter().map(|dev| dev.remove());
Result::from_iter(unbinds.chain(removes)) Result::from_iter(unbinds.chain(removes))
.map_err(|err| RogError::Command("device unbind error".into(), err))?; .map_err(|err| RogError::Command("device unbind error".into(), err))
}
Ok(()) fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> {
let unbinds = devices.iter().map(|dev| dev.unbind());
Result::from_iter(unbinds)
.map_err(|err| RogError::Command("device unbind error".into(), err))
} }
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> { fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
let mut cmd; let mut cmd = Command::new(action);
if Self::kmod_exists() {
info!("using kmod");
cmd = Command::new("kmod");
cmd.arg(action);
} else {
cmd = Command::new(action);
}
cmd.arg(driver); cmd.arg(driver);
let output = cmd let mut count = 0;
.output() const MAX_TRIES: i32 = 6;
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; loop {
if !output.status.success() { if count > MAX_TRIES {
if output.stderr.ends_with("is not currently loaded\n".as_bytes()) { let msg = format!("{} {} failed for unknown reason", action, driver);
return Ok(()) error!("GFX: {}", msg);
return Ok(()); //Err(RogError::Modprobe(msg));
} }
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr)); let output = cmd
warn!("{}", msg); .output()
warn!("It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded"); .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
return Ok(()) if !output.status.success() {
if output
.stderr
.ends_with("is not currently loaded\n".as_bytes())
{
return Ok(());
}
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
warn!(
"{} {} failed: {:?}",
action,
driver,
String::from_utf8_lossy(&output.stderr)
);
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
return Ok(());
}
if count >= MAX_TRIES {
let msg = format!(
"{} {} failed: {:?}",
action,
driver,
String::from_utf8_lossy(&output.stderr)
);
return Err(RogError::Modprobe(msg));
}
} else if output.status.success() {
return Ok(());
} }
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr));
return Err(RogError::Modprobe(msg)); count += 1;
std::thread::sleep(std::time::Duration::from_millis(250));
} }
Ok(())
} }
fn do_display_manager_action(action: &str) -> Result<(), RogError> { fn do_display_manager_action(action: &str) -> Result<(), RogError> {
@@ -303,105 +367,269 @@ impl CtrlGraphics {
"systemctl {} {} failed: {:?}", "systemctl {} {} failed: {:?}",
action, DISPLAY_MANAGER, status action, DISPLAY_MANAGER, status
); );
return Err(GfxError::DisplayManager(msg).into()); return Err(GfxError::DisplayManagerAction(msg, status).into());
} }
Ok(()) Ok(())
} }
fn wait_display_manager_inactive() -> Result<(), RogError> { fn wait_display_manager_state(state: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl"); let mut cmd = Command::new("systemctl");
cmd.arg("is-active"); cmd.arg("is-active");
cmd.arg(DISPLAY_MANAGER); cmd.arg(DISPLAY_MANAGER);
let mut count = 0; let mut count = 0;
while count <= 4 { while count <= 5 {
let output = cmd let output = cmd
.output() .output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with("inactive".as_bytes()) { if output.stdout.starts_with(state.as_bytes()) {
return Ok(()); return Ok(());
} }
std::thread::sleep(std::time::Duration::from_millis(500)); std::thread::sleep(std::time::Duration::from_millis(500));
count += 1; count += 1;
} }
return Err( Err(GfxError::DisplayManagerTimeout(state.into()).into())
GfxError::DisplayManager("display-manager did not completely stop".into()).into(),
);
} }
fn kmod_exists() -> bool { /// Determine if we need to logout/thread. Integrated<->Vfio mode does not
let mut cmd = Command::new("which"); /// require logout.
cmd.arg("kmod"); fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
if let Ok(output) = cmd if let Ok(config) = self.config.lock() {
.output() { let current = config.gfx_mode;
return output.status.success() && output.stdout.ends_with("kmod".as_bytes()) if matches!(current, GfxVendors::Integrated | GfxVendors::Vfio)
&& matches!(vendor, GfxVendors::Integrated | GfxVendors::Vfio)
{
return GfxRequiredUserAction::None;
}
} }
//Path::new("/usr/bin/kmod").exists() GfxRequiredUserAction::Logout
false
} }
pub fn do_vendor_tasks(&mut self, vendor: GfxVendors) -> Result<(), RogError> { /// Write the config changes and add/remove drivers and devices depending
Self::write_xorg_conf(vendor)?; /// on selected mode:
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup? ///
/// Tasks:
/// - write xorg config
/// - write modprobe config
/// - rescan for devices
/// + add drivers
/// + or remove drivers and devices
///
/// The daemon needs direct access to this function when it detects that the
pub fn do_vendor_tasks(
vendor: GfxVendors,
devices: &[GraphicsDevice],
bus: &PciBus,
) -> Result<(), RogError> {
// Rescan before doing remove or add drivers // Rescan before doing remove or add drivers
self.bus bus.rescan()?;
.rescan() //
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?; Self::write_xorg_conf(vendor)?;
// Write different modprobe to enable boot control to work
Self::write_modprobe_conf(vendor, devices)?;
match vendor { match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => { GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
for driver in NVIDIA_DRIVERS.iter() { for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "modprobe")?; Self::do_driver_action(driver, "modprobe")?;
} }
} }
// TODO: compute mode, needs different setup GfxVendors::Vfio => {
// GfxVendors::Compute => {}
GfxVendors::Integrated => {
for driver in NVIDIA_DRIVERS.iter() { for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?; Self::do_driver_action(driver, "rmmod")?;
} }
self.unbind_remove_nvidia()?; Self::unbind_only(&devices)?;
Self::do_driver_action("vfio-pci", "modprobe")?;
}
GfxVendors::Integrated => {
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
Self::unbind_remove_nvidia(&devices)?;
} }
} }
self.save_gfx_mode(vendor)?;
Ok(()) Ok(())
} }
/// For manually calling (not on boot/startup) fn graphical_session_alive(
/// connection: &Connection,
/// Will stop and start display manager without warning sessions: &[SessionInfo],
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> { ) -> Result<bool, RogError> {
for session in sessions {
let session_proxy = SessionProxy::new(&connection, session)?;
if session_proxy.get_class()? == SessionClass::User {
match session_proxy.get_type()? {
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
//if session_proxy.get_active()? {
return Ok(true);
//}
}
_ => {}
}
}
}
Ok(false)
}
/// Spools until all user sessions are ended then switches to requested mode
fn fire_starter(
vendor: GfxVendors,
devices: Vec<GraphicsDevice>,
bus: PciBus,
thread_stop: mpsc::Receiver<bool>,
config: Arc<Mutex<Config>>,
) -> Result<String, RogError> {
info!("GFX: display-manager thread started");
const SLEEP_PERIOD: Duration = Duration::from_millis(100);
let start_time = Instant::now();
let connection = Connection::new_system()?;
let manager = ManagerProxy::new(&connection)?;
let mut sessions = manager.list_sessions()?;
loop {
let tmp = manager.list_sessions()?;
if !tmp.iter().eq(&sessions) {
warn!("GFX: Sessions list changed");
warn!("GFX: Old list:\n{:?}\nNew list:\n{:?}", &sessions, &tmp);
sessions = tmp;
}
if !Self::graphical_session_alive(&connection, &sessions)? {
break;
}
if let Ok(stop) = thread_stop.try_recv() {
if stop {
return Ok("Graphics mode change was cancelled".into());
}
}
// exit if 3 minutes pass
if Instant::now().duration_since(start_time).as_secs() > 180 {
warn!("{}", THREAD_TIMEOUT_MSG);
return Ok(THREAD_TIMEOUT_MSG.into());
}
// Don't spin at max speed
sleep(SLEEP_PERIOD);
}
info!("GFX: all graphical user sessions ended, continuing");
Self::do_display_manager_action("stop")?; Self::do_display_manager_action("stop")?;
Self::wait_display_manager_inactive()?;
self.do_vendor_tasks(vendor)?; match Self::wait_display_manager_state("inactive") {
Ok(_) => info!("GFX: display-manager stopped"),
Err(err) => {
warn!("GFX: {}", err);
warn!("GFX: Retry stop display manager");
Self::do_display_manager_action("stop")?;
Self::wait_display_manager_state("inactive")?;
}
}
Self::do_vendor_tasks(vendor, &devices, &bus)?;
Self::do_display_manager_action("start")?; Self::do_display_manager_action("start")?;
// TODO: undo if failed? Save last mode, catch errors...
if Self::wait_display_manager_state("active").is_err() {
error!("GFX: display-manager failed to start normally, attempting restart");
Self::do_display_manager_action("restart")?;
Self::wait_display_manager_state("active")?;
}
// Save selected mode in case of reboot
Self::save_gfx_mode(vendor, config);
info!("GFX: display-manager started");
let v: &str = vendor.into(); let v: &str = vendor.into();
info!("GFX: Graphics mode changed to {} successfully", v);
Ok(format!("Graphics mode changed to {} successfully", v)) Ok(format!("Graphics mode changed to {} successfully", v))
} }
// if CtrlRogBios::has_dedicated_gfx_toggle() { fn cancel_thread(&self) {
// if let Ok(config) = self.config.clone().try_lock() { if let Ok(lock) = self.thread_kill.lock() {
// // Switch to dedicated if config says to do so if let Some(tx) = lock.as_ref() {
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia { // Cancel the running thread
// CtrlRogBios::set_gfx_mode(true) info!("GFX: Cancelling previous thread");
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err)); tx.send(true)
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() { .map_err(|err| {
// // otherwise if switching to non-Nvidia mode turn off dedicated mode warn!("GFX: {}", err);
// if ded == 1 && vendor != GfxVendors::Nvidia { })
// CtrlRogBios::set_gfx_mode(false) .ok();
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err)); }
// } }
// } }
// }
// }
/// The thread is used only in cases where a logout is required
fn setup_thread(&mut self, vendor: GfxVendors) {
let config = self.config.clone();
let devices = self.nvidia.clone();
let bus = self.bus.clone();
let (tx, rx) = mpsc::channel();
if let Ok(mut lock) = self.thread_kill.lock() {
*lock = Some(tx);
}
let killer = self.thread_kill.clone();
let _join: JoinHandle<()> = std::thread::spawn(move || {
Self::fire_starter(vendor, devices, bus, rx, config)
.map_err(|err| {
error!("GFX: {}", err);
})
.ok();
// clear the tx/rx when done
if let Ok(mut lock) = killer.try_lock() {
*lock = None;
}
});
}
/// Initiates a mode change by starting a thread that will wait until all
/// graphical sessions are exited before performing the tasks required
/// to switch modes.
///
/// For manually calling (not on boot/startup) via dbus
pub fn set_gfx_config(
&mut self,
vendor: GfxVendors,
) -> Result<GfxRequiredUserAction, RogError> {
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
if gsync == 1 {
return Err(GfxError::GsyncModeActive.into());
}
}
// Must always cancel any thread running
self.cancel_thread();
// determine which method we need here
let action_required = self.logout_required(vendor);
if matches!(action_required, GfxRequiredUserAction::Logout) {
// Yeah need the thread to check if all users are logged out
info!("GFX: mode change requires a logout to complete");
self.setup_thread(vendor);
} else {
// Okay cool, we can switch on/off vfio
info!("GFX: mode change does not require logout");
let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
}
// TODO: undo if failed? Save last mode, catch errors...
Ok(action_required)
}
/// Used only on boot to set correct mode
fn auto_power(&mut self) -> Result<(), RogError> { fn auto_power(&mut self) -> Result<(), RogError> {
let vendor = self.get_gfx_mode()?; let vendor = self.get_gfx_mode()?;
self.do_vendor_tasks(vendor)?; let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
Self::toggle_fallback_service(vendor)?; Self::toggle_fallback_service(vendor)?;
Ok(()) Ok(())
} }
+22 -2
View File
@@ -6,11 +6,21 @@ pub mod system;
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"]; const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
const VFIO_DRIVERS: [&str; 5] = [
"vfio-pci",
"vfio_iommu_type1",
"vfio_virqfd",
"vfio_mdev",
"vfio",
];
const DISPLAY_MANAGER: &str = "display-manager.service"; const DISPLAY_MANAGER: &str = "display-manager.service";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf"; const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
# If you have issues with i2c_nvidia_gpu, copy the 2 lines below to a
# new blacklist file and uncomment
#blacklist i2c_nvidia_gpu #blacklist i2c_nvidia_gpu
#alias i2c_nvidia_gpu off #alias i2c_nvidia_gpu off
blacklist nouveau blacklist nouveau
@@ -19,6 +29,17 @@ options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=1 options nvidia-drm modeset=1
"#; "#;
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
blacklist nvidia
blacklist nvidia-drm
blacklist nvidia-modeset
blacklist nouveau
alias nouveau off
"#;
static MODPROBE_VFIO: &[u8] = br#"options vfio-pci ids="#;
const XORG_FILE: &str = "90-nvidia-primary.conf"; const XORG_FILE: &str = "90-nvidia-primary.conf";
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/"; const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";
@@ -27,8 +48,7 @@ Section "OutputClass"
Identifier "nvidia" Identifier "nvidia"
MatchDriver "nvidia-drm" MatchDriver "nvidia-drm"
Driver "nvidia" Driver "nvidia"
Option "AllowEmptyInitialConfiguration" Option "AllowEmptyInitialConfiguration" "true""#;
Option "AllowExternalGpus""#;
static PRIMARY_GPU_NVIDIA: &[u8] = br#" static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#; Option "PrimaryGPU" "true""#;
+6
View File
@@ -33,6 +33,7 @@ impl Module {
} }
} }
#[derive(Clone)]
pub struct PciBus { pub struct PciBus {
path: PathBuf, path: PathBuf,
} }
@@ -56,6 +57,7 @@ impl PciBus {
} }
} }
#[derive(Clone)]
pub struct GraphicsDevice { pub struct GraphicsDevice {
_id: String, _id: String,
functions: Vec<PciDevice>, functions: Vec<PciDevice>,
@@ -70,6 +72,10 @@ impl GraphicsDevice {
self.functions.iter().any(|func| func.path().exists()) self.functions.iter().any(|func| func.path().exists())
} }
pub fn functions(&self) -> &[PciDevice] {
&self.functions
}
pub fn unbind(&self) -> Result<(), std::io::Error> { pub fn unbind(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() { for func in self.functions.iter() {
if func.path().exists() { if func.path().exists() {
+165 -192
View File
@@ -5,22 +5,20 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness"; static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
use crate::{ use crate::{
config::Config, config_aura::AuraConfig,
error::RogError, error::RogError,
laptops::{match_laptop, HELP_ADDRESS}, laptops::{match_laptop, LaptopLedData, HELP_ADDRESS},
}; };
use log::{error, info, warn}; use log::{error, info, warn};
use rog_types::{ use rog_types::{
aura_brightness_bytes, aura_modes::{AuraEffect, AuraModeNum},
aura_modes::{AuraModes, PER_KEY},
fancy::KeyColourArray,
LED_MSG_LEN, LED_MSG_LEN,
}; };
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::{convert::TryInto, path::Path};
use zbus::dbus_interface; use zbus::dbus_interface;
use crate::GetSupported; use crate::GetSupported;
@@ -29,7 +27,8 @@ use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct LedSupportedFunctions { pub struct LedSupportedFunctions {
pub brightness_set: bool, pub brightness_set: bool,
pub stock_led_modes: Option<Vec<u8>>, pub stock_led_modes: Option<Vec<AuraModeNum>>,
pub multizone_led_mode: bool,
pub per_key_led_mode: bool, pub per_key_led_mode: bool,
} }
@@ -39,21 +38,20 @@ impl GetSupported for CtrlKbdBacklight {
fn get_supported() -> Self::A { fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode)); // let mode = <&str>::from(&<AuraModes>::from(*mode));
let mut stock_led_modes = None; let mut stock_led_modes = None;
let mut per_key_led_mode = false; let multizone_led_mode = false;
let per_key_led_mode = false;
if let Some(laptop) = match_laptop() { if let Some(laptop) = match_laptop() {
let modes = laptop.supported_modes().to_vec(); stock_led_modes = if laptop.supported_modes().standard.is_empty() {
if modes.contains(&PER_KEY) { None
per_key_led_mode = true;
let modes = modes.iter().filter(|x| **x != PER_KEY).copied().collect();
stock_led_modes = Some(modes);
} else { } else {
stock_led_modes = Some(modes); Some(laptop.supported_modes().standard.clone())
} };
} }
LedSupportedFunctions { LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(), brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
stock_led_modes, stock_led_modes,
multizone_led_mode,
per_key_led_mode, per_key_led_mode,
} }
} }
@@ -64,9 +62,9 @@ pub struct CtrlKbdBacklight {
#[allow(dead_code)] #[allow(dead_code)]
kbd_node: Option<String>, kbd_node: Option<String>,
pub bright_node: String, pub bright_node: String,
supported_modes: Vec<u8>, supported_modes: LaptopLedData,
flip_effect_write: bool, flip_effect_write: bool,
config: Arc<Mutex<Config>>, config: AuraConfig,
} }
pub struct DbusKbdBacklight { pub struct DbusKbdBacklight {
@@ -88,7 +86,7 @@ trait Dbus {
impl crate::ZbusAdd for DbusKbdBacklight { impl crate::ZbusAdd for DbusKbdBacklight {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/Led".try_into().unwrap(), self) .at("/org/asuslinux/Led", self)
.map_err(|err| { .map_err(|err| {
error!("DbusKbdBacklight: add_to_server {}", err); error!("DbusKbdBacklight: add_to_server {}", err);
}) })
@@ -96,48 +94,42 @@ impl crate::ZbusAdd for DbusKbdBacklight {
} }
} }
/// The main interface for changing, reading, or notfying signals
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusKbdBacklight { impl DbusKbdBacklight {
fn set_led_mode(&mut self, data: String) { fn set_brightness(&mut self, brightness: u8) {
if let Ok(data) = serde_json::from_str(&data) { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut ctrl) = self.inner.try_lock() { ctrl.set_brightness(brightness)
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { .map_err(|err| warn!("{}", err))
match &data { .ok();
AuraModes::PerKey(_) => { }
ctrl.do_command(data, &mut cfg) }
.unwrap_or_else(|err| warn!("{}", err));
} fn set_led_mode(&mut self, effect: AuraEffect) {
_ => { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(json) = serde_json::to_string(&data) { let mode_name = effect.mode_name();
match ctrl.do_command(data, &mut cfg) { match ctrl.do_command(effect) {
Ok(_) => { Ok(_) => {
self.notify_led(&json).ok(); self.notify_led(&mode_name).ok();
} }
Err(err) => { Err(err) => {
warn!("{}", err); warn!("{}", err);
}
}
}
}
}
} }
} }
} else {
warn!("SetKeyBacklight could not deserialise");
} }
} }
fn next_led_mode(&self) { fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { ctrl.toggle_mode(false)
ctrl.toggle_mode(false, &mut cfg) .unwrap_or_else(|err| warn!("{}", err));
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) { if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json) self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
}
} }
} }
} }
@@ -145,40 +137,24 @@ impl DbusKbdBacklight {
fn prev_led_mode(&self) { fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { ctrl.toggle_mode(true)
ctrl.toggle_mode(true, &mut cfg) .unwrap_or_else(|err| warn!("{}", err));
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) { if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json) self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
}
} }
} }
} }
} }
/// Return the current mode data /// Return the current mode data
#[dbus_interface(property)]
fn led_mode(&self) -> String { fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) { if let Ok(json) = serde_json::to_string(&mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
if let Ok(json) = serde_json::to_string(&cfg.kbd_backlight_modes) {
return json; return json;
} }
} }
@@ -187,14 +163,25 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string() "SetKeyBacklight could not deserialise".to_string()
} }
/// Return the current LED brightness /// Return a list of available modes
fn led_brightness(&self) -> i8 { #[dbus_interface(property)]
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() { if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return cfg.kbd_led_brightness as i8; return json;
} }
} }
warn!("SetKeyBacklight could not deserialise"); warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not serialise".to_string()
}
/// Return the current LED brightness
#[dbus_interface(property)]
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
}
warn!("SetKeyBacklight could not serialise");
-1 -1
} }
@@ -205,44 +192,40 @@ impl DbusKbdBacklight {
impl crate::Reloadable for CtrlKbdBacklight { impl crate::Reloadable for CtrlKbdBacklight {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
// set current mode (if any) // set current mode (if any)
if let Ok(mut config) = self.config.clone().try_lock() { if self.supported_modes.standard.len() > 1 {
if self.supported_modes.len() > 1 { let current_mode = self.config.current_mode;
if self.supported_modes.contains(&config.kbd_backlight_mode) { if self.supported_modes.standard.contains(&(current_mode)) {
let mode = config let mode = self
.get_led_mode_data(config.kbd_backlight_mode) .config
.ok_or(RogError::NotSupported)? .builtins
.to_owned(); .get(&current_mode)
self.write_mode(&mode)?; .ok_or(RogError::NotSupported)?
info!("Reloaded last used mode"); .to_owned();
} else { self.write_mode(&mode)?;
warn!( info!("Reloaded last used mode");
"An unsupported mode was set: {}, reset to first mode available", } else {
<&str>::from(&<AuraModes>::from(config.kbd_backlight_mode)) warn!(
); "An unsupported mode was set: {}, reset to first mode available",
for (idx, mode) in config.kbd_backlight_modes.iter_mut().enumerate() { <&str>::from(&self.config.current_mode)
if !self.supported_modes.contains(&mode.into()) { );
config.kbd_backlight_modes.remove(idx); self.config.builtins.remove(&current_mode);
config.write(); self.config.current_mode = AuraModeNum::Static;
break; // TODO: do a recursive call with a boxed dyn future later
} let mode = self
} .config
config.kbd_backlight_mode = self.supported_modes[0]; .builtins
// TODO: do a recursive call with a boxed dyn future later .get(&current_mode)
let mode = config .ok_or(RogError::NotSupported)?
.get_led_mode_data(config.kbd_backlight_mode) .to_owned();
.ok_or(RogError::NotSupported)? self.write_mode(&mode)?;
.to_owned(); info!("Reloaded last used mode");
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
} }
// Reload brightness
let bright = config.kbd_led_brightness;
let bytes = aura_brightness_bytes(bright);
self.write_bytes(&bytes)?;
info!("Reloaded last used brightness");
} }
// Reload brightness
let bright = self.config.brightness;
self.set_brightness(bright)?;
info!("Reloaded last used brightness");
Ok(()) Ok(())
} }
} }
@@ -262,12 +245,10 @@ impl crate::CtrlTask for CtrlKbdBacklight {
file.read_exact(&mut buf) file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?; .map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) { if let Some(num) = char::from(buf[0]).to_digit(10) {
if let Ok(mut config) = self.config.clone().try_lock() { if self.config.brightness != num as u8 {
if config.kbd_led_brightness != num as u8 { self.config.read();
config.read(); self.config.brightness = num as u8;
config.kbd_led_brightness = num as u8; self.config.write();
config.write();
}
} }
return Ok(()); return Ok(());
} }
@@ -280,8 +261,8 @@ impl CtrlKbdBacklight {
pub fn new( pub fn new(
id_product: &str, id_product: &str,
condev_iface: Option<&String>, condev_iface: Option<&String>,
supported_modes: Vec<u8>, supported_modes: LaptopLedData,
config: Arc<Mutex<Config>>, config: AuraConfig,
) -> Result<Self, RogError> { ) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None // TODO: return error if *all* nodes are None
let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else( let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else(
@@ -334,6 +315,37 @@ impl CtrlKbdBacklight {
} }
} }
pub fn get_brightness(&self) -> Result<u8, RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(buf[0])
}
pub fn set_brightness(&self, brightness: u8) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.write(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
file.write_all(&[brightness])
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(())
}
fn get_node_failover( fn get_node_failover(
id_product: &str, id_product: &str,
iface: Option<&String>, iface: Option<&String>,
@@ -432,8 +444,8 @@ impl CtrlKbdBacklight {
)) ))
} }
pub fn do_command(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> { pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.set_and_save(mode, config) self.set_and_save(mode)
} }
/// Should only be used if the bytes you are writing are verified correct /// Should only be used if the bytes you are writing are verified correct
@@ -470,100 +482,61 @@ impl CtrlKbdBacklight {
/// ///
/// This needs to be universal so that settings applied by dbus stick /// This needs to be universal so that settings applied by dbus stick
#[inline] #[inline]
fn set_and_save(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> { fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> {
match mode { self.config.read();
AuraModes::LedBrightness(n) => { self.write_mode(&mode)?;
let bytes: [u8; LED_MSG_LEN] = (&mode).into(); self.config.current_mode = *mode.mode();
self.write_bytes(&bytes)?; self.config.set_builtin(mode);
config.read(); self.config.write();
config.kbd_led_brightness = n;
config.write();
info!("LED brightness set to {:#?}", n);
}
AuraModes::PerKey(v) => {
if v.is_empty() || v[0].is_empty() {
let bytes = KeyColourArray::get_init_msg();
self.write_bytes(&bytes)?;
} else {
self.write_effect(&v)?;
}
}
_ => {
config.read();
let mode_num: u8 = u8::from(&mode);
self.write_mode(&mode)?;
config.kbd_backlight_mode = mode_num;
config.set_mode_data(mode);
config.write();
}
}
Ok(()) Ok(())
} }
#[inline] #[inline]
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> { fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> {
let current = config.kbd_backlight_mode; let current = self.config.current_mode;
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) { if let Some(idx) = self
.supported_modes
.standard
.iter()
.position(|v| *v == current)
{
let mut idx = idx; let mut idx = idx;
// goes past end of array // goes past end of array
if reverse { if reverse {
if idx == 0 { if idx == 0 {
idx = self.supported_modes.len() - 1; idx = self.supported_modes.standard.len() - 1;
} else { } else {
idx -= 1; idx -= 1;
} }
} else { } else {
idx += 1; idx += 1;
if idx == self.supported_modes.len() { if idx == self.supported_modes.standard.len() {
idx = 0; idx = 0;
} }
} }
let next = self.supported_modes[idx]; let next = self.supported_modes.standard[idx];
config.read(); self.config.read();
if let Some(data) = config.get_led_mode_data(next) { if let Some(data) = self.config.builtins.get(&next) {
self.write_mode(&data)?; self.write_mode(&data)?;
config.kbd_backlight_mode = next; self.config.current_mode = next;
} }
config.write(); self.config.write();
} }
Ok(()) Ok(())
} }
#[inline] #[inline]
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> { fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> {
let mode_num: u8 = u8::from(mode); if !self.supported_modes.standard.contains(&mode.mode()) {
if !self.supported_modes.contains(&mode_num) {
return Err(RogError::NotSupported); return Err(RogError::NotSupported);
} }
match mode { let bytes: [u8; LED_MSG_LEN] = mode.into();
AuraModes::PerKey(v) => { self.write_bytes(&bytes)?;
if v.is_empty() || v[0].is_empty() { self.write_bytes(&LED_SET)?;
let bytes = KeyColourArray::get_init_msg(); // Changes won't persist unless apply is set
self.write_bytes(&bytes)?; self.write_bytes(&LED_APPLY)?;
} else {
self.write_effect(v)?;
}
}
AuraModes::MultiStatic(_) | AuraModes::MultiBreathe(_) => {
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
for array in bytes.iter() {
self.write_bytes(array)?;
}
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
return Ok(());
}
_ => {
let bytes: [u8; LED_MSG_LEN] = mode.into();
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
}
}
Ok(()) Ok(())
} }
} }
+5 -6
View File
@@ -2,12 +2,12 @@ use crate::{config::Config, error::RogError, GetSupported};
use log::{error, info, warn}; use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::BufRead;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::{convert::TryInto, io::BufRead};
use zbus::dbus_interface; use zbus::dbus_interface;
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs"; const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
@@ -101,7 +101,7 @@ impl CtrlRogBios {
impl crate::ZbusAdd for CtrlRogBios { impl crate::ZbusAdd for CtrlRogBios {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/RogBios".try_into().unwrap(), self) .at("/org/asuslinux/RogBios", self)
.map_err(|err| { .map_err(|err| {
warn!("CtrlRogBios: add_to_server {}", err); warn!("CtrlRogBios: add_to_server {}", err);
err err
@@ -136,9 +136,7 @@ impl CtrlRogBios {
} }
} }
Ok(CtrlRogBios { Ok(CtrlRogBios { _config: config })
_config: config,
})
} }
fn set_path_mutable(path: &str) -> Result<(), RogError> { fn set_path_mutable(path: &str) -> Result<(), RogError> {
@@ -271,6 +269,7 @@ impl CtrlRogBios {
} else if Path::new(DRACUT_PATH).exists() { } else if Path::new(DRACUT_PATH).exists() {
let mut cmd = Command::new("dracut"); let mut cmd = Command::new("dracut");
cmd.arg("-f"); cmd.arg("-f");
cmd.arg("-q");
initfs_cmd = Some(cmd); initfs_cmd = Some(cmd);
info!("Using initramfs update command 'dracut'"); info!("Using initramfs update command 'dracut'");
} }
@@ -335,7 +334,7 @@ impl CtrlRogBios {
.map_err(|err| RogError::Write(format!("{:?}", cmd), err))?; .map_err(|err| RogError::Write(format!("{:?}", cmd), err))?;
if !status.success() { if !status.success() {
error!("Ram disk update failed"); error!("Ram disk update failed");
return Err(RogError::Initramfs("Ram disk update failed".into()).into()); return Err(RogError::Initramfs("Ram disk update failed".into()));
} else { } else {
info!("Successfully updated initramfs"); info!("Successfully updated initramfs");
} }
+6 -8
View File
@@ -1,5 +1,3 @@
use std::convert::TryInto;
use log::warn; use log::warn;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface; use zbus::dbus_interface;
@@ -15,11 +13,11 @@ use crate::{
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct SupportedFunctions { pub struct SupportedFunctions {
anime_ctrl: AnimeSupportedFunctions, pub anime_ctrl: AnimeSupportedFunctions,
charge_ctrl: ChargeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions,
fan_cpu_ctrl: FanCpuSupportedFunctions, pub fan_cpu_ctrl: FanCpuSupportedFunctions,
keyboard_led: LedSupportedFunctions, pub keyboard_led: LedSupportedFunctions,
rog_bios_ctrl: RogBiosSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions,
} }
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
@@ -32,7 +30,7 @@ impl SupportedFunctions {
impl crate::ZbusAdd for SupportedFunctions { impl crate::ZbusAdd for SupportedFunctions {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server server
.at(&"/org/asuslinux/Supported".try_into().unwrap(), self) .at("/org/asuslinux/Supported", self)
.map_err(|err| { .map_err(|err| {
warn!("SupportedFunctions: add_to_server {}", err); warn!("SupportedFunctions: add_to_server {}", err);
err err
+14 -18
View File
@@ -1,10 +1,10 @@
use daemon::ctrl_charge::CtrlCharge;
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu}; use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight}; use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::laptops::match_laptop; use daemon::laptops::match_laptop;
use daemon::{ use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
}; };
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics}; use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
use daemon::{CtrlTask, Reloadable, ZbusAdd}; use daemon::{CtrlTask, Reloadable, ZbusAdd};
@@ -19,7 +19,6 @@ use std::sync::Mutex;
use daemon::ctrl_rog_bios::CtrlRogBios; use daemon::ctrl_rog_bios::CtrlRogBios;
use std::convert::Into; use std::convert::Into;
use std::convert::TryInto;
use zbus::fdo; use zbus::fdo;
use zbus::Connection; use zbus::Connection;
@@ -51,12 +50,9 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
print_board_info(); print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap()); println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let laptop = match_laptop(); let config = Config::load();
let config = if let Some(laptop) = laptop.as_ref() { let enable_gfx_switching = config.gfx_managed;
Config::load(laptop.supported_modes()) let config = Arc::new(Mutex::new(config));
} else {
Config::load(&[])
};
let connection = Connection::new_system()?; let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)? fdo::DBusProxy::new(&connection)?
@@ -65,9 +61,6 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
supported.add_to_server(&mut object_server); supported.add_to_server(&mut object_server);
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
match CtrlRogBios::new(config.clone()) { match CtrlRogBios::new(config.clone()) {
Ok(mut ctrl) => { Ok(mut ctrl) => {
// Do a reload of any settings // Do a reload of any settings
@@ -111,9 +104,10 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() { if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(vendor) = ctrl.get_gfx_mode() { if let Ok(vendor) = ctrl.get_gfx_mode() {
if ded == 1 && vendor != GfxVendors::Nvidia { if ded == 1 && vendor != GfxVendors::Nvidia {
error!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
error!("You must reboot to enable Nvidia driver"); let devices = ctrl.devices();
ctrl.do_vendor_tasks(GfxVendors::Nvidia)?; let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks(GfxVendors::Nvidia, &devices, &bus)?;
} else if ded == 0 { } else if ded == 0 {
info!("Dedicated GFX toggle is off"); info!("Dedicated GFX toggle is off");
} }
@@ -133,7 +127,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
// Collect tasks for task thread // Collect tasks for task thread
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new(); let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config.clone()).map_err(|err| { if let Ok(mut ctrl) = CtrlFanAndCPU::new(config).map_err(|err| {
error!("Profile control: {}", err); error!("Profile control: {}", err);
}) { }) {
ctrl.reload() ctrl.reload()
@@ -142,12 +136,14 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server); DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
}; };
if let Some(laptop) = laptop { if let Some(laptop) = match_laptop() {
let aura_config = AuraConfig::load(laptop.supported_modes());
if let Ok(ctrl) = CtrlKbdBacklight::new( if let Ok(ctrl) = CtrlKbdBacklight::new(
laptop.usb_product(), laptop.usb_product(),
laptop.condev_iface(), laptop.condev_iface(),
laptop.supported_modes().to_owned(), laptop.supported_modes().to_owned(),
config, aura_config,
) )
.map_err(|err| { .map_err(|err| {
error!("Keyboard control: {}", err); error!("Keyboard control: {}", err);
@@ -179,7 +175,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}); });
object_server object_server
.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| { .with("/org/asuslinux/Charge", |obj: &CtrlCharge| {
let x = obj.limit(); let x = obj.limit();
obj.notify_charge(x as u8) obj.notify_charge(x as u8)
}) })
+16
View File
@@ -28,6 +28,8 @@ pub enum RogError {
Initramfs(String), Initramfs(String),
Modprobe(String), Modprobe(String),
Command(String, std::io::Error), Command(String, std::io::Error),
Io(std::io::Error),
Zbus(zbus::Error),
} }
impl fmt::Display for RogError { impl fmt::Display for RogError {
@@ -54,6 +56,8 @@ impl fmt::Display for RogError {
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error), RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
} }
} }
} }
@@ -79,3 +83,15 @@ impl From<GraphicsError> for RogError {
} }
} }
} }
impl From<zbus::Error> for RogError {
fn from(err: zbus::Error) -> Self {
RogError::Zbus(err)
}
}
impl From<std::io::Error> for RogError {
fn from(err: std::io::Error) -> Self {
RogError::Io(err)
}
}
+41 -39
View File
@@ -1,20 +1,19 @@
use log::{info, warn}; use log::{info, warn};
use rog_types::aura_modes::{AuraModes, BREATHING, STATIC}; use rog_types::aura_modes::AuraModeNum;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Read; use std::io::Read;
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml"; pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl"; pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6]; static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6];
/// A helper of sorts specifically for functions tied to laptop models
#[derive(Debug)] #[derive(Debug)]
pub struct LaptopBase { pub struct LaptopBase {
usb_product: String, usb_product: String,
condev_iface: Option<String>, // required for finding the Consumer Device interface condev_iface: Option<String>, // required for finding the Consumer Device interface
supported_modes: Vec<u8>, led_support: LaptopLedData,
} }
impl LaptopBase { impl LaptopBase {
@@ -24,8 +23,8 @@ impl LaptopBase {
pub fn condev_iface(&self) -> Option<&String> { pub fn condev_iface(&self) -> Option<&String> {
self.condev_iface.as_ref() self.condev_iface.as_ref()
} }
pub fn supported_modes(&self) -> &[u8] { pub fn supported_modes(&self) -> &LaptopLedData {
&self.supported_modes &self.led_support
} }
} }
@@ -34,21 +33,16 @@ pub fn match_laptop() -> Option<LaptopBase> {
let device_desc = device let device_desc = device
.device_descriptor() .device_descriptor()
.expect("Couldn't get device descriptor"); .expect("Couldn't get device descriptor");
if device_desc.vendor_id() == 0x0b05 { if device_desc.vendor_id() == 0x0b05 && LAPTOP_DEVICES.contains(&device_desc.product_id()) {
if LAPTOP_DEVICES.contains(&device_desc.product_id()) { let prod_str = format!("{:x?}", device_desc.product_id());
let prod_str = format!("{:x?}", device_desc.product_id());
if device_desc.product_id() == 0x1854 { if device_desc.product_id() == 0x1854 {
let mut laptop = laptop(prod_str, None); let laptop = laptop(prod_str, None);
if laptop.supported_modes.is_empty() {
laptop.supported_modes = vec![STATIC, BREATHING];
}
return Some(laptop);
}
let laptop = laptop(prod_str, Some("02".to_owned()));
return Some(laptop); return Some(laptop);
} }
let laptop = laptop(prod_str, Some("02".to_owned()));
return Some(laptop);
} }
} }
warn!( warn!(
@@ -67,12 +61,18 @@ fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
let mut laptop = LaptopBase { let mut laptop = LaptopBase {
usb_product: prod, usb_product: prod,
condev_iface, condev_iface,
supported_modes: vec![], led_support: LaptopLedData {
board_names: vec![],
prod_family: String::new(),
standard: vec![],
multizone: false,
per_key: false,
},
}; };
if let Some(modes) = LEDModeGroup::load_from_config() { if let Some(modes) = LedSupportFile::load_from_config() {
if let Some(led_modes) = modes.matcher(&prod_family, &board_name) { if let Some(led_modes) = modes.matcher(&prod_family, &board_name) {
laptop.supported_modes = led_modes; laptop.led_support = led_modes;
return laptop; return laptop;
} }
} }
@@ -94,7 +94,7 @@ pub fn print_modes(supported_modes: &[u8]) {
if !supported_modes.is_empty() { if !supported_modes.is_empty() {
info!("Supported Keyboard LED modes are:"); info!("Supported Keyboard LED modes are:");
for mode in supported_modes { for mode in supported_modes {
let mode = <&str>::from(&<AuraModes>::from(*mode)); let mode = <&str>::from(&<AuraModeNum>::from(*mode));
info!("- {}", mode); info!("- {}", mode);
} }
info!( info!(
@@ -107,19 +107,28 @@ pub fn print_modes(supported_modes: &[u8]) {
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct LEDModeGroup { struct LedSupportFile {
led_modes: Vec<LEDModes>, led_data: Vec<LaptopLedData>,
} }
impl LEDModeGroup { #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LaptopLedData {
pub prod_family: String,
pub board_names: Vec<String>,
pub standard: Vec<AuraModeNum>,
pub multizone: bool,
pub per_key: bool,
}
impl LedSupportFile {
/// Consumes the LEDModes /// Consumes the LEDModes
fn matcher(self, prod_family: &str, board_name: &str) -> Option<Vec<u8>> { fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
for led_modes in self.led_modes { for config in self.led_data {
if prod_family.contains(&led_modes.prod_family) { if prod_family.contains(&config.prod_family) {
for board in led_modes.board_names { for board in &config.board_names {
if board_name.contains(&board) { if board_name.contains(board) {
info!("Matched to {} {}", led_modes.prod_family, board); info!("Matched to {} {}", config.prod_family, board);
return Some(led_modes.led_modes); return Some(config);
} }
} }
} }
@@ -144,10 +153,3 @@ impl LEDModeGroup {
None None
} }
} }
#[derive(Debug, Deserialize, Serialize)]
struct LEDModes {
prod_family: String,
board_names: Vec<String>,
led_modes: Vec<u8>,
}
+1
View File
@@ -1,6 +1,7 @@
#![deny(unused_must_use)] #![deny(unused_must_use)]
/// Configuration loading, saving /// Configuration loading, saving
pub mod config; pub mod config;
pub mod config_aura;
pub(crate) mod config_old; pub(crate) mod config_old;
/// Control of AniMe matrix display /// Control of AniMe matrix display
pub mod ctrl_anime; pub mod ctrl_anime;
+48 -24
View File
@@ -1,59 +1,83 @@
[[led_modes]] [[led_data]]
prod_family = "Zephyrus S" prod_family = "Zephyrus S"
board_names = ["GX502", "GX701", "G531", "GL531", "G532"] board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false
per_key = true
[[led_modes]] [[led_data]]
prod_family = "Zephyrus M" prod_family = "Zephyrus M"
board_names = ["GU502GV"] board_names = ["GU502GV"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false
per_key = true
[[led_modes]] [[led_data]]
prod_family = "ROG Zephyrus M15" prod_family = "ROG Zephyrus M15"
board_names = ["GU502LW"] board_names = ["GU502LW"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false
per_key = true
[[led_modes]] [[led_data]]
prod_family = "ROG Zephyrus M15" prod_family = "ROG Zephyrus M15"
board_names = ["GU502LU"] board_names = ["GU502LU"]
led_modes = [0, 1, 2, 10] standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = false
per_key = false
[[led_modes]] [[led_data]]
prod_family = "Zephyrus" prod_family = "Zephyrus"
board_names = ["GM501GM", "GX531"] board_names = ["GM501GM", "GX531"]
led_modes = [0, 1, 2, 3, 10, 13] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = true
per_key = false
[[led_modes]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["G531GW"] board_names = ["G531GW"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false
per_key = true
[[led_modes]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["GX531", "G512LV", "G712LV"] board_names = ["GX531", "G512LV", "G712LV"]
led_modes = [0, 1, 2, 3, 10, 13, 14] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = true
per_key = false
[[led_modes]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["G512LI", "G712LI", "G531GD"] board_names = ["G512LI", "G712LI", "G531GD"]
led_modes = [0, 1, 2, 3, 10] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = false
per_key = false
[[led_modes]] [[led_data]]
prod_family = "Strix" prod_family = "Strix"
board_names = ["G731GV", "G731GW", "G531GV"] board_names = ["G731GV", "G731GW", "G531GV"]
led_modes = [0, 1, 2, 3, 13, 14] standard = ["Static", "Breathe", "Strobe", "Rainbow"]
multizone = true
per_key = false
[[led_modes]] [[led_data]]
prod_family = "Strix" prod_family = "Strix"
board_names = ["G731GT", "G731GU", "G531GT", "G531GU"] board_names = ["G731GT", "G731GU", "G531GT", "G531GU"]
led_modes = [0, 1, 2, 3] standard = ["Static", "Breathe", "Strobe", "Rainbow"]
multizone = false
per_key = false
[[led_modes]] [[led_data]]
prod_family = "Strix Scar" prod_family = "Strix Scar"
board_names = ["G531", "G731"] board_names = ["G531", "G731"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 255] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = true
per_key = true
[[led_modes]] [[led_data]]
prod_family = "ROG" prod_family = "ROG"
board_names = ["GL553VE"] board_names = ["GL553VE"]
led_modes = [0, 1, 2, 13, 14] standard = ["Static", "Breathe", "Strobe"]
multizone = true
per_key = false
+77
View File
@@ -0,0 +1,77 @@
# Author: AlenPaulVarghese <alenpaul2001@gmail.com>
set -l progname asusctl
set -l noopt "not __fish_contains_opt -s -s h -s v -s s -s k -s f -s c help version show-supported kbd-bright fan-mode chg-limit; and not __fish_seen_subcommand_from led-mode profile graphics;"
set -l gmod_options '__fish_contains_opt -s m mode;'
set -l fan_options '__fish_contains_opt -s f fan-mode;'
set -l led_options '__fish_seen_subcommand_from led-mode;'
set -l profile_options '__fish_seen_subcommand_from profile;'
set -l keyboard_options '__fish_contains_opt -s k kbd-bright;'
set -l graphics_options '__fish_seen_subcommand_from graphics;'
set -l fan_modes 'silent normal boost'
set -l brightness_modes 'off low med high'
set -l led_modes 'static breathe strobe rainbow comet'
set -l graphics_modes 'nvidia hybird compute integrated'
complete -c $progname -e
complete -c $progname -f
# asusctl completion
complete -c $progname -s h -f -l help -n "$noopt" -d "print help message"
complete -c $progname -s v -f -l version -n "$noopt" -d "show program version number"
complete -c $progname -s s -f -l show-supported -n "$noopt" -d "show supported functions of this laptop"
complete -c $progname -s k -f -l kbd-bright -n "$noopt" -d "set led brightness"
complete -c $progname -s f -f -l fan-mode -n "$noopt" -d "set fan mode independent of profile"
complete -c $progname -s c -f -l chg-limit -n "$noopt" -d "set charge limit <20-100>"
complete -c $progname -f -a "led-mode" -n "$noopt" -d "Set the keyboard lighting from built-in modes"
complete -c $progname -f -a "profile" -n "$noopt" -d "Create and configure profiles"
complete -c $progname -f -a "graphics" -n "$noopt" -d "Set the graphics mode"
# brightness completion
complete -c $progname -n "$keyboard_options" -d "available brightness modes" -a "$brightness_modes"
# fan completion
complete -c $progname -n "$fan_options" -d "available fan modes" -a $fan_modes
# graphics completion
set -l gopt 'not __fish_contains_opt -s h -s g -s m -s p help mode get pow;'
complete -c $progname -n "$graphics_options and $gopt" -a "-h" -d "print help message"
complete -c $progname -n "$graphics_options and $gopt" -a "-g" -d "Get the current mode"
complete -c $progname -s h -f -l help -n "$graphics_options and $gopt" -d "print help message"
complete -c $progname -s m -f -l mode -n "$graphics_options and $gopt" -d "Set graphics mode: <nvidia, hybrid, compute, integrated>"
complete -c $progname -s g -f -l get -n "$graphics_options and $gopt" -d "Get the current mode"
complete -c $progname -s p -f -l pow -n "$graphics_options and $gopt" -d "Get the current power status"
complete -c $progname -n "$graphics_options and $gmod_options" -d "available graphics modes" -a "$graphics_modes"
# led-mode completion
complete -c $progname -n "$led_options" -a "-h" -d "print help message"
complete -c $progname -n "$led_options" -a "-n" -d "switch to next aura mode"
complete -c $progname -s h -f -l help -n "$led_options" -d "print help message"
complete -c $progname -s n -f -l next-mode -n "$led_options" -d "switch to nex aura mode"
complete -c $progname -s p -f -l prev-mode -n "$led_options" -d "switch to previous aura mode"
complete -c $progname -n "$led_options" -d "available led modes" -a "$led_modes"
# profile completion
set -l popt 'not __fish_contains_opt -s h -s n -s c -s t -s m -s M -s f help next create turbo min-percentage max-percentage fan-preset;'
complete -c $progname -n "$profile_options and $popt" -a "-h" -d "print help message"
complete -c $progname -n "$profile_options and $popt" -a "-n" -d "toggle to next profile in list"
complete -c $progname -s h -f -l help -n "$profile_options and $popt" -d "print help message"
complete -c $progname -s n -f -l next -n "$profile_options and $popt" -d "toggle to next profile in list"
complete -c $progname -s c -f -l create -n "$profile_options and $popt" -d "create the profile if it doesn't exist"
complete -c $progname -s t -f -l turbo -n "$profile_options and $popt" -d "enable or disable cpu turbo"
complete -c $progname -s m -f -l min-percentage -n "$profile_options and $popt" -d "set min cpu scaling (intel)"
complete -c $progname -s M -f -l max-percentage -n "$profile_options and $popt" -d "set max cpu scaling (intel)"
complete -c $progname -s f -f -l fan-preset -n "$profile_options and $popt" -d "<silent, normal, boost>"
complete -c $progname -n "$profile_option and __fish_contains_opt fan-preset" -d "available fan modes" -a $fan_modes
+1 -1
View File
@@ -15,4 +15,4 @@ rog_types = { path = "../rog-types" }
rog_fan_curve = { version = "^0.1", features = ["serde"] } rog_fan_curve = { version = "^0.1", features = ["serde"] }
zbus = "^1.8" zbus = "^1.8"
zbus_macros = "^1.8" zbus_macros = "^1.8"
zvariant = "^2.4" zvariant = "^2.5"
+9 -6
View File
@@ -11,7 +11,10 @@ pub mod zbus_profile;
pub mod zbus_rogbios; pub mod zbus_rogbios;
pub mod zbus_supported; pub mod zbus_supported;
use rog_types::aura_modes::AuraModes; use rog_types::{
aura_modes::AuraEffect,
gfx_vendors::{GfxRequiredUserAction, GfxVendors},
};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use zbus::{Connection, Result, SignalReceiver}; use zbus::{Connection, Result, SignalReceiver};
@@ -86,10 +89,10 @@ impl<'a> DbusProxies<'a> {
// Signals separated out // Signals separated out
pub struct Signals { pub struct Signals {
pub gfx_vendor: Arc<Mutex<Option<String>>>, pub gfx_vendor: Arc<Mutex<Option<GfxVendors>>>,
pub gfx_action: Arc<Mutex<Option<String>>>, pub gfx_action: Arc<Mutex<Option<GfxRequiredUserAction>>>,
pub profile: Arc<Mutex<Option<String>>>, pub profile: Arc<Mutex<Option<String>>>,
pub led_mode: Arc<Mutex<Option<AuraModes>>>, pub led_mode: Arc<Mutex<Option<AuraEffect>>>,
pub charge: Arc<Mutex<Option<u8>>>, pub charge: Arc<Mutex<Option<u8>>>,
} }
@@ -151,13 +154,13 @@ impl<'a> AuraDbusClient<'a> {
/* /*
* GFX * GFX
*/ */
pub fn gfx_wait_changed(&self) -> Result<String> { pub fn gfx_wait_changed(&self) -> Result<GfxRequiredUserAction> {
loop { loop {
if let Ok(res) = self.proxies.gfx.proxy().next_signal() { if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
if res.is_none() { if res.is_none() {
if let Ok(lock) = self.signals.gfx_action.lock() { if let Ok(lock) = self.signals.gfx_action.lock() {
if let Some(stuff) = lock.as_ref() { if let Some(stuff) = lock.as_ref() {
return Ok(stuff.to_string()); return Ok(*stuff);
} }
} }
// return Ok("Failed for unknown reason".to_owned()); // return Ok("Failed for unknown reason".to_owned());
+14 -10
View File
@@ -21,6 +21,7 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
@@ -32,18 +33,18 @@ trait Daemon {
fn power(&self) -> zbus::Result<String>; fn power(&self) -> zbus::Result<String>;
/// SetVendor method /// SetVendor method
fn set_vendor(&self, vendor: &str) -> zbus::Result<()>; fn set_vendor(&self, vendor: &GfxVendors) -> zbus::Result<GfxRequiredUserAction>;
/// Vendor method /// Vendor method
fn vendor(&self) -> zbus::Result<String>; fn vendor(&self) -> zbus::Result<GfxVendors>;
/// NotifyAction signal /// NotifyAction signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()>; fn notify_action(&self, action: GfxRequiredUserAction) -> zbus::Result<()>;
/// NotifyGfx signal /// NotifyGfx signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>; fn notify_gfx(&self, vendor: GfxVendors) -> zbus::Result<()>;
} }
pub struct GfxProxy<'a>(DaemonProxy<'a>); pub struct GfxProxy<'a>(DaemonProxy<'a>);
@@ -64,33 +65,36 @@ impl<'a> GfxProxy<'a> {
} }
#[inline] #[inline]
pub fn gfx_get_mode(&self) -> Result<String> { pub fn gfx_get_mode(&self) -> Result<GfxVendors> {
self.0.vendor() self.0.vendor()
} }
#[inline] #[inline]
pub fn gfx_write_mode(&self, vendor: &str) -> Result<()> { pub fn gfx_write_mode(&self, vendor: &GfxVendors) -> Result<GfxRequiredUserAction> {
self.0.set_vendor(vendor) self.0.set_vendor(vendor)
} }
#[inline] #[inline]
pub fn connect_notify_action( pub fn connect_notify_action(
&self, &self,
action: Arc<Mutex<Option<String>>>, action: Arc<Mutex<Option<GfxRequiredUserAction>>>,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.0.connect_notify_action(move |data| { self.0.connect_notify_action(move |data| {
if let Ok(mut lock) = action.lock() { if let Ok(mut lock) = action.lock() {
*lock = Some(data.to_owned()); *lock = Some(data);
} }
Ok(()) Ok(())
}) })
} }
#[inline] #[inline]
pub fn connect_notify_gfx(&self, vendor: Arc<Mutex<Option<String>>>) -> zbus::fdo::Result<()> { pub fn connect_notify_gfx(
&self,
vendor: Arc<Mutex<Option<GfxVendors>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_gfx(move |data| { self.0.connect_notify_gfx(move |data| {
if let Ok(mut lock) = vendor.lock() { if let Ok(mut lock) = vendor.lock() {
*lock = Some(data.to_owned()); *lock = Some(data);
} }
Ok(()) Ok(())
}) })
+31 -27
View File
@@ -23,7 +23,7 @@ use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
use rog_types::{aura_modes::AuraModes, cli_options::LedBrightness, fancy::KeyColourArray}; use rog_types::{aura_modes::AuraEffect, aura_perkey::KeyColourArray};
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
@@ -32,27 +32,34 @@ const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 F
default_path = "/org/asuslinux/Led" default_path = "/org/asuslinux/Led"
)] )]
trait Daemon { trait Daemon {
/// LedBrightness method
fn led_brightness(&self) -> zbus::Result<i16>;
/// LedMode method
fn led_mode(&self) -> zbus::Result<String>;
/// LedModes method
fn led_modes(&self) -> zbus::Result<String>;
/// NextLedMode method /// NextLedMode method
fn next_led_mode(&self) -> zbus::Result<()>; fn next_led_mode(&self) -> zbus::Result<()>;
/// PrevLedMode method /// PrevLedMode method
fn prev_led_mode(&self) -> zbus::Result<()>; fn prev_led_mode(&self) -> zbus::Result<()>;
/// SetLedMode method /// SetBrightness method
fn set_led_mode(&self, data: &str) -> zbus::Result<()>; fn set_brightness(&self, brightness: u8) -> zbus::Result<()>;
/// SetLedMode method
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
/// NotifyLed signal
/// NotifyLed signal /// NotifyLed signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>; fn notify_led(&self, data: &str) -> zbus::Result<()>;
/// LedBrightness property
#[dbus_proxy(property)]
fn led_brightness(&self) -> zbus::Result<i16>;
/// LedMode property
#[dbus_proxy(property)]
fn led_mode(&self) -> zbus::Result<String>;
/// LedModes property
#[dbus_proxy(property)]
fn led_modes(&self) -> zbus::Result<String>;
} }
pub struct LedProxy<'a>(DaemonProxy<'a>); pub struct LedProxy<'a>(DaemonProxy<'a>);
@@ -68,16 +75,13 @@ impl<'a> LedProxy<'a> {
} }
#[inline] #[inline]
pub fn get_led_brightness(&self) -> Result<LedBrightness> { pub fn get_led_brightness(&self) -> Result<i16> {
match self.0.led_brightness()? { self.0.led_brightness()
-1 => Ok(LedBrightness::new(None)),
level => Ok(LedBrightness::new(Some(level as u8))),
}
} }
#[inline] #[inline]
pub fn set_brightness(&self, level: u8) -> Result<()> { pub fn set_led_brightness(&self, level: u8) -> Result<()> {
self.set_led_mode(&AuraModes::LedBrightness(level))?; self.0.set_brightness(level)?;
Ok(()) Ok(())
} }
@@ -92,8 +96,8 @@ impl<'a> LedProxy<'a> {
} }
#[inline] #[inline]
pub fn set_led_mode(&self, mode: &AuraModes) -> Result<()> { pub fn set_led_mode(&self, mode: &AuraEffect) -> Result<()> {
self.0.set_led_mode(&serde_json::to_string(mode).unwrap()) self.0.set_led_mode(mode)
} }
/// Write a single colour block. /// Write a single colour block.
@@ -107,9 +111,8 @@ impl<'a> LedProxy<'a> {
for v in group { for v in group {
vecs.push(v.to_vec()); vecs.push(v.to_vec());
} }
let mode = AuraModes::PerKey(vecs); // TODO: let mode = AuraModes::PerKey(vecs);
// self.set_led_mode(&mode)?;
self.set_led_mode(&mode)?;
std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME)); std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME));
@@ -124,12 +127,13 @@ impl<'a> LedProxy<'a> {
/// the keyboard LED EC in the correct mode /// the keyboard LED EC in the correct mode
#[inline] #[inline]
pub fn init_effect(&self) -> Result<()> { pub fn init_effect(&self) -> Result<()> {
let mode = AuraModes::PerKey(vec![vec![]]); // TODO: let mode = AuraModes::PerKey(vec![vec![]]);
self.0.set_led_mode(&serde_json::to_string(&mode).unwrap()) // self.0.set_led_mode(&serde_json::to_string(&mode).unwrap())
Ok(())
} }
#[inline] #[inline]
pub fn connect_notify_led(&self, led: Arc<Mutex<Option<AuraModes>>>) -> zbus::fdo::Result<()> { pub fn connect_notify_led(&self, led: Arc<Mutex<Option<AuraEffect>>>) -> zbus::fdo::Result<()> {
self.0.connect_notify_led(move |data| { self.0.connect_notify_led(move |data| {
if let Ok(mut lock) = led.lock() { if let Ok(mut lock) = led.lock() {
if let Ok(dat) = serde_json::from_str(&data) { if let Ok(dat) = serde_json::from_str(&data) {
+16
View File
@@ -41,6 +41,12 @@ trait Daemon {
/// Profiles method /// Profiles method
fn profiles(&self) -> zbus::Result<String>; fn profiles(&self) -> zbus::Result<String>;
/// ProfileNames method
fn profile_names(&self) -> zbus::Result<String>;
/// Remove method
fn remove(&self, profile: &str) -> zbus::Result<()>;
/// SetProfile method /// SetProfile method
fn set_profile(&self, profile: &str) -> zbus::Result<()>; fn set_profile(&self, profile: &str) -> zbus::Result<()>;
@@ -82,6 +88,16 @@ impl<'a> ProfileProxy<'a> {
self.0.set_profile(&serde_json::to_string(cmd).unwrap()) self.0.set_profile(&serde_json::to_string(cmd).unwrap())
} }
#[inline]
pub fn profile_names(&self) -> Result<String> {
self.0.profile_names()
}
#[inline]
pub fn remove(&self, profile: &str) -> Result<()> {
self.0.remove(profile)
}
#[inline] #[inline]
pub fn connect_notify_profile( pub fn connect_notify_profile(
&self, &self,
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_types" name = "rog_types"
version = "3.0.0" version = "3.1.0"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
+261 -219
View File
@@ -1,31 +1,21 @@
use crate::cli_options::SetAuraBuiltin; // static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use crate::error::AuraError; use crate::error::AuraError;
use gumdrop::Options; use crate::LED_MSG_LEN;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use zvariant_derive::Type;
pub const STATIC: u8 = 0x00; #[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize, Type)]
pub const BREATHING: u8 = 0x01;
pub const STROBE: u8 = 0x02;
pub const RAINBOW: u8 = 0x03;
pub const STAR: u8 = 0x04;
pub const RAIN: u8 = 0x05;
pub const HIGHLIGHT: u8 = 0x06;
pub const LASER: u8 = 0x07;
pub const RIPPLE: u8 = 0x08;
pub const PULSE: u8 = 0x0a;
pub const COMET: u8 = 0x0b;
pub const FLASH: u8 = 0x0c;
pub const MULTISTATIC: u8 = 0x0d;
pub const MULTIBREATHE: u8 = 0x0e;
pub const PER_KEY: u8 = 0xff;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Colour(pub u8, pub u8, pub u8); pub struct Colour(pub u8, pub u8, pub u8);
impl Default for Colour { impl Default for Colour {
fn default() -> Self { fn default() -> Self {
Colour(128, 0, 0) Colour(166, 0, 0)
} }
} }
@@ -43,7 +33,7 @@ impl FromStr for Colour {
} }
} }
#[derive(Debug, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
pub enum Speed { pub enum Speed {
Low = 0xe1, Low = 0xe1,
Med = 0xeb, Med = 0xeb,
@@ -71,7 +61,7 @@ impl FromStr for Speed {
/// Used for Rainbow mode. /// Used for Rainbow mode.
/// ///
/// Enum corresponds to the required integer value /// Enum corresponds to the required integer value
#[derive(Debug, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
pub enum Direction { pub enum Direction {
Right, Right,
Left, Left,
@@ -98,213 +88,265 @@ impl FromStr for Direction {
} }
} }
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)] /// Writes out the correct byte string for brightness
pub struct SingleSpeed { pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
#[serde(skip)] [
#[options(help = "print help message")] 0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
help: bool, ]
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
pub speed: Speed,
} }
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
pub struct SingleSpeedDirection { #[derive(
#[serde(skip)] Debug, Type, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize,
#[options(help = "print help message")] )]
help: bool, pub enum AuraModeNum {
#[options(no_long, meta = "", help = "set the direction: up, down, left, right")] Static = 0,
Breathe = 1,
Strobe = 2,
Rainbow = 3,
Star = 4,
Rain = 5,
Highlight = 6,
Laser = 7,
Ripple = 8,
Pulse = 10,
Comet = 11,
Flash = 12,
}
impl From<&AuraModeNum> for &str {
fn from(mode: &AuraModeNum) -> Self {
match mode {
AuraModeNum::Static => "Static",
AuraModeNum::Breathe => "Breathing",
AuraModeNum::Strobe => "Strobing",
AuraModeNum::Rainbow => "Rainbow",
AuraModeNum::Star => "Stars",
AuraModeNum::Rain => "Rain",
AuraModeNum::Highlight => "Keypress Highlight",
AuraModeNum::Laser => "Keypress Laser",
AuraModeNum::Ripple => "Keypress Ripple",
AuraModeNum::Pulse => "Pulse",
AuraModeNum::Comet => "Comet",
AuraModeNum::Flash => "Flash",
}
}
}
impl From<&str> for AuraModeNum {
fn from(mode: &str) -> Self {
match mode {
"Static" => AuraModeNum::Static,
"Breathing" => AuraModeNum::Breathe,
"Strobing" => AuraModeNum::Strobe,
"Rainbow" => AuraModeNum::Rainbow,
"Stars" => AuraModeNum::Star,
"Rain" => AuraModeNum::Rain,
"Keypress Highlight" => AuraModeNum::Highlight,
"Keypress Laser" => AuraModeNum::Laser,
"Keypress Ripple" => AuraModeNum::Ripple,
"Pulse" => AuraModeNum::Pulse,
"Comet" => AuraModeNum::Comet,
"Flash" => AuraModeNum::Flash,
_ => AuraModeNum::Static,
}
}
}
impl From<u8> for AuraModeNum {
fn from(mode: u8) -> Self {
match mode {
0 => AuraModeNum::Static,
1 => AuraModeNum::Breathe,
2 => AuraModeNum::Strobe,
3 => AuraModeNum::Rainbow,
4 => AuraModeNum::Star,
5 => AuraModeNum::Rain,
6 => AuraModeNum::Highlight,
7 => AuraModeNum::Laser,
8 => AuraModeNum::Ripple,
10 => AuraModeNum::Pulse,
11 => AuraModeNum::Comet,
12 => AuraModeNum::Flash,
_ => AuraModeNum::Static,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraMultiZone {
static_: [AuraEffect; 4],
breathe: [AuraEffect; 4],
}
impl AuraMultiZone {
pub fn set(&mut self, effect: AuraEffect) {
if effect.mode == AuraModeNum::Static {
match effect.zone {
AuraZone::None => {}
AuraZone::One => self.static_[0] = effect,
AuraZone::Two => self.static_[1] = effect,
AuraZone::Three => self.static_[2] = effect,
AuraZone::Four => self.static_[3] = effect,
}
} else if effect.mode == AuraModeNum::Breathe {
match effect.zone {
AuraZone::None => {}
AuraZone::One => self.breathe[0] = effect,
AuraZone::Two => self.breathe[1] = effect,
AuraZone::Three => self.breathe[2] = effect,
AuraZone::Four => self.breathe[3] = effect,
}
}
}
pub fn static_(&self) -> &[AuraEffect; 4] {
&self.static_
}
pub fn breathe(&self) -> &[AuraEffect; 4] {
&self.breathe
}
}
impl Default for AuraMultiZone {
fn default() -> Self {
Self {
static_: [
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::One,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Two,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Three,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Four,
..Default::default()
},
],
breathe: [
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::One,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Two,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Three,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Four,
..Default::default()
},
],
}
}
}
/// Base effects have no zoning, while multizone is 1-4
#[derive(Debug, Type, Copy, Clone, PartialEq, Deserialize, Serialize)]
pub enum AuraZone {
None,
One,
Two,
Three,
Four,
}
/// Default factory modes structure
#[derive(Debug, Type, Clone, Deserialize, Serialize)]
pub struct AuraEffect {
/// The effect type
pub mode: AuraModeNum,
/// `AuraZone::None` for no zone or zoneless keyboards
pub zone: AuraZone,
/// Primary colour for all modes
pub colour1: Colour,
/// Secondary colour in some modes like Breathing or Stars
pub colour2: Colour,
/// One of three speeds for modes that support speed (most that animate)
pub speed: Speed,
/// Up, down, left, right. Only Rainbow mode seems to use this
pub direction: Direction, pub direction: Direction,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
} }
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)] impl AuraEffect {
pub struct SingleColour { pub fn mode(&self) -> &AuraModeNum {
#[serde(skip)] &self.mode
#[options(help = "print help message")] }
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")] pub fn mode_name(&self) -> String {
pub colour: Colour, (<&str>::from(&self.mode)).to_string()
}
pub fn mode_num(&self) -> u8 {
self.mode as u8
}
pub fn default_with_mode(mode: AuraModeNum) -> Self {
Self {
mode,
..Default::default()
}
}
pub fn zone(&self) -> AuraZone {
self.zone
}
} }
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)] impl Default for AuraEffect {
pub struct SingleColourSpeed { fn default() -> Self {
#[serde(skip)] Self {
#[options(help = "print help message")] mode: AuraModeNum::Static,
help: bool, zone: AuraZone::None,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")] colour1: Colour(166, 0, 0),
pub colour: Colour, colour2: Colour(0, 0, 0),
#[options(no_long, meta = "", help = "set the speed: low, med, high")] speed: Speed::Med,
pub speed: Speed, direction: Direction::Right,
}
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
pub struct TwoColourSpeed {
#[serde(skip)]
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the first RGB value e.g, ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "", help = "set the second RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
pub struct MultiColour {
#[serde(skip)]
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour4: Colour,
}
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
pub struct MultiColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour3: Colour,
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour4: Colour,
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum AuraModes {
Static(SingleColour),
Breathe(TwoColourSpeed),
Strobe(SingleSpeed),
Rainbow(SingleSpeedDirection),
Star(TwoColourSpeed),
Rain(SingleSpeed),
Highlight(SingleColourSpeed),
Laser(SingleColourSpeed),
Ripple(SingleColourSpeed),
Pulse(SingleColour),
Comet(SingleColour),
Flash(SingleColour),
MultiStatic(MultiColour),
MultiBreathe(MultiColourSpeed),
LedBrightness(u8),
// TODO: use a serializable structure for this (KeyColourArray)
PerKey(Vec<Vec<u8>>),
}
impl From<SetAuraBuiltin> for AuraModes {
fn from(mode: SetAuraBuiltin) -> Self {
match mode {
SetAuraBuiltin::Static(x) => AuraModes::Static(x),
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x),
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x),
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x),
SetAuraBuiltin::Star(x) => AuraModes::Star(x),
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x),
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x),
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x),
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x),
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x),
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x),
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x),
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x),
SetAuraBuiltin::MultiBreathe(x) => AuraModes::MultiBreathe(x),
} }
} }
} }
/// Very specific mode conversion required because numbering isn't linear /// Parses `AuraEffect` in to packet data for writing to the USB interface
impl From<AuraModes> for u8 { ///
fn from(mode: AuraModes) -> Self { /// Byte structure:
u8::from(&mode) /// ```ignore
} /// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
} /// |---|---|---|---|---|---|---|---|---|---|---|---|---|
/// |5d |b3 |00 |03 |ff |00 |00 |00 |00 |00 |00 |ff |00 |
/// ```
impl From<&AuraEffect> for [u8; LED_MSG_LEN] {
fn from(aura: &AuraEffect) -> Self {
let mut msg = [0u8; LED_MSG_LEN];
msg[0] = 0x5d;
msg[1] = 0xb3;
msg[2] = aura.zone as u8;
msg[3] = aura.mode as u8;
msg[4] = aura.colour1.0;
msg[5] = aura.colour1.1;
msg[6] = aura.colour1.2;
msg[7] = aura.speed as u8;
msg[8] = aura.direction as u8;
msg[10] = aura.colour2.0;
msg[11] = aura.colour2.1;
msg[12] = aura.colour2.2;
/// Very specific mode conversion required because numbering isn't linear msg
impl From<&mut AuraModes> for u8 {
fn from(mode: &mut AuraModes) -> Self {
u8::from(&*mode)
}
}
/// Very specific mode conversion required because numbering isn't linear
impl From<&AuraModes> for u8 {
fn from(mode: &AuraModes) -> Self {
match mode {
AuraModes::Static(_) => STATIC,
AuraModes::Breathe(_) => BREATHING,
AuraModes::Strobe(_) => STROBE,
AuraModes::Rainbow(_) => RAINBOW,
AuraModes::Star(_) => STAR,
AuraModes::Rain(_) => RAIN,
AuraModes::Highlight(_) => HIGHLIGHT,
AuraModes::Laser(_) => LASER,
AuraModes::Ripple(_) => RIPPLE,
AuraModes::Pulse(_) => PULSE,
AuraModes::Comet(_) => COMET,
AuraModes::Flash(_) => FLASH,
AuraModes::MultiStatic(_) => MULTISTATIC,
AuraModes::MultiBreathe(_) => MULTIBREATHE,
AuraModes::PerKey(_) => PER_KEY,
_ => panic!("Invalid mode"),
}
}
}
impl From<&AuraModes> for &str {
fn from(mode: &AuraModes) -> Self {
match mode {
AuraModes::Static(_) => "Static",
AuraModes::Breathe(_) => "Breathing",
AuraModes::Strobe(_) => "Strobing",
AuraModes::Rainbow(_) => "Rainbow",
AuraModes::Star(_) => "Stars",
AuraModes::Rain(_) => "Rain",
AuraModes::Highlight(_) => "Keypress Highlight",
AuraModes::Laser(_) => "Keypress Laser",
AuraModes::Ripple(_) => "Keypress Ripple",
AuraModes::Pulse(_) => "Pulse",
AuraModes::Comet(_) => "Comet",
AuraModes::Flash(_) => "Flash",
AuraModes::MultiStatic(_) => "4-Zone Static Colours",
AuraModes::MultiBreathe(_) => "4-Zone Breathing Colours",
AuraModes::PerKey(_) => "RGB per-key",
_ => panic!("Invalid mode"),
}
}
}
/// Exists to convert back from correct bytes. PER_KEY byte intentionally left off as it
/// does not correspond to an actual pre-set mode, nor does brightness.
impl From<u8> for AuraModes {
fn from(byte: u8) -> Self {
match byte {
STATIC => AuraModes::Static(SingleColour::default()),
BREATHING => AuraModes::Breathe(TwoColourSpeed::default()),
STROBE => AuraModes::Strobe(SingleSpeed::default()),
RAINBOW => AuraModes::Rainbow(SingleSpeedDirection::default()),
STAR => AuraModes::Star(TwoColourSpeed::default()),
RAIN => AuraModes::Rain(SingleSpeed::default()),
HIGHLIGHT => AuraModes::Highlight(SingleColourSpeed::default()),
LASER => AuraModes::Laser(SingleColourSpeed::default()),
RIPPLE => AuraModes::Ripple(SingleColourSpeed::default()),
PULSE => AuraModes::Pulse(SingleColour::default()),
COMET => AuraModes::Comet(SingleColour::default()),
FLASH => AuraModes::Flash(SingleColour::default()),
MULTISTATIC => AuraModes::MultiStatic(MultiColour::default()),
MULTIBREATHE => AuraModes::MultiBreathe(MultiColourSpeed::default()),
PER_KEY => AuraModes::PerKey(vec![]),
_ => panic!("Invalid mode byte"),
}
} }
} }
@@ -35,8 +35,8 @@ impl KeyColourArray {
/// Initialise and clear the keyboard for custom effects /// Initialise and clear the keyboard for custom effects
#[inline] #[inline]
pub fn get_init_msg() -> Vec<u8> { pub const fn get_init_msg() -> [u8; 64] {
let mut init = vec![0u8; 64]; let mut init = [0u8; 64];
init[0] = 0x5d; // Report ID init[0] = 0x5d; // Report ID
init[1] = 0xbc; // Mode = custom??, 0xb3 is builtin init[1] = 0xbc; // Mode = custom??, 0xb3 is builtin
init init
+1 -91
View File
@@ -1,97 +1,7 @@
use crate::{ use crate::error::AuraError;
aura_modes::{
MultiColour, MultiColourSpeed, SingleColour, SingleColourSpeed, SingleSpeed,
SingleSpeedDirection, TwoColourSpeed,
},
error::AuraError,
};
use gumdrop::Options; use gumdrop::Options;
use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
#[derive(Options)]
pub struct LedBrightness {
level: Option<u8>,
}
impl LedBrightness {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u8> {
self.level
}
}
impl FromStr for LedBrightness {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"off" => Ok(LedBrightness { level: Some(0x00) }),
"low" => Ok(LedBrightness { level: Some(0x01) }),
"med" => Ok(LedBrightness { level: Some(0x02) }),
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
print!("Invalid argument, must be one of: off, low, med, high");
Err(AuraError::ParseBrightness)
}
}
}
}
impl ToString for LedBrightness {
fn to_string(&self) -> String {
let s = match self.level {
Some(0x00) => "low",
Some(0x01) => "med",
Some(0x02) => "high",
_ => "unknown",
};
s.to_string()
}
}
/// Byte value for setting the built-in mode.
///
/// Enum corresponds to the required integer value
#[derive(Options, Deserialize, Serialize)]
pub enum SetAuraBuiltin {
#[options(help = "set a single static colour")]
Static(SingleColour),
#[options(help = "pulse between one or two colours")]
Breathe(TwoColourSpeed),
#[options(help = "strobe through all colours")]
Strobe(SingleSpeed),
#[options(help = "rainbow cycling in one of four directions")]
Rainbow(SingleSpeedDirection),
#[options(help = "rain pattern mimicking raindrops")]
Star(TwoColourSpeed),
#[options(help = "rain pattern of three preset colours")]
Rain(SingleSpeed),
#[options(help = "pressed keys are highlighted to fade")]
Highlight(SingleColourSpeed),
#[options(help = "pressed keys generate horizontal laser")]
Laser(SingleColourSpeed),
#[options(help = "pressed keys ripple outwards like a splash")]
Ripple(SingleColourSpeed),
#[options(help = "set a rapid pulse")]
Pulse(SingleColour),
#[options(help = "set a vertical line zooming from left")]
Comet(SingleColour),
#[options(help = "set a wide vertical line zooming from left")]
Flash(SingleColour),
#[options(help = "4-zone multi-colour")]
MultiStatic(MultiColour),
#[options(help = "4-zone multi-colour breathing")]
MultiBreathe(MultiColourSpeed),
}
impl Default for SetAuraBuiltin {
fn default() -> Self {
SetAuraBuiltin::Static(SingleColour::default())
}
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum AniMeStatusValue { pub enum AniMeStatusValue {
On, On,
+23 -54
View File
@@ -1,17 +1,17 @@
use crate::error::GraphicsError;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
use zvariant_derive::Type;
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum GfxVendors { pub enum GfxVendors {
Nvidia, Nvidia,
Integrated, Integrated,
Compute, Compute,
Vfio,
Hybrid, Hybrid,
} }
use std::str::FromStr;
use crate::error::GraphicsError;
impl FromStr for GfxVendors { impl FromStr for GfxVendors {
type Err = GraphicsError; type Err = GraphicsError;
@@ -20,80 +20,49 @@ impl FromStr for GfxVendors {
"nvidia" => Ok(GfxVendors::Nvidia), "nvidia" => Ok(GfxVendors::Nvidia),
"hybrid" => Ok(GfxVendors::Hybrid), "hybrid" => Ok(GfxVendors::Hybrid),
"compute" => Ok(GfxVendors::Compute), "compute" => Ok(GfxVendors::Compute),
"vfio" => Ok(GfxVendors::Vfio),
"integrated" => Ok(GfxVendors::Integrated), "integrated" => Ok(GfxVendors::Integrated),
"nvidia\n" => Ok(GfxVendors::Nvidia), "nvidia\n" => Ok(GfxVendors::Nvidia),
"hybrid\n" => Ok(GfxVendors::Hybrid), "hybrid\n" => Ok(GfxVendors::Hybrid),
"compute\n" => Ok(GfxVendors::Compute), "compute\n" => Ok(GfxVendors::Compute),
"vfio\n" => Ok(GfxVendors::Vfio),
"integrated\n" => Ok(GfxVendors::Integrated), "integrated\n" => Ok(GfxVendors::Integrated),
_ => Err(GraphicsError::ParseVendor), _ => Err(GraphicsError::ParseVendor),
} }
} }
} }
impl Into<&str> for GfxVendors { impl From<&GfxVendors> for &str {
fn into(self) -> &'static str { fn from(gfx: &GfxVendors) -> &'static str {
match self { match gfx {
GfxVendors::Nvidia => "nvidia", GfxVendors::Nvidia => "nvidia",
GfxVendors::Hybrid => "hybrid", GfxVendors::Hybrid => "hybrid",
GfxVendors::Compute => "compute", GfxVendors::Compute => "compute",
GfxVendors::Vfio => "vfio",
GfxVendors::Integrated => "integrated", GfxVendors::Integrated => "integrated",
} }
} }
} }
impl Into<String> for GfxVendors { impl From<GfxVendors> for &str {
fn into(self) -> String { fn from(gfx: GfxVendors) -> &'static str {
match self { (&gfx).into()
GfxVendors::Nvidia => "nvidia".to_string(),
GfxVendors::Hybrid => "hybrid".to_string(),
GfxVendors::Compute => "compute".to_string(),
GfxVendors::Integrated => "integrated".to_string(),
}
} }
} }
#[derive(Debug)] #[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum GfxCtrlAction { pub enum GfxRequiredUserAction {
Logout,
Reboot, Reboot,
RestartX,
None, None,
} }
impl FromStr for GfxCtrlAction { impl From<&GfxRequiredUserAction> for &str {
type Err = GraphicsError; fn from(gfx: &GfxRequiredUserAction) -> &'static str {
match gfx {
fn from_str(s: &str) -> Result<Self, GraphicsError> { GfxRequiredUserAction::Logout => "logout",
match s.to_lowercase().as_str() { GfxRequiredUserAction::Reboot => "reboot",
"reboot" => Ok(GfxCtrlAction::Reboot), GfxRequiredUserAction::None => "no action",
"restartx" => Ok(GfxCtrlAction::RestartX),
"none" => Ok(GfxCtrlAction::None),
_ => Err(GraphicsError::ParseVendor),
} }
} }
} }
impl From<&GfxCtrlAction> for &str {
fn from(mode: &GfxCtrlAction) -> Self {
match mode {
GfxCtrlAction::Reboot => "reboot",
GfxCtrlAction::RestartX => "restartx",
GfxCtrlAction::None => "none",
}
}
}
impl From<&GfxCtrlAction> for String {
fn from(mode: &GfxCtrlAction) -> Self {
match mode {
GfxCtrlAction::Reboot => "reboot".into(),
GfxCtrlAction::RestartX => "restartx".into(),
GfxCtrlAction::None => "none".into(),
}
}
}
impl From<GfxCtrlAction> for String {
fn from(mode: GfxCtrlAction) -> Self {
(&mode).into()
}
}
+5 -261
View File
@@ -1,10 +1,13 @@
//! This crate is intended for shared types (eg, between daemon and CLI), or
//! for types that might be useful in third-party crates perhaps for
//! sending messages over dbus wire
pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
pub const LED_MSG_LEN: usize = 17; pub const LED_MSG_LEN: usize = 17;
pub mod aura_modes; pub mod aura_modes;
use aura_modes::AuraModes;
pub mod profile; pub mod profile;
@@ -12,7 +15,7 @@ pub mod profile;
pub mod cli_options; pub mod cli_options;
/// Enables you to create fancy RGB effects /// Enables you to create fancy RGB effects
pub mod fancy; pub mod aura_perkey;
/// Helper functions for the AniMe display /// Helper functions for the AniMe display
pub mod anime_matrix; pub mod anime_matrix;
@@ -22,262 +25,3 @@ pub mod gfx_vendors;
pub mod error; pub mod error;
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
/// Writes aout the correct byte string for brightness
///
/// The HID descriptor looks like:
///
/// ```ignore
/// 0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
/// 0x09, 0x76, // Usage (0x76)
/// 0xA1, 0x01, // Collection (Application)
/// 0x85, 0x5A, // Report ID (90)
/// 0x19, 0x00, // Usage Minimum (0x00)
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
/// 0x15, 0x00, // Logical Minimum (0)
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
/// 0x75, 0x08, // Report Size (8)
/// 0x95, 0x05, // Report Count (5)
/// 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
/// 0x19, 0x00, // Usage Minimum (0x00)
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
/// 0x15, 0x00, // Logical Minimum (0)
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
/// 0x75, 0x08, // Report Size (8)
/// 0x95, 0x3F, // Report Count (63)
/// 0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
/// 0xC0, // End Collection
/// ```
pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
// TODO: check brightness range
[
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]
}
/// Parses `AuraCommands` in to packet data
///
/// Byte structure:
///
/// ```ignore
/// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
/// |---|---|---|---|---|---|---|---|---|---|---|---|---|
/// |5d |b3 |00 |03 |ff |00 |00 |00 |00 |00 |00 |ff |00 |
/// ```
///
/// Bytes 0 and 1 should always be 5d, b3
///
/// On multizone laptops byte 2 is the zone number, RGB in usual
/// place, byte 3 set to zero
///
/// Byte 3 sets the mode type:
/// - 00 = static
/// - 01 = breathe (can set two colours)
/// - 02 = strobe (through all colours)
/// - 03 = rainbow
/// - 04 = star (byte 9 sets rain colour)
/// - 05 = rain keys, red, white, turquoise
/// - 06 = pressed keys light up and fade
/// - 07 = pressed key emits laser
/// - 08 = pressed key emits water ripple
/// - 09 = no effect/not used
/// - 0a fast pulse (no speed setting)
/// - 0b vertical line racing to right (no speed setting)
/// - 0c wider vertical line racing to right (no speed setting)
///
/// Bytes 4, 5, 6 are Red, Green, Blue
///
/// Byte 7 sets speed from
/// - 0x00 = Off
/// - 0xe1 = Slow
/// - 0xeb = Medium
/// - 0xf5 = Fast
///
/// Byte 8 sets rainbow direction:
/// - 0x00 = rightwards
/// - 0x01 = leftwards
/// - 0x02 = upwards
/// - 0x03 = downwards
///
/// Bytes 10, 11, 12 are Red, Green, Blue for second colour if mode supports it
///
/// The HID descriptor looks like:
/// ```ignore
/// 0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
/// 0x09, 0x79, // Usage (0x79)
/// 0xA1, 0x01, // Collection (Application)
/// 0x85, 0x5D, // Report ID (93)
/// 0x19, 0x00, // Usage Minimum (0x00)
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
/// 0x15, 0x00, // Logical Minimum (0)
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
/// 0x75, 0x08, // Report Size (8)
/// 0x95, 0x1F, // Report Count (31)
/// 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
/// 0x19, 0x00, // Usage Minimum (0x00)
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
/// 0x15, 0x00, // Logical Minimum (0)
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
/// 0x75, 0x08, // Report Size (8)
/// 0x95, 0x3F, // Report Count (63)
/// 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
/// 0x19, 0x00, // Usage Minimum (0x00)
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
/// 0x15, 0x00, // Logical Minimum (0)
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
/// 0x75, 0x08, // Report Size (8)
/// 0x95, 0x3F, // Report Count (63)
/// 0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
/// 0xC0, // End Collection
/// ```
///
/// This descriptor is also used for the per-key LED settings
impl From<&AuraModes> for [u8; LED_MSG_LEN] {
fn from(mode: &AuraModes) -> Self {
let mut msg = [0u8; LED_MSG_LEN];
msg[0] = 0x5d;
msg[1] = 0xb3;
msg[7] = 0xeb;
match mode {
AuraModes::LedBrightness(n) => return aura_brightness_bytes(*n),
AuraModes::Static(_) => msg[3] = 0x00,
AuraModes::Breathe(_) => msg[3] = 0x01,
AuraModes::Strobe(_) => msg[3] = 0x02,
AuraModes::Rainbow(_) => msg[3] = 0x03,
AuraModes::Star(_) => msg[3] = 0x04,
AuraModes::Rain(_) => msg[3] = 0x05,
AuraModes::Highlight(_) => msg[3] = 0x06,
AuraModes::Laser(_) => msg[3] = 0x07,
AuraModes::Ripple(_) => msg[3] = 0x08,
AuraModes::Pulse(_) => msg[3] = 0x0a,
AuraModes::Comet(_) => msg[3] = 0x0b,
AuraModes::Flash(_) => msg[3] = 0x0c,
_ => panic!("Mode not convertable to 1D array: {}", <&str>::from(mode)),
}
match mode {
AuraModes::Rainbow(settings) => {
msg[7] = settings.speed as u8;
msg[8] = settings.direction as u8;
}
AuraModes::Star(settings) => {
msg[4] = settings.colour.0;
msg[5] = settings.colour.1;
msg[6] = settings.colour.2;
msg[7] = settings.speed as u8;
msg[9] = settings.colour2.2;
}
AuraModes::Breathe(settings) => {
msg[4] = settings.colour.0;
msg[5] = settings.colour.1;
msg[6] = settings.colour.2;
msg[7] = settings.speed as u8;
msg[10] = settings.colour2.0;
msg[11] = settings.colour2.1;
msg[12] = settings.colour2.2;
}
AuraModes::Strobe(settings) | AuraModes::Rain(settings) => {
msg[7] = settings.speed as u8;
}
AuraModes::Highlight(settings)
| AuraModes::Laser(settings)
| AuraModes::Ripple(settings) => {
msg[4] = settings.colour.0;
msg[5] = settings.colour.1;
msg[6] = settings.colour.2;
msg[7] = settings.speed as u8;
}
AuraModes::Static(settings)
| AuraModes::Pulse(settings)
| AuraModes::Comet(settings)
| AuraModes::Flash(settings) => {
msg[4] = settings.colour.0;
msg[5] = settings.colour.1;
msg[6] = settings.colour.2;
}
_ => panic!("Mode not convertable to 1D array: {}", <&str>::from(mode)),
}
msg
}
}
impl From<AuraModes> for [u8; LED_MSG_LEN] {
#[inline]
fn from(mode: AuraModes) -> Self {
<[u8; LED_MSG_LEN]>::from(&mode)
}
}
impl From<AuraModes> for [[u8; LED_MSG_LEN]; 4] {
#[inline]
fn from(mode: AuraModes) -> Self {
<[[u8; LED_MSG_LEN]; 4]>::from(&mode)
}
}
impl From<&AuraModes> for [[u8; LED_MSG_LEN]; 4] {
#[inline]
fn from(mode: &AuraModes) -> Self {
let mut msg = [[0u8; LED_MSG_LEN]; 4];
match mode {
AuraModes::MultiStatic(settings) => {
for (i, row) in msg.iter_mut().enumerate() {
row[0] = 0x5d;
row[1] = 0xb3;
row[2] = i as u8 + 1; // zone
row[3] = 0x00; // mode
row[7] = 0xeb; // static needs speed?
}
msg[0][4] = settings.colour1.0;
msg[0][5] = settings.colour1.1;
msg[0][6] = settings.colour1.2;
msg[1][4] = settings.colour2.0;
msg[1][5] = settings.colour2.1;
msg[1][6] = settings.colour2.2;
msg[2][4] = settings.colour3.0;
msg[2][5] = settings.colour3.1;
msg[2][6] = settings.colour3.2;
msg[3][4] = settings.colour4.0;
msg[3][5] = settings.colour4.1;
msg[3][6] = settings.colour4.2;
}
AuraModes::MultiBreathe(settings) => {
for (i, row) in msg.iter_mut().enumerate() {
row[0] = 0x5d;
row[1] = 0xb3;
row[2] = i as u8 + 1; // zone
row[3] = 0x01; // mode
}
let speed = match settings.speed {
aura_modes::Speed::Low => 0xfd,
aura_modes::Speed::Med => 0xfe,
aura_modes::Speed::High => 0xff,
};
msg[0][4] = settings.colour1.0;
msg[0][5] = settings.colour1.1;
msg[0][6] = settings.colour1.2;
msg[0][7] = speed; // fd, fe, ff
msg[1][4] = settings.colour2.0;
msg[1][5] = settings.colour2.1;
msg[1][6] = settings.colour2.2;
msg[1][7] = speed;
msg[2][4] = settings.colour3.0;
msg[2][5] = settings.colour3.1;
msg[2][6] = settings.colour3.2;
msg[2][7] = speed;
msg[3][4] = settings.colour4.0;
msg[3][5] = settings.colour4.1;
msg[3][6] = settings.colour4.2;
msg[3][7] = speed;
}
_ => panic!("Mode not convertable to 2D array: {}", <&str>::from(mode)),
}
msg
}
}
+14 -6
View File
@@ -80,18 +80,26 @@ pub struct ProfileCommand {
pub next: bool, pub next: bool,
#[options(help = "create the profile if it doesn't exist")] #[options(help = "create the profile if it doesn't exist")]
pub create: bool, pub create: bool,
#[options(help = "list available profiles")]
pub list: bool,
#[options(help = "enable or disable cpu turbo")] #[options(meta = "", help = "enable or disable cpu turbo")]
pub turbo: Option<bool>, pub turbo: Option<bool>,
#[options(help = "set min cpu scaling (intel)")] #[options(meta = "", help = "set min cpu scaling (intel)")]
pub min_percentage: Option<u8>, pub min_percentage: Option<u8>,
#[options(help = "set max cpu scaling (intel)")] #[options(meta = "", help = "set max cpu scaling (intel)")]
pub max_percentage: Option<u8>, pub max_percentage: Option<u8>,
#[options(meta = "PWR", help = "<silent, normal, boost>")] #[options(meta = "", help = "<silent, normal, boost>")]
pub preset: Option<FanLevel>, pub fan_preset: Option<FanLevel>,
#[options(parse(try_from_str = "parse_fan_curve"), help = "set fan curve")] #[options(
meta = "",
parse(try_from_str = "parse_fan_curve"),
help = "set fan curve"
)]
pub curve: Option<Curve>, pub curve: Option<Curve>,
#[options(free)] #[options(free)]
pub profile: Option<String>, pub profile: Option<String>,
#[options(help = "remove a profile by name")]
pub remove: Option<String>,
} }