Compare commits

...

144 Commits

Author SHA1 Message Date
Luke D. Jones 1b023d0f5f Fix and prep new 6.0.2 release 2024-05-08 16:27:40 +12:00
Luke D. Jones 74f74e73c4 Update deps, point release 2024-05-07 13:56:25 +12:00
Luke D. Jones 9c7df9ad39 Update deps, point release 2024-05-07 12:58:17 +12:00
Luke D. Jones 94adf5d24d Revert back to zbus 4.1 2024-05-06 23:54:36 +12:00
Luke D. Jones 8dbdb68175 Increase tray icon sleep time 2024-05-06 23:14:51 +12:00
Luke D. Jones 89002eb5ec Use fluent-dark instead of cosmic due to compile times 2024-05-06 23:01:03 +12:00
Luke D. Jones dc9ef8cf54 Remove unused deps 2024-05-06 13:25:07 +12:00
Luke D. Jones 667697d042 Cleanup deps 2024-05-06 10:58:11 +12:00
Luke D. Jones bc92fa11f9 Update all cargo.toml. Support G713P 2024-05-06 09:45:35 +12:00
Luke D. Jones f5d5681b49 Prep changelog 2024-05-05 20:52:38 +12:00
Luke D. Jones 1c8e50843b Cleanup files, prep new release 2024-05-05 20:22:56 +12:00
Luke D. Jones 487d140bd5 Anime: Better prevent await blocking. Prevent Slash taking over anime USB dev 2024-05-05 10:56:55 +12:00
Luke D. Jones 661ea8d3bf Fix fedora install instruction 2024-04-19 11:11:58 +12:00
Luke D. Jones 28d1ed6ab3 Fix broke logix 2024-04-18 14:40:39 +12:00
Luke D. Jones 903b978e86 Add missing files 2024-04-18 13:55:02 +12:00
Luke D. Jones 519f6bd46b Cleanup notifs, sys state, ac/bat commands 2024-04-18 13:48:23 +12:00
Luke D. Jones a94a8ca28d Support the GU605M keyboard 2024-04-18 10:08:40 +12:00
Luke D. Jones f9dca2da5d Re-add TUF keyboard support 2024-04-17 21:39:58 +12:00
Luke Jones df88ff1acb Update asusd.service 2024-04-17 06:11:00 +00:00
Luke Jones cb5aa0f170 Update asusd.service 2024-04-17 06:10:44 +00:00
Luke D. Jones 4ea79f966e Add updated translation + aura_support.ron 2024-04-17 14:18:27 +12:00
Luke D. Jones b8bc1a01b3 Fix colour hex in gui 2024-04-17 12:46:36 +12:00
Luke D. Jones 0e5d1815bd Bump alpha version 2024-04-17 11:55:19 +12:00
Luke D. Jones 64e8cb65d0 Many cleanup and fix 2024-04-17 11:54:14 +12:00
Luke D. Jones 3142353f98 Fix tests 2024-04-11 13:18:03 +12:00
Luke D. Jones 484ca692ad Refactoring led support data 2024-04-10 21:14:47 +12:00
Luke D. Jones 1ebdfada96 Update discord invite 2024-04-10 18:09:41 +12:00
Luke D. Jones 3bc9dfcda1 Support GA402N keyboard 2024-04-10 17:04:21 +12:00
Luke D. Jones 895e5d2ca3 Support GA402N keyboard 2024-04-10 17:04:08 +12:00
Luke D. Jones 564992719e Fixes to slash merge 2024-04-10 09:13:26 +12:00
Luke Jones a737d240be Merge pull request #23 from jschoubben/main
Add support for 2024 G14 Slash lighting (GA403UI)
2024-04-10 08:55:17 +12:00
Luke Jones d89c1ebf26 Merge branch 'main' into main 2024-04-10 08:54:54 +12:00
Luke D. Jones be7686bb46 Dump deps and version 2024-04-09 21:24:55 +12:00
Luke D. Jones 4f70055f85 Complete building 2024-04-09 21:02:09 +12:00
Luke D. Jones 91ca049298 Unify the laptop aura power stuff 2024-04-09 12:13:42 +12:00
Luke D. Jones 635d0378ac Bump deps 2024-04-06 14:10:18 +13:00
Luke D. Jones 1c729316f7 Refactor, rename, organise rog-aura stuff better 2024-04-05 21:20:34 +13:00
Luke D. Jones 4701c019a8 Major cleanup of older gui state code 2024-04-05 20:19:07 +13:00
Luke D. Jones ca0d8bda4b Update readme. Fix tray startup 2024-04-05 16:00:20 +13:00
Luke D. Jones a271ffbb10 rcc: run as app only on Ally 2024-04-04 09:58:40 +13:00
Luke D. Jones 00babaf949 Update translations 2024-04-03 16:15:09 +13:00
Luke D. Jones 2f844ac151 Cleanup 2024-04-03 16:15:09 +13:00
Luke D. Jones 5178bf1d1a Update readme 2024-04-03 16:15:09 +13:00
jochen@g14 116afb9b6c Initialize slash from config file 2024-03-31 01:08:26 +01:00
jochen@g14 4468a58487 Use enable/disable commands and cleanup build warnings 2024-03-31 00:34:44 +01:00
jochen@g14 2f73577e91 Fix Cargo.toml 2024-03-30 23:33:30 +01:00
jochen@g14 c1cffc8f59 Remove example file since it's not correct 2024-03-30 23:29:55 +01:00
jochen@g14 6d8f85c154 Minor changes to reflect original files 2024-03-30 23:27:33 +01:00
jochen@g14 0674e7f61c Changes after my own PR review 2024-03-30 23:23:37 +01:00
jochen@g14 fde2f3ba15 Fixed issues with asusctl-slash command 2024-03-30 21:19:55 +01:00
jochen@g14 70493d1a93 Fix error in makefile 2024-03-30 19:39:42 +01:00
jochen@g14 c20d0a76a0 Fix build after merge 2024-03-30 19:00:22 +01:00
jochen@g14 e6952e241a Merge from main 2024-03-30 18:44:15 +01:00
jochen@g14 b40812928a Imlement Display and FromStr traits for SlashMode 2024-03-30 18:42:42 +01:00
jochen@g14 8cdc9773c9 Added working implementation of the G14 Slash ledstrip 2024-03-30 18:41:31 +01:00
Luke Jones 8d30282edf Update default.md 2024-03-28 01:03:30 +00:00
Luke D. Jones 4ba44560a9 Update deps 2024-03-27 19:27:22 +13:00
jochen@g14 cdc9ca7b58 Try to implement slash bar functionality - part 1 2024-03-25 01:54:05 +01:00
Luke D. Jones 7eae7c5664 Change aura manager task to blocking. Remove idle tasks that keep hanging 2024-03-24 21:14:54 +13:00
Luke D. Jones 739a0ffa63 aura debugging 2024-03-24 10:55:20 +13:00
Luke D. Jones 637360095c Shift init actions up a few calls to prevent over-eager init 2024-03-23 23:27:26 +13:00
Luke D. Jones 4b34ab83fb Initial pass of async task sync in aura 2024-03-23 23:15:38 +13:00
Luke D. Jones ac605cbc00 Narrow the search space of aura devices down 2024-03-23 14:30:00 +13:00
Luke D. Jones 4b38e5daa6 Further adjustments to aura 2024-03-23 13:07:20 +13:00
Luke D. Jones 1c007b4216 Small refinement to aura control init 2024-03-23 11:45:20 +13:00
Luke D. Jones 193f9dfa1e Extra logging for aura 2024-03-23 11:27:20 +13:00
Jochen@Jinbe 1366422d96 Play around and add rog-slash 2024-03-22 22:05:27 +01:00
Luke D. Jones 4e778a3d28 Refactor HidRaw 2024-03-22 19:47:24 +13:00
Luke D. Jones be05508110 Try to ensure all aura are detected at start 2024-03-22 17:36:58 +13:00
Luke D. Jones 9119229d41 Update deps 2024-03-20 23:12:52 +13:00
Luke D. Jones 5c43c31331 Manage add/remove aura
Serialize aura config filename
2024-03-20 23:00:25 +13:00
Luke D. Jones 014604724f Fix clippy lints 2024-03-15 19:41:38 +13:00
Luke D. Jones 7d076368e9 Adjust organization of rog control src 2024-03-15 17:19:54 +13:00
Luke D. Jones 5d6ed5c365 Remove old screenshits 2024-03-14 22:17:42 +13:00
Luke D. Jones a2b8f0f93c Minor updates 2024-03-14 22:10:14 +13:00
Luke D. Jones 5fe8416c65 Only apply fan curve for profile if *on* that profile, but still save config 2024-03-14 21:28:06 +13:00
Luke D. Jones 1b4d7a95af Minor corrections 2024-03-14 21:24:28 +13:00
Luke D. Jones e8627fde4c Fix applying disabled and enabled fan curves 2024-03-14 21:11:18 +13:00
Luke D. Jones 6b0edc6da1 Enable fan curves 2024-03-14 17:17:55 +13:00
Luke D. Jones f6ad631a0f Update readme 2024-03-14 11:19:31 +13:00
Luke D. Jones f6393a3926 Further fan-curve graph work 2024-03-13 23:30:06 +13:00
Luke D. Jones d51384c3a1 Fix the fan curve defaults again 2024-03-13 21:19:01 +13:00
Luke D. Jones 78f18959fb Populate fan curve data 2024-03-13 20:18:41 +13:00
Luke D. Jones 7a661a585e Add missing file 2024-03-13 19:14:29 +13:00
Luke D. Jones f4f7a1e648 Check in the fan curve work 2024-03-13 18:57:38 +13:00
Luke D. Jones b6e3e5e823 Remove a dbg 2024-03-13 14:08:43 +13:00
Luke D. Jones 41b1bd23d6 Fix fancurves 2024-03-13 14:08:08 +13:00
Luke D. Jones 69458a0595 Minor fix to graph widget 2024-03-12 22:06:56 +13:00
Luke D. Jones 5fd107df27 Initial fan graph widget 2024-03-12 21:33:39 +13:00
Luke D. Jones 2558057e9f Use mix instead of interpolate 2024-03-12 00:09:54 +13:00
Luke D. Jones 8111daaf1d Use mix instead of interpolate 2024-03-12 00:08:54 +13:00
Luke D. Jones 672acb234f Make aura settings apply instantly 2024-03-11 23:27:07 +13:00
Luke D. Jones 9725062fb9 Refactor and cleanup theming 2024-03-11 22:26:26 +13:00
Luke D. Jones c7b1624313 Remove dbg statements 2024-03-11 12:53:38 +13:00
Luke D. Jones 67b97f1d43 Update ci and readme 2024-03-10 23:29:50 +13:00
Luke D. Jones 6498fd1349 Move rog<->slint type conversions to module 2024-03-10 21:12:36 +13:00
Luke D. Jones e371229b6c Update support for boot_sound kernel patch 2024-03-10 20:53:03 +13:00
Luke D. Jones 0fac33a8ff Update pipeline 2024-03-09 23:49:42 +13:00
Luke D. Jones b0da062577 Clean up debug info 2024-03-09 23:30:15 +13:00
Luke D. Jones ca41bd59de Begin implmenting keyboard power states 2024-03-09 23:18:30 +13:00
Luke D. Jones efcad3f6f9 Small colour correction 2024-03-06 22:41:55 +13:00
Luke D. Jones fa2255cbaf Atempt better aura colour mix 2024-03-06 22:35:16 +13:00
Luke D. Jones 02b9bac899 Clean up the tray code 2024-03-04 13:28:19 +13:00
Luke D. Jones a1fcf5023c Force tray process to exit if Quit 2024-03-03 22:41:57 +13:00
Luke D. Jones 2f8ea80e6d Replace shitty gtk tray with betrayer 2024-03-03 22:26:52 +13:00
Luke D. Jones b798cf6a4e Minor adjust to rgb bright slider 2024-03-03 13:30:46 +13:00
Luke D. Jones 3da848d131 Init with colour sliders in approx position 2024-03-03 12:57:45 +13:00
Luke D. Jones a88c33c201 MOrE 2024-03-02 23:49:11 +13:00
Luke D. Jones 7b0f037cba Trying different strategies for non-blocking UI 2024-02-25 23:21:11 +13:00
Luke D. Jones 91b1456d06 Formulate slint patterns 2024-02-25 19:24:20 +13:00
Luke D. Jones c3b02a2bb0 Fix the IPC 2024-02-25 13:09:13 +13:00
Luke D. Jones 8e4b7d53f4 More updating to zbus 4.0.1 2024-02-24 21:56:52 +13:00
Luke D. Jones a44145f487 Update to zbus 4.0.1 2024-02-24 21:56:29 +13:00
Luke D. Jones bb7b3a81fb Bump version 2024-02-24 21:50:52 +13:00
Luke D. Jones 19607d71c3 Prep 5.0.8 release 2024-02-24 17:09:24 +13:00
Luke D. Jones 96f281d789 Remove the use of bytes in zbus signatures 2024-02-23 21:50:53 +13:00
Luke D. Jones 7613eded95 Sane defaults for asusd config 2024-02-23 14:40:00 +13:00
Luke D. Jones 50eccd2b1d Formatting and fixes 2024-02-23 12:36:16 +13:00
Luke Jones ba54007102 Merge branch 'bugfix/persistent-theme' into 'main'
Reintroduce persistent dark/light mode

See merge request asus-linux/asusctl!180
2024-02-19 19:44:59 +00:00
Filip Binkiewicz a028f5375f Reintroduce persistent dark/light mode 2024-02-19 19:27:56 +00:00
Luke Jones 9ec02cd727 Merge branch 'dearner-main-patch-22870' into 'main'
Added G814JZ to aura_support.ron (uses G814JI keymap)

See merge request asus-linux/asusctl!179
2024-02-14 01:40:26 +00:00
Chris Dearner 4b46ece09a Added G814JZ to aura_support.ron (uses G814JI keymap) 2024-02-05 12:49:49 +00:00
Luke D. Jones 086bbd0908 Fix the broken pipe error 2024-02-02 23:26:41 +13:00
Luke D. Jones c94eaa473e Update TS bindings 2024-01-24 22:37:10 +13:00
Luke D. Jones b1b809834b Reload and apply settings if config file externally changed 2024-01-24 12:19:34 +13:00
Luke D. Jones 84183288ec Fix inotify watch failing thanks to vim idiocy 2024-01-23 22:44:20 +13:00
Luke D. Jones 86cbef83b6 Reload asusd.ron if changed 2024-01-22 21:54:19 +13:00
Luke D. Jones 006fb632c4 Doc and feature fixes 2024-01-22 19:33:40 +13:00
Luke D. Jones e3636ed8ce Update smithay-client-toolkit 2024-01-22 12:06:42 +13:00
Luke D. Jones cfd207f251 Remove async-trait crate and set min rustc 1.75 2024-01-15 18:22:41 +13:00
Luke D. Jones d4c68546e7 Added ability to change what EPP is linked with each throttle profile 2024-01-15 18:00:27 +13:00
Luke D. Jones 6f4a7e16dc Fixes to RCC 2024-01-05 14:21:31 +13:00
Luke D. Jones f64253d633 Various bugfixes 2024-01-05 13:53:57 +13:00
Luke D. Jones 124c17aadc Add default issue template 2024-01-04 14:30:11 +13:00
Luke D. Jones ab40f9fcbf Add FX705D led support 2024-01-04 09:23:37 +13:00
Luke D. Jones 5cdfa5a8d4 Fix to suspend process in anime thread to let custom anims run on wake 2023-12-27 11:24:39 +13:00
Luke D. Jones ce870cd5ed Revert egui update due to a lot of issues arising from window closing 2023-12-27 10:13:26 +13:00
Luke D. Jones 4541d2e1ba Update dbus introspection 2023-12-26 11:56:47 +13:00
Luke D. Jones b525411fd3 Minor fixes in asusctl 2023-12-25 21:24:05 +13:00
Luke D. Jones a867496f13 Re-enable ROGCC fan curves 2023-12-24 10:30:33 +13:00
Luke D. Jones f421b8ee3b Fix to apply led effect in rogcc 2023-12-23 21:45:19 +13:00
Luke D. Jones 82780feb4b Update readme 2023-12-23 10:37:46 +13:00
Luke D. Jones 1e5443e206 Bugfix release 2023-12-22 11:39:17 +13:00
Luke D. Jones 027a591d26 Add cargo-vendor-filterer to pipeline 2023-12-17 21:44:33 +13:00
194 changed files with 12900 additions and 15376 deletions
+6
View File
@@ -2,11 +2,17 @@
set -e set -e
echo 'find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po'
find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po
echo '+cargo +nightly fmt --all -- --check' echo '+cargo +nightly fmt --all -- --check'
cargo +nightly fmt --all -- --check cargo +nightly fmt --all -- --check
echo '+cargo clippy --all -- -D warnings' echo '+cargo clippy --all -- -D warnings'
cargo clippy --all -- -D warnings cargo clippy --all -- -D warnings
echo '+cargo test --all' echo '+cargo test --all'
cargo test --all cargo test --all
echo '+cargo cranky' echo '+cargo cranky'
cargo cranky cargo cranky
+4 -3
View File
@@ -17,7 +17,7 @@ image: rust:latest
- target/release/.cargo-lock - target/release/.cargo-lock
before_script: before_script:
- apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep llvm clang libclang-dev libsdl2-dev libsdl2-gfx-dev - apt-get update -qq && apt-get install -y -qq libinput-dev libseat-dev libudev-dev libgtk-3-dev grep llvm clang libclang-dev libsdl2-dev libsdl2-gfx-dev
stages: stages:
- format - format
@@ -59,11 +59,12 @@ release:
- tags - tags
<<: *rust_cache <<: *rust_cache
script: script:
- cargo install cargo-vendor-filterer
- make && make vendor - make && make vendor
artifacts: artifacts:
paths: paths:
- vendor_asusctl*.tar.xz - vendor_asusctl*.tar.xz
- cargo-config - cargo-config
pages: pages:
stage: deploy stage: deploy
+32
View File
@@ -0,0 +1,32 @@
## Issue description
(** I can not support distros which are outdated by default. This includes Ubuntu at least 50% of the time, and definitely includes Mint. **)
(Summarize the bug encountered)
## Steps to reproduce
(How can the issue be reproduced)
## What is the current bug behavior?
(What actually happens)
## What is the expected correct behavior?
(What you should see instead)
## Relevant logs and/or screenshots
(run `journalctl -b -u asusd > ~/asusd.log` and attach `~/asusd.log`)
(Paste any relevant logs - use code blocks (```) to format console output, logs, and code, as
it's very hard to read otherwise.)
## System details
- Distro:
- Kernel: (`uname -r`)
- Desktop:
- Xorg or wayland: ??
/label ~bug ~reproducable ~needs-investigation
+369 -56
View File
File diff suppressed because it is too large Load Diff
Generated
+2333 -1417
View File
File diff suppressed because it is too large Load Diff
+53 -15
View File
@@ -1,25 +1,57 @@
[workspace] [workspace]
members = ["asusctl", "asusd", "asusd-user", "config-traits", "cpuctl", "dmi-id", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center", "simulators"] members = [
default-members = ["asusctl", "asusd", "asusd-user", "cpuctl", "rog-control-center"] "asusctl",
"asusd",
"asusd-user",
"config-traits",
"cpuctl",
"dmi-id",
"rog-platform",
"rog-dbus",
"rog-anime",
"rog-aura",
"rog-profiles",
"rog-control-center",
"rog-slash",
"simulators",
]
default-members = [
"asusctl",
"asusd",
"asusd-user",
"cpuctl",
"rog-control-center",
]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "5.0.2" version = "6.0.2"
rust-version = "1.77"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asusctl"
homepage = "https://gitlab.com/asus-linux/asusctl"
description = "Laptop feature control for ASUS ROG laptops and others"
edition = "2021"
[workspace.dependencies] [workspace.dependencies]
async-trait = "^0.1" tokio = { version = "^1.36.0", default-features = false, features = [
tokio = { version = "^1.23.0", default-features = false, features = ["macros", "sync"]} "macros",
"sync",
"time",
"rt-multi-thread",
] }
concat-idents = "^1.1" concat-idents = "^1.1"
dirs = "^4.0" dirs = "^4.0"
smol = "^1.3" smol = "^1.3"
mio = "0.8.11"
zbus = "~3.14.1" zbus = "4.1"
logind-zbus = { version = "~3.1" } #, default-features = false, features = ["non_blocking"] } logind-zbus = { version = "4.0.2" } #, default-features = false, features = ["non_blocking"] }
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
serde_json = "^1.0"
toml = "^0.5.10"
ron = "*" ron = "*"
typeshare = "1.0.0" typeshare = "1.0.0"
@@ -28,7 +60,7 @@ env_logger = "^0.10.0"
glam = { version = "^0.22", features = ["serde"] } glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8" gumdrop = "^0.8"
udev = "^0.7" udev = { version = "^0.8", features = ["mio"] }
rusb = "^0.9" rusb = "^0.9"
inotify = "^0.10.0" inotify = "^0.10.0"
@@ -37,9 +69,11 @@ pix = "^0.13"
tinybmp = "^0.4.0" tinybmp = "^0.4.0"
gif = "^0.12.0" gif = "^0.12.0"
versions = "4.1" versions = "6.2"
notify-rust = { git = "https://github.com/flukejones/notify-rust.git", default-features = false, features = ["z"] } notify-rust = { git = "https://github.com/flukejones/notify-rust.git", rev = "54176413b81189a3e4edbdc20a0b4f7e2e35c063", default-features = false, features = [
"z",
] }
[profile.release] [profile.release]
# thin = 57s, asusd = 9.0M # thin = 57s, asusd = 9.0M
@@ -48,11 +82,15 @@ lto = "fat"
debug = false debug = false
opt-level = 3 opt-level = 3
panic = "abort" panic = "abort"
#codegen-units = 1 codegen-units = 1
[profile.dev] [profile.dev]
debug = true
opt-level = 1 opt-level = 1
codegen-units = 16
[profile.dev.package."*"]
opt-level = 1
codegen-units = 16
[profile.bench] [profile.bench]
debug = false debug = false
@@ -61,4 +99,4 @@ opt-level = 3
[workspace.dependencies.cargo-husky] [workspace.dependencies.cargo-husky]
version = "1" version = "1"
default-features = false default-features = false
features = ["user-hooks"] features = ["user-hooks"]
+22 -15
View File
@@ -1,5 +1,7 @@
# asusctrl manual # asusctrl manual
**NOTE:** this manual is in need of an update in some places. If you find issues please file issue reports.
`asusd` is a utility for Linux to control many aspects of various ASUS laptops `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. but can also be used with non-asus laptops with reduced features.
@@ -8,11 +10,10 @@ but can also be used with non-asus laptops with reduced features.
- `asusd`: The main system daemon. It is autostarted by a udev rule and systemd unit. - `asusd`: The main system daemon. It is autostarted by a udev rule and systemd unit.
- `asusd-user`: The user level daemon. Currently will run an anime sequence, with RGB keyboard sequences soon. - `asusd-user`: The user level daemon. Currently will run an anime sequence, with RGB keyboard sequences soon.
- `asusctl`: The CLI for interacting with the system daemon - `asusctl`: The CLI for interacting with the system daemon
- `asus-notify`: A notification daemon with a user systemd unit that can be enabled.
## `asusd` ## `asusd`
`asusd` is the main system-level daemon which will control/load/save various settings in a safe way for the user, along with exposing a *safe* dbus interface for these interactions. This section covers only the daemon plus the various configuration file options. `asusd` is the main system-level daemon which will control/load/save various settings in a safe way for the user, along with exposing a _safe_ dbus interface for these interactions. This section covers only the daemon plus the various configuration file options.
The functionality that `asusd` exposes is: The functionality that `asusd` exposes is:
@@ -56,6 +57,7 @@ Almost all modern ASUS laptops have charging limit control now. This can be cont
```json ```json
"bat_charge_limit": 80, "bat_charge_limit": 80,
``` ```
where the number is a percentage. where the number is a percentage.
### Bios control ### Bios control
@@ -63,7 +65,7 @@ where the number is a percentage.
Some options that you find in Armory Crate are available under this controller, so far there is: Some options that you find in Armory Crate are available under this controller, so far there is:
- POST sound: this is the sound you hear on bios boot post - POST sound: this is the sound you hear on bios boot post
- GPU MUX: this controls if the dGPU is the *only* GPU, making it the main GPU and disabling the iGPU - GPU MUX: this controls if the dGPU is the _only_ GPU, making it the main GPU and disabling the iGPU
These options are not written to the config file as they are stored in efivars. The only way to change these is to use the exposed safe dbus methods, or use the `asusctl` CLI tool. These options are not written to the config file as they are stored in efivars. The only way to change these is to use the exposed safe dbus methods, or use the `asusctl` CLI tool.
@@ -72,6 +74,7 @@ These options are not written to the config file as they are stored in efivars.
asusctl can support setting a power profile via platform_profile drivers. This requires [power-profiles-daemon](https://gitlab.freedesktop.org/hadess/power-profiles-daemon) v0.10.0 minimum. It also requires the kernel patch for platform_profile support to be applied form [here](https://lkml.org/lkml/2021/8/18/1022) - this patch is merged to 5.15 kernel upstream. asusctl can support setting a power profile via platform_profile drivers. This requires [power-profiles-daemon](https://gitlab.freedesktop.org/hadess/power-profiles-daemon) v0.10.0 minimum. It also requires the kernel patch for platform_profile support to be applied form [here](https://lkml.org/lkml/2021/8/18/1022) - this patch is merged to 5.15 kernel upstream.
A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n` to cycle through the 3 profiles: A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n` to cycle through the 3 profiles:
1. Balanced 1. Balanced
2. Performance 2. Performance
3. Quiet 3. Quiet
@@ -97,7 +100,7 @@ There is one more controller; the support controller. The sole pupose of this co
## asusd-user ## asusd-user
`asusd-user` is a usermode daemon. The intended purpose is to provide a method for users to run there own custom per-key keyboard effects and modes, AniMe sequences, and possibly their own profiles - all without overwriting the *base* system config. As such some parts of the system daemon will migrate to the user daemon over time with the expectation that the Linux system runs both. `asusd-user` is a usermode daemon. The intended purpose is to provide a method for users to run there own custom per-key keyboard effects and modes, AniMe sequences, and possibly their own profiles - all without overwriting the _base_ system config. As such some parts of the system daemon will migrate to the user daemon over time with the expectation that the Linux system runs both.
As of now only AniMe is active in this with configuration in `~/.config/rog/`. On first run defaults are created that are intended to work as examples. As of now only AniMe is active in this with configuration in `~/.config/rog/`. On first run defaults are created that are intended to work as examples.
@@ -177,6 +180,7 @@ An Aura config itself is a file with contents:
``` ```
If your laptop supports multizone, `"led"` can also be `"Zone": <one of the following>` If your laptop supports multizone, `"led"` can also be `"Zone": <one of the following>`
- `SingleZone` // Keyboards with only one zone - `SingleZone` // Keyboards with only one zone
- `ZonedKbLeft` // keyboard left - `ZonedKbLeft` // keyboard left
- `ZonedKbLeftMid` // keyboard left-middle - `ZonedKbLeftMid` // keyboard left-middle
@@ -238,6 +242,7 @@ Each object in the array can be one of:
##### AsusAnimation ##### AsusAnimation
`AsusAnimation` is specifically for running the gif files that Armory Crate comes with. `asusctl` includes all of these in `/usr/share/asusd/anime/asus/` `AsusAnimation` is specifically for running the gif files that Armory Crate comes with. `asusctl` includes all of these in `/usr/share/asusd/anime/asus/`
```json ```json
"AsusAnimation": { "AsusAnimation": {
"file": "<FILE_PATH>", "file": "<FILE_PATH>",
@@ -260,7 +265,7 @@ Virtually the same as `AsusAnimation` but for png files, typically created in th
##### ImageAnimation ##### ImageAnimation
`ImageAnimation` can play *any* gif of any size. `ImageAnimation` can play _any_ gif of any size.
```json ```json
"ImageAnimation": { "ImageAnimation": {
@@ -319,6 +324,7 @@ Must be full path: `"/usr/share/asusd/anime/asus/gaming/Controller.gif"` or `/ho
**<FLOAT>** **<FLOAT>**
A number from 0.0-1.0. A number from 0.0-1.0.
- `brightness`: If it is brightness it is combined with the system daemon global brightness - `brightness`: If it is brightness it is combined with the system daemon global brightness
- `scale`: 1.0 is the original size with lower number shrinking, larger growing - `scale`: 1.0 is the original size with lower number shrinking, larger growing
- `angle`: Rotation angle in radians - `angle`: Rotation angle in radians
@@ -327,6 +333,7 @@ A number from 0.0-1.0.
**<TIME>** **<TIME>**
Time is the length of time to run the gif for: Time is the length of time to run the gif for:
```json ```json
"time": { "time": {
"Time": { "Time": {
@@ -335,17 +342,23 @@ Time is the length of time to run the gif for:
} }
}, },
``` ```
A cycle is how many gif loops to run: A cycle is how many gif loops to run:
```json ```json
"time": { "time": {
"Cycles": 2 "Cycles": 2
}, },
``` ```
`Infinite` means that this gif will never end: `Infinite` means that this gif will never end:
```json ```json
"time": "Infinite", "time": "Infinite",
``` ```
`Fade` allows an image or gif to fade in and out, and remain at max brightness to n time: `Fade` allows an image or gif to fade in and out, and remain at max brightness to n time:
```json ```json
"time": { "time": {
"Fade": { "Fade": {
@@ -364,6 +377,7 @@ A cycle is how many gif loops to run:
} }
}, },
``` ```
`show_for` can be `null`, if it is `null` then the `show_for` becomes `gif_time_length - fade_in - fade_out`. `show_for` can be `null`, if it is `null` then the `show_for` becomes `gif_time_length - fade_in - fade_out`.
This is period for which the gif or image will be max brightness (as set). This is period for which the gif or image will be max brightness (as set).
@@ -404,26 +418,19 @@ asusctl <command> <subcommand> --help
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of: To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next** **Next**
``` ```
asusctl led-mode -n asusctl led-mode -n
``` ```
**Previous** **Previous**
``` ```
asusctl led-mode -p asusctl led-mode -p
``` ```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`. To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
can enable the user service to get basic notifications when something changes.
```
systemctl --user enable asus-notify.service
systemctl --user start asus-notify.service
```
# License & Trademarks # License & Trademarks
Mozilla Public License 2 (MPL-2.0) Mozilla Public License 2 (MPL-2.0)
+2 -8
View File
@@ -123,14 +123,8 @@ bindings:
typeshare ./rog-profiles/src/ --lang=typescript --output-file=bindings/ts/profiles.ts typeshare ./rog-profiles/src/ --lang=typescript --output-file=bindings/ts/profiles.ts
typeshare ./rog-platform/src/ --lang=typescript --output-file=bindings/ts/platform.ts typeshare ./rog-platform/src/ --lang=typescript --output-file=bindings/ts/platform.ts
introspect: translate:
gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Platform -x > bindings/dbus-xml/org-asuslinux-platform-4.xml find -name \*.slint | xargs slint-tr-extractor -o rog-control-center/translations/en/rog-control-center.po
gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Aura -x > bindings/dbus-xml/org-asuslinux-aura-4.xml
gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/Anime -x > bindings/dbus-xml/org-asuslinux-anime-4.xml
gdbus introspect --system -d org.asuslinux.Daemon -o /org/asuslinux/FanCurves -x > bindings/dbus-xml/org-asuslinux-fan-curves-4.xml
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Introspectable"]' bindings/dbus-xml/org-asuslinux-*
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Properties"]' bindings/dbus-xml/org-asuslinux-*
xmlstarlet ed -L -O -d '//interface[@name="org.freedesktop.DBus.Peer"]' bindings/dbus-xml/org-asuslinux-*
build: build:
ifeq ($(VENDORED),1) ifeq ($(VENDORED),1)
+46 -50
View File
@@ -2,7 +2,7 @@
[Become a Patron!](https://www.patreon.com/bePatron?u=7602281) - [Asus Linux Website](https://asus-linux.org/) [Become a Patron!](https://www.patreon.com/bePatron?u=7602281) - [Asus Linux Website](https://asus-linux.org/)
**WARNING:** Many features are developed in tandem with kernel patches. If you see a feature is missing you either need a patched kernel, or v6.1 which has all my work merged upstream. **WARNING:** Many features are developed in tandem with kernel patches. If you see a feature is missing you either need a patched kernel or latest release.
`asusd` is a utility for Linux to control many aspects of various ASUS laptops `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. but can also be used with non-asus laptops with reduced features.
@@ -11,27 +11,29 @@ Now includes a GUI, `rog-control-center`.
## Kernel support ## Kernel support
**The minimum supported kernel version is 5.17** **The minimum supported kernel version is 6.10**, which will contain the patches from [here](https://lore.kernel.org/platform-driver-x86/20240404001652.86207-1-luke@ljones.dev/). This is especially required for 2023+ devices and possibly some lat 2022 devices.
**For TUF laptops, the minimum supported kernel version is 6.1** Z13 devices will need [these](https://lore.kernel.org/linux-input/20240416090402.31057-1-luke@ljones.dev/T/#t)
## Goals ## Goals
1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes. The main goal of this work is to provide a safe and easy to use abstraction over various laptop features via DBUS, and to provide some helpful defaults and other behaviour such as toggling throttle/profile on AC/battery change.
2. Enable third-party apps to use the above with dbus methods
3. To make the above as easy as possible for new users
4. Respect the users resources: be small, light, and fast
Point 3 means that the list of supported distros is very narrow - fedora is explicitly 1. Provide safe dbus interface
supported. All other distros are *not* supported (while asusd might still run fine on them). 2. Respect the users resources: be small, light, and fast
For best support use fedora 36+ Workstation.
Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way
a system-level daemon should. a system-level daemon should. Languages such as JS and python should never be used for system level daemons (please stop).
## Keyboard LEDs
The level of support for laptops is dependent on folks submitting data to include in [`./rog-aura/data/layouts/aura_support.ron`](./rog-aura/data/layouts/aura_support.ron), typically installed in `/usr/share/asusd/aura_support.ron`. This is because the controller used for keyboards and LEDs is used across many years and many laptop models, all with different firmware configurations - the only way to track this is with the file mentioned above. Why not just enable all by default? Because it confuses people.
See the [rog-aura readme](./rog-aura/README.md) for more details.
## Discord ## Discord
[Discord server link](https://discord.gg/WTHnqabm) [![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/z8y99XqPb7)
## SUPPORTED LAPTOPS ## SUPPORTED LAPTOPS
@@ -42,54 +44,42 @@ to this:
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
``` ```
or
```
Bus 003 Device 002: ID 0b05:19b6 ASUSTek Computer, Inc. [unknown]
```
then it may work without tweaks. Technically all other functions except the LED then it may work without tweaks. Technically all other functions except the LED
and AniMe parts should work regardless of your latop make. and AniMe parts should work regardless of your latop make.
## Implemented ## Implemented
- [X] System daemon The list is a bit outdated as many features have been enabled in the Linux kernel with upstream patches and then supported in asusctl suite.
- [X] GUI app (includes tray and notifications)
- [X] Setting/modifying built-in LED modes - [x] System daemon
- [X] Per-key LED setting - [x] GUI app (includes tray and notifications)
- [X] Fancy LED modes (See examples) (currently being reworked) - [x] Setting/modifying built-in LED modes
- [X] AniMatrix display on G14 and M16 models that include it - [x] Per-key LED setting
- [X] Set battery charge limit (with kernel supporting this) - [x] Fancy LED modes (See examples) (currently being reworked)
- [X] Fan curve control on supported laptops (G14/G15, some TUF like FA507) - [x] AniMatrix display on G14 and M16 models that include it
- [X] Toggle bios setting for boot/POST sound - [x] Set battery charge limit (with kernel supporting this)
- [X] Toggle GPU MUX (g-sync, or called MUX on 2022+ laptops) - [x] Fan curve control on supported laptops (G14/G15, some TUF like FA507)
- [x] Toggle bios setting for boot/POST sound
- [x] Toggle GPU MUX (g-sync, or called MUX on 2022+ laptops)
# GUI # GUI
A gui is now in the repo - ROG Control Center. At this time it is still a WIP, but it has almost all features in place already. A gui is now in the repo - ROG Control Center. At this time it is still a WIP, but it has almost all features in place already.
![](/extra/system.png)
![](/extra/fan-curves.png)
![](/extra/keyboard.png)
# BUILDING # BUILDING
Requirements are rust >= 1.57 installed from rustup.io if the distro provided version is too old, and `make`. Rust and cargo are required, they can be installed from [rustup.rs](https://rustup.rs/) or from the distro repos if newer than 1.75.
**Ubuntu (unsuported):**
apt install libgtk-3-dev libpango1.0-dev libgdk-pixbuf-2.0-dev libglib2.0-dev cmake libclang-dev libudev-dev libayatana-appindicator3-1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
make
sudo make install
**popos (unsuported):**
sudo apt install cmake libclang-dev libudev-dev libgtk-3-dev libclang-dev libglib2.0-dev libatkmm-1.6-dev libpangomm-1.4-dev librust-gdk-pixbuf-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
make
sudo make install
**fedora:** **fedora:**
dnf install cmake clang-devel systemd-devel glib2-devel cairo-devel atkmm-devel pangomm-devel gdk-pixbuf2-devel gtk3-devel libappindicator-gtk3 dnf install cmake clang-devel libinput-devel libseat-devel libgbm-devel libxkbcommon-devel systemd-devel \
libdrm-devel expat-devel pcre2-devel libzstd-devel libappindicator-gtk3
make make
sudo make install sudo make install
@@ -98,28 +88,34 @@ Requirements are rust >= 1.57 installed from rustup.io if the distro provided ve
Works with KDE Plasma (without GTK packages) Works with KDE Plasma (without GTK packages)
zypper in -t pattern devel_basis zypper in -t pattern devel_basis
zypper in rustup make cmake systemd-devel clang-devel llvm-devel gdk-pixbuf-devel cairo-devel pango-devel freetype-devel gtk3-devel libexpat-devel libayatana-indicator3-7 zypper in rustup make cmake libinput-devel libseat-devel libgbm-devel systemd-devel clang-devel llvm-devel gdk-pixbuf-devel cairo-devel pango-devel freetype-devel libexpat-devel libayatana-indicator3-7
make make
sudo make install sudo make install
**Ubuntu, Popos (unsuported):**
instructions removed as outdated
## Installing ## Installing
- Fedora copr = https://copr.fedorainfracloud.org/coprs/lukenukem/asus-linux/ - Fedora copr = https://copr.fedorainfracloud.org/coprs/lukenukem/asus-linux/
- openSUSE = https://download.opensuse.org/repositories/home:/luke_nukem:/asus/ - openSUSE = https://download.opensuse.org/repositories/home:/luke_nukem:/asus/
- Ubuntu = not supported due to packaging woes, but you can build and install on your own.
======= =======
The default init method is to use the udev rule, this ensures that the service is The default init method is to use the udev rule, this ensures that the service is
started when the device is initialised and ready. started when the device is initialised and ready.
You may also need to activate the service for debian install. If running Pop!\_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
## Upgrading
If you are upgrading from a previous installed version, you will need to restart the service or reboot. If you are upgrading from a previous installed version, you will need to restart the service or reboot.
``` ```
$ systemctl daemon-reload && systemctl restart asusd $ systemctl daemon-reload && systemctl restart asusd
``` ```
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
## Uninstalling ## Uninstalling
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`. Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
@@ -136,7 +132,7 @@ Dbus introsepction XML requires with `make introspection` requires `anime_sim` t
## AniMe Matrix simulator ## AniMe Matrix simulator
A simulator using SDL2 can be built using `cargo build --package rog_simulators` and run with `./target/debug/anime_sim`. Once started `asusd` will need restarting to pick it up. If running this sim on a laptop *with* the display, the simulated display will be used instead of the physical display. A simulator using SDL2 can be built using `cargo build --package rog_simulators` and run with `./target/debug/anime_sim`. Once started `asusd` will need restarting to pick it up. If running this sim on a laptop _with_ the display, the simulated display will be used instead of the physical display.
## Supporting more laptops ## Supporting more laptops
+10 -8
View File
@@ -1,12 +1,16 @@
[package] [package]
name = "asusctl" name = "asusctl"
license = "MPL-2.0" license.workspace = true
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2021"
version.workspace = true version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies] [dependencies]
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
rog_slash = { path = "../rog-slash" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
@@ -14,13 +18,11 @@ rog_platform = { path = "../rog-platform" }
asusd = { path = "../asusd" } asusd = { path = "../asusd" }
dmi_id = { path = "../dmi-id" } dmi_id = { path = "../dmi-id" }
ron.workspace = true
gumdrop.workspace = true gumdrop.workspace = true
toml.workspace = true zbus.workspace = true
[dev-dependencies] [dev-dependencies]
gif.workspace = true
tinybmp.workspace = true
glam.workspace = true
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
cargo-husky.workspace = true cargo-husky.workspace = true
+5 -7
View File
@@ -5,10 +5,12 @@ use std::process::exit;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDiagonal, AnimeType}; use rog_anime::{AnimeDiagonal, AnimeType};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if args.len() != 3 { if args.len() != 3 {
@@ -26,11 +28,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let anime_type = get_anime_type()?; let anime_type = get_anime_type()?;
client proxy.write(matrix.into_data_buffer(anime_type)?).unwrap();
.proxies()
.anime()
.write(matrix.into_data_buffer(anime_type)?)
.unwrap();
Ok(()) Ok(())
} }
+5 -5
View File
@@ -3,7 +3,8 @@ use std::time::Duration;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDiagonal, AnimeType}; use rog_anime::{AnimeDiagonal, AnimeType};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
@@ -11,7 +12,8 @@ use rog_dbus::RogDbusClientBlocking;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
for step in (2..50).rev() { for step in (2..50).rev() {
let mut matrix = AnimeDiagonal::new(AnimeType::GA401, None); let mut matrix = AnimeDiagonal::new(AnimeType::GA401, None);
@@ -28,9 +30,7 @@ fn main() {
} }
let anime_type = get_anime_type().unwrap(); let anime_type = get_anime_type().unwrap();
client proxy
.proxies()
.anime()
.write(matrix.into_data_buffer(anime_type).unwrap()) .write(matrix.into_data_buffer(anime_type).unwrap())
.unwrap(); .unwrap();
sleep(Duration::from_millis(300)); sleep(Duration::from_millis(300));
+5 -7
View File
@@ -4,10 +4,12 @@ use std::thread::sleep;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{ActionData, ActionLoader, Sequences}; use rog_anime::{ActionData, ActionLoader, Sequences};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() { fn main() {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if args.len() != 3 { if args.len() != 3 {
@@ -33,11 +35,7 @@ fn main() {
for action in seq.iter() { for action in seq.iter() {
if let ActionData::Animation(frames) = action { if let ActionData::Animation(frames) = action {
for frame in frames.frames() { for frame in frames.frames() {
client proxy.write(frame.frame().clone()).unwrap();
.proxies()
.anime()
.write(frame.frame().clone())
.unwrap();
sleep(frame.delay()); sleep(frame.delay());
} }
} }
+6 -3
View File
@@ -2,7 +2,8 @@ use std::convert::TryFrom;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeGrid}; use rog_anime::{AnimeDataBuffer, AnimeGrid};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
@@ -10,7 +11,9 @@ use rog_dbus::RogDbusClientBlocking;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let anime_type = get_anime_type().unwrap(); let anime_type = get_anime_type().unwrap();
let mut matrix = AnimeGrid::new(anime_type); let mut matrix = AnimeGrid::new(anime_type);
let tmp = matrix.get_mut(); let tmp = matrix.get_mut();
@@ -43,5 +46,5 @@ fn main() {
let matrix = <AnimeDataBuffer>::try_from(matrix).unwrap(); let matrix = <AnimeDataBuffer>::try_from(matrix).unwrap();
client.proxies().anime().write(matrix).unwrap(); proxy.write(matrix).unwrap();
} }
+5 -3
View File
@@ -1,12 +1,14 @@
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::AnimeDataBuffer; use rog_anime::AnimeDataBuffer;
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
fn main() { fn main() {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let anime_type = get_anime_type().unwrap(); let anime_type = get_anime_type().unwrap();
let mut matrix = AnimeDataBuffer::new(anime_type); let mut matrix = AnimeDataBuffer::new(anime_type);
matrix.data_mut()[1] = 100; // start = 1 matrix.data_mut()[1] = 100; // start = 1
@@ -127,5 +129,5 @@ fn main() {
matrix.data_mut()[1244] = 100; // end matrix.data_mut()[1244] = 100; // end
println!("{:?}", &matrix); println!("{:?}", &matrix);
client.proxies().anime().write(matrix).unwrap(); proxy.write(matrix).unwrap();
} }
+5 -7
View File
@@ -6,10 +6,12 @@ use std::process::exit;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2}; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if args.len() != 7 { if args.len() != 7 {
@@ -31,11 +33,7 @@ fn main() -> Result<(), Box<dyn Error>> {
anime_type, anime_type,
)?; )?;
client proxy.write(<AnimeDataBuffer>::try_from(&matrix)?).unwrap();
.proxies()
.anime()
.write(<AnimeDataBuffer>::try_from(&matrix)?)
.unwrap();
Ok(()) Ok(())
} }
+5 -7
View File
@@ -9,10 +9,12 @@ use std::time::Duration;
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2}; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if args.len() != 7 { if args.len() != 7 {
@@ -41,11 +43,7 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
matrix.update(); matrix.update();
client proxy.write(<AnimeDataBuffer>::try_from(&matrix)?).unwrap();
.proxies()
.anime()
.write(<AnimeDataBuffer>::try_from(&matrix)?)
.unwrap();
sleep(Duration::from_micros(500)); sleep(Duration::from_micros(500));
} }
} }
+6 -5
View File
@@ -1,16 +1,17 @@
//! Using a combination of key-colour array plus a key layout to generate //! Using a combination of key-colour array plus a key layout to generate
//! outputs. //! outputs.
use rog_aura::advanced::LedCode;
use rog_aura::effects::{AdvancedEffects, Effect}; use rog_aura::effects::{AdvancedEffects, Effect};
use rog_aura::layouts::KeyLayout; use rog_aura::keyboard::{KeyLayout, LedCode};
use rog_aura::Colour; use rog_aura::Colour;
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_aura::AuraProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let layout = KeyLayout::default_layout(); let layout = KeyLayout::default_layout();
let (client, _) = RogDbusClientBlocking::new().unwrap(); let conn = Connection::system().unwrap();
let proxy = AuraProxyBlocking::new(&conn).unwrap();
let mut seq = AdvancedEffects::new(true); let mut seq = AdvancedEffects::new(true);
@@ -62,7 +63,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
seq.next_state(&layout); seq.next_state(&layout);
let packets = seq.create_packets(); let packets = seq.create_packets();
client.proxies().aura().direct_addressing_raw(packets)?; proxy.direct_addressing_raw(packets)?;
std::thread::sleep(std::time::Duration::from_millis(33)); std::thread::sleep(std::time::Duration::from_millis(33));
} }
} }
+17 -16
View File
@@ -10,10 +10,10 @@ pub struct LedPowerCommand1 {
pub help: bool, pub help: bool,
#[options(meta = "", help = "Control if LEDs enabled while awake <true/false>")] #[options(meta = "", help = "Control if LEDs enabled while awake <true/false>")]
pub awake: Option<bool>, pub awake: Option<bool>,
#[options(meta = "", help = "Use with awake option <true/false>")] #[options(help = "Use with awake option, if excluded defaults to false")]
pub keyboard: Option<bool>, pub keyboard: bool,
#[options(meta = "", help = "Use with awake option <true/false>")] #[options(help = "Use with awake option, if excluded defaults to false")]
pub lightbar: Option<bool>, pub lightbar: bool,
#[options(meta = "", help = "Control boot animations <true/false>")] #[options(meta = "", help = "Control boot animations <true/false>")]
pub boot: Option<bool>, pub boot: Option<bool>,
#[options(meta = "", help = "Control suspend animations <true/false>")] #[options(meta = "", help = "Control suspend animations <true/false>")]
@@ -87,6 +87,7 @@ impl FromStr for LedBrightness {
} }
} }
} }
#[allow(clippy::to_string_trait_impl)]
impl ToString for LedBrightness { impl ToString for LedBrightness {
fn to_string(&self) -> String { fn to_string(&self) -> String {
let s = match self.level { let s = match self.level {
@@ -214,29 +215,29 @@ pub struct MultiColourSpeed {
#[derive(Options)] #[derive(Options)]
pub enum SetAuraBuiltin { pub enum SetAuraBuiltin {
#[options(help = "set a single static colour")] #[options(help = "set a single static colour")]
Static(SingleColour), Static(SingleColour), // 0
#[options(help = "pulse between one or two colours")] #[options(help = "pulse between one or two colours")]
Breathe(TwoColourSpeed), Breathe(TwoColourSpeed), // 1
#[options(help = "strobe through all colours")] #[options(help = "strobe through all colours")]
Strobe(SingleSpeed), Strobe(SingleSpeed), // 2
#[options(help = "rainbow cycling in one of four directions")] #[options(help = "rainbow cycling in one of four directions")]
Rainbow(SingleSpeedDirection), Rainbow(SingleSpeedDirection), // 3
#[options(help = "rain pattern mimicking raindrops")] #[options(help = "rain pattern mimicking raindrops")]
Stars(TwoColourSpeed), Stars(TwoColourSpeed), // 4
#[options(help = "rain pattern of three preset colours")] #[options(help = "rain pattern of three preset colours")]
Rain(SingleSpeed), Rain(SingleSpeed), // 5
#[options(help = "pressed keys are highlighted to fade")] #[options(help = "pressed keys are highlighted to fade")]
Highlight(SingleColourSpeed), Highlight(SingleColourSpeed), // 6
#[options(help = "pressed keys generate horizontal laser")] #[options(help = "pressed keys generate horizontal laser")]
Laser(SingleColourSpeed), Laser(SingleColourSpeed), // 7
#[options(help = "pressed keys ripple outwards like a splash")] #[options(help = "pressed keys ripple outwards like a splash")]
Ripple(SingleColourSpeed), Ripple(SingleColourSpeed), // 8
#[options(help = "set a rapid pulse")] #[options(help = "set a rapid pulse")]
Pulse(SingleColour), Pulse(SingleColour), // 10
#[options(help = "set a vertical line zooming from left")] #[options(help = "set a vertical line zooming from left")]
Comet(SingleColour), Comet(SingleColour), // 11
#[options(help = "set a wide vertical line zooming from left")] #[options(help = "set a wide vertical line zooming from left")]
Flash(SingleColour), Flash(SingleColour), // 12
} }
impl Default for SetAuraBuiltin { impl Default for SetAuraBuiltin {
+5 -2
View File
@@ -1,9 +1,10 @@
use gumdrop::Options; use gumdrop::Options;
use rog_platform::platform::PlatformPolicy; use rog_platform::platform::ThrottlePolicy;
use crate::anime_cli::AnimeCommand; use crate::anime_cli::AnimeCommand;
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin}; use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
use crate::fan_curve_cli::FanCurveCommand; use crate::fan_curve_cli::FanCurveCommand;
use crate::slash_cli::SlashCommand;
#[derive(Default, Options)] #[derive(Default, Options)]
pub struct CliStart { pub struct CliStart {
@@ -41,6 +42,8 @@ pub enum CliCommand {
Graphics(GraphicsCommand), Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")] #[options(name = "anime", help = "Manage AniMe Matrix")]
Anime(AnimeCommand), Anime(AnimeCommand),
#[options(name = "slash", help = "Manage Slash Ledbar")]
Slash(SlashCommand),
#[options(help = "Change bios settings")] #[options(help = "Change bios settings")]
Bios(BiosCommand), Bios(BiosCommand),
} }
@@ -60,7 +63,7 @@ pub struct ProfileCommand {
pub profile_get: bool, pub profile_get: bool,
#[options(meta = "", help = "set the active profile")] #[options(meta = "", help = "set the active profile")]
pub profile_set: Option<PlatformPolicy>, pub profile_set: Option<ThrottlePolicy>,
} }
#[derive(Options)] #[derive(Options)]
+2 -2
View File
@@ -1,5 +1,5 @@
use gumdrop::Options; use gumdrop::Options;
use rog_platform::platform::PlatformPolicy; use rog_platform::platform::ThrottlePolicy;
use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::FanCurvePU; use rog_profiles::FanCurvePU;
@@ -18,7 +18,7 @@ pub struct FanCurveCommand {
meta = "", meta = "",
help = "profile to modify fan-curve for. Shows data if no options provided" help = "profile to modify fan-curve for. Shows data if no options provided"
)] )]
pub mod_profile: Option<PlatformPolicy>, pub mod_profile: Option<ThrottlePolicy>,
#[options( #[options(
meta = "", meta = "",
+339 -267
View File
@@ -5,7 +5,6 @@ use std::process::Command;
use std::thread::sleep; use std::thread::sleep;
use anime_cli::{AnimeActions, AnimeCommand}; use anime_cli::{AnimeActions, AnimeCommand};
use asusd::ctrl_aura::trait_impls::AURA_ZBUS_NAME;
use asusd::ctrl_fancurves::FAN_CURVE_ZBUS_NAME; use asusd::ctrl_fancurves::FAN_CURVE_ZBUS_NAME;
use aura_cli::{LedPowerCommand1, LedPowerCommand2}; use aura_cli::{LedPowerCommand1, LedPowerCommand2};
use dmi_id::DMIID; use dmi_id::DMIID;
@@ -13,21 +12,28 @@ use fan_curve_cli::FanCurveCommand;
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, Vec2}; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, Vec2};
use rog_aura::power::KbAuraPowerState; use rog_aura::keyboard::{AuraPowerState, LaptopAuraPower};
use rog_aura::usb::{AuraDevRog1, AuraDevTuf, AuraPowerDev}; use rog_aura::{self, AuraDeviceType, AuraEffect, PowerZones};
use rog_aura::{self, AuraEffect}; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_aura::AuraProxyBlocking;
use rog_platform::error::PlatformError; use rog_dbus::zbus_fan_curves::FanCurvesProxyBlocking;
use rog_platform::platform::{GpuMode, PlatformPolicy, Properties}; use rog_dbus::zbus_platform::PlatformProxyBlocking;
use rog_dbus::zbus_slash::SlashProxyBlocking;
use rog_platform::platform::{GpuMode, Properties, ThrottlePolicy};
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
use rog_slash::SlashMode;
use ron::ser::PrettyConfig;
use zbus::blocking::Connection;
use crate::aura_cli::{AuraPowerStates, LedBrightness}; use crate::aura_cli::{AuraPowerStates, LedBrightness};
use crate::cli_opts::*; use crate::cli_opts::*;
use crate::slash_cli::SlashCommand;
mod anime_cli; mod anime_cli;
mod aura_cli; mod aura_cli;
mod cli_opts; mod cli_opts;
mod fan_curve_cli; mod fan_curve_cli;
mod slash_cli;
fn main() { fn main() {
let args: Vec<String> = args().skip(1).collect(); let args: Vec<String> = args().skip(1).collect();
@@ -45,13 +51,21 @@ fn main() {
} }
}; };
if let Ok((dbus, _)) = RogDbusClientBlocking::new().map_err(|e| { let conn = Connection::system().unwrap();
if let Ok(platform_proxy) = PlatformProxyBlocking::new(&conn).map_err(|e| {
check_service("asusd"); check_service("asusd");
println!("\nError: {e}\n"); println!("\nError: {e}\n");
print_info(); print_info();
}) { }) {
let supported_properties = dbus.proxies().platform().supported_properties().unwrap(); let self_version = env!("CARGO_PKG_VERSION");
let supported_interfaces = dbus.proxies().platform().supported_interfaces().unwrap(); let asusd_version = platform_proxy.version().unwrap();
if asusd_version != self_version {
println!("Version mismatch: asusctl = {self_version}, asusd = {asusd_version}");
return;
}
let supported_properties = platform_proxy.supported_properties().unwrap();
let supported_interfaces = platform_proxy.supported_interfaces().unwrap();
if parsed.version { if parsed.version {
println!("asusctl v{}", env!("CARGO_PKG_VERSION")); println!("asusctl v{}", env!("CARGO_PKG_VERSION"));
@@ -59,7 +73,7 @@ fn main() {
print_info(); print_info();
} }
if let Err(err) = do_parsed(&parsed, &supported_interfaces, &supported_properties, &dbus) { if let Err(err) = do_parsed(&parsed, &supported_interfaces, &supported_properties, conn) {
print_error_help(&*err, &supported_interfaces, &supported_properties); print_error_help(&*err, &supported_interfaces, &supported_properties);
} }
} }
@@ -104,23 +118,68 @@ fn check_service(name: &str) -> bool {
false false
} }
fn find_aura_iface() -> Result<Vec<AuraProxyBlocking<'static>>, Box<dyn std::error::Error>> {
let conn = zbus::blocking::Connection::system().unwrap();
let f = zbus::blocking::fdo::ObjectManagerProxy::new(
&conn,
"org.asuslinux.Daemon",
"/org/asuslinux",
)
.unwrap();
let interfaces = f.get_managed_objects().unwrap();
let mut aura_paths = Vec::new();
for v in interfaces.iter() {
// let o: Vec<zbus::names::OwnedInterfaceName> = v.1.keys().map(|e|
// e.to_owned()).collect(); println!("{}, {:?}", v.0, o);
for k in v.1.keys() {
if k.as_str() == "org.asuslinux.Aura" {
println!("Found aura device at {}, {}", v.0, k);
aura_paths.push(v.0.clone());
}
}
}
if aura_paths.len() > 1 {
println!("Multiple aura devices found: {aura_paths:?}");
println!("TODO: enable selection");
}
if !aura_paths.is_empty() {
let mut ctrl = Vec::new();
for path in aura_paths {
ctrl.push(
AuraProxyBlocking::builder(&conn)
.path(path.clone())?
.destination("org.asuslinux.Daemon")?
.build()?,
);
}
return Ok(ctrl);
}
Err("No Aura interface".into())
}
fn do_parsed( fn do_parsed(
parsed: &CliStart, parsed: &CliStart,
supported_interfaces: &[String], supported_interfaces: &[String],
supported_properties: &[Properties], supported_properties: &[Properties],
dbus: &RogDbusClientBlocking<'_>, conn: Connection,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
match &parsed.command { match &parsed.command {
Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, supported_interfaces, mode)?, Some(CliCommand::LedMode(mode)) => handle_led_mode(&find_aura_iface()?, mode)?,
Some(CliCommand::LedPow1(pow)) => handle_led_power1(dbus, supported_interfaces, pow)?, Some(CliCommand::LedPow1(pow)) => handle_led_power1(&find_aura_iface()?, pow)?,
Some(CliCommand::LedPow2(pow)) => handle_led_power2(dbus, supported_interfaces, pow)?, Some(CliCommand::LedPow2(pow)) => handle_led_power2(&find_aura_iface()?, pow)?,
Some(CliCommand::Profile(cmd)) => handle_throttle_profile(dbus, supported_properties, cmd)?, Some(CliCommand::Profile(cmd)) => {
handle_throttle_profile(&conn, supported_properties, cmd)?
}
Some(CliCommand::FanCurve(cmd)) => { Some(CliCommand::FanCurve(cmd)) => {
handle_fan_curve(dbus, supported_interfaces, cmd)?; handle_fan_curve(&conn, supported_interfaces, cmd)?;
} }
Some(CliCommand::Graphics(_)) => do_gfx(), Some(CliCommand::Graphics(_)) => do_gfx(),
Some(CliCommand::Anime(cmd)) => handle_anime(dbus, cmd)?, Some(CliCommand::Anime(cmd)) => handle_anime(&conn, cmd)?,
Some(CliCommand::Bios(cmd)) => handle_platform_properties(dbus, supported_properties, cmd)?, Some(CliCommand::Slash(cmd)) => handle_slash(&conn, cmd)?,
Some(CliCommand::Bios(cmd)) => {
handle_platform_properties(&conn, supported_properties, cmd)?
}
None => { None => {
if (!parsed.show_supported if (!parsed.show_supported
&& parsed.kbd_bright.is_none() && parsed.kbd_bright.is_none()
@@ -132,16 +191,25 @@ fn do_parsed(
println!("{}", CliStart::usage()); println!("{}", CliStart::usage());
println!(); println!();
if let Some(cmdlist) = CliStart::command_list() { if let Some(cmdlist) = CliStart::command_list() {
let dev_type = if let Ok(proxy) = find_aura_iface() {
// TODO: commands on all?
proxy
.first()
.unwrap()
.device_type()
.unwrap_or(AuraDeviceType::Unknown)
} else {
AuraDeviceType::Unknown
};
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
for command in commands.iter().filter(|command| { for command in commands.iter().filter(|command| {
let dev_type = dbus.proxies().aura().device_type().unwrap(); if !dev_type.is_old_laptop()
if !dev_type.is_old_style() && !dev_type.is_tuf_laptop()
&& !dev_type.is_tuf_style()
&& command.trim().starts_with("led-pow-1") && command.trim().starts_with("led-pow-1")
{ {
return false; return false;
} }
if !dev_type.is_new_style() && command.trim().starts_with("led-pow-2") { if !dev_type.is_new_laptop() && command.trim().starts_with("led-pow-2") {
return false; return false;
} }
true true
@@ -158,37 +226,67 @@ fn do_parsed(
} }
if let Some(brightness) = &parsed.kbd_bright { if let Some(brightness) = &parsed.kbd_bright {
match brightness.level() { if let Ok(aura) = find_aura_iface() {
None => { for aura in aura.iter() {
let level = dbus.proxies().aura().brightness()?; match brightness.level() {
println!("Current keyboard led brightness: {level:?}"); None => {
let level = aura.brightness()?;
println!("Current keyboard led brightness: {level:?}");
}
Some(level) => aura.set_brightness(rog_aura::LedBrightness::from(level))?,
}
} }
Some(level) => dbus } else {
.proxies() println!("No aura interface found");
.aura()
.set_brightness(rog_aura::LedBrightness::from(level))?,
} }
} }
if parsed.next_kbd_bright { if parsed.next_kbd_bright {
let brightness = dbus.proxies().aura().brightness()?; if let Ok(aura) = find_aura_iface() {
dbus.proxies().aura().set_brightness(brightness.next())?; for aura in aura.iter() {
let brightness = aura.brightness()?;
aura.set_brightness(brightness.next())?;
}
} else {
println!("No aura interface found");
}
} }
if parsed.prev_kbd_bright { if parsed.prev_kbd_bright {
let brightness = dbus.proxies().aura().brightness()?; if let Ok(aura) = find_aura_iface() {
dbus.proxies().aura().set_brightness(brightness.prev())?; for aura in aura.iter() {
let brightness = aura.brightness()?;
aura.set_brightness(brightness.prev())?;
}
} else {
println!("No aura interface found");
}
} }
// TODO: if parsed.show_supported {
// if parsed.show_supported { println!("Supported Core Functions:\n{:#?}", supported_interfaces);
// println!("Supported laptop functions:\n\n{}", supported); println!(
// } "Supported Platform Properties:\n{:#?}",
supported_properties
);
if let Ok(aura) = find_aura_iface() {
// TODO: multiple RGB check
let bright = aura.first().unwrap().supported_brightness()?;
let modes = aura.first().unwrap().supported_basic_modes()?;
let zones = aura.first().unwrap().supported_basic_zones()?;
let power = aura.first().unwrap().supported_power_zones()?;
println!("Supported Keyboard Brightness:\n{:#?}", bright);
println!("Supported Aura Modes:\n{:#?}", modes);
println!("Supported Aura Zones:\n{:#?}", zones);
println!("Supported Aura Power Zones:\n{:#?}", power);
} else {
println!("No aura interface found");
}
}
if let Some(chg_limit) = parsed.chg_limit { if let Some(chg_limit) = parsed.chg_limit {
dbus.proxies() let proxy = PlatformProxyBlocking::new(&conn)?;
.platform() proxy.set_charge_control_end_threshold(chg_limit)?;
.set_charge_control_end_threshold(chg_limit)?;
} }
Ok(()) Ok(())
@@ -202,10 +300,7 @@ fn do_gfx() {
println!("This command will be removed in future"); println!("This command will be removed in future");
} }
fn handle_anime( fn handle_anime(conn: &Connection, cmd: &AnimeCommand) -> Result<(), Box<dyn std::error::Error>> {
dbus: &RogDbusClientBlocking<'_>,
cmd: &AnimeCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if (cmd.command.is_none() if (cmd.command.is_none()
&& cmd.enable_display.is_none() && cmd.enable_display.is_none()
&& cmd.enable_powersave_anim.is_none() && cmd.enable_powersave_anim.is_none()
@@ -222,23 +317,24 @@ fn handle_anime(
println!("\n{}", lst); println!("\n{}", lst);
} }
} }
let proxy = AnimeProxyBlocking::new(conn)?;
if let Some(enable) = cmd.enable_display { if let Some(enable) = cmd.enable_display {
dbus.proxies().anime().set_enable_display(enable)?; proxy.set_enable_display(enable)?;
} }
if let Some(enable) = cmd.enable_powersave_anim { if let Some(enable) = cmd.enable_powersave_anim {
dbus.proxies().anime().set_builtins_enabled(enable)?; proxy.set_builtins_enabled(enable)?;
} }
if let Some(bright) = cmd.brightness { if let Some(bright) = cmd.brightness {
dbus.proxies().anime().set_brightness(bright)?; proxy.set_brightness(bright)?;
} }
if let Some(enable) = cmd.off_when_lid_closed { if let Some(enable) = cmd.off_when_lid_closed {
dbus.proxies().anime().set_off_when_lid_closed(enable)?; proxy.set_off_when_lid_closed(enable)?;
} }
if let Some(enable) = cmd.off_when_suspended { if let Some(enable) = cmd.off_when_suspended {
dbus.proxies().anime().set_off_when_suspended(enable)?; proxy.set_off_when_suspended(enable)?;
} }
if let Some(enable) = cmd.off_when_unplugged { if let Some(enable) = cmd.off_when_unplugged {
dbus.proxies().anime().set_off_when_unplugged(enable)?; proxy.set_off_when_unplugged(enable)?;
} }
if cmd.off_with_his_head.is_some() { if cmd.off_with_his_head.is_some() {
println!("Did Alice _really_ make it back from Wonderland?"); println!("Did Alice _really_ make it back from Wonderland?");
@@ -254,7 +350,7 @@ fn handle_anime(
if cmd.clear { if cmd.clear {
let data = vec![255u8; anime_type.data_length()]; let data = vec![255u8; anime_type.data_length()];
let tmp = AnimeDataBuffer::from_vec(anime_type, data)?; let tmp = AnimeDataBuffer::from_vec(anime_type, data)?;
dbus.proxies().anime().write(tmp)?; proxy.write(tmp)?;
} }
if let Some(action) = cmd.command.as_ref() { if let Some(action) = cmd.command.as_ref() {
@@ -278,9 +374,7 @@ fn handle_anime(
anime_type, anime_type,
)?; )?;
dbus.proxies() proxy.write(<AnimeDataBuffer>::try_from(&matrix)?)?;
.anime()
.write(<AnimeDataBuffer>::try_from(&matrix)?)?;
} }
AnimeActions::PixelImage(image) => { AnimeActions::PixelImage(image) => {
if image.help_requested() || image.path.is_empty() { if image.help_requested() || image.path.is_empty() {
@@ -299,9 +393,7 @@ fn handle_anime(
anime_type, anime_type,
)?; )?;
dbus.proxies() proxy.write(matrix.into_data_buffer(anime_type)?)?;
.anime()
.write(matrix.into_data_buffer(anime_type)?)?;
} }
AnimeActions::Gif(gif) => { AnimeActions::Gif(gif) => {
if gif.help_requested() || gif.path.is_empty() { if gif.help_requested() || gif.path.is_empty() {
@@ -326,7 +418,7 @@ fn handle_anime(
let mut loops = gif.loops as i32; let mut loops = gif.loops as i32;
loop { loop {
for frame in matrix.frames() { for frame in matrix.frames() {
dbus.proxies().anime().write(frame.frame().clone())?; proxy.write(frame.frame().clone())?;
sleep(frame.delay()); sleep(frame.delay());
} }
if loops >= 0 { if loops >= 0 {
@@ -357,7 +449,7 @@ fn handle_anime(
let mut loops = gif.loops as i32; let mut loops = gif.loops as i32;
loop { loop {
for frame in matrix.frames() { for frame in matrix.frames() {
dbus.proxies().anime().write(frame.frame().clone())?; proxy.write(frame.frame().clone())?;
sleep(frame.delay()); sleep(frame.delay());
} }
if loops >= 0 { if loops >= 0 {
@@ -378,14 +470,12 @@ fn handle_anime(
return Ok(()); return Ok(());
} }
dbus.proxies() proxy.set_builtin_animations(rog_anime::Animations {
.anime() boot: builtins.boot,
.set_builtin_animations(rog_anime::Animations { awake: builtins.awake,
boot: builtins.boot, sleep: builtins.sleep,
awake: builtins.awake, shutdown: builtins.shutdown,
sleep: builtins.sleep, })?;
shutdown: builtins.shutdown,
})?;
} }
} }
} }
@@ -401,16 +491,50 @@ fn verify_brightness(brightness: f32) {
} }
} }
fn handle_led_mode( fn handle_slash(conn: &Connection, cmd: &SlashCommand) -> Result<(), Box<dyn std::error::Error>> {
dbus: &RogDbusClientBlocking<'_>, if (cmd.brightness.is_none()
supported: &[String], && cmd.interval.is_none()
mode: &LedModeCommand, && cmd.slash_mode.is_none()
) -> Result<(), Box<dyn std::error::Error>> { && !cmd.list
if !supported.contains(&AURA_ZBUS_NAME.to_string()) { && !cmd.enable
println!("This laptop does not support power options"); && !cmd.disable)
return Err(PlatformError::NotSupported.into()); || cmd.help
{
println!("Missing arg or command\n\n{}", cmd.self_usage());
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
}
let proxy = SlashProxyBlocking::new(conn)?;
if cmd.enable {
proxy.set_enabled(true)?;
}
if cmd.disable {
proxy.set_enabled(false)?;
}
if let Some(brightness) = cmd.brightness {
proxy.set_brightness(brightness)?;
}
if let Some(interval) = cmd.interval {
proxy.set_interval(interval)?;
}
if let Some(slash_mode) = cmd.slash_mode {
proxy.set_slash_mode(slash_mode)?;
}
if cmd.list {
let res = SlashMode::list();
for p in &res {
println!("{:?}", p);
}
} }
Ok(())
}
fn handle_led_mode(
aura: &[AuraProxyBlocking],
mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if mode.command.is_none() && !mode.prev_mode && !mode.next_mode { if mode.command.is_none() && !mode.prev_mode && !mode.next_mode {
if !mode.help { if !mode.help {
println!("Missing arg or command\n"); println!("Missing arg or command\n");
@@ -420,8 +544,9 @@ fn handle_led_mode(
if let Some(cmdlist) = LedModeCommand::command_list() { if let Some(cmdlist) = LedModeCommand::command_list() {
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
// TODO: multiple rgb check
let modes = aura.first().unwrap().supported_basic_modes()?;
for command in commands.iter().filter(|command| { for command in commands.iter().filter(|command| {
let modes = dbus.proxies().aura().supported_modes().unwrap();
for mode in &modes { for mode in &modes {
if command if command
.trim() .trim()
@@ -449,71 +574,67 @@ fn handle_led_mode(
return Ok(()); return Ok(());
} }
if mode.next_mode { if mode.next_mode {
let mode = dbus.proxies().aura().led_mode()?; for aura in aura {
let modes = dbus.proxies().aura().supported_modes()?; let mode = aura.led_mode()?;
let mut pos = modes.iter().position(|m| *m == mode).unwrap() + 1; let modes = aura.supported_basic_modes()?;
if pos >= modes.len() { let mut pos = modes.iter().position(|m| *m == mode).unwrap() + 1;
pos = 0; if pos >= modes.len() {
pos = 0;
}
aura.set_led_mode(modes[pos])?;
} }
dbus.proxies().aura().set_led_mode(modes[pos])?;
} else if mode.prev_mode { } else if mode.prev_mode {
let mode = dbus.proxies().aura().led_mode()?; for aura in aura {
let modes = dbus.proxies().aura().supported_modes()?; let mode = aura.led_mode()?;
let mut pos = modes.iter().position(|m| *m == mode).unwrap(); let modes = aura.supported_basic_modes()?;
if pos == 0 { let mut pos = modes.iter().position(|m| *m == mode).unwrap();
pos = modes.len() - 1; if pos == 0 {
} else { pos = modes.len() - 1;
pos -= 1; } else {
pos -= 1;
}
aura.set_led_mode(modes[pos])?;
} }
dbus.proxies().aura().set_led_mode(modes[pos])?;
} else if let Some(mode) = mode.command.as_ref() { } else if let Some(mode) = mode.command.as_ref() {
if mode.help_requested() { if mode.help_requested() {
println!("{}", mode.self_usage()); println!("{}", mode.self_usage());
return Ok(()); return Ok(());
} }
dbus.proxies() for aura in aura {
.aura() aura.set_led_mode_data(<AuraEffect>::from(mode))?;
.set_led_mode_data(<AuraEffect>::from(mode))?; }
} }
Ok(()) Ok(())
} }
fn handle_led_power1( fn handle_led_power1(
dbus: &RogDbusClientBlocking<'_>, aura: &[AuraProxyBlocking],
supported: &[String],
power: &LedPowerCommand1, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if !supported.contains(&AURA_ZBUS_NAME.to_string()) { for aura in aura {
println!("This laptop does not support power options"); let dev_type = aura.device_type()?;
return Err(PlatformError::NotSupported.into()); if !dev_type.is_old_laptop() && !dev_type.is_tuf_laptop() {
} println!("This option applies only to keyboards 2021+");
let dev_type = dbus.proxies().aura().device_type()?;
if !dev_type.is_old_style() && !dev_type.is_tuf_style() {
println!("This option applies only to keyboards 2021+");
}
if power.awake.is_none()
&& power.sleep.is_none()
&& power.boot.is_none()
&& power.keyboard.is_none()
&& power.lightbar.is_none()
{
if !power.help {
println!("Missing arg or command\n");
} }
println!("{}\n", power.self_usage());
return Ok(());
}
if dev_type.is_old_style() { if power.awake.is_none()
handle_led_power_1_do_1866(dbus, power)?; && power.sleep.is_none()
return Ok(()); && power.boot.is_none()
} && !power.keyboard
&& !power.lightbar
{
if !power.help {
println!("Missing arg or command\n");
}
println!("{}\n", power.self_usage());
return Ok(());
}
if dev_type.is_tuf_style() { if dev_type.is_old_laptop() || dev_type.is_tuf_laptop() {
handle_led_power_1_do_tuf(dbus, power)?; handle_led_power_1_do_1866(aura, power)?;
return Ok(()); return Ok(());
}
} }
println!("These options are for keyboards of product ID 0x1866 or TUF only"); println!("These options are for keyboards of product ID 0x1866 or TUF only");
@@ -521,148 +642,102 @@ fn handle_led_power1(
} }
fn handle_led_power_1_do_1866( fn handle_led_power_1_do_1866(
dbus: &RogDbusClientBlocking<'_>, aura: &AuraProxyBlocking,
power: &LedPowerCommand1, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let mut enabled: Vec<AuraDevRog1> = Vec::new(); let zone = if power.keyboard && power.lightbar {
let mut disabled: Vec<AuraDevRog1> = Vec::new(); PowerZones::KeyboardAndLightbar
} else if power.lightbar {
let mut check = |e: Option<bool>, a: AuraDevRog1| { PowerZones::Lightbar
if let Some(arg) = e { } else {
if arg { PowerZones::Keyboard
enabled.push(a); };
} else { let states = LaptopAuraPower {
disabled.push(a); states: vec![AuraPowerState {
} zone,
} boot: power.boot.unwrap_or_default(),
awake: power.awake.unwrap_or_default(),
sleep: power.sleep.unwrap_or_default(),
shutdown: false,
}],
}; };
check(power.awake, AuraDevRog1::Awake); aura.set_led_power(states)?;
check(power.boot, AuraDevRog1::Boot);
check(power.sleep, AuraDevRog1::Sleep);
check(power.keyboard, AuraDevRog1::Keyboard);
check(power.lightbar, AuraDevRog1::Lightbar);
let data = AuraPowerDev {
old_rog: enabled,
..Default::default()
};
dbus.proxies().aura().set_led_power((data, true))?;
let data = AuraPowerDev {
old_rog: disabled,
..Default::default()
};
dbus.proxies().aura().set_led_power((data, false))?;
Ok(())
}
fn handle_led_power_1_do_tuf(
dbus: &RogDbusClientBlocking<'_>,
power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> {
let mut enabled: Vec<AuraDevTuf> = Vec::new();
let mut disabled: Vec<AuraDevTuf> = Vec::new();
let mut check = |e: Option<bool>, a: AuraDevTuf| {
if let Some(arg) = e {
if arg {
enabled.push(a);
} else {
disabled.push(a);
}
}
};
check(power.awake, AuraDevTuf::Awake);
check(power.boot, AuraDevTuf::Boot);
check(power.sleep, AuraDevTuf::Sleep);
check(power.keyboard, AuraDevTuf::Keyboard);
let data = AuraPowerDev {
tuf: enabled,
..Default::default()
};
dbus.proxies().aura().set_led_power((data, true))?;
let data = AuraPowerDev {
tuf: disabled,
..Default::default()
};
dbus.proxies().aura().set_led_power((data, false))?;
Ok(()) Ok(())
} }
fn handle_led_power2( fn handle_led_power2(
dbus: &RogDbusClientBlocking<'_>, aura: &[AuraProxyBlocking],
supported: &[String],
power: &LedPowerCommand2, power: &LedPowerCommand2,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if !supported.contains(&AURA_ZBUS_NAME.to_string()) { for aura in aura {
println!("This laptop does not support power options"); let dev_type = aura.device_type()?;
return Err(PlatformError::NotSupported.into()); if !dev_type.is_new_laptop() {
} println!("This option applies only to keyboards 2021+");
let dev_type = dbus.proxies().aura().device_type()?; continue;
if !dev_type.is_new_style() {
println!("This option applies only to keyboards 2021+");
}
if power.command().is_none() {
if !power.help {
println!("Missing arg or command\n");
} }
println!("{}\n", power.self_usage());
println!("Commands available");
if let Some(cmdlist) = LedPowerCommand2::command_list() { if power.command().is_none() {
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect(); if !power.help {
for command in &commands { println!("Missing arg or command\n");
println!("{}", command);
} }
} println!("{}\n", power.self_usage());
println!("Commands available");
println!("\nHelp can also be requested on commands, e.g: boot --help"); if let Some(cmdlist) = LedPowerCommand2::command_list() {
return Ok(()); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
} for command in &commands {
println!("{}", command);
}
}
if let Some(pow) = power.command.as_ref() { println!("\nHelp can also be requested on commands, e.g: boot --help");
if pow.help_requested() {
println!("{}", pow.self_usage());
return Ok(()); return Ok(());
} }
let set = |power: &mut KbAuraPowerState, set_to: &AuraPowerStates| { if let Some(pow) = power.command.as_ref() {
power.boot = set_to.boot; if pow.help_requested() {
power.awake = set_to.awake; println!("{}", pow.self_usage());
power.sleep = set_to.sleep; return Ok(());
power.shutdown = set_to.shutdown;
};
let mut enabled = dbus.proxies().aura().led_power()?;
if let Some(cmd) = &power.command {
match cmd {
aura_cli::SetAuraZoneEnabled::Keyboard(k) => set(&mut enabled.rog.keyboard, k),
aura_cli::SetAuraZoneEnabled::Logo(l) => set(&mut enabled.rog.logo, l),
aura_cli::SetAuraZoneEnabled::Lightbar(l) => set(&mut enabled.rog.lightbar, l),
aura_cli::SetAuraZoneEnabled::Lid(l) => set(&mut enabled.rog.lid, l),
aura_cli::SetAuraZoneEnabled::RearGlow(r) => set(&mut enabled.rog.rear_glow, r),
} }
}
dbus.proxies().aura().set_led_power((enabled, true))?; let mut states = aura.led_power()?;
let mut set = |zone: PowerZones, set_to: &AuraPowerStates| {
for state in states.states.iter_mut() {
if state.zone == zone {
state.boot = set_to.boot;
state.awake = set_to.awake;
state.sleep = set_to.sleep;
state.shutdown = set_to.shutdown;
break;
}
}
};
if let Some(cmd) = &power.command {
match cmd {
aura_cli::SetAuraZoneEnabled::Keyboard(k) => set(PowerZones::Keyboard, k),
aura_cli::SetAuraZoneEnabled::Logo(l) => set(PowerZones::Logo, l),
aura_cli::SetAuraZoneEnabled::Lightbar(l) => set(PowerZones::Lightbar, l),
aura_cli::SetAuraZoneEnabled::Lid(l) => set(PowerZones::Lid, l),
aura_cli::SetAuraZoneEnabled::RearGlow(r) => set(PowerZones::RearGlow, r),
}
}
aura.set_led_power(states)?;
}
} }
Ok(()) Ok(())
} }
fn handle_throttle_profile( fn handle_throttle_profile(
dbus: &RogDbusClientBlocking<'_>, conn: &Connection,
supported: &[Properties], supported: &[Properties],
cmd: &ProfileCommand, cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if !supported.contains(&Properties::DgpuDisable) { if !supported.contains(&Properties::ThrottlePolicy) {
println!("Profiles not supported by either this kernel or by the laptop."); println!("Profiles not supported by either this kernel or by the laptop.");
return Err(ProfileError::NotSupported.into()); return Err(ProfileError::NotSupported.into());
} }
@@ -678,20 +753,18 @@ fn handle_throttle_profile(
} }
return Ok(()); return Ok(());
} }
let current = dbus.proxies().platform().throttle_thermal_policy()?;
let proxy = PlatformProxyBlocking::new(conn)?;
let current = proxy.throttle_thermal_policy()?;
if cmd.next { if cmd.next {
dbus.proxies() proxy.set_throttle_thermal_policy(current.next())?;
.platform()
.set_throttle_thermal_policy(current.next())?;
} else if let Some(profile) = cmd.profile_set { } else if let Some(profile) = cmd.profile_set {
dbus.proxies() proxy.set_throttle_thermal_policy(profile)?;
.platform()
.set_throttle_thermal_policy(profile)?;
} }
if cmd.list { if cmd.list {
let res = PlatformPolicy::list(); let res = ThrottlePolicy::list();
for p in &res { for p in &res {
println!("{:?}", p); println!("{:?}", p);
} }
@@ -705,7 +778,7 @@ fn handle_throttle_profile(
} }
fn handle_fan_curve( fn handle_fan_curve(
dbus: &RogDbusClientBlocking<'_>, conn: &Connection,
supported: &[String], supported: &[String],
cmd: &FanCurveCommand, cmd: &FanCurveCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -736,36 +809,35 @@ fn handle_fan_curve(
return Ok(()); return Ok(());
} }
let plat_proxy = PlatformProxyBlocking::new(conn)?;
let fan_proxy = FanCurvesProxyBlocking::new(conn)?;
if cmd.get_enabled { if cmd.get_enabled {
let profile = dbus.proxies().platform().throttle_thermal_policy()?; let profile = plat_proxy.throttle_thermal_policy()?;
let curves = dbus.proxies().fan_curves().fan_curve_data(profile)?; let curves = fan_proxy.fan_curve_data(profile)?;
for curve in curves.iter() { for curve in curves.iter() {
println!("{}", String::from(curve)); println!("{}", String::from(curve));
} }
} }
if cmd.default { if cmd.default {
dbus.proxies().fan_curves().set_active_curve_to_defaults()?; let active = plat_proxy.throttle_thermal_policy()?;
fan_proxy.set_curves_to_defaults(active)?;
} }
if let Some(profile) = cmd.mod_profile { if let Some(profile) = cmd.mod_profile {
if cmd.enable_fan_curves.is_none() && cmd.data.is_none() { if cmd.enable_fan_curves.is_none() && cmd.data.is_none() {
let data = dbus.proxies().fan_curves().fan_curve_data(profile)?; let data = fan_proxy.fan_curve_data(profile)?;
let data = toml::to_string(&data)?; let ron = ron::ser::to_string_pretty(&data, PrettyConfig::new().depth_limit(4))?;
println!("\nFan curves for {:?}\n\n{}", profile, data); println!("\nFan curves for {:?}\n\n{}", profile, ron);
} }
if let Some(enabled) = cmd.enable_fan_curves { if let Some(enabled) = cmd.enable_fan_curves {
dbus.proxies() fan_proxy.set_fan_curves_enabled(profile, enabled)?;
.fan_curves()
.set_fan_curves_enabled(profile, enabled)?;
} }
if let Some(enabled) = cmd.enable_fan_curve { if let Some(enabled) = cmd.enable_fan_curve {
if let Some(fan) = cmd.fan { if let Some(fan) = cmd.fan {
dbus.proxies() fan_proxy.set_profile_fan_curve_enabled(profile, fan, enabled)?;
.fan_curves()
.set_profile_fan_curve_enabled(profile, fan, enabled)?;
} else { } else {
println!( println!(
"--enable-fan-curves, --enable-fan-curve, --fan, and --data options require \ "--enable-fan-curves, --enable-fan-curve, --fan, and --data options require \
@@ -777,7 +849,7 @@ fn handle_fan_curve(
if let Some(mut curve) = cmd.data.clone() { if let Some(mut curve) = cmd.data.clone() {
let fan = cmd.fan.unwrap_or_default(); let fan = cmd.fan.unwrap_or_default();
curve.set_fan(fan); curve.set_fan(fan);
dbus.proxies().fan_curves().set_fan_curve(profile, curve)?; fan_proxy.set_fan_curve(profile, curve)?;
} }
} }
@@ -785,7 +857,7 @@ fn handle_fan_curve(
} }
fn handle_platform_properties( fn handle_platform_properties(
dbus: &RogDbusClientBlocking<'_>, conn: &Connection,
supported: &[Properties], supported: &[Properties],
cmd: &BiosCommand, cmd: &BiosCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -811,34 +883,34 @@ fn handle_platform_properties(
} }
} }
let proxy = PlatformProxyBlocking::new(conn)?;
if let Some(opt) = cmd.post_sound_set { if let Some(opt) = cmd.post_sound_set {
dbus.proxies().platform().set_post_animation_sound(opt)?; proxy.set_boot_sound(opt)?;
} }
if cmd.post_sound_get { if cmd.post_sound_get {
let res = dbus.proxies().platform().post_animation_sound()?; let res = proxy.boot_sound()?;
println!("Bios POST sound on: {}", res); println!("Bios POST sound on: {}", res);
} }
if let Some(opt) = cmd.gpu_mux_mode_set { if let Some(opt) = cmd.gpu_mux_mode_set {
println!("Rebuilding initrd to include drivers"); println!("Rebuilding initrd to include drivers");
dbus.proxies() proxy.set_gpu_mux_mode(GpuMode::from_mux(opt))?;
.platform()
.set_gpu_mux_mode(GpuMode::from_mux(opt))?;
println!( println!(
"The mode change is not active until you reboot, on boot the bios will make the \ "The mode change is not active until you reboot, on boot the bios will make the \
required change" required change"
); );
} }
if cmd.gpu_mux_mode_get { if cmd.gpu_mux_mode_get {
let res = dbus.proxies().platform().gpu_mux_mode()?; let res = proxy.gpu_mux_mode()?;
println!("Bios GPU MUX: {:?}", res); println!("Bios GPU MUX: {:?}", res);
} }
if let Some(opt) = cmd.panel_overdrive_set { if let Some(opt) = cmd.panel_overdrive_set {
dbus.proxies().platform().set_panel_od(opt)?; proxy.set_panel_od(opt)?;
} }
if cmd.panel_overdrive_get { if cmd.panel_overdrive_get {
let res = dbus.proxies().platform().panel_od()?; let res = proxy.panel_od()?;
println!("Panel overdrive on: {}", res); println!("Panel overdrive on: {}", res);
} }
} }
+20
View File
@@ -0,0 +1,20 @@
use gumdrop::Options;
use rog_slash::SlashMode;
#[derive(Options)]
pub struct SlashCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "Enable the Slash Ledbar")]
pub enable: bool,
#[options(help = "Ddisable the Slash Ledbar")]
pub disable: bool,
#[options(meta = "", help = "Set brightness value <0-255>")]
pub brightness: Option<u8>,
#[options(meta = "", help = "Set interval value <0-255>")]
pub interval: Option<u8>,
#[options(help = "Set SlashMode (so 'list' for all options)")]
pub slash_mode: Option<SlashMode>,
#[options(help = "list available animations")]
pub list: bool,
}
+11 -9
View File
@@ -1,10 +1,12 @@
[package] [package]
name = "asusd-user" name = "asusd-user"
license = "MPL-2.0" license.workspace = true
version.workspace = true version.workspace = true
authors = ["Luke D Jones <luke@ljones.dev>"] readme.workspace = true
edition = "2021" authors.workspace = true
description = "Usermode daemon for user settings, anime, per-key lighting" repository.workspace = true
homepage.workspace = true
edition.workspace = true
[[bin]] [[bin]]
name = "asusd-user" name = "asusd-user"
@@ -16,8 +18,8 @@ smol.workspace = true
# serialisation # serialisation
serde.workspace = true serde.workspace = true
serde_json.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
ron.workspace = true
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
@@ -26,10 +28,10 @@ rog_platform = { path = "../rog-platform" }
config-traits = { path = "../config-traits" } config-traits = { path = "../config-traits" }
zbus.workspace = true zbus.workspace = true
# cli and logging
log.workspace = true
env_logger.workspace = true env_logger.workspace = true
[dev-dependencies] [dev-dependencies]
cargo-husky.workspace = true cargo-husky.workspace = true
[package.metadata.cargo-machete]
ignored = ["serde"]
+1 -1
View File
@@ -3,8 +3,8 @@ use std::time::Duration;
use config_traits::{StdConfig, StdConfigLoad}; use config_traits::{StdConfig, StdConfigLoad};
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2}; use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2};
use rog_aura::advanced::LedCode;
use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static}; use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static};
use rog_aura::keyboard::LedCode;
use rog_aura::{Colour, Speed}; use rog_aura::{Colour, Speed};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
+26 -34
View File
@@ -7,9 +7,10 @@ use std::time::{Duration, Instant};
use config_traits::StdConfig; use config_traits::StdConfig;
use rog_anime::error::AnimeError; use rog_anime::error::AnimeError;
use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2}; use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use ron::ser::PrettyConfig;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface; use zbus::interface;
use zbus::zvariant::{ObjectPath, Type}; use zbus::zvariant::{ObjectPath, Type};
use crate::config::ConfigAnime; use crate::config::ConfigAnime;
@@ -61,14 +62,14 @@ pub enum TimeType {
/// thread and a zbus server behind `Arc<Mutex<T>>` /// thread and a zbus server behind `Arc<Mutex<T>>`
pub struct CtrlAnimeInner<'a> { pub struct CtrlAnimeInner<'a> {
sequences: Sequences, sequences: Sequences,
client: RogDbusClientBlocking<'a>, client: AnimeProxyBlocking<'a>,
do_early_return: Arc<AtomicBool>, do_early_return: Arc<AtomicBool>,
} }
impl<'a> CtrlAnimeInner<'static> { impl<'a> CtrlAnimeInner<'static> {
pub fn new( pub fn new(
sequences: Sequences, sequences: Sequences,
client: RogDbusClientBlocking<'static>, client: AnimeProxyBlocking<'static>,
do_early_return: Arc<AtomicBool>, do_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
@@ -93,19 +94,13 @@ impl<'a> CtrlAnimeInner<'static> {
return Ok(true); // Do safe exit return Ok(true); // Do safe exit
} }
self.client self.client
.proxies()
.anime()
.write(output) .write(output)
.map_err(|e| AnimeError::Dbus(format!("{}", e))) .map_err(|e| AnimeError::Dbus(format!("{}", e)))
.map(|_| false) .map(|_| false)
}); });
} }
ActionData::Image(image) => { ActionData::Image(image) => {
self.client self.client.write(image.as_ref().clone()).ok();
.proxies()
.anime()
.write(image.as_ref().clone())
.ok();
} }
ActionData::Pause(duration) => { ActionData::Pause(duration) => {
let start = Instant::now(); let start = Instant::now();
@@ -132,7 +127,7 @@ impl<'a> CtrlAnimeInner<'static> {
pub struct CtrlAnime<'a> { pub struct CtrlAnime<'a> {
config: Arc<Mutex<ConfigAnime>>, config: Arc<Mutex<ConfigAnime>>,
client: RogDbusClientBlocking<'a>, client: AnimeProxyBlocking<'a>,
inner: Arc<Mutex<CtrlAnimeInner<'a>>>, inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
/// Must be the same Atomic as in CtrlAnimeInner /// Must be the same Atomic as in CtrlAnimeInner
inner_early_return: Arc<AtomicBool>, inner_early_return: Arc<AtomicBool>,
@@ -142,7 +137,7 @@ impl CtrlAnime<'static> {
pub fn new( pub fn new(
config: Arc<Mutex<ConfigAnime>>, config: Arc<Mutex<ConfigAnime>>,
inner: Arc<Mutex<CtrlAnimeInner<'static>>>, inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
client: RogDbusClientBlocking<'static>, client: AnimeProxyBlocking<'static>,
inner_early_return: Arc<AtomicBool>, inner_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(CtrlAnime { Ok(CtrlAnime {
@@ -175,7 +170,7 @@ impl CtrlAnime<'static> {
// - Do actions // - Do actions
// - Write config if required // - Write config if required
// - Unset inner_early_return // - Unset inner_early_return
#[dbus_interface(name = "org.asuslinux.Daemon")] #[interface(name = "org.asuslinux.Daemon")]
impl CtrlAnime<'static> { impl CtrlAnime<'static> {
pub fn insert_asus_gif( pub fn insert_asus_gif(
&mut self, &mut self,
@@ -205,11 +200,12 @@ impl CtrlAnime<'static> {
config.anime.push(action); config.anime.push(action);
config.write(); config.write();
let json = serde_json::to_string_pretty(&*config).expect("Parse config to JSON failed"); let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again // Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(json); return Ok(ron);
} }
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into())) Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
} }
@@ -250,12 +246,11 @@ impl CtrlAnime<'static> {
config.anime.push(action); config.anime.push(action);
config.write(); config.write();
let json = let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed"); .expect("Parse config to RON failed");
// Release the inner run loop again // Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(json); return Ok(ron);
} }
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into())) Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
} }
@@ -295,12 +290,11 @@ impl CtrlAnime<'static> {
config.anime.push(action); config.anime.push(action);
config.write(); config.write();
let json = let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed"); .expect("Parse config to RON failed");
// Release the inner run loop again // Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(json); return Ok(ron);
} }
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into())) Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
} }
@@ -320,12 +314,11 @@ impl CtrlAnime<'static> {
config.anime.push(action); config.anime.push(action);
config.write(); config.write();
let json = let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed"); .expect("Parse config to RON failed");
// Release the inner run loop again // Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(json); return Ok(ron);
} }
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into())) Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
} }
@@ -343,12 +336,11 @@ impl CtrlAnime<'static> {
} }
config.write(); config.write();
let json = let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed"); .expect("Parse config to RON failed");
// Release the inner run loop again // Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(json); return Ok(ron);
} }
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into())) Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
} }
@@ -356,13 +348,13 @@ impl CtrlAnime<'static> {
pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> { pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> {
// Operations here need to be in specific order // Operations here need to be in specific order
if on { if on {
self.client.proxies().anime().set_enable_display(on).ok(); self.client.set_enable_display(on).ok();
// Let the inner loop run // Let the inner loop run
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
} else { } else {
// Must make the inner run loop return early // Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
self.client.proxies().anime().set_enable_display(on).ok(); self.client.set_enable_display(on).ok();
} }
Ok(()) Ok(())
} }
+27 -22
View File
@@ -7,9 +7,12 @@ use asusd_user::config::*;
use asusd_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner}; use asusd_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner};
use config_traits::{StdConfig, StdConfigLoad}; use config_traits::{StdConfig, StdConfigLoad};
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_aura::aura_detection::LaptopLedData; use rog_aura::aura_detection::LedSupportData;
use rog_aura::layouts::KeyLayout; use rog_aura::keyboard::KeyLayout;
use rog_dbus::{RogDbusClientBlocking, DBUS_NAME}; use rog_dbus::zbus_anime::AnimeProxyBlocking;
use rog_dbus::zbus_aura::AuraProxyBlocking;
use rog_dbus::zbus_platform::PlatformProxyBlocking;
use rog_dbus::DBUS_NAME;
use smol::Executor; use smol::Executor;
use zbus::Connection; use zbus::Connection;
@@ -32,10 +35,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" rog-dbus v{}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!("rog-platform v{}", rog_platform::VERSION); println!("rog-platform v{}", rog_platform::VERSION);
let (client, _) = RogDbusClientBlocking::new()?; let conn = zbus::blocking::Connection::system().unwrap();
let supported = client let platform_proxy = PlatformProxyBlocking::new(&conn).unwrap();
.proxies()
.platform() let supported = platform_proxy
.supported_interfaces() .supported_interfaces()
.unwrap_or_default() .unwrap_or_default()
.contains(&"Anime".to_string()); .contains(&"Anime".to_string());
@@ -51,6 +54,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let anime = anime_config.create(anime_type)?; let anime = anime_config.create(anime_type)?;
let anime_config = Arc::new(Mutex::new(anime_config)); let anime_config = Arc::new(Mutex::new(anime_config));
let anime_proxy_blocking = AnimeProxyBlocking::new(&conn).unwrap();
executor executor
.spawn(async move { .spawn(async move {
// Create server // Create server
@@ -59,12 +63,21 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Inner behind mutex required for thread safety // Inner behind mutex required for thread safety
let inner = Arc::new(Mutex::new( let inner = Arc::new(Mutex::new(
CtrlAnimeInner::new(anime, client, early_return.clone()).unwrap(), CtrlAnimeInner::new(
anime,
anime_proxy_blocking.clone(),
early_return.clone(),
)
.unwrap(),
)); ));
// Need new client object for dbus control part // Need new client object for dbus control part
let (client, _) = RogDbusClientBlocking::new().unwrap(); let anime_control = CtrlAnime::new(
let anime_control = anime_config,
CtrlAnime::new(anime_config, inner.clone(), client, early_return).unwrap(); inner.clone(),
anime_proxy_blocking,
early_return,
)
.unwrap();
anime_control.add_to_server(&mut connection).await; anime_control.add_to_server(&mut connection).await;
loop { loop {
if let Ok(inner) = inner.clone().try_lock() { if let Ok(inner) = inner.clone().try_lock() {
@@ -81,7 +94,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut aura_config = ConfigAura::new().set_name(cfg).load(); let mut aura_config = ConfigAura::new().set_name(cfg).load();
// let baord_name = std::fs::read_to_string(BOARD_NAME)?; // let baord_name = std::fs::read_to_string(BOARD_NAME)?;
let led_support = LaptopLedData::get_data(); let led_support = LedSupportData::get_data("");
let layout = KeyLayout::find_layout(led_support, PathBuf::from(DATA_DIR)) let layout = KeyLayout::find_layout(led_support, PathBuf::from(DATA_DIR))
.map_err(|e| { .map_err(|e| {
@@ -89,22 +102,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}) })
.unwrap_or_else(|_| KeyLayout::default_layout()); .unwrap_or_else(|_| KeyLayout::default_layout());
let aura_proxy_blocking = AuraProxyBlocking::new(&conn).unwrap();
executor executor
.spawn(async move { .spawn(async move {
// Create server
let (client, _) = RogDbusClientBlocking::new().unwrap();
// let connection = Connection::session().await.unwrap();
// connection.request_name(DBUS_NAME).await.unwrap();
loop { loop {
aura_config.aura.next_state(&layout); aura_config.aura.next_state(&layout);
let packets = aura_config.aura.create_packets(); let packets = aura_config.aura.create_packets();
client aura_proxy_blocking.direct_addressing_raw(packets).unwrap();
.proxies()
.aura()
.direct_addressing_raw(packets)
.unwrap();
std::thread::sleep(std::time::Duration::from_millis(33)); std::thread::sleep(std::time::Duration::from_millis(33));
} }
}) })
+2 -2
View File
@@ -21,9 +21,9 @@
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use zbus::dbus_proxy; use zbus::proxy;
#[dbus_proxy( #[proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Anime" default_path = "/org/asuslinux/Anime"
)] )]
+15 -11
View File
@@ -1,13 +1,13 @@
[package] [package]
name = "asusd" name = "asusd"
license = "MPL-2.0" license.workspace = true
version.workspace = true version.workspace = true
readme = "README.md" readme.workspace = true
authors = ["Luke <luke@ljones.dev>"] authors.workspace = true
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl" repository.workspace = true
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl" homepage.workspace = true
description = "A daemon app for ASUS GX502 and similar laptops to control missing features" description.workspace = true
edition = "2021" edition.workspace = true
[[bin]] [[bin]]
name = "asusd" name = "asusd"
@@ -16,15 +16,18 @@ path = "src/daemon.rs"
[dependencies] [dependencies]
config-traits = { path = "../config-traits" } config-traits = { path = "../config-traits" }
rog_anime = { path = "../rog-anime", features = ["dbus"] } rog_anime = { path = "../rog-anime", features = ["dbus"] }
rog_slash = { path = "../rog-slash", features = ["dbus"] }
rog_aura = { path = "../rog-aura", features = ["dbus"] } rog_aura = { path = "../rog-aura", features = ["dbus"] }
rog_platform = { path = "../rog-platform" } rog_platform = { path = "../rog-platform" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
dmi_id = { path = "../dmi-id" } dmi_id = { path = "../dmi-id" }
futures-lite = "*" futures-lite = "*"
udev.workspace = true udev.workspace = true
inotify.workspace = true
async-trait.workspace = true mio.workspace = true
tokio.workspace = true tokio.workspace = true
# console-subscriber = "0.2.0"
# cli and logging # cli and logging
log.workspace = true log.workspace = true
@@ -39,7 +42,8 @@ serde_derive.workspace = true
concat-idents.workspace = true concat-idents.workspace = true
systemd-zbus = "*"
[dev-dependencies] [dev-dependencies]
cargo-husky.workspace = true cargo-husky.workspace = true
[package.metadata.cargo-machete]
ignored = ["serde"]
+186 -51
View File
@@ -1,11 +1,115 @@
use config_traits::{StdConfig, StdConfigLoad2}; use config_traits::{StdConfig, StdConfigLoad3};
use rog_platform::platform::PlatformPolicy; use rog_platform::cpu::CPUEPP;
use rog_platform::platform::ThrottlePolicy;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "asusd.ron"; const CONFIG_FILE: &str = "asusd.ron";
#[derive(Deserialize, Serialize, Default, Debug)] #[derive(Deserialize, Serialize, Debug, PartialEq, PartialOrd)]
pub struct Config { pub struct Config {
/// Save charge limit for restoring on boot/resume
pub charge_control_end_threshold: u8,
pub panel_od: bool,
pub boot_sound: bool,
pub mini_led_mode: bool,
pub disable_nvidia_powerd_on_battery: bool,
/// An optional command/script to run when power is changed to AC
pub ac_command: String,
/// An optional command/script to run when power is changed to battery
pub bat_command: String,
/// Set true if energy_performance_preference should be set if the
/// throttle/platform profile is changed
pub throttle_policy_linked_epp: bool,
/// Which throttle/profile to use on battery power
pub throttle_policy_on_battery: ThrottlePolicy,
/// Which throttle/profile to use on AC power
pub throttle_policy_on_ac: ThrottlePolicy,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_quiet_epp: CPUEPP,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_balanced_epp: CPUEPP,
/// The energy_performance_preference for this throttle/platform profile
pub throttle_performance_epp: CPUEPP,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl1_spl: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl2_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_fppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_apu_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_platform_sppt: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_dynamic_boost: Option<u8>,
/// Defaults to `None` if not supported
#[serde(skip_serializing_if = "Option::is_none", default)]
pub nv_temp_target: Option<u8>,
/// Temporary state for AC/Batt
#[serde(skip)]
pub last_power_plugged: u8,
}
impl Default for Config {
fn default() -> Self {
Self {
charge_control_end_threshold: 100,
panel_od: false,
boot_sound: false,
mini_led_mode: false,
disable_nvidia_powerd_on_battery: true,
ac_command: Default::default(),
bat_command: Default::default(),
throttle_policy_linked_epp: true,
throttle_policy_on_battery: ThrottlePolicy::Quiet,
throttle_policy_on_ac: ThrottlePolicy::Performance,
throttle_quiet_epp: CPUEPP::Power,
throttle_balanced_epp: CPUEPP::BalancePower,
throttle_performance_epp: CPUEPP::Performance,
ppt_pl1_spl: Default::default(),
ppt_pl2_sppt: Default::default(),
ppt_fppt: Default::default(),
ppt_apu_sppt: Default::default(),
ppt_platform_sppt: Default::default(),
nv_dynamic_boost: Default::default(),
nv_temp_target: Default::default(),
last_power_plugged: Default::default(),
}
}
}
impl StdConfig for Config {
fn new() -> Self {
Config {
charge_control_end_threshold: 100,
disable_nvidia_powerd_on_battery: true,
throttle_policy_on_battery: ThrottlePolicy::Quiet,
throttle_policy_on_ac: ThrottlePolicy::Performance,
ac_command: String::new(),
bat_command: String::new(),
..Default::default()
}
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
impl StdConfigLoad3<Config472, Config506, Config507> for Config {}
#[derive(Deserialize, Serialize)]
pub struct Config507 {
/// Save charge limit for restoring on boot /// Save charge limit for restoring on boot
pub charge_control_end_threshold: u8, pub charge_control_end_threshold: u8,
pub panel_od: bool, pub panel_od: bool,
@@ -13,11 +117,9 @@ pub struct Config {
pub disable_nvidia_powerd_on_battery: bool, pub disable_nvidia_powerd_on_battery: bool,
pub ac_command: String, pub ac_command: String,
pub bat_command: String, pub bat_command: String,
/// Restored on boot as well as when power is plugged pub platform_policy_linked_epp: bool,
#[serde(skip)] pub platform_policy_on_battery: ThrottlePolicy,
pub platform_policy_to_restore: PlatformPolicy, pub platform_policy_on_ac: ThrottlePolicy,
pub platform_policy_on_battery: PlatformPolicy,
pub platform_policy_on_ac: PlatformPolicy,
// //
pub ppt_pl1_spl: Option<u8>, pub ppt_pl1_spl: Option<u8>,
pub ppt_pl2_sppt: Option<u8>, pub ppt_pl2_sppt: Option<u8>,
@@ -28,31 +130,87 @@ pub struct Config {
pub nv_temp_target: Option<u8>, pub nv_temp_target: Option<u8>,
} }
impl StdConfig for Config { impl From<Config507> for Config {
fn new() -> Self { fn from(c: Config507) -> Self {
Config { Self {
charge_control_end_threshold: 100, charge_control_end_threshold: c.charge_control_end_threshold,
disable_nvidia_powerd_on_battery: true, panel_od: c.panel_od,
platform_policy_on_battery: PlatformPolicy::Quiet, boot_sound: false,
platform_policy_on_ac: PlatformPolicy::Performance, disable_nvidia_powerd_on_battery: c.disable_nvidia_powerd_on_battery,
ac_command: String::new(), ac_command: c.ac_command,
bat_command: String::new(), bat_command: c.bat_command,
..Default::default() mini_led_mode: c.mini_led_mode,
throttle_policy_linked_epp: true,
throttle_policy_on_battery: c.platform_policy_on_battery,
throttle_policy_on_ac: c.platform_policy_on_ac,
throttle_quiet_epp: CPUEPP::Power,
throttle_balanced_epp: CPUEPP::BalancePower,
throttle_performance_epp: CPUEPP::Performance,
ppt_pl1_spl: c.ppt_pl1_spl,
ppt_pl2_sppt: c.ppt_pl2_sppt,
ppt_fppt: c.ppt_fppt,
ppt_apu_sppt: c.ppt_apu_sppt,
ppt_platform_sppt: c.ppt_platform_sppt,
nv_dynamic_boost: c.nv_dynamic_boost,
nv_temp_target: c.nv_temp_target,
last_power_plugged: 0,
} }
} }
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
} }
impl StdConfigLoad2<Config462, Config472> for Config {} #[derive(Deserialize, Serialize)]
pub struct Config506 {
/// Save charge limit for restoring on boot
pub charge_control_end_threshold: u8,
pub panel_od: bool,
pub mini_led_mode: bool,
pub disable_nvidia_powerd_on_battery: bool,
pub ac_command: String,
pub bat_command: String,
/// Restored on boot as well as when power is plugged
#[serde(skip)]
pub platform_policy_to_restore: ThrottlePolicy,
pub platform_policy_on_battery: ThrottlePolicy,
pub platform_policy_on_ac: ThrottlePolicy,
//
pub ppt_pl1_spl: Option<u8>,
pub ppt_pl2_sppt: Option<u8>,
pub ppt_fppt: Option<u8>,
pub ppt_apu_sppt: Option<u8>,
pub ppt_platform_sppt: Option<u8>,
pub nv_dynamic_boost: Option<u8>,
pub nv_temp_target: Option<u8>,
}
#[derive(Deserialize, Serialize, Default, Debug)] impl From<Config506> for Config {
fn from(c: Config506) -> Self {
Self {
charge_control_end_threshold: c.charge_control_end_threshold,
panel_od: c.panel_od,
boot_sound: false,
disable_nvidia_powerd_on_battery: c.disable_nvidia_powerd_on_battery,
ac_command: c.ac_command,
bat_command: c.bat_command,
mini_led_mode: c.mini_led_mode,
throttle_policy_linked_epp: true,
throttle_policy_on_battery: c.platform_policy_on_battery,
throttle_policy_on_ac: c.platform_policy_on_ac,
throttle_quiet_epp: CPUEPP::Power,
throttle_balanced_epp: CPUEPP::BalancePower,
throttle_performance_epp: CPUEPP::Performance,
ppt_pl1_spl: c.ppt_pl1_spl,
ppt_pl2_sppt: c.ppt_pl2_sppt,
ppt_fppt: c.ppt_fppt,
ppt_apu_sppt: c.ppt_apu_sppt,
ppt_platform_sppt: c.ppt_platform_sppt,
nv_dynamic_boost: c.nv_dynamic_boost,
nv_temp_target: c.nv_temp_target,
last_power_plugged: 0,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct Config472 { pub struct Config472 {
/// Save charge limit for restoring on boot /// Save charge limit for restoring on boot
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
@@ -75,26 +233,3 @@ impl From<Config472> for Config {
} }
} }
} }
#[derive(Deserialize, Serialize)]
pub struct Config462 {
/// Save charge limit for restoring on boot
pub bat_charge_limit: u8,
pub panel_od: bool,
pub disable_nvidia_powerd_on_battery: bool,
pub ac_command: String,
pub bat_command: String,
}
impl From<Config462> for Config {
fn from(c: Config462) -> Self {
Self {
charge_control_end_threshold: c.bat_charge_limit,
panel_od: c.panel_od,
disable_nvidia_powerd_on_battery: true,
ac_command: String::new(),
bat_command: String::new(),
..Default::default()
}
}
}
+5 -5
View File
@@ -106,7 +106,7 @@ impl AnimeConfigCached {
} }
/// Config for base system actions for the anime display /// Config for base system actions for the anime display
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug, Clone)]
pub struct AnimeConfig { pub struct AnimeConfig {
pub model_override: Option<AnimeType>, pub model_override: Option<AnimeType>,
pub system: Vec<ActionLoader>, pub system: Vec<ActionLoader>,
@@ -150,13 +150,13 @@ impl StdConfig for AnimeConfig {
Self::create_default() Self::create_default()
} }
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
fn file_name(&self) -> String { fn file_name(&self) -> String {
CONFIG_FILE.to_owned() CONFIG_FILE.to_owned()
} }
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
} }
impl StdConfigLoad2<AnimeConfigV460, AnimeConfigV472> for AnimeConfig {} impl StdConfigLoad2<AnimeConfigV460, AnimeConfigV472> for AnimeConfig {}
+16 -12
View File
@@ -8,6 +8,7 @@ use std::sync::Arc;
use std::thread::sleep; use std::thread::sleep;
use ::zbus::export::futures_util::lock::Mutex; use ::zbus::export::futures_util::lock::Mutex;
use config_traits::{StdConfig, StdConfigLoad2};
use log::{error, info, warn}; use log::{error, info, warn};
use rog_anime::error::AnimeError; use rog_anime::error::AnimeError;
use rog_anime::usb::{ use rog_anime::usb::{
@@ -62,31 +63,34 @@ pub struct CtrlAnime {
impl CtrlAnime { impl CtrlAnime {
#[inline] #[inline]
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, RogError> { pub fn new() -> Result<CtrlAnime, RogError> {
let usb = USBRaw::new(0x193b).ok(); let usb = USBRaw::new(0x193b).ok();
let hid = HidRaw::new("193b").ok(); let hid = HidRaw::new("193b").ok();
let node = if usb.is_some() { let node = if usb.is_some() {
info!("Anime using the USB interface");
unsafe { Node::Usb(usb.unwrap_unchecked()) } unsafe { Node::Usb(usb.unwrap_unchecked()) }
} else if hid.is_some() { } else if hid.is_some() {
info!("Anime using the HID interface");
unsafe { Node::Hid(hid.unwrap_unchecked()) } unsafe { Node::Hid(hid.unwrap_unchecked()) }
} else { } else {
return Err(RogError::Anime(AnimeError::NoDevice)); return Err(RogError::Anime(AnimeError::NoDevice));
}; };
// TODO: something better to set wakeups disabled // TODO: something better to set wakeups disabled
if matches!(node, Node::Usb(_)) { // if matches!(node, Node::Usb(_)) {
if let Ok(mut enumerator) = udev::Enumerator::new() { // if let Ok(mut enumerator) = udev::Enumerator::new() {
enumerator.match_subsystem("usb").ok(); // enumerator.match_subsystem("usb").ok();
enumerator.match_attribute("idProduct", "193b").ok(); // enumerator.match_attribute("idProduct", "193b").ok();
if let Ok(mut enumer) = enumerator.scan_devices() { // if let Ok(mut enumer) = enumerator.scan_devices() {
if let Some(mut dev) = enumer.next() { // if let Some(mut dev) = enumer.next() {
dev.set_attribute_value("power/wakeup", "disabled").ok(); // dev.set_attribute_value("power/wakeup", "disabled").ok();
} // }
} // }
} // }
} // }
let config = AnimeConfig::new().load();
let mut anime_type = get_anime_type()?; let mut anime_type = get_anime_type()?;
if let AnimeType::Unknown = anime_type { if let AnimeType::Unknown = anime_type {
if let Some(model) = config.model_override { if let Some(model) = config.model_override {
+205 -115
View File
@@ -1,7 +1,6 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait;
use config_traits::StdConfig; use config_traits::StdConfig;
use log::warn; use log::warn;
use logind_zbus::manager::ManagerProxy; use logind_zbus::manager::ManagerProxy;
@@ -11,13 +10,14 @@ use rog_anime::usb::{
}; };
use rog_anime::{Animations, AnimeDataBuffer, DeviceState}; use rog_anime::{Animations, AnimeDataBuffer, DeviceState};
use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::lock::Mutex;
use zbus::{dbus_interface, CacheProperties, Connection, SignalContext}; use zbus::{interface, CacheProperties, Connection, SignalContext};
use super::config::AnimeConfig;
use super::CtrlAnime; use super::CtrlAnime;
use crate::error::RogError; use crate::error::RogError;
pub const ANIME_ZBUS_NAME: &str = "Anime"; pub const ANIME_ZBUS_NAME: &str = "Anime";
pub const ANIME_ZBUS_PATH: &str = "/org/asuslinux/Anime"; pub const ANIME_ZBUS_PATH: &str = "/org/asuslinux";
async fn get_logind_manager<'a>() -> ManagerProxy<'a> { async fn get_logind_manager<'a>() -> ManagerProxy<'a> {
let connection = Connection::system() let connection = Connection::system()
@@ -35,7 +35,6 @@ async fn get_logind_manager<'a>() -> ManagerProxy<'a> {
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>); pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
/// The struct with the main dbus methods requires this trait /// The struct with the main dbus methods requires this trait
#[async_trait]
impl crate::ZbusRun for CtrlAnimeZbus { impl crate::ZbusRun for CtrlAnimeZbus {
async fn add_to_server(self, server: &mut Connection) { async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, ANIME_ZBUS_PATH, server).await; Self::add_to_server_helper(self, ANIME_ZBUS_PATH, server).await;
@@ -45,50 +44,61 @@ impl crate::ZbusRun for CtrlAnimeZbus {
// None of these calls can be guarnateed to succeed unless we loop until okay // None of these calls can be guarnateed to succeed unless we loop until okay
// If the try_lock *does* succeed then any other thread trying to lock will not // If the try_lock *does* succeed then any other thread trying to lock will not
// grab it until we finish. // grab it until we finish.
#[dbus_interface(name = "org.asuslinux.Daemon")] #[interface(name = "org.asuslinux.Anime")]
impl CtrlAnimeZbus { impl CtrlAnimeZbus {
/// Writes a data stream of length. Will force system thread to exit until /// Writes a data stream of length. Will force system thread to exit until
/// it is restarted /// it is restarted
async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> {
let lock = self.0.lock().await; self.0
lock.thread_exit.store(true, Ordering::SeqCst); .lock()
lock.write_data_buffer(input).map_err(|err| { .await
warn!("ctrl_anime::run_animation:callback {}", err); .thread_exit
err .store(true, Ordering::SeqCst);
})?; self.0
.lock()
.await
.write_data_buffer(input)
.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
err
})?;
Ok(()) Ok(())
} }
/// Set base brightness level /// Set base brightness level
#[dbus_interface(property)] #[zbus(property)]
async fn brightness(&self) -> Brightness { async fn brightness(&self) -> Brightness {
let lock = self.0.lock().await; self.0.lock().await.config.display_brightness
lock.config.display_brightness
} }
/// Set base brightness level /// Set base brightness level
#[dbus_interface(property)] #[zbus(property)]
async fn set_brightness(&self, brightness: Brightness) { async fn set_brightness(&self, brightness: Brightness) {
let mut lock = self.0.lock().await; self.0
lock.node .lock()
.await
.node
.write_bytes(&pkt_set_brightness(brightness)) .write_bytes(&pkt_set_brightness(brightness))
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::set_brightness {}", err); warn!("ctrl_anime::set_brightness {}", err);
}) })
.ok(); .ok();
lock.node self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(brightness != Brightness::Off)) .write_bytes(&pkt_set_enable_display(brightness != Brightness::Off))
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::set_brightness {}", err); warn!("ctrl_anime::set_brightness {}", err);
}) })
.ok(); .ok();
lock.config.display_enabled = brightness != Brightness::Off; self.0.lock().await.config.display_enabled = brightness != Brightness::Off;
lock.config.display_brightness = brightness; self.0.lock().await.config.display_brightness = brightness;
lock.config.write(); self.0.lock().await.config.write();
} }
#[dbus_interface(property)] #[zbus(property)]
async fn builtins_enabled(&self) -> bool { async fn builtins_enabled(&self) -> bool {
let lock = self.0.lock().await; let lock = self.0.lock().await;
lock.config.builtin_anims_enabled lock.config.builtin_anims_enabled
@@ -96,22 +106,29 @@ impl CtrlAnimeZbus {
/// Enable the builtin animations or not. This is quivalent to "Powersave /// Enable the builtin animations or not. This is quivalent to "Powersave
/// animations" in Armory crate /// animations" in Armory crate
#[dbus_interface(property)] #[zbus(property)]
async fn set_builtins_enabled(&self, enabled: bool) { async fn set_builtins_enabled(&self, enabled: bool) {
let mut lock = self.0.lock().await; let brightness = self.0.lock().await.config.display_brightness;
lock.node self.0
.set_builtins_enabled(enabled, lock.config.display_brightness) .lock()
.await
.node
.set_builtins_enabled(enabled, brightness)
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err); warn!("ctrl_anime::set_builtins_enabled {}", err);
}) })
.ok(); .ok();
if !enabled { if !enabled {
let data = vec![255u8; lock.anime_type.data_length()]; let anime_type = self.0.lock().await.anime_type;
if let Ok(tmp) = AnimeDataBuffer::from_vec(lock.anime_type, data).map_err(|err| { let data = vec![255u8; anime_type.data_length()];
if let Ok(tmp) = AnimeDataBuffer::from_vec(anime_type, data).map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err); warn!("ctrl_anime::set_builtins_enabled {}", err);
}) { }) {
lock.node self.0
.lock()
.await
.node
.write_bytes(tmp.data()) .write_bytes(tmp.data())
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err); warn!("ctrl_anime::set_builtins_enabled {}", err);
@@ -120,24 +137,29 @@ impl CtrlAnimeZbus {
} }
} }
lock.config.builtin_anims_enabled = enabled; self.0.lock().await.config.builtin_anims_enabled = enabled;
lock.config.write(); self.0.lock().await.config.write();
if enabled { if enabled {
lock.thread_exit.store(true, Ordering::Release); self.0
.lock()
.await
.thread_exit
.store(true, Ordering::Release);
} }
} }
#[dbus_interface(property)] #[zbus(property)]
async fn builtin_animations(&self) -> Animations { async fn builtin_animations(&self) -> Animations {
let lock = self.0.lock().await; self.0.lock().await.config.builtin_anims
lock.config.builtin_anims
} }
/// Set which builtin animation is used for each stage /// Set which builtin animation is used for each stage
#[dbus_interface(property)] #[zbus(property)]
async fn set_builtin_animations(&self, settings: Animations) { async fn set_builtin_animations(&self, settings: Animations) {
let mut lock = self.0.lock().await; self.0
lock.node .lock()
.await
.node
.write_bytes(&pkt_set_builtin_animations( .write_bytes(&pkt_set_builtin_animations(
settings.boot, settings.boot,
settings.awake, settings.awake,
@@ -148,118 +170,128 @@ impl CtrlAnimeZbus {
warn!("ctrl_anime::run_animation:callback {}", err); warn!("ctrl_anime::run_animation:callback {}", err);
}) })
.ok(); .ok();
lock.node self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(true)) .write_bytes(&pkt_set_enable_powersave_anim(true))
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err); warn!("ctrl_anime::run_animation:callback {}", err);
}) })
.ok(); .ok();
lock.config.display_enabled = true; self.0.lock().await.config.display_enabled = true;
lock.config.builtin_anims = settings; self.0.lock().await.config.builtin_anims = settings;
lock.config.write(); self.0.lock().await.config.write();
} }
#[dbus_interface(property)] #[zbus(property)]
async fn enable_display(&self) -> bool { async fn enable_display(&self) -> bool {
let lock = self.0.lock().await; self.0.lock().await.config.display_enabled
lock.config.display_enabled
} }
/// Set whether the AniMe is enabled at all /// Set whether the AniMe is enabled at all
#[dbus_interface(property)] #[zbus(property)]
async fn set_enable_display(&self, enabled: bool) { async fn set_enable_display(&self, enabled: bool) {
let mut lock = self.0.lock().await; self.0
lock.node .lock()
.await
.node
.write_bytes(&pkt_set_enable_display(enabled)) .write_bytes(&pkt_set_enable_display(enabled))
.map_err(|err| { .map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err); warn!("ctrl_anime::run_animation:callback {}", err);
}) })
.ok(); .ok();
lock.config.display_enabled = enabled; self.0.lock().await.config.display_enabled = enabled;
lock.config.write(); self.0.lock().await.config.write();
} }
#[dbus_interface(property)] #[zbus(property)]
async fn off_when_unplugged(&self) -> bool { async fn off_when_unplugged(&self) -> bool {
let lock = self.0.lock().await; self.0.lock().await.config.off_when_unplugged
lock.config.off_when_unplugged
} }
/// Set if to turn the AniMe Matrix off when external power is unplugged /// Set if to turn the AniMe Matrix off when external power is unplugged
#[dbus_interface(property)] #[zbus(property)]
async fn set_off_when_unplugged(&self, enabled: bool) { async fn set_off_when_unplugged(&self, enabled: bool) {
let mut lock = self.0.lock().await;
let manager = get_logind_manager().await; let manager = get_logind_manager().await;
let pow = manager.on_external_power().await.unwrap_or_default(); let pow = manager.on_external_power().await.unwrap_or_default();
lock.node self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(!pow && !enabled)) .write_bytes(&pkt_set_enable_display(!pow && !enabled))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err); warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
}) })
.ok(); .ok();
lock.config.off_when_unplugged = enabled; self.0.lock().await.config.off_when_unplugged = enabled;
lock.config.write(); self.0.lock().await.config.write();
} }
#[dbus_interface(property)] #[zbus(property)]
async fn off_when_suspended(&self) -> bool { async fn off_when_suspended(&self) -> bool {
let lock = self.0.lock().await; self.0.lock().await.config.off_when_suspended
lock.config.off_when_suspended
} }
/// Set if to turn the AniMe Matrix off when the laptop is suspended /// Set if to turn the AniMe Matrix off when the laptop is suspended
#[dbus_interface(property)] #[zbus(property)]
async fn set_off_when_suspended(&self, enabled: bool) { async fn set_off_when_suspended(&self, enabled: bool) {
let mut lock = self.0.lock().await; self.0.lock().await.config.off_when_suspended = enabled;
lock.config.off_when_suspended = enabled; self.0.lock().await.config.write();
lock.config.write();
} }
#[dbus_interface(property)] #[zbus(property)]
async fn off_when_lid_closed(&self) -> bool { async fn off_when_lid_closed(&self) -> bool {
let lock = self.0.lock().await; self.0.lock().await.config.off_when_lid_closed
lock.config.off_when_lid_closed
} }
/// Set if to turn the AniMe Matrix off when the lid is closed /// Set if to turn the AniMe Matrix off when the lid is closed
#[dbus_interface(property)] #[zbus(property)]
async fn set_off_when_lid_closed(&self, enabled: bool) { async fn set_off_when_lid_closed(&self, enabled: bool) {
let mut lock = self.0.lock().await;
let manager = get_logind_manager().await; let manager = get_logind_manager().await;
let lid = manager.lid_closed().await.unwrap_or_default(); let lid = manager.lid_closed().await.unwrap_or_default();
lock.node self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(lid && !enabled)) .write_bytes(&pkt_set_enable_display(lid && !enabled))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err); warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
}) })
.ok(); .ok();
lock.config.off_when_lid_closed = enabled; self.0.lock().await.config.off_when_lid_closed = enabled;
lock.config.write(); self.0.lock().await.config.write();
} }
/// The main loop is the base system set action if the user isn't running /// The main loop is the base system set action if the user isn't running
/// the user daemon /// the user daemon
async fn run_main_loop(&self, start: bool) { async fn run_main_loop(&self, start: bool) {
if start { if start {
let lock = self.0.lock().await; self.0
lock.thread_exit.store(true, Ordering::SeqCst); .lock()
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false).await; .await
.thread_exit
.store(true, Ordering::SeqCst);
CtrlAnime::run_thread(
self.0.clone(),
self.0.lock().await.cache.system.clone(),
false,
)
.await;
} }
} }
/// Get the device state as stored by asusd /// Get the device state as stored by asusd
// #[dbus_interface(property)] // #[zbus(property)]
async fn device_state(&self) -> DeviceState { async fn device_state(&self) -> DeviceState {
let lock = self.0.lock().await; DeviceState::from(&self.0.lock().await.config)
DeviceState::from(&lock.config)
} }
} }
#[async_trait]
impl crate::CtrlTask for CtrlAnimeZbus { impl crate::CtrlTask for CtrlAnimeZbus {
fn zbus_path() -> &'static str { fn zbus_path() -> &'static str {
ANIME_ZBUS_PATH ANIME_ZBUS_PATH
@@ -275,30 +307,53 @@ impl crate::CtrlTask for CtrlAnimeZbus {
// on_sleep // on_sleep
let inner = inner1.clone(); let inner = inner1.clone();
async move { async move {
let lock = inner.lock().await; let config = inner.lock().await.config.clone();
if lock.config.display_enabled { if config.display_enabled {
lock.node inner
.write_bytes(&pkt_set_enable_powersave_anim( .lock()
!(sleeping && lock.config.off_when_suspended), .await
)) .thread_exit
.map_err(|err| { .store(true, Ordering::Release); // ensure clean slate
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
lock.thread_exit.store(true, Ordering::Release); // ensure clean slate inner
lock.node .lock()
.await
.node
.write_bytes(&pkt_set_enable_display( .write_bytes(&pkt_set_enable_display(
!(sleeping && lock.config.off_when_suspended), !(sleeping && config.off_when_suspended),
)) ))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err); warn!("create_sys_event_tasks::off_when_suspended {}", err);
}) })
.ok(); .ok();
if !sleeping && !lock.config.builtin_anims_enabled { if config.builtin_anims_enabled {
CtrlAnime::run_thread(inner.clone(), lock.cache.wake.clone(), true) inner
.await; .lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(
!(sleeping && config.off_when_suspended),
))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
} else if !sleeping && !config.builtin_anims_enabled {
// Run custom wake animation
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(false))
.ok(); // ensure builtins are disabled
CtrlAnime::run_thread(
inner.clone(),
inner.lock().await.cache.wake.clone(),
true,
)
.await;
} }
} }
} }
@@ -307,14 +362,26 @@ impl crate::CtrlTask for CtrlAnimeZbus {
// on_shutdown // on_shutdown
let inner = inner2.clone(); let inner = inner2.clone();
async move { async move {
let lock = inner.lock().await; let AnimeConfig {
if lock.config.display_enabled && !lock.config.builtin_anims_enabled { display_enabled,
builtin_anims_enabled,
..
} = inner.lock().await.config;
if display_enabled && !builtin_anims_enabled {
if shutting_down { if shutting_down {
CtrlAnime::run_thread(inner.clone(), lock.cache.shutdown.clone(), true) CtrlAnime::run_thread(
.await; inner.clone(),
inner.lock().await.cache.shutdown.clone(),
true,
)
.await;
} else { } else {
CtrlAnime::run_thread(inner.clone(), lock.cache.boot.clone(), true) CtrlAnime::run_thread(
.await; inner.clone(),
inner.lock().await.cache.boot.clone(),
true,
)
.await;
} }
} }
} }
@@ -323,17 +390,27 @@ impl crate::CtrlTask for CtrlAnimeZbus {
let inner = inner3.clone(); let inner = inner3.clone();
// on lid change // on lid change
async move { async move {
let lock = inner.lock().await; let AnimeConfig {
if lock.config.off_when_lid_closed { off_when_lid_closed,
if lock.config.builtin_anims_enabled { builtin_anims_enabled,
lock.node ..
} = inner.lock().await.config;
if off_when_lid_closed {
if builtin_anims_enabled {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(!lid_closed)) .write_bytes(&pkt_set_enable_powersave_anim(!lid_closed))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err); warn!("create_sys_event_tasks::off_when_suspended {}", err);
}) })
.ok(); .ok();
} }
lock.node inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(!lid_closed)) .write_bytes(&pkt_set_enable_display(!lid_closed))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err); warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
@@ -346,25 +423,39 @@ impl crate::CtrlTask for CtrlAnimeZbus {
let inner = inner4.clone(); let inner = inner4.clone();
// on power change // on power change
async move { async move {
let lock = inner.lock().await; let AnimeConfig {
if lock.config.off_when_unplugged { off_when_unplugged,
if lock.config.builtin_anims_enabled { builtin_anims_enabled,
lock.node brightness_on_battery,
..
} = inner.lock().await.config;
if off_when_unplugged {
if builtin_anims_enabled {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(power_plugged)) .write_bytes(&pkt_set_enable_powersave_anim(power_plugged))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err); warn!("create_sys_event_tasks::off_when_suspended {}", err);
}) })
.ok(); .ok();
} }
lock.node inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(power_plugged)) .write_bytes(&pkt_set_enable_display(power_plugged))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_unplugged {}", err); warn!("create_sys_event_tasks::off_when_unplugged {}", err);
}) })
.ok(); .ok();
} else { } else {
lock.node inner
.write_bytes(&pkt_set_brightness(lock.config.brightness_on_battery)) .lock()
.await
.node
.write_bytes(&pkt_set_brightness(brightness_on_battery))
.map_err(|err| { .map_err(|err| {
warn!("create_sys_event_tasks::off_when_unplugged {}", err); warn!("create_sys_event_tasks::off_when_unplugged {}", err);
}) })
@@ -379,7 +470,6 @@ impl crate::CtrlTask for CtrlAnimeZbus {
} }
} }
#[async_trait]
impl crate::Reloadable for CtrlAnimeZbus { impl crate::Reloadable for CtrlAnimeZbus {
async fn reload(&mut self) -> Result<(), RogError> { async fn reload(&mut self) -> Result<(), RogError> {
if let Some(lock) = self.0.try_lock() { if let Some(lock) = self.0.try_lock() {
+31 -142
View File
@@ -1,167 +1,60 @@
use std::collections::{BTreeMap, HashSet}; use std::collections::BTreeMap;
use config_traits::{StdConfig, StdConfigLoad}; use config_traits::{StdConfig, StdConfigLoad};
use log::{debug, warn}; use log::{debug, info, warn};
use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use rog_aura::aura_detection::LedSupportData;
use rog_aura::power::AuraPower; use rog_aura::keyboard::LaptopAuraPower;
use rog_aura::usb::{AuraDevRog1, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; AuraDeviceType, AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT,
use rog_platform::hid_raw::HidRaw; };
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "aura.ron"; #[derive(Deserialize, Serialize, Default, Debug, Clone)]
/// Enable/disable LED control in various states such as
/// when the device is awake, suspended, shutting down or
/// booting.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AuraPowerConfig {
AuraDevTuf(HashSet<AuraDevTuf>),
AuraDevRog1(HashSet<AuraDevRog1>),
AuraDevRog2(AuraPower),
}
impl AuraPowerConfig {
/// Invalid for TUF laptops
pub fn to_bytes(control: &Self) -> [u8; 4] {
match control {
AuraPowerConfig::AuraDevTuf(_) => [0, 0, 0, 0],
AuraPowerConfig::AuraDevRog1(c) => {
let c: Vec<AuraDevRog1> = c.iter().copied().collect();
AuraDevRog1::to_bytes(&c)
}
AuraPowerConfig::AuraDevRog2(c) => c.to_bytes(),
}
}
pub fn to_tuf_bool_array(control: &Self) -> Option<[bool; 5]> {
if let Self::AuraDevTuf(c) = control {
return Some([
true,
c.contains(&AuraDevTuf::Boot),
c.contains(&AuraDevTuf::Awake),
c.contains(&AuraDevTuf::Sleep),
c.contains(&AuraDevTuf::Keyboard),
]);
}
if let Self::AuraDevRog1(c) = control {
return Some([
true,
c.contains(&AuraDevRog1::Boot),
c.contains(&AuraDevRog1::Awake),
c.contains(&AuraDevRog1::Sleep),
c.contains(&AuraDevRog1::Keyboard),
]);
}
None
}
pub fn set_tuf(&mut self, power: AuraDevTuf, on: bool) {
if let Self::AuraDevTuf(p) = self {
if on {
p.insert(power);
} else {
p.remove(&power);
}
}
}
pub fn set_0x1866(&mut self, power: AuraDevRog1, on: bool) {
if let Self::AuraDevRog1(p) = self {
if on {
p.insert(power);
} else {
p.remove(&power);
}
}
}
pub fn set_0x19b6(&mut self, power: AuraPower) {
if let Self::AuraDevRog2(p) = self {
*p = power;
}
}
}
impl From<&AuraPowerConfig> for AuraPowerDev {
fn from(config: &AuraPowerConfig) -> Self {
match config {
AuraPowerConfig::AuraDevTuf(d) => AuraPowerDev {
tuf: d.iter().copied().collect(),
..Default::default()
},
AuraPowerConfig::AuraDevRog1(d) => AuraPowerDev {
old_rog: d.iter().copied().collect(),
..Default::default()
},
AuraPowerConfig::AuraDevRog2(d) => AuraPowerDev {
rog: d.clone(),
..Default::default()
},
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
// #[serde(default)] // #[serde(default)]
pub struct AuraConfig { pub struct AuraConfig {
pub config_name: String,
pub brightness: LedBrightness, pub brightness: LedBrightness,
pub current_mode: AuraModeNum, pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>, pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub multizone: Option<BTreeMap<AuraModeNum, Vec<AuraEffect>>>, pub multizone: Option<BTreeMap<AuraModeNum, Vec<AuraEffect>>>,
pub multizone_on: bool, pub multizone_on: bool,
pub enabled: AuraPowerConfig, pub enabled: LaptopAuraPower,
} }
impl StdConfig for AuraConfig { impl StdConfig for AuraConfig {
/// Detect the keyboard type and load from default DB if data available /// Detect the keyboard type and load from default DB if data available
fn new() -> Self { fn new() -> Self {
warn!("AuraConfig: creating new config"); panic!("This should not be used");
let mut prod_id = AuraDevice::Unknown; }
for prod in ASUS_KEYBOARD_DEVICES {
if HidRaw::new(prod.into()).is_ok() { fn file_name(&self) -> String {
prod_id = prod; if self.config_name.is_empty() {
break; panic!("Config file name should not be empty");
}
} }
Self::from_default_support(prod_id, &LaptopLedData::get_data()) self.config_name.to_owned()
} }
fn config_dir() -> std::path::PathBuf { fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE) std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
} }
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
} }
impl StdConfigLoad for AuraConfig {} impl StdConfigLoad for AuraConfig {}
impl AuraConfig { impl AuraConfig {
pub fn from_default_support(prod_id: AuraDevice, support_data: &LaptopLedData) -> Self { /// Detect the keyboard type and load from default DB if data available
pub fn new(prod_id: &str) -> Self {
info!("Setting up AuraConfig for {prod_id:?}");
// create a default config here // create a default config here
let enabled = if prod_id.is_new_style() { let device_type = AuraDeviceType::from(prod_id);
AuraPowerConfig::AuraDevRog2(AuraPower::new_all_on()) if device_type == AuraDeviceType::Unknown {
} else if prod_id.is_tuf_style() { warn!("idProduct:{prod_id:?} is unknown");
AuraPowerConfig::AuraDevTuf(HashSet::from([ }
AuraDevTuf::Awake, let support_data = LedSupportData::get_data(prod_id);
AuraDevTuf::Boot, let enabled = LaptopAuraPower::new(device_type, &support_data);
AuraDevTuf::Sleep,
AuraDevTuf::Keyboard,
]))
} else {
AuraPowerConfig::AuraDevRog1(HashSet::from([
AuraDevRog1::Awake,
AuraDevRog1::Boot,
AuraDevRog1::Sleep,
AuraDevRog1::Keyboard,
AuraDevRog1::Lightbar,
]))
};
let mut config = AuraConfig { let mut config = AuraConfig {
config_name: format!("aura_{prod_id}.ron"),
brightness: LedBrightness::Med, brightness: LedBrightness::Med,
current_mode: AuraModeNum::Static, current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(), builtins: BTreeMap::new(),
@@ -171,7 +64,7 @@ impl AuraConfig {
}; };
for n in &support_data.basic_modes { for n in &support_data.basic_modes {
debug!("AuraConfig: creating default for {n}"); debug!("creating default for {n}");
config config
.builtins .builtins
.insert(*n, AuraEffect::default_with_mode(*n)); .insert(*n, AuraEffect::default_with_mode(*n));
@@ -241,16 +134,13 @@ impl AuraConfig {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rog_aura::aura_detection::LaptopLedData;
use rog_aura::usb::AuraDevice;
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour};
use super::AuraConfig; use super::AuraConfig;
#[test] #[test]
fn set_multizone_4key_config() { fn set_multizone_4key_config() {
let mut config = let mut config = AuraConfig::new("19b6");
AuraConfig::from_default_support(AuraDevice::X19b6, &LaptopLedData::default());
let effect = AuraEffect { let effect = AuraEffect {
colour1: Colour { colour1: Colour {
@@ -340,8 +230,7 @@ mod tests {
#[test] #[test]
fn set_multizone_multimode_config() { fn set_multizone_multimode_config() {
let mut config = let mut config = AuraConfig::new("19b6");
AuraConfig::from_default_support(AuraDevice::X19b6, &LaptopLedData::default());
let effect = AuraEffect { let effect = AuraEffect {
zone: AuraZone::Key1, zone: AuraZone::Key1,
+190 -95
View File
@@ -1,82 +1,176 @@
use std::collections::BTreeMap; use std::collections::{BTreeMap, HashSet};
use config_traits::{StdConfig, StdConfigLoad}; use config_traits::{StdConfig, StdConfigLoad};
use dmi_id::DMIID; use inotify::Inotify;
use log::{info, warn}; use log::{debug, info, warn};
use rog_aura::advanced::{LedUsbPackets, UsbPackets}; use rog_aura::aura_detection::LedSupportData;
use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use rog_aura::keyboard::{LedUsbPackets, UsbPackets};
use rog_aura::usb::{AuraDevice, LED_APPLY, LED_SET}; use rog_aura::usb::{LED_APPLY, LED_SET};
use rog_aura::{AuraEffect, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN}; use rog_aura::{
AuraDeviceType, AuraEffect, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN,
};
use rog_platform::hid_raw::HidRaw; use rog_platform::hid_raw::HidRaw;
use rog_platform::keyboard_led::KeyboardLed; use rog_platform::keyboard_led::KeyboardLed;
use zbus::zvariant::OwnedObjectPath;
use super::config::{AuraConfig, AuraPowerConfig}; use super::config::AuraConfig;
use crate::ctrl_aura::manager::{dbus_path_for_dev, dbus_path_for_tuf};
use crate::error::RogError; use crate::error::RogError;
#[derive(Debug)] #[derive(Debug)]
pub enum LEDNode { pub enum LEDNode {
/// Brightness and/or TUF RGB controls
KbdLed(KeyboardLed), KbdLed(KeyboardLed),
Rog(HidRaw), /// Raw HID handle
None, Rog(KeyboardLed, HidRaw),
} }
impl LEDNode {
// TODO: move various methods upwards to this
pub fn set_brightness(&self, value: u8) -> Result<(), RogError> {
match self {
LEDNode::KbdLed(k) => k.set_brightness(value)?,
LEDNode::Rog(k, _) => k.set_brightness(value)?,
}
Ok(())
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
Ok(match self {
LEDNode::KbdLed(k) => k.get_brightness()?,
LEDNode::Rog(k, _) => k.get_brightness()?,
})
}
pub fn monitor_brightness(&self) -> Result<Inotify, RogError> {
Ok(match self {
LEDNode::KbdLed(k) => k.monitor_brightness()?,
LEDNode::Rog(k, _) => k.monitor_brightness()?,
})
}
}
/// Individual controller for one Aura device
pub struct CtrlKbdLed { pub struct CtrlKbdLed {
// TODO: config stores the keyboard type as an AuraPower, use or update this pub led_type: AuraDeviceType,
pub led_prod: AuraDevice,
pub led_node: LEDNode, pub led_node: LEDNode,
pub sysfs_node: KeyboardLed, pub supported_data: LedSupportData, // TODO: is storing this really required?
pub supported_modes: LaptopLedData,
pub per_key_mode_active: bool, pub per_key_mode_active: bool,
pub config: AuraConfig, pub config: AuraConfig,
pub dbus_path: OwnedObjectPath,
} }
impl CtrlKbdLed { impl CtrlKbdLed {
pub fn new(supported_modes: LaptopLedData) -> Result<Self, RogError> { pub fn find_all() -> Result<Vec<Self>, RogError> {
let mut led_prod = AuraDevice::Unknown; info!("Searching for all Aura devices");
let mut usb_node = None; let mut devices = Vec::new();
for prod in ASUS_KEYBOARD_DEVICES { let mut found = HashSet::new(); // track and ensure we use only one hidraw per prod_id
match HidRaw::new(prod.into()) {
Ok(node) => { let mut enumerator = udev::Enumerator::new().map_err(|err| {
led_prod = prod; warn!("{}", err);
usb_node = Some(node); err
info!( })?;
"Looked for keyboard controller 0x{}: Found",
<&str>::from(prod) enumerator.match_subsystem("hidraw").map_err(|err| {
); warn!("{}", err);
break; err
})?;
for end_point in enumerator.scan_devices()? {
// usb_device gives us a product and vendor ID
if let Some(usb_device) =
end_point.parent_with_subsystem_devtype("usb", "usb_device")?
{
// The asus_wmi driver latches MCU that controls the USB endpoints
if let Some(parent) = end_point.parent() {
if let Some(driver) = parent.driver() {
// There is a tree of devices added so filter by driver
if driver != "asus" {
continue;
}
} else {
continue;
}
} }
Err(err) => info!( // Device is something like 002, while its parent is the MCU
"Looked for keyboard controller 0x{}: {err}", // Think of it like the device is an endpoint of the USB device attached
<&str>::from(prod) let mut prod_id = String::new();
), if let Some(usb_id) = usb_device.attribute_value("idProduct") {
prod_id = usb_id.to_string_lossy().to_string();
let aura_dev = AuraDeviceType::from(prod_id.as_str());
if aura_dev == AuraDeviceType::Unknown || found.contains(&aura_dev) {
log::debug!("Unknown or invalid device: {usb_id:?}, skipping");
continue;
}
found.insert(aura_dev);
}
let dev_node = if let Some(dev_node) = usb_device.devnode() {
dev_node
} else {
debug!("Device has no devnode, skipping");
continue;
};
info!("AuraControl found device at: {:?}", dev_node);
let dbus_path = dbus_path_for_dev(&usb_device).unwrap_or_default();
let dev = HidRaw::from_device(end_point)?;
let mut dev = Self::from_hidraw(dev, dbus_path)?;
dev.config = Self::init_config(&prod_id);
devices.push(dev);
} }
} }
// Check for a TUF laptop LED. Assume there is only ever one.
if let Ok(kbd_backlight) = KeyboardLed::new() {
if kbd_backlight.has_kbd_rgb_mode() {
info!("AuraControl found a TUF laptop keyboard");
let ctrl = CtrlKbdLed {
led_type: AuraDeviceType::LaptopTuf,
led_node: LEDNode::KbdLed(kbd_backlight),
supported_data: LedSupportData::get_data("tuf"),
per_key_mode_active: false,
config: Self::init_config("tuf"),
dbus_path: dbus_path_for_tuf(),
};
devices.push(ctrl);
}
}
info!("Found {} Aura devices", devices.len());
Ok(devices)
}
/// The generated data from this function has a default config. This config
/// should be overwritten. The reason for the default config is because
/// of async issues between this and udev/hidraw
pub fn from_hidraw(device: HidRaw, dbus_path: OwnedObjectPath) -> Result<Self, RogError> {
let rgb_led = KeyboardLed::new()?; let rgb_led = KeyboardLed::new()?;
let prod_id = AuraDeviceType::from(device.prod_id());
if usb_node.is_none() && !rgb_led.has_kbd_rgb_mode() { if prod_id == AuraDeviceType::Unknown {
let dmi = DMIID::new().unwrap_or_default(); log::error!("{} is AuraDevice::Unknown", device.prod_id());
if dmi.dmi_family.contains("TUF") { return Err(RogError::NoAuraNode);
warn!(
"kbd_rgb_mode was not found in the /sys/. You require a minimum 6.1 kernel \
and a supported TUF laptop"
);
}
return Err(RogError::NoAuraKeyboard);
} }
let led_node = if let Some(rog) = usb_node { // New loads data from the DB also
info!("Found ROG USB keyboard"); // let config = Self::init_config(prod_id, data);
LEDNode::Rog(rog)
} else if rgb_led.has_kbd_rgb_mode() {
info!("Found TUF keyboard");
LEDNode::KbdLed(rgb_led.clone())
} else {
LEDNode::None
};
// New loads data fromt he DB also let data = LedSupportData::get_data(device.prod_id());
let mut config_init = AuraConfig::new(); let ctrl = CtrlKbdLed {
led_type: prod_id,
led_node: LEDNode::Rog(rgb_led, device),
supported_data: data.clone(),
per_key_mode_active: false,
config: AuraConfig::default(),
dbus_path,
};
Ok(ctrl)
}
pub fn init_config(prod_id: &str) -> AuraConfig {
// New loads data from the DB also
let mut config_init = AuraConfig::new(prod_id);
// config_init.set_filename(prod_id);
let mut config_loaded = config_init.clone().load(); let mut config_loaded = config_init.clone().load();
// update the initialised data with what we loaded from disk // update the initialised data with what we loaded from disk
for mode in &mut config_init.builtins { for mode in &mut config_init.builtins {
@@ -95,9 +189,10 @@ impl CtrlKbdLed {
// update init values from loaded values if they exist // update init values from loaded values if they exist
if let Some(loaded) = multizone_loaded.get(mode.0) { if let Some(loaded) = multizone_loaded.get(mode.0) {
let mut new_set = Vec::new(); let mut new_set = Vec::new();
let data = LedSupportData::get_data(prod_id);
// only reuse a zone mode if the mode is supported // only reuse a zone mode if the mode is supported
for mode in loaded { for mode in loaded {
if supported_modes.basic_modes.contains(&mode.mode) { if data.basic_modes.contains(&mode.mode) {
new_set.push(mode.clone()); new_set.push(mode.clone());
} }
} }
@@ -107,27 +202,21 @@ impl CtrlKbdLed {
*multizone_loaded = multizone_init; *multizone_loaded = multizone_init;
} }
let ctrl = CtrlKbdLed { config_loaded
led_prod,
led_node, // on TUF this is the same as rgb_led / kd_brightness
sysfs_node: rgb_led, // If was none then we already returned above
supported_modes,
per_key_mode_active: false,
config: config_loaded,
};
Ok(ctrl)
} }
/// Set combination state for boot animation/sleep animation/all leds/keys /// Set combination state for boot animation/sleep animation/all leds/keys
/// leds/side leds LED active /// leds/side leds LED active
pub(super) fn set_power_states(&mut self) -> Result<(), RogError> { pub(super) fn set_power_states(&mut self) -> Result<(), RogError> {
if let LEDNode::KbdLed(platform) = &mut self.led_node { if let LEDNode::KbdLed(_platform) = &mut self.led_node {
if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) { // TODO: tuf bool array
let buf = [1, pwr[1] as u8, pwr[2] as u8, pwr[3] as u8, pwr[4] as u8]; // if let Some(pwr) =
platform.set_kbd_rgb_state(&buf)?; // AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) {
} // let buf = [1, pwr[1] as u8, pwr[2] as u8, pwr[3] as u8,
} else if let LEDNode::Rog(hid_raw) = &self.led_node { // pwr[4] as u8]; platform.set_kbd_rgb_state(&buf)?;
let bytes = AuraPowerConfig::to_bytes(&self.config.enabled); // }
} else if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let bytes = self.config.enabled.to_bytes(self.led_type);
let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3]]; let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3]];
hid_raw.write_bytes(&message)?; hid_raw.write_bytes(&message)?;
@@ -152,20 +241,20 @@ impl CtrlKbdLed {
if pkt_type != PER_KEY_TYPE { if pkt_type != PER_KEY_TYPE {
self.per_key_mode_active = false; self.per_key_mode_active = false;
if let LEDNode::Rog(hid_raw) = &self.led_node { if let LEDNode::Rog(_, hid_raw) = &self.led_node {
hid_raw.write_bytes(&effect[0])?; hid_raw.write_bytes(&effect[0])?;
hid_raw.write_bytes(&LED_SET)?; hid_raw.write_bytes(&LED_SET)?;
// hid_raw.write_bytes(&LED_APPLY)?; // hid_raw.write_bytes(&LED_APPLY)?;
} }
} else { } else {
if !self.per_key_mode_active { if !self.per_key_mode_active {
if let LEDNode::Rog(hid_raw) = &self.led_node { if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let init = LedUsbPackets::get_init_msg(); let init = LedUsbPackets::get_init_msg();
hid_raw.write_bytes(&init)?; hid_raw.write_bytes(&init)?;
} }
self.per_key_mode_active = true; self.per_key_mode_active = true;
} }
if let LEDNode::Rog(hid_raw) = &self.led_node { if let LEDNode::Rog(_, hid_raw) = &self.led_node {
for row in effect.iter() { for row in effect.iter() {
hid_raw.write_bytes(row)?; hid_raw.write_bytes(row)?;
} }
@@ -192,7 +281,7 @@ impl CtrlKbdLed {
mode.speed as u8, mode.speed as u8,
]; ];
platform.set_kbd_rgb_mode(&buf)?; platform.set_kbd_rgb_mode(&buf)?;
} else if let LEDNode::Rog(hid_raw) = &self.led_node { } else if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let bytes: [u8; LED_MSG_LEN] = mode.into(); let bytes: [u8; LED_MSG_LEN] = mode.into();
hid_raw.write_bytes(&bytes)?; hid_raw.write_bytes(&bytes)?;
hid_raw.write_bytes(&LED_SET)?; hid_raw.write_bytes(&LED_SET)?;
@@ -245,7 +334,7 @@ impl CtrlKbdLed {
/// exists. /// exists.
fn create_multizone_default(&mut self) -> Result<(), RogError> { fn create_multizone_default(&mut self) -> Result<(), RogError> {
let mut default = vec![]; let mut default = vec![];
for (i, tmp) in self.supported_modes.basic_zones.iter().enumerate() { for (i, tmp) in self.supported_data.basic_zones.iter().enumerate() {
default.push(AuraEffect { default.push(AuraEffect {
mode: self.config.current_mode, mode: self.config.current_mode,
zone: *tmp, zone: *tmp,
@@ -272,42 +361,45 @@ impl CtrlKbdLed {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rog_aura::aura_detection::{LaptopLedData, PowerZones}; use rog_aura::aura_detection::LedSupportData;
use rog_aura::usb::AuraDevice; use rog_aura::{AuraDeviceType, AuraModeNum, AuraZone, PowerZones};
use rog_aura::{AuraModeNum, AuraZone}; use rog_platform::hid_raw::HidRaw;
use rog_platform::keyboard_led::KeyboardLed; use rog_platform::keyboard_led::KeyboardLed;
use zbus::zvariant::OwnedObjectPath;
use super::CtrlKbdLed; use super::CtrlKbdLed;
use crate::ctrl_aura::config::AuraConfig; use crate::ctrl_aura::config::AuraConfig;
use crate::ctrl_aura::controller::LEDNode; use crate::ctrl_aura::controller::LEDNode;
#[test] #[test]
#[ignore = "Unable to run in CI as the HIDRAW device is required"]
fn create_multizone_if_no_config() { fn create_multizone_if_no_config() {
// Checking to ensure set_mode errors when unsupported modes are tried // Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::from_default_support(AuraDevice::X19b6, &LaptopLedData::default()); let config = AuraConfig::new("19b6");
let supported_modes = LaptopLedData { let supported_basic_modes = LedSupportData {
board_name: String::new(), device_name: String::new(),
product_id: String::new(),
layout_name: "ga401".to_owned(), layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static], basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![], basic_zones: vec![],
advanced_type: rog_aura::AdvancedAuraType::None, advanced_type: rog_aura::keyboard::AdvancedAuraType::None,
power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow], power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow],
}; };
let mut controller = CtrlKbdLed { let mut controller = CtrlKbdLed {
led_prod: AuraDevice::X19b6, led_type: AuraDeviceType::LaptopPost2021,
led_node: LEDNode::None, led_node: LEDNode::Rog(KeyboardLed::default(), HidRaw::new("19b6").unwrap()),
sysfs_node: KeyboardLed::default(), supported_data: supported_basic_modes,
supported_modes,
per_key_mode_active: false, per_key_mode_active: false,
config, config,
dbus_path: OwnedObjectPath::default(),
}; };
assert!(controller.config.multizone.is_none()); assert!(controller.config.multizone.is_none());
assert!(controller.create_multizone_default().is_err()); assert!(controller.create_multizone_default().is_err());
assert!(controller.config.multizone.is_none()); assert!(controller.config.multizone.is_none());
controller.supported_modes.basic_zones.push(AuraZone::Key1); controller.supported_data.basic_zones.push(AuraZone::Key1);
controller.supported_modes.basic_zones.push(AuraZone::Key2); controller.supported_data.basic_zones.push(AuraZone::Key2);
assert!(controller.create_multizone_default().is_ok()); assert!(controller.create_multizone_default().is_ok());
assert!(controller.config.multizone.is_some()); assert!(controller.config.multizone.is_some());
@@ -320,24 +412,27 @@ mod tests {
} }
#[test] #[test]
#[ignore = "Unable to run in CI as the HIDRAW device is required"]
// TODO: use sim device
fn next_mode_create_multizone_if_no_config() { fn next_mode_create_multizone_if_no_config() {
// Checking to ensure set_mode errors when unsupported modes are tried // Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::from_default_support(AuraDevice::X19b6, &LaptopLedData::default()); let config = AuraConfig::new("19b6");
let supported_modes = LaptopLedData { let supported_basic_modes = LedSupportData {
board_name: String::new(), device_name: String::new(),
product_id: String::new(),
layout_name: "ga401".to_owned(), layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static], basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![AuraZone::Key1, AuraZone::Key2], basic_zones: vec![AuraZone::Key1, AuraZone::Key2],
advanced_type: rog_aura::AdvancedAuraType::None, advanced_type: rog_aura::keyboard::AdvancedAuraType::None,
power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow], power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow],
}; };
let mut controller = CtrlKbdLed { let mut controller = CtrlKbdLed {
led_prod: AuraDevice::X19b6, led_type: AuraDeviceType::LaptopPost2021,
led_node: LEDNode::None, led_node: LEDNode::Rog(KeyboardLed::default(), HidRaw::new("19b6").unwrap()),
sysfs_node: KeyboardLed::default(), supported_data: supported_basic_modes,
supported_modes,
per_key_mode_active: false, per_key_mode_active: false,
config, config,
dbus_path: OwnedObjectPath::default(),
}; };
assert!(controller.config.multizone.is_none()); assert!(controller.config.multizone.is_none());
+187
View File
@@ -0,0 +1,187 @@
// Plan:
// - Manager has udev monitor on USB looking for ROG devices
// - If a device is found, add it to watch
// - Add it to Zbus server
// - If udev sees device removed then remove the zbus path
use std::collections::HashSet;
use log::{debug, error, info, warn};
use mio::{Events, Interest, Poll, Token};
use rog_aura::AuraDeviceType;
use rog_platform::hid_raw::HidRaw;
use tokio::task::spawn_blocking;
use udev::{Device, MonitorBuilder};
use zbus::object_server::SignalContext;
use zbus::zvariant::{ObjectPath, OwnedObjectPath};
use zbus::Connection;
use crate::ctrl_aura::controller::CtrlKbdLed;
use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_PATH};
use crate::error::RogError;
use crate::{CtrlTask, Reloadable};
pub struct AuraManager {
_connection: Connection,
}
impl AuraManager {
pub async fn new(connection: Connection) -> Result<Self, RogError> {
let conn_copy = connection.clone();
let mut interfaces = HashSet::new();
// Do the initial keyboard detection:
let all = CtrlKbdLed::find_all()?;
for ctrl in all {
let path = ctrl.dbus_path.clone();
interfaces.insert(path.clone()); // ensure we record the initial stuff
let sig_ctx = CtrlAuraZbus::signal_context(&connection)?;
let sig_ctx2 = sig_ctx.clone();
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
start_tasks(zbus, connection.clone(), sig_ctx2, path).await?;
}
let manager = Self {
_connection: connection,
};
// detect all plugged in aura devices (eventually)
// only USB devices are detected for here
spawn_blocking(move || {
let mut monitor = MonitorBuilder::new()?.match_subsystem("hidraw")?.listen()?;
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);
poll.registry()
.register(&mut monitor, Token(0), Interest::READABLE)?;
loop {
if poll.poll(&mut events, None).is_err() {
continue;
}
for event in monitor.iter() {
let parent = if let Some(parent) =
event.parent_with_subsystem_devtype("usb", "usb_device")?
{
parent
} else {
continue;
};
let action = if let Some(action) = event.action() {
action
} else {
continue;
};
let id_product = if let Some(id_product) = parent.attribute_value("idProduct") {
id_product.to_string_lossy()
} else {
continue;
};
let path = if let Some(path) = dbus_path_for_dev(&parent) {
path
} else {
continue;
};
let aura_device = AuraDeviceType::from(&*id_product);
if aura_device == AuraDeviceType::Unknown {
warn!("idProduct:{id_product:?} is unknown, not using");
continue;
}
if action == "remove" {
if interfaces.remove(&path) {
info!("AuraManager removing: {path:?}");
let conn_copy = conn_copy.clone();
tokio::spawn(async move {
let res = conn_copy
.object_server()
.remove::<CtrlAuraZbus, _>(&path)
.await
.map_err(|e| {
error!("Failed to remove {path:?}, {e:?}");
e
})?;
info!("AuraManager removed: {path:?}, {res}");
Ok::<(), RogError>(())
});
}
} else if action == "add" {
if interfaces.contains(&path) {
debug!("Already a ctrl at {path:?}");
continue;
}
// Need to check the driver is asus to prevent using hid_generic
if let Some(p2) = event.parent() {
if let Some(driver) = p2.driver() {
// There is a tree of devices added so filter by driver
if driver != "asus" {
debug!("{id_product:?} driver was not asus, skipping");
continue;
}
} else {
continue;
}
}
if let Some(dev_node) = event.devnode() {
if let Ok(raw) = HidRaw::from_device(event.device())
.map_err(|e| error!("device path error: {e:?}"))
{
if let Ok(mut ctrl) = CtrlKbdLed::from_hidraw(raw, path.clone()) {
ctrl.config = CtrlKbdLed::init_config(&id_product);
interfaces.insert(path.clone());
info!("AuraManager starting device at: {dev_node:?}, {path:?}");
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
let conn_copy = conn_copy.clone();
tokio::spawn(async move {
start_tasks(zbus, conn_copy.clone(), sig_ctx, path).await
});
}
}
}
};
}
}
// Required for return type on spawn
#[allow(unreachable_code)]
Ok::<(), RogError>(())
});
Ok(manager)
}
}
pub(crate) fn dbus_path_for_dev(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(filename) = super::filename_partial(parent) {
return Some(
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/{filename}")).into(),
);
}
None
}
pub(crate) fn dbus_path_for_tuf() -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/tuf")).into()
}
async fn start_tasks(
mut zbus: CtrlAuraZbus,
connection: Connection,
_signal_ctx: SignalContext<'static>,
path: OwnedObjectPath,
) -> Result<(), RogError> {
// let task = zbus.clone();
// let signal_ctx = signal_ctx.clone();
zbus.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
connection.object_server().at(path, zbus).await.unwrap();
// TODO: skip this until we keep handles to tasks so they can be killed
// task.create_tasks(signal_ctx).await
Ok(())
}
+25
View File
@@ -1,4 +1,29 @@
use udev::Device;
use zbus::zvariant::{ObjectPath, OwnedObjectPath};
pub mod config; pub mod config;
pub mod controller; pub mod controller;
pub mod manager;
/// Implements `CtrlTask`, `Reloadable`, `ZbusRun` /// Implements `CtrlTask`, `Reloadable`, `ZbusRun`
pub mod trait_impls; pub mod trait_impls;
/// Returns only the Device details concatenated in a form usable for
/// adding/appending to a filename
pub(super) fn filename_partial(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(id_product) = parent.attribute_value("idProduct") {
let id_product = id_product.to_string_lossy();
let path = if let Some(devnum) = parent.attribute_value("devnum") {
let devnum = devnum.to_string_lossy();
if let Some(devpath) = parent.attribute_value("devpath") {
let devpath = devpath.to_string_lossy();
format!("{id_product}_{devnum}_{devpath}")
} else {
format!("{id_product}_{devnum}")
}
} else {
format!("{id_product}")
};
return Some(ObjectPath::from_str_unchecked(&path).into());
}
None
}
+91 -74
View File
@@ -1,30 +1,32 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait;
use config_traits::StdConfig; use config_traits::StdConfig;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use rog_aura::advanced::UsbPackets; use rog_aura::keyboard::{LaptopAuraPower, UsbPackets};
use rog_aura::usb::{AuraDevice, AuraPowerDev}; use rog_aura::{AuraDeviceType, AuraEffect, AuraModeNum, AuraZone, LedBrightness, PowerZones};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness};
use zbus::export::futures_util::lock::{Mutex, MutexGuard}; use zbus::export::futures_util::lock::{Mutex, MutexGuard};
use zbus::export::futures_util::StreamExt; use zbus::export::futures_util::StreamExt;
use zbus::fdo::Error as ZbErr; use zbus::fdo::Error as ZbErr;
use zbus::{dbus_interface, Connection, SignalContext}; use zbus::{interface, SignalContext};
use super::controller::CtrlKbdLed; use super::controller::CtrlKbdLed;
use crate::error::RogError; use crate::error::RogError;
use crate::CtrlTask; use crate::CtrlTask;
pub const AURA_ZBUS_NAME: &str = "Aura"; pub const AURA_ZBUS_NAME: &str = "Aura";
pub const AURA_ZBUS_PATH: &str = "/org/asuslinux/Aura"; pub const AURA_ZBUS_PATH: &str = "/org/asuslinux";
#[derive(Clone)] #[derive(Clone)]
pub struct CtrlAuraZbus(pub Arc<Mutex<CtrlKbdLed>>); pub struct CtrlAuraZbus(Arc<Mutex<CtrlKbdLed>>, SignalContext<'static>);
impl CtrlAuraZbus { impl CtrlAuraZbus {
pub fn new(controller: CtrlKbdLed, signal: SignalContext<'static>) -> Self {
Self(Arc::new(Mutex::new(controller)), signal)
}
fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> {
let bright = lock.sysfs_node.get_brightness()?; let bright = lock.led_node.get_brightness()?;
lock.config.read(); lock.config.read();
lock.config.brightness = bright.into(); lock.config.brightness = bright.into();
lock.config.write(); lock.config.write();
@@ -32,41 +34,34 @@ impl CtrlAuraZbus {
} }
} }
#[async_trait] /// The main interface for changing, reading, or notfying
impl crate::ZbusRun for CtrlAuraZbus {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, AURA_ZBUS_PATH, server).await;
}
}
/// The main interface for changing, reading, or notfying signals
/// ///
/// LED commands are split between Brightness, Modes, Per-Key /// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")] #[interface(name = "org.asuslinux.Aura")]
impl CtrlAuraZbus { impl CtrlAuraZbus {
/// Return the device type for this Aura keyboard /// Return the device type for this Aura keyboard
#[dbus_interface(property)] #[zbus(property)]
async fn device_type(&self) -> AuraDevice { async fn device_type(&self) -> AuraDeviceType {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
ctrl.led_prod ctrl.led_type
} }
/// Return the current LED brightness /// Return the current LED brightness
#[dbus_interface(property)] #[zbus(property)]
async fn brightness(&self) -> Result<LedBrightness, ZbErr> { async fn brightness(&self) -> Result<LedBrightness, ZbErr> {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
Ok(ctrl.sysfs_node.get_brightness().map(|n| n.into())?) Ok(ctrl.led_node.get_brightness().map(|n| n.into())?)
} }
/// Set the keyboard brightness level (0-3) /// Set the keyboard brightness level (0-3)
#[dbus_interface(property)] #[zbus(property)]
async fn set_brightness(&mut self, brightness: LedBrightness) -> Result<(), ZbErr> { async fn set_brightness(&mut self, brightness: LedBrightness) -> Result<(), ZbErr> {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
Ok(ctrl.sysfs_node.set_brightness(brightness.into())?) Ok(ctrl.led_node.set_brightness(brightness.into())?)
} }
/// Total levels of brightness available /// Total levels of brightness available
#[dbus_interface(property)] #[zbus(property)]
async fn supported_brightness(&self) -> Vec<LedBrightness> { async fn supported_brightness(&self) -> Vec<LedBrightness> {
vec![ vec![
LedBrightness::Off, LedBrightness::Off,
@@ -77,14 +72,26 @@ impl CtrlAuraZbus {
} }
/// The total available modes /// The total available modes
#[dbus_interface(property)] #[zbus(property)]
async fn supported_modes(&self) -> Result<Vec<AuraModeNum>, ZbErr> { async fn supported_basic_modes(&self) -> Result<Vec<AuraModeNum>, ZbErr> {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
Ok(ctrl.config.builtins.keys().cloned().collect()) Ok(ctrl.config.builtins.keys().cloned().collect())
} }
#[zbus(property)]
async fn supported_basic_zones(&self) -> Result<Vec<AuraZone>, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.supported_data.basic_zones.clone())
}
#[zbus(property)]
async fn supported_power_zones(&self) -> Result<Vec<PowerZones>, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.supported_data.power_zones.clone())
}
/// The current mode data /// The current mode data
#[dbus_interface(property)] #[zbus(property)]
async fn led_mode(&self) -> Result<AuraModeNum, ZbErr> { async fn led_mode(&self) -> Result<AuraModeNum, ZbErr> {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
Ok(ctrl.config.current_mode) Ok(ctrl.config.current_mode)
@@ -94,7 +101,7 @@ impl CtrlAuraZbus {
/// ///
/// On success the aura config file is read to refresh cached values, then /// On success the aura config file is read to refresh cached values, then
/// the effect is stored and config written to disk. /// the effect is stored and config written to disk.
#[dbus_interface(property)] #[zbus(property)]
async fn set_led_mode(&mut self, num: AuraModeNum) -> Result<(), ZbErr> { async fn set_led_mode(&mut self, num: AuraModeNum) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await; let mut ctrl = self.0.lock().await;
ctrl.config.current_mode = num; ctrl.config.current_mode = num;
@@ -102,14 +109,16 @@ impl CtrlAuraZbus {
if ctrl.config.brightness == LedBrightness::Off { if ctrl.config.brightness == LedBrightness::Off {
ctrl.config.brightness = LedBrightness::Med; ctrl.config.brightness = LedBrightness::Med;
} }
ctrl.sysfs_node ctrl.led_node
.set_brightness(ctrl.config.brightness.into())?; .set_brightness(ctrl.config.brightness.into())?;
ctrl.config.write(); ctrl.config.write();
self.led_mode_data_invalidate(&self.1).await.ok();
Ok(()) Ok(())
} }
/// The current mode data /// The current mode data
#[dbus_interface(property)] #[zbus(property)]
async fn led_mode_data(&self) -> Result<AuraEffect, ZbErr> { async fn led_mode_data(&self) -> Result<AuraEffect, ZbErr> {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
let mode = ctrl.config.current_mode; let mode = ctrl.config.current_mode;
@@ -123,12 +132,12 @@ impl CtrlAuraZbus {
/// ///
/// On success the aura config file is read to refresh cached values, then /// On success the aura config file is read to refresh cached values, then
/// the effect is stored and config written to disk. /// the effect is stored and config written to disk.
#[dbus_interface(property)] #[zbus(property)]
async fn set_led_mode_data(&mut self, effect: AuraEffect) -> Result<(), ZbErr> { async fn set_led_mode_data(&mut self, effect: AuraEffect) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await; let mut ctrl = self.0.lock().await;
if !ctrl.supported_modes.basic_modes.contains(&effect.mode) if !ctrl.supported_data.basic_modes.contains(&effect.mode)
|| effect.zone != AuraZone::None || effect.zone != AuraZone::None
&& !ctrl.supported_modes.basic_zones.contains(&effect.zone) && !ctrl.supported_data.basic_zones.contains(&effect.zone)
{ {
return Err(ZbErr::NotSupported(format!( return Err(ZbErr::NotSupported(format!(
"The Aura effect is not supported: {effect:?}" "The Aura effect is not supported: {effect:?}"
@@ -139,10 +148,12 @@ impl CtrlAuraZbus {
if ctrl.config.brightness == LedBrightness::Off { if ctrl.config.brightness == LedBrightness::Off {
ctrl.config.brightness = LedBrightness::Med; ctrl.config.brightness = LedBrightness::Med;
} }
ctrl.sysfs_node ctrl.led_node
.set_brightness(ctrl.config.brightness.into())?; .set_brightness(ctrl.config.brightness.into())?;
ctrl.config.set_builtin(effect); ctrl.config.set_builtin(effect);
ctrl.config.write(); ctrl.config.write();
self.led_mode_invalidate(&self.1).await.ok();
Ok(()) Ok(())
} }
@@ -153,28 +164,27 @@ impl CtrlAuraZbus {
} }
// As property doesn't work for AuraPowerDev (complexity of serialization?) // As property doesn't work for AuraPowerDev (complexity of serialization?)
#[dbus_interface(property)] #[zbus(property)]
async fn led_power(&self) -> AuraPowerDev { async fn led_power(&self) -> LaptopAuraPower {
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
AuraPowerDev::from(&ctrl.config.enabled) ctrl.config.enabled.clone()
} }
/// Set a variety of states, input is array of enum. /// Set a variety of states, input is array of enum.
/// `enabled` sets if the sent array should be disabled or enabled /// `enabled` sets if the sent array should be disabled or enabled
/// ///
/// For Modern ROG devices the "enabled" flag is ignored. /// For Modern ROG devices the "enabled" flag is ignored.
#[dbus_interface(property)] #[zbus(property)]
async fn set_led_power(&mut self, options: (AuraPowerDev, bool)) -> Result<(), ZbErr> { async fn set_led_power(&mut self, options: LaptopAuraPower) -> Result<(), ZbErr> {
let enabled = options.1;
let options = options.0;
let mut ctrl = self.0.lock().await; let mut ctrl = self.0.lock().await;
for p in options.tuf { for opt in options.states {
ctrl.config.enabled.set_tuf(p, enabled); let zone = opt.zone;
for config in ctrl.config.enabled.states.iter_mut() {
if config.zone == zone {
*config = opt;
}
}
} }
for p in options.old_rog {
ctrl.config.enabled.set_0x1866(p, enabled);
}
ctrl.config.enabled.set_0x19b6(options.rog);
ctrl.config.write(); ctrl.config.write();
Ok(ctrl.set_power_states().map_err(|e| { Ok(ctrl.set_power_states().map_err(|e| {
warn!("{}", e); warn!("{}", e);
@@ -192,30 +202,35 @@ impl CtrlAuraZbus {
} }
} }
#[async_trait]
impl CtrlTask for CtrlAuraZbus { impl CtrlTask for CtrlAuraZbus {
fn zbus_path() -> &'static str { fn zbus_path() -> &'static str {
AURA_ZBUS_PATH "/org/asuslinux"
} }
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let load_save = |start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| { let load_save =
// If waking up |start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| -> Result<(), RogError> {
if !start { // If waking up
info!("CtrlKbdLedTask reloading brightness and modes"); if !start {
lock.sysfs_node info!("CtrlKbdLedTask reloading brightness and modes");
.set_brightness(lock.config.brightness.into()) lock.led_node
.map_err(|e| error!("CtrlKbdLedTask: {e}")) .set_brightness(lock.config.brightness.into())
.ok(); .map_err(|e| {
lock.write_current_config_mode() error!("CtrlKbdLedTask: {e}");
.map_err(|e| error!("CtrlKbdLedTask: {e}")) e
.ok(); })?;
} else if start { lock.write_current_config_mode().map_err(|e| {
Self::update_config(&mut lock) error!("CtrlKbdLedTask: {e}");
.map_err(|e| error!("CtrlKbdLedTask: {e}")) e
.ok(); })?;
} } else if start {
}; Self::update_config(&mut lock).map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
}
Ok(())
};
let inner1 = self.0.clone(); let inner1 = self.0.clone();
let inner3 = self.0.clone(); let inner3 = self.0.clone();
@@ -224,14 +239,16 @@ impl CtrlTask for CtrlAuraZbus {
let inner1 = inner1.clone(); let inner1 = inner1.clone();
async move { async move {
let lock = inner1.lock().await; let lock = inner1.lock().await;
load_save(sleeping, lock); load_save(sleeping, lock).unwrap(); // unwrap as we want to
// bomb out of the task
} }
}, },
move |_shutting_down| { move |_shutting_down| {
let inner3 = inner3.clone(); let inner3 = inner3.clone();
async move { async move {
let lock = inner3.lock().await; let lock = inner3.lock().await;
load_save(false, lock); load_save(false, lock).unwrap(); // unwrap as we want to
// bomb out of the task
} }
}, },
move |_lid_closed| { move |_lid_closed| {
@@ -247,7 +264,7 @@ impl CtrlTask for CtrlAuraZbus {
let ctrl2 = self.0.clone(); let ctrl2 = self.0.clone();
let ctrl = self.0.lock().await; let ctrl = self.0.lock().await;
let watch = ctrl.sysfs_node.monitor_brightness()?; let watch = ctrl.led_node.monitor_brightness()?;
tokio::spawn(async move { tokio::spawn(async move {
let mut buffer = [0; 32]; let mut buffer = [0; 32];
watch watch
@@ -255,7 +272,8 @@ impl CtrlTask for CtrlAuraZbus {
.unwrap() .unwrap()
.for_each(|_| async { .for_each(|_| async {
if let Some(lock) = ctrl2.try_lock() { if let Some(lock) = ctrl2.try_lock() {
load_save(true, lock); load_save(true, lock).unwrap(); // unwrap as we want to
// bomb out of the task
} }
}) })
.await; .await;
@@ -265,13 +283,12 @@ impl CtrlTask for CtrlAuraZbus {
} }
} }
#[async_trait]
impl crate::Reloadable for CtrlAuraZbus { impl crate::Reloadable for CtrlAuraZbus {
async fn reload(&mut self) -> Result<(), RogError> { async fn reload(&mut self) -> Result<(), RogError> {
let mut ctrl = self.0.lock().await; let mut ctrl = self.0.lock().await;
debug!("CtrlKbdLedZbus: reloading keyboard mode"); debug!("reloading keyboard mode");
ctrl.write_current_config_mode()?; ctrl.write_current_config_mode()?;
debug!("CtrlKbdLedZbus: reloading power states"); debug!("reloading power states");
ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); ctrl.set_power_states().map_err(|err| warn!("{err}")).ok();
Ok(()) Ok(())
} }
+93 -120
View File
@@ -1,30 +1,26 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait;
use config_traits::{StdConfig, StdConfigLoad}; use config_traits::{StdConfig, StdConfigLoad};
use futures_lite::StreamExt; use futures_lite::StreamExt;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use rog_platform::platform::{PlatformPolicy, RogPlatform}; use rog_platform::platform::{RogPlatform, ThrottlePolicy};
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::{find_fan_curve_node, FanCurvePU, FanCurveProfiles}; use rog_profiles::{find_fan_curve_node, FanCurvePU, FanCurveProfiles};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use zbus::{dbus_interface, Connection, SignalContext}; use zbus::{interface, Connection, SignalContext};
use crate::error::RogError; use crate::error::RogError;
use crate::{CtrlTask, CONFIG_PATH_BASE}; use crate::{CtrlTask, CONFIG_PATH_BASE};
const MOD_NAME: &str = "FanCurveZbus";
pub const FAN_CURVE_ZBUS_NAME: &str = "FanCurves"; pub const FAN_CURVE_ZBUS_NAME: &str = "FanCurves";
pub const FAN_CURVE_ZBUS_PATH: &str = "/org/asuslinux/FanCurves"; pub const FAN_CURVE_ZBUS_PATH: &str = "/org/asuslinux";
#[derive(Deserialize, Serialize, Debug, Default)] #[derive(Deserialize, Serialize, Debug, Default)]
pub struct FanCurveConfig { pub struct FanCurveConfig {
pub balanced: Vec<CurveData>, pub profiles: FanCurveProfiles,
pub performance: Vec<CurveData>,
pub quiet: Vec<CurveData>,
#[serde(skip)] #[serde(skip)]
pub current: u8, pub current: u8,
} }
@@ -50,7 +46,6 @@ impl StdConfigLoad for FanCurveConfig {}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CtrlFanCurveZbus { pub struct CtrlFanCurveZbus {
config: Arc<Mutex<FanCurveConfig>>, config: Arc<Mutex<FanCurveConfig>>,
fan_curves: Arc<Mutex<FanCurveProfiles>>,
platform: RogPlatform, platform: RogPlatform,
} }
@@ -59,89 +54,71 @@ impl CtrlFanCurveZbus {
pub fn new() -> Result<Self, RogError> { pub fn new() -> Result<Self, RogError> {
let platform = RogPlatform::new()?; let platform = RogPlatform::new()?;
if platform.has_throttle_thermal_policy() { if platform.has_throttle_thermal_policy() {
info!("{MOD_NAME}: Device has profile control available"); info!("Device has profile control available");
find_fan_curve_node()?; find_fan_curve_node()?;
info!("{MOD_NAME}: Device has fan curves available"); info!("Device has fan curves available");
let mut config = FanCurveConfig::new(); let mut config = FanCurveConfig::new().load();
let mut fan_curves = FanCurveProfiles::default(); let mut fan_curves = FanCurveProfiles::default();
// Only do defaults if the config doesn't already exist // Only do defaults if the config doesn't already exist\
if !config.file_path().exists() { if config.profiles.balanced.is_empty() || !config.file_path().exists() {
info!("{MOD_NAME}: Fetching default fan curves"); info!("Fetching default fan curves");
let current = platform.get_throttle_thermal_policy()?;
for this in [ for this in [
PlatformPolicy::Balanced, ThrottlePolicy::Balanced,
PlatformPolicy::Performance, ThrottlePolicy::Performance,
PlatformPolicy::Quiet, ThrottlePolicy::Quiet,
] { ] {
// For each profile we need to switch to it before we // For each profile we need to switch to it before we
// can read the existing values from hardware. The ACPI method used // can read the existing values from hardware. The ACPI method used
// for this is what limits us. // for this is what limits us.
let next = PlatformPolicy::get_next_profile(this); platform.set_throttle_thermal_policy(this.into())?;
platform.set_throttle_thermal_policy(next.into())?; let mut dev = find_fan_curve_node()?;
fan_curves.set_active_curve_to_defaults(this, &mut dev)?;
let active = platform info!("{this:?}:");
.get_throttle_thermal_policy() for curve in fan_curves.get_fan_curves_for(this) {
.map_or(PlatformPolicy::Balanced, |t| t.into());
info!("{MOD_NAME}: {active:?}:");
for curve in fan_curves.get_fan_curves_for(active) {
info!("{}", String::from(curve)); info!("{}", String::from(curve));
} }
} }
platform.set_throttle_thermal_policy(current)?;
config.profiles = fan_curves;
config.write(); config.write();
} else { } else {
info!("{MOD_NAME}: Fan curves previously stored, loading..."); info!("Fan curves previously stored, loading...");
config = config.load(); config = config.load();
fan_curves.balanced = config.balanced.clone();
fan_curves.performance = config.performance.clone();
fan_curves.quiet = config.quiet.clone();
} }
return Ok(Self { return Ok(Self {
config: Arc::new(Mutex::new(config)), config: Arc::new(Mutex::new(config)),
fan_curves: Arc::new(Mutex::new(fan_curves)),
platform, platform,
}); });
} }
Err(ProfileError::NotSupported.into()) Err(ProfileError::NotSupported.into())
} }
pub async fn update_profiles_from_config(&self) {
self.fan_curves.lock().await.balanced = self.config.lock().await.balanced.clone();
self.fan_curves.lock().await.performance = self.config.lock().await.performance.clone();
self.fan_curves.lock().await.quiet = self.config.lock().await.quiet.clone();
}
/// Because this locks both config and fan_curves, it means nothing else can
/// hold a lock across this function call. Stupid choice to do this and
/// needs to be fixed.
pub async fn update_config_from_profiles(&self) {
self.config.lock().await.balanced = self.fan_curves.lock().await.balanced.clone();
self.config.lock().await.performance = self.fan_curves.lock().await.performance.clone();
self.config.lock().await.quiet = self.fan_curves.lock().await.quiet.clone();
}
} }
#[dbus_interface(name = "org.asuslinux.Daemon")] #[interface(name = "org.asuslinux.FanCurves")]
impl CtrlFanCurveZbus { impl CtrlFanCurveZbus {
/// Set all fan curves for a profile to enabled status. Will also activate a /// Set all fan curves for a profile to enabled status. Will also activate a
/// fan curve if in the same profile mode /// fan curve if in the same profile mode
async fn set_fan_curves_enabled( async fn set_fan_curves_enabled(
&mut self, &mut self,
profile: PlatformPolicy, profile: ThrottlePolicy,
enabled: bool, enabled: bool,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.fan_curves self.config
.lock() .lock()
.await .await
.profiles
.set_profile_curves_enabled(profile, enabled); .set_profile_curves_enabled(profile, enabled);
self.fan_curves self.config
.lock() .lock()
.await .await
.profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?; .write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
self.update_config_from_profiles().await;
self.config.lock().await.write(); self.config.lock().await.write();
Ok(()) Ok(())
} }
@@ -150,32 +127,34 @@ impl CtrlFanCurveZbus {
/// activate a fan curve if in the same profile mode /// activate a fan curve if in the same profile mode
async fn set_profile_fan_curve_enabled( async fn set_profile_fan_curve_enabled(
&mut self, &mut self,
profile: PlatformPolicy, profile: ThrottlePolicy,
fan: FanCurvePU, fan: FanCurvePU,
enabled: bool, enabled: bool,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.fan_curves self.config
.lock() .lock()
.await .await
.profiles
.set_profile_fan_curve_enabled(profile, fan, enabled); .set_profile_fan_curve_enabled(profile, fan, enabled);
self.fan_curves self.config
.lock() .lock()
.await .await
.profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?; .write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
self.update_config_from_profiles().await;
self.config.lock().await.write(); self.config.lock().await.write();
Ok(()) Ok(())
} }
/// Get the fan-curve data for the currently active PlatformPolicy /// Get the fan-curve data for the currently active ThrottlePolicy
async fn fan_curve_data( async fn fan_curve_data(
&mut self, &mut self,
profile: PlatformPolicy, profile: ThrottlePolicy,
) -> zbus::fdo::Result<Vec<CurveData>> { ) -> zbus::fdo::Result<Vec<CurveData>> {
let curve = self let curve = self
.fan_curves .config
.lock() .lock()
.await .await
.profiles
.get_fan_curves_for(profile) .get_fan_curves_for(profile)
.to_vec(); .to_vec();
Ok(curve) Ok(curve)
@@ -185,72 +164,71 @@ impl CtrlFanCurveZbus {
/// Will also activate the fan curve if the user is in the same mode. /// Will also activate the fan curve if the user is in the same mode.
async fn set_fan_curve( async fn set_fan_curve(
&mut self, &mut self,
profile: PlatformPolicy, profile: ThrottlePolicy,
curve: CurveData, curve: CurveData,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.fan_curves self.config
.lock() .lock()
.await .await
.profiles
.save_fan_curve(curve, profile)?; .save_fan_curve(curve, profile)?;
self.fan_curves let active: ThrottlePolicy = self.platform.get_throttle_thermal_policy()?.into();
.lock() if active == profile {
.await self.config
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
self.update_config_from_profiles().await;
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curve to the defaults of the
/// platform.
///
/// Each platform_profile has a different default and the defualt can be
/// read only for the currently active profile.
async fn set_active_curve_to_defaults(&mut self) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
self.fan_curves
.lock()
.await
.set_active_curve_to_defaults(active.into(), &mut find_fan_curve_node()?)?;
self.update_config_from_profiles().await;
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curve to the defaults of the
/// platform.
///
/// Each platform_profile has a different default and the defualt can be
/// read only for the currently active profile.
async fn reset_profile_curves(&self, profile: PlatformPolicy) -> zbus::fdo::Result<()> {
let active = self
.platform
.get_throttle_thermal_policy()
.unwrap_or(PlatformPolicy::Balanced.into());
self.platform.set_throttle_thermal_policy(profile.into())?;
{
self.fan_curves
.lock() .lock()
.await .await
.set_active_curve_to_defaults(active.into(), &mut find_fan_curve_node()?)?; .profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
} }
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curves to the defaults of the
/// platform.
///
/// Each platform_profile has a different default and the default can be
/// read only for the currently active profile.
async fn set_curves_to_defaults(&mut self, profile: ThrottlePolicy) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
self.platform.set_throttle_thermal_policy(profile.into())?;
self.config
.lock()
.await
.profiles
.set_active_curve_to_defaults(profile, &mut find_fan_curve_node()?)?;
self.platform.set_throttle_thermal_policy(active)?;
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curve to the defaults of the
/// platform.
///
/// Each platform_profile has a different default and the defualt can be
/// read only for the currently active profile.
async fn reset_profile_curves(&self, profile: ThrottlePolicy) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
self.platform.set_throttle_thermal_policy(profile.into())?;
self.config
.lock()
.await
.profiles
.set_active_curve_to_defaults(active.into(), &mut find_fan_curve_node()?)?;
self.platform.set_throttle_thermal_policy(active)?; self.platform.set_throttle_thermal_policy(active)?;
self.update_config_from_profiles().await;
self.config.lock().await.write(); self.config.lock().await.write();
Ok(()) Ok(())
} }
} }
#[async_trait]
impl crate::ZbusRun for CtrlFanCurveZbus { impl crate::ZbusRun for CtrlFanCurveZbus {
async fn add_to_server(self, server: &mut Connection) { async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, FAN_CURVE_ZBUS_PATH, server).await; Self::add_to_server_helper(self, FAN_CURVE_ZBUS_PATH, server).await;
} }
} }
#[async_trait]
impl CtrlTask for CtrlFanCurveZbus { impl CtrlTask for CtrlFanCurveZbus {
fn zbus_path() -> &'static str { fn zbus_path() -> &'static str {
FAN_CURVE_ZBUS_PATH FAN_CURVE_ZBUS_PATH
@@ -260,7 +238,7 @@ impl CtrlTask for CtrlFanCurveZbus {
let watch_throttle_thermal_policy = self.platform.monitor_throttle_thermal_policy()?; let watch_throttle_thermal_policy = self.platform.monitor_throttle_thermal_policy()?;
let platform = self.platform.clone(); let platform = self.platform.clone();
let config = self.config.clone(); let config = self.config.clone();
let fan_curves = self.fan_curves.clone(); let fan_curves = self.config.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut buffer = [0; 32]; let mut buffer = [0; 32];
@@ -268,25 +246,23 @@ impl CtrlTask for CtrlFanCurveZbus {
while (stream.next().await).is_some() { while (stream.next().await).is_some() {
debug!("watch_throttle_thermal_policy changed"); debug!("watch_throttle_thermal_policy changed");
if let Ok(profile) = platform.get_throttle_thermal_policy().map_err(|e| { if let Ok(profile) = platform.get_throttle_thermal_policy().map_err(|e| {
error!("{MOD_NAME}: get_throttle_thermal_policy error: {e}"); error!("get_throttle_thermal_policy error: {e}");
}) { }) {
if profile != config.lock().await.current { if profile != config.lock().await.current {
fan_curves fan_curves
.lock() .lock()
.await .await
.profiles
.write_profile_curve_to_platform( .write_profile_curve_to_platform(
profile.into(), profile.into(),
&mut find_fan_curve_node().unwrap(), &mut find_fan_curve_node().unwrap(),
) )
.map_err(|e| { .map_err(|e| warn!("write_profile_curve_to_platform, {}", e))
warn!("{MOD_NAME}: write_profile_curve_to_platform, {}", e)
})
.ok(); .ok();
config.lock().await.current = profile; config.lock().await.current = profile;
} }
} }
} }
dbg!("STREAM ENDED");
} }
}); });
@@ -294,20 +270,17 @@ impl CtrlTask for CtrlFanCurveZbus {
} }
} }
#[async_trait]
impl crate::Reloadable for CtrlFanCurveZbus { impl crate::Reloadable for CtrlFanCurveZbus {
/// Fetch the active profile and use that to set all related components up /// Fetch the active profile and use that to set all related components up
async fn reload(&mut self) -> Result<(), RogError> { async fn reload(&mut self) -> Result<(), RogError> {
// let active = self.platform.get_throttle_thermal_policy()?.into(); let active = self.platform.get_throttle_thermal_policy()?.into();
// if let Ok(mut device) = find_fan_curve_node() { let mut config = self.config.lock().await;
// // There is a possibility that the curve was default zeroed, so this call if let Ok(mut device) = find_fan_curve_node() {
// // initialises the data from system read and we need to save it config
// // after .profiles
// self.fan_curves .write_profile_curve_to_platform(active, &mut device)?;
// .lock() }
// .await
// .write_profile_curve_to_platform(active, &mut device)?;
// }
Ok(()) Ok(())
} }
} }
+481 -168
View File
@@ -1,24 +1,26 @@
use std::path::Path;
use std::process::Command; use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait;
use config_traits::StdConfig; use config_traits::StdConfig;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use rog_platform::cpu::{CPUControl, CPUGovernor}; use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP};
use rog_platform::platform::{GpuMode, PlatformPolicy, Properties, RogPlatform}; use rog_platform::platform::{GpuMode, Properties, RogPlatform, ThrottlePolicy};
use rog_platform::power::AsusPower; use rog_platform::power::AsusPower;
use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::lock::Mutex;
use zbus::fdo::Error as FdoErr; use zbus::fdo::Error as FdoErr;
use zbus::{dbus_interface, Connection, ObjectServer, SignalContext}; use zbus::{interface, Connection, ObjectServer, SignalContext};
use crate::config::Config; use crate::config::Config;
use crate::ctrl_anime::trait_impls::{CtrlAnimeZbus, ANIME_ZBUS_NAME, ANIME_ZBUS_PATH}; use crate::ctrl_anime::trait_impls::{CtrlAnimeZbus, ANIME_ZBUS_NAME, ANIME_ZBUS_PATH};
use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_NAME, AURA_ZBUS_PATH}; use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_NAME, AURA_ZBUS_PATH};
use crate::ctrl_fancurves::{CtrlFanCurveZbus, FAN_CURVE_ZBUS_NAME, FAN_CURVE_ZBUS_PATH}; use crate::ctrl_fancurves::{CtrlFanCurveZbus, FAN_CURVE_ZBUS_NAME, FAN_CURVE_ZBUS_PATH};
use crate::ctrl_slash::trait_impls::{CtrlSlashZbus, SLASH_ZBUS_NAME, SLASH_ZBUS_PATH};
use crate::error::RogError; use crate::error::RogError;
use crate::{task_watch_item, task_watch_item_notify, CtrlTask}; use crate::{task_watch_item, task_watch_item_notify, CtrlTask, ReloadAndNotify};
const ZBUS_PATH: &str = "/org/asuslinux/Platform"; const PLATFORM_ZBUS_NAME: &str = "Platform";
const PLATFORM_ZBUS_PATH: &str = "/org/asuslinux";
macro_rules! platform_get_value { macro_rules! platform_get_value {
($self:ident, $property:tt, $prop_name:literal) => { ($self:ident, $property:tt, $prop_name:literal) => {
@@ -28,33 +30,18 @@ macro_rules! platform_get_value {
$self.platform $self.platform
.get() .get()
.map_err(|err| { .map_err(|err| {
warn!("RogPlatform: {}: {}", $prop_name, err); warn!("{}: {}", $prop_name, err);
FdoErr::Failed(format!("RogPlatform: {}: {}", $prop_name, err)) FdoErr::Failed(format!("RogPlatform: {}: {}", $prop_name, err))
}) })
}) })
} else { } else {
error!("RogPlatform: {} not supported", $prop_name);
return Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name))); return Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name)));
} }
}) })
} }
} }
macro_rules! platform_get_value_if_some { macro_rules! platform_set_value {
($self:ident, $property:tt, $prop_name:literal, $default:expr) => {
concat_idents::concat_idents!(has = has_, $property {
if $self.platform.has() {
let lock = $self.config.lock().await;
Ok(lock.ppt_pl1_spl.unwrap_or($default))
} else {
error!("RogPlatform: {} not supported", $prop_name);
return Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name)));
}
})
}
}
macro_rules! platform_set_bool {
($self:ident, $property:tt, $prop_name:literal, $new_value:expr) => { ($self:ident, $property:tt, $prop_name:literal, $new_value:expr) => {
concat_idents::concat_idents!(has = has_, $property { concat_idents::concat_idents!(has = has_, $property {
if $self.platform.has() { if $self.platform.has() {
@@ -69,40 +56,32 @@ macro_rules! platform_set_bool {
lock.write(); lock.write();
Ok(()) Ok(())
} else { } else {
error!("RogPlatform: {} not supported", $prop_name); debug!("RogPlatform: {} not supported", $prop_name);
Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name))) Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name)))
} }
}) })
} }
} }
/// Intended only for setting platform object values where the value isn't macro_rules! platform_ppt_set_value {
/// retained across boots ($self:ident, $property:tt, $prop_name:literal, $new_value:expr) => {
macro_rules! platform_set_with_min_max { concat_idents::concat_idents!(has = has_, $property {
($self:ident, $property:tt, $prop_name:literal, $new_value:expr, $min_value:expr, $max_value:expr) => { if $self.platform.has() {
if !($min_value..=$max_value).contains(&$new_value) { concat_idents::concat_idents!(set = set_, $property {
Err(FdoErr::Failed( $self.platform.set($new_value).map_err(|err| {
format!("RogPlatform: {} value not in range {}=..={}", $prop_name, $min_value, $max_value) error!("RogPlatform: {} {err}", $prop_name);
)) FdoErr::NotSupported(format!("RogPlatform: {} {err}", $prop_name))
} else { })?;
concat_idents::concat_idents!(has = has_, $property { });
if $self.platform.has() { let mut lock = $self.config.lock().await;
concat_idents::concat_idents!(set = set_, $property { lock.$property = Some($new_value);
$self.platform.set($new_value).map_err(|err| { lock.write();
error!("RogPlatform: {} {err}", $prop_name); Ok(())
FdoErr::NotSupported(format!("RogPlatform: {} {err}", $prop_name)) } else {
})?; debug!("RogPlatform: ppt: setting {} not supported", $prop_name);
}); Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name)))
let mut lock = $self.config.lock().await; }
lock.$property = Some($new_value); })
lock.write();
} else {
error!("RogPlatform: {} not supported", $prop_name);
return Err(FdoErr::NotSupported(format!("RogPlatform: {} not supported", $prop_name)));
}
});
Ok(())
}
} }
} }
@@ -115,7 +94,11 @@ pub struct CtrlPlatform {
} }
impl CtrlPlatform { impl CtrlPlatform {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> { pub fn new(
config: Arc<Mutex<Config>>,
config_path: &Path,
signal_context: SignalContext<'static>,
) -> Result<Self, RogError> {
let platform = RogPlatform::new()?; let platform = RogPlatform::new()?;
let power = AsusPower::new()?; let power = AsusPower::new()?;
@@ -124,20 +107,76 @@ impl CtrlPlatform {
info!("Standard graphics switching will still work."); info!("Standard graphics switching will still work.");
} }
Ok(CtrlPlatform { let config1 = config.clone();
let config_path = config_path.to_owned();
let ret_self = CtrlPlatform {
power, power,
platform, platform,
config, config,
cpu_control: CPUControl::new() cpu_control: CPUControl::new()
.map_err(|e| error!("Couldn't get CPU control sysfs: {e}")) .map_err(|e| error!("Couldn't get CPU control sysfs: {e}"))
.ok(), .ok(),
}) };
let mut inotify_self = ret_self.clone();
tokio::spawn(async move {
use zbus::export::futures_util::StreamExt;
info!("Starting inotify watch for asusd config file");
let mut buffer = [0; 32];
loop {
// vi and vim do stupid shit causing the file watch to be removed
let inotify = inotify::Inotify::init().unwrap();
inotify
.watches()
.add(
&config_path,
inotify::WatchMask::MODIFY
| inotify::WatchMask::CLOSE_WRITE
| inotify::WatchMask::ATTRIB
| inotify::WatchMask::CREATE,
)
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
error!("Not found: {:?}", config_path);
} else {
error!("Could not set asusd config inotify: {:?}", config_path);
}
e
})
.ok();
let mut events = inotify.into_event_stream(&mut buffer).unwrap();
while let Some(ev) = events.next().await {
if let Ok(ev) = ev {
if ev.mask == inotify::EventMask::IGNORED {
warn!(
"Something modified asusd.ron vi/vim style. Now need to reload \
inotify watch"
);
break;
}
}
let res = config1.lock().await.read_new();
if let Some(new_cfg) = res {
inotify_self
.reload_and_notify(&signal_context, new_cfg)
.await
.unwrap();
}
}
}
});
Ok(ret_self)
} }
fn set_gfx_mode(&self, mode: GpuMode) -> Result<(), RogError> { fn set_gfx_mode(&self, mode: GpuMode) -> Result<(), RogError> {
self.platform.set_gpu_mux_mode(mode.to_mux_attr())?; self.platform.set_gpu_mux_mode(mode.to_mux_attr())?;
// self.update_initramfs(enable)?; // self.update_initramfs(enable)?;
if mode == GpuMode::Discrete { if mode == GpuMode::Ultimate {
info!("Set system-level graphics mode: Dedicated Nvidia"); info!("Set system-level graphics mode: Dedicated Nvidia");
} else { } else {
info!("Set system-level graphics mode: Optimus"); info!("Set system-level graphics mode: Optimus");
@@ -180,38 +219,66 @@ impl CtrlPlatform {
} }
} }
fn check_and_set_epp(&self, profile: PlatformPolicy) { fn check_and_set_epp(&self, enegy_pref: CPUEPP, change_epp: bool) {
info!("PlatformPolicy setting EPP"); if !change_epp {
info!("ThrottlePolicy unlinked from EPP");
return;
}
info!("ThrottlePolicy setting EPP");
if let Some(cpu) = self.cpu_control.as_ref() { if let Some(cpu) = self.cpu_control.as_ref() {
if let Ok(epp) = cpu.get_available_epp() { if let Ok(epp) = cpu.get_available_epp() {
debug!("Available EPP: {epp:?}"); debug!("Available EPP: {epp:?}");
if epp.contains(&profile.into()) { if epp.contains(&enegy_pref) {
debug!("Setting {profile:?}"); debug!("Setting {enegy_pref:?}");
cpu.set_epp(profile.into()).ok(); cpu.set_epp(enegy_pref).ok();
} else if let Ok(gov) = cpu.get_governor() { } else if let Ok(gov) = cpu.get_governor() {
if gov != CPUGovernor::Powersave { if gov != CPUGovernor::Powersave {
warn!("powersave governor is not is use, you should use it."); warn!("powersave governor is not is use, trying to set.");
cpu.set_governor(CPUGovernor::Powersave)
.map_err(|e| error!("couldn't set powersave: {e:?}"))
.ok();
if epp.contains(&enegy_pref) {
debug!("Setting {enegy_pref:?}");
cpu.set_epp(enegy_pref)
.map_err(|e| error!("couldn't set EPP: {e:?}"))
.ok();
}
} }
} }
} }
} }
} }
async fn update_policy_ac_or_bat(&self, power_plugged: bool) { async fn get_config_epp_for_throttle(&self, throttle: ThrottlePolicy) -> CPUEPP {
let profile = if power_plugged { match throttle {
self.config.lock().await.platform_policy_on_ac ThrottlePolicy::Balanced => self.config.lock().await.throttle_balanced_epp,
ThrottlePolicy::Performance => self.config.lock().await.throttle_performance_epp,
ThrottlePolicy::Quiet => self.config.lock().await.throttle_quiet_epp,
}
}
async fn update_policy_ac_or_bat(&self, power_plugged: bool, change_epp: bool) {
let throttle = if power_plugged {
self.config.lock().await.throttle_policy_on_ac
} else { } else {
self.config.lock().await.platform_policy_on_battery self.config.lock().await.throttle_policy_on_battery
}; };
debug!("Setting {throttle:?} before EPP");
let epp = self.get_config_epp_for_throttle(throttle).await;
self.platform self.platform
.set_throttle_thermal_policy(profile.into()) .set_throttle_thermal_policy(throttle.into())
.ok(); .ok();
self.check_and_set_epp(profile); self.check_and_set_epp(epp, change_epp);
} }
} }
#[dbus_interface(name = "org.asuslinux.Daemon")] #[interface(name = "org.asuslinux.Platform")]
impl CtrlPlatform { impl CtrlPlatform {
#[zbus(property)]
async fn version(&self) -> String {
crate::VERSION.to_string()
}
/// Returns a list of property names that this system supports /// Returns a list of property names that this system supports
async fn supported_properties(&self) -> Vec<Properties> { async fn supported_properties(&self) -> Vec<Properties> {
let mut supported = Vec::new(); let mut supported = Vec::new();
@@ -244,11 +311,11 @@ impl CtrlPlatform {
platform_name!(dgpu_disable, Properties::DgpuDisable); platform_name!(dgpu_disable, Properties::DgpuDisable);
platform_name!(gpu_mux_mode, Properties::GpuMuxMode); platform_name!(gpu_mux_mode, Properties::GpuMuxMode);
platform_name!(post_animation_sound, Properties::PostAnimationSound); platform_name!(boot_sound, Properties::PostAnimationSound);
platform_name!(panel_od, Properties::PanelOd); platform_name!(panel_od, Properties::PanelOd);
platform_name!(mini_led_mode, Properties::MiniLedMode); platform_name!(mini_led_mode, Properties::MiniLedMode);
platform_name!(egpu_enable, Properties::EgpuEnable); platform_name!(egpu_enable, Properties::EgpuEnable);
platform_name!(throttle_thermal_policy, Properties::PlatformPolicy); platform_name!(throttle_thermal_policy, Properties::ThrottlePolicy);
platform_name!(ppt_pl1_spl, Properties::PptPl1Spl); platform_name!(ppt_pl1_spl, Properties::PptPl1Spl);
platform_name!(ppt_pl2_sppt, Properties::PptPl2Sppt); platform_name!(ppt_pl2_sppt, Properties::PptPl2Sppt);
@@ -287,45 +354,62 @@ impl CtrlPlatform {
{ {
interfaces.push(FAN_CURVE_ZBUS_NAME.to_owned()); interfaces.push(FAN_CURVE_ZBUS_NAME.to_owned());
} }
if server
.interface::<_, CtrlPlatform>(PLATFORM_ZBUS_PATH)
.await
.is_ok()
{
interfaces.push(PLATFORM_ZBUS_NAME.to_owned());
}
if server
.interface::<_, CtrlSlashZbus>(SLASH_ZBUS_PATH)
.await
.is_ok()
{
interfaces.push(SLASH_ZBUS_NAME.to_owned());
}
interfaces interfaces
} }
#[dbus_interface(property)] #[zbus(property)]
fn charge_control_end_threshold(&self) -> Result<u8, FdoErr> { fn charge_control_end_threshold(&self) -> Result<u8, FdoErr> {
let limit = self.power.get_charge_control_end_threshold()?; let limit = self.power.get_charge_control_end_threshold()?;
Ok(limit) Ok(limit)
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_charge_control_end_threshold(&mut self, limit: u8) -> Result<(), FdoErr> { async fn set_charge_control_end_threshold(&mut self, limit: u8) -> Result<(), FdoErr> {
if !(20..=100).contains(&limit) { if !(20..=100).contains(&limit) {
return Err(RogError::ChargeLimit(limit))?; return Err(RogError::ChargeLimit(limit))?;
} }
self.power.set_charge_control_end_threshold(limit)?; self.power.set_charge_control_end_threshold(limit)?;
self.config.lock().await.charge_control_end_threshold = limit; self.config.lock().await.charge_control_end_threshold = limit;
self.config.lock().await.write();
Ok(()) Ok(())
} }
#[dbus_interface(property)] #[zbus(property)]
fn gpu_mux_mode(&self) -> Result<u8, FdoErr> { fn gpu_mux_mode(&self) -> Result<u8, FdoErr> {
self.platform.get_gpu_mux_mode().map_err(|err| { self.platform.get_gpu_mux_mode().map_err(|err| {
warn!("RogPlatform: set_gpu_mux_mode {err}"); warn!("get_gpu_mux_mode {err}");
FdoErr::NotSupported("RogPlatform: set_gpu_mux_mode not supported".to_owned()) FdoErr::NotSupported("RogPlatform: set_gpu_mux_mode not supported".to_owned())
}) })
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_gpu_mux_mode(&mut self, mode: u8) -> Result<(), FdoErr> { async fn set_gpu_mux_mode(&mut self, mode: u8) -> Result<(), FdoErr> {
if self.platform.has_gpu_mux_mode() { if self.platform.has_gpu_mux_mode() {
self.set_gfx_mode(mode.into()).map_err(|err| { self.set_gfx_mode(mode.into()).map_err(|err| {
warn!("RogPlatform: set_gpu_mux_mode {}", err); warn!("set_gpu_mux_mode {}", err);
FdoErr::Failed(format!("RogPlatform: set_gpu_mux_mode: {err}")) FdoErr::Failed(format!("RogPlatform: set_gpu_mux_mode: {err}"))
}) })?;
self.config.lock().await.write();
} else { } else {
Err(FdoErr::NotSupported( return Err(FdoErr::NotSupported(
"RogPlatform: set_gpu_mux_mode not supported".to_owned(), "RogPlatform: set_gpu_mux_mode not supported".to_owned(),
)) ));
} }
Ok(())
} }
/// Toggle to next platform_profile. Names provided by `Profiles`. /// Toggle to next platform_profile. Names provided by `Profiles`.
@@ -334,20 +418,21 @@ impl CtrlPlatform {
&mut self, &mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>, #[zbus(signal_context)] ctxt: SignalContext<'_>,
) -> Result<(), FdoErr> { ) -> Result<(), FdoErr> {
let policy: PlatformPolicy = let policy: ThrottlePolicy =
platform_get_value!(self, throttle_thermal_policy, "throttle_thermal_policy") platform_get_value!(self, throttle_thermal_policy, "throttle_thermal_policy")
.map(|n| n.into())?; .map(|n| n.into())?;
let policy = PlatformPolicy::next(&policy); let policy = ThrottlePolicy::next(policy);
if self.platform.has_throttle_thermal_policy() { if self.platform.has_throttle_thermal_policy() {
self.check_and_set_epp(policy); let change_epp = self.config.lock().await.throttle_policy_linked_epp;
let epp = self.get_config_epp_for_throttle(policy).await;
self.check_and_set_epp(epp, change_epp);
self.platform self.platform
.set_throttle_thermal_policy(policy.into()) .set_throttle_thermal_policy(policy.into())
.map_err(|err| { .map_err(|err| {
warn!("RogPlatform: throttle_thermal_policy {}", err); warn!("throttle_thermal_policy {}", err);
FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}")) FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}"))
})?; })?;
self.config.lock().await.platform_policy_to_restore = policy;
Ok(self.throttle_thermal_policy_changed(&ctxt).await?) Ok(self.throttle_thermal_policy_changed(&ctxt).await?)
} else { } else {
Err(FdoErr::NotSupported( Err(FdoErr::NotSupported(
@@ -356,22 +441,24 @@ impl CtrlPlatform {
} }
} }
#[dbus_interface(property)] #[zbus(property)]
fn throttle_thermal_policy(&self) -> Result<PlatformPolicy, FdoErr> { fn throttle_thermal_policy(&self) -> Result<ThrottlePolicy, FdoErr> {
platform_get_value!(self, throttle_thermal_policy, "throttle_thermal_policy") platform_get_value!(self, throttle_thermal_policy, "throttle_thermal_policy")
.map(|n| n.into()) .map(|n| n.into())
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_throttle_thermal_policy(&mut self, policy: PlatformPolicy) -> Result<(), FdoErr> { async fn set_throttle_thermal_policy(&mut self, policy: ThrottlePolicy) -> Result<(), FdoErr> {
// TODO: watch for external changes // TODO: watch for external changes
if self.platform.has_throttle_thermal_policy() { if self.platform.has_throttle_thermal_policy() {
self.check_and_set_epp(policy); let change_epp = self.config.lock().await.throttle_policy_linked_epp;
self.config.lock().await.platform_policy_to_restore = policy; let epp = self.get_config_epp_for_throttle(policy).await;
self.check_and_set_epp(epp, change_epp);
self.config.lock().await.write();
self.platform self.platform
.set_throttle_thermal_policy(policy.into()) .set_throttle_thermal_policy(policy.into())
.map_err(|err| { .map_err(|err| {
warn!("RogPlatform: throttle_thermal_policy {}", err); warn!("throttle_thermal_policy {}", err);
FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}")) FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}"))
}) })
} else { } else {
@@ -381,150 +468,363 @@ impl CtrlPlatform {
} }
} }
#[dbus_interface(property)] #[zbus(property)]
fn post_animation_sound(&self) -> Result<bool, FdoErr> { async fn throttle_policy_linked_epp(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, post_animation_sound, "post_animation_sound") Ok(self.config.lock().await.throttle_policy_linked_epp)
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_post_animation_sound(&mut self, on: bool) -> Result<(), FdoErr> { async fn set_throttle_policy_linked_epp(&self, linked: bool) -> Result<(), zbus::Error> {
if self.platform.has_post_animation_sound() { self.config.lock().await.throttle_policy_linked_epp = linked;
self.platform.set_post_animation_sound(on).map_err(|err| { self.config.lock().await.write();
warn!("RogPlatform: set_post_animation_sound {}", err); Ok(())
FdoErr::Failed(format!("RogPlatform: set_post_animation_sound: {err}")) }
})
} else { #[zbus(property)]
Err(FdoErr::NotSupported( async fn throttle_policy_on_battery(&self) -> Result<ThrottlePolicy, FdoErr> {
"RogPlatform: set_post_animation_sound not supported".to_owned(), Ok(self.config.lock().await.throttle_policy_on_battery)
)) }
}
#[zbus(property)]
async fn set_throttle_policy_on_battery(
&mut self,
policy: ThrottlePolicy,
) -> Result<(), FdoErr> {
self.config.lock().await.throttle_policy_on_battery = policy;
self.set_throttle_thermal_policy(policy).await?;
self.config.lock().await.write();
Ok(())
}
#[zbus(property)]
async fn throttle_policy_on_ac(&self) -> Result<ThrottlePolicy, FdoErr> {
Ok(self.config.lock().await.throttle_policy_on_ac)
}
#[zbus(property)]
async fn set_throttle_policy_on_ac(&mut self, policy: ThrottlePolicy) -> Result<(), FdoErr> {
self.config.lock().await.throttle_policy_on_ac = policy;
self.set_throttle_thermal_policy(policy).await?;
self.config.lock().await.write();
Ok(())
}
/// The energy_performance_preference for the quiet throttle/platform
/// profile
#[zbus(property)]
async fn throttle_quiet_epp(&self) -> Result<CPUEPP, FdoErr> {
Ok(self.config.lock().await.throttle_quiet_epp)
}
#[zbus(property)]
async fn set_throttle_quiet_epp(&mut self, epp: CPUEPP) -> Result<(), FdoErr> {
let change_pp = self.config.lock().await.throttle_policy_linked_epp;
self.config.lock().await.throttle_quiet_epp = epp;
self.check_and_set_epp(epp, change_pp);
self.config.lock().await.write();
Ok(())
}
/// The energy_performance_preference for the balanced throttle/platform
/// profile
#[zbus(property)]
async fn throttle_balanced_epp(&self) -> Result<CPUEPP, FdoErr> {
Ok(self.config.lock().await.throttle_balanced_epp)
}
#[zbus(property)]
async fn set_throttle_balanced_epp(&mut self, epp: CPUEPP) -> Result<(), FdoErr> {
let change_pp = self.config.lock().await.throttle_policy_linked_epp;
self.config.lock().await.throttle_balanced_epp = epp;
self.check_and_set_epp(epp, change_pp);
self.config.lock().await.write();
Ok(())
}
/// The energy_performance_preference for the performance throttle/platform
/// profile
#[zbus(property)]
async fn throttle_performance_epp(&self) -> Result<CPUEPP, FdoErr> {
Ok(self.config.lock().await.throttle_performance_epp)
}
#[zbus(property)]
async fn set_throttle_performance_epp(&mut self, epp: CPUEPP) -> Result<(), FdoErr> {
let change_pp = self.config.lock().await.throttle_policy_linked_epp;
self.config.lock().await.throttle_performance_epp = epp;
self.check_and_set_epp(epp, change_pp);
self.config.lock().await.write();
Ok(())
} }
/// Get the `panel_od` value from platform. Updates the stored value in /// Get the `panel_od` value from platform. Updates the stored value in
/// internal config also. /// internal config also.
#[dbus_interface(property)] #[zbus(property)]
fn panel_od(&self) -> Result<bool, FdoErr> { fn panel_od(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, panel_od, "panel_od") platform_get_value!(self, panel_od, "panel_od")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_panel_od(&mut self, overdrive: bool) -> Result<(), FdoErr> { async fn set_panel_od(&mut self, overdrive: bool) -> Result<(), FdoErr> {
platform_set_bool!(self, panel_od, "panel_od", overdrive) platform_set_value!(self, panel_od, "panel_od", overdrive)?;
self.config.lock().await.write();
Ok(())
}
/// Get the `boot_sound` value from platform. Updates the stored value in
/// internal config also.
#[zbus(property)]
fn boot_sound(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, boot_sound, "boot_sound")
}
#[zbus(property)]
async fn set_boot_sound(&mut self, on: bool) -> Result<(), FdoErr> {
platform_set_value!(self, boot_sound, "boot_sound", on)?;
self.config.lock().await.write();
Ok(())
} }
/// Get the `panel_od` value from platform. Updates the stored value in /// Get the `panel_od` value from platform. Updates the stored value in
/// internal config also. /// internal config also.
#[dbus_interface(property)] #[zbus(property)]
fn mini_led_mode(&self) -> Result<bool, FdoErr> { fn mini_led_mode(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, mini_led_mode, "mini_led_mode") platform_get_value!(self, mini_led_mode, "mini_led_mode")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_mini_led_mode(&mut self, on: bool) -> Result<(), FdoErr> { async fn set_mini_led_mode(&mut self, on: bool) -> Result<(), FdoErr> {
platform_set_bool!(self, mini_led_mode, "mini_led_mode", on) platform_set_value!(self, mini_led_mode, "mini_led_mode", on)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] #[zbus(property)]
fn dgpu_disable(&self) -> Result<bool, FdoErr> { fn dgpu_disable(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, dgpu_disable, "dgpu_disable") platform_get_value!(self, dgpu_disable, "dgpu_disable")
} }
#[dbus_interface(property)] #[zbus(property)]
fn egpu_enable(&self) -> Result<bool, FdoErr> { fn egpu_enable(&self) -> Result<bool, FdoErr> {
platform_get_value!(self, egpu_enable, "egpu_enable") platform_get_value!(self, egpu_enable, "egpu_enable")
} }
/// ************************************************************************ /// ***********************************************************************
#[dbus_interface(property)] /// Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
/// Shown on Intel+Nvidia or AMD+Nvidia based systems:
/// * min=5, max=250
#[zbus(property)]
async fn ppt_pl1_spl(&self) -> Result<u8, FdoErr> { async fn ppt_pl1_spl(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, ppt_pl1_spl, "ppt_pl1_spl", 5) platform_get_value!(self, ppt_pl1_spl, "ppt_pl1_spl")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_ppt_pl1_spl(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_ppt_pl1_spl(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, ppt_pl1_spl, "ppt_pl1_spl", value, 5, 250) platform_ppt_set_value!(self, ppt_pl1_spl, "ppt_pl1_spl", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
/// on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
/// * min=5, max=250
#[zbus(property)]
async fn ppt_pl2_sppt(&self) -> Result<u8, FdoErr> { async fn ppt_pl2_sppt(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, ppt_pl2_sppt, "ppt_pl2_sppt", 5) platform_get_value!(self, ppt_pl2_sppt, "ppt_pl2_sppt")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_ppt_pl2_sppt(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_ppt_pl2_sppt(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, ppt_pl2_sppt, "ppt_pl2_sppt", value, 5, 250) platform_ppt_set_value!(self, ppt_pl2_sppt, "ppt_pl2_sppt", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
/// * min=5, max=250
#[zbus(property)]
async fn ppt_fppt(&self) -> Result<u8, FdoErr> { async fn ppt_fppt(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, ppt_fppt, "ppt_fppt", 5) platform_get_value!(self, ppt_fppt, "ppt_fppt")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_ppt_fppt(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_ppt_fppt(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, ppt_fppt, "ppt_fppt", value, 5, 250) platform_ppt_set_value!(self, ppt_fppt, "ppt_fppt", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the APU SPPT limit. Shown on full AMD systems only:
/// * min=5, max=130
#[zbus(property)]
async fn ppt_apu_sppt(&self) -> Result<u8, FdoErr> { async fn ppt_apu_sppt(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, ppt_apu_sppt, "ppt_apu_sppt", 5) platform_get_value!(self, ppt_apu_sppt, "ppt_apu_sppt")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_ppt_apu_sppt(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_ppt_apu_sppt(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, ppt_apu_sppt, "ppt_apu_sppt", value, 5, 130) platform_ppt_set_value!(self, ppt_apu_sppt, "ppt_apu_sppt", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the platform SPPT limit. Shown on full AMD systems only:
/// * min=5, max=130
#[zbus(property)]
async fn ppt_platform_sppt(&self) -> Result<u8, FdoErr> { async fn ppt_platform_sppt(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, ppt_platform_sppt, "ppt_platform_sppt", 5) platform_get_value!(self, ppt_platform_sppt, "ppt_platform_sppt")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_ppt_platform_sppt(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_ppt_platform_sppt(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, ppt_platform_sppt, "ppt_platform_sppt", value, 5, 130) platform_ppt_set_value!(self, ppt_platform_sppt, "ppt_platform_sppt", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the dynamic boost limit of the Nvidia dGPU:
/// * min=5, max=25
#[zbus(property)]
async fn nv_dynamic_boost(&self) -> Result<u8, FdoErr> { async fn nv_dynamic_boost(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, nv_dynamic_boost, "nv_dynamic_boost", 5) platform_get_value!(self, nv_dynamic_boost, "nv_dynamic_boost")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_nv_dynamic_boost(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_nv_dynamic_boost(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, nv_dynamic_boost, "nv_dynamic_boost", value, 5, 25) platform_ppt_set_value!(self, nv_dynamic_boost, "nv_dynamic_boost", value)?;
self.config.lock().await.write();
Ok(())
} }
#[dbus_interface(property)] /// Set the target temperature limit of the Nvidia dGPU:
/// * min=75, max=87
#[zbus(property)]
async fn nv_temp_target(&self) -> Result<u8, FdoErr> { async fn nv_temp_target(&self) -> Result<u8, FdoErr> {
platform_get_value_if_some!(self, nv_temp_target, "nv_temp_target", 5) platform_get_value!(self, nv_temp_target, "nv_temp_target")
} }
#[dbus_interface(property)] #[zbus(property)]
async fn set_nv_temp_target(&mut self, value: u8) -> Result<(), FdoErr> { async fn set_nv_temp_target(&mut self, value: u8) -> Result<(), FdoErr> {
platform_set_with_min_max!(self, nv_temp_target, "nv_temp_target", value, 5, 87) platform_ppt_set_value!(self, nv_temp_target, "nv_temp_target", value)?;
self.config.lock().await.write();
Ok(())
} }
} }
#[async_trait]
impl crate::ZbusRun for CtrlPlatform { impl crate::ZbusRun for CtrlPlatform {
async fn add_to_server(self, server: &mut Connection) { async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, ZBUS_PATH, server).await; Self::add_to_server_helper(self, PLATFORM_ZBUS_PATH, server).await;
} }
} }
#[async_trait] impl ReloadAndNotify for CtrlPlatform {
impl crate::Reloadable for CtrlPlatform { type Data = Config;
async fn reload(&mut self) -> Result<(), RogError> {
if self.platform.has_panel_od() { /// Called on config file changed externally
self.platform async fn reload_and_notify(
.set_panel_od(self.config.lock().await.panel_od)?; &mut self,
signal_context: &SignalContext<'static>,
data: Self::Data,
) -> Result<(), RogError> {
let mut config = self.config.lock().await;
if *config != data {
info!("asusd.ron updated externally, reloading and updating internal copy");
if self.power.has_charge_control_end_threshold() {
self.power
.set_charge_control_end_threshold(data.charge_control_end_threshold)?;
self.charge_control_end_threshold_changed(signal_context)
.await?;
}
if self.platform.has_throttle_thermal_policy()
&& config.throttle_policy_linked_epp != data.throttle_policy_linked_epp
{
// TODO: extra stuff
}
macro_rules! reload_and_notify {
($property:tt, $prop_name:literal) => {
concat_idents::concat_idents!(has = has_, $property {
if self.platform.has() && config.$property != data.$property {
concat_idents::concat_idents!(set = set_, $property {
self.platform
.set(data.$property)?;});
concat_idents::concat_idents!(changed = $property, _changed {
self.changed(signal_context).await?;});
}
})
}
}
reload_and_notify!(mini_led_mode, "mini_led_mode");
reload_and_notify!(panel_od, "panel_od");
reload_and_notify!(boot_sound, "boot_sound");
// reload_and_notify!(throttle_thermal_policy, "throttle_thermal_policy");
macro_rules! ppt_reload_and_notify {
($property:tt, $prop_name:literal) => {
concat_idents::concat_idents!(has = has_, $property {
if self.platform.has() && config.$property != data.$property {
concat_idents::concat_idents!(set = set_, $property {
self.platform
.set(data.$property.unwrap_or_default())?;});
concat_idents::concat_idents!(changed = $property, _changed {
self.changed(signal_context).await?;});
}
})
}
}
ppt_reload_and_notify!(ppt_pl1_spl, "ppt_pl1_spl");
ppt_reload_and_notify!(ppt_pl2_sppt, "ppt_pl2_sppt");
ppt_reload_and_notify!(ppt_fppt, "ppt_fppt");
ppt_reload_and_notify!(ppt_apu_sppt, "ppt_apu_sppt");
ppt_reload_and_notify!(ppt_platform_sppt, "ppt_platform_sppt");
ppt_reload_and_notify!(nv_dynamic_boost, "nv_dynamic_boost");
ppt_reload_and_notify!(nv_temp_target, "nv_temp_target");
*config = data;
} }
if self.platform.has_mini_led_mode() { Ok(())
self.platform }
.set_mini_led_mode(self.config.lock().await.mini_led_mode)?; }
impl crate::Reloadable for CtrlPlatform {
async fn reload(&mut self) -> Result<(), RogError> {
macro_rules! reload {
($property:tt, $prop_name:literal) => {
concat_idents::concat_idents!(has = has_, $property {
if self.platform.has() {
concat_idents::concat_idents!(set = set_, $property {
self.platform
.set(self.config.lock().await.$property)?;});
}
})
}
} }
reload!(mini_led_mode, "mini_led_mode");
reload!(panel_od, "panel_od");
reload!(boot_sound, "boot_sound");
macro_rules! ppt_reload {
($property:tt, $prop_name:literal) => {
concat_idents::concat_idents!(has = has_, $property {
if self.platform.has() {
concat_idents::concat_idents!(set = set_, $property {
self.platform
.set(self.config.lock().await.$property.unwrap_or_default())?;});
}
})
}
}
ppt_reload!(ppt_pl1_spl, "ppt_pl1_spl");
ppt_reload!(ppt_pl2_sppt, "ppt_pl2_sppt");
ppt_reload!(ppt_fppt, "ppt_fppt");
ppt_reload!(ppt_apu_sppt, "ppt_apu_sppt");
ppt_reload!(ppt_platform_sppt, "ppt_platform_sppt");
ppt_reload!(nv_dynamic_boost, "nv_dynamic_boost");
ppt_reload!(nv_temp_target, "nv_temp_target");
if self.power.has_charge_control_end_threshold() { if self.power.has_charge_control_end_threshold() {
self.power.set_charge_control_end_threshold( self.power.set_charge_control_end_threshold(
@@ -533,8 +833,11 @@ impl crate::Reloadable for CtrlPlatform {
} }
if let Ok(power_plugged) = self.power.get_online() { if let Ok(power_plugged) = self.power.get_online() {
self.config.lock().await.last_power_plugged = power_plugged;
if self.platform.has_throttle_thermal_policy() { if self.platform.has_throttle_thermal_policy() {
self.update_policy_ac_or_bat(power_plugged > 0).await; let change_epp = self.config.lock().await.throttle_policy_linked_epp;
self.update_policy_ac_or_bat(power_plugged > 0, change_epp)
.await;
} }
self.run_ac_or_bat_cmd(power_plugged > 0).await; self.run_ac_or_bat_cmd(power_plugged > 0).await;
} }
@@ -550,7 +853,7 @@ impl CtrlPlatform {
task_watch_item!(charge_control_end_threshold power); task_watch_item!(charge_control_end_threshold power);
task_watch_item_notify!(post_animation_sound platform); task_watch_item_notify!(boot_sound platform);
task_watch_item_notify!(dgpu_disable platform); task_watch_item_notify!(dgpu_disable platform);
@@ -574,10 +877,9 @@ impl CtrlPlatform {
task_watch_item_notify!(nv_temp_target platform); task_watch_item_notify!(nv_temp_target platform);
} }
#[async_trait]
impl CtrlTask for CtrlPlatform { impl CtrlTask for CtrlPlatform {
fn zbus_path() -> &'static str { fn zbus_path() -> &'static str {
ZBUS_PATH PLATFORM_ZBUS_PATH
} }
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
@@ -613,11 +915,18 @@ impl CtrlTask for CtrlPlatform {
.ok(); .ok();
} }
if let Ok(power_plugged) = platform1.power.get_online() { if let Ok(power_plugged) = platform1.power.get_online() {
if !sleeping && platform1.platform.has_throttle_thermal_policy() { if platform1.config.lock().await.last_power_plugged != power_plugged {
platform1.update_policy_ac_or_bat(power_plugged > 0).await; if !sleeping && platform1.platform.has_throttle_thermal_policy() {
} let change_epp =
if !sleeping { platform1.config.lock().await.throttle_policy_linked_epp;
platform1.run_ac_or_bat_cmd(power_plugged > 0).await; platform1
.update_policy_ac_or_bat(power_plugged > 0, change_epp)
.await;
}
if !sleeping {
platform1.run_ac_or_bat_cmd(power_plugged > 0).await;
}
platform1.config.lock().await.last_power_plugged = power_plugged;
} }
} }
} }
@@ -648,7 +957,10 @@ impl CtrlTask for CtrlPlatform {
// power change // power change
async move { async move {
if platform3.platform.has_throttle_thermal_policy() { if platform3.platform.has_throttle_thermal_policy() {
platform3.update_policy_ac_or_bat(power_plugged).await; let change_epp = platform3.config.lock().await.throttle_policy_linked_epp;
platform3
.update_policy_ac_or_bat(power_plugged, change_epp)
.await;
} }
platform3.run_ac_or_bat_cmd(power_plugged).await; platform3.run_ac_or_bat_cmd(power_plugged).await;
} }
@@ -669,7 +981,7 @@ impl CtrlTask for CtrlPlatform {
// NOTE: Can't have this as a watch because on a write to it, it reverts back to // NOTE: Can't have this as a watch because on a write to it, it reverts back to
// booted-with value as it does not actually change until reboot. // booted-with value as it does not actually change until reboot.
self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; self.watch_gpu_mux_mode(signal_ctxt.clone()).await?;
self.watch_post_animation_sound(signal_ctxt.clone()).await?; self.watch_boot_sound(signal_ctxt.clone()).await?;
self.watch_ppt_pl1_spl(signal_ctxt.clone()).await?; self.watch_ppt_pl1_spl(signal_ctxt.clone()).await?;
self.watch_ppt_pl2_sppt(signal_ctxt.clone()).await?; self.watch_ppt_pl2_sppt(signal_ctxt.clone()).await?;
@@ -692,13 +1004,14 @@ impl CtrlTask for CtrlPlatform {
if let Ok(profile) = ctrl if let Ok(profile) = ctrl
.platform .platform
.get_throttle_thermal_policy() .get_throttle_thermal_policy()
.map(PlatformPolicy::from) .map(ThrottlePolicy::from)
.map_err(|e| { .map_err(|e| {
error!("Platform: get_throttle_thermal_policy error: {e}"); error!("Platform: get_throttle_thermal_policy error: {e}");
}) })
{ {
ctrl.check_and_set_epp(profile); let change_epp = ctrl.config.lock().await.throttle_policy_linked_epp;
ctrl.config.lock().await.platform_policy_to_restore = profile; let epp = ctrl.get_config_epp_for_throttle(profile).await;
ctrl.check_and_set_epp(epp, change_epp);
} }
} }
} }
+51
View File
@@ -0,0 +1,51 @@
use config_traits::{StdConfig, StdConfigLoad};
use rog_slash::{DeviceState, SlashMode};
use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "slash.ron";
/// Config for base system actions for the anime display
#[derive(Deserialize, Serialize, Debug)]
pub struct SlashConfig {
pub slash_enabled: bool,
pub slash_brightness: u8,
pub slash_interval: u8,
pub slash_mode: SlashMode,
}
impl Default for SlashConfig {
fn default() -> Self {
SlashConfig {
slash_enabled: true,
slash_brightness: 255,
slash_interval: 0,
slash_mode: SlashMode::Bounce,
}
}
}
impl StdConfig for SlashConfig {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
impl StdConfigLoad for SlashConfig {}
impl From<&SlashConfig> for DeviceState {
fn from(config: &SlashConfig) -> Self {
DeviceState {
slash_enabled: config.slash_enabled,
slash_brightness: config.slash_brightness,
slash_interval: config.slash_interval,
slash_mode: config.slash_mode,
}
}
}
+98
View File
@@ -0,0 +1,98 @@
pub mod config;
pub mod trait_impls;
use config_traits::{StdConfig, StdConfigLoad};
use rog_platform::hid_raw::HidRaw;
use rog_platform::usb_raw::USBRaw;
use rog_slash::error::SlashError;
use rog_slash::usb::{get_slash_type, pkt_set_mode, pkt_set_options, pkts_for_init};
use rog_slash::{SlashMode, SlashType};
use crate::ctrl_slash::config::SlashConfig;
use crate::error::RogError;
enum Node {
Usb(USBRaw),
Hid(HidRaw),
}
impl Node {
pub fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
// TODO: map and pass on errors
match self {
Node::Usb(u) => {
u.write_bytes(message).ok();
}
Node::Hid(h) => {
h.write_bytes(message).ok();
}
}
Ok(())
}
}
pub struct CtrlSlash {
node: Node,
config: SlashConfig,
}
impl CtrlSlash {
#[inline]
pub fn new() -> Result<CtrlSlash, RogError> {
let slash_type = get_slash_type()?;
if matches!(slash_type, SlashType::Unknown | SlashType::Unsupported) {
return Err(RogError::Slash(SlashError::NoDevice));
}
let usb = USBRaw::new(rog_slash::usb::PROD_ID).ok();
let hid = HidRaw::new(rog_slash::usb::PROD_ID_STR).ok();
let node = if usb.is_some() {
unsafe { Node::Usb(usb.unwrap_unchecked()) }
} else if hid.is_some() {
unsafe { Node::Hid(hid.unwrap_unchecked()) }
} else {
return Err(RogError::NotSupported);
};
let ctrl = CtrlSlash {
node,
config: SlashConfig::new().load(),
};
ctrl.do_initialization()?;
Ok(ctrl)
}
fn do_initialization(&self) -> Result<(), RogError> {
let init_packets = pkts_for_init();
self.node.write_bytes(&init_packets[0])?;
self.node.write_bytes(&init_packets[1])?;
// Apply config upon initialization
let option_packets = pkt_set_options(
self.config.slash_enabled,
self.config.slash_brightness,
self.config.slash_interval,
);
self.node.write_bytes(&option_packets)?;
let mode_packets = pkt_set_mode(self.config.slash_mode);
self.node.write_bytes(&mode_packets[0])?;
self.node.write_bytes(&mode_packets[1])?;
Ok(())
}
pub fn set_options(&self, enabled: bool, brightness: u8, interval: u8) -> Result<(), RogError> {
let command_packets = pkt_set_options(enabled, brightness, interval);
self.node.write_bytes(&command_packets)?;
Ok(())
}
pub fn set_slash_mode(&self, slash_mode: SlashMode) -> Result<(), RogError> {
let command_packets = pkt_set_mode(slash_mode);
self.node.write_bytes(&command_packets[0])?;
self.node.write_bytes(&command_packets[1])?;
Ok(())
}
}
+161
View File
@@ -0,0 +1,161 @@
use std::sync::Arc;
use config_traits::StdConfig;
use log::warn;
use rog_slash::usb::{pkt_set_mode, pkt_set_options};
use rog_slash::{DeviceState, SlashMode};
use zbus::export::futures_util::lock::Mutex;
use zbus::{interface, Connection, SignalContext};
use crate::ctrl_slash::CtrlSlash;
use crate::error::RogError;
pub const SLASH_ZBUS_NAME: &str = "Slash";
pub const SLASH_ZBUS_PATH: &str = "/org/asuslinux";
#[derive(Clone)]
pub struct CtrlSlashZbus(pub Arc<Mutex<CtrlSlash>>);
/// The struct with the main dbus methods requires this trait
impl crate::ZbusRun for CtrlSlashZbus {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, SLASH_ZBUS_PATH, server).await;
}
}
#[interface(name = "org.asuslinux.Slash")]
impl CtrlSlashZbus {
/// Get enabled or not
#[zbus(property)]
async fn enabled(&self) -> bool {
let lock = self.0.lock().await;
lock.config.slash_enabled
}
/// Set enabled true or false
async fn set_enabled(&self, enabled: bool) {
let mut lock = self.0.lock().await;
let brightness = if enabled && lock.config.slash_brightness == 0 {
0x88
} else {
lock.config.slash_brightness
};
lock.node
.write_bytes(&pkt_set_options(
enabled,
brightness,
lock.config.slash_interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_enabled = enabled;
lock.config.slash_brightness = brightness;
lock.config.write();
}
/// Get brightness level
#[zbus(property)]
async fn brightness(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_brightness
}
/// Set brightness level
async fn set_brightness(&self, brightness: u8) {
let mut lock = self.0.lock().await;
let enabled = brightness > 0;
lock.node
.write_bytes(&pkt_set_options(
enabled,
brightness,
lock.config.slash_interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_enabled = enabled;
lock.config.slash_brightness = brightness;
lock.config.write();
}
#[zbus(property)]
async fn interval(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_interval
}
/// Set interval between slash animations (0-255)
async fn set_interval(&self, interval: u8) {
let mut lock = self.0.lock().await;
lock.node
.write_bytes(&pkt_set_options(
lock.config.slash_enabled,
lock.config.slash_brightness,
interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_interval = interval;
lock.config.write();
}
#[zbus(property)]
async fn slash_mode(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_interval
}
/// Set interval between slash animations (0-255)
async fn set_slash_mode(&self, slash_mode: SlashMode) {
let mut lock = self.0.lock().await;
let command_packets = pkt_set_mode(slash_mode);
lock.node
.write_bytes(&command_packets[0])
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.node
.write_bytes(&command_packets[1])
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_mode = slash_mode;
lock.config.write();
}
/// Get the device state as stored by asusd
// #[zbus(property)]
async fn device_state(&self) -> DeviceState {
let lock = self.0.lock().await;
DeviceState::from(&lock.config)
}
}
impl crate::CtrlTask for CtrlSlashZbus {
fn zbus_path() -> &'static str {
SLASH_ZBUS_PATH
}
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
Ok(())
}
}
impl crate::Reloadable for CtrlSlashZbus {
async fn reload(&mut self) -> Result<(), RogError> {
Ok(())
}
}
+42 -50
View File
@@ -1,33 +1,30 @@
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::io::Write;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use ::zbus::export::futures_util::lock::Mutex; use ::zbus::export::futures_util::lock::Mutex;
use ::zbus::Connection; use ::zbus::Connection;
use asusd::config::Config; use asusd::config::Config;
use asusd::ctrl_anime::config::AnimeConfig;
use asusd::ctrl_anime::trait_impls::CtrlAnimeZbus; use asusd::ctrl_anime::trait_impls::CtrlAnimeZbus;
use asusd::ctrl_anime::CtrlAnime; use asusd::ctrl_anime::CtrlAnime;
use asusd::ctrl_aura::controller::CtrlKbdLed; use asusd::ctrl_aura::manager::AuraManager;
use asusd::ctrl_aura::trait_impls::CtrlAuraZbus;
use asusd::ctrl_fancurves::CtrlFanCurveZbus; use asusd::ctrl_fancurves::CtrlFanCurveZbus;
use asusd::ctrl_platform::CtrlPlatform; use asusd::ctrl_platform::CtrlPlatform;
use asusd::{print_board_info, CtrlTask, Reloadable, ZbusRun, DBUS_NAME}; use asusd::ctrl_slash::trait_impls::CtrlSlashZbus;
use config_traits::{StdConfig, StdConfigLoad2}; use asusd::ctrl_slash::CtrlSlash;
use log::{error, info, warn}; use asusd::{print_board_info, start_tasks, CtrlTask, DBUS_NAME};
use rog_aura::aura_detection::LaptopLedData; use config_traits::{StdConfig, StdConfigLoad3};
use tokio::time::sleep; use log::{error, info};
use zbus::SignalContext; use zbus::fdo::ObjectManager;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// console_subscriber::init();
let mut logger = env_logger::Builder::new(); let mut logger = env_logger::Builder::new();
logger logger
.parse_default_env() .parse_default_env()
.target(env_logger::Target::Stdout) .target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())) .format_timestamp(None)
.init(); .init();
let is_service = match env::var_os("IS_SERVICE") { let is_service = match env::var_os("IS_SERVICE") {
@@ -46,6 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
info!(" daemon v{}", asusd::VERSION); info!(" daemon v{}", asusd::VERSION);
info!(" rog-anime v{}", rog_anime::VERSION); info!(" rog-anime v{}", rog_anime::VERSION);
info!(" rog-slash v{}", rog_slash::VERSION);
info!(" rog-aura v{}", rog_aura::VERSION); info!(" rog-aura v{}", rog_aura::VERSION);
info!(" rog-profiles v{}", rog_profiles::VERSION); info!(" rog-profiles v{}", rog_profiles::VERSION);
info!("rog-platform v{}", rog_platform::VERSION); info!("rog-platform v{}", rog_platform::VERSION);
@@ -62,22 +60,18 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
// Start zbus server // Start zbus server
let mut connection = Connection::system().await?; let mut connection = Connection::system().await?;
connection
.object_server()
.at("/org/asuslinux", ObjectManager)
.await
.unwrap();
let config = Config::new().load(); let config = Config::new().load();
let cfg_path = config.file_path();
let config = Arc::new(Mutex::new(config)); let config = Arc::new(Mutex::new(config));
// supported.add_to_server(&mut connection).await; // supported.add_to_server(&mut connection).await;
match CtrlPlatform::new(config.clone()) {
Ok(ctrl) => {
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("CtrlPlatform: {}", err);
}
}
match CtrlFanCurveZbus::new() { match CtrlFanCurveZbus::new() {
Ok(ctrl) => { Ok(ctrl) => {
let sig_ctx = CtrlFanCurveZbus::signal_context(&connection)?; let sig_ctx = CtrlFanCurveZbus::signal_context(&connection)?;
@@ -88,7 +82,21 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
} }
} }
match CtrlAnime::new(AnimeConfig::new().load()) { match CtrlPlatform::new(
config.clone(),
&cfg_path,
CtrlPlatform::signal_context(&connection)?,
) {
Ok(ctrl) => {
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("CtrlPlatform: {}", err);
}
}
match CtrlAnime::new() {
Ok(ctrl) => { Ok(ctrl) => {
let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl))); let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl)));
let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?; let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?;
@@ -99,44 +107,28 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
} }
} }
let laptop = LaptopLedData::get_data(); match CtrlSlash::new() {
// CtrlKbdLed deviates from the config pattern above due to requiring a keyboard
// detection first
match CtrlKbdLed::new(laptop) {
Ok(ctrl) => { Ok(ctrl) => {
let zbus = CtrlAuraZbus(Arc::new(Mutex::new(ctrl))); let zbus = CtrlSlashZbus(Arc::new(Mutex::new(ctrl)));
let sig_ctx = CtrlAuraZbus::signal_context(&connection)?; // Currently, the Slash has no need for a loop watching power events, however,
// it could be cool to have the slash do some power-on/off animation
// (It has a built-in power on animation which plays when u plug in the power
// supply)
let sig_ctx = CtrlSlashZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?; start_tasks(zbus, &mut connection, sig_ctx).await?;
} }
Err(err) => { Err(err) => {
error!("Keyboard control: {}", err); info!("AniMe control: {}", err);
} }
} }
let _ = AuraManager::new(connection.clone()).await?;
// Request dbus name after finishing initalizing all functions // Request dbus name after finishing initalizing all functions
connection.request_name(DBUS_NAME).await?; connection.request_name(DBUS_NAME).await?;
loop { loop {
// This is just a blocker to idle and ensure the reator reacts // This is just a blocker to idle and ensure the reator reacts
sleep(Duration::from_millis(1000)).await; connection.executor().tick().await;
} }
} }
async fn start_tasks<T>(
mut zbus: T,
connection: &mut Connection,
signal_ctx: SignalContext<'static>,
) -> Result<(), Box<dyn Error>>
where
T: ZbusRun + Reloadable + CtrlTask + Clone,
{
let task = zbus.clone();
zbus.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
zbus.add_to_server(connection).await;
task.create_tasks(signal_ctx).await.ok();
Ok(())
}
+9
View File
@@ -5,6 +5,7 @@ use config_traits::ron;
use rog_anime::error::AnimeError; use rog_anime::error::AnimeError;
use rog_platform::error::PlatformError; use rog_platform::error::PlatformError;
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
use rog_slash::error::SlashError;
#[derive(Debug)] #[derive(Debug)]
pub enum RogError { pub enum RogError {
@@ -31,6 +32,7 @@ pub enum RogError {
NoAuraKeyboard, NoAuraKeyboard,
NoAuraNode, NoAuraNode,
Anime(AnimeError), Anime(AnimeError),
Slash(SlashError),
Platform(PlatformError), Platform(PlatformError),
SystemdUnitAction(String), SystemdUnitAction(String),
SystemdUnitWaitTimeout(String), SystemdUnitWaitTimeout(String),
@@ -72,6 +74,7 @@ impl fmt::Display for RogError {
RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"), RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets), RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
RogError::Slash(deets) => write!(f, "Slash error: {}", deets),
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets), RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
RogError::SystemdUnitAction(action) => { RogError::SystemdUnitAction(action) => {
write!(f, "systemd unit action {} failed", action) write!(f, "systemd unit action {} failed", action)
@@ -103,6 +106,12 @@ impl From<AnimeError> for RogError {
} }
} }
impl From<SlashError> for RogError {
fn from(err: SlashError) -> Self {
RogError::Slash(err)
}
}
impl From<PlatformError> for RogError { impl From<PlatformError> for RogError {
fn from(err: PlatformError) -> Self { fn from(err: PlatformError) -> Self {
RogError::Platform(err) RogError::Platform(err)
+111 -85
View File
@@ -9,13 +9,14 @@ pub mod ctrl_aura;
pub mod ctrl_fancurves; pub mod ctrl_fancurves;
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode /// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
pub mod ctrl_platform; pub mod ctrl_platform;
/// Control of Slash led bar
pub mod ctrl_slash;
pub mod error; pub mod error;
use std::future::Future; use std::future::Future;
use std::time::Duration; use std::time::Duration;
use async_trait::async_trait;
use dmi_id::DMIID; use dmi_id::DMIID;
use futures_lite::stream::StreamExt; use futures_lite::stream::StreamExt;
use log::{debug, info, warn}; use log::{debug, info, warn};
@@ -51,7 +52,7 @@ pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
/// task_watch_item!(panel_od platform); /// task_watch_item!(panel_od platform);
/// task_watch_item!(gpu_mux_mode platform); /// task_watch_item!(gpu_mux_mode platform);
/// } /// }
/// ``` /// ```\
/// // TODO: this is kind of useless if it can't trigger some action /// // TODO: this is kind of useless if it can't trigger some action
#[macro_export] #[macro_export]
macro_rules! task_watch_item { macro_rules! task_watch_item {
@@ -130,34 +131,43 @@ pub fn print_board_info() {
info!("Board name: {}", dmi.board_name); info!("Board name: {}", dmi.board_name);
} }
#[async_trait]
pub trait Reloadable { pub trait Reloadable {
async fn reload(&mut self) -> Result<(), RogError>; fn reload(&mut self) -> impl Future<Output = Result<(), RogError>> + Send;
} }
#[async_trait] pub trait ReloadAndNotify {
pub trait ZbusRun { type Data: Send;
async fn add_to_server(self, server: &mut Connection);
async fn add_to_server_helper( fn reload_and_notify(
&mut self,
signal_context: &SignalContext<'static>,
data: Self::Data,
) -> impl Future<Output = Result<(), RogError>> + Send;
}
pub trait ZbusRun {
fn add_to_server(self, server: &mut Connection) -> impl Future<Output = ()> + Send;
fn add_to_server_helper(
iface: impl zbus::Interface, iface: impl zbus::Interface,
path: &str, path: &str,
server: &mut Connection, server: &mut Connection,
) { ) -> impl Future<Output = ()> + Send {
server async move {
.object_server() server
.at(&ObjectPath::from_str_unchecked(path), iface) .object_server()
.await .at(&ObjectPath::from_str_unchecked(path), iface)
.map_err(|err| { .await
warn!("{}: add_to_server {}", path, err); .map_err(|err| {
err warn!("{}: add_to_server {}", path, err);
}) err
.ok(); })
.ok();
}
} }
} }
/// Set up a task to run on the async executor /// Set up a task to run on the async executor
#[async_trait]
pub trait CtrlTask { pub trait CtrlTask {
fn zbus_path() -> &'static str; fn zbus_path() -> &'static str;
@@ -168,7 +178,10 @@ pub trait CtrlTask {
/// Implement to set up various tasks that may be required, using the /// Implement to set up various tasks that may be required, using the
/// `Executor`. No blocking loops are allowed, or they must be run on a /// `Executor`. No blocking loops are allowed, or they must be run on a
/// separate thread. /// separate thread.
async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; fn create_tasks(
&self,
signal: SignalContext<'static>,
) -> impl Future<Output = Result<(), RogError>> + Send;
// /// Create a timed repeating task // /// Create a timed repeating task
// async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + // async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send +
@@ -186,95 +199,89 @@ pub trait CtrlTask {
/// ///
/// The closures can potentially block, so execution time should be the /// The closures can potentially block, so execution time should be the
/// minimal possible such as save a variable. /// minimal possible such as save a variable.
async fn create_sys_event_tasks< fn create_sys_event_tasks<Fut1, Fut2, Fut3, Fut4, F1, F2, F3, F4>(
Fut1,
Fut2,
Fut3,
Fut4,
F1: Send + 'static,
F2: Send + 'static,
F3: Send + 'static,
F4: Send + 'static,
>(
&self, &self,
mut on_prepare_for_sleep: F1, mut on_prepare_for_sleep: F1,
mut on_prepare_for_shutdown: F2, mut on_prepare_for_shutdown: F2,
mut on_lid_change: F3, mut on_lid_change: F3,
mut on_external_power_change: F4, mut on_external_power_change: F4,
) where ) -> impl Future<Output = ()> + Send
F1: FnMut(bool) -> Fut1, where
F2: FnMut(bool) -> Fut2, F1: FnMut(bool) -> Fut1 + Send + 'static,
F3: FnMut(bool) -> Fut3, F2: FnMut(bool) -> Fut2 + Send + 'static,
F4: FnMut(bool) -> Fut4, F3: FnMut(bool) -> Fut3 + Send + 'static,
F4: FnMut(bool) -> Fut4 + Send + 'static,
Fut1: Future<Output = ()> + Send, Fut1: Future<Output = ()> + Send,
Fut2: Future<Output = ()> + Send, Fut2: Future<Output = ()> + Send,
Fut3: Future<Output = ()> + Send, Fut3: Future<Output = ()> + Send,
Fut4: Future<Output = ()> + Send, Fut4: Future<Output = ()> + Send,
{ {
let connection = Connection::system() async {
.await let connection = Connection::system()
.expect("Controller could not create dbus connection"); .await
.expect("Controller could not create dbus connection");
let manager = ManagerProxy::builder(&connection) let manager = ManagerProxy::builder(&connection)
.cache_properties(CacheProperties::No) .cache_properties(CacheProperties::No)
.build() .build()
.await .await
.expect("Controller could not create ManagerProxy"); .expect("Controller could not create ManagerProxy");
let manager1 = manager.clone(); let manager1 = manager.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Ok(mut notif) = manager1.receive_prepare_for_shutdown().await { if let Ok(mut notif) = manager1.receive_prepare_for_shutdown().await {
while let Some(event) = notif.next().await { while let Some(event) = notif.next().await {
// blocks thread :| // blocks thread :|
if let Ok(args) = event.args() { if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_shutdown({})", args.start); debug!("Doing on_prepare_for_shutdown({})", args.start);
on_prepare_for_shutdown(args.start).await; on_prepare_for_shutdown(args.start).await;
}
} }
} }
} });
});
let manager2 = manager.clone(); let manager2 = manager.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Ok(mut notif) = manager2.receive_prepare_for_sleep().await { if let Ok(mut notif) = manager2.receive_prepare_for_sleep().await {
while let Some(event) = notif.next().await { while let Some(event) = notif.next().await {
// blocks thread :| // blocks thread :|
if let Ok(args) = event.args() { if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_sleep({})", args.start); debug!("Doing on_prepare_for_sleep({})", args.start);
on_prepare_for_sleep(args.start).await; on_prepare_for_sleep(args.start).await;
}
} }
} }
} });
});
let manager3 = manager.clone(); let manager3 = manager.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut last_power = manager3.on_external_power().await.unwrap_or_default(); let mut last_power = manager3.on_external_power().await.unwrap_or_default();
loop { loop {
if let Ok(next) = manager3.on_external_power().await { if let Ok(next) = manager3.on_external_power().await {
if next != last_power { if next != last_power {
last_power = next; last_power = next;
on_external_power_change(next).await; on_external_power_change(next).await;
}
} }
sleep(Duration::from_secs(2)).await;
} }
sleep(Duration::from_secs(2)).await; });
}
});
tokio::spawn(async move { tokio::spawn(async move {
let mut last_lid = manager.lid_closed().await.unwrap_or_default(); let mut last_lid = manager.lid_closed().await.unwrap_or_default();
// need to loop on these as they don't emit signals // need to loop on these as they don't emit signals
loop { loop {
if let Ok(next) = manager.lid_closed().await { if let Ok(next) = manager.lid_closed().await {
if next != last_lid { if next != last_lid {
last_lid = next; last_lid = next;
on_lid_change(next).await; on_lid_change(next).await;
}
} }
sleep(Duration::from_secs(2)).await;
} }
sleep(Duration::from_secs(2)).await; });
} }
});
} }
} }
@@ -283,3 +290,22 @@ pub trait GetSupported {
fn get_supported() -> Self::A; fn get_supported() -> Self::A;
} }
pub async fn start_tasks<T>(
mut zbus: T,
connection: &mut Connection,
signal_ctx: SignalContext<'static>,
) -> Result<(), RogError>
where
T: ZbusRun + Reloadable + CtrlTask + Clone,
{
let zbus_clone = zbus.clone();
zbus.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
zbus.add_to_server(connection).await;
zbus_clone.create_tasks(signal_ctx).await.ok();
Ok(())
}
@@ -1,57 +0,0 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.asuslinux.Daemon">
<!--
Writes a data stream of length. Will force system thread to exit until
it is restarted
-->
<method name="Write">
<arg name="input" type="(ays)" direction="in"/>
</method>
<!--
The main loop is the base system set action if the user isn't running
the user daemon
-->
<method name="RunMainLoop">
<arg name="start" type="b" direction="in"/>
</method>
<!--
Get the device state as stored by asusd
-->
<method name="DeviceState">
<arg type="(bub(ssss)bbbu)" direction="out"/>
</method>
<!--
Set base brightness level
-->
<!--
Set base brightness level
-->
<property name="Brightness" type="u" access="readwrite"/>
<!--
Set which builtin animation is used for each stage
-->
<property name="BuiltinAnimations" type="(ssss)" access="readwrite"/>
<!--
Enable the builtin animations or not. This is quivalent to "Powersave
animations" in Armory crate
-->
<property name="BuiltinsEnabled" type="b" access="readwrite"/>
<!--
Set whether the AniMe is enabled at all
-->
<property name="EnableDisplay" type="b" access="readwrite"/>
<!--
Set if to turn the AniMe Matrix off when the lid is closed
-->
<property name="OffWhenLidClosed" type="b" access="readwrite"/>
<!--
Set if to turn the AniMe Matrix off when the laptop is suspended
-->
<property name="OffWhenSuspended" type="b" access="readwrite"/>
<!--
Set if to turn the AniMe Matrix off when external power is unplugged
-->
<property name="OffWhenUnplugged" type="b" access="readwrite"/>
</interface>
</node>
@@ -1,65 +0,0 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.asuslinux.Daemon">
<!--
Get the data set for every mode available
-->
<method name="AllModeData">
<arg type="a{u(us(yyy)(yyy)ss)}" direction="out"/>
</method>
<!--
On machine that have some form of either per-key keyboard or per-zone
this can be used to write custom effects over dbus. The input is a
nested `Vec<Vec<8>>` where `Vec<u8>` is a raw USB packet
-->
<method name="DirectAddressingRaw">
<arg name="data" type="aay" direction="in"/>
</method>
<!--
Return the current LED brightness
-->
<!--
Set the keyboard brightness level (0-3)
-->
<property name="Brightness" type="u" access="readwrite"/>
<!--
Return the device type for this Aura keyboard
-->
<property name="DeviceType" type="s" access="read"/>
<!--
The current mode data
-->
<!--
Set an Aura effect if the effect mode or zone is supported.
On success the aura config file is read to refresh cached values, then
the effect is stored and config written to disk.
-->
<property name="LedMode" type="u" access="readwrite"/>
<!--
The current mode data
-->
<!--
Set an Aura effect if the effect mode or zone is supported.
On success the aura config file is read to refresh cached values, then
the effect is stored and config written to disk.
-->
<property name="LedModeData" type="(us(yyy)(yyy)ss)" access="readwrite"/>
<!--
Set a variety of states, input is array of enum.
`enabled` sets if the sent array should be disabled or enabled
For Modern ROG devices the "enabled" flag is ignored.
-->
<property name="LedPower" type="(asas((sbbbb)(sbbbb)(sbbbb)(sbbbb)(sbbbb)))" access="readwrite"/>
<!--
Total levels of brightness available
-->
<property name="SupportedBrightness" type="au" access="read"/>
<!--
The total available modes
-->
<property name="SupportedModes" type="au" access="read"/>
</interface>
</node>
@@ -1,56 +0,0 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.asuslinux.Daemon">
<!--
Set all fan curves for a profile to enabled status. Will also activate a
fan curve if in the same profile mode
-->
<method name="SetFanCurvesEnabled">
<arg name="profile" type="s" direction="in"/>
<arg name="enabled" type="b" direction="in"/>
</method>
<!--
Set a single fan curve for a profile to enabled status. Will also
activate a fan curve if in the same profile mode
-->
<method name="SetProfileFanCurveEnabled">
<arg name="profile" type="s" direction="in"/>
<arg name="fan" type="s" direction="in"/>
<arg name="enabled" type="b" direction="in"/>
</method>
<!--
Get the fan-curve data for the currently active PlatformPolicy
-->
<method name="FanCurveData">
<arg name="profile" type="s" direction="in"/>
<arg type="a(s(yyyyyyyy)(yyyyyyyy)b)" direction="out"/>
</method>
<!--
Set the fan curve for the specified profile.
Will also activate the fan curve if the user is in the same mode.
-->
<method name="SetFanCurve">
<arg name="profile" type="s" direction="in"/>
<arg name="curve" type="(s(yyyyyyyy)(yyyyyyyy)b)" direction="in"/>
</method>
<!--
Reset the stored (self) and device curve to the defaults of the
platform.
Each platform_profile has a different default and the defualt can be
read only for the currently active profile.
-->
<method name="SetActiveCurveToDefaults">
</method>
<!--
Reset the stored (self) and device curve to the defaults of the
platform.
Each platform_profile has a different default and the defualt can be
read only for the currently active profile.
-->
<method name="ResetProfileCurves">
<arg name="profile" type="s" direction="in"/>
</method>
</interface>
</node>
@@ -1,46 +0,0 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.asuslinux.Daemon">
<!--
Returns a list of property names that this system supports
-->
<method name="SupportedProperties">
<arg type="as" direction="out"/>
</method>
<method name="SupportedInterfaces">
<arg type="as" direction="out"/>
</method>
<!--
Toggle to next platform_profile. Names provided by `Profiles`.
If fan-curves are supported will also activate a fan curve for profile.
-->
<method name="NextThrottleThermalPolicy">
</method>
<property name="ChargeControlEndThreshold" type="y" access="readwrite"/>
<property name="DgpuDisable" type="b" access="read"/>
<property name="EgpuEnable" type="b" access="read"/>
<property name="GpuMuxMode" type="y" access="readwrite"/>
<!--
Get the `panel_od` value from platform. Updates the stored value in
internal config also.
-->
<property name="MiniLedMode" type="b" access="readwrite"/>
<property name="NvDynamicBoost" type="y" access="readwrite"/>
<property name="NvTempTarget" type="y" access="readwrite"/>
<!--
Get the `panel_od` value from platform. Updates the stored value in
internal config also.
-->
<property name="PanelOd" type="b" access="readwrite"/>
<property name="PostAnimationSound" type="b" access="readwrite"/>
<property name="PptApuSppt" type="y" access="readwrite"/>
<property name="PptFppt" type="y" access="readwrite"/>
<!--
************************************************************************
-->
<property name="PptPl1Spl" type="y" access="readwrite"/>
<property name="PptPl2Sppt" type="y" access="readwrite"/>
<property name="PptPlatformSppt" type="y" access="readwrite"/>
<property name="ThrottleThermalPolicy" type="s" access="readwrite"/>
</interface>
</node>
-57
View File
@@ -1,57 +0,0 @@
/*
Generated by typeshare 1.7.0
*/
export enum AnimBooting {
GlitchConstruction = "GlitchConstruction",
StaticEmergence = "StaticEmergence",
}
export enum AnimAwake {
BinaryBannerScroll = "BinaryBannerScroll",
RogLogoGlitch = "RogLogoGlitch",
}
export enum AnimSleeping {
BannerSwipe = "BannerSwipe",
Starfield = "Starfield",
}
export enum AnimShutdown {
GlitchOut = "GlitchOut",
SeeYa = "SeeYa",
}
export interface Animations {
boot: AnimBooting;
awake: AnimAwake;
sleep: AnimSleeping;
shutdown: AnimShutdown;
}
/** Base LED brightness of the display */
export enum Brightness {
Off = "Off",
Low = "Low",
Med = "Med",
High = "High",
}
export interface DeviceState {
display_enabled: boolean;
display_brightness: Brightness;
builtin_anims_enabled: boolean;
builtin_anims: Animations;
off_when_unplugged: boolean;
off_when_suspended: boolean;
off_when_lid_closed: boolean;
brightness_on_battery: Brightness;
}
export enum AnimeType {
GA401 = "GA401",
GA402 = "GA402",
GU604 = "GU604",
Unknown = "Unknown",
}
-233
View File
@@ -1,233 +0,0 @@
/*
Generated by typeshare 1.7.0
*/
/** Represents the per-key raw USB packets */
export type UsbPackets = number[][];
/**
* A `UsbPackets` contains all data to change the full set of keyboard
* key colours individually.
*
* Each row of the internal array is a full HID packet that can be sent
* to the keyboard EC. One row controls one group of keys, these keys are not
* necessarily all on the same row of the keyboard, with some splitting between
* two rows.
*/
export interface LedUsbPackets {
/** The packet data used to send data to the USB keyboard */
usb_packets: UsbPackets;
/**
* Wether or not this packet collection is zoned. The determines which
* starting bytes are used and what the indexing is for lightbar RGB
* colours
*/
zoned: boolean;
}
export interface Colour {
r: number;
g: number;
b: number;
}
/** Enum of modes that convert to the actual number required by a USB HID packet */
export enum AuraModeNum {
Static = "Static",
Breathe = "Breathe",
Strobe = "Strobe",
Rainbow = "Rainbow",
Star = "Star",
Rain = "Rain",
Highlight = "Highlight",
Laser = "Laser",
Ripple = "Ripple",
Pulse = "Pulse",
Comet = "Comet",
Flash = "Flash",
}
/** Base effects have no zoning, while multizone is 1-4 */
export enum AuraZone {
/** Used if keyboard has no zones, or if setting all */
None = "None",
/** Leftmost zone */
Key1 = "Key1",
/** Zone after leftmost */
Key2 = "Key2",
/** Zone second from right */
Key3 = "Key3",
/** Rightmost zone */
Key4 = "Key4",
/** Logo on the lid (or elsewhere?) */
Logo = "Logo",
/** The left part of a lightbar (typically on the front of laptop) */
BarLeft = "BarLeft",
/** The right part of a lightbar */
BarRight = "BarRight",
}
export enum Speed {
Low = "Low",
Med = "Med",
High = "High",
}
/**
* Used for Rainbow mode.
*
* Enum corresponds to the required integer value
*/
export enum Direction {
Right = "Right",
Left = "Left",
Up = "Up",
Down = "Down",
}
/**
* Default factory modes structure. This easily converts to an USB HID packet
* with:
* ```rust
* // let bytes: [u8; LED_MSG_LEN] = mode.into();
* ```
*/
export interface AuraEffect {
/** The effect type */
mode: AuraModeNum;
/** `AuraZone::None` for no zone or zoneless keyboards */
zone: AuraZone;
/** Primary colour for all modes */
colour1: Colour;
/** Secondary colour in some modes like Breathing or Stars */
colour2: Colour;
/** One of three speeds for modes that support speed (most that animate) */
speed: Speed;
/** Up, down, left, right. Only Rainbow mode seems to use this */
direction: Direction;
}
/** The powerr zones this laptop supports */
export enum PowerZones {
/** The logo on some laptop lids */
Logo = "Logo",
/** The full keyboard (not zones) */
Keyboard = "Keyboard",
/** The lightbar, typically on the front of the laptop */
Lightbar = "Lightbar",
/** The leds that may be placed around the edge of the laptop lid */
Lid = "Lid",
/** The led strip on the rear of some laptops */
RearGlow = "RearGlow",
}
export interface KbAuraPowerState {
zone: PowerZones;
boot: boolean;
awake: boolean;
sleep: boolean;
shutdown: boolean;
}
/**
* Track and control the Aura keyboard power state
*
* # Bits for newer 0x18c6, 0x19B6, 0x1a30, keyboard models
*
* | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Label |
* |--------|---------|---------|---------|----------|
* |00000001| 00000000| 00000000| 00000000|boot_logo_|
* |00000010| 00000000| 00000000| 00000000|boot_keyb_|
* |00000100| 00000000| 00000000| 00000000|awake_logo|
* |00001000| 00000000| 00000000| 00000000|awake_keyb|
* |00010000| 00000000| 00000000| 00000000|sleep_logo|
* |00100000| 00000000| 00000000| 00000000|sleep_keyb|
* |01000000| 00000000| 00000000| 00000000|shut_logo_|
* |10000000| 00000000| 00000000| 00000000|shut_keyb_|
* |00000000| 00000010| 00000000| 00000000|boot_bar__|
* |00000000| 00000100| 00000000| 00000000|awake_bar_|
* |00000000| 00001000| 00000000| 00000000|sleep_bar_|
* |00000000| 00010000| 00000000| 00000000|shut_bar__|
* |00000000| 00000000| 00000001| 00000000|boot_lid__|
* |00000000| 00000000| 00000010| 00000000|awkae_lid_|
* |00000000| 00000000| 00000100| 00000000|sleep_lid_|
* |00000000| 00000000| 00001000| 00000000|shut_lid__|
* |00000000| 00000000| 00000000| 00000001|boot_rear_|
* |00000000| 00000000| 00000000| 00000010|awake_rear|
* |00000000| 00000000| 00000000| 00000100|sleep_rear|
* |00000000| 00000000| 00000000| 00001000|shut_rear_|
*/
export interface AuraPower {
keyboard: KbAuraPowerState;
logo: KbAuraPowerState;
lightbar: KbAuraPowerState;
lid: KbAuraPowerState;
rear_glow: KbAuraPowerState;
}
export enum AuraDevTuf {
Boot = "Boot",
Awake = "Awake",
Sleep = "Sleep",
Keyboard = "Keyboard",
}
/**
* # Bits for older 0x1866 keyboard model
*
* Keybord and Lightbar require Awake, Boot and Sleep apply to both
* Keybord and Lightbar regardless of if either are enabled (or Awake is
* enabled)
*
* | Byte 1 | Byte 2 | Byte 3 | function | hex |
* |------------|------------|------------|----------|----------|
* | 0000, 0000 | 0000, 0000 | 0000, 0010 | Awake | 00,00,02 |
* | 0000, 1000 | 0000, 0000 | 0000, 0000 | Keyboard | 08,00,00 |
* | 0000, 0100 | 0000, 0101 | 0000, 0000 | Lightbar | 04,05,00 |
* | 1100, 0011 | 0001, 0010 | 0000, 1001 | Boot/Sht | c3,12,09 |
* | 0011, 0000 | 0000, 1000 | 0000, 0100 | Sleep | 30,08,04 |
* | 1111, 1111 | 0001, 1111 | 0000, 1111 | all on | |
*/
export enum AuraDevRog1 {
Awake = "Awake",
Keyboard = "Keyboard",
Lightbar = "Lightbar",
Boot = "Boot",
Sleep = "Sleep",
}
/** This struct is intended as a helper to pass args to generic dbus interface */
export interface AuraPowerDev {
/**
* TUF laptops use a similar style of control to the older ROG devices but
* through WMI
*/
tuf: AuraDevTuf[];
/**
* Pre-0x19b6 devices use a different smaller scheme to the newer ROG
* devices
*/
old_rog: AuraDevRog1[];
/** ASUS standardised control scheme from 2020 onwards */
rog: AuraPower;
}
export enum LedBrightness {
Off = "Off",
Low = "Low",
Med = "Med",
High = "High",
}
export enum AuraDevice {
Tuf = "Tuf",
X1854 = "X1854",
X1869 = "X1869",
X1866 = "X1866",
X18c6 = "X18c6",
X19b6 = "X19b6",
X1a30 = "X1a30",
X1abe = "X1abe",
Unknown = "Unknown",
}
-40
View File
@@ -1,40 +0,0 @@
/*
Generated by typeshare 1.7.0
*/
export enum GpuMode {
Discrete = "Discrete",
Optimus = "Optimus",
Integrated = "Integrated",
Egpu = "Egpu",
Vfio = "Vfio",
Ultimate = "Ultimate",
Error = "Error",
NotSupported = "NotSupported",
}
export enum PlatformPolicy {
Balanced = "Balanced",
Performance = "Performance",
Quiet = "Quiet",
}
/** CamelCase names of the properties. Intended for use with DBUS */
export enum Properties {
ChargeControlEndThreshold = "ChargeControlEndThreshold",
DgpuDisable = "DgpuDisable",
GpuMuxMode = "GpuMuxMode",
PostAnimationSound = "PostAnimationSound",
PanelOd = "PanelOd",
MiniLedMode = "MiniLedMode",
EgpuEnable = "EgpuEnable",
PlatformPolicy = "PlatformPolicy",
PptPl1Spl = "PptPl1Spl",
PptPl2Sppt = "PptPl2Sppt",
PptFppt = "PptFppt",
PptApuSppt = "PptApuSppt",
PptPlatformSppt = "PptPlatformSppt",
NvDynamicBoost = "NvDynamicBoost",
NvTempTarget = "NvTempTarget",
}
-24
View File
@@ -1,24 +0,0 @@
/*
Generated by typeshare 1.7.0
*/
export enum FanCurvePU {
CPU = "CPU",
GPU = "GPU",
MID = "MID",
}
export interface CurveData {
fan: FanCurvePU;
pwm: [number, number, number, number, number, number, number, number];
temp: [number, number, number, number, number, number, number, number];
enabled: boolean;
}
/** Main purpose of `FanCurves` is to enable restoring state on system boot */
export interface FanCurveProfiles {
balanced: CurveData[];
performance: CurveData[];
quiet: CurveData[];
}
+7 -7
View File
@@ -1,18 +1,18 @@
[package] [package]
name = "config-traits" name = "config-traits"
license = "MPL-2.0" license.workspace = true
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2021"
version.workspace = true version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies] [dependencies]
serde.workspace = true serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
toml.workspace = true
ron.workspace = true ron.workspace = true
log.workspace = true log.workspace = true
[dev-dependencies] [dev-dependencies]
cargo-husky.workspace = true cargo-husky.workspace = true
+17 -17
View File
@@ -3,10 +3,7 @@
//! updating them from previous versions where fields or names are changed in //! updating them from previous versions where fields or names are changed in
//! some way. //! some way.
//! //!
//! The end canonical file format is `.ron` as this supports rust types well, //! The end canonical file format is `.ron` as this supports rust types well
//! and includes the ability to add commenting, and is less verbose than `json`.
//! Currently the crate will also try to parse from `json` and `toml` if the
//! `ron` parsing fails, then update to `ron` format.
use std::fs::{self, create_dir, File, OpenOptions}; use std::fs::{self, create_dir, File, OpenOptions};
use std::io::{Read, Write}; use std::io::{Read, Write};
@@ -92,6 +89,7 @@ where
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.truncate(false)
.open(self.file_path()) .open(self.file_path())
.unwrap_or_else(|e| panic!("Could not open {:?} {e}", self.file_path())) .unwrap_or_else(|e| panic!("Could not open {:?} {e}", self.file_path()))
} }
@@ -109,6 +107,20 @@ where
} }
} }
/// Open and parse the config file to self from ron format
fn read_new(&self) -> Option<Self> {
if let Ok(data) = fs::read_to_string(self.file_path()) {
if data.is_empty() {
warn!("File is empty {:?}", self.file_path());
} else if let Ok(data) = ron::from_str(&data) {
return Some(data);
} else {
warn!("Could not deserialise {:?}", self.file_path());
}
}
None
}
/// Write the config file data to pretty ron format /// Write the config file data to pretty ron format
fn write(&self) { fn write(&self) {
let mut file = match File::create(self.file_path()) { let mut file = match File::create(self.file_path()) {
@@ -206,21 +218,9 @@ macro_rules! std_config_load {
if let Ok(data) = ron::from_str(&buf) { if let Ok(data) = ron::from_str(&buf) {
self = data; self = data;
log::info!("Parsed RON for {:?}", std::any::type_name::<Self>()); log::info!("Parsed RON for {:?}", std::any::type_name::<Self>());
} else if let Ok(data) = serde_json::from_str(&buf) { } $(else if let Ok(data) = ron::from_str::<$generic>(&buf) {
self = data;
log::info!("Parsed JSON for {:?}", std::any::type_name::<Self>());
} else if let Ok(data) = toml::from_str(&buf) {
self = data;
log::info!("Parsed TOML for {:?}", std::any::type_name::<Self>());
} $(else if let Ok(data) = ron::from_str::<$generic>(&buf) {
self = data.into(); self = data.into();
log::info!("New version failed, trying previous: Parsed RON for {:?}", std::any::type_name::<$generic>()); log::info!("New version failed, trying previous: Parsed RON for {:?}", std::any::type_name::<$generic>());
} else if let Ok(data) = serde_json::from_str::<$generic>(&buf) {
self = data.into();
log::info!("New version failed, trying previous: Parsed JSON for {:?}", std::any::type_name::<$generic>());
} else if let Ok(data) = toml::from_str::<$generic>(&buf) {
self = data.into();
log::info!("Newvious version failed, trying previous: Parsed TOML for {:?}", std::any::type_name::<$generic>());
})* else { })* else {
self.rename_file_old(); self.rename_file_old();
self = Self::new(); self = Self::new();
+6 -2
View File
@@ -1,7 +1,11 @@
[package] [package]
name = "cpuctl" name = "cpuctl"
license = "MPL-2.0" license.workspace = true
edition = "2021"
version.workspace = true version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies] [dependencies]
+3 -2
View File
@@ -7,11 +7,12 @@ After=nvidia-powerd.service systemd-udevd.service
[Service] [Service]
Environment=IS_SERVICE=1 Environment=IS_SERVICE=1
Environment=RUST_LOG="info" Environment=RUST_LOG="info"
# ExecStartPre=/bin/sleep 2 # was required only for slow devices # required to prevent init issues with hid_asus and MCU
ExecStartPre=/bin/sleep 1
ExecStart=/usr/bin/asusd ExecStart=/usr/bin/asusd
Restart=on-failure Restart=on-failure
RestartSec=1 RestartSec=1
Type=dbus Type=dbus
BusName=org.asuslinux.Daemon BusName=org.asuslinux.Daemon
SELinuxContext=system_u:system_r:unconfined_t:s0 SELinuxContext=system_u:system_r:unconfined_t:s0
#SELinuxContext=system_u:object_r:modules_object_t:s0 #SELinuxContext=system_u:object_r:modules_object_t:s0
-25
View File
@@ -1,25 +0,0 @@
/* eslint-env node */
module.exports = {
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
root: true,
rules: {
// enable additional rules
indent: ["error", 4],
"linebreak-style": ["error", "unix"],
quotes: ["error", "double"],
semi: ["error", "always"],
// override configuration set by extending "eslint:recommended"
"no-empty": "warn",
"no-cond-assign": ["error", "always"],
// disable rules from base configurations
"for-direction": "off",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/ban-ts-comment": "off",
},
};
@@ -1,13 +0,0 @@
# Generated files
/@types/gir-generated/*
# Build outputes
/dist/
/build/
# Node configuration and modules
/package.json
/node_modules/
# Files I prefer not to be formatted
*.md
@@ -1,9 +0,0 @@
{
"printWidth": 100,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always"
}
-373
View File
@@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.
-21
View File
@@ -1,21 +0,0 @@
# asusctl
Requires `asusd` to be installed and running.
## build and install
```
npm install
npm run build && gnome-extensions install asusctl-gnome@asus-linux.org.zip --force
npm run build && gnome-extensions enable asusctl-gnome@asus-linux.org.zip
```
You will need to restart Gnome after installing or updating
## development
```
npm run build
gnome-extensions install asusctl-gnome@asus-linux.org.zip --force
MUTTER_DEBUG_DUMMY_MODE_SPECS=1366x768 dbus-run-session -- gnome-shell --nested --wayland
```
-67
View File
@@ -1,67 +0,0 @@
import { build } from "esbuild";
import { exec } from "child_process";
import { copyFileSync, cpSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";
import AdmZip from "adm-zip";
import metadata from "./src/metadata.json" assert { type: "json" };
build({
entryPoints: ["src/extension.ts"],
outdir: "dist",
bundle: true,
// Do not remove the functions `enable()`, `disable()` and `init()`
treeShaking: false,
// firefox60 // Since GJS 1.53.90
// firefox68 // Since GJS 1.63.90
// firefox78 // Since GJS 1.65.90
// firefox91 // Since GJS 1.71.1
// firefox102 // Since GJS 1.73.2
target: "firefox102",
//platform: "neutral",
platform: "node",
// mainFields: ['main'],
// conditions: ['require', 'default'],
format: "esm",
external: ["gi://*", "resource://*", "system", "gettext", "cairo"],
}).then(() => {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const metaSrc = resolve(__dirname, "src/metadata.json");
const metaDist = resolve(__dirname, "dist/metadata.json");
const schemaSrc = resolve(__dirname, "schemas");
const schemaDist = resolve(__dirname, "dist/schemas");
const dbusXmlSrc = resolve(__dirname, "../../bindings/dbus-xml");
const dbusXmlDist = resolve(__dirname, "dist/resources/dbus");
const zipFilename = `${metadata.uuid}.zip`;
const zipDist = resolve(__dirname, zipFilename);
exec("glib-compile-schemas schemas/", (error, stdout, stderr) => {
console.log("stdout: " + stdout);
console.log("stderr: " + stderr);
});
copyFileSync(metaSrc, metaDist);
cpSync(schemaSrc, schemaDist, { recursive: true }, (err) => {
if (err) {
console.error(err);
}
});
cpSync(dbusXmlSrc, dbusXmlDist, { recursive: true }, (err) => {
if (err) {
console.error(err);
}
});
const zip = new AdmZip();
zip.addLocalFolder(resolve(__dirname, "dist"));
zip.writeZip(zipDist);
console.log(`Build complete. Zip file: ${zipFilename}\n`);
console.log(`Install with: gnome-extensions install ${zipFilename}`);
console.log(`Update with: gnome-extensions install ${zipFilename} --force`);
console.log(`Enable with: gnome-extensions enable ${metadata.uuid} --user`);
});
-51
View File
@@ -1,51 +0,0 @@
#!/bin/bash
## Script to initialise dev-environment (types)
gv="44"
wd=${PWD}
# cleanup
rm -rf @types
# generate GJS from gir (this does not include the extensions)
echo "Generating GJS types from gir.."
npx ts-for-gir generate Shell-12 St-12 Gtk-4.0 \
-g /usr/share/gir-1.0 \
-g /usr/share/gnome-shell \
-g /usr/share/gnome-shell/gir-1.0 \
-g /usr/lib64/mutter-12 \
-t esm -o @types/Gjs
# get latest js (44) in this case and create the types for it
echo "Generating GJS Extension (Gex) types from extension source.."
mkdir -p ./_tmp/
cd ./_tmp
wget -q -O gnome-shell-js-${gv}.tar.gz https://gitlab.gnome.org/GNOME/gnome-shell/-/archive/gnome-${gv}/gnome-shell-gnome-${gv}.tar.gz?path=js
tar xf gnome-shell-js-${gv}.tar.gz
cd gnome-shell-gnome-${gv}-js
cat >tsconfig.json <<EOL
{
"include": ["js/ui/*"],
"exclude": [
"js/ui/shellDBus.js",
"node_modules",
"**/node_modules/*"
],
"compilerOptions": {
"allowJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "gex-types",
"declarationMap": true,
"lib": ["es2019"]
}
}
EOL
npx tsc
cd ${wd}
mv ./_tmp/gnome-shell-gnome-${gv}-js/gex-types @types/Gex
# rm -rf ./_tmp/
echo "done."
exit 0
File diff suppressed because it is too large Load Diff
-55
View File
@@ -1,55 +0,0 @@
{
"name": "asusctl-gnome",
"version": "5.0.0-RC1",
"description": "asusctl-gnome a gnome extension exposing some of the base features of asusd in a helpful and easy to use way",
"type": "module",
"main": "dist/extension.js",
"scripts": {
"clear": "rm -rf dist",
"compile": "tsc --build tsconfig.json",
"build:app": "node esbuild.js",
"build": "yarn run clear && yarn run build:app",
"validate": "tsc --noEmit",
"generate:gir-types": "ts-for-gir generate",
"check:types": "tsc --build tsconfig.types.json",
"lint": "eslint .",
"format": "prettier . -w"
},
"devDependencies": {
"@girs/gnome-shell": "^45.0.0-beta2",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"adm-zip": "^0.5.10",
"esbuild": "^0.19.5",
"eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-promise": "^6.1.1",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
},
"dependencies": {
"@girs/gjs": "^3.2.5",
"@girs/gobject-2.0": "^2.78.0-3.2.5",
"@girs/st-13": "^13.0.0-3.2.5"
},
"repository": {
"type": "git",
"url": "git+ssh://git@gitlab.com/asus-linux/asusctl.git"
},
"keywords": [
"gnome-shell",
"extension",
"asusctl",
"asus",
"rog",
"gnome",
"gjs",
"typescript"
],
"author": "Armas Spann, Marco Laux, Luke Jones",
"license": "MPL-2",
"bugs": {
"url": "https://gitlab.com/asus-linux/asusctl/issues"
},
"homepage": "https://gitlab.com/asus-linux/asusctl/desktop-extensions/gnome#readme"
}
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="AsusctlGnomeExtension">
<schema id="org.gnome.shell.extensions.asusctl-gnome" path="/org/gnome/shell/extensions/asusctl-gnome/" >
<key type="b" name="mini-led-enabled">
<default>false</default>
</key>
<key type="b" name="panel-od-enabled">
<default>false</default>
</key>
<key type="b" name="anime-power">
<default>false</default>
</key>
<key type="b" name="anime-builtins">
<default>false</default>
</key>
<key name="charge-level" type="u">
<range min="20" max="100"/>
<default>100</default>
</key>
<key type="s" name="primary-quickmenu-toggle">
<default>"mini-led"</default>
</key>
</schema>
</schemalist>
-1
View File
@@ -1 +0,0 @@
../../../bindings/ts
@@ -1,127 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import * as platform from "./bindings/platform";
import { AsusQuickToggle } from "./modules/rog_quick_toggle";
import { AsusMenuToggle } from "./modules/rog_menu_toggle";
import { AsusIndicator } from "./modules/rog_indicator";
import { AsusSlider } from "./modules/rog_slider_100pc";
import { FeatureMenuToggle } from "./modules/quick_menus/laptop_features";
import { DbusBase } from "./modules/dbus_proxy";
import { main } from "@girs/gnome-shell/ui";
export const uuid = "asusctl-gnome@asus-linux.org";
export default class AsusExtension extends Extension {
// public dbus_aura: AuraDbus = new AuraDbus;
// public dbus_anime: AnimeDbus = new AnimeDbus;
public dbus_platform: DbusBase | undefined;
public dbus_anime: DbusBase | undefined;
private individual = false;
public supported_properties!: platform.Properties;
public supported_interfaces: string[] = [];
private feature_menu = null;
private panel_od = null;
private mini_led = null;
private anime_display = null;
private anime_builtins = null;
private charge_thres = null;
// private _feature: typeof FeatureMenuToggle;
async enable() {
log(this.path);
if (this.dbus_platform == undefined) {
this.dbus_platform = new DbusBase("org-asuslinux-platform-4.xml", "/org/asuslinux/Platform");
await this.dbus_platform.start();
}
if (this.dbus_anime == undefined) {
this.dbus_anime = new DbusBase("org-asuslinux-anime-4.xml", "/org/asuslinux/Anime");
await this.dbus_anime.start();
}
this.supported_interfaces = this.dbus_platform?.proxy.SupportedInterfacesSync()[0];
this.supported_properties = this.dbus_platform?.proxy.SupportedPropertiesSync()[0];
log(this.supported_interfaces);
log(this.supported_properties);
// new AsusIndicator("selection-mode-symbolic", "mini-led-enabled");
// new AsusIndicator("selection-mode-symbolic", "panel-od-enabled");
if (!this.individual) {
if (this.feature_menu == null)
this.feature_menu = new FeatureMenuToggle(this.dbus_platform, this.dbus_anime);
} else {
if (this.supported_properties.includes("PanelOd") && this.dbus_platform.proxy.PanelOd != null)
if (this.panel_od == null) {
this.panel_od = new AsusQuickToggle(
this.dbus_platform,
"PanelOd",
"panel-od-enabled",
"Panel Overdrive",
);
}
if (this.supported_properties.includes("MiniLed") && this.dbus_platform.proxy.MiniLed != null)
if (this.mini_led == null) {
this.mini_led = new AsusQuickToggle(
this.dbus_platform,
"MiniLed",
"mini-led-enabled",
"Mini-LED",
);
}
if (
this.supported_interfaces.includes("Anime") &&
this.dbus_anime.proxy.EnableDisplay != null
)
if (this.anime_display == null) {
this.anime_display = new AsusQuickToggle(
this.dbus_anime,
"EnableDisplay",
"anime-power",
"AniMe Display",
);
}
if (
this.supported_interfaces.includes("Anime") &&
this.dbus_anime.proxy.BuiltinsEnabled != null
)
if (this.anime_builtins == null) {
this.anime_builtins = new AsusQuickToggle(
this.dbus_anime,
"BuiltinsEnabled",
"anime-builtins",
"Use builtins",
);
}
}
if (
this.supported_properties.includes("ChargeControlEndThreshold") &&
this.dbus_platform.proxy.ChargeControlEndThreshold != null
)
if (this.charge_thres == null) {
this.charge_thres = new AsusSlider(
this.dbus_platform,
"ChargeControlEndThreshold",
"charge-level",
"Charge Level",
);
}
}
disable() {
this.dbus_platform?.stop();
this.dbus_anime?.stop();
this.feature_menu?.destroy();
feature_menu?.destroy();
panel_od?.destroy();
mini_led?.destroy();
anime_display?.destroy();
anime_builtins?.destroy();
charge_thres?.destroy();
}
}
@@ -1,9 +0,0 @@
{
"name": "asusctl-gnome",
"description": "asusctl-gnome a gnome extension exposing some of the base features of asusd in a helpful and easy to use way",
"uuid": "asusctl-gnome@asus-linux.org",
"uuid-dev": "asusctl-gnome-dev@asus-linux.org",
"settings-schema": "org.gnome.shell.extensions.asusctl-gnome",
"version": "4.3.2",
"shell-version": ["45"]
}
@@ -1,98 +0,0 @@
import { DbusBase } from "../dbus_proxy";
import {
DeviceState,
AnimBooting,
Brightness,
AnimAwake,
AnimSleeping,
AnimShutdown,
} from "../../bindings/anime";
export class AnimeDbus extends DbusBase {
deviceState: DeviceState = {
display_enabled: false,
display_brightness: Brightness.Med,
builtin_anims_enabled: false,
builtin_anims: {
boot: AnimBooting.GlitchConstruction,
awake: AnimAwake.BinaryBannerScroll,
sleep: AnimSleeping.BannerSwipe,
shutdown: AnimShutdown.GlitchOut,
},
off_when_unplugged: false,
off_when_suspended: false,
off_when_lid_closed: false,
};
// TODO: interface or something to enforce requirement of "sync()" method
public notifyAnimeStateSubscribers: any[] = [];
constructor() {
super("org-asuslinux-anime-4", "/org/asuslinux/Anime");
}
_parseData(data: any) {
if (data.length > 0) {
this.deviceState.display_enabled = data[0];
this.deviceState.display_brightness = Brightness[data[1] as Brightness];
this.deviceState.builtin_anims_enabled = data[2];
this.deviceState.builtin_anims.boot = AnimBooting[data[3][0] as AnimBooting];
this.deviceState.builtin_anims.awake = AnimAwake[data[3][1] as AnimAwake];
this.deviceState.builtin_anims.sleep = AnimSleeping[data[3][2] as AnimSleeping];
this.deviceState.builtin_anims.shutdown = AnimShutdown[data[3][3] as AnimShutdown];
this.deviceState.off_when_unplugged = data[4];
this.deviceState.off_when_suspended = data[5];
this.deviceState.off_when_lid_closed = data[6];
}
}
public getDeviceState() {
if (this.isRunning()) {
try {
// janky shit going on with DeviceStateSync
this._parseData(this.dbus_proxy.DeviceStateSync());
//@ts-ignore
log("Anime Matrix: display_enabled: " + this.deviceState.display_enabled);
//@ts-ignore
log("Anime Matrix: display_brightness: " + this.deviceState.display_brightness);
//@ts-ignore
log("Anime Matrix: builtin_anims_enabled: " + this.deviceState.builtin_anims_enabled);
//@ts-ignore
log("Anime Matrix: builtin_anims: " + this.deviceState.builtin_anims);
//@ts-ignore
log("Anime Matrix: off_when_unplugged: " + this.deviceState.off_when_unplugged);
//@ts-ignore
log("Anime Matrix: off_when_suspended: " + this.deviceState.off_when_suspended);
//@ts-ignore
log("Anime Matrix: off_when_lid_closed: " + this.deviceState.off_when_lid_closed);
} catch (e) {
//@ts-ignore
log("Failed to fetch DeviceState!", e);
}
}
return this.deviceState;
}
async start() {
await super.start();
this.getDeviceState();
this.dbus_proxy.connectSignal(
"NotifyDeviceState",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(proxy: any = null, name: string, data: string) => {
if (proxy) {
// idiot xml parsing mneans the get is not nested while this is
this._parseData(data[0]);
this.notifyAnimeStateSubscribers.forEach((sub) => {
sub.sync();
});
}
},
);
}
async stop() {
await super.stop();
}
}
@@ -1,300 +0,0 @@
import {
AuraDevRog1,
AuraDevTuf,
AuraDevice,
AuraEffect,
AuraModeNum,
AuraPower,
AuraPowerDev,
AuraZone,
Direction,
PowerZones,
Speed,
} from "../../bindings/aura";
import { DbusBase } from "./base";
export class AuraDbus extends DbusBase {
public device: AuraDevice = AuraDevice.Unknown;
public current_aura_mode: AuraModeNum = AuraModeNum.Static;
public aura_modes: Map<AuraModeNum, AuraEffect> = new Map();
public leds_powered: AuraPowerDev = {
tuf: [],
old_rog: [],
rog: {
keyboard: {
zone: PowerZones.Keyboard,
boot: false,
awake: false,
sleep: false,
shutdown: false,
},
logo: {
zone: PowerZones.Logo,
boot: false,
awake: false,
sleep: false,
shutdown: false,
},
lightbar: {
zone: PowerZones.Lightbar,
boot: false,
awake: false,
sleep: false,
shutdown: false,
},
lid: {
zone: PowerZones.Lid,
boot: false,
awake: false,
sleep: false,
shutdown: false,
},
rear_glow: {
zone: PowerZones.RearGlow,
boot: false,
awake: false,
sleep: false,
shutdown: false,
},
},
};
// TODO: interface or something to enforce requirement of "sync()" method
public notifyAuraModeSubscribers: any[] = [];
public notifyAuraPowerSubscribers: any[] = [];
constructor() {
super("org-asuslinux-aura-4", "/org/asuslinux/Aura");
}
public getDevice() {
if (this.isRunning()) {
try {
this.device = AuraDevice[this.dbus_proxy.DeviceTypeSync() as AuraDevice];
//@ts-ignore
log("LED device: " + this.device);
} catch (e) {
//@ts-ignore
log("Failed to fetch supported functionalities", e);
}
}
}
_parsePowerStates(data: any[]) {
const power: AuraPowerDev = this.leds_powered;
power.tuf = data[0].map((value: string) => {
return AuraDevTuf[value as AuraDevTuf];
});
power.old_rog = data[1].map((value: string) => {
return AuraDevRog1[value as AuraDevRog1];
});
power.rog = {
keyboard: {
zone: PowerZones[data[2][0][0] as PowerZones],
boot: data[2][0][1],
awake: data[2][0][2],
sleep: data[2][0][3],
shutdown: data[2][0][4],
},
logo: {
zone: PowerZones[data[2][1][0] as PowerZones],
boot: data[2][1][1],
awake: data[2][1][2],
sleep: data[2][1][3],
shutdown: data[2][1][4],
},
lightbar: {
zone: PowerZones[data[2][2][0] as PowerZones],
boot: data[2][2][1],
awake: data[2][2][2],
sleep: data[2][2][3],
shutdown: data[2][2][4],
},
lid: {
zone: PowerZones[data[2][3][0] as PowerZones],
boot: data[2][3][1],
awake: data[2][3][2],
sleep: data[2][3][3],
shutdown: data[2][3][4],
},
rear_glow: {
zone: PowerZones[data[2][4][0] as PowerZones],
boot: data[2][4][1],
awake: data[2][4][2],
sleep: data[2][4][3],
shutdown: data[2][4][4],
},
};
return power;
}
public getLedPower() {
if (this.isRunning()) {
try {
const data = this.dbus_proxy.LedPowerSync();
this.leds_powered = this._parsePowerStates(data);
//@ts-ignore
log("LED power tuf: " + this.leds_powered.tuf);
//@ts-ignore
log("LED power x1866: " + this.leds_powered.old_rog);
//@ts-ignore
log("LED power x19b6: " + this.leds_powered.rog);
} catch (e) {
//@ts-ignore
log("Failed to fetch supported functionalities", e);
}
}
}
public getLedMode() {
if (this.isRunning()) {
try {
this.current_aura_mode = AuraModeNum[this.dbus_proxy.LedModeSync() as AuraModeNum];
//@ts-ignore
log("Current LED mode:", this.current_aura_mode);
} catch (e) {
//@ts-ignore
log("Failed to fetch supported functionalities", e);
}
}
}
public setLedMode(mode: AuraEffect) {
if (this.isRunning()) {
try {
this.dbus_proxy.SetLedModeSync([
mode.mode,
mode.zone,
[mode.colour1.r, mode.colour1.g, mode.colour1.b],
[mode.colour2.r, mode.colour2.g, mode.colour2.b],
mode.speed,
mode.direction,
]);
} catch (e) {
//@ts-ignore
log("Failed to fetch supported functionalities", e);
}
}
}
_parseAuraEffect(data: any[]) {
const aura: AuraEffect = {
mode: AuraModeNum[data[0] as AuraModeNum],
zone: AuraZone[data[1] as AuraZone],
colour1: {
r: parseInt(data[2][0]),
g: parseInt(data[2][1]),
b: parseInt(data[2][2]),
},
colour2: {
r: parseInt(data[3][0]),
g: parseInt(data[3][1]),
b: parseInt(data[3][2]),
},
speed: Speed[data[4] as Speed],
direction: Direction[data[5] as Direction],
};
return aura;
}
// Return a list of the available modes, and the current settings for each
public getLedModes() {
// {'Breathe': ('Breathe', 'None', (166, 0, 0), (0, 0, 0), 'Med', 'Right'),
// 'Comet': ('Comet', 'None', (166, 0, 0), (0, 0, 0), 'Med', 'Right'),
// 'Static': ('Static', 'None', (78, 0, 0), (0, 0, 0), 'Med', 'Right'),
// 'Strobe': ('Strobe', 'None', (166, 0, 0), (0, 0, 0), 'Med', 'Right')}
if (this.isRunning()) {
try {
const _data = this.dbus_proxy.LedModesSync();
for (const key in _data[0]) {
const data = _data[0][key];
const aura: AuraEffect = this._parseAuraEffect(data);
this.aura_modes.set(AuraModeNum[key as AuraModeNum], aura);
}
for (const [key, value] of this.aura_modes) {
//@ts-ignore
log(key, value.zone, value.colour1.r, value.speed, value.direction);
}
} catch (e) {
//@ts-ignore
log("Failed to fetch supported functionalities", e);
}
}
}
async start() {
try {
await super.start();
this.getDevice();
this.getLedPower();
this.getLedMode();
this.getLedModes();
//@ts-ignore
log("Current LED mode data:", this.aura_modes.get(this.current_aura_mode)?.speed);
this.dbus_proxy.connectSignal("NotifyLed", (proxy: any = null, name: string, data: any) => {
if (proxy) {
const aura: AuraEffect = this._parseAuraEffect(data[0]);
this.current_aura_mode = aura.mode;
this.aura_modes.set(aura.mode, aura);
//@ts-ignore
log(
"LED data has changed to ",
aura.mode,
aura.zone,
aura.colour1.r,
aura.speed,
aura.direction,
);
this.notifyAuraModeSubscribers.forEach((sub) => {
sub.sync();
});
}
});
this.dbus_proxy.connectSignal(
"NotifyPowerStates",
(proxy: any = null, name: string, data: any) => {
if (proxy) {
const power: AuraPowerDev = this._parsePowerStates(data[0]);
this.leds_powered = power;
switch (this.device) {
case AuraDevice.Tuf:
//@ts-ignore
log("LED power has changed to ", this.leds_powered.tuf);
break;
case AuraDevice.X1854:
case AuraDevice.X1869:
case AuraDevice.X18c6:
//@ts-ignore
log("LED power has changed to ", this.leds_powered.old_rog);
break;
case AuraDevice.X19b6:
case AuraDevice.X1a30:
//@ts-ignore
log("LED power has changed to ", this.leds_powered.rog);
break;
default:
break;
}
//@ts-ignore
log("LED power has changed to ", this.leds_powered.rog);
this.notifyAuraPowerSubscribers.forEach((sub) => {
sub.sync();
});
}
},
);
} catch (e) {
//@ts-ignore
log("Supported DBus initialization failed!", e);
}
}
async stop() {
await super.stop();
}
}
@@ -1,64 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import { Gio } from "@girs/gio-2.0";
import { GLib } from "@girs/glib-2.0";
import { imports } from "@girs/gjs";
// Reads the contents of a file contained in the global resources archive. The data
// is returned as a string.
export function getStringResource(path: string | null) {
const data = Gio.resources_lookup_data(path, 0);
return new TextDecoder().decode(data.get_data()?.buffer);
}
export class DbusBase {
proxy!: Gio.DBusProxy;
connected = false;
ifaceXml = "";
dbus_path = "";
constructor(file_name: string, dbus_path: string) {
let extensionObject = Extension.lookupByUUID("asusctl-gnome@asus-linux.org");
const path = extensionObject?.path + "/resources/dbus/" + file_name;
const [ok, data] = GLib.file_get_contents(path);
if (!ok) {
throw new Error("could not read interface file");
}
this.ifaceXml = imports.byteArray.toString(data);
this.dbus_path = dbus_path;
}
async start() {
//@ts-ignore
log(`Starting ${this.dbus_path} dbus module`);
try {
log(this.ifaceXml);
this.proxy = Gio.DBusProxy.makeProxyWrapper(this.ifaceXml)(
Gio.DBus.system,
"org.asuslinux.Daemon",
this.dbus_path,
);
this.connected = true;
//@ts-ignore
log(`${this.dbus_path} client started successfully.`);
} catch (e) {
//@ts-ignore
logError(`${this.xml_resource} dbus init failed!`, e);
}
}
async stop() {
//@ts-ignore
log(`Stopping ${this.xml_resource} dbus module`);
if (this.connected && this.proxy != undefined) {
this.proxy.run_dispose();
this.proxy = undefined;
this.connected = false;
}
}
isRunning(): boolean {
return this.connected;
}
}
@@ -1,14 +0,0 @@
import * as Main from "resource:///org/gnome/shell/ui/main.js";
import { QuickToggle } from "resource:///org/gnome/shell/ui/quickSettings.js";
export function addQuickSettingsItems(items: [typeof QuickToggle], width = 1) {
const QuickSettingsMenu = Main.panel.statusArea.quickSettings;
items.forEach((item) => QuickSettingsMenu.menu.addItem(item, width));
// Ensure the tile(s) are above the background apps menu
for (const item of items) {
QuickSettingsMenu.menu._grid.set_child_below_sibling(
item,
QuickSettingsMenu._backgroundApps.quickSettingsItems[0],
);
}
}
@@ -1,85 +0,0 @@
import { addQuickSettingsItems } from "../helpers";
import { AuraDbus } from "../dbus/aura";
import { AuraEffect, AuraModeNum } from "../../bindings/aura";
import GObject from "gi://GObject";
import * as PopupMenu from "resource:///org/gnome/shell/ui/popupMenu.js";
import * as QuickSettings from "resource:///org/gnome/shell/ui/quickSettings.js";
export const AuraMenuToggle = GObject.registerClass(
class AuraMenuToggle extends QuickSettings.QuickMenuToggle {
private _dbus_aura: AuraDbus;
private _last_mode: AuraModeNum = AuraModeNum.Static;
constructor(dbus_aura: AuraDbus) {
super({
title: "Aura Modes",
iconName: "selection-mode-symbolic",
toggleMode: true,
});
this._dbus_aura = dbus_aura;
this.connectObject(this);
this.menu.setHeader("selection-mode-symbolic", this._dbus_aura.current_aura_mode);
this._itemsSection = new PopupMenu.PopupMenuSection();
this._dbus_aura.aura_modes.forEach((mode, key) => {
this._itemsSection.addAction(
key,
() => {
this._dbus_aura.setLedMode(mode);
this.sync();
},
"",
);
});
this.menu.addMenuItem(this._itemsSection);
// Add an entry-point for more settings
// this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
// const settingsItem = this.menu.addAction("More Settings",
// () => ExtensionUtils.openPrefs());
// // Ensure the settings are unavailable when the screen is locked
// settingsItem.visible = Main.sessionMode.allowSettings;
// this.menu._settingsActions[Me.uuid] = settingsItem;
this.connectObject(
"clicked",
() => {
let mode: AuraEffect | undefined;
if (this._dbus_aura.current_aura_mode == AuraModeNum.Static) {
mode = this._dbus_aura.aura_modes.get(this._last_mode);
} else {
mode = this._dbus_aura.aura_modes.get(AuraModeNum.Static);
}
if (mode != undefined) {
this._dbus_aura.setLedMode(mode);
this.sync();
}
},
this,
);
this._dbus_aura.notifyAuraModeSubscribers.push(this);
this.sync();
addQuickSettingsItems([this]);
}
sync() {
const checked = this._dbus_aura.current_aura_mode != AuraModeNum.Static;
this.title = this._dbus_aura.current_aura_mode;
if (
this._last_mode != this._dbus_aura.current_aura_mode &&
this._dbus_aura.current_aura_mode != AuraModeNum.Static
) {
this._last_mode = this._dbus_aura.current_aura_mode;
}
if (this.checked !== checked) this.set({ checked });
}
},
);
@@ -1,216 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import { quickSettings, popupMenu } from "@girs/gnome-shell/ui";
import { GObject } from "@girs/gobject-2.0";
import { DbusBase } from "../../modules/dbus_proxy";
import { addQuickSettingsItems } from "../helpers";
import * as AsusExtension from "../../extension";
import * as platform from "../../bindings/platform";
import { uuid } from "../../extension";
import { AsusMenuToggle } from "../rog_menu_toggle";
export const FeatureMenuToggle = GObject.registerClass(
class FeatureMenuToggle extends quickSettings.QuickMenuToggle {
private dbus_platform: DbusBase;
private dbus_anime: DbusBase;
private last_selection = "mini-led";
private supported_properties!: platform.Properties;
private supported_interfaces: string[] = [];
private miniLed?: typeof AsusMenuToggle;
private panelOd?: typeof AsusMenuToggle;
private animeDisplayPower?: typeof AsusMenuToggle;
private animePowersaveAnim?: typeof AsusMenuToggle;
_itemsSection: popupMenu.PopupMenuSection;
constructor(dbus_platform: DbusBase, dbus_anime: DbusBase) {
super({
label: "Laptop",
toggle_mode: true,
icon_name: "selection-mode-symbolic",
});
this.label = "Laptop";
this.title = "Laptop";
this.dbus_platform = dbus_platform;
this.dbus_anime = dbus_anime;
this.menu.setHeader("selection-mode-symbolic", "Laptop features");
this.last_selection = Extension.lookupByUUID(AsusExtension.uuid)
?.getSettings()
.get_string("primary-quickmenu-toggle")!;
this.supported_interfaces = this.dbus_platform?.proxy.SupportedInterfacesSync()[0];
this.supported_properties = this.dbus_platform?.proxy.SupportedPropertiesSync()[0];
// TODO: temporary block
if (this.last_selection == "mini-led" && !this.supported_properties.includes("MiniLed")) {
this.last_selection = "panel-od";
} else if (
this.last_selection == "panel-od" &&
!this.supported_properties.includes("PanelOd")
) {
this.last_selection = "anime-power";
} else if (
this.last_selection == "anime-power" &&
!this.supported_interfaces.includes("Anime")
) {
this.last_selection = "mini-led";
} else if (this.last_selection.length == 0) {
this.last_selection = "panel-od";
}
// AsusExtension.extension._settings.connect('changed::primary-quickmenu-toggle', this.sync);
Extension.lookupByUUID(uuid)
?.getSettings()
.set_string("primary-quickmenu-toggle", this.last_selection);
this._itemsSection = new popupMenu.PopupMenuSection();
if (this.supported_properties.includes("MiniLed")) {
if (this.miniLed == null) {
this.miniLed = new AsusMenuToggle(
this.dbus_platform,
"MiniLed",
"mini-led-enabled",
"Mini-LED Enabled",
);
this._itemsSection.addMenuItem(this.miniLed, 0);
this.miniLed.toggle_callback = () => {
this.last_selection = "mini-led";
};
}
}
if (this.supported_properties.includes("PanelOd")) {
if (this.panelOd == null) {
this.panelOd = new AsusMenuToggle(
this.dbus_platform,
"PanelOd",
"panel-od-enabled",
"Panel Overdrive Enabled",
);
this._itemsSection.addMenuItem(this.panelOd, 1);
this.panelOd.toggle_callback = () => {
this.last_selection = "panel-od";
};
}
}
if (this.supported_interfaces.includes("Anime")) {
if (this.animeDisplayPower == null) {
this.animeDisplayPower = new AsusMenuToggle(
this.dbus_anime,
"EnableDisplay",
"anime-power",
"AniMe Display Enabled",
);
this._itemsSection.addMenuItem(this.animeDisplayPower, 2);
this.animeDisplayPower.toggle_callback = () => {
this.last_selection = "anime-power";
};
}
if (this.animePowersaveAnim == null) {
this.animePowersaveAnim = new AsusMenuToggle(
this.dbus_anime,
"BuiltinsEnabled",
"anime-builtins",
"AniMe Built-in Animations",
);
this._itemsSection.addMenuItem(this.animePowersaveAnim, 3);
this.animePowersaveAnim.toggle_callback = () => {
this.last_selection = "anime-builtins";
};
}
}
this.connectObject(
"clicked",
() => {
this._toggle();
},
this,
);
this.menu.addMenuItem(this._itemsSection, 0);
this.dbus_platform?.proxy.connect("g-properties-changed", (_proxy, changed, invalidated) => {
//const properties = changed.deepUnpack();
this.sync();
});
this.dbus_anime?.proxy.connect("g-properties-changed", (_proxy, changed, invalidated) => {
//const properties = changed.deepUnpack();
this.sync();
});
// // Add an entry-point for more extension._settings
// this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
// const settingsItem = this.menu.addAction("More Settings",
// () => ExtensionUtils.openPrefs());
// // Ensure the extension._settings are unavailable when the screen is locked
// settingsItem.visible = Main.sessionMode.allowSettings;
// this.menu._settingsActions[Me.uuid] = settingsItem;
this.sync();
addQuickSettingsItems([this]);
}
_toggle() {
if (this.last_selection == "mini-led" && this.miniLed != null) {
if (this.checked !== this.dbus_platform.proxy.MiniLed)
this.dbus_platform.proxy.MiniLed = this.checked;
}
if (this.last_selection == "panel-od" && this.panelOd != null) {
if (this.checked !== this.dbus_platform.proxy.PanelOd) {
this.dbus_platform.proxy.PanelOd = this.checked;
}
}
if (this.last_selection == "anime-power" && this.animeDisplayPower != null) {
if (this.checked !== this.dbus_anime.proxy.EnableDisplay)
this.dbus_anime.proxy.EnableDisplay = this.checked;
}
if (this.last_selection == "anime-builtins" && this.animePowersaveAnim != null) {
if (this.checked !== this.dbus_anime.proxy.BuiltinsEnabled)
this.dbus_anime.proxy.BuiltinsEnabled = this.checked;
}
}
sync() {
let checked = false;
if (this.last_selection == "mini-led" && this.miniLed != null) {
this.title = this.miniLed.title;
checked = this.dbus_platform.proxy.MiniLed;
}
if (this.last_selection == "panel-od" && this.panelOd != null) {
this.title = this.panelOd.title;
checked = this.dbus_platform.proxy.PanelOd;
}
if (this.last_selection == "anime-power" && this.animeDisplayPower != null) {
this.title = this.animeDisplayPower.title;
checked = this.dbus_anime.proxy.EnableDisplay;
}
if (this.last_selection == "anime-builtins" && this.animePowersaveAnim != null) {
this.title = this.animePowersaveAnim.title;
checked = this.dbus_anime.proxy.BuiltinsEnabled;
}
// if (this.animePowersaveAnim != null) {
// }
if (this.checked !== checked) this.set({ checked });
}
destroy() {
// this.panelOd?.destroy();
}
},
);
@@ -1,26 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import { quickSettings, main } from "@girs/gnome-shell/ui";
import { Gio } from "@girs/gio-2.0";
import { GObject } from "@girs/gobject-2.0";
import { uuid } from "../extension";
//import { DbusBase } from '../dbus_proxy';
export const AsusIndicator = GObject.registerClass(
class AsusIndicator extends quickSettings.SystemIndicator {
private _indicator: any;
private _settings: Gio.Settings | undefined;
constructor(icon_name: string, setting_name: string) {
super();
// Create an icon for the indicator
this._indicator = this._addIndicator();
this._indicator.icon_name = icon_name;
// Showing an indicator when the feature is enabled
this._settings = Extension.lookupByUUID(uuid)?.getSettings();
this._settings?.bind(setting_name, this._indicator, "visible", Gio.SettingsBindFlags.DEFAULT);
main.panel.statusArea.quickSettings.addExternalIndicator(this);
}
},
);
@@ -1,50 +0,0 @@
import { popupMenu } from "@girs/gnome-shell/ui";
import { GObject } from "@girs/gobject-2.0";
import { DbusBase } from "./dbus_proxy";
export const AsusMenuToggle = GObject.registerClass(
class AsusMenuToggle extends popupMenu.PopupSwitchMenuItem {
public title: string = "";
dbus!: DbusBase;
prop_name: string = "";
public toggle_callback = () => {};
constructor(dbus: DbusBase, prop_name: string, setting: string, title: string) {
super(title, true);
this.prop_name = prop_name;
this.dbus = dbus;
this.title = title;
this.dbus?.proxy.connect("g-properties-changed", (_proxy, changed, invalidated) => {
const properties = changed.deepUnpack();
// .find() fails on some shit for some reason
for (const v of Object.entries(properties)) {
if (v[0] == this.prop_name) {
this.sync();
break;
}
}
});
this.connectObject("toggled", () => this._toggleMode(), this);
this.connect("destroy", () => {
this.destroy();
});
this.sync();
}
_toggleMode() {
// hacky shit, index to get base object property and set it
const state = this.dbus.proxy[this.prop_name];
if (this.state !== state) this.dbus.proxy[this.prop_name] = this.state;
this.toggle_callback();
}
sync() {
const state = this.dbus.proxy[this.prop_name];
if (this.state !== state) this.setToggleState(state);
}
},
);
@@ -1,64 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import { addQuickSettingsItems } from "./helpers";
import { quickSettings } from "@girs/gnome-shell/ui";
import { Gio } from "@girs/gio-2.0";
import { GObject } from "@girs/gobject-2.0";
import { uuid } from "../extension";
import { DbusBase } from "./dbus_proxy";
export const AsusQuickToggle = GObject.registerClass(
class AsusQuickToggle extends quickSettings.QuickToggle {
dbus!: DbusBase;
prop_name: string = "";
public toggle_callback = () => {};
constructor(dbus: DbusBase, prop_name: string, setting: string, title: string) {
super({
label: title,
icon_name: "selection-mode-symbolic",
toggle_mode: true,
});
this.prop_name = prop_name;
this.label = title;
this.dbus = dbus;
this.dbus?.proxy.connect("g-properties-changed", (_proxy, changed, invalidated) => {
const properties = changed.deepUnpack();
// .find() fails on some shit for some reason
for (const v of Object.entries(properties)) {
if (v[0] == this.prop_name) {
const checked = v[1].unpack();
if (this.checked !== checked) this.checked = checked;
break;
}
}
});
this.connectObject("clicked", () => this._toggleMode(), this);
this.connect("destroy", () => {
this.destroy();
});
Extension.lookupByUUID(uuid)
?.getSettings()
.bind(setting, this, "checked", Gio.SettingsBindFlags.DEFAULT);
this.sync();
addQuickSettingsItems([this]);
}
_toggleMode() {
// hacky shit, index to get base object property and set it
const checked = this.dbus.proxy[this.prop_name];
if (this.checked !== checked) this.dbus.proxy[this.prop_name] = this.checked;
this.toggle_callback();
}
sync() {
const checked = this.dbus.proxy[this.prop_name];
if (this.checked !== checked) this.set({ checked });
}
},
);
@@ -1,75 +0,0 @@
import { Extension, gettext as _ } from "@girs/gnome-shell/extensions/extension";
import { addQuickSettingsItems } from "./helpers";
import { quickSettings } from "@girs/gnome-shell/ui";
import { Gio } from "@girs/gio-2.0";
import { GObject } from "@girs/gobject-2.0";
import { uuid } from "../extension";
import { DbusBase } from "./dbus_proxy";
export const AsusSlider = GObject.registerClass(
class AsusSlider extends quickSettings.QuickSlider {
private dbus: DbusBase;
private settings: any = undefined;
private setting = "";
private prop_name = "";
constructor(dbus: DbusBase, prop_name: string, setting: string, title: string) {
super({
label: title,
icon_name: "selection-mode-symbolic",
});
this.label = title;
this.dbus = dbus;
this.setting = setting;
this.prop_name = prop_name;
this.settings = Extension.lookupByUUID(uuid)?.getSettings();
this._sliderChangedId = this.slider.connect("drag-end", this._onSliderChanged.bind(this));
// Binding the slider to a GSettings key
this.settings.connect(`changed::${this.setting}`, this._onSettingsChanged.bind(this));
// Set an accessible name for the slider
this.slider.accessible_name = title;
this.dbus?.proxy.connect("g-properties-changed", (_proxy, changed, invalidated) => {
const properties = changed.deepUnpack();
// .find() fails on some shit for some reason
for (const v of Object.entries(properties)) {
if (v[0] == this.prop_name) {
const checked = v[1].unpack();
this._sync();
break;
}
}
});
this._sync();
this._onSettingsChanged();
addQuickSettingsItems([this], 2);
}
_onSettingsChanged() {
// Prevent the slider from emitting a change signal while being updated
this.slider.block_signal_handler(this._sliderChangedId);
this.slider.value = this.settings.get_uint(this.setting) / 100.0;
this.slider.unblock_signal_handler(this._sliderChangedId);
}
_onSliderChanged() {
// Assuming our GSettings holds values between 0..100, adjust for the
// slider taking values between 0..1
const percent = Math.floor(this.slider.value * 100);
const stored = Math.floor(this.settings.get_uint(this.setting) / 100.0);
if (this.slider.value !== stored) this.dbus.proxy[this.prop_name] = percent;
this.settings.set_uint(this.setting, percent);
}
_sync() {
const value = this.dbus.proxy[this.prop_name];
if (this.slider.value !== value / 100) this.settings.set_uint(this.setting, value);
}
},
);
-19
View File
@@ -1,19 +0,0 @@
{
// "extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"lib": ["ESNext"],
"types": [],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"declaration": true,
"removeComments": true,
"strict": true,
"allowJs": true,
"paths": {},
"skipLibCheck": true
},
"files": ["./src/extension.ts"],
"include": ["src/*.ts"],
"exclude": [".ts-for-girrc.js", ".eslintrc.cjs"]
}
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -1,8 +1,13 @@
[package] [package]
name = "dmi_id" name = "dmi_id"
edition = "2021" license.workspace = true
version.workspace = true version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies] [dependencies]
log.workspace = true log.workspace = true
udev.workspace = true udev.workspace = true
Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

-12
View File
@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script language="javascript" type="text/javascript">
<!--
window.setTimeout('window.location="room4doom/index.html"; ', 0);
// -->
</script>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

+10 -7
View File
@@ -1,15 +1,15 @@
[package] [package]
name = "rog_anime" name = "rog_anime"
license = "MPL-2.0" license.workspace = true
version.workspace = true version.workspace = true
readme = "README.md" readme.workspace = true
authors = ["Luke <luke@ljones.dev>"] authors.workspace = true
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl" repository.workspace = true
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl" homepage.workspace = true
edition.workspace = true
documentation = "https://docs.rs/rog-anime" documentation = "https://docs.rs/rog-anime"
description = "Types useful for translating images and other data for display on the ASUS AniMe Matrix display" description = "Types useful for translating images and other data for display on the ASUS AniMe Matrix display"
keywords = ["ROG", "ASUS", "AniMe"] keywords = ["ROG", "ASUS", "AniMe"]
edition = "2021"
exclude = ["data"] exclude = ["data"]
[features] [features]
@@ -38,4 +38,7 @@ zbus = { workspace = true, optional = true }
dmi_id = { path = "../dmi-id", optional = true } dmi_id = { path = "../dmi-id", optional = true }
[dev-dependencies] [dev-dependencies]
cargo-husky.workspace = true cargo-husky.workspace = true
[package.metadata.cargo-machete]
ignored = ["serde"]
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::AnimeType;
/// Mostly intended to be used with ASUS gifs, but can be used for other /// Mostly intended to be used with ASUS gifs, but can be used for other
/// purposes (like images) /// purposes (like images)
#[derive(Debug, Clone)] #[allow(dead_code)]
pub struct AnimeDiagonal(AnimeType, Vec<Vec<u8>>, Option<Duration>); pub struct AnimeDiagonal(AnimeType, Vec<Vec<u8>>, Option<Duration>);
impl AnimeDiagonal { impl AnimeDiagonal {
+77 -1
View File
@@ -58,13 +58,25 @@ impl From<u8> for Brightness {
fn from(v: u8) -> Brightness { fn from(v: u8) -> Brightness {
match v { match v {
0 => Brightness::Off, 0 => Brightness::Off,
2 => Brightness::Low, 1 => Brightness::Low,
3 => Brightness::High, 3 => Brightness::High,
_ => Brightness::Med, _ => Brightness::Med,
} }
} }
} }
impl From<i32> for Brightness {
fn from(v: i32) -> Brightness {
(v as u8).into()
}
}
impl From<Brightness> for i32 {
fn from(v: Brightness) -> i32 {
v as i32
}
}
#[cfg_attr( #[cfg_attr(
feature = "dbus", feature = "dbus",
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
@@ -90,6 +102,22 @@ impl FromStr for AnimBooting {
} }
} }
impl From<i32> for AnimBooting {
fn from(value: i32) -> Self {
match value {
0 => Self::GlitchConstruction,
1 => Self::StaticEmergence,
_ => Self::default(),
}
}
}
impl From<AnimBooting> for i32 {
fn from(value: AnimBooting) -> Self {
value as i32
}
}
#[cfg_attr( #[cfg_attr(
feature = "dbus", feature = "dbus",
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
@@ -115,6 +143,22 @@ impl FromStr for AnimAwake {
} }
} }
impl From<i32> for AnimAwake {
fn from(value: i32) -> Self {
match value {
0 => Self::BinaryBannerScroll,
1 => Self::RogLogoGlitch,
_ => Self::default(),
}
}
}
impl From<AnimAwake> for i32 {
fn from(value: AnimAwake) -> Self {
value as i32
}
}
#[cfg_attr( #[cfg_attr(
feature = "dbus", feature = "dbus",
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
@@ -140,6 +184,22 @@ impl FromStr for AnimSleeping {
} }
} }
impl From<i32> for AnimSleeping {
fn from(value: i32) -> Self {
match value {
0 => Self::BannerSwipe,
1 => Self::Starfield,
_ => Self::default(),
}
}
}
impl From<AnimSleeping> for i32 {
fn from(value: AnimSleeping) -> Self {
value as i32
}
}
#[cfg_attr( #[cfg_attr(
feature = "dbus", feature = "dbus",
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
@@ -165,6 +225,22 @@ impl FromStr for AnimShutdown {
} }
} }
impl From<i32> for AnimShutdown {
fn from(value: i32) -> Self {
match value {
0 => Self::GlitchOut,
1 => Self::SeeYa,
_ => Self::default(),
}
}
}
impl From<AnimShutdown> for i32 {
fn from(value: AnimShutdown) -> Self {
value as i32
}
}
/// `get_anime_type` is very broad, matching on part of the laptop board name /// `get_anime_type` is very broad, matching on part of the laptop board name
/// only. For this reason `find_node()` must be used also to verify if the USB /// only. For this reason `find_node()` must be used also to verify if the USB
/// device is available. /// device is available.
+1 -1
View File
@@ -29,4 +29,4 @@ typeshare.workspace = true
ron = { version = "*", optional = true } ron = { version = "*", optional = true }
[dev-dependencies] [dev-dependencies]
cargo-husky.workspace = true cargo-husky.workspace = true
+297 -102
View File
@@ -1,6 +1,7 @@
([ ([
( (
board_name: "FA506I", device_name: "FA506I",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -8,7 +9,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FA506Q", device_name: "FA506Q",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [], basic_zones: [],
@@ -16,7 +18,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FA507", device_name: "FA507",
product_id: "",
layout_name: "fa507", layout_name: "fa507",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -24,7 +27,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX505D", device_name: "FX505D",
product_id: "",
layout_name: "fx505d", layout_name: "fx505d",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -32,7 +36,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX505G", device_name: "FX505G",
product_id: "",
layout_name: "fx505d", layout_name: "fx505d",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -40,7 +45,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX506H", device_name: "FX506H",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -48,7 +54,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX506L", device_name: "FX506L",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -56,7 +63,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX507Z", device_name: "FX507Z",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -64,7 +72,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "FX516P", device_name: "FX516P",
product_id: "",
layout_name: "fa506i", layout_name: "fa506i",
basic_modes: [Static, Breathe, Strobe], basic_modes: [Static, Breathe, Strobe],
basic_zones: [], basic_zones: [],
@@ -72,7 +81,17 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G512", device_name: "FX705D",
product_id: "",
layout_name: "fx505d",
basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "G512",
product_id: "",
layout_name: "g512", layout_name: "g512",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -80,7 +99,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G512LV", device_name: "G512LV",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -88,7 +108,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G513I", device_name: "G513I",
product_id: "",
layout_name: "g513i", layout_name: "g513i",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -96,7 +117,8 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "G513QE", device_name: "G513QE",
product_id: "",
layout_name: "g513i", layout_name: "g513i",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -104,7 +126,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G513QM", device_name: "G513QM",
product_id: "",
layout_name: "g513i", layout_name: "g513i",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -112,7 +135,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G513QR", device_name: "G513QR",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -120,7 +144,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G513QY", device_name: "G513QY",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -128,7 +153,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G513RC", device_name: "G513RC",
product_id: "",
layout_name: "g513i", layout_name: "g513i",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -136,7 +162,8 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "G513RM", device_name: "G513RM",
product_id: "",
layout_name: "g513i", layout_name: "g513i",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -144,7 +171,8 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "G513RW", device_name: "G513RW",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -152,7 +180,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531", device_name: "G531",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -160,7 +189,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531", device_name: "G531",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -168,7 +198,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531GD", device_name: "G531GD",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -176,7 +207,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531GT", device_name: "G531GT",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [], basic_zones: [],
@@ -184,7 +216,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531GU", device_name: "G531GU",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -192,7 +225,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531GV", device_name: "G531GV",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -200,7 +234,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G531GW", device_name: "G531GW",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -208,7 +243,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G532", device_name: "G532",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -216,7 +252,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G533Q", device_name: "G533Q",
product_id: "",
layout_name: "g533q-per-key", layout_name: "g533q-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -224,7 +261,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G533Z", device_name: "G533Z",
product_id: "",
layout_name: "g533q-per-key", layout_name: "g533q-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -232,7 +270,17 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G634J", device_name: "G614J",
product_id: "",
layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, Pulse, Strobe, Rainbow],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G634J",
product_id: "",
layout_name: "g634j-per-key", layout_name: "g634j-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -240,7 +288,8 @@
power_zones: [Keyboard, Lightbar, Logo, RearGlow], power_zones: [Keyboard, Lightbar, Logo, RearGlow],
), ),
( (
board_name: "G712LI", device_name: "G712LI",
product_id: "",
layout_name: "gl503", layout_name: "gl503",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -248,7 +297,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G712LV", device_name: "G712LV",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -256,7 +306,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G712LW", device_name: "G712LW",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -264,7 +315,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713IC", device_name: "G713IC",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -272,7 +324,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713QM", device_name: "G713P",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -280,7 +333,17 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713QR", device_name: "G713QM",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "G713QR",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -288,7 +351,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713RC", device_name: "G713RC",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -296,7 +360,8 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "G713RM", device_name: "G713RM",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -304,7 +369,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713RS", device_name: "G713RS",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -312,7 +378,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G713RW", device_name: "G713RW",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -320,7 +387,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G731", device_name: "G731",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -328,7 +396,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G731GT", device_name: "G731GT",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [], basic_zones: [],
@@ -336,7 +405,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G731GU", device_name: "G731GU",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [], basic_zones: [],
@@ -344,7 +414,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G731GV", device_name: "G731GV",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -352,7 +423,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G731GW", device_name: "G731GW",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -360,7 +432,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G733C", device_name: "G733C",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [Logo, BarLeft, BarRight], basic_zones: [Logo, BarLeft, BarRight],
@@ -368,7 +441,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G733PZ", device_name: "G733PZ",
product_id: "",
layout_name: "g733pz-per-key", layout_name: "g733pz-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -376,7 +450,8 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "G733Q", device_name: "G733Q",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -384,7 +459,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G733Z", device_name: "G733Z",
product_id: "",
layout_name: "g513i-per-key", layout_name: "g513i-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -392,7 +468,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "G814JI", device_name: "G814JI",
product_id: "",
layout_name: "g814ji-per-key", layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -400,7 +477,26 @@
power_zones: [Keyboard, Lightbar], power_zones: [Keyboard, Lightbar],
), ),
( (
board_name: "GA401Q", device_name: "G814JZ",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G834JZ",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo, RearGlow],
),
(
device_name: "GA401Q",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -408,23 +504,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GA402R", device_name: "GA402N",
layout_name: "ga401q", product_id: "",
basic_modes: [Static, Breathe, Pulse, Rainbow],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
board_name: "GA402X",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
board_name: "GA503Q",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe], basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe],
basic_zones: [], basic_zones: [],
@@ -432,7 +513,26 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GA503QE", device_name: "GA402R",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "GA402X",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "GA402XV",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -440,7 +540,17 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GA503R", device_name: "GA403UI",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "GA503Q",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe], basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe],
basic_zones: [], basic_zones: [],
@@ -448,7 +558,26 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL503", device_name: "GA503QE",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "GA503R",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "GL503",
product_id: "",
layout_name: "gl503", layout_name: "gl503",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -456,7 +585,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL503V", device_name: "GL503V",
product_id: "",
layout_name: "gl503", layout_name: "gl503",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -464,7 +594,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL504G", device_name: "GL504G",
product_id: "",
layout_name: "gl503", layout_name: "gl503",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4, Logo, BarLeft, BarRight], basic_zones: [Key1, Key2, Key3, Key4, Logo, BarLeft, BarRight],
@@ -472,7 +603,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL531", device_name: "GL531",
product_id: "",
layout_name: "g512", layout_name: "g512",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -480,7 +612,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL553VE", device_name: "GL553V",
product_id: "",
layout_name: "g533q", layout_name: "g533q",
basic_modes: [Static, Breathe, Strobe], basic_modes: [Static, Breathe, Strobe],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -488,7 +621,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GL703G", device_name: "GL703G",
product_id: "",
layout_name: "gl503", layout_name: "gl503",
basic_modes: [Static, Breathe, Strobe, Rainbow], basic_modes: [Static, Breathe, Strobe, Rainbow],
basic_zones: [], basic_zones: [],
@@ -496,7 +630,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GM501G", device_name: "GM501G",
product_id: "",
layout_name: "fa507", layout_name: "fa507",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -504,7 +639,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU502", device_name: "GU502",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -512,7 +648,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU502G", device_name: "GU502G",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -520,7 +657,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU502L", device_name: "GU502L",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -528,7 +666,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU502LU", device_name: "GU502LU",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -536,7 +675,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU603H", device_name: "GU603H",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -544,7 +684,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU603VV", device_name: "GU603VV",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -552,7 +693,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU603Z", device_name: "GU603Z",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -560,7 +702,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GU604V", device_name: "GU604V",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -568,7 +711,17 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV301Q", device_name: "GU605M",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [],
advanced_type: Zoned([SingleZone]),
power_zones: [Keyboard],
),
(
device_name: "GV301Q",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -576,7 +729,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV301V", device_name: "GV301V",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -584,7 +738,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV301VIC", device_name: "GV301VIC",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -592,7 +747,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV601R", device_name: "GV601R",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -600,7 +756,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV601V", device_name: "GV601V",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -608,7 +765,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GV604V", device_name: "GV604V",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Strobe, Pulse], basic_modes: [Static, Breathe, Strobe, Pulse],
basic_zones: [], basic_zones: [],
@@ -616,7 +774,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX502", device_name: "GX502",
product_id: "",
layout_name: "gx502", layout_name: "gx502",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -624,7 +783,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX531", device_name: "GX531",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [Key1, Key2, Key3, Key4], basic_zones: [Key1, Key2, Key3, Key4],
@@ -632,7 +792,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX550L", device_name: "GX550L",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -640,7 +801,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX551Q", device_name: "GX551Q",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse],
basic_zones: [], basic_zones: [],
@@ -648,7 +810,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX650P", device_name: "GX650P",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -656,7 +819,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX701", device_name: "GX701",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -664,7 +828,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GX703H", device_name: "GX703H",
product_id: "",
layout_name: "gx531-per-key", layout_name: "gx531-per-key",
basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [], basic_zones: [],
@@ -672,7 +837,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GZ301V", device_name: "GZ301V",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -680,7 +846,8 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "GZ301VIC", device_name: "GZ301VIC",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
@@ -688,11 +855,39 @@
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
( (
board_name: "RC71L", device_name: "GZ301Z",
product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse],
basic_zones: [], basic_zones: [],
advanced_type: None, advanced_type: None,
power_zones: [Keyboard], power_zones: [Keyboard],
), ),
]) (
device_name: "GZ301Z",
product_id: "18c6",
layout_name: "",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [None],
),
(
device_name: "GZ301Z",
product_id: "1a30",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
(
device_name: "RC71L",
product_id: "",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: None,
power_zones: [Keyboard],
),
])
-149
View File
@@ -1,149 +0,0 @@
use crate::advanced::LedCode;
impl From<LedCode> for &str {
fn from(k: LedCode) -> Self {
(&k).into()
}
}
impl From<&LedCode> for &str {
fn from(k: &LedCode) -> Self {
#[allow(clippy::match_same_arms)]
match k {
LedCode::VolUp => "Volume Up",
LedCode::VolDown => "Volume Down",
LedCode::MicMute => "Mute Mic",
LedCode::RogApp => "ROG",
LedCode::RogFan => "Fan Control",
LedCode::Esc => "Escape",
LedCode::F1 => "F1",
LedCode::F2 => "F2",
LedCode::F3 => "F3",
LedCode::F4 => "F4",
LedCode::F5 => "F5",
LedCode::F6 => "F6",
LedCode::F7 => "F7",
LedCode::F8 => "F8",
LedCode::F9 => "F9",
LedCode::F10 => "F10",
LedCode::F11 => "F11",
LedCode::F12 => "F12",
LedCode::Del => "Delete",
LedCode::Tilde => "Tilde",
LedCode::N1 => "1",
LedCode::N2 => "2",
LedCode::N3 => "3",
LedCode::N4 => "4",
LedCode::N5 => "5",
LedCode::N6 => "6",
LedCode::N7 => "7",
LedCode::N8 => "8",
LedCode::N9 => "9",
LedCode::N0 => "0",
LedCode::Hyphen => "-",
LedCode::Equals => "=",
LedCode::Backspace => "Backspace",
LedCode::Backspace3_1 => "Backspace LED 1",
LedCode::Backspace3_2 => "Backspace LED 2",
LedCode::Backspace3_3 => "Backspace LED 3",
LedCode::Home => "Home",
LedCode::Tab => "Tab",
LedCode::Q => "Q",
LedCode::W => "W",
LedCode::E => "E",
LedCode::R => "R",
LedCode::T => "T",
LedCode::Y => "Y",
LedCode::U => "U",
LedCode::I => "I",
LedCode::O => "O",
LedCode::P => "P",
LedCode::LBracket => "[",
LedCode::RBracket => "]",
LedCode::BackSlash => "\\",
LedCode::PgUp => "Page Up",
LedCode::Caps => "Caps Lock",
LedCode::A => "A",
LedCode::S => "S",
LedCode::D => "D",
LedCode::F => "F",
LedCode::G => "G",
LedCode::H => "H",
LedCode::J => "J",
LedCode::K => "K",
LedCode::L => "L",
LedCode::SemiColon => ";",
LedCode::Quote => "'",
LedCode::Return => "Return",
LedCode::Return3_1 => "Return LED 1",
LedCode::Return3_2 => "Return LED 2",
LedCode::Return3_3 => "Return LED 3",
LedCode::PgDn => "Page Down",
LedCode::LShift => "Left Shift",
LedCode::LShift3_1 => "Left Shift LED 1",
LedCode::LShift3_2 => "Left Shift LED 2",
LedCode::LShift3_3 => "Left Shift LED 3",
LedCode::Z => "Z",
LedCode::X => "X",
LedCode::C => "C",
LedCode::V => "V",
LedCode::B => "B",
LedCode::N => "N",
LedCode::M => "M",
LedCode::Comma => ",",
LedCode::Period => ".",
LedCode::Star => "*",
LedCode::NumPadDel => "Delete",
LedCode::NumPadPlus => "+",
LedCode::NumPadEnter => "Enter",
LedCode::NumPadPause => "Pause",
LedCode::NumPadPrtSc => "Print Screen",
LedCode::NumPadHome => "Home",
LedCode::NumLock => "Num-Lock",
LedCode::FwdSlash => "/",
LedCode::Rshift => "Right Shift",
LedCode::Rshift3_1 => "Right Shift LED 1",
LedCode::Rshift3_2 => "Right Shift LED 2",
LedCode::Rshift3_3 => "Right Shift LED 3",
LedCode::End => "End",
LedCode::LCtrl => "Left Control",
LedCode::LFn => "Left Fn",
LedCode::Meta => "Meta",
LedCode::LAlt => "Left Alt",
LedCode::Spacebar => "Space",
LedCode::Spacebar5_1 => "Space LED 1",
LedCode::Spacebar5_2 => "Space LED 2",
LedCode::Spacebar5_3 => "Space LED 3",
LedCode::Spacebar5_4 => "Space LED 4",
LedCode::Spacebar5_5 => "Space LED 5",
LedCode::RAlt => "Right Alt",
LedCode::PrtSc => "Print Screen",
LedCode::RCtrl => "Right Control",
LedCode::Pause => "Pause",
LedCode::Up => "Up",
LedCode::Down => "Down",
LedCode::Left => "Left",
LedCode::Right => "Right",
LedCode::RFn => "Right Fn",
LedCode::MediaPlay => "Media Play",
LedCode::MediaStop => "Media Stop",
LedCode::MediaNext => "Media Next",
LedCode::MediaPrev => "Media Previous",
LedCode::LidLogo => "Lid Logo",
LedCode::LidLeft => "Lid Left",
LedCode::LidRight => "Lid Right",
LedCode::LightbarRight => "Lightbar Right",
LedCode::LightbarRightCorner => "Lightbar Right Corner",
LedCode::LightbarRightBottom => "Lightbar Right Bottom",
LedCode::LightbarLeftBottom => "Lightbar Left Bottom",
LedCode::LightbarLeftCorner => "Lightbar Left Corner",
LedCode::LightbarLeft => "Lightbar Left",
LedCode::Spacing | LedCode::Blocking => "",
LedCode::SingleZone => "Single Zoned Keyboard",
LedCode::ZonedKbLeft => "Left Zone (zone 1)",
LedCode::ZonedKbLeftMid => "Center-left Zone (zone 2)",
LedCode::ZonedKbRightMid => "Center-right Zone (zone 3)",
LedCode::ZonedKbRight => "Right Zone (zone 4)",
}
}
}
+70 -60
View File
@@ -1,94 +1,102 @@
use dmi_id::DMIID; use dmi_id::DMIID;
use log::{error, info, warn}; use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use typeshare::typeshare;
use zbus::zvariant::{OwnedValue, Type, Value};
use crate::usb::AuraDevice; use crate::keyboard::AdvancedAuraType;
use crate::{AdvancedAuraType, AuraModeNum, AuraZone}; use crate::{AuraModeNum, AuraZone, PowerZones};
pub const ASUS_LED_MODE_CONF: &str = "/usr/share/asusd/aura_support.ron"; pub const ASUS_LED_MODE_CONF: &str = "/usr/share/asusd/aura_support.ron";
pub const ASUS_LED_MODE_USER_CONF: &str = "/etc/asusd/asusd_user_ledmodes.ron"; pub const ASUS_LED_MODE_USER_CONF: &str = "/etc/asusd/asusd_user_ledmodes.ron";
pub const ASUS_KEYBOARD_DEVICES: [AuraDevice; 8] = [
AuraDevice::Tuf,
AuraDevice::X1854,
AuraDevice::X1869,
AuraDevice::X1866,
AuraDevice::X18c6,
AuraDevice::X19b6,
AuraDevice::X1a30,
AuraDevice::X1abe,
];
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct LedSupportFile(Vec<LaptopLedData>);
/// The powerr zones this laptop supports
#[typeshare]
#[cfg_attr(
feature = "dbus",
derive(Type, Value, OwnedValue),
zvariant(signature = "s")
)]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Default, Copy, Clone)]
pub enum PowerZones {
/// The logo on some laptop lids
#[default]
Logo = 0,
/// The full keyboard (not zones)
Keyboard = 1,
/// The lightbar, typically on the front of the laptop
Lightbar = 2,
/// The leds that may be placed around the edge of the laptop lid
Lid = 3,
/// The led strip on the rear of some laptops
RearGlow = 4,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct LaptopLedData { pub struct LedSupportData {
/// Found via `cat /sys/class/dmi/id/board_name`, e.g `GU603ZW`. /// This can be many different types of name:
/// The match doesn't have to be the complete model number as it is /// - `/sys/class/dmi/id/board_name` (must use for laptops)
/// typically broken down such: /// - The device name from `lsusb`
///
/// The laptop board_name is found via `cat /sys/class/dmi/id/board_name`,
/// e.g `GU603ZW`. The match doesn't have to be the complete model
/// number as it is typically broken down such:
/// - GU = product /// - GU = product
/// - 603 = model/platform /// - 603 = model/platform
/// - Z = variant/year or perhaps dGPU model (such as RTX 3xxx) /// - Z = variant/year or perhaps dGPU model (such as RTX 3xxx)
/// - W = possibly dGPU model (such as RTX 3060Ti) /// - W = possibly dGPU model (such as RTX 3060Ti)
pub board_name: String, ///
/// If using a device name the match is similar to the above where it can be
/// partial, so `ASUSTek Computer, Inc. ROG STRIX Arion` can be `STRIX
/// Arion` for short. Case insensitive.
pub device_name: String,
/// The product ID (usb only)
/// Example of using a product ID is:
/// ```ignore
/// $ lsusb
/// $ Bus 003 Device 003: ID 0b05:19b6 ASUSTek Computer, Inc. N-KEY Device
/// ```
/// here `19b6` is all that is required. Case insensitive.
#[serde(default)]
pub product_id: String,
/// Keyboard or device LED layout, this is the name of the externally
/// defined layout file. Optional, can be an empty string
#[serde(default)]
pub layout_name: String, pub layout_name: String,
/// If empty will default to `Static` mode
pub basic_modes: Vec<AuraModeNum>, pub basic_modes: Vec<AuraModeNum>,
/// Available on some laptops. This is where the keyboard may be split in to
/// 4 zones and may have a logo and lightbar.
///
/// Ignored if empty.
#[serde(default)]
pub basic_zones: Vec<AuraZone>, pub basic_zones: Vec<AuraZone>,
/// `Zoned` or `PerKey`.
// TODO: remove and use layouts only
#[serde(default)]
pub advanced_type: AdvancedAuraType, pub advanced_type: AdvancedAuraType,
/// If empty will default to `Keyboard` power zone
pub power_zones: Vec<PowerZones>, pub power_zones: Vec<PowerZones>,
} }
impl LaptopLedData { impl LedSupportData {
pub fn get_data() -> Self { /// Find the data for the device. This function will check DMI info for
/// matches against laptops first, then will proceed with matching the
/// `device_name` if there are no DMI matches.
pub fn get_data(product_id: &str) -> Self {
let dmi = DMIID::new().unwrap_or_default(); let dmi = DMIID::new().unwrap_or_default();
// let prod_family = dmi.product_family().expect("Could not get // let prod_family = dmi.product_family().expect("Could not get
// product_family"); // product_family");
if let Some(modes) = LedSupportFile::load_from_supoprt_db() { if let Some(data) = LedSupportFile::load_from_supoprt_db() {
if let Some(data) = modes.matcher(&dmi.board_name) { if let Some(data) = data.match_device(&dmi.board_name, product_id) {
return data; return data;
} }
} }
info!("Using generic LED control for keyboard brightness only"); info!("Using generic LED control for keyboard brightness only");
LaptopLedData::default() LedSupportData::default()
} }
} }
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct LedSupportFile(Vec<LedSupportData>);
impl LedSupportFile { impl LedSupportFile {
pub fn get(&self) -> &[LaptopLedData] { pub fn get(&self) -> &[LedSupportData] {
&self.0 &self.0
} }
/// The list is stored in ordered format, so the iterator must be reversed /// The list is stored in ordered format, so the iterator must be reversed
/// to ensure we match to *whole names* first before doing a glob match /// to ensure we match to *whole names* first before doing a glob match
pub fn matcher(self, board_name: &str) -> Option<LaptopLedData> { fn match_device(&self, device_name: &str, product_id: &str) -> Option<LedSupportData> {
for config in self.0.iter().rev() { for config in self.0.iter().rev() {
if board_name.contains(&config.board_name) { if device_name.contains(&config.device_name) {
info!("LedSupport: Matched to {}", config.board_name); info!("Matched to {}", config.device_name);
if !config.product_id.is_empty() {
info!("Checking product ID");
if config.product_id == product_id {
info!("Matched to {}", config.product_id);
return Some(config.clone());
} else {
continue;
}
}
return Some(config.clone()); return Some(config.clone());
} }
} }
@@ -133,7 +141,7 @@ impl LedSupportFile {
); );
} }
} }
data.0.sort_by(|a, b| a.board_name.cmp(&b.board_name)); data.0.sort_by(|a, b| a.device_name.cmp(&b.device_name));
if loaded { if loaded {
return Some(data); return Some(data);
@@ -152,16 +160,17 @@ mod tests {
use ron::ser::PrettyConfig; use ron::ser::PrettyConfig;
use super::LaptopLedData; use super::LedSupportData;
use crate::advanced::LedCode;
use crate::aura_detection::{LedSupportFile, PowerZones}; use crate::aura_detection::{LedSupportFile, PowerZones};
use crate::keyboard::{AdvancedAuraType, LedCode};
// use crate::zoned::Zone; // use crate::zoned::Zone;
use crate::{AdvancedAuraType, AuraModeNum, AuraZone}; use crate::{AuraModeNum, AuraZone};
#[test] #[test]
fn check_data_parse() { fn check_data_parse() {
let led = LaptopLedData { let led = LedSupportData {
board_name: "Test".to_owned(), device_name: "Test".to_owned(),
product_id: String::new(),
layout_name: "ga401".to_owned(), layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static], basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft], basic_zones: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft],
@@ -184,7 +193,8 @@ mod tests {
// Ensure the data is sorted // Ensure the data is sorted
let mut tmp_sort = tmp.clone(); let mut tmp_sort = tmp.clone();
tmp_sort.0.sort_by(|a, b| a.board_name.cmp(&b.board_name)); tmp_sort.0.sort_by(|a, b| a.product_id.cmp(&b.product_id));
tmp_sort.0.sort_by(|a, b| a.device_name.cmp(&b.device_name));
if tmp != tmp_sort { if tmp != tmp_sort {
let sorted = let sorted =
ron::ser::to_string_pretty(&tmp_sort, PrettyConfig::new().depth_limit(2)).unwrap(); ron::ser::to_string_pretty(&tmp_sort, PrettyConfig::new().depth_limit(2)).unwrap();
+89 -7
View File
@@ -1,9 +1,3 @@
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use std::fmt::Display; use std::fmt::Display;
use std::str::FromStr; use std::str::FromStr;
@@ -67,6 +61,24 @@ impl From<LedBrightness> for u8 {
} }
} }
impl From<LedBrightness> for i32 {
fn from(l: LedBrightness) -> Self {
l as i32
}
}
impl From<i32> for LedBrightness {
fn from(l: i32) -> Self {
match l {
0 => LedBrightness::Off,
1 => LedBrightness::Low,
2 => LedBrightness::Med,
3 => LedBrightness::High,
_ => LedBrightness::Med,
}
}
}
#[typeshare] #[typeshare]
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))] #[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)]
@@ -156,6 +168,26 @@ impl FromStr for Speed {
} }
} }
impl From<i32> for Speed {
fn from(value: i32) -> Self {
match value {
0 => Self::Low,
2 => Self::High,
_ => Self::Med,
}
}
}
impl From<Speed> for i32 {
fn from(value: Speed) -> Self {
match value {
Speed::Low => 0,
Speed::Med => 1,
Speed::High => 2,
}
}
}
impl From<Speed> for u8 { impl From<Speed> for u8 {
fn from(s: Speed) -> u8 { fn from(s: Speed) -> u8 {
match s { match s {
@@ -198,6 +230,23 @@ impl FromStr for Direction {
} }
} }
impl From<i32> for Direction {
fn from(value: i32) -> Self {
match value {
1 => Self::Left,
2 => Self::Up,
3 => Self::Down,
_ => Self::Right,
}
}
}
impl From<Direction> for i32 {
fn from(value: Direction) -> Self {
value as i32
}
}
/// Enum of modes that convert to the actual number required by a USB HID packet /// Enum of modes that convert to the actual number required by a USB HID packet
#[typeshare] #[typeshare]
#[cfg_attr( #[cfg_attr(
@@ -292,6 +341,18 @@ impl From<u8> for AuraModeNum {
} }
} }
impl From<i32> for AuraModeNum {
fn from(mode: i32) -> Self {
(mode as u8).into()
}
}
impl From<AuraModeNum> for i32 {
fn from(value: AuraModeNum) -> Self {
value as i32
}
}
impl From<AuraEffect> for AuraModeNum { impl From<AuraEffect> for AuraModeNum {
fn from(value: AuraEffect) -> Self { fn from(value: AuraEffect) -> Self {
value.mode value.mode
@@ -303,7 +364,7 @@ impl From<AuraEffect> for AuraModeNum {
#[cfg_attr( #[cfg_attr(
feature = "dbus", feature = "dbus",
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
zvariant(signature = "s") zvariant(signature = "u")
)] )]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum AuraZone { pub enum AuraZone {
@@ -345,6 +406,27 @@ impl FromStr for AuraZone {
} }
} }
impl From<i32> for AuraZone {
fn from(value: i32) -> Self {
match value {
1 => Self::Key1,
2 => Self::Key2,
3 => Self::Key3,
4 => Self::Key4,
5 => Self::Logo,
6 => Self::BarLeft,
7 => Self::BarRight,
_ => Self::default(),
}
}
}
impl From<AuraZone> for i32 {
fn from(value: AuraZone) -> Self {
value as i32
}
}
/// Default factory modes structure. This easily converts to an USB HID packet /// Default factory modes structure. This easily converts to an USB HID packet
/// with: /// with:
/// ```rust /// ```rust
-162
View File
@@ -1,162 +0,0 @@
//! Older code that is not useful but stillr elevant as a reference
/// # Bits for newer 0x18c6, 0x19B6, 0x1a30, keyboard models
///
/// | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Label |
/// |--------|---------|---------|---------|----------|
/// |00000001| 00000000| 00000000| 00000000|boot_logo_|
/// |00000010| 00000000| 00000000| 00000000|boot_keyb_|
/// |00000100| 00000000| 00000000| 00000000|awake_logo|
/// |00001000| 00000000| 00000000| 00000000|awake_keyb|
/// |00010000| 00000000| 00000000| 00000000|sleep_logo|
/// |00100000| 00000000| 00000000| 00000000|sleep_keyb|
/// |01000000| 00000000| 00000000| 00000000|shut_logo_|
/// |10000000| 00000000| 00000000| 00000000|shut_keyb_|
/// |00000000| 00000010| 00000000| 00000000|boot_bar__|
/// |00000000| 00000100| 00000000| 00000000|awake_bar_|
/// |00000000| 00001000| 00000000| 00000000|sleep_bar_|
/// |00000000| 00010000| 00000000| 00000000|shut_bar__|
/// |00000000| 00000000| 00000001| 00000000|boot_lid__|
/// |00000000| 00000000| 00000010| 00000000|awkae_lid_|
/// |00000000| 00000000| 00000100| 00000000|sleep_lid_|
/// |00000000| 00000000| 00001000| 00000000|shut_lid__|
/// |00000000| 00000000| 00000000| 00000001|boot_rear_|
/// |00000000| 00000000| 00000000| 00000010|awake_rear|
/// |00000000| 00000000| 00000000| 00000100|sleep_rear|
/// |00000000| 00000000| 00000000| 00001000|shut_rear_|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum AuraDevRog2 {
BootLogo = 1,
BootKeyb = 1 << 1,
AwakeLogo = 1 << 2,
AwakeKeyb = 1 << 3,
SleepLogo = 1 << 4,
SleepKeyb = 1 << 5,
ShutdownLogo = 1 << 6,
ShutdownKeyb = 1 << 7,
BootBar = 1 << (7 + 2),
AwakeBar = 1 << (7 + 3),
SleepBar = 1 << (7 + 4),
ShutdownBar = 1 << (7 + 5),
BootLid = 1 << (15 + 1),
AwakeLid = 1 << (15 + 2),
SleepLid = 1 << (15 + 3),
ShutdownLid = 1 << (15 + 4),
BootRearGlow = 1 << (23 + 1),
AwakeRearGlow = 1 << (23 + 2),
SleepRearGlow = 1 << (23 + 3),
ShutdownRearGlow = 1 << (23 + 4),
}
impl From<AuraDevRog2> for u32 {
fn from(a: AuraDevRog2) -> Self {
a as u32
}
}
impl AuraDevRog2 {
pub fn to_bytes(control: &[Self]) -> [u8; 4] {
let mut a: u32 = 0;
for n in control {
a |= *n as u32;
}
[
(a & 0xff) as u8,
((a & 0xff00) >> 8) as u8,
((a & 0xff0000) >> 16) as u8,
((a & 0xff000000) >> 24) as u8,
]
}
pub const fn dev_id() -> &'static str {
"0x196b"
}
}
#[cfg(test)]
mod tests {
use crate::deprecated::AuraDevRog2;
#[test]
fn check_0x19b6_control_bytes_binary_rep() {
fn to_binary_string(bytes: &[AuraDevRog2]) -> String {
let bytes = AuraDevRog2::to_bytes(bytes);
format!(
"{:08b}, {:08b}, {:08b}, {:08b}",
bytes[0], bytes[1], bytes[2], bytes[3]
)
}
let boot_logo_ = to_binary_string(&[AuraDevRog2::BootLogo]);
let boot_keyb_ = to_binary_string(&[AuraDevRog2::BootKeyb]);
let sleep_logo = to_binary_string(&[AuraDevRog2::SleepLogo]);
let sleep_keyb = to_binary_string(&[AuraDevRog2::SleepKeyb]);
let awake_logo = to_binary_string(&[AuraDevRog2::AwakeLogo]);
let awake_keyb = to_binary_string(&[AuraDevRog2::AwakeKeyb]);
let shut_logo_ = to_binary_string(&[AuraDevRog2::ShutdownLogo]);
let shut_keyb_ = to_binary_string(&[AuraDevRog2::ShutdownKeyb]);
let boot_bar__ = to_binary_string(&[AuraDevRog2::BootBar]);
let awake_bar_ = to_binary_string(&[AuraDevRog2::AwakeBar]);
let sleep_bar_ = to_binary_string(&[AuraDevRog2::SleepBar]);
let shut_bar__ = to_binary_string(&[AuraDevRog2::ShutdownBar]);
let boot_lid__ = to_binary_string(&[AuraDevRog2::BootLid]);
let awkae_lid_ = to_binary_string(&[AuraDevRog2::AwakeLid]);
let sleep_lid_ = to_binary_string(&[AuraDevRog2::SleepLid]);
let shut_lid__ = to_binary_string(&[AuraDevRog2::ShutdownLid]);
let boot_rear_ = to_binary_string(&[AuraDevRog2::BootRearGlow]);
let awake_rear = to_binary_string(&[AuraDevRog2::AwakeRearGlow]);
let sleep_rear = to_binary_string(&[AuraDevRog2::SleepRearGlow]);
let shut_rear_ = to_binary_string(&[AuraDevRog2::ShutdownRearGlow]);
assert_eq!(boot_logo_, "00000001, 00000000, 00000000, 00000000");
assert_eq!(boot_keyb_, "00000010, 00000000, 00000000, 00000000");
assert_eq!(awake_logo, "00000100, 00000000, 00000000, 00000000");
assert_eq!(awake_keyb, "00001000, 00000000, 00000000, 00000000");
assert_eq!(sleep_logo, "00010000, 00000000, 00000000, 00000000");
assert_eq!(sleep_keyb, "00100000, 00000000, 00000000, 00000000");
assert_eq!(shut_logo_, "01000000, 00000000, 00000000, 00000000");
assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000");
//
assert_eq!(boot_bar__, "00000000, 00000010, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000100, 00000000, 00000000");
assert_eq!(sleep_bar_, "00000000, 00001000, 00000000, 00000000");
assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000");
//
assert_eq!(boot_lid__, "00000000, 00000000, 00000001, 00000000");
assert_eq!(awkae_lid_, "00000000, 00000000, 00000010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 00000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 00001000, 00000000");
//
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00000001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00000010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 00000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 00001000");
// All on
let byte1 = [
AuraDevRog2::BootLogo,
AuraDevRog2::BootKeyb,
AuraDevRog2::SleepLogo,
AuraDevRog2::SleepKeyb,
AuraDevRog2::AwakeLogo,
AuraDevRog2::AwakeKeyb,
AuraDevRog2::ShutdownLogo,
AuraDevRog2::ShutdownKeyb,
AuraDevRog2::BootBar,
AuraDevRog2::AwakeBar,
AuraDevRog2::SleepBar,
AuraDevRog2::ShutdownBar,
AuraDevRog2::AwakeLid,
AuraDevRog2::BootLid,
AuraDevRog2::SleepLid,
AuraDevRog2::ShutdownLid,
AuraDevRog2::AwakeRearGlow,
AuraDevRog2::BootRearGlow,
AuraDevRog2::SleepRearGlow,
AuraDevRog2::ShutdownRearGlow,
];
let out = to_binary_string(&byte1);
assert_eq!(out, "11111111, 00011110, 00001111, 00001111");
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
use super::{EffectState, InputForEffect}; use super::{EffectState, InputForEffect};
use crate::advanced::LedCode; use crate::keyboard::{KeyLayout, LedCode};
use crate::Colour; use crate::Colour;
pub struct InputBased { pub struct InputBased {
@@ -14,7 +14,7 @@ pub struct InputBased {
} }
impl EffectState for InputBased { impl EffectState for InputBased {
fn next_colour_state(&mut self, _layout: &crate::layouts::KeyLayout) { fn next_colour_state(&mut self, _layout: &KeyLayout) {
self.input.next_colour_state(); self.input.next_colour_state();
self.colour = self.input.get_colour(); self.colour = self.input.get_colour();
} }
+1 -2
View File
@@ -1,8 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::EffectState; use super::EffectState;
use crate::advanced::LedCode; use crate::keyboard::{KeyLayout, LedCode};
use crate::layouts::KeyLayout;
use crate::{effect_state_impl, Colour, Speed}; use crate::{effect_state_impl, Colour, Speed};
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
+1 -2
View File
@@ -1,8 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::advanced::LedCode;
use crate::effects::{p_random, EffectState}; use crate::effects::{p_random, EffectState};
use crate::layouts::KeyLayout; use crate::keyboard::{KeyLayout, LedCode};
use crate::{effect_state_impl, Colour}; use crate::{effect_state_impl, Colour};
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]

Some files were not shown because too many files have changed in this diff Show More