Compare commits

...

38 Commits
2.1.2 ... 3.1.2

Author SHA1 Message Date
Luke D Jones
b8384c55c3 Bump changelog version 2021-03-10 11:21:09 +13:00
Luke D Jones
dfe1f02101 Hotfix: Catch some edge-cases exposed on fedora 34 2021-03-10 11:20:19 +13:00
Luke D Jones
7c2fb0be81 Hotfix: Nvidia module handling improved 2021-03-10 10:15:59 +13:00
Luke D Jones
b05f680650 Test and create /etc/X11/xorg.conf.d/ if not exist 2021-03-10 09:20:59 +13:00
Luke D Jones
2a9a436f9c Add nvidia-uvm to module list 2021-03-10 07:34:03 +13:00
Luke D Jones
0d6faf3fda Mark as new release 2021-03-09 17:23:19 +13:00
Luke Jones
aede000218 Merge branch 'fluke/rebootless-gfx-switch' into 'main'
Fluke/rebootless gfx switch

See merge request asus-linux/asus-nb-ctrl!29
2021-03-09 04:20:29 +00:00
Luke D Jones
176ab0a639 Rebootless graphics switching
This changes out how the current graphics switching works, enabling
asusd to stop/start the display-manager to enable/disable PCI devices
and add/remove drivers as required.

All existing graphics modes and commands still work as normal.

G-Sync enable is now only through the bios setting, and on reboot
will set all relevant settings to Nvidia mode.
2021-03-09 16:45:43 +13:00
Luke D Jones
4efb2caa56 GU502LU led-modes 2021-03-07 21:48:44 +13:00
Luke D Jones
6f81f86483 Version bump 2021-02-22 11:48:08 +13:00
Luke D Jones
b64b8a38e4 cargo update, update udev rules 2021-02-22 11:34:47 +13:00
Luke Jones
ff56170ac5 Merge branch 'main' into 'main'
added G531GD stock_led_modes

See merge request asus-linux/asus-nb-ctrl!28
2021-02-21 08:47:51 +00:00
alenpaul2001
733f1f827e added G531GD stock_led_modes 2021-02-21 13:00:04 +05:30
Luke Jones
ac903a05da Merge branch 'donate-button' into 'main'
Test donate button

See merge request asus-linux/asus-nb-ctrl!27
2021-02-19 21:39:49 +00:00
Luke D Jones
838e6f789b Test donate button 2021-02-20 10:36:28 +13:00
Luke D Jones
d462393e8b Add 'users' group to dbus config 2021-02-20 10:15:38 +13:00
Luke D Jones
e98cf8d50b Add 0x19b6 to supported keyb list 2021-02-19 19:32:14 +13:00
Luke
eb173fc9dc CI pipe fix 2021-02-14 22:45:37 +13:00
Luke
50756046cf Cleanup fan+cpu+config 2021-02-07 00:25:40 +13:00
Luke
629bdc2213 Large code cleanup 2021-02-06 23:18:01 +13:00
Luke
39bbe33831 Further refinement 2021-02-06 08:53:02 +13:00
Luke
00bd556d7a Initial refactor 2021-02-06 08:53:02 +13:00
Luke
12061ea9df Fix 'Supported' dbus method 2021-02-06 08:52:35 +13:00
Luke Jones
580ed72e73 Merge branch 'asere/anime_compatibility' into 'next'
Adding asusd rules to restart asusd service when anime is detected too late

See merge request asus-linux/asus-nb-ctrl!18
2021-02-04 00:31:04 +00:00
Asere
c01f0892a5 adding asusd rules to restart asusd service when anime is detected too late 2021-02-03 16:44:44 +01:00
Luke Jones
0fed34b12e Merge branch 'fluke/crate-refactor' into 'next'
split out types, dbus

See merge request asus-linux/asus-nb-ctrl!21
2021-02-03 10:07:10 +00:00
Luke
0af68baf7b split out types, dbus 2021-02-03 23:06:54 +13:00
Luke Jones
161e3c4d3b Merge branch 'fluke/zbus-migrate' into 'next'
Migrate to use zbus for all dbus requirements

See merge request asus-linux/asus-nb-ctrl!20
2021-02-03 03:47:16 +00:00
Luke
4720af2cb8 Migrate to use zbus for all dbus requirements 2021-02-03 16:46:48 +13:00
Luke Jones
06d37aa009 Merge branch 'fluke/1854-device' into 'next'
Try to fix up multizone modes

See merge request asus-linux/asus-nb-ctrl!19
2021-02-01 22:09:17 +00:00
Luke
c6fa860b2e Try to fix up multizone modes
- Write set+apply after each array in multizone
- Remove misc bad logic
- Use same code path as 0x1866 device to configure led support
- Remove duplicate code
- Set correct speeds for multizone
2021-02-02 11:08:45 +13:00
Luke
4fe9ab70e5 Merge branch 'fluke/1854-device' into next 2021-01-31 10:00:48 +13:00
Luke
920e4e86f5 Trial fix for 1854 2021-01-31 10:00:06 +13:00
Luke
720dc0c177 v2.2.2 prep 2021-01-31 09:59:24 +13:00
Luke Jones
b3a555cab9 Merge branch 'fluke/asus_bios_settings' into 'next'
Bugfixes and improvements

Closes #48

See merge request asus-linux/asus-nb-ctrl!17
2021-01-27 01:16:39 +00:00
Luke
cf13b4f71b Bugfixes and improvements
- fix CLI feedback for reboot/restartx. Update readme
- dracut force driver include for nvidia dedicated
- change fan-mode CLI tag

Closes #48
2021-01-27 14:13:02 +13:00
Luke Jones
cd0b9fe350 Merge branch 'fluke/asus_bios_settings' into 'next'
Fluke/asus bios settings

See merge request asus-linux/asus-nb-ctrl!15
2021-01-26 08:08:13 +00:00
Luke
82900f4645 CLI args for bios. Cleanup and improve
- dbus method for 'supported modes'
- add dedicated gfx safety
- bring ctrl-gfx back in to main control for better integration
- safely upgrade config files
2021-01-26 21:07:19 +13:00
76 changed files with 3485 additions and 3674 deletions

View File

@@ -13,7 +13,7 @@ test:
build:
only:
- next
- main
script:
- make && make vendor
artifacts:

View File

@@ -6,6 +6,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
# [3.1.2] - 2021-03-10
### Changed
- Test and create /etc/X11/xorg.conf.d/ if it doesn't exist
- Hotfix to better report module issues
# [3.1.1] - 2021-03-10
### Changed
- Add missing nvidia module nvidia_uvm to gfx ctrl list
# [3.1.0] - 2021-03-09
### Added
- GU502LU led-modes
### Changed
- Graphics switching is now rebootless, the daemon will now restart the
display-manager to switch modes instead. Caveats are:
+ There is no confirmation from the daemon, the program issuing the command
must confirm the request.
+ systemd only
- Laptops with dedicated Nvidia mode:
+ You still must reboot for the bios to switch modes
+ On boot if dedicated mode is active then asusd will update the required configs
to put display-manager in nvidia mode
# [3.0.0] - 2021-02-22
### Added
- G531GD led modes
# [3.0.0] - 2021-02-14
### Changed
- Write set+apply after each array in multizone
- Remove misc bad logic
- Use same code path as 0x1866 device to configure led support for 0x1854 device
- Remove duplicate code
- Set correct speeds for multizone
- Remove dbus crate in favour of zbus. This removes the external dbus lib requirement.
- Huge internal refactor
- BREAKING CHANGE: Anime code refactor. DBUS method names have changed
- Cleanup fan and cpu control + configs
# [2.2.2] - 2021-01-31
### Changed
- Fix for dedicated gfx capable laptops in integrated mode
- Fix for 0x1854 device
# [2.2.1] - 2021-01-27
### Added
- Add ROG Zephyrus M15 LED config
### Changed
- Bugfixes
- Fix reboot/restartx status for GFX switching
- Update readme
- Change CLI arg tag for fan modes
- Make dracut include the nvidia modules in initramfs
# [2.2.0] - 2021-01-26
### Added
- Dbus command to fetch all supported functions of the laptop. That is, all the
functions that asusd supports for the currently running laptop.
- Bios setting toggles for:
+ Dedicated gfx toggle (support depends on the laptop)
+ Bios boot POST sound toggle
### Changed
- added config option for dedicated gfx mode on laptops with it to enable
switching directly to dedicated using `asusctl graphics -m nvidia`
# [2.1.2] - 2021-01-10
### Changed
- Adjust gfx controller to assume that the graphics driver is loaded if the

430
Cargo.lock generated
View File

@@ -1,11 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aho-corasick"
version = "0.7.15"
@@ -28,56 +22,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "asus-nb"
version = "2.1.2"
name = "asus-notify"
version = "3.0.0"
dependencies = [
"daemon",
"notify-rust",
"rog_dbus",
"serde_json",
]
[[package]]
name = "asusctl"
version = "3.1.0"
dependencies = [
"ctrl-gfx",
"dbus",
"gumdrop",
"rog_fan_curve",
"serde",
"serde_derive",
"rog_dbus",
"rog_types",
"serde_json",
"tinybmp",
"yansi-term",
"zbus",
"zvariant",
]
[[package]]
name = "asus-nb-ctrl"
version = "2.1.2"
dependencies = [
"asus-nb",
"ctrl-gfx",
"env_logger",
"gumdrop",
"intel-pstate",
"log",
"rog_fan_curve",
"rusb",
"serde",
"serde_derive",
"serde_json",
"sysfs-class",
"toml 0.4.10",
"udev",
"yansi-term",
"zbus",
"zvariant",
]
[[package]]
name = "asus-notify"
version = "2.0.4"
dependencies = [
"asus-nb",
"asus-nb-ctrl",
"dbus",
"notify-rust",
"serde",
"serde_derive",
"serde_json",
]
[[package]]
@@ -166,9 +129,9 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
[[package]]
name = "cc"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
@@ -210,55 +173,48 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crc32fast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
checksum = "bae8f328835f8f5a6ceb6a7842a7f2d0c03692adb5c889347235d59194731fe3"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"lazy_static",
"loom",
]
[[package]]
name = "ctrl-gfx"
version = "2.1.4"
name = "daemon"
version = "3.1.2"
dependencies = [
"env_logger",
"intel-pstate",
"log",
"rog_dbus",
"rog_fan_curve",
"rog_types",
"rusb",
"serde",
"serde_derive",
"serde_json",
"sysfs-class",
"toml",
"udev",
"zbus",
"zvariant",
]
[[package]]
name = "dbus"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cd9e78c210146a1860f897db03412fd5091fd73100778e43ee255cca252cf32"
dependencies = [
"libc",
"libdbus-sys",
]
[[package]]
name = "derivative"
version = "2.1.3"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
@@ -289,15 +245,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "env_logger"
version = "0.7.1"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
dependencies = [
"atty",
"humantime",
@@ -314,9 +270,9 @@ checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote 1.0.8",
"quote 1.0.9",
"rustversion",
"syn 1.0.58",
"syn 1.0.60",
"synstructure",
]
@@ -329,23 +285,11 @@ dependencies = [
"instant",
]
[[package]]
name = "filetime"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "futures"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c"
checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150"
dependencies = [
"futures-channel",
"futures-core",
@@ -358,9 +302,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9"
checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846"
dependencies = [
"futures-core",
"futures-sink",
@@ -368,15 +312,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08"
checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65"
[[package]]
name = "futures-executor"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068"
checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9"
dependencies = [
"futures-core",
"futures-task",
@@ -385,9 +329,9 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b"
checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500"
[[package]]
name = "futures-lite"
@@ -406,36 +350,36 @@ dependencies = [
[[package]]
name = "futures-macro"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664"
checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "futures-sink"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb"
checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6"
[[package]]
name = "futures-task"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038"
checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86"
dependencies = [
"once_cell",
]
[[package]]
name = "futures-util"
version = "0.3.9"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9"
checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b"
dependencies = [
"futures-channel",
"futures-core",
@@ -451,6 +395,19 @@ dependencies = [
"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]]
name = "getrandom"
version = "0.1.16"
@@ -478,27 +435,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "hermit-abi"
version = "0.1.17"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "instant"
@@ -533,36 +487,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.82"
version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]]
name = "libdbus-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
dependencies = [
"pkg-config",
]
[[package]]
name = "libflate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389de7875e06476365974da3e7ff85d55f1972188ccd9f6020dd7c8156e17914"
dependencies = [
"adler32",
"crc32fast",
"libflate_lz77",
"rle-decode-fast",
]
[[package]]
name = "libflate_lz77"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]]
name = "libudev-sys"
@@ -576,25 +503,34 @@ dependencies = [
[[package]]
name = "libusb1-sys"
version = "0.4.4"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be241693102a24766d0b8526c8988771edac2842630d7e730f8e9fbc014f3703"
checksum = "e22e89d08bbe6816c6c5d446203b859eba35b8fa94bf1b7edb2f6d25d43f023f"
dependencies = [
"cc",
"libc",
"libflate",
"pkg-config",
"tar",
"vcpkg",
]
[[package]]
name = "log"
version = "0.4.11"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
]
[[package]]
name = "loom"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d44c73b4636e497b4917eb21c33539efa3816741a2d3ff26c6316f1b529481a4"
dependencies = [
"cfg-if 1.0.0",
"generator",
"scoped-tls",
]
[[package]]
@@ -626,12 +562,12 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "nb-connect"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998"
checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f"
dependencies = [
"libc",
"winapi",
"socket2",
]
[[package]]
@@ -739,9 +675,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]]
name = "pin-project-lite"
version = "0.2.1"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36743d754ccdf9954c2e352ce2d4b106e024c814f6499c2dadff80da9a442d8"
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
[[package]]
name = "pin-utils"
@@ -774,7 +710,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml 0.5.8",
"toml",
]
[[package]]
@@ -785,8 +721,8 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
"version_check",
]
@@ -797,7 +733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"quote 1.0.9",
"version_check",
]
@@ -809,9 +745,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
@@ -822,12 +758,6 @@ dependencies = [
"unicode-xid 0.2.1",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "0.3.15"
@@ -836,9 +766,9 @@ checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
[[package]]
name = "quote"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
@@ -879,10 +809,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rle-decode-fast"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
name = "rog_dbus"
version = "3.0.0"
dependencies = [
"rog_fan_curve",
"rog_types",
"serde_json",
"zbus",
"zbus_macros",
"zvariant",
]
[[package]]
name = "rog_fan_curve"
@@ -893,11 +829,23 @@ dependencies = [
"serde",
]
[[package]]
name = "rog_types"
version = "3.0.0"
dependencies = [
"gumdrop",
"rog_fan_curve",
"serde",
"serde_derive",
"zvariant",
"zvariant_derive",
]
[[package]]
name = "rusb"
version = "0.6.5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f32cd45962594f9f8cd4547b5757132715600e2c8840aa9ccd3d1a9ed6fdc6"
checksum = "c470dc7dc6e4710b6f85e9c4aa4650bc742260b39a36328180578db76fa258c1"
dependencies = [
"libc",
"libusb1-sys",
@@ -935,29 +883,29 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "serde"
version = "1.0.118"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.118"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "serde_json"
version = "1.0.61"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
dependencies = [
"itoa",
"ryu",
@@ -971,8 +919,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
@@ -988,8 +936,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "socket2"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
"cfg-if 1.0.0",
"libc",
"winapi",
]
[[package]]
@@ -1021,12 +980,12 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.58"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"quote 1.0.9",
"unicode-xid 0.2.1",
]
@@ -1046,8 +1005,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
"unicode-xid 0.2.1",
]
@@ -1060,18 +1019,6 @@ dependencies = [
"numtoa",
]
[[package]]
name = "tar"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290"
dependencies = [
"filetime",
"libc",
"redox_syscall",
"xattr",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@@ -1083,11 +1030,11 @@ dependencies = [
[[package]]
name = "thread_local"
version = "1.1.0"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"lazy_static",
"once_cell",
]
[[package]]
@@ -1110,15 +1057,6 @@ dependencies = [
"nom",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.5.8"
@@ -1130,12 +1068,13 @@ dependencies = [
[[package]]
name = "udev"
version = "0.4.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24953d50a3bce0f5f5a9a2766567072dc9af8096f8c40ea81815da651066bc9f"
checksum = "307c2b8c8a320a38365def5bb3ee92d146d405655196230f7a445fe4da6749f6"
dependencies = [
"libc",
"libudev-sys",
"pkg-config",
]
[[package]]
@@ -1243,9 +1182,9 @@ dependencies = [
[[package]]
name = "winrt-notification"
version = "0.2.2"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c31a65da50d792c6f9bd2e3216249566c4fb1d2d34f9b7d2d66d2e93f62a242"
checksum = "57790eb281688a4682dab44df2a1ba8b78373233bd71cb291c3e75fecb1a01c4"
dependencies = [
"strum",
"strum_macros",
@@ -1254,15 +1193,6 @@ dependencies = [
"xml-rs",
]
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
dependencies = [
"libc",
]
[[package]]
name = "xml-rs"
version = "0.6.1"
@@ -1312,15 +1242,15 @@ checksum = "87cc141cda72384bef359badf1808e391d3968f9299e8f3c3cbb78dafa1e0930"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]]
name = "zvariant"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bfdc513511335faee7b18d6e8b6086de555d6e8b0a598415571bb0f0b446519"
checksum = "2fc67d552ac18ccd9e440f062f5b32c46776f96073122a8da2fe0c533833a213"
dependencies = [
"byteorder",
"enumflags2",
@@ -1330,12 +1260,12 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6651d08772eefc17d36ef4da3a521b2e5f87c10ef730125b83eb500512073c92"
checksum = "eaee686340b5bff077d52423d8cc4f0f7cb323fe3f31ef676b8a3a2810bc53c5"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.8",
"syn 1.0.58",
"quote 1.0.9",
"syn 1.0.60",
]

View File

@@ -1,5 +1,5 @@
[workspace]
members = ["asus-notify", "asus-nb-ctrl", "asus-nb", "ctrl-gfx"]
members = ["asusctl", "asus-notify", "daemon", "rog-types", "rog-dbus"]
[profile.release]
lto = true

View File

@@ -1,4 +1,4 @@
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2)
INSTALL = install
INSTALL_PROGRAM = ${INSTALL} -D -m 0755

View File

@@ -1,5 +1,7 @@
# ASUS NB Ctrl
[![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/)
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features.
@@ -7,6 +9,10 @@ but can also be used with non-asus laptops with reduced features.
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
**NOTICE:**
The following is *not* required for 5.11 kernel versions, as this version includes
all the required patches.
---
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
Alternatively you may use the dkms module for 'hid-asus-rog` from one of the
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
@@ -53,13 +59,17 @@ will probably suffer another rename once it becomes generic enough to do so.
- [X] Set battery charge limit (with kernel supporting this)
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
- [X] Toggle bios setting for boot/POST sound
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
# FUNCTIONS
## Graphics switching
A new feature has been added to enable switching graphics modes. This can be disabled
in the config with `"manage_gfx": false,`. Please be aware it is a work in progress.
in the config with `"manage_gfx": false,`. Additionally there is an extra setting
for laptops capable of g-sync dedicated gfx mode to enable the graphics switching
to switch on dedicated gfx for "nvidia" mode.
The CLI option for this does not require root until it asks for it, and provides
instructions.
@@ -79,7 +89,8 @@ If you have installed the Nvidia driver manually you will require the
### fedora and openSUSE
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
to stop dracut including the nvidia modules in the ramdisk.
to stop dracut including the nvidia modules in the ramdisk. This is espeically
true if you manually installed the nvidia drivers.
```
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
@@ -135,9 +146,9 @@ To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profil
Requirements are rust >= 1.40 installed from rustup.io if the distro provided version is too old, and `make`.
**Ubuntu*:** `apt install libdbus-1-dev libclang-dev libudev-dev`
**Ubuntu*:** `apt install libclang-dev libudev-dev`
**fedora:** `dnf install clang-devel dbus-devel systemd-devel`
**fedora:** `dnf install clang-devel systemd-devel`
## Installing

1016
asus-nb-ctrl/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
///
pub mod ctrl_anime;
///
pub mod ctrl_charge;
///
pub mod ctrl_fan_cpu;
///
pub mod ctrl_leds;
///
/// Laptop matching to determine capabilities
pub mod laptops;
mod error;
use crate::error::RogError;
use config::Config;
use zbus::ObjectServer;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>;
}
pub trait ZbusAdd {
fn add_to_server(self, server: &mut ObjectServer);
}
pub trait CtrlTask {
fn do_task(&mut self) -> Result<(), RogError>;
}
pub trait CtrlTaskComplex {
type A;
fn do_task(&mut self, config: &mut Config, event: Self::A);
}

View File

@@ -1,269 +0,0 @@
use asus_nb::{
anime_dbus::AniMeDbusWriter,
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin},
core_dbus::AuraDbusClient,
profile::{ProfileCommand, ProfileEvent},
};
use ctrl_gfx::vendors::GfxVendors;
use daemon::ctrl_fan_cpu::FanLevel;
use gumdrop::{Opt, Options};
use log::LevelFilter;
use std::{env::args, io::Write, process::Command};
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
#[derive(Default, Options)]
struct CLIStart {
#[options(help_flag, help = "print help message")]
help: bool,
#[options(help = "show program version number")]
version: bool,
#[options(meta = "VAL", help = "<off, low, med, high>")]
kbd_bright: Option<LedBrightness>,
#[options(meta = "PWR", help = "<silent, normal, boost>")]
pwr_profile: Option<FanLevel>,
#[options(meta = "CHRG", help = "<20-100>")]
chg_limit: Option<u8>,
#[options(command)]
command: Option<CliCommand>,
}
#[derive(Options)]
enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand),
#[options(help = "Create and configure profiles")]
Profile(ProfileCommand),
#[options(help = "Set the graphics mode")]
Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")]
AniMe(AniMeCommand),
}
#[derive(Options)]
struct LedModeCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "switch to next aura mode")]
next_mode: bool,
#[options(help = "switch to previous aura mode")]
prev_mode: bool,
#[options(command)]
command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
struct GraphicsCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "Set graphics mode: <nvidia, hybrid, compute, integrated>")]
mode: Option<GfxVendors>,
#[options(help = "Get the current mode")]
get: bool,
#[options(help = "Get the current power status")]
pow: bool,
#[options(help = "Do not ask for confirmation")]
force: bool,
}
#[derive(Options)]
struct AniMeCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "turn on/off the panel (accept/reject write requests)")]
turn: Option<AniMeStatusValue>,
#[options(help = "turn on/off the panel at boot (with Asus effect)")]
boot: Option<AniMeStatusValue>,
#[options(command)]
command: Option<AniMeActions>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init();
let mut args: Vec<String> = args().collect();
args.remove(0);
let parsed: CLIStart;
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
match CLIStart::parse_args_default(&args) {
Ok(p) => {
parsed = p;
}
Err(err) if err.to_string() == missing_argument_k.to_string() => {
parsed = CLIStart {
kbd_bright: Some(LedBrightness::new(None)),
..Default::default()
};
}
Err(err) => {
eprintln!("source {}", err);
std::process::exit(2);
}
}
if parsed.help_requested() {
// As help option don't work with `parse_args_default`
// we will call `parse_args_default_or_exit` instead
CLIStart::parse_args_default_or_exit();
}
if parsed.version {
println!("Version: {}", daemon::VERSION);
}
let writer = AuraDbusClient::new()?;
let anime_writer = AniMeDbusWriter::new()?;
match parsed.command {
Some(CliCommand::LedMode(mode)) => {
if mode.next_mode && mode.prev_mode {
println!("Please specify either next or previous")
}
if mode.next_mode {
writer.next_keyboard_led_mode()?;
} else if mode.prev_mode {
writer.prev_keyboard_led_mode()?;
} else if let Some(command) = mode.command {
writer.write_builtin_mode(&command.into())?
}
}
Some(CliCommand::Profile(command)) => {
if command.next {
writer.next_fan_profile()?;
} else {
writer.write_profile_command(&ProfileEvent::Cli(command))?
}
}
Some(CliCommand::Graphics(command)) => do_gfx(command, &writer)?,
Some(CliCommand::AniMe(anime)) => {
if let Some(anime_turn) = anime.turn {
anime_writer.turn_on_off(anime_turn.into())?
}
if let Some(anime_boot) = anime.boot {
anime_writer.turn_boot_on_off(anime_boot.into())?
}
if let Some(action) = anime.command {
match action {
AniMeActions::Leds(anime_leds) => {
let led_brightness = anime_leds.led_brightness();
anime_writer.set_leds_brightness(led_brightness)?;
}
}
}
}
None => (),
}
if let Some(brightness) = parsed.kbd_bright {
match brightness.level() {
None => {
let level = writer.get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string());
}
Some(level) => writer.write_brightness(level)?,
}
}
if let Some(fan_level) = parsed.pwr_profile {
writer.write_fan_mode(fan_level.into())?;
}
if let Some(chg_limit) = parsed.chg_limit {
writer.write_charge_limit(chg_limit)?;
}
Ok(())
}
fn do_gfx(
command: GraphicsCommand,
writer: &AuraDbusClient,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(mode) = command.mode {
println!("Updating settings, please wait...");
println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`");
writer.write_gfx_mode(mode)?;
let res = writer.wait_gfx_changed()?;
match res.as_str() {
"reboot" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n"),
);
do_gfx_action(
command.force,
Command::new("systemctl").arg("reboot").arg("-i"),
"Reboot Linux PC",
"Please reboot when ready",
)?;
}
"restartx" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n")
);
do_gfx_action(
command.force,
Command::new("systemctl")
.arg("restart")
.arg("display-manager.service"),
"Restart display-manager server",
"Please restart display-manager when ready",
)?;
std::process::exit(1)
}
_ => std::process::exit(-1),
}
std::process::exit(-1)
}
if command.get {
let res = writer.get_gfx_mode()?;
println!("Current graphics mode: {}", res);
}
if command.pow {
let res = writer.get_gfx_pwr()?;
if res.contains("active") {
println!("Current power status: {}", Red.paint(&format!("{}", res)));
} else {
println!("Current power status: {}", Green.paint(&format!("{}", res)));
}
}
Ok(())
}
fn do_gfx_action(
no_confirm: bool,
command: &mut Command,
ask_msg: &str,
cancel_msg: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{}? y/n", ask_msg);
let mut buf = String::new();
if no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
}
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' || no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
} else {
println!("{}", Red.paint(&format!("{}", cancel_msg)));
}
Ok(())
}

View File

@@ -1,107 +0,0 @@
const DBUS_ANIME_PATH: &str = "/org/asuslinux/Anime";
pub const ANIME_PANE1_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
use crate::DBUS_NAME;
use dbus::blocking::{Connection, Proxy};
use std::error::Error;
use std::{thread, time::Duration};
use crate::dbus_anime::OrgAsuslinuxDaemon as OrgAsuslinuxDaemonAniMe;
/// Interface for the AniMe dot-matrix display
///
/// The resolution is 34x56 (1904) but only 1,215 LEDs in the top-left are used.
/// The display is available only on select GA401 models.
///
/// Actual image ratio when displayed is stretched width.
///
/// Data structure should be nested array of [[u8; 33]; 56]
pub struct AniMeDbusWriter {
connection: Box<Connection>,
block_time: u64,
}
impl AniMeDbusWriter {
#[inline]
pub fn new() -> Result<Self, Box<dyn Error>> {
let connection = Connection::new_system()?;
Ok(AniMeDbusWriter {
connection: Box::new(connection),
block_time: 25,
})
}
// Create D-Bus proxy
fn new_proxy(&self) -> Proxy<&Connection> {
self.connection
.with_proxy(DBUS_NAME, DBUS_ANIME_PATH, Duration::from_millis(200))
}
fn thread_sleep(&self) {
thread::sleep(Duration::from_millis(self.block_time));
}
pub fn write_image_to_buf(_buf: &mut AniMePacketType, _image_data: &[u8]) {
unimplemented!("Image format is in progress of being worked out")
}
/// Write an Animatrix image
///
/// The expected input here is *two* Vectors, 640 bytes in length.
/// The two vectors are each one half of the full image write.
///
/// After each write a flush is written, it is assumed that this tells the
/// device to go ahead and display the written bytes
///
/// # Note: The vectors are expected to contain the full sequence of bytes
/// as follows
///
/// - Write packet 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. <led brightness>
/// - Write packet 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
pub fn write_image(&self, image: &mut AniMePacketType) -> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
proxy.set_anime(vec![image[0].to_vec(), image[1].to_vec()])?;
self.thread_sleep();
Ok(())
}
#[inline]
pub fn set_leds_brightness(&self, led_brightness: u8) -> Result<(), Box<dyn Error>> {
let mut anime_matrix = AniMeMatrix::new();
anime_matrix.fill_with(led_brightness);
self.write_image(&mut AniMePacketType::from(anime_matrix))?;
Ok(())
}
#[inline]
pub fn turn_on_off(&self, status: bool) -> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
proxy.set_on_off(status)?;
self.thread_sleep();
Ok(())
}
#[inline]
pub fn turn_boot_on_off(&self, status: bool) -> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
proxy.set_boot_on_off(status)?;
self.thread_sleep();
Ok(())
}
}

View File

@@ -1,287 +0,0 @@
use crate::error::AuraError;
use gumdrop::Options;
use serde_derive::{Deserialize, Serialize};
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!(
"{}\n{}\n",
"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(Deserialize, Serialize)]
pub struct Colour(pub u8, pub u8, pub u8);
impl Default for Colour {
fn default() -> Self {
Colour(255, 0, 0)
}
}
impl FromStr for Colour {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() < 6 {
return Err(AuraError::ParseColour);
}
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
Ok(Colour(r, g, b))
}
}
#[derive(Deserialize, Serialize)]
pub enum Speed {
Low = 0xe1,
Med = 0xeb,
High = 0xf5,
}
impl Default for Speed {
fn default() -> Self {
Speed::Med
}
}
impl FromStr for Speed {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"low" => Ok(Speed::Low),
"med" => Ok(Speed::Med),
"high" => Ok(Speed::High),
_ => Err(AuraError::ParseSpeed),
}
}
}
/// Used for Rainbow mode.
///
/// Enum corresponds to the required integer value
#[derive(Deserialize, Serialize)]
pub enum Direction {
Right,
Left,
Up,
Down,
}
impl Default for Direction {
fn default() -> Self {
Direction::Right
}
}
impl FromStr for Direction {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"right" => Ok(Direction::Right),
"up" => Ok(Direction::Up),
"down" => Ok(Direction::Down),
"left" => Ok(Direction::Left),
_ => Err(AuraError::ParseDirection),
}
}
}
#[derive(Default, Options, Deserialize, Serialize)]
pub struct TwoColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "HEX", help = "set the first RGB value e.g, ff00ff")]
pub colour: Colour,
#[options(no_long, meta = "HEX", help = "set the second RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(no_long, help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Default, Options, Deserialize, Serialize)]
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(Default, Options, Deserialize, Serialize)]
pub struct SingleColour {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour: Colour,
}
#[derive(Default, Options, Deserialize, Serialize)]
pub struct MultiColour {
#[options(help = "print help message")]
help: bool,
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour1: Colour,
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour2: Colour,
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour3: Colour,
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour4: Colour,
}
#[derive(Default, Options, Deserialize, Serialize)]
pub struct SingleSpeedDirection {
#[options(help = "print help message")]
help: bool,
#[options(
no_long,
meta = "DIR",
help = "set the direction: up, down, left, right"
)]
pub direction: Direction,
#[options(no_long, help = "set the speed: low, med, high")]
pub speed: Speed,
}
#[derive(Default, Options, Deserialize, Serialize)]
pub struct SingleColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "HEX", help = "set the RGB value e.g, ff00ff")]
pub colour: Colour,
#[options(no_long, 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, 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),
}
impl Default for SetAuraBuiltin {
fn default() -> Self {
SetAuraBuiltin::Static(SingleColour {
help: false,
colour: Colour(255, 0, 0),
})
}
}
#[derive(Copy, Clone, Debug)]
pub enum AniMeStatusValue {
On,
Off,
}
impl FromStr for AniMeStatusValue {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"on" => Ok(AniMeStatusValue::On),
"off" => Ok(AniMeStatusValue::Off),
_ => {
print!("{}\n{}\n", "Invalid argument, must be one of:", "on, off");
Err(AuraError::ParseAnime)
}
}
}
}
impl From<AniMeStatusValue> for bool {
fn from(value: AniMeStatusValue) -> Self {
match value {
AniMeStatusValue::On => true,
AniMeStatusValue::Off => false,
}
}
}
#[derive(Options)]
pub struct AniMeLeds {
#[options(help = "print help message")]
help: bool,
#[options(
no_long,
required,
short = "b",
meta = "BYTE",
help = "set all leds brightness value"
)]
led_brightness: u8,
}
impl AniMeLeds {
pub fn led_brightness(&self) -> u8 {
self.led_brightness
}
}
#[derive(Options)]
pub enum AniMeActions {
#[options(help = "change all leds brightness")]
Leds(AniMeLeds),
}

View File

@@ -1,361 +0,0 @@
use super::*;
use crate::cli_options::LedBrightness;
use crate::fancy::KeyColourArray;
use crate::profile::ProfileEvent;
use ctrl_gfx::vendors::GfxVendors;
use dbus::{blocking::Connection, Message};
use std::error::Error;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
};
use std::{thread, time::Duration};
use crate::dbus_charge::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonCharge, OrgAsuslinuxDaemonNotifyCharge,
};
use crate::dbus_gfx::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonGfx, OrgAsuslinuxDaemonNotifyAction,
OrgAsuslinuxDaemonNotifyGfx,
};
use crate::dbus_ledmode::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonLed, OrgAsuslinuxDaemonNotifyLed,
};
use crate::dbus_profile::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonProfile, OrgAsuslinuxDaemonNotifyProfile,
};
// Signals separated out
pub struct CtrlSignals {
pub gfx_vendor_signal: Arc<Mutex<Option<String>>>,
pub gfx_action_signal: Arc<Mutex<Option<String>>>,
pub profile_signal: Arc<Mutex<Option<String>>>,
pub ledmode_signal: Arc<Mutex<Option<AuraModes>>>,
pub charge_signal: Arc<Mutex<Option<u8>>>,
}
impl CtrlSignals {
#[inline]
pub fn new(connection: &Connection) -> Result<Self, Box<dyn Error>> {
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(2),
);
let gfx_vendor_signal = Arc::new(Mutex::new(None));
let gfx_res1 = gfx_vendor_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyGfx, _: &Connection, _: &Message| {
if let Ok(mut lock) = gfx_res1.lock() {
*lock = Some(sig.vendor);
}
true
},
)?;
let gfx_action_signal = Arc::new(Mutex::new(None));
let gfx_res1 = gfx_action_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyAction, _: &Connection, _: &Message| {
if let Ok(mut lock) = gfx_res1.lock() {
*lock = Some(sig.action);
}
true
},
)?;
//
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
let profile_signal = Arc::new(Mutex::new(None));
let prof_res1 = profile_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyProfile, _: &Connection, _: &Message| {
if let Ok(mut lock) = prof_res1.lock() {
*lock = Some(sig.profile);
}
true
},
)?;
//
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
let ledmode_signal = Arc::new(Mutex::new(None));
let led_res1 = ledmode_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyLed, _: &Connection, _: &Message| {
if let Ok(mut lock) = led_res1.lock() {
if let Ok(dat) = serde_json::from_str(&sig.data) {
*lock = Some(dat);
}
}
true
},
)?;
//
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Charge",
Duration::from_secs(2),
);
let charge_signal = Arc::new(Mutex::new(None));
let charge_res1 = charge_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyCharge, _: &Connection, _: &Message| {
if let Ok(mut lock) = charge_res1.lock() {
*lock = Some(sig.limit);
}
true
},
)?;
Ok(CtrlSignals {
gfx_vendor_signal,
gfx_action_signal,
profile_signal,
ledmode_signal,
charge_signal,
})
}
}
/// Simplified way to write a effect block
pub struct AuraDbusClient {
connection: Box<Connection>,
block_time: u64,
stop: Arc<AtomicBool>,
signals: CtrlSignals,
}
impl AuraDbusClient {
#[inline]
pub fn new() -> Result<Self, Box<dyn Error>> {
let connection = Connection::new_system()?;
let stop = Arc::new(AtomicBool::new(false));
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "NotifyLed");
let stop1 = stop.clone();
connection.add_match(match_rule, move |_: (), _, msg| {
if msg.read1::<&str>().is_ok() {
stop1.clone().store(true, Ordering::Relaxed);
}
true
})?;
let signals = CtrlSignals::new(&connection)?;
Ok(AuraDbusClient {
connection: Box::new(connection),
block_time: 33333,
stop,
signals,
})
}
pub fn wait_gfx_changed(&self) -> Result<String, Box<dyn Error>> {
loop {
self.connection.process(Duration::from_millis(1))?;
if let Ok(lock) = self.signals.gfx_action_signal.lock() {
if let Some(stuff) = lock.as_ref() {
return Ok(stuff.to_string());
}
}
}
}
/// This method must always be called before the very first write to initialise
/// the keyboard LED EC in the correct mode
#[inline]
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
let mode = AuraModes::PerKey(vec![vec![]]);
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.set_led_mode(&serde_json::to_string(&mode)?)?;
Ok(())
}
/// Write a single colour block.
///
/// Intentionally blocks for 10ms after sending to allow the block to
/// be written to the keyboard EC. This should not be async.
#[inline]
pub fn write_colour_block(
&mut self,
key_colour_array: &KeyColourArray,
) -> Result<(), Box<dyn Error>> {
let group = key_colour_array.get();
let mut vecs = Vec::with_capacity(group.len());
for v in group {
vecs.push(v.to_vec());
}
let mode = AuraModes::PerKey(vecs);
self.write_keyboard_leds(&mode)?;
thread::sleep(Duration::from_micros(self.block_time));
self.connection.process(Duration::from_micros(500))?;
if self.stop.load(Ordering::Relaxed) {
println!("Keyboard backlight was changed, exiting");
std::process::exit(1)
}
Ok(())
}
#[inline]
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.set_led_mode(&serde_json::to_string(mode)?)?;
Ok(())
}
#[inline]
pub fn next_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.next_led_mode()?;
Ok(())
}
#[inline]
pub fn prev_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.prev_led_mode()?;
Ok(())
}
#[inline]
pub fn get_gfx_pwr(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(2),
);
let x = proxy.power()?;
Ok(x)
}
#[inline]
pub fn get_gfx_mode(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(2),
);
let x = proxy.vendor()?;
Ok(x)
}
#[inline]
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(30),
);
proxy.set_vendor(<&str>::from(&vendor))?;
Ok(())
}
#[inline]
pub fn next_fan_profile(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
proxy.next_profile()?;
Ok(())
}
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
proxy.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level))?)?;
Ok(())
}
#[inline]
pub fn write_profile_command(
&self,
cmd: &ProfileEvent,
) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
proxy.set_profile(&serde_json::to_string(cmd)?)?;
Ok(())
}
#[inline]
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Charge",
Duration::from_secs(2),
);
proxy.set_limit(level)?;
Ok(())
}
#[inline]
pub fn write_builtin_mode(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
self.write_keyboard_leds(mode)
}
#[inline]
pub fn get_led_brightness(&self) -> Result<LedBrightness, Box<dyn Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
match proxy.led_brightness()? {
-1 => Ok(LedBrightness::new(None)),
level => Ok(LedBrightness::new(Some(level as u8))),
}
}
#[inline]
pub fn write_brightness(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
self.write_keyboard_leds(&AuraModes::LedBrightness(level))?;
Ok(())
}
}

View File

@@ -1,27 +0,0 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Anime -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error>;
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error>;
fn set_boot_on_off(&self, status: bool) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetAnime", (input,))
}
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetOnOff", (status,))
}
fn set_boot_on_off(&self, status: bool) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetBootOnOff", (status,))
}
}

View File

@@ -1,45 +0,0 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Charge -m None`, see https://github.com/diwic/dbus-rs
use dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_limit(&self, limit: u8) -> Result<(), dbus::Error>;
fn limit(&self) -> Result<i16, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
fn set_limit(&self, limit: u8) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetLimit", (limit,))
}
fn limit(&self) -> Result<i16, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Limit", ())
.and_then(|r: (i16,)| Ok(r.0))
}
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyCharge {
pub limit: u8,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyCharge {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.limit, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyCharge {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyCharge { limit: i.read()? })
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyCharge {
const NAME: &'static str = "NotifyCharge";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}

View File

@@ -1,73 +0,0 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Gfx -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn vendor(&self) -> Result<String, dbus::Error>;
fn power(&self) -> Result<String, dbus::Error>;
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
fn vendor(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Vendor", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn power(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Power", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetVendor", (vendor,))
}
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyGfx {
pub vendor: String,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyGfx {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.vendor, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyGfx {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyGfx { vendor: i.read()? })
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyGfx {
const NAME: &'static str = "NotifyGfx";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyAction {
pub action: String,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyAction {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.action, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyAction {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyAction { action: i.read()? })
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyAction {
const NAME: &'static str = "NotifyAction";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}

View File

@@ -1,67 +0,0 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Led -m None`, see https://github.com/diwic/dbus-rs
use dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error>;
fn next_led_mode(&self) -> Result<(), dbus::Error>;
fn prev_led_mode(&self) -> Result<(), dbus::Error>;
fn led_mode(&self) -> Result<String, dbus::Error>;
fn led_modes(&self) -> Result<String, dbus::Error>;
fn led_brightness(&self) -> Result<i16, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetLedMode", (data,))
}
fn next_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextLedMode", ())
}
fn prev_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "PrevLedMode", ())
}
fn led_mode(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedMode", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn led_modes(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedModes", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn led_brightness(&self) -> Result<i16, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedBrightness", ())
.and_then(|r: (i16,)| Ok(r.0))
}
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyLed {
pub data: String,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyLed {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.data, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyLed {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyLed { data: i.read()? })
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyLed {
const NAME: &'static str = "NotifyLed";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}

View File

@@ -1,62 +0,0 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Profile -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error>;
fn next_profile(&self) -> Result<(), dbus::Error>;
fn active_profile_name(&self) -> Result<String, dbus::Error>;
fn profile(&self) -> Result<String, dbus::Error>;
fn profiles(&self) -> Result<String, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile,))
}
fn next_profile(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextProfile", ())
}
fn active_profile_name(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "ActiveProfileName", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn profile(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profile", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn profiles(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profiles", ())
.and_then(|r: (String,)| Ok(r.0))
}
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyProfile {
pub profile: String,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyProfile {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.profile, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyProfile {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyProfile { profile: i.read()? })
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyProfile {
const NAME: &'static str = "NotifyProfile";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-notify"
version = "2.0.4"
version = "3.0.0"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
@@ -8,14 +8,11 @@ edition = "2018"
[dependencies]
# serialisation
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
dbus = { version = "^0.8" }
asus-nb = { path = "../asus-nb" }
asus-nb-ctrl = { path = "../asus-nb-ctrl" }
rog_dbus = { path = "../rog-dbus" }
daemon = { path = "../daemon" }
[dependencies.notify-rust]
version = "^4.0.0"
version = "^4.0"
default-features = false
features = ["z"]

View File

@@ -1,29 +1,31 @@
use asus_nb::core_dbus::CtrlSignals;
use daemon::config::{Config, Profile};
use dbus::blocking::Connection;
use daemon::config::Profile;
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_dbus::{DbusProxies, Signals};
use std::error::Error;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Version {}", env!("CARGO_PKG_VERSION"));
println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
println!(" daemon version {}", daemon::VERSION);
println!(" rog-dbus version {}", rog_dbus::VERSION);
let mut cfg = Config::read_new()?;
let mut last_profile = String::new();
// let mut cfg = Config::read_new()?;
// let mut last_profile = String::new();
let connection = Connection::new_system()?;
let signals = CtrlSignals::new(&connection)?;
let (proxies, conn) = DbusProxies::new()?;
let signals = Signals::new(&proxies)?;
let mut last_profile_notif: Option<NotificationHandle> = None;
let mut last_led_notif: Option<NotificationHandle> = None;
let mut last_gfx_notif: Option<NotificationHandle> = None;
let mut last_chrg_notif: Option<NotificationHandle> = None;
let recv = proxies.setup_recv(conn);
loop {
std::thread::sleep(Duration::from_millis(100));
connection.process(std::time::Duration::from_millis(200))?;
recv.next_signal().unwrap();
if let Ok(mut lock) = signals.gfx_vendor_signal.lock() {
if let Ok(mut lock) = signals.gfx_vendor.lock() {
if let Some(vendor) = lock.take() {
if let Some(notif) = last_gfx_notif.take() {
notif.close();
@@ -33,17 +35,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
if let Ok(mut lock) = signals.charge_signal.lock() {
if let Ok(mut lock) = signals.charge.lock() {
if let Some(limit) = lock.take() {
if let Some(notif) = last_chrg_notif.take() {
notif.close();
}
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
last_led_notif = Some(x);
last_chrg_notif = Some(x);
}
}
if let Ok(mut lock) = signals.ledmode_signal.lock() {
if let Ok(mut lock) = signals.profile.lock() {
if let Some(profile) = lock.take() {
if let Some(notif) = last_profile_notif.take() {
notif.close();
}
if let Ok(profile) = serde_json::from_str(&profile) {
let profile: Profile = profile;
if let Ok(name) = proxies.profile().active_profile_name() {
let x = do_thermal_notif(&profile, &name)?;
last_profile_notif = Some(x);
}
}
}
}
if let Ok(mut lock) = signals.led_mode.lock() {
if let Some(ledmode) = lock.take() {
if let Some(notif) = last_led_notif.take() {
notif.close();
@@ -55,20 +72,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
last_led_notif = Some(x);
}
}
// We need to do the config read because of a limitation preventing
// easy dbus notification from the profile controller
cfg.read();
if last_profile != cfg.active_profile {
if let Some(notif) = last_profile_notif.take() {
notif.close();
}
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
let x = do_thermal_notif(&profile, &cfg.active_profile)?;
last_profile_notif = Some(x);
last_profile = cfg.active_profile.clone();
}
}
}
}

20
asusctl/Cargo.toml Normal file
View File

@@ -0,0 +1,20 @@
[package]
name = "asusctl"
version = "3.1.0"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# serialisation
serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" }
rog_types = { path = "../rog-types" }
gumdrop = "^0.8"
yansi-term = "^0.1"
[dev-dependencies]
tinybmp = "^0.2.3"
rog_dbus = { path = "../rog-dbus" }

View File

@@ -1,9 +1,9 @@
use asus_nb::anime_dbus::AniMeDbusWriter;
use asus_nb::anime_matrix::{AniMeMatrix, AniMePacketType, HEIGHT, WIDTH};
use rog_dbus::AuraDbusClient;
use rog_types::anime_matrix::{AniMeImageBuffer, AniMePacketType, HEIGHT, WIDTH};
use tinybmp::{Bmp, Pixel};
fn main() {
let mut writer = AniMeDbusWriter::new().unwrap();
let (client, _) = AuraDbusClient::new().unwrap();
let bmp =
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
@@ -11,7 +11,7 @@ fn main() {
//assert_eq!(pixels.len(), 56 * 56);
// Try an outline, top and right
let mut matrix = AniMeMatrix::new();
let mut matrix = AniMeImageBuffer::new();
// Aligned left
for (i, px) in pixels.iter().enumerate() {
@@ -38,5 +38,5 @@ fn main() {
// println!("{:?}", matrix[0].to_vec());
// println!("{:?}", matrix[1].to_vec());
writer.write_image(&mut matrix).unwrap();
//client.proxies().anime().set_brightness(&mut matrix).unwrap();
}

View File

@@ -1,7 +1,5 @@
use asus_nb::{
core_dbus::AuraDbusClient,
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
};
use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
use std::collections::LinkedList;
#[derive(Debug, Clone)]
@@ -54,7 +52,7 @@ impl Ball {
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = AuraDbusClient::new()?;
let (dbus, _) = AuraDbusClient::new()?;
let mut colours = KeyColourArray::new();
@@ -62,7 +60,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)];
writer.init_effect()?;
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
loop {
@@ -89,10 +87,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
*c.2 = 255;
};
}
dbus.proxies().led().set_per_key(&colours)?;
writer.write_colour_block(&colours)?;
// can change 100 times per second, so need to slow it down
std::thread::sleep(std::time::Duration::from_millis(30));
std::thread::sleep(std::time::Duration::from_millis(10));
}
}

View File

@@ -1,14 +1,12 @@
use asus_nb::{
core_dbus::AuraDbusClient,
fancy::{GX502Layout, KeyColourArray, KeyLayout},
};
use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = AuraDbusClient::new()?;
let (dbus, _) = AuraDbusClient::new()?;
let layout = GX502Layout::default();
writer.init_effect()?;
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
let mut column = 0;
@@ -25,7 +23,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
column += 1;
}
writer.write_colour_block(&key_colours)?;
std::thread::sleep(std::time::Duration::from_millis(30));
dbus.proxies().led().set_per_key(&key_colours)?;
}
}

View File

@@ -1,15 +1,13 @@
use asus_nb::{
core_dbus::AuraDbusClient,
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
};
use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = AuraDbusClient::new()?;
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default();
writer.init_effect()?;
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
loop {
for (r, row) in rows.iter().enumerate() {
@@ -48,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
*key_colours.key(Key::S).unwrap().0 = 255;
*key_colours.key(Key::D).unwrap().0 = 255;
writer.write_colour_block(&key_colours)?;
dbus.proxies().led().set_per_key(&key_colours)?;
std::thread::sleep(std::time::Duration::from_millis(100));
}
}

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,14 +1,12 @@
use asus_nb::{
core_dbus::AuraDbusClient,
fancy::{Key, KeyColourArray},
};
use rog_dbus::AuraDbusClient;
use rog_types::fancy::{Key, KeyColourArray};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = AuraDbusClient::new()?;
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
writer.init_effect()?;
dbus.proxies().led().init_effect()?;
loop {
let count = 49;
for _ in 0..count {
@@ -18,7 +16,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
*key_colours.key(Key::N).unwrap().0 += 5;
*key_colours.key(Key::U).unwrap().0 += 5;
*key_colours.key(Key::X).unwrap().0 += 5;
writer.write_colour_block(&key_colours)?;
dbus.proxies().led().set_per_key(&key_colours)?;
}
for _ in 0..count {
*key_colours.key(Key::ROG).unwrap().0 -= 5;
@@ -27,7 +25,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
*key_colours.key(Key::N).unwrap().0 -= 5;
*key_colours.key(Key::U).unwrap().0 -= 5;
*key_colours.key(Key::X).unwrap().0 -= 5;
writer.write_colour_block(&key_colours)?;
dbus.proxies().led().set_per_key(&key_colours)?;
}
}
}

View File

@@ -1,15 +1,13 @@
use asus_nb::{
core_dbus::AuraDbusClient,
fancy::{GX502Layout, KeyColourArray, KeyLayout},
};
use rog_dbus::AuraDbusClient;
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = AuraDbusClient::new()?;
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default();
writer.init_effect()?;
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
let mut fade = 50;
@@ -23,7 +21,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
writer.write_colour_block(&key_colours)?;
dbus.proxies().led().set_per_key(&key_colours)?;
if flip {
if fade > 1 {

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

333
asusctl/src/main.rs Normal file
View File

@@ -0,0 +1,333 @@
use gumdrop::{Opt, Options};
use rog_dbus::AuraDbusClient;
use rog_types::{
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin},
gfx_vendors::GfxVendors,
profile::{FanLevel, ProfileCommand, ProfileEvent},
};
use std::env::args;
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
#[derive(Default, Options)]
struct CLIStart {
#[options(help_flag, help = "print help message")]
help: bool,
#[options(help = "show program version number")]
version: bool,
#[options(help = "show supported functions of this laptop")]
show_supported: bool,
#[options(meta = "", help = "<off, low, med, high>")]
kbd_bright: Option<LedBrightness>,
#[options(
meta = "",
help = "<silent, normal, boost>, set fan mode independent of profile"
)]
fan_mode: Option<FanLevel>,
#[options(meta = "", help = "<20-100>")]
chg_limit: Option<u8>,
#[options(command)]
command: Option<CliCommand>,
}
#[derive(Options)]
enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand),
#[options(help = "Create and configure profiles")]
Profile(ProfileCommand),
#[options(help = "Set the graphics mode")]
Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")]
AniMe(AniMeCommand),
#[options(help = "Change bios settings")]
Bios(BiosCommand),
}
#[derive(Options)]
struct LedModeCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "switch to next aura mode")]
next_mode: bool,
#[options(help = "switch to previous aura mode")]
prev_mode: bool,
#[options(command)]
command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
struct GraphicsCommand {
#[options(help = "print help message")]
help: bool,
#[options(
meta = "",
help = "Set graphics mode: <nvidia, hybrid, compute, integrated>"
)]
mode: Option<GfxVendors>,
#[options(help = "Get the current mode")]
get: bool,
#[options(help = "Get the current power status")]
pow: bool,
#[options(help = "Do not ask for confirmation")]
force: bool,
}
#[derive(Options)]
struct AniMeCommand {
#[options(help = "print help message")]
help: bool,
#[options(
meta = "",
help = "turn on/off the panel (accept/reject write requests)"
)]
turn: Option<AniMeStatusValue>,
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")]
boot: Option<AniMeStatusValue>,
#[options(command)]
command: Option<AniMeActions>,
}
#[derive(Options, Debug)]
struct BiosCommand {
#[options(help = "print help message")]
help: bool,
#[options(meta = "", no_long, help = "toggle bios POST sound")]
post_sound_set: Option<bool>,
#[options(no_long, help = "read bios POST sound")]
post_sound_get: bool,
#[options(meta = "", no_long, help = "toggle GPU to/from dedicated mode")]
dedicated_gfx_set: Option<bool>,
#[options(no_long, help = "get GPU mode")]
dedicated_gfx_get: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut args: Vec<String> = args().collect();
args.remove(0);
let parsed: CLIStart;
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
match CLIStart::parse_args_default(&args) {
Ok(p) => {
parsed = p;
}
Err(err) if err.to_string() == missing_argument_k.to_string() => {
parsed = CLIStart {
kbd_bright: Some(LedBrightness::new(None)),
..Default::default()
};
}
Err(err) => {
eprintln!("source {}", err);
std::process::exit(2);
}
}
if parsed.help_requested() {
// As help option don't work with `parse_args_default`
// we will call `parse_args_default_or_exit` instead
CLIStart::parse_args_default_or_exit();
}
if parsed.version {
println!(" asusctl version {}", env!("CARGO_PKG_VERSION"));
println!(" rog-dbus version {}", rog_dbus::VERSION);
println!("rog-types version {}", rog_types::VERSION);
}
let (dbus, _) = AuraDbusClient::new()?;
match parsed.command {
Some(CliCommand::LedMode(mode)) => {
if (mode.command.is_none() && !mode.prev_mode && !mode.next_mode) || mode.help {
println!("Missing arg or command\n\n{}", mode.self_usage());
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)) => {
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());
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
}
if let Some(anime_turn) = cmd.turn {
dbus.proxies().anime().toggle_on(anime_turn.into())?
}
if let Some(anime_boot) = cmd.boot {
dbus.proxies().anime().toggle_boot_on(anime_boot.into())?
}
if let Some(action) = cmd.command {
match action {
AniMeActions::Leds(anime_leds) => {
let mut data = AniMeDataBuffer::new();
data.set([anime_leds.led_brightness(); FULL_PANE_LEN]);
dbus.proxies().anime().write_direct(data)?;
}
}
}
}
Some(CliCommand::Bios(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 => {
if (!parsed.show_supported
&& parsed.kbd_bright.is_none()
&& parsed.fan_mode.is_none()
&& parsed.chg_limit.is_none())
|| parsed.help
{
println!("{}", CLIStart::usage());
println!();
println!("{}", CLIStart::command_list().unwrap());
}
}
}
if let Some(brightness) = parsed.kbd_bright {
match brightness.level() {
None => {
let level = dbus.proxies().led().get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string());
}
Some(level) => dbus.proxies().led().set_brightness(level)?,
}
}
if parsed.show_supported {
let dat = dbus.proxies().supported().get_supported_functions()?;
println!("Supported laptop functions:\n{}", dat.to_string());
}
if let Some(fan_level) = parsed.fan_mode {
dbus.proxies().profile().write_fan_mode(fan_level.into())?;
}
if let Some(chg_limit) = parsed.chg_limit {
dbus.proxies().charge().write_limit(chg_limit)?;
}
Ok(())
}
fn do_gfx(
command: GraphicsCommand,
dbus_client: &AuraDbusClient,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(mode) = command.mode {
println!("Changing graphics modes...");
println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`");
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 command.get {
let res = dbus_client.proxies().gfx().gfx_get_mode()?;
println!("Current graphics mode: {}", res);
}
if command.pow {
let res = dbus_client.proxies().gfx().gfx_get_pwr()?;
if res.contains("active") {
println!("Current power status: {}", Red.paint(&format!("{}", res)));
} else {
println!("Current power status: {}", Green.paint(&format!("{}", res)));
}
}
Ok(())
}
fn do_gfx_action(no_confirm: bool, ask_msg: &str, ok_msg: &str) -> bool {
println!("{}", Red.paint(&format!("{} Continue?", ask_msg)));
let mut buf = String::new();
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' || no_confirm {
println!("{}", Green.paint(&format!("{}", ok_msg)));
return true;
}
false
}

View File

@@ -1,19 +0,0 @@
[package]
name = "ctrl-gfx"
version = "2.1.4"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
description = "Fine control of laptop GPU"
edition = "2018"
[dependencies]
sysfs-class = "^0.1.2"
log = "^0.4"
zbus = { version = "1.8.0", optional = true }
zvariant = { version = "2.4.0", optional = true }
[features]
default = ["use-zbus"]
use-zbus = ["zbus", "zvariant"]

View File

@@ -1,372 +0,0 @@
use log::{error, info, warn};
use std::error::Error;
use std::io::Write;
use std::iter::FromIterator;
use std::path::Path;
use std::process::Command;
use std::str::FromStr;
use sysfs_class::{PciDevice, SysClass};
use zbus::dbus_interface;
use crate::vendors::*;
use crate::*;
use crate::{error::GfxError, system::*};
pub struct CtrlGraphics {
bus: PciBus,
_amd: Vec<GraphicsDevice>,
_intel: Vec<GraphicsDevice>,
nvidia: Vec<GraphicsDevice>,
#[allow(dead_code)]
other: Vec<GraphicsDevice>,
initfs_cmd: Option<Command>,
}
trait Dbus {
fn vendor(&self) -> String;
fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String);
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>;
}
#[cfg(feature = "use-zbus")]
use std::convert::TryInto;
#[cfg(feature = "use-zbus")]
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics {
fn vendor(&self) -> String {
Self::get_vendor().unwrap_or_else(|err| format!("Get vendor failed: {}", err))
}
fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
}
fn set_vendor(&mut self, vendor: String) {
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
let action = self.set(tmp).unwrap_or_else(|err| {
warn!("{}", err);
format!("Failed: {}", err.to_string())
});
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_action(&action)
.unwrap_or_else(|err| warn!("{}", err));
}
}
#[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
#[dbus_interface(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()>;
}
impl CtrlGraphics {
pub fn new() -> std::io::Result<CtrlGraphics> {
let bus = PciBus::new()?;
info!("Rescanning PCI bus");
bus.rescan()?;
let devs = PciDevice::all()?;
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
let mut functions = Vec::new();
if let Some(parent_slot) = parent.id().split('.').next() {
for func in devs.iter() {
if let Some(func_slot) = func.id().split('.').next() {
if func_slot == parent_slot {
info!("{}: Function for {}", func.id(), parent.id());
functions.push(func.clone());
}
}
}
}
functions
};
let mut amd = Vec::new();
let mut intel = Vec::new();
let mut nvidia = Vec::new();
let mut other = Vec::new();
for dev in devs.iter() {
let c = dev.class()?;
if 0x03 == (c >> 16) & 0xFF {
match dev.vendor()? {
0x1002 => {
info!("{}: AMD graphics", dev.id());
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x10DE => {
info!("{}: NVIDIA graphics", dev.id());
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x8086 => {
info!("{}: Intel graphics", dev.id());
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
vendor => {
info!("{}: Other({:X}) graphics", dev.id(), vendor);
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
}
}
}
let mut initfs_cmd = None;
if Path::new(INITRAMFS_PATH).exists() {
let mut cmd = Command::new("update-initramfs");
cmd.arg("-u");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'update-initramfs'");
}
// } else if Path::new(DRACUT_PATH).exists() {
// let mut cmd = Command::new("dracut");
// cmd.arg("-f");
// initfs_cmd = Some(cmd);
// info!("Using initramfs update command 'dracut'");
// }
Ok(CtrlGraphics {
bus,
_amd: amd,
_intel: intel,
nvidia,
other,
initfs_cmd,
})
}
#[cfg(feature = "use-zbus")]
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Gfx".try_into().unwrap(), self)
.map_err(|err| {
warn!("CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
pub fn reload(&mut self) -> Result<(), Box<dyn Error>> {
self.auto_power()?;
info!("Reloaded gfx mode: {:?}", CtrlGraphics::get_vendor()?);
Ok(())
}
// fn can_switch(&self) -> bool {
// !self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
// }
fn get_prime_discrete() -> Result<String, GfxError> {
let s = std::fs::read_to_string(PRIME_DISCRETE_PATH)
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?
.trim()
.to_owned();
Ok(s)
}
fn set_prime_discrete(mode: &str) -> Result<(), GfxError> {
std::fs::write(PRIME_DISCRETE_PATH, mode)
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?;
Ok(())
}
/// Associated method to get which vendor mode is set
pub fn get_vendor() -> Result<String, GfxError> {
let mode = match Self::get_prime_discrete() {
Ok(m) => m,
Err(_) => "nvidia".to_string(),
};
let modules = Module::all().map_err(|err| GfxError::Read("get_vendor".into(), err))?;
let driver_loaded = if modules
.iter()
.any(|module| module.name == "nouveau" || module.name == "nvidia")
{
true
} else {
false
};
let vendor = if mode == "off" {
if driver_loaded {
info!("dGPU driver loaded for compute mode");
"compute".to_string()
} else {
info!("No dGPU driver loaded");
"integrated".to_string()
}
} else {
info!("Assuming dGPU driver loaded");
if mode == "on-demand" {
"hybrid".to_string()
} else {
"nvidia".to_string()
}
};
Ok(vendor)
}
pub fn is_switching_prime_modes(vendor: &GfxVendors) -> Result<bool, GfxError> {
let prev_mode = GfxVendors::from_str(&Self::get_vendor()?)?;
let x = (prev_mode == GfxVendors::Hybrid || prev_mode == GfxVendors::Nvidia)
&& (*vendor == GfxVendors::Hybrid || *vendor == GfxVendors::Nvidia);
Ok(x)
}
/// Write out config files if required, enable/disable relevant services, and update the ramdisk
pub fn set(&mut self, vendor: GfxVendors) -> Result<String, GfxError> {
//self.switchable_or_fail()?;
let mode = if vendor == GfxVendors::Hybrid {
"on-demand\n"
} else if vendor == GfxVendors::Nvidia {
"on\n"
} else {
// Integrated or Compute
"off\n"
};
info!("Setting {} to {}", PRIME_DISCRETE_PATH, mode);
Self::set_prime_discrete(mode)?;
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
// or a reboot.
let no_reboot = Self::is_switching_prime_modes(&vendor)?;
{
info!("Writing {}", MODPROBE_PATH);
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(MODPROBE_PATH)
.map_err(|err| GfxError::Path(MODPROBE_PATH.into(), err))?;
let text = if vendor == GfxVendors::Hybrid {
MODPROBE_HYBRID
} else if vendor == GfxVendors::Compute {
MODPROBE_COMPUTE
} else if vendor == GfxVendors::Nvidia {
MODPROBE_NVIDIA
} else {
MODPROBE_INTEGRATED
};
file.write_all(text)
.and_then(|_| file.sync_all())
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
}
info!("Writing {}", PRIMARY_GPU_XORG_PATH);
// begin section for non-separated Nvidia xorg modules
// eg, not put in their own directory
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(PRIMARY_GPU_XORG_PATH)
.map_err(|err| GfxError::Write(PRIMARY_GPU_XORG_PATH.into(), err))?;
let text = if vendor == GfxVendors::Nvidia {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
} else {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_END].concat()
};
file.write_all(&text)
.and_then(|_| file.sync_all())
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
let action = if vendor == GfxVendors::Nvidia {
info!("Enabling nvidia-fallback.service");
"enable"
} else {
info!("Disabling nvidia-fallback.service");
"disable"
};
let status = Command::new("systemctl")
.arg(action)
.arg("nvidia-fallback.service")
.status()
.map_err(|err| GfxError::Command("systemctl".into(), err))?;
if !status.success() {
// Error is ignored in case this service is removed
warn!(
"systemctl: {} (ignore warning if service does not exist!)",
status
);
}
let mut required_action = GfxCtrlAction::None;
if !no_reboot {
info!("Updating initramfs");
if let Some(cmd) = self.initfs_cmd.as_mut() {
let status = cmd
.status()
.map_err(|err| GfxError::Write(format!("{:?}", cmd), err))?;
if !status.success() {
error!("Ram disk update failed");
} else {
info!("Successfully updated iniramfs");
}
}
required_action = GfxCtrlAction::Reboot;
} else if no_reboot {
required_action = GfxCtrlAction::RestartX;
}
Ok(required_action.into())
}
// pub fn get_power(&self) -> Option<bool> {
// if self.can_switch() {
// return Some(self.nvidia.iter().any(GraphicsDevice::exists));
// }
// None
// }
pub fn get_runtime_status() -> Result<String, GfxError> {
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
let buf = std::fs::read_to_string(PATH).map_err(|err| GfxError::Read(PATH.into(), err))?;
Ok(buf)
}
fn set_power(&self, power: bool) -> Result<(), GfxError> {
// self.switchable_or_fail()?;
if power {
info!("Enabling graphics power");
self.bus
.rescan()
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
} else {
info!("Disabling graphics power");
// Unbind NVIDIA graphics devices and their functions
let unbinds = self.nvidia.iter().map(|dev| dev.unbind());
// Remove NVIDIA graphics devices and their functions
let removes = self.nvidia.iter().map(|dev| dev.remove());
Result::from_iter(unbinds.chain(removes))
.map_err(|err| GfxError::Command("device unbind error".into(), err))?;
}
Ok(())
}
fn auto_power(&self) -> Result<(), GfxError> {
let vendor = CtrlGraphics::get_vendor()?;
self.set_power(vendor != "integrated")
}
}

View File

@@ -1,30 +0,0 @@
use std::error;
use std::fmt;
#[derive(Debug)]
pub enum GfxError {
ParseVendor,
Path(String, std::io::Error),
Read(String, std::io::Error),
Write(String, std::io::Error),
Module(String, std::io::Error),
Bus(String, std::io::Error),
Command(String, std::io::Error),
}
impl fmt::Display for GfxError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
GfxError::Path(path, error) => write!(f, "Path {}: {}", path, error),
GfxError::Read(path, error) => write!(f, "Read {}: {}", path, error),
GfxError::Write(path, error) => write!(f, "Write {}: {}", path, error),
GfxError::Module(func, error) => write!(f, "Module error: {}: {}", func, error),
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
}
}
}
impl error::Error for GfxError {}

View File

@@ -1,57 +0,0 @@
pub mod vendors;
pub mod error;
pub mod ctrl_gfx;
pub mod system;
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
// const DRACUT_PATH: &str = "/usr/bin/dracut";
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
static MODPROBE_HYBRID: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
alias i2c_nvidia_gpu off
options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=1
"#;
static MODPROBE_COMPUTE: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
alias i2c_nvidia_gpu off
options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=0
"#;
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
blacklist nouveau
blacklist nvidia
blacklist nvidia-drm
blacklist nvidia-modeset
alias i2c_nvidia_gpu off
alias nouveau off
alias nvidia off
alias nvidia-drm off
alias nvidia-modeset off
"#;
const PRIMARY_GPU_XORG_PATH: &str = "/etc/X11/xorg.conf.d/90-nvidia-primary.conf";
static PRIMARY_GPU_BEGIN: &[u8] = br#"# Automatically generated by asusd
Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration"
Option "AllowExternalGpus""#;
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#;
static PRIMARY_GPU_END: &[u8] = br#"
EndSection"#;

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb-ctrl"
version = "2.1.2"
name = "daemon"
version = "3.1.2"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -13,38 +13,31 @@ edition = "2018"
name = "daemon"
path = "src/lib.rs"
[[bin]]
name = "asusctl"
path = "src/main.rs"
[[bin]]
name = "asusd"
path = "src/daemon.rs"
[dependencies]
ctrl-gfx = { path = "../ctrl-gfx" }
asus-nb = { path = "../asus-nb" }
rusb = "^0.6.0"
udev = "^0.4.0"
rog_types = { path = "../rog-types" }
rog_dbus = { path = "../rog-dbus" }
rusb = "^0.7"
udev = "^0.6"
# cli and logging
gumdrop = "^0.8.0"
log = "^0.4.8"
env_logger = "^0.7.1"
log = "^0.4"
env_logger = "^0.8"
zbus = "^1.8.0"
zvariant = "^2.4.0"
zbus = "^1.8"
zvariant = "^2.4"
# serialisation
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
toml = "0.4.6"
toml = "^0.5"
# Device control
sysfs-class = "^0.1.2" # used for backlight control and baord ID
rog_fan_curve = { version = "0.1.5", features = ["serde"] }
rog_fan_curve = { version = "0.1", features = ["serde"] }
# cpu power management
intel-pstate = "^0.2.1"
yansi-term = "^0.1"
intel-pstate = "^0.2"

View File

@@ -1,20 +1,24 @@
use asus_nb::aura_modes::AuraModes;
use log::{error, warn};
use log::{error, info, warn};
use rog_fan_curve::Curve;
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use crate::config_old::*;
use crate::VERSION;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Default, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
pub struct Config {
pub gfx_mode: GfxVendors,
pub gfx_managed: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
// TODO: remove power_profile
pub power_profile: u8,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
@@ -22,9 +26,31 @@ pub struct Config {
pub power_profiles: BTreeMap<String, Profile>,
}
impl Default for Config {
fn default() -> Self {
let mut pwr = BTreeMap::new();
pwr.insert("normal".into(), Profile::new(0, 100, true, 0, None));
pwr.insert("boost".into(), Profile::new(0, 100, true, 1, None));
pwr.insert("silent".into(), Profile::new(0, 100, true, 2, None));
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: true,
active_profile: "normal".into(),
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0,
bat_charge_limit: 100,
kbd_led_brightness: 1,
kbd_backlight_mode: 0,
kbd_backlight_modes: Vec::new(),
power_profiles: pwr,
}
}
}
impl Config {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(mut self, supported_led_modes: &[u8]) -> Self {
pub fn load(supported_led_modes: &[u8]) -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
@@ -35,51 +61,43 @@ impl Config {
CONFIG_PATH
)); // okay to cause panic here
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
self = Config::create_default(&mut file, &supported_led_modes);
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return Config::create_default(&mut file, &supported_led_modes);
} else {
self = serde_json::from_str(&buf).unwrap_or_else(|_| {
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);
});
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&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::<ConfigV222>(&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::<ConfigV212>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
}
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);
}
}
self
Config::create_default(&mut file, &supported_led_modes)
}
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
// create a default config here
let mut config = Config::default();
config.gfx_managed = true;
config.bat_charge_limit = 100;
config.kbd_backlight_mode = 0;
config.kbd_led_brightness = 1;
for n in supported_led_modes {
config.kbd_backlight_modes.push(AuraModes::from(*n))
}
let mut profile = Profile::default();
profile.fan_preset = 0;
profile.turbo = true;
config.power_profiles.insert("normal".into(), profile);
let mut profile = Profile::default();
profile.fan_preset = 1;
profile.turbo = true;
config.power_profiles.insert("boost".into(), profile);
let mut profile = Profile::default();
profile.fan_preset = 2;
config.power_profiles.insert("silent".into(), profile);
config.toggle_profiles.push("normal".into());
config.toggle_profiles.push("boost".into());
config.toggle_profiles.push("silent".into());
config.active_profile = "normal".into();
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string_pretty(&config).unwrap();
file.write_all(json.as_bytes())
@@ -166,3 +184,21 @@ impl Default for Profile {
}
}
}
impl Profile {
pub fn new(
min_percentage: u8,
max_percentage: u8,
turbo: bool,
fan_preset: u8,
fan_curve: Option<Curve>,
) -> Self {
Profile {
min_percentage,
max_percentage,
turbo,
fan_preset,
fan_curve,
}
}
}

100
daemon/src/config_old.rs Normal file
View File

@@ -0,0 +1,100 @@
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::config::{Config, Profile};
/// for parsing old v2.1.2 config
#[derive(Deserialize)]
pub(crate) struct ConfigV212 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>,
}
impl ConfigV212 {
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.power_profile,
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,
}
}
}
/// for parsing old v2.2.2 config
#[derive(Deserialize)]
pub(crate) struct ConfigV222 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraModes>,
}
impl ConfigV222 {
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.power_profile,
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,
}
}
}
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV301 {
pub gfx_managed: bool,
pub gfx_nv_mode_is_dedicated: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
// TODO: remove power_profile
#[serde(skip)]
pub curr_fan_mode: 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>,
}
impl ConfigV301 {
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,
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,
}
}
}

View File

@@ -13,36 +13,48 @@ const APPLY: u8 = 0xc4;
// The next byte can be 0x03 for "on" and 0x00 for "off"
const ON_OFF: u8 = 0x04;
use asus_nb::error::AuraError;
use log::{error, info, warn};
use rog_types::{
anime_matrix::{
AniMeDataBuffer, AniMeImageBuffer, AniMePacketType, ANIME_PANE1_PREFIX, ANIME_PANE2_PREFIX,
},
error::AuraError,
};
use rusb::{Device, DeviceHandle};
use std::convert::TryInto;
use std::error::Error;
use std::time::Duration;
use zbus::dbus_interface;
#[allow(dead_code)]
#[derive(Debug)]
pub enum AnimatrixCommand {
Apply,
SetBoot(bool),
Write(Vec<u8>),
WriteImage(Vec<Vec<u8>>),
//ReloadLast,
use crate::GetSupported;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct AnimeSupportedFunctions(bool);
impl GetSupported for CtrlAnimeDisplay {
type A = AnimeSupportedFunctions;
fn get_supported() -> Self::A {
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(0x0b05, 0x193b).is_ok())
}
}
pub struct CtrlAnimeDisplay {
handle: DeviceHandle<rusb::GlobalContext>,
initialised: bool,
}
//AnimatrixWrite
pub trait Dbus {
fn set_anime(&mut self, input: Vec<Vec<u8>>);
/// Write an image 34x56 pixels. Each pixel is 0-255 greyscale.
fn write_image(&self, input: AniMeImageBuffer);
fn set_on_off(&mut self, status: bool);
/// Write a direct stream of data
fn write_direct(&self, input: AniMeDataBuffer);
fn set_boot_on_off(&mut self, status: bool);
fn set_on_off(&self, status: bool);
fn set_boot_on_off(&self, status: bool);
}
impl crate::ZbusAdd for CtrlAnimeDisplay {
@@ -59,41 +71,44 @@ impl crate::ZbusAdd for CtrlAnimeDisplay {
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlAnimeDisplay {
fn set_anime(&mut self, input: Vec<Vec<u8>>) {
self.do_command(AnimatrixCommand::WriteImage(input))
/// Writes a 34x56 image
fn write_image(&self, input: AniMeImageBuffer) {
self.write_image_buffer(input)
.map_or_else(|err| warn!("{}", err), |()| info!("Writing image to Anime"));
}
fn set_on_off(&mut self, status: bool) {
let mut flush: Vec<u8> = vec![0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = WRITE;
flush[2] = ON_OFF;
let status_str;
if status {
flush[3] = 0x03;
status_str = "on";
} else {
flush[3] = 0x00;
status_str = "off";
}
self.do_command(AnimatrixCommand::Write(flush)).map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe", status_str),
);
/// Writes a data stream of length
fn write_direct(&self, input: AniMeDataBuffer) {
self.write_data_buffer(input)
.map_or_else(|err| warn!("{}", err), |()| info!("Writing data to Anime"));
}
fn set_boot_on_off(&mut self, status: bool) {
fn set_on_off(&self, status: bool) {
let mut buffer = [0u8; PACKET_SIZE];
buffer[0] = DEV_PAGE;
buffer[1] = WRITE;
buffer[2] = ON_OFF;
if status {
buffer[3] = 0x03;
} else {
buffer[3] = 0x00;
}
self.write_bytes(&buffer);
}
fn set_boot_on_off(&self, status: bool) {
let status_str = if status { "on" } else { "off" };
self.do_command(AnimatrixCommand::SetBoot(status))
.and_then(|()| self.do_command(AnimatrixCommand::Apply))
.map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
);
self.do_set_boot(status).map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
);
self.do_apply().map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
);
}
}
@@ -117,10 +132,10 @@ impl CtrlAnimeDisplay {
})?;
info!("Device has an AniMe Matrix display");
Ok(CtrlAnimeDisplay {
handle: device,
initialised: false,
})
let ctrl = CtrlAnimeDisplay { handle: device };
ctrl.do_initialization()?;
Ok(ctrl)
}
#[inline]
@@ -134,25 +149,9 @@ impl CtrlAnimeDisplay {
Err(rusb::Error::NoDevice)
}
pub fn do_command(&mut self, command: AnimatrixCommand) -> Result<(), AuraError> {
if !self.initialised {
self.do_initialization()?
}
match command {
AnimatrixCommand::Apply => self.do_apply()?,
//AnimatrixCommand::Set => self.do_set_boot()?,
AnimatrixCommand::SetBoot(status) => self.do_set_boot(status)?,
AnimatrixCommand::Write(bytes) => self.write_bytes(&bytes)?,
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
//AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?,
}
Ok(())
}
/// Should only be used if the bytes you are writing are verified correct
#[inline]
fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
fn write_bytes(&self, message: &[u8]) {
match self.handle.write_control(
0x21, // request_type
0x09, // request
@@ -167,12 +166,23 @@ impl CtrlAnimeDisplay {
_ => error!("Failed to write to led interrupt: {}", err),
},
}
}
#[inline]
fn write_data_buffer(&self, buffer: AniMeDataBuffer) -> Result<(), AuraError> {
let mut image = AniMePacketType::from(buffer);
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
for row in image.iter() {
self.write_bytes(row);
}
self.do_flush()?;
Ok(())
}
/// Write an Animatrix image
///
/// The expected input here is *two* Vectors, 640 bytes in length. The two vectors
/// The expected USB input here is *two* Vectors, 640 bytes in length. The two vectors
/// are each one half of the full image write.
///
/// After each write a flush is written, it is assumed that this tells the device to
@@ -186,22 +196,26 @@ impl CtrlAnimeDisplay {
///
/// Where led brightness is 0..255, low to high
#[inline]
fn write_image(&mut self, image: Vec<Vec<u8>>) -> Result<(), AuraError> {
fn write_image_buffer(&self, buffer: AniMeImageBuffer) -> Result<(), AuraError> {
let mut image = AniMePacketType::from(buffer);
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
for row in image.iter() {
self.write_bytes(row)?;
self.write_bytes(row);
}
self.do_flush()?;
Ok(())
}
#[inline]
fn do_initialization(&mut self) -> Result<(), AuraError> {
fn do_initialization(&self) -> Result<(), AuraError> {
let mut init = [0; PACKET_SIZE];
init[0] = DEV_PAGE; // This is the USB page we're using throughout
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
init[idx + 1] = *byte
}
self.write_bytes(&init)?;
self.write_bytes(&init);
// clear the init array and write other init message
for ch in init.iter_mut() {
@@ -210,43 +224,42 @@ impl CtrlAnimeDisplay {
init[0] = DEV_PAGE; // write it to be sure?
init[1] = INIT;
self.write_bytes(&init)?;
self.initialised = true;
self.write_bytes(&init);
Ok(())
}
#[inline]
fn do_flush(&mut self) -> Result<(), AuraError> {
fn do_flush(&self) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = WRITE;
flush[2] = 0x03;
self.write_bytes(&flush)?;
self.write_bytes(&flush);
Ok(())
}
#[inline]
fn do_set_boot(&mut self, status: bool) -> Result<(), AuraError> {
fn do_set_boot(&self, status: bool) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = SET;
flush[2] = 0x01;
flush[3] = if status { 0x00 } else { 0x80 };
self.write_bytes(&flush)?;
self.write_bytes(&flush);
Ok(())
}
#[inline]
fn do_apply(&mut self) -> Result<(), AuraError> {
fn do_apply(&self) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = APPLY;
flush[2] = 0x01;
flush[3] = 0x80;
self.write_bytes(&flush)?;
self.write_bytes(&flush);
Ok(())
}
}

View File

@@ -1,6 +1,7 @@
use crate::{config::Config, error::RogError};
use crate::{config::Config, error::RogError, GetSupported};
//use crate::dbus::DbusEvents;
use log::{info, warn};
use serde_derive::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fs::OpenOptions;
use std::io::Write;
@@ -11,8 +12,22 @@ use zbus::dbus_interface;
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
#[derive(Serialize, Deserialize)]
pub struct ChargeSupportedFunctions {
pub charge_level_set: bool,
}
impl GetSupported for CtrlCharge {
type A = ChargeSupportedFunctions;
fn get_supported() -> Self::A {
ChargeSupportedFunctions {
charge_level_set: CtrlCharge::get_battery_path().is_ok(),
}
}
}
pub struct CtrlCharge {
path: &'static str,
config: Arc<Mutex<Config>>,
}
@@ -43,7 +58,7 @@ impl CtrlCharge {
}
#[dbus_interface(signal)]
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for CtrlCharge {
@@ -62,7 +77,6 @@ impl crate::Reloadable for CtrlCharge {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.try_lock() {
config.read();
info!("Reloaded battery charge limit");
self.set(config.bat_charge_limit, &mut config)?;
}
Ok(())
@@ -71,9 +85,8 @@ impl crate::Reloadable for CtrlCharge {
impl CtrlCharge {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
let path = CtrlCharge::get_battery_path()?;
info!("Device has battery charge threshold control");
Ok(CtrlCharge { path, config })
CtrlCharge::get_battery_path()?;
Ok(CtrlCharge { config })
}
fn get_battery_path() -> Result<&'static str, RogError> {
@@ -88,7 +101,7 @@ impl CtrlCharge {
}
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> {
if limit < 20 || limit > 100 {
if !(20..=100).contains(&limit) {
warn!(
"Unable to set battery charge limit, must be between 20-100: requested {}",
limit
@@ -97,10 +110,10 @@ impl CtrlCharge {
let mut file = OpenOptions::new()
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
.open(BAT_CHARGE_PATH)
.map_err(|err| RogError::Path(BAT_CHARGE_PATH.into(), err))?;
file.write_all(limit.to_string().as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
.map_err(|err| RogError::Write(BAT_CHARGE_PATH.into(), err))?;
info!("Battery charge limit: {}", limit);
config.read();

View File

@@ -1,11 +1,15 @@
use crate::config::{Config, Profile};
use asus_nb::profile::ProfileEvent;
use crate::error::RogError;
use crate::{
config::{Config, Profile},
GetSupported,
};
use log::{info, warn};
use rog_types::profile::{FanLevel, ProfileEvent};
use serde_derive::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::io::Write;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::dbus_interface;
@@ -19,6 +23,25 @@ pub struct CtrlFanAndCPU {
config: Arc<Mutex<Config>>,
}
#[derive(Serialize, Deserialize)]
pub struct FanCpuSupportedFunctions {
pub stock_fan_modes: bool,
pub min_max_freq: bool,
pub fan_curve_set: bool,
}
impl GetSupported for CtrlFanAndCPU {
type A = FanCpuSupportedFunctions;
fn get_supported() -> Self::A {
FanCpuSupportedFunctions {
stock_fan_modes: CtrlFanAndCPU::get_fan_path().is_ok(),
min_max_freq: intel_pstate::PState::new().is_ok(),
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
}
}
}
pub struct DbusFanAndCpu {
inner: Arc<Mutex<CtrlFanAndCPU>>,
}
@@ -39,8 +62,7 @@ impl DbusFanAndCpu {
cfg.read();
ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_profile(&cfg.active_profile)
.unwrap_or_else(|_| ());
self.notify_profile(&cfg.active_profile).unwrap_or(());
}
}
}
@@ -101,7 +123,7 @@ impl DbusFanAndCpu {
}
#[dbus_interface(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for DbusFanAndCpu {
@@ -109,7 +131,7 @@ impl crate::ZbusAdd for DbusFanAndCpu {
server
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self)
.map_err(|err| {
warn!("DbusFanAndCpu: {}", err);
warn!("DbusFanAndCpu: add_to_server {}", err);
err
})
.ok();
@@ -119,65 +141,17 @@ impl crate::ZbusAdd for DbusFanAndCpu {
impl crate::Reloadable for CtrlFanAndCPU {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.clone().try_lock() {
let mut file = OpenOptions::new()
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
file.write_all(format!("{}\n", config.power_profile).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
let profile = config.active_profile.clone();
self.set(&profile, &mut config)?;
info!(
"Reloaded fan mode: {:?}",
FanLevel::from(config.power_profile)
);
// info!(
// "Reloaded fan mode: {:?}",
// FanLevel::from(config.power_profile)
// );
}
Ok(())
}
}
impl crate::CtrlTask for CtrlFanAndCPU {
fn do_task(&mut self) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read(self.path.into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if let Ok(mut config) = self.config.clone().try_lock() {
if config.power_profile != num as u8 {
config.read();
let mut i = config
.toggle_profiles
.iter()
.position(|x| x == &config.active_profile)
.map(|i| i + 1)
.unwrap_or(0);
if i >= config.toggle_profiles.len() {
i = 0;
}
let new_profile = config
.toggle_profiles
.get(i)
.unwrap_or(&config.active_profile)
.clone();
self.set(&new_profile, &mut config)?;
info!("Profile was changed: {}", &new_profile);
}
}
return Ok(());
}
Err(RogError::DoTask("Fan-level could not be parsed".into()))
}
}
impl CtrlFanAndCPU {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
let path = CtrlFanAndCPU::get_fan_path()?;
@@ -223,7 +197,7 @@ impl CtrlFanAndCPU {
Ok(())
}
pub(super) fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
let mode = config.active_profile.clone();
let mut fan_ctrl = OpenOptions::new()
.write(true)
@@ -234,15 +208,13 @@ impl CtrlFanAndCPU {
.power_profiles
.get_mut(&mode)
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
config.power_profile = preset;
config.curr_fan_mode = preset;
mode_config.fan_preset = preset;
config.write();
fan_ctrl
.write_all(format!("{}\n", preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
info!("Fan mode set to: {:?}", FanLevel::from(preset));
self.set_pstate_for_fan_mode(&mode, config)?;
self.set_fan_curve_for_fan_mode(&mode, config)?;
Ok(())
}
@@ -255,6 +227,9 @@ impl CtrlFanAndCPU {
ProfileEvent::Toggle => self.do_next_profile(config)?,
ProfileEvent::ChangeMode(mode) => {
self.set_fan_mode(*mode, config)?;
let mode = config.active_profile.clone();
self.set_pstate_for_fan_mode(&mode, config)?;
self.set_fan_curve_for_fan_mode(&mode, config)?;
}
ProfileEvent::Cli(command) => {
let profile_key = match command.profile.as_ref() {
@@ -305,10 +280,10 @@ impl CtrlFanAndCPU {
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
config.curr_fan_mode = mode_config.fan_preset;
fan_ctrl
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
config.power_profile = mode_config.fan_preset;
self.set_pstate_for_fan_mode(profile, config)?;
self.set_fan_curve_for_fan_mode(profile, config)?;
@@ -370,46 +345,3 @@ impl CtrlFanAndCPU {
Ok(())
}
}
use crate::error::RogError;
#[derive(Debug)]
pub enum FanLevel {
Normal,
Boost,
Silent,
}
impl FromStr for FanLevel {
type Err = RogError;
fn from_str(s: &str) -> Result<Self, RogError> {
match s.to_lowercase().as_str() {
"normal" => Ok(FanLevel::Normal),
"boost" => Ok(FanLevel::Boost),
"silent" => Ok(FanLevel::Silent),
_ => Err(RogError::ParseFanLevel),
}
}
}
impl From<u8> for FanLevel {
fn from(n: u8) -> Self {
match n {
0 => FanLevel::Normal,
1 => FanLevel::Boost,
2 => FanLevel::Silent,
_ => FanLevel::Normal,
}
}
}
impl From<FanLevel> for u8 {
fn from(n: FanLevel) -> Self {
match n {
FanLevel::Normal => 0,
FanLevel::Boost => 1,
FanLevel::Silent => 2,
}
}
}

View File

@@ -0,0 +1,30 @@
use std::error;
use std::fmt;
use crate::error::RogError;
#[derive(Debug)]
pub enum GfxError {
ParseVendor,
Bus(String, std::io::Error),
DisplayManager(String),
}
impl fmt::Display for GfxError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
GfxError::DisplayManager(detail) => write!(f, "Display manager: {}", detail),
}
}
}
impl error::Error for GfxError {}
impl From<GfxError> for RogError {
fn from(err: GfxError) -> Self {
RogError::GfxSwitching(err)
}
}

408
daemon/src/ctrl_gfx/gfx.rs Normal file
View File

@@ -0,0 +1,408 @@
use ctrl_gfx::error::GfxError;
use ctrl_gfx::*;
use log::{error, info, warn};
use rog_types::gfx_vendors::GfxVendors;
use std::iter::FromIterator;
use std::process::Command;
use std::str::FromStr;
use std::{io::Write, ops::Add, path::Path};
use std::{sync::Arc, sync::Mutex};
use sysfs_class::{PciDevice, SysClass};
use system::{GraphicsDevice, PciBus};
use zbus::dbus_interface;
use crate::*;
pub struct CtrlGraphics {
bus: PciBus,
_amd: Vec<GraphicsDevice>,
_intel: Vec<GraphicsDevice>,
nvidia: Vec<GraphicsDevice>,
#[allow(dead_code)]
other: Vec<GraphicsDevice>,
config: Arc<Mutex<Config>>,
}
trait Dbus {
fn vendor(&self) -> String;
fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String);
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>;
}
use std::convert::TryInto;
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics {
fn vendor(&self) -> String {
self.get_gfx_mode()
.map(|gfx| gfx.into())
.unwrap_or_else(|err| format!("Get vendor failed: {}", err))
}
fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
}
fn set_vendor(&mut self, vendor: String) {
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
info!("Switching gfx mode to {}", vendor);
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| {
error!("{}", err);
format!("Failed: {}", err.to_string())
});
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_action(&msg)
.unwrap_or_else(|err| warn!("{}", err));
}
}
#[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()> {}
#[dbus_interface(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()> {}
}
impl ZbusAdd for CtrlGraphics {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&"/org/asuslinux/Gfx"
.try_into()
.expect("Couldn't add to zbus"),
self,
)
.map_err(|err| {
warn!("CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
}
impl Reloadable for CtrlGraphics {
fn reload(&mut self) -> Result<(), RogError> {
self.auto_power()?;
info!("Reloaded gfx mode: {:?}", self.get_gfx_mode()?);
Ok(())
}
}
impl CtrlGraphics {
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
let bus = PciBus::new()?;
info!("Rescanning PCI bus");
bus.rescan()?;
let devs = PciDevice::all()?;
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
let mut functions = Vec::new();
if let Some(parent_slot) = parent.id().split('.').next() {
for func in devs.iter() {
if let Some(func_slot) = func.id().split('.').next() {
if func_slot == parent_slot {
info!("{}: Function for {}", func.id(), parent.id());
functions.push(func.clone());
}
}
}
}
functions
};
let mut amd = Vec::new();
let mut intel = Vec::new();
let mut nvidia = Vec::new();
let mut other = Vec::new();
for dev in devs.iter() {
let c = dev.class()?;
if 0x03 == (c >> 16) & 0xFF {
match dev.vendor()? {
0x1002 => {
info!("{}: AMD graphics", dev.id());
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x10DE => {
info!("{}: NVIDIA graphics", dev.id());
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x8086 => {
info!("{}: Intel graphics", dev.id());
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
vendor => {
info!("{}: Other({:X}) graphics", dev.id(), vendor);
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
}
}
}
Ok(CtrlGraphics {
bus,
_amd: amd,
_intel: intel,
nvidia,
other,
config,
})
}
fn save_gfx_mode(&self, vendor: GfxVendors) -> Result<(), RogError> {
if let Ok(mut config) = self.config.lock() {
config.gfx_mode = vendor.clone();
config.write();
return Ok(());
}
// TODO: Error here
Ok(())
}
/// Associated method to get which vendor mode is set
pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
if let Ok(config) = self.config.lock() {
return Ok(config.gfx_mode.clone());
}
// TODO: Error here
Ok(GfxVendors::Hybrid)
}
fn get_runtime_status() -> Result<String, RogError> {
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
let buf = std::fs::read_to_string(PATH).map_err(|err| RogError::Read(PATH.into(), err))?;
Ok(buf)
}
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
let action = if vendor == GfxVendors::Nvidia {
info!("Enabling nvidia-fallback.service");
"enable"
} else {
info!("Disabling nvidia-fallback.service");
"disable"
};
let status = Command::new("systemctl")
.arg(action)
.arg("nvidia-fallback.service")
.status()
.map_err(|err| RogError::Command("systemctl".into(), err))?;
if !status.success() {
// Error is ignored in case this service is removed
warn!(
"systemctl: {} (ignore warning if service does not exist!)",
status
);
}
Ok(())
}
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
let text = if vendor == GfxVendors::Nvidia {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
} else {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_END].concat()
};
if !Path::new(XORG_PATH).exists() {
std::fs::create_dir(XORG_PATH).map_err(|err| RogError::Write(XORG_PATH.into(), err))?;
}
let file = XORG_PATH.to_string().add(XORG_FILE);
info!("Writing {}", file);
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&file)
.map_err(|err| RogError::Write(file, err))?;
file.write_all(&text)
.and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
Ok(())
}
fn write_modprobe_conf() -> Result<(), RogError> {
info!("Writing {}", MODPROBE_PATH);
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(MODPROBE_PATH)
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
file.write_all(MODPROBE_BASE)
.and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
Ok(())
}
fn unbind_remove_nvidia(&self) -> Result<(), RogError> {
// Unbind NVIDIA graphics devices and their functions
let unbinds = self.nvidia.iter().map(|dev| dev.unbind());
// Remove NVIDIA graphics devices and their functions
let removes = self.nvidia.iter().map(|dev| dev.remove());
Result::from_iter(unbinds.chain(removes))
.map_err(|err| RogError::Command("device unbind error".into(), err))?;
Ok(())
}
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
let mut cmd;
if Self::kmod_exists() {
info!("using kmod");
cmd = Command::new("kmod");
cmd.arg(action);
} else {
cmd = Command::new(action);
}
cmd.arg(driver);
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
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()) {
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr));
warn!("{}", msg);
warn!("It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded");
return Ok(())
}
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr));
return Err(RogError::Modprobe(msg));
}
Ok(())
}
fn do_display_manager_action(action: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg(action);
cmd.arg(DISPLAY_MANAGER);
let status = cmd
.status()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if !status.success() {
let msg = format!(
"systemctl {} {} failed: {:?}",
action, DISPLAY_MANAGER, status
);
return Err(GfxError::DisplayManager(msg).into());
}
Ok(())
}
fn wait_display_manager_inactive() -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg("is-active");
cmd.arg(DISPLAY_MANAGER);
let mut count = 0;
while count <= 4 {
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with("inactive".as_bytes()) {
return Ok(());
}
std::thread::sleep(std::time::Duration::from_millis(500));
count += 1;
}
return Err(
GfxError::DisplayManager("display-manager did not completely stop".into()).into(),
);
}
fn kmod_exists() -> bool {
let mut cmd = Command::new("which");
cmd.arg("kmod");
if let Ok(output) = cmd
.output() {
return output.status.success() && output.stdout.ends_with("kmod".as_bytes())
}
//Path::new("/usr/bin/kmod").exists()
false
}
pub fn do_vendor_tasks(&mut self, vendor: GfxVendors) -> Result<(), RogError> {
Self::write_xorg_conf(vendor)?;
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup?
// Rescan before doing remove or add drivers
self.bus
.rescan()
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "modprobe")?;
}
}
// TODO: compute mode, needs different setup
// GfxVendors::Compute => {}
GfxVendors::Integrated => {
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
self.unbind_remove_nvidia()?;
}
}
self.save_gfx_mode(vendor)?;
Ok(())
}
/// For manually calling (not on boot/startup)
///
/// Will stop and start display manager without warning
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
Self::do_display_manager_action("stop")?;
Self::wait_display_manager_inactive()?;
self.do_vendor_tasks(vendor)?;
Self::do_display_manager_action("start")?;
// TODO: undo if failed? Save last mode, catch errors...
let v: &str = vendor.into();
Ok(format!("Graphics mode changed to {} successfully", v))
}
// if CtrlRogBios::has_dedicated_gfx_toggle() {
// if let Ok(config) = self.config.clone().try_lock() {
// // Switch to dedicated if config says to do so
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia {
// CtrlRogBios::set_gfx_mode(true)
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
// // otherwise if switching to non-Nvidia mode turn off dedicated mode
// if ded == 1 && vendor != GfxVendors::Nvidia {
// CtrlRogBios::set_gfx_mode(false)
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
// }
// }
// }
// }
fn auto_power(&mut self) -> Result<(), RogError> {
let vendor = self.get_gfx_mode()?;
self.do_vendor_tasks(vendor)?;
Self::toggle_fallback_service(vendor)?;
Ok(())
}
}

View File

@@ -0,0 +1,37 @@
pub mod error;
pub mod gfx;
pub mod system;
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
const DISPLAY_MANAGER: &str = "display-manager.service";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
#blacklist i2c_nvidia_gpu
#alias i2c_nvidia_gpu off
blacklist nouveau
alias nouveau off
options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=1
"#;
const XORG_FILE: &str = "90-nvidia-primary.conf";
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";
static PRIMARY_GPU_BEGIN: &[u8] = br#"# Automatically generated by asusd
Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration"
Option "AllowExternalGpus""#;
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#;
static PRIMARY_GPU_END: &[u8] = br#"
EndSection"#;

View File

@@ -50,19 +50,20 @@ impl PciBus {
}
}
/// Will rescan the device tree, which adds all removed devices back
pub fn rescan(&self) -> io::Result<()> {
write(self.path.join("rescan"), "1")
}
}
pub struct GraphicsDevice {
id: String,
_id: String,
functions: Vec<PciDevice>,
}
impl GraphicsDevice {
pub fn new(id: String, functions: Vec<PciDevice>) -> GraphicsDevice {
GraphicsDevice { id, functions }
GraphicsDevice { _id: id, functions }
}
pub fn exists(&self) -> bool {
@@ -95,6 +96,32 @@ impl GraphicsDevice {
Ok(())
}
pub fn rebind(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() {
if func.path().exists() {
match func.driver() {
Ok(driver) => {
info!("{}: Binding {}", driver.id(), func.id());
unsafe {
driver.bind(&func).map_err(|err| {
error!("gfx bind: {}", err);
err
})?;
}
}
Err(err) => match err.kind() {
io::ErrorKind::NotFound => (),
_ => {
error!("gfx driver: {:?}, {}", func.path(), err);
return Err(err);
}
},
}
}
}
Ok(())
}
pub fn remove(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() {
if func.path().exists() {

View File

@@ -4,9 +4,18 @@ 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";
use crate::{config::Config, error::RogError, laptops::HELP_ADDRESS};
use asus_nb::{aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN};
use log::{info, warn};
use crate::{
config::Config,
error::RogError,
laptops::{match_laptop, HELP_ADDRESS},
};
use log::{error, info, warn};
use rog_types::{
aura_brightness_bytes,
aura_modes::{AuraModes, PER_KEY},
fancy::KeyColourArray,
LED_MSG_LEN,
};
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::sync::Arc;
@@ -14,6 +23,42 @@ use std::sync::Mutex;
use std::{convert::TryInto, path::Path};
use zbus::dbus_interface;
use crate::GetSupported;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct LedSupportedFunctions {
pub brightness_set: bool,
pub stock_led_modes: Option<Vec<u8>>,
pub per_key_led_mode: bool,
}
impl GetSupported for CtrlKbdBacklight {
type A = LedSupportedFunctions;
fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode));
let mut stock_led_modes = None;
let mut per_key_led_mode = false;
if let Some(laptop) = match_laptop() {
let modes = laptop.supported_modes().to_vec();
if modes.contains(&PER_KEY) {
per_key_led_mode = true;
let modes = modes.iter().filter(|x| **x != PER_KEY).copied().collect();
stock_led_modes = Some(modes);
} else {
stock_led_modes = Some(modes);
}
}
LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
stock_led_modes,
per_key_led_mode,
}
}
}
pub struct CtrlKbdBacklight {
led_node: Option<String>,
#[allow(dead_code)]
@@ -44,6 +89,9 @@ impl crate::ZbusAdd for DbusKbdBacklight {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Led".try_into().unwrap(), self)
.map_err(|err| {
error!("DbusKbdBacklight: add_to_server {}", err);
})
.ok();
}
}
@@ -61,9 +109,14 @@ impl DbusKbdBacklight {
}
_ => {
if let Ok(json) = serde_json::to_string(&data) {
ctrl.do_command(data, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_led(&json).ok();
match ctrl.do_command(data, &mut cfg) {
Ok(_) => {
self.notify_led(&json).ok();
}
Err(err) => {
warn!("{}", err);
}
}
}
}
}
@@ -231,13 +284,39 @@ impl CtrlKbdBacklight {
config: Arc<Mutex<Config>>,
) -> Result<Self, RogError> {
// 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(
|err| {
warn!("led_node: {}", err);
None
},
Some,
);
let kbd_node = Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node)
.map_or_else(
|err| {
warn!("kbd_node: {}", err);
None
},
Some,
);
let bright_node = Self::get_kbd_bright_path();
if led_node.is_none() && kbd_node.is_none() && Self::get_kbd_bright_path().is_err() {
return Err(RogError::MissingFunction(
"All keyboard features missing, you may require a v5.11 series kernel or newer"
.into(),
));
}
let ctrl = CtrlKbdBacklight {
// Using `ok` here so we can continue without keyboard features but
// still get brightness control at least... maybe...
led_node: Self::get_node_failover(id_product, None, Self::scan_led_node).ok(),
kbd_node: Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node).ok(),
led_node,
kbd_node,
// TODO: Check for existance
bright_node: Self::get_kbd_bright_path()?.to_owned(),
bright_node: bright_node?.to_owned(),
supported_modes,
flip_effect_write: false,
config,
@@ -260,23 +339,12 @@ impl CtrlKbdBacklight {
iface: Option<&String>,
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
) -> Result<String, RogError> {
// We do three tries here just to be certain that we avoid systemd unit
// load order issues
for n in 0..=2 {
// 0,1,2 inclusive
match fun(id_product, iface) {
Ok(o) => return Ok(o),
Err(e) => {
if n == 2 {
warn!("Looking for node: {}", e.to_string());
std::thread::sleep(std::time::Duration::from_secs(1));
} else {
break;
}
}
match fun(id_product, iface) {
Ok(o) => return Ok(o),
Err(e) => {
warn!("Looking for node: {}", e.to_string());
}
}
// Shouldn't be possible to reach this...
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
}
@@ -303,7 +371,7 @@ impl CtrlKbdBacklight {
{
if parent
.attribute_value("idProduct")
.ok_or(RogError::NotFound("LED idProduct".into()))?
.ok_or_else(|| RogError::NotFound("LED idProduct".into()))?
== id_product
{
if let Some(dev_node) = device.devnode() {
@@ -373,6 +441,7 @@ impl CtrlKbdBacklight {
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
if let Some(led_node) = &self.led_node {
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
// println!("write: {:02x?}", &message);
return file
.write_all(message)
.map_err(|err| RogError::Write("write_bytes".into(), err));
@@ -464,6 +533,10 @@ impl CtrlKbdBacklight {
#[inline]
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
let mode_num: u8 = u8::from(mode);
if !self.supported_modes.contains(&mode_num) {
return Err(RogError::NotSupported);
}
match mode {
AuraModes::PerKey(v) => {
if v.is_empty() || v[0].is_empty() {
@@ -473,27 +546,22 @@ impl CtrlKbdBacklight {
self.write_effect(v)?;
}
}
_ => {
let mode_num: u8 = u8::from(mode);
match mode {
AuraModes::MultiStatic(_) => {
if self.supported_modes.contains(&mode_num) {
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
for array in bytes.iter() {
self.write_bytes(array)?;
}
}
}
_ => {
if self.supported_modes.contains(&mode_num) {
let bytes: [u8; LED_MSG_LEN] = mode.into();
self.write_bytes(&bytes)?;
}
}
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(())

345
daemon/src/ctrl_rog_bios.rs Normal file
View File

@@ -0,0 +1,345 @@
use crate::{config::Config, error::RogError, GetSupported};
use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use std::sync::Mutex;
use std::{convert::TryInto, io::BufRead};
use zbus::dbus_interface;
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
const DRACUT_PATH: &str = "/usr/bin/dracut";
static ASUS_SWITCH_GRAPHIC_MODE: &str =
"/sys/firmware/efi/efivars/AsusSwitchGraphicMode-607005d5-3f75-4b2e-98f0-85ba66797a3e";
static ASUS_POST_LOGO_SOUND: &str =
"/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e";
pub struct CtrlRogBios {
_config: Arc<Mutex<Config>>,
}
#[derive(Serialize, Deserialize)]
pub struct RogBiosSupportedFunctions {
pub post_sound_toggle: bool,
pub dedicated_gfx_toggle: bool,
}
impl GetSupported for CtrlRogBios {
type A = RogBiosSupportedFunctions;
fn get_supported() -> Self::A {
RogBiosSupportedFunctions {
post_sound_toggle: CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND).is_ok(),
dedicated_gfx_toggle: CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok(),
}
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlRogBios {
pub fn set_dedicated_graphic_mode(&mut self, dedicated: bool) {
self.set_gfx_mode(dedicated)
.map_err(|err| {
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
err
})
.ok();
self.notify_dedicated_graphic_mode(dedicated)
.map_err(|err| {
warn!("CtrlRogBios: notify_asus_switch_graphic_mode {}", err);
err
})
.ok();
}
pub fn dedicated_graphic_mode(&self) -> i8 {
Self::get_gfx_mode()
.map_err(|err| {
warn!("CtrlRogBios: get_gfx_mode {}", err);
err
})
.unwrap_or(-1)
}
#[dbus_interface(signal)]
pub fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()> {}
// // // // // // // // // //
pub fn set_post_boot_sound(&mut self, on: bool) {
Self::set_boot_sound(on)
.map_err(|err| {
warn!("CtrlRogBios: set_post_boot_sound {}", err);
err
})
.ok();
self.notify_post_boot_sound(on)
.map_err(|err| {
warn!("CtrlRogBios: notify_post_boot_sound {}", err);
err
})
.ok();
}
pub fn post_boot_sound(&self) -> i8 {
Self::get_boot_sound()
.map_err(|err| {
warn!("CtrlRogBios: get_boot_sound {}", err);
err
})
.unwrap_or(-1)
}
#[dbus_interface(signal)]
pub fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for CtrlRogBios {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/RogBios".try_into().unwrap(), self)
.map_err(|err| {
warn!("CtrlRogBios: add_to_server {}", err);
err
})
.ok();
}
}
impl crate::Reloadable for CtrlRogBios {
fn reload(&mut self) -> Result<(), RogError> {
Ok(())
}
}
impl CtrlRogBios {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
match CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE) {
Ok(_) => {
CtrlRogBios::set_path_mutable(ASUS_SWITCH_GRAPHIC_MODE)?;
}
Err(err) => {
info!("ROG Switchable Graphics (bios) not detected: {}", err);
}
}
match CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND) {
Ok(_) => {
CtrlRogBios::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
}
Err(err) => {
info!("ROG boot sound toggle (bios) not detected: {}", err);
}
}
Ok(CtrlRogBios {
_config: config,
})
}
fn set_path_mutable(path: &str) -> Result<(), RogError> {
let output = Command::new("/usr/bin/chattr")
.arg("-i")
.arg(path)
.output()
.map_err(|err| RogError::Path(path.into(), err))?;
info!("Set {} writeable: status: {}", path, output.status);
Ok(())
}
fn check_path_exists(path: &str) -> Result<(), RogError> {
if Path::new(path).exists() {
Ok(())
} else {
Err(RogError::MissingFunction(path.into()))
}
}
pub fn has_dedicated_gfx_toggle() -> bool {
if CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok() {
return true;
}
false
}
pub fn get_gfx_mode() -> Result<i8, RogError> {
let path = ASUS_SWITCH_GRAPHIC_MODE;
let mut file = OpenOptions::new()
.read(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
Ok(data[idx] as i8)
}
pub(super) fn set_gfx_mode(&self, dedicated: bool) -> Result<(), RogError> {
let path = ASUS_SWITCH_GRAPHIC_MODE;
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data).unwrap();
let idx = data.len() - 1;
if dedicated {
data[idx] = 1;
info!("Set system-level graphics mode: Dedicated Nvidia");
} else {
data[idx] = 0;
info!("Set system-level graphics mode: Optimus");
}
file.write_all(&data)
.map_err(|err| RogError::Path(path.into(), err))?;
self.update_initramfs(dedicated)?;
// if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
// if let Ok(vendor) = CtrlGraphics::get_vendor() {
// if ded == 1 && vendor != "nvidia" {
// warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
// CtrlGraphics::set_gfx_config(&GfxVendors::Nvidia)
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
// }
// }
// }
Ok(())
}
pub fn get_boot_sound() -> Result<i8, RogError> {
let path = ASUS_POST_LOGO_SOUND;
let mut file = OpenOptions::new()
.read(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
Ok(data[idx] as i8)
}
pub(super) fn set_boot_sound(on: bool) -> Result<(), RogError> {
let path = ASUS_POST_LOGO_SOUND;
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
if on {
data[idx] = 1;
info!("Set boot POST sound on");
} else {
data[idx] = 0;
info!("Set boot POST sound off");
}
file.write_all(&data)
.map_err(|err| RogError::Path(path.into(), err))?;
Ok(())
}
// required for g-sync mode
fn update_initramfs(&self, dedicated: bool) -> Result<(), RogError> {
let mut initfs_cmd = None;
if Path::new(INITRAMFS_PATH).exists() {
let mut cmd = Command::new("update-initramfs");
cmd.arg("-u");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'update-initramfs'");
} else if Path::new(DRACUT_PATH).exists() {
let mut cmd = Command::new("dracut");
cmd.arg("-f");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'dracut'");
}
if let Some(mut cmd) = initfs_cmd {
info!("Updating initramfs");
// If switching to Nvidia dedicated we need these modules included
if Path::new(DRACUT_PATH).exists() && dedicated {
cmd.arg("--add-drivers");
cmd.arg("nvidia nvidia-drm nvidia-modeset nvidia-uvm");
info!("System uses dracut, forcing nvidia modules to be included in init");
} else if Path::new(INITRAMFS_PATH).exists() {
let modules = vec![
"nvidia\n",
"nvidia-drm\n",
"nvidia-modeset\n",
"nvidia-uvm\n",
];
let module_include = Path::new("/etc/initramfs-tools/modules");
if dedicated {
let mut file = std::fs::OpenOptions::new()
.append(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
// add nvidia modules to module_include
file.write_all(modules.concat().as_bytes()).unwrap();
} else {
let file = std::fs::OpenOptions::new()
.read(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
let mut buf = Vec::new();
// remove modules
for line in std::io::BufReader::new(file).lines() {
if let Ok(l) = line {
if !modules.contains(&l.as_ref()) {
buf.append(&mut l.as_bytes().to_vec());
}
}
}
let file = std::fs::OpenOptions::new()
.write(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
std::io::BufWriter::new(file).write_all(&buf).unwrap();
}
}
let status = cmd
.status()
.map_err(|err| RogError::Write(format!("{:?}", cmd), err))?;
if !status.success() {
error!("Ram disk update failed");
return Err(RogError::Initramfs("Ram disk update failed".into()).into());
} else {
info!("Successfully updated initramfs");
}
}
Ok(())
}
}

View File

@@ -0,0 +1,56 @@
use std::convert::TryInto;
use log::warn;
use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface;
use crate::{
ctrl_anime::{AnimeSupportedFunctions, CtrlAnimeDisplay},
ctrl_charge::{ChargeSupportedFunctions, CtrlCharge},
ctrl_fan_cpu::{CtrlFanAndCPU, FanCpuSupportedFunctions},
ctrl_leds::{CtrlKbdBacklight, LedSupportedFunctions},
ctrl_rog_bios::{CtrlRogBios, RogBiosSupportedFunctions},
GetSupported,
};
#[derive(Serialize, Deserialize)]
pub struct SupportedFunctions {
anime_ctrl: AnimeSupportedFunctions,
charge_ctrl: ChargeSupportedFunctions,
fan_cpu_ctrl: FanCpuSupportedFunctions,
keyboard_led: LedSupportedFunctions,
rog_bios_ctrl: RogBiosSupportedFunctions,
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl SupportedFunctions {
fn supported_functions(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
}
impl crate::ZbusAdd for SupportedFunctions {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Supported".try_into().unwrap(), self)
.map_err(|err| {
warn!("SupportedFunctions: add_to_server {}", err);
err
})
.ok();
}
}
impl GetSupported for SupportedFunctions {
type A = SupportedFunctions;
fn get_supported() -> Self::A {
SupportedFunctions {
keyboard_led: CtrlKbdBacklight::get_supported(),
anime_ctrl: CtrlAnimeDisplay::get_supported(),
charge_ctrl: CtrlCharge::get_supported(),
fan_cpu_ctrl: CtrlFanAndCPU::get_supported(),
rog_bios_ctrl: CtrlRogBios::get_supported(),
}
}
}

View File

@@ -1,20 +1,23 @@
use ctrl_gfx::ctrl_gfx::CtrlGraphics;
use daemon::config::Config;
use daemon::ctrl_anime::CtrlAnimeDisplay;
use daemon::ctrl_charge::CtrlCharge;
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::laptops::match_laptop;
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
use asus_nb::DBUS_NAME;
use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
use log::{error, info, warn};
use rog_dbus::DBUS_NAME;
use rog_types::gfx_vendors::GfxVendors;
use std::error::Error;
use std::io::Write;
use std::sync::Arc;
use std::sync::Mutex;
use daemon::ctrl_rog_bios::CtrlRogBios;
use std::convert::Into;
use std::convert::TryInto;
use zbus::fdo;
@@ -28,7 +31,10 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
.filter(None, LevelFilter::Info)
.init();
info!("Version: {}", daemon::VERSION);
info!(" daemon v{}", daemon::VERSION);
info!(" rog-dbus v{}", rog_dbus::VERSION);
info!("rog-types v{}", rog_types::VERSION);
start_daemon()?;
Ok(())
}
@@ -40,14 +46,16 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
//
// DBUS processing takes 6ms if not tokiod
fn start_daemon() -> Result<(), Box<dyn Error>> {
let supported = SupportedFunctions::get_supported();
print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let laptop = match_laptop();
let config = if let Some(laptop) = laptop.as_ref() {
Config::default().load(laptop.supported_modes())
Config::load(laptop.supported_modes())
} else {
Config::default().load(&[])
Config::load(&[])
};
let connection = Connection::new_system()?;
@@ -55,9 +63,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
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()) {
Ok(mut ctrl) => {
// Do a reload of any settings
ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("rog_bios_control: {}", err);
}
}
match CtrlCharge::new(config.clone()) {
Ok(mut ctrl) => {
// Do a reload of any settings
@@ -81,10 +104,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
if enable_gfx_switching {
match CtrlGraphics::new() {
match CtrlGraphics::new(config.clone()) {
Ok(mut ctrl) => {
// Need to check if a laptop has the dedicated gfx switch
if CtrlRogBios::has_dedicated_gfx_toggle() {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(vendor) = ctrl.get_gfx_mode() {
if ded == 1 && vendor != GfxVendors::Nvidia {
error!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
error!("You must reboot to enable Nvidia driver");
ctrl.do_vendor_tasks(GfxVendors::Nvidia)?;
} else if ded == 0 {
info!("Dedicated GFX toggle is off");
}
}
}
}
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
.unwrap_or_else(|err| error!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
@@ -102,8 +139,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
DbusFanAndCpu::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
if let Some(laptop) = laptop {
@@ -115,6 +151,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
)
.map_err(|err| {
error!("Keyboard control: {}", err);
err
}) {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
@@ -141,10 +178,15 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
});
object_server.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| {
let x = obj.limit();
obj.notify_charge(x as u8)
})?;
object_server
.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| {
let x = obj.limit();
obj.notify_charge(x as u8)
})
.map_err(|err| {
warn!("object_server notify_charge error: {}", err);
})
.ok();
loop {
if let Err(err) = object_server.try_handle_next() {

View File

@@ -1,8 +1,11 @@
use intel_pstate::PStateError;
use rog_fan_curve::CurveError;
use rog_types::error::GraphicsError;
use std::convert::From;
use std::fmt;
use crate::ctrl_gfx::error::GfxError;
#[derive(Debug)]
pub enum RogError {
ParseFanLevel,
@@ -20,6 +23,11 @@ pub enum RogError {
DoTask(String),
MissingFunction(String),
MissingLedBrightNode(String, std::io::Error),
ReloadFail(String),
GfxSwitching(GfxError),
Initramfs(String),
Modprobe(String),
Command(String, std::io::Error),
}
impl fmt::Display for RogError {
@@ -41,6 +49,11 @@ impl fmt::Display for RogError {
RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets),
RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
}
}
}
@@ -58,3 +71,11 @@ impl From<CurveError> for RogError {
RogError::FanCurve(err)
}
}
impl From<GraphicsError> for RogError {
fn from(err: GraphicsError) -> Self {
match err {
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
}
}
}

View File

@@ -1,5 +1,5 @@
use asus_nb::aura_modes::{AuraModes, BREATHING, STATIC, STROBE};
use log::{info, warn};
use rog_types::aura_modes::{AuraModes, BREATHING, STATIC};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Read;
@@ -8,6 +8,9 @@ pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6];
#[derive(Debug)]
pub struct LaptopBase {
usb_product: String,
condev_iface: Option<String>, // required for finding the Consumer Device interface
@@ -27,25 +30,24 @@ impl LaptopBase {
}
pub fn match_laptop() -> Option<LaptopBase> {
for device in rusb::devices().unwrap().iter() {
let device_desc = device.device_descriptor().unwrap();
for device in rusb::devices().expect("Couldn't get device").iter() {
let device_desc = device
.device_descriptor()
.expect("Couldn't get device descriptor");
if device_desc.vendor_id() == 0x0b05 {
match device_desc.product_id() {
0x1866 => {
let laptop = select_1866_device("1866".to_owned());
print_modes(&laptop.supported_modes);
if LAPTOP_DEVICES.contains(&device_desc.product_id()) {
let prod_str = format!("{:x?}", device_desc.product_id());
if device_desc.product_id() == 0x1854 {
let mut laptop = laptop(prod_str, None);
if laptop.supported_modes.is_empty() {
laptop.supported_modes = vec![STATIC, BREATHING];
}
return Some(laptop);
}
0x1869 => return Some(select_1866_device("1869".to_owned())),
0x1854 => {
info!("Found GL753 or similar");
return Some(LaptopBase {
usb_product: "1854".to_string(),
condev_iface: None,
supported_modes: vec![STATIC, BREATHING, STROBE],
});
}
_ => {}
let laptop = laptop(prod_str, Some("02".to_owned()));
return Some(laptop);
}
}
}
@@ -57,18 +59,14 @@ pub fn match_laptop() -> Option<LaptopBase> {
None
}
fn select_1866_device(prod: String) -> LaptopBase {
fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
let prod_name = dmi.product_name().expect("Could not get product_name");
info!("Product name: {}", prod_name.trim());
info!("Board name: {}", board_name.trim());
let mut laptop = LaptopBase {
usb_product: prod,
condev_iface: Some("02".to_owned()),
condev_iface,
supported_modes: vec![],
};
@@ -81,7 +79,18 @@ fn select_1866_device(prod: String) -> LaptopBase {
laptop
}
fn print_modes(supported_modes: &[u8]) {
pub fn print_board_info() {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_name = dmi.product_name().expect("Could not get product_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
info!("Product name: {}", prod_name.trim());
info!("Product family: {}", prod_family.trim());
info!("Board name: {}", board_name.trim());
}
pub fn print_modes(supported_modes: &[u8]) {
if !supported_modes.is_empty() {
info!("Supported Keyboard LED modes are:");
for mode in supported_modes {

63
daemon/src/lib.rs Normal file
View File

@@ -0,0 +1,63 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub(crate) mod config_old;
/// Control of AniMe matrix display
pub mod ctrl_anime;
/// Control of battery charge level
pub mod ctrl_charge;
/// Control CPU min/max freq and turbo, fan mode, fan curves
///
/// Intel machines can control:
/// - CPU min/max frequency
/// - CPU turbo enable/disable
/// - Fan mode (normal, boost, silent)
///
/// AMD machines can control:
/// - CPU turbo enable/disable
/// - Fan mode (normal, boost, silent)
/// - Fan min/max RPM curve
pub mod ctrl_fan_cpu;
/// GPU switching and power
pub mod ctrl_gfx;
/// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_leds;
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
pub mod ctrl_rog_bios;
/// Laptop matching to determine capabilities
pub mod laptops;
/// Fetch all supported functions for the laptop
pub mod ctrl_supported;
mod error;
use crate::error::RogError;
use config::Config;
use zbus::ObjectServer;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>;
}
pub trait ZbusAdd {
fn add_to_server(self, server: &mut ObjectServer);
}
pub trait CtrlTask {
fn do_task(&mut self) -> Result<(), RogError>;
}
pub trait CtrlTaskComplex {
type A;
fn do_task(&mut self, config: &mut Config, event: Self::A);
}
pub trait GetSupported {
type A;
fn get_supported() -> Self::A;
}

View File

@@ -8,6 +8,16 @@ prod_family = "Zephyrus M"
board_names = ["GU502GV"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "ROG Zephyrus M15"
board_names = ["GU502LW"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "ROG Zephyrus M15"
board_names = ["GU502LU"]
led_modes = [0, 1, 2, 10]
[[led_modes]]
prod_family = "Zephyrus"
board_names = ["GM501GM", "GX531"]
@@ -21,17 +31,17 @@ led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "ROG Strix"
board_names = ["GX531", "G512LV", "G712LV"]
led_modes = [0, 1, 2, 3, 10, 13]
led_modes = [0, 1, 2, 3, 10, 13, 14]
[[led_modes]]
prod_family = "ROG Strix"
board_names = ["G512LI", "G712LI"]
board_names = ["G512LI", "G712LI", "G531GD"]
led_modes = [0, 1, 2, 3, 10]
[[led_modes]]
prod_family = "Strix"
board_names = ["G731GV", "G731GW", "G531GV"]
led_modes = [0, 1, 2, 3, 13]
led_modes = [0, 1, 2, 3, 13, 14]
[[led_modes]]
prod_family = "Strix"
@@ -41,4 +51,9 @@ led_modes = [0, 1, 2, 3]
[[led_modes]]
prod_family = "Strix Scar"
board_names = ["G531", "G731"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 255]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 255]
[[led_modes]]
prod_family = "ROG"
board_names = ["GL553VE"]
led_modes = [0, 1, 2, 13, 14]

View File

@@ -10,6 +10,10 @@
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
</policy>
<policy group="users">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>
</policy>
<policy group="wheel">
<allow send_destination="org.asuslinux.Daemon"/>
<allow receive_sender="org.asuslinux.Daemon"/>

View File

@@ -1 +1,2 @@
ACTION=="add|change", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="18[0-9][0-9]", ENV{ID_TYPE}=="hid", TAG+="systemd", ENV{SYSTEMD_WANTS}="asusd.service"
ACTION=="add|change", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="1[89][a-zA-Z0-9][a-zA-Z0-9]|193b", ENV{ID_TYPE}=="hid", TAG+="systemd", ENV{SYSTEMD_WANTS}="asusd.service"
ACTION=="add|remove", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="1[89][a-zA-Z0-9][a-zA-Z0-9]|193b", RUN+="systemctl restart asusd.service"

View File

@@ -2,6 +2,7 @@
Description=ASUS Notebook Control
StartLimitInterval=200
StartLimitBurst=2
Before=display-manager.service
[Service]
ExecStart=/usr/bin/asusd

18
rog-dbus/Cargo.toml Normal file
View File

@@ -0,0 +1,18 @@
[package]
name = "rog_dbus"
version = "3.0.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
description = "dbus interface methods for asusctl"
edition = "2018"
[dependencies]
serde_json = "^1.0"
rog_types = { path = "../rog-types" }
rog_fan_curve = { version = "^0.1", features = ["serde"] }
zbus = "^1.8"
zbus_macros = "^1.8"
zvariant = "^2.4"

168
rog-dbus/src/lib.rs Normal file
View File

@@ -0,0 +1,168 @@
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
pub const LED_MSG_LEN: usize = 17;
pub mod zbus_anime;
pub mod zbus_charge;
pub mod zbus_gfx;
pub mod zbus_led;
pub mod zbus_profile;
pub mod zbus_rogbios;
pub mod zbus_supported;
use rog_types::aura_modes::AuraModes;
use std::sync::{Arc, Mutex};
use zbus::{Connection, Result, SignalReceiver};
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub struct DbusProxies<'a> {
anime: zbus_anime::AnimeProxy<'a>,
charge: zbus_charge::ChargeProxy<'a>,
gfx: zbus_gfx::GfxProxy<'a>,
led: zbus_led::LedProxy<'a>,
profile: zbus_profile::ProfileProxy<'a>,
rog_bios: zbus_rogbios::RogBiosProxy<'a>,
supported: zbus_supported::SupportProxy<'a>,
}
impl<'a> DbusProxies<'a> {
#[inline]
pub fn new() -> Result<(Self, Connection)> {
let conn = Connection::new_system()?;
Ok((
DbusProxies {
anime: zbus_anime::AnimeProxy::new(&conn)?,
led: zbus_led::LedProxy::new(&conn)?,
charge: zbus_charge::ChargeProxy::new(&conn)?,
gfx: zbus_gfx::GfxProxy::new(&conn)?,
profile: zbus_profile::ProfileProxy::new(&conn)?,
rog_bios: zbus_rogbios::RogBiosProxy::new(&conn)?,
supported: zbus_supported::SupportProxy::new(&conn)?,
},
conn,
))
}
pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver {
let mut recv = SignalReceiver::new(conn);
//recv.receive_for(&self.proxy_anime);
recv.receive_for(self.led.proxy());
recv.receive_for(self.charge.proxy());
recv.receive_for(self.gfx.proxy());
recv.receive_for(self.profile.proxy());
recv
}
pub fn anime(&self) -> &zbus_anime::AnimeProxy<'a> {
&self.anime
}
pub fn charge(&self) -> &zbus_charge::ChargeProxy<'a> {
&self.charge
}
pub fn gfx(&self) -> &zbus_gfx::GfxProxy<'a> {
&self.gfx
}
pub fn led(&self) -> &zbus_led::LedProxy<'a> {
&self.led
}
pub fn profile(&self) -> &zbus_profile::ProfileProxy<'a> {
&self.profile
}
pub fn rog_bios(&self) -> &zbus_rogbios::RogBiosProxy<'a> {
&self.rog_bios
}
pub fn supported(&self) -> &zbus_supported::SupportProxy<'a> {
&self.supported
}
}
// Signals separated out
pub struct Signals {
pub gfx_vendor: Arc<Mutex<Option<String>>>,
pub gfx_action: Arc<Mutex<Option<String>>>,
pub profile: Arc<Mutex<Option<String>>>,
pub led_mode: Arc<Mutex<Option<AuraModes>>>,
pub charge: Arc<Mutex<Option<u8>>>,
}
impl Signals {
#[inline]
pub fn new(proxies: &DbusProxies) -> Result<Self> {
//
let charge_signal = Arc::new(Mutex::new(None));
proxies
.charge
.connect_notify_charge(charge_signal.clone())?;
//
let ledmode_signal = Arc::new(Mutex::new(None));
proxies.led.connect_notify_led(ledmode_signal.clone())?;
let gfx_action_signal = Arc::new(Mutex::new(None));
proxies
.gfx
.connect_notify_action(gfx_action_signal.clone())?;
let gfx_vendor_signal = Arc::new(Mutex::new(None));
proxies.gfx.connect_notify_gfx(gfx_vendor_signal.clone())?;
let profile_signal = Arc::new(Mutex::new(None));
proxies
.profile
.connect_notify_profile(profile_signal.clone())?;
Ok(Signals {
gfx_vendor: gfx_vendor_signal,
gfx_action: gfx_action_signal,
profile: profile_signal,
led_mode: ledmode_signal,
charge: charge_signal,
})
}
}
/// This is the main way to communicate with the DBUS interface
pub struct AuraDbusClient<'a> {
proxies: DbusProxies<'a>,
signals: Signals,
}
impl<'a> AuraDbusClient<'a> {
#[inline]
pub fn new() -> Result<(Self, Connection)> {
let (proxies, conn) = DbusProxies::new()?;
let signals = Signals::new(&proxies)?;
Ok((AuraDbusClient { proxies, signals }, conn))
}
pub fn proxies(&self) -> &DbusProxies {
&self.proxies
}
/*
* GFX
*/
pub fn gfx_wait_changed(&self) -> Result<String> {
loop {
if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
if res.is_none() {
if let Ok(lock) = self.signals.gfx_action.lock() {
if let Some(stuff) = lock.as_ref() {
return Ok(stuff.to_string());
}
}
// return Ok("Failed for unknown reason".to_owned());
}
}
}
}
}

View File

@@ -0,0 +1,74 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_types::anime_matrix::{AniMeDataBuffer, AniMeImageBuffer};
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Anime"
)]
trait Daemon {
/// SetBootOnOff method
fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>;
/// SetOnOff method
fn set_on_off(&self, status: bool) -> zbus::Result<()>;
/// WriteDirect method
fn write_direct(&self, input: &[u8]) -> zbus::Result<()>;
/// WriteImage method
fn write_image(&self, input: &[Vec<u8>]) -> zbus::Result<()>;
}
pub struct AnimeProxy<'a>(DaemonProxy<'a>);
impl<'a> AnimeProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(AnimeProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn toggle_boot_on(&self, on: bool) -> Result<()> {
self.0.set_boot_on_off(on)
}
#[inline]
pub fn toggle_on(&self, on: bool) -> Result<()> {
self.0.set_on_off(on)
}
#[inline]
pub fn write_direct(&self, input: AniMeDataBuffer) -> Result<()> {
self.0.write_direct(input.get())
}
#[inline]
pub fn write_image(&self, input: AniMeImageBuffer) -> Result<()> {
self.0.write_image(input.get())
}
}

View File

@@ -0,0 +1,73 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Charge' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PropertiesProxy`]
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Charge"
)]
trait Daemon {
/// Limit method
fn limit(&self) -> zbus::Result<i16>;
/// SetLimit method
fn set_limit(&self, limit: u8) -> zbus::Result<()>;
/// NotifyCharge signal
#[dbus_proxy(signal)]
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
}
pub struct ChargeProxy<'a>(DaemonProxy<'a>);
impl<'a> ChargeProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(ChargeProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn write_limit(&self, level: u8) -> Result<()> {
self.0.set_limit(level)
}
#[inline]
pub fn get_limit(&self) -> Result<i16> {
self.0.limit()
}
#[inline]
pub fn connect_notify_charge(&self, charge: Arc<Mutex<Option<u8>>>) -> zbus::fdo::Result<()> {
self.0.connect_notify_charge(move |data| {
if let Ok(mut lock) = charge.lock() {
*lock = Some(data);
}
Ok(())
})
}
}

98
rog-dbus/src/zbus_gfx.rs Normal file
View File

@@ -0,0 +1,98 @@
//! # DBus interface proxy for: `org.asuslinux.Gfx`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Gfx' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PropertiesProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PeerProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Gfx"
)]
trait Daemon {
/// Power method
fn power(&self) -> zbus::Result<String>;
/// SetVendor method
fn set_vendor(&self, vendor: &str) -> zbus::Result<()>;
/// Vendor method
fn vendor(&self) -> zbus::Result<String>;
/// NotifyAction signal
#[dbus_proxy(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()>;
/// NotifyGfx signal
#[dbus_proxy(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
}
pub struct GfxProxy<'a>(DaemonProxy<'a>);
impl<'a> GfxProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(GfxProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn gfx_get_pwr(&self) -> Result<String> {
self.0.power()
}
#[inline]
pub fn gfx_get_mode(&self) -> Result<String> {
self.0.vendor()
}
#[inline]
pub fn gfx_write_mode(&self, vendor: &str) -> Result<()> {
self.0.set_vendor(vendor)
}
#[inline]
pub fn connect_notify_action(
&self,
action: Arc<Mutex<Option<String>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_action(move |data| {
if let Ok(mut lock) = action.lock() {
*lock = Some(data.to_owned());
}
Ok(())
})
}
#[inline]
pub fn connect_notify_gfx(&self, vendor: Arc<Mutex<Option<String>>>) -> zbus::fdo::Result<()> {
self.0.connect_notify_gfx(move |data| {
if let Ok(mut lock) = vendor.lock() {
*lock = Some(data.to_owned());
}
Ok(())
})
}
}

142
rog-dbus/src/zbus_led.rs Normal file
View File

@@ -0,0 +1,142 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Led' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result};
use rog_types::{aura_modes::AuraModes, cli_options::LedBrightness, fancy::KeyColourArray};
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Led"
)]
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
fn next_led_mode(&self) -> zbus::Result<()>;
/// PrevLedMode method
fn prev_led_mode(&self) -> zbus::Result<()>;
/// SetLedMode method
fn set_led_mode(&self, data: &str) -> zbus::Result<()>;
/// NotifyLed signal
#[dbus_proxy(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
pub struct LedProxy<'a>(DaemonProxy<'a>);
impl<'a> LedProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(LedProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn get_led_brightness(&self) -> Result<LedBrightness> {
match self.0.led_brightness()? {
-1 => Ok(LedBrightness::new(None)),
level => Ok(LedBrightness::new(Some(level as u8))),
}
}
#[inline]
pub fn set_brightness(&self, level: u8) -> Result<()> {
self.set_led_mode(&AuraModes::LedBrightness(level))?;
Ok(())
}
#[inline]
pub fn next_led_mode(&self) -> Result<()> {
self.0.next_led_mode()
}
#[inline]
pub fn prev_led_mode(&self) -> Result<()> {
self.0.prev_led_mode()
}
#[inline]
pub fn set_led_mode(&self, mode: &AuraModes) -> Result<()> {
self.0.set_led_mode(&serde_json::to_string(mode).unwrap())
}
/// Write a single colour block.
///
/// Intentionally blocks for 10ms after sending to allow the block to
/// be written to the keyboard EC. This should not be async.
#[inline]
pub fn set_per_key(&self, key_colour_array: &KeyColourArray) -> Result<()> {
let group = key_colour_array.get();
let mut vecs = Vec::with_capacity(group.len());
for v in group {
vecs.push(v.to_vec());
}
let mode = AuraModes::PerKey(vecs);
self.set_led_mode(&mode)?;
std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME));
// if self.stop.load(Ordering::Relaxed) {
// println!("Keyboard backlight was changed, exiting");
// std::process::exit(1)
// }
Ok(())
}
/// This method must always be called before the very first write to initialise
/// the keyboard LED EC in the correct mode
#[inline]
pub fn init_effect(&self) -> Result<()> {
let mode = AuraModes::PerKey(vec![vec![]]);
self.0.set_led_mode(&serde_json::to_string(&mode).unwrap())
}
#[inline]
pub fn connect_notify_led(&self, led: Arc<Mutex<Option<AuraModes>>>) -> zbus::fdo::Result<()> {
self.0.connect_notify_led(move |data| {
if let Ok(mut lock) = led.lock() {
if let Ok(dat) = serde_json::from_str(&data) {
*lock = Some(dat);
}
}
Ok(())
})
}
}

View File

@@ -0,0 +1,97 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Profile' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::{Arc, Mutex};
use rog_types::profile::ProfileEvent;
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Profile"
)]
trait Daemon {
/// ActiveProfileName method
fn active_profile_name(&self) -> zbus::Result<String>;
/// NextProfile method
fn next_profile(&self) -> zbus::Result<()>;
/// Profile method
fn profile(&self) -> zbus::Result<String>;
/// Profiles method
fn profiles(&self) -> zbus::Result<String>;
/// SetProfile method
fn set_profile(&self, profile: &str) -> zbus::Result<()>;
/// NotifyProfile signal
#[dbus_proxy(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
}
pub struct ProfileProxy<'a>(DaemonProxy<'a>);
impl<'a> ProfileProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(ProfileProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn active_profile_name(&self) -> Result<String> {
self.0.active_profile_name()
}
#[inline]
pub fn next_fan(&self) -> Result<()> {
self.0.next_profile()
}
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<()> {
self.0
.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level)).unwrap())
}
#[inline]
pub fn write_command(&self, cmd: &ProfileEvent) -> Result<()> {
self.0.set_profile(&serde_json::to_string(cmd).unwrap())
}
#[inline]
pub fn connect_notify_profile(
&self,
charge: Arc<Mutex<Option<String>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_profile(move |data| {
if let Ok(mut lock) = charge.lock() {
*lock = Some(data.to_owned());
}
Ok(())
})
}
}

View File

@@ -0,0 +1,109 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/RogBios' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PropertiesProxy`]
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/RogBios"
)]
trait Daemon {
/// DedicatedGraphicMode method
fn dedicated_graphic_mode(&self) -> zbus::Result<i16>;
/// PostBootSound method
fn post_boot_sound(&self) -> zbus::Result<i16>;
/// SetDedicatedGraphicMode method
fn set_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()>;
/// SetPostBootSound method
fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>;
/// NotifyDedicatedGraphicMode signal
#[dbus_proxy(signal)]
fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()>;
/// NotifyPostBootSound signal
#[dbus_proxy(signal)]
fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()>;
}
pub struct RogBiosProxy<'a>(DaemonProxy<'a>);
impl<'a> RogBiosProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(RogBiosProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn get_dedicated_gfx(&self) -> Result<i16> {
self.0.dedicated_graphic_mode()
}
#[inline]
pub fn set_dedicated_gfx(&self, on: bool) -> Result<()> {
self.0.set_dedicated_graphic_mode(on)
}
#[inline]
pub fn get_post_sound(&self) -> Result<i16> {
self.0.post_boot_sound()
}
#[inline]
pub fn set_post_sound(&self, on: bool) -> Result<()> {
self.0.set_post_boot_sound(on)
}
#[inline]
pub fn connect_notify_dedicated_graphic_mode(
&self,
dedicated: Arc<Mutex<Option<bool>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_dedicated_graphic_mode(move |data| {
if let Ok(mut lock) = dedicated.lock() {
*lock = Some(data);
}
Ok(())
})
}
#[inline]
pub fn connect_notify_post_boot_sound(
&self,
sound: Arc<Mutex<Option<bool>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_post_boot_sound(move |data| {
if let Ok(mut lock) = sound.lock() {
*lock = Some(data);
}
Ok(())
})
}
}

View File

@@ -0,0 +1,49 @@
//! # DBus interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Supported' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This DBus object implements
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Supported"
)]
trait Daemon {
/// SupportedFunctions method
fn supported_functions(&self) -> zbus::Result<String>;
}
pub struct SupportProxy<'a>(DaemonProxy<'a>);
impl<'a> SupportProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(SupportProxy(DaemonProxy::new(&conn)?))
}
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn get_supported_functions(&self) -> Result<String> {
self.0.supported_functions()
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb"
version = "2.1.2"
name = "rog_types"
version = "3.0.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -11,15 +11,8 @@ edition = "2018"
[dependencies]
gumdrop = "^0.8"
dbus = { version = "^0.8" }
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
yansi-term = "^0.1"
rog_fan_curve = { version = "0.1", features = ["serde"] }
zbus = "^1.8.0"
zvariant = "^2.4.0"
ctrl-gfx = { path = "../ctrl-gfx" }
[dev-dependencies]
tinybmp = "^0.2.3"
rog_fan_curve = { version = "^0.1", features = ["serde"] }
zvariant = "^2.5"
zvariant_derive = "^2.5"

View File

@@ -1,32 +1,76 @@
use serde_derive::{Deserialize, Serialize};
use zvariant_derive::Type;
pub const WIDTH: usize = 34; // Width is definitely 34 items
pub const HEIGHT: usize = 56;
pub type AniMeBufferType = [[u8; WIDTH]; HEIGHT];
pub type AniMePacketType = [[u8; 640]; 2];
const BLOCK_START: usize = 7;
/// *Not* inclusive, the byte before this is the final for each "pane"
const BLOCK_END: usize = 634;
use yansi_term::Colour::RGB;
pub const PANE_LEN: usize = BLOCK_END - BLOCK_START;
/// The length of usable data
pub const FULL_PANE_LEN: usize = PANE_LEN * 2;
/// Helper structure for writing images.
///
/// See the examples for ways to write an image to `AniMeMatrix` format.
pub struct AniMeMatrix(AniMeBufferType);
pub const ANIME_PANE1_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
impl Default for AniMeMatrix {
#[derive(Debug, Deserialize, Serialize, Type)]
pub struct AniMeDataBuffer(Vec<u8>);
impl Default for AniMeDataBuffer {
fn default() -> Self {
Self::new()
}
}
impl AniMeMatrix {
impl AniMeDataBuffer {
pub fn new() -> Self {
AniMeMatrix([[0u8; WIDTH]; HEIGHT])
AniMeDataBuffer(vec![0u8; FULL_PANE_LEN])
}
pub fn get(&self) -> &AniMeBufferType {
pub fn get(&self) -> &[u8] {
&self.0
}
pub fn get_mut(&mut self) -> &mut AniMeBufferType {
pub fn set(&mut self, input: [u8; FULL_PANE_LEN]) {
self.0 = input.to_vec();
}
}
impl From<AniMeDataBuffer> for AniMePacketType {
#[inline]
fn from(anime: AniMeDataBuffer) -> Self {
assert!(anime.0.len() == FULL_PANE_LEN);
let mut buffers = [[0; 640]; 2];
for (idx, chunk) in anime.0.as_slice().chunks(PANE_LEN).enumerate() {
buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk);
}
buffers
}
}
/// Helper structure for writing images.
///
/// See the examples for ways to write an image to `AniMeMatrix` format.
#[derive(Debug, Deserialize, Serialize, Type)]
pub struct AniMeImageBuffer(Vec<Vec<u8>>);
impl Default for AniMeImageBuffer {
fn default() -> Self {
Self::new()
}
}
impl AniMeImageBuffer {
pub fn new() -> Self {
AniMeImageBuffer(vec![vec![0u8; WIDTH]; HEIGHT])
}
pub fn get(&self) -> &Vec<Vec<u8>> {
&self.0
}
pub fn get_mut(&mut self) -> &mut Vec<Vec<u8>> {
&mut self.0
}
@@ -55,8 +99,8 @@ impl AniMeMatrix {
} else {
row.iter()
};
for x in tmp {
print!(" {}", RGB(*x, *x, *x).paint("XY"));
for _ in tmp {
print!(" XY");
}
println!();
@@ -78,9 +122,9 @@ impl AniMeMatrix {
if count % 2 == 0 {
print!(" ");
}
for (i, x) in row.iter().enumerate() {
for (i, _) in row.iter().enumerate() {
if i >= index {
print!(" {}", RGB(*x, *x, *x).paint("XY"));
print!(" XY");
} else {
print!(" ");
}
@@ -91,11 +135,11 @@ impl AniMeMatrix {
}
}
impl From<AniMeMatrix> for AniMePacketType {
impl From<AniMeImageBuffer> for AniMePacketType {
/// Do conversion from the nested Vec in AniMeMatrix to the two required
/// packets suitable for sending over USB
#[inline]
fn from(anime: AniMeMatrix) -> Self {
fn from(anime: AniMeImageBuffer) -> Self {
let mut buffers = [[0; 640]; 2];
let mut write_index = BLOCK_START;
@@ -153,15 +197,26 @@ impl From<AniMeMatrix> for AniMePacketType {
#[cfg(test)]
mod tests {
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
use crate::anime_matrix::*;
use super::AniMeDataBuffer;
#[test]
fn check_from_data_buffer() {
let mut data = AniMeDataBuffer::new();
data.set([42u8; FULL_PANE_LEN]);
let out: AniMePacketType = data.into();
}
#[test]
fn check_data_alignment() {
let mut matrix = AniMeMatrix::new();
let mut matrix = AniMeImageBuffer::new();
{
let tmp = matrix.get_mut();
for row in tmp.iter_mut() {
row[row.len() - 1] = 0xff;
let idx = row.len() - 1;
row[idx] = 0xff;
}
}

View File

@@ -1,6 +1,8 @@
use crate::cli_options;
use crate::cli_options::SetAuraBuiltin;
use crate::error::AuraError;
use gumdrop::Options;
use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
pub const STATIC: u8 = 0x00;
pub const BREATHING: u8 = 0x01;
@@ -15,41 +17,56 @@ 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);
impl From<cli_options::Colour> for Colour {
fn from(c: cli_options::Colour) -> Self {
Colour(c.0, c.1, c.2)
}
}
impl Default for Colour {
fn default() -> Self {
Colour(128, 0, 0)
}
}
impl FromStr for Colour {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() < 6 {
return Err(AuraError::ParseColour);
}
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
Ok(Colour(r, g, b))
}
}
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
pub enum Speed {
Low = 0xe1,
Med = 0xeb,
High = 0xf5,
}
impl From<cli_options::Speed> for Speed {
fn from(s: cli_options::Speed) -> Self {
match s {
cli_options::Speed::Low => Speed::Low,
cli_options::Speed::Med => Speed::Med,
cli_options::Speed::High => Speed::High,
}
}
}
impl Default for Speed {
fn default() -> Self {
Speed::Med
}
}
impl FromStr for Speed {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"low" => Ok(Speed::Low),
"med" => Ok(Speed::Med),
"high" => Ok(Speed::High),
_ => Err(AuraError::ParseSpeed),
}
}
}
/// Used for Rainbow mode.
///
@@ -61,107 +78,108 @@ pub enum Direction {
Up,
Down,
}
impl From<cli_options::Direction> for Direction {
fn from(s: cli_options::Direction) -> Self {
match s {
cli_options::Direction::Right => Direction::Right,
cli_options::Direction::Left => Direction::Left,
cli_options::Direction::Up => Direction::Up,
cli_options::Direction::Down => Direction::Down,
}
}
}
impl Default for Direction {
fn default() -> Self {
Direction::Right
}
}
impl FromStr for Direction {
type Err = AuraError;
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct TwoColourSpeed {
pub colour: Colour,
pub colour2: Colour,
pub speed: Speed,
}
impl From<cli_options::TwoColourSpeed> for TwoColourSpeed {
fn from(mode: cli_options::TwoColourSpeed) -> Self {
TwoColourSpeed {
colour: mode.colour.into(),
colour2: mode.colour2.into(),
speed: mode.speed.into(),
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"right" => Ok(Direction::Right),
"up" => Ok(Direction::Up),
"down" => Ok(Direction::Down),
"left" => Ok(Direction::Left),
_ => Err(AuraError::ParseDirection),
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
pub struct SingleSpeed {
#[serde(skip)]
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
pub speed: Speed,
}
impl From<cli_options::SingleSpeed> for SingleSpeed {
fn from(mode: cli_options::SingleSpeed) -> Self {
SingleSpeed {
speed: mode.speed.into(),
}
}
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
pub struct SingleSpeedDirection {
#[serde(skip)]
#[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, Deserialize, Serialize)]
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
pub struct SingleColour {
#[serde(skip)]
#[options(help = "print help message")]
help: bool,
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
pub colour: Colour,
}
impl From<cli_options::SingleColour> for SingleColour {
fn from(mode: cli_options::SingleColour) -> Self {
SingleColour {
colour: mode.colour.into(),
}
}
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
pub struct SingleColourSpeed {
#[serde(skip)]
#[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, Default, Deserialize, Serialize)]
pub struct MultiColour {
pub colour1: Colour,
#[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,
}
impl From<cli_options::MultiColour> for MultiColour {
fn from(mode: cli_options::MultiColour) -> Self {
MultiColour {
colour1: mode.colour1.into(),
colour2: mode.colour2.into(),
colour3: mode.colour3.into(),
colour4: mode.colour4.into(),
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct SingleSpeedDirection {
pub direction: Direction,
#[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,
}
impl From<cli_options::SingleSpeedDirection> for SingleSpeedDirection {
fn from(mode: cli_options::SingleSpeedDirection) -> Self {
SingleSpeedDirection {
direction: mode.direction.into(),
speed: mode.speed.into(),
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct SingleColourSpeed {
pub colour: Colour,
pub speed: Speed,
}
impl From<cli_options::SingleColourSpeed> for SingleColourSpeed {
fn from(mode: cli_options::SingleColourSpeed) -> Self {
SingleColourSpeed {
colour: mode.colour.into(),
speed: mode.speed.into(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum AuraModes {
@@ -178,6 +196,7 @@ pub enum AuraModes {
Comet(SingleColour),
Flash(SingleColour),
MultiStatic(MultiColour),
MultiBreathe(MultiColourSpeed),
LedBrightness(u8),
// TODO: use a serializable structure for this (KeyColourArray)
PerKey(Vec<Vec<u8>>),
@@ -186,19 +205,20 @@ pub enum AuraModes {
impl From<SetAuraBuiltin> for AuraModes {
fn from(mode: SetAuraBuiltin) -> Self {
match mode {
SetAuraBuiltin::Static(x) => AuraModes::Static(x.into()),
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x.into()),
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x.into()),
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x.into()),
SetAuraBuiltin::Star(x) => AuraModes::Star(x.into()),
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x.into()),
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x.into()),
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x.into()),
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x.into()),
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x.into()),
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x.into()),
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x.into()),
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x.into()),
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),
}
}
}
@@ -234,6 +254,7 @@ impl From<&AuraModes> for u8 {
AuraModes::Comet(_) => COMET,
AuraModes::Flash(_) => FLASH,
AuraModes::MultiStatic(_) => MULTISTATIC,
AuraModes::MultiBreathe(_) => MULTIBREATHE,
AuraModes::PerKey(_) => PER_KEY,
_ => panic!("Invalid mode"),
}
@@ -256,6 +277,7 @@ impl From<&AuraModes> for &str {
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"),
}
@@ -280,6 +302,7 @@ impl From<u8> for AuraModes {
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"),
}

View File

@@ -0,0 +1,147 @@
use crate::{
aura_modes::{
MultiColour, MultiColourSpeed, SingleColour, SingleColourSpeed, SingleSpeed,
SingleSpeedDirection, TwoColourSpeed,
},
error::AuraError,
};
use gumdrop::Options;
use serde_derive::{Deserialize, Serialize};
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)]
pub enum AniMeStatusValue {
On,
Off,
}
impl FromStr for AniMeStatusValue {
type Err = AuraError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"on" => Ok(AniMeStatusValue::On),
"off" => Ok(AniMeStatusValue::Off),
_ => {
print!("Invalid argument, must be one of: on, off");
Err(AuraError::ParseAnime)
}
}
}
}
impl From<AniMeStatusValue> for bool {
fn from(value: AniMeStatusValue) -> Self {
match value {
AniMeStatusValue::On => true,
AniMeStatusValue::Off => false,
}
}
}
#[derive(Options)]
pub struct AniMeLeds {
#[options(help = "print help message")]
help: bool,
#[options(
no_long,
required,
short = "b",
meta = "",
help = "set all leds brightness value"
)]
led_brightness: u8,
}
impl AniMeLeds {
pub fn led_brightness(&self) -> u8 {
self.led_brightness
}
}
#[derive(Options)]
pub enum AniMeActions {
#[options(help = "change all leds brightness")]
Leds(AniMeLeds),
}

View File

@@ -1,4 +1,6 @@
#[derive(Debug, PartialEq, Clone)]
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum GfxVendors {
Nvidia,
Integrated,
@@ -6,13 +8,14 @@ pub enum GfxVendors {
Hybrid,
}
use crate::error::GfxError;
use std::str::FromStr;
impl FromStr for GfxVendors {
type Err = GfxError;
use crate::error::GraphicsError;
fn from_str(s: &str) -> Result<Self, GfxError> {
impl FromStr for GfxVendors {
type Err = GraphicsError;
fn from_str(s: &str) -> Result<Self, GraphicsError> {
match s.to_lowercase().as_str() {
"nvidia" => Ok(GfxVendors::Nvidia),
"hybrid" => Ok(GfxVendors::Hybrid),
@@ -22,14 +25,14 @@ impl FromStr for GfxVendors {
"hybrid\n" => Ok(GfxVendors::Hybrid),
"compute\n" => Ok(GfxVendors::Compute),
"integrated\n" => Ok(GfxVendors::Integrated),
_ => Err(GfxError::ParseVendor),
_ => Err(GraphicsError::ParseVendor),
}
}
}
impl From<&GfxVendors> for &str {
fn from(mode: &GfxVendors) -> Self {
match mode {
impl Into<&str> for GfxVendors {
fn into(self) -> &'static str {
match self {
GfxVendors::Nvidia => "nvidia",
GfxVendors::Hybrid => "hybrid",
GfxVendors::Compute => "compute",
@@ -38,6 +41,17 @@ impl From<&GfxVendors> for &str {
}
}
impl Into<String> for GfxVendors {
fn into(self) -> String {
match self {
GfxVendors::Nvidia => "nvidia".to_string(),
GfxVendors::Hybrid => "hybrid".to_string(),
GfxVendors::Compute => "compute".to_string(),
GfxVendors::Integrated => "integrated".to_string(),
}
}
}
#[derive(Debug)]
pub enum GfxCtrlAction {
Reboot,
@@ -46,14 +60,14 @@ pub enum GfxCtrlAction {
}
impl FromStr for GfxCtrlAction {
type Err = GfxError;
type Err = GraphicsError;
fn from_str(s: &str) -> Result<Self, GfxError> {
fn from_str(s: &str) -> Result<Self, GraphicsError> {
match s.to_lowercase().as_str() {
"reboot" => Ok(GfxCtrlAction::Reboot),
"restartx" => Ok(GfxCtrlAction::RestartX),
"none" => Ok(GfxCtrlAction::None),
_ => Err(GfxError::ParseVendor),
_ => Err(GraphicsError::ParseVendor),
}
}
}

View File

@@ -14,23 +14,15 @@ pub mod cli_options;
/// Enables you to create fancy RGB effects
pub mod fancy;
/// The main dbus group for system controls, e.g, fan control, keyboard LED's
pub mod core_dbus;
/// Specific dbus for writing to the AniMe Matrix display (if supported)
pub mod anime_dbus;
/// Helper functions for the AniMe display
pub mod anime_matrix;
pub mod dbus_anime;
pub mod dbus_charge;
pub mod dbus_gfx;
pub mod dbus_ledmode;
pub mod dbus_profile;
pub mod gfx_vendors;
pub mod error;
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];
@@ -151,6 +143,7 @@ impl From<&AuraModes> for [u8; LED_MSG_LEN] {
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,
@@ -232,14 +225,15 @@ impl From<&AuraModes> for [[u8; LED_MSG_LEN]; 4] {
#[inline]
fn from(mode: &AuraModes) -> Self {
let mut msg = [[0u8; LED_MSG_LEN]; 4];
for (i, row) in msg.iter_mut().enumerate() {
row[0] = 0x5d;
row[1] = 0xb3;
row[2] = i as u8 + 1;
}
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;
@@ -253,6 +247,35 @@ impl From<&AuraModes> for [[u8; LED_MSG_LEN]; 4] {
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

View File

@@ -75,7 +75,7 @@ fn parse_fan_curve(data: &str) -> Result<Curve, String> {
#[derive(Debug, Clone, Options, Serialize, Deserialize)]
pub struct ProfileCommand {
#[options(help = "print help message")]
help: bool,
pub help: bool,
#[options(help = "toggle to next profile in list")]
pub next: bool,
#[options(help = "create the profile if it doesn't exist")]