Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ebf0c2bb2 | ||
|
|
77c658c94e | ||
|
|
df64a51372 | ||
|
|
0657c6cc74 | ||
|
|
f116905e85 | ||
|
|
e515741efa | ||
|
|
d516abdc92 | ||
|
|
ece565de1c | ||
|
|
eb83d1a835 | ||
|
|
7d0f15d738 | ||
|
|
8010da0891 | ||
|
|
aa500c35c4 | ||
|
|
2af33a0416 | ||
|
|
9b4ed6eb62 | ||
|
|
47c1ca9fe4 | ||
|
|
3cd624daf0 | ||
|
|
fa16864a3e | ||
|
|
bfc31b06d5 | ||
|
|
d854f7da1b | ||
|
|
6d746b21a5 | ||
|
|
226c083a51 | ||
|
|
de59d00949 | ||
|
|
7ff01f12e9 | ||
|
|
fbc248177a | ||
|
|
fc3d7653f5 | ||
|
|
2dc70ea6af | ||
|
|
01345b28a5 | ||
|
|
4eeacea832 | ||
|
|
6bf0fdd117 | ||
|
|
7fcde7df17 | ||
|
|
543b0b817f | ||
|
|
5a7d31fdf6 | ||
|
|
301c532b65 | ||
|
|
df7ae4d014 | ||
|
|
96ceef1bdb | ||
|
|
bc72b93625 | ||
|
|
03b338bdfa | ||
|
|
7a51cd1c70 | ||
|
|
0449a4b06b | ||
|
|
bc46fa2b1e | ||
|
|
759ddeb270 | ||
|
|
538e111e78 | ||
|
|
45ab568f7a | ||
|
|
b32089843a | ||
|
|
d960aacf4f | ||
|
|
1c48ab227d | ||
|
|
6528ec95c2 | ||
|
|
53ee6015d0 | ||
|
|
ad150903af |
53
CHANGELOG.md
@@ -5,14 +5,63 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
# [3.4.0] - 2021-04-11
|
||||
### Changed
|
||||
- Revert zbus to 1.9.1
|
||||
- Use enum to show power states, and catch missing pci path for nvidia.
|
||||
- Partial user-daemon for anime/per-key done, `asusd-user`. Includes asusd-user systemd unit.
|
||||
- user-daemon provides dbus emthods to insert anime actions, remove from index, set leds on/off
|
||||
+ COnfig file is stored in `~/.config/rog/rog-user.cfg`
|
||||
- AniMe display parts split out to individual crate in preparation for publishing
|
||||
on crates.io
|
||||
|
||||
# [3.3.0] - 2021-04-3
|
||||
### Changed
|
||||
- Add ledmodes for G733QS
|
||||
- Add ledmodes for GA401Q
|
||||
- Default to vfio disabled in configuration. Will now hard-error if enabled and
|
||||
the kernel modules are builtin. To enable vfio switching `"gfx_vfio_enable": false,`
|
||||
must be changed to `true` in `/etc/asusd/asusd.conf`
|
||||
|
||||
# [3.2.4] - 2021-03-24
|
||||
### Changed
|
||||
- Ignore vfio-builtin error if switching to integrated
|
||||
|
||||
# [3.2.3] - 2021-03-24
|
||||
### Changed
|
||||
- Better handling of session tracking
|
||||
### Added
|
||||
- List all profile data
|
||||
- Get active profile name
|
||||
- Get active profile data
|
||||
|
||||
# [3.2.2] - 2021-03-23
|
||||
### Changed
|
||||
- Fix brightness control, again, for non-RGB keyboards
|
||||
|
||||
# [3.2.1] - 2021-03-21
|
||||
### Changed
|
||||
- Fix brightness control
|
||||
- Large cleanup of code relating to LED controls
|
||||
|
||||
# [3.2.0] - 2021-03-21
|
||||
### Changed
|
||||
- Refactor keyboard LED handling
|
||||
- Added --list for profiles (Thanks @aqez)
|
||||
- Added --remove for profiles (Thanks @aqez)
|
||||
- Added a graphics mode: vfio. This attaches Nvidia devices to vfio module.
|
||||
### Broken
|
||||
- Per-key LED modes, which need thinking about how to go ahead with for future
|
||||
|
||||
# [3.1.7] - 2021-03-11
|
||||
### Changed
|
||||
- Refactor many parts of daemon
|
||||
- Switch out session monitoring to logind-zbus
|
||||
- Switch out session monitoring to logind-zbus
|
||||
|
||||
# [3.1.6] - 2021-03-11
|
||||
### Changed
|
||||
- Graphics switching will now wait until all users logged out before switching
|
||||
- Graphics switching will now wait until all users logged out before switching
|
||||
|
||||
### Changed
|
||||
- Further tweaks to gfx switching
|
||||
|
||||
419
Cargo.lock
generated
@@ -1,5 +1,13 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
@@ -28,15 +36,19 @@ dependencies = [
|
||||
"daemon",
|
||||
"notify-rust",
|
||||
"rog_dbus",
|
||||
"rog_types",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asusctl"
|
||||
version = "3.1.3"
|
||||
version = "3.4.0"
|
||||
dependencies = [
|
||||
"daemon",
|
||||
"gif",
|
||||
"glam",
|
||||
"gumdrop",
|
||||
"rog_anime",
|
||||
"rog_dbus",
|
||||
"rog_types",
|
||||
"serde_json",
|
||||
@@ -64,15 +76,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@@ -168,6 +171,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.2"
|
||||
@@ -196,12 +205,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "daemon"
|
||||
version = "3.1.7"
|
||||
version = "3.4.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"intel-pstate",
|
||||
"log",
|
||||
"logind-zbus",
|
||||
"rog_anime",
|
||||
"rog_dbus",
|
||||
"rog_fan_curve",
|
||||
"rog_types",
|
||||
@@ -212,10 +222,26 @@ dependencies = [
|
||||
"sysfs-class",
|
||||
"toml",
|
||||
"udev",
|
||||
"zbus 2.0.0-beta.3",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "daemon-user"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"dirs 3.0.1",
|
||||
"rog_anime",
|
||||
"rog_dbus",
|
||||
"rog_types",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
@@ -224,7 +250,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -238,6 +264,26 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.6.4"
|
||||
@@ -256,7 +302,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -282,16 +328,10 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"rustversion",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.4.0"
|
||||
@@ -303,9 +343,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
|
||||
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -318,9 +358,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
|
||||
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -328,15 +368,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
|
||||
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
|
||||
checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -345,9 +385,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
|
||||
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -366,33 +406,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7"
|
||||
checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
|
||||
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
|
||||
checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
|
||||
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -420,14 +460,22 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.2"
|
||||
name = "gif"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||
checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glam"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -447,7 +495,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -459,12 +507,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
@@ -504,9 +546,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.89"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "libudev-sys"
|
||||
@@ -541,14 +583,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "logind-zbus"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6671f6cf88b63e9d63009f4f6f8826fcc265c51a9977e4c7dc1263d743e0dfbb"
|
||||
checksum = "dca64bea11e365933e0c4a1a9342f0122d1d2822a09c87dab0e1d314adb353a2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"zbus 2.0.0-beta.3",
|
||||
"zbus_macros 2.0.0-beta.3",
|
||||
"zbus",
|
||||
"zbus_macros",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
@@ -561,7 +603,7 @@ checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chrono",
|
||||
"dirs",
|
||||
"dirs 1.0.5",
|
||||
"objc-foundation",
|
||||
]
|
||||
|
||||
@@ -581,10 +623,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "nb-connect"
|
||||
version = "1.0.3"
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb-connect"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19900e7eee95eb2b3c2e26d12a874cc80aaf750e31be6fcbe743ead369fa45d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"socket2",
|
||||
@@ -603,18 +655,6 @@ dependencies = [
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
@@ -634,7 +674,7 @@ dependencies = [
|
||||
"mac-notification-sys",
|
||||
"serde",
|
||||
"winrt-notification",
|
||||
"zbus 1.8.0",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
@@ -717,6 +757,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pix"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bea9d5c668f13b4a1b97d848780e00cfabf76eb83538129c264c0c6d6a968047"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
@@ -724,24 +770,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.0.2"
|
||||
name = "png_pong"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4"
|
||||
checksum = "75851150081bd473079e03e2fa00e25557bcb19706e502b095ca71ce392b70ff"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"miniz_oxide",
|
||||
"pix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"log",
|
||||
"wepoll-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
@@ -760,7 +810,7 @@ dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -789,9 +839,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
@@ -811,46 +861,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
@@ -863,7 +873,7 @@ version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
@@ -886,14 +896,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
|
||||
[[package]]
|
||||
name = "rog_dbus"
|
||||
version = "3.0.0"
|
||||
name = "rog_anime"
|
||||
version = "1.0.2"
|
||||
dependencies = [
|
||||
"gif",
|
||||
"glam",
|
||||
"pix",
|
||||
"png_pong",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"zbus",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rog_dbus"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"rog_anime",
|
||||
"rog_fan_curve",
|
||||
"rog_types",
|
||||
"serde_json",
|
||||
"zbus 1.8.0",
|
||||
"zbus_macros 1.8.0",
|
||||
"zbus",
|
||||
"zbus_macros",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
@@ -908,7 +934,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rog_types"
|
||||
version = "3.0.0"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"gumdrop",
|
||||
"rog_fan_curve",
|
||||
@@ -920,9 +946,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rusb"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c470dc7dc6e4710b6f85e9c4aa4650bc742260b39a36328180578db76fa258c1"
|
||||
checksum = "12f3264859095257507e4c011ab420ff9b2d9cc3349c6c08a1d3a019260bb437"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libusb1-sys",
|
||||
@@ -960,22 +986,22 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -997,30 +1023,15 @@ checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smart-default"
|
||||
version = "0.6.0"
|
||||
@@ -1029,16 +1040,15 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.19"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
|
||||
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
@@ -1072,9 +1082,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
@@ -1098,7 +1108,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
@@ -1122,11 +1132,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -1150,9 +1161,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "udev"
|
||||
version = "0.6.0"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "307c2b8c8a320a38365def5bb3ee92d146d405655196230f7a445fe4da6749f6"
|
||||
checksum = "3193363f52bb34c6708ac2ffedcb5f7e5874f0329ef68e1315f27d8d768eb568"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
@@ -1179,9 +1190,9 @@ checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
|
||||
|
||||
[[package]]
|
||||
name = "vec-arena"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d"
|
||||
checksum = "34b2f665b594b07095e3ac3f718e13c2197143416fae4c5706cffb7b1af8d7f1"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@@ -1209,9 +1220,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c"
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-sys"
|
||||
@@ -1295,9 +1312,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "1.8.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b4d4aa39daed4e32aed75f0c37b969184949a0fdfd5f2e1277abfda61f02a8"
|
||||
checksum = "2326acc379a3ac4e34b794089f5bdb17086bf29a5fdf619b7b4cc772dc2e9dad"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"byteorder",
|
||||
@@ -1306,66 +1323,26 @@ dependencies = [
|
||||
"fastrand",
|
||||
"futures",
|
||||
"nb-connect",
|
||||
"nix 0.17.0",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"polling",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"zbus_macros 1.8.0",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "2.0.0-beta.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e1e656194618d167524f97e88ff9bf87f2b1e8bf58f357b2a7abfdff8cc85c9"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"byteorder",
|
||||
"derivative",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"nix 0.19.1",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"sha1",
|
||||
"slotmap",
|
||||
"zbus_macros 2.0.0-beta.3",
|
||||
"zbus_macros",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "1.8.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc141cda72384bef359badf1808e391d3968f9299e8f3c3cbb78dafa1e0930"
|
||||
checksum = "a482c56029e48681b89b92b5db3c446db0915e8dd1052c0328a574eda38d5f93"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "2.0.0-beta.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcd4cb372bc2cade3f2323e4104112dceb6819f5dd9afa98515b4e821d232932"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1389,5 +1366,5 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"syn 1.0.69",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["asusctl", "asus-notify", "daemon", "rog-types", "rog-dbus"]
|
||||
members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-types", "rog-dbus", "rog-anime"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
9
Makefile
@@ -13,6 +13,7 @@ zshcpl = $(datarootdir)/zsh/site-functions
|
||||
|
||||
BIN_C := asusctl
|
||||
BIN_D := asusd
|
||||
BIN_U := asusd-user
|
||||
BIN_N := asus-notify
|
||||
LEDCFG := asusd-ledmodes.toml
|
||||
X11CFG := 90-nvidia-screen-G05.conf
|
||||
@@ -42,6 +43,7 @@ distclean:
|
||||
install:
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
|
||||
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||
$(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
|
||||
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
|
||||
@@ -50,11 +52,13 @@ install:
|
||||
$(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
|
||||
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
|
||||
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
|
||||
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
|
||||
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||
$(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl"
|
||||
$(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
|
||||
cd data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \;
|
||||
|
||||
uninstall:
|
||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||
@@ -72,6 +76,7 @@ uninstall:
|
||||
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||
rm -f "$(DESTDIR)$(zshcpl)/_asusctl"
|
||||
rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
|
||||
rm -rf "$(DESTDIR)$(datarootdir)/asusd"
|
||||
|
||||
update:
|
||||
cargo update
|
||||
@@ -82,13 +87,13 @@ vendor:
|
||||
echo 'directory = "vendor"' >> .cargo/config
|
||||
mv .cargo/config ./cargo-config
|
||||
rm -rf .cargo
|
||||
tar pcfJ vendor_asus-nb-ctrl_$(VERSION).tar.xz vendor
|
||||
tar pcfJ vendor_asusctl_$(VERSION).tar.xz vendor
|
||||
rm -rf vendor
|
||||
|
||||
build:
|
||||
ifeq ($(VENDORED),1)
|
||||
@echo "version = $(VERSION)"
|
||||
tar pxf vendor_asus-nb-ctrl_$(VERSION).tar.xz
|
||||
tar pxf vendor_asusctl_$(VERSION).tar.xz
|
||||
endif
|
||||
cargo build $(ARGS)
|
||||
|
||||
|
||||
150
README.md
@@ -5,29 +5,26 @@
|
||||
`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.
|
||||
|
||||
**NOTICE:**
|
||||
## Goals
|
||||
|
||||
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
|
||||
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.
|
||||
2. Enable third-party apps to use the above with dbus methods
|
||||
3. To make the above as easy as possible for new users
|
||||
|
||||
Point 3 means that the list of supported distros is very narrow - fedora is explicitly
|
||||
supported, while Ubuntu and openSUSE are level-2 support. All other distros are *not*
|
||||
supported (while asusd might still run fine on them). For best support use fedora 32+ Workstation.
|
||||
|
||||
**NOTICE:**
|
||||
The following is *not* required for 5.11 kernel versions, as this version includes
|
||||
all the required patches.
|
||||
---
|
||||
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
|
||||
Alternatively you may use the dkms module for 'hid-asus-rog` from one of the
|
||||
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
|
||||
1. The following is *not* required for 5.11 kernel versions, as this version includes all the required patches.
|
||||
2. 2021 hardware has a new keyboard prod_id and the patch is included in 5.12+
|
||||
|
||||
The patch enables the following in kernel:
|
||||
'hid-asus-rog` DKMS module from [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
|
||||
|
||||
The module enables the following in kernel:
|
||||
|
||||
- Initialising the keyboard
|
||||
- All hotkeys (FN+Key combos)
|
||||
- Control of keyboard brightness using FN+Key combos (not RGB)
|
||||
- FN+F5 (fan) to toggle fan modes
|
||||
|
||||
You will not get RGB control in kernel (yet), and `asusd` + `asusctl` is required
|
||||
to change modes and RGB settings.
|
||||
|
||||
Many other patches for these laptops, AMD and Intel based, are working their way
|
||||
in to the kernel.
|
||||
|
||||
## Discord
|
||||
|
||||
@@ -52,13 +49,14 @@ will probably suffer another rename once it becomes generic enough to do so.
|
||||
- [X] User notifications daemon
|
||||
- [X] Setting/modifying built-in LED modes
|
||||
- [X] Per-key LED setting
|
||||
- [X] Fancy LED modes (See examples)
|
||||
- [X] Fancy LED modes (See examples) (currently being reworked)
|
||||
- [X] Saving settings for reload
|
||||
- [X] Logging - required for journalctl
|
||||
- [X] AniMatrix display on G14 models that include it
|
||||
- [X] AniMatrix display on G14 models that include it (currently being reworked)
|
||||
- [X] Set battery charge limit (with kernel supporting this)
|
||||
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
|
||||
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
|
||||
- [X] Fan curve control on G14 + G15 thanks to @Yarn1
|
||||
- [X] Graphics mode switching between iGPU, dGPU, on-demand, and vfio (for VM pass-through)
|
||||
+ [X] Requires only a logout/login
|
||||
- [X] Toggle bios setting for boot/POST sound
|
||||
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
|
||||
|
||||
@@ -66,13 +64,20 @@ will probably suffer another rename once it becomes generic enough to do so.
|
||||
|
||||
## Graphics switching
|
||||
|
||||
A new feature has been added to enable switching graphics modes. This can be disabled
|
||||
in the config with `"manage_gfx": false,`. Additionally there is an extra setting
|
||||
for laptops capable of g-sync dedicated gfx mode to enable the graphics switching
|
||||
to switch on dedicated gfx for "nvidia" mode.
|
||||
`asusd` can switch graphics modes between:
|
||||
- `integrated`, uses the iGPU only and force-disables the dGPU
|
||||
- `hybrid`, enables Nvidia prime-offload mode
|
||||
- `nvidia`, uses the Nvidia gpu only
|
||||
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
|
||||
|
||||
The CLI option for this does not require root until it asks for it, and provides
|
||||
instructions.
|
||||
**Rebootless note:** You must edit `/etc/default/grub` to remove `nvidia-drm.modeset=1`
|
||||
from the line `GRUB_CMDLINE_LINUX=` and then recreate your grub config. In fedora
|
||||
you can do this with `sudo grub2-mkconfig -o /etc/grub2.cfg` - other distro may be
|
||||
similar but with a different config location.
|
||||
|
||||
This can be disabled in the config with `"manage_gfx": false,`. Additionally there
|
||||
is an extra setting for laptops capable of g-sync dedicated gfx mode to enable the
|
||||
graphics switching to switch on dedicated gfx for "nvidia" mode.
|
||||
|
||||
This switcher conflicts with other gpu switchers like optimus-manager, suse-prime
|
||||
or ubuntu-prime, system76-power, and bbswitch. If you have issues with `asusd`
|
||||
@@ -81,6 +86,12 @@ stray configs blocking nvidia modules from loading in:
|
||||
- `/etc/modprobe.d/`
|
||||
- `/usr/lib/modprope.d/`
|
||||
|
||||
**VFIO NOTE:** The vfio modules *must not* be compiled into the kernel, they need
|
||||
to be separate modules. If you don't plan to use vfio mode then you can ignore this
|
||||
otherwise you may need a custom built kernel.
|
||||
|
||||
To enable vfio switching you need to edit `/etc/asusd/asusd.conf` and change `"gfx_vfio_enable": false,` to true.
|
||||
|
||||
### Power management udev rule
|
||||
|
||||
If you have installed the Nvidia driver manually you will require the
|
||||
@@ -89,8 +100,8 @@ If you have installed the Nvidia driver manually you will require the
|
||||
### fedora and openSUSE
|
||||
|
||||
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
|
||||
to stop dracut including the nvidia modules in the ramdisk. This is espeically
|
||||
true if you manually installed the nvidia drivers.
|
||||
to stop dracut including the nvidia modules in the ramdisk if you manually
|
||||
installed the nvidia drivers.
|
||||
|
||||
```
|
||||
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
|
||||
@@ -109,24 +120,21 @@ Models GA401, GA502, GU502 support LED brightness change only (no RGB).
|
||||
If you model isn't getting the correct led modes, you can edit the file
|
||||
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
|
||||
|
||||
```
|
||||
0 STATIC
|
||||
1 BREATHING
|
||||
2 STROBE
|
||||
3 RAINBOW
|
||||
4 STAR
|
||||
5 RAIN
|
||||
6 HIGHLIGHT
|
||||
7 LASER
|
||||
8 RIPPLE
|
||||
10 PULSE
|
||||
11 COMET
|
||||
12 FLASH
|
||||
13 MULTISTATIC
|
||||
255 PER_KEY
|
||||
```
|
||||
- Static
|
||||
- Breathe
|
||||
- Strobe
|
||||
- Rainbow
|
||||
- Star
|
||||
- Rain
|
||||
- Highlight
|
||||
- Laser
|
||||
- Ripple
|
||||
- Pulse
|
||||
- Comet
|
||||
- Flash
|
||||
|
||||
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
|
||||
use `cat /sys/class/dmi/id/product_name` to get details about your laptop. You
|
||||
must restart the `asusd.service` after editing.
|
||||
|
||||
# Keybinds
|
||||
|
||||
@@ -156,8 +164,6 @@ Packaging and auto-builds are available [here](https://build.opensuse.org/packag
|
||||
|
||||
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
|
||||
|
||||
Alternatively check the releases page for f33 RPM.
|
||||
|
||||
---
|
||||
|
||||
Run `make` then `sudo make install` then reboot.
|
||||
@@ -182,26 +188,8 @@ can be added on request). You will need to install the alternative service from
|
||||
|
||||
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
|
||||
|
||||
## Updating
|
||||
|
||||
If there has been a config file format change your config will be overwritten. This will
|
||||
become less of an issue once the feature set is nailed down. Work is happening to enable
|
||||
parsing of older configs and transferring settings to new.
|
||||
|
||||
# USAGE
|
||||
|
||||
**NOTE! Fan mode toggling requires a newer kernel**. I'm unsure when the patches
|
||||
required for it got merged - I've tested with the 5.6.6 kernel and above only.
|
||||
To see if the fan-mode changed cat either:
|
||||
|
||||
- `cat /sys/devices/platform/asus-nb-wmi/throttle_thermal_policy` or
|
||||
- `cat /sys/devices/platform/asus-nb-wmi/fan_boost_mode`
|
||||
|
||||
The numbers are 0 = Normal/Balanced, 1 = Boost, 2 = Silent.
|
||||
|
||||
Running the program as a daemon manually will require root. Standard (non-daemon)
|
||||
mode expects to be communicating with the daemon mode over dbus.
|
||||
|
||||
Commands are given by:
|
||||
|
||||
```
|
||||
@@ -221,23 +209,6 @@ Some commands may have subcommands:
|
||||
asusctl <command> <subcommand> --help
|
||||
```
|
||||
|
||||
## Daemon mode
|
||||
|
||||
If the daemon service is enabled then on boot the following will be reloaded from save:
|
||||
|
||||
- LED brightness
|
||||
- Last used built-in mode
|
||||
- fan-boost/thermal mode
|
||||
- battery charging limit
|
||||
|
||||
The daemon also saves the settings per mode as the keyboard does not do this
|
||||
itself - this means cycling through modes with the Aura keys will use the
|
||||
settings that were used via CLI.
|
||||
|
||||
Daemon mode creates a config file at `/etc/asusd/asusd.conf` which you can edit a
|
||||
little of. Most parts will be byte arrays, but you can adjust things like
|
||||
`mode_performance`.
|
||||
|
||||
## User NOTIFICATIONS via dbus
|
||||
|
||||
If you have a notifications handler set up, or are using KDE or Gnome then you
|
||||
@@ -247,12 +218,9 @@ can enable the user service to get basic notifications when something changes.
|
||||
systemctl --user enable asus-notify.service
|
||||
systemctl --user start asus-notify.service
|
||||
```
|
||||
|
||||
# OTHER
|
||||
|
||||
## DBUS Input
|
||||
|
||||
See [README_DBUS.md](./README_DBUS.md).
|
||||
|
||||
## AniMe input
|
||||
|
||||
You will want to look at what MeuMeu has done with [https://github.com/Meumeu/ZephyrusBling/](https://github.com/Meumeu/ZephyrusBling/)
|
||||
@@ -278,11 +246,3 @@ omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
|
||||
# License
|
||||
|
||||
Mozilla Public License 2 (MPL-2.0)
|
||||
|
||||
# Credits
|
||||
|
||||
- [flukejones](https://github.com/flukejones/), project maintainer.
|
||||
- [tuxuser](https://github.com/tuxuser/)
|
||||
- [aspann](https://github.com/aspann)
|
||||
- [meumeu](https://github.com/Meumeu)
|
||||
- Anyone missed? Please contact me
|
||||
|
||||
115
README_DBUS.md
@@ -1,115 +0,0 @@
|
||||
# DBUS Guide
|
||||
|
||||
**WARNING: In progress updates**
|
||||
|
||||
Interface name = org.asuslinux.Daemon
|
||||
|
||||
Paths:
|
||||
- `/org/asuslinux/Gfx`
|
||||
+ `SetVendor` (string)
|
||||
+ `NotifyVendor` (recv vendor label string)
|
||||
- `/org/asuslinux/Led`
|
||||
+ `LedMode` (AuraMode as json)
|
||||
+ `LedModes` (array[AuraMode] as json)
|
||||
+ `SetLedMode` (AuraMode -> json)
|
||||
+ `NotifyLed` (recv json data)
|
||||
- `/org/asuslinux/Anime`
|
||||
+ `SetAnime` (byte array data)
|
||||
- `/org/asuslinux/Charge`
|
||||
+ `Limit` (u8)
|
||||
+ `SetLimit` (u8)
|
||||
+ `NotifyCharge` (recv i8)
|
||||
- `/org/asuslinux/Profile`
|
||||
+ `Profile` (recv current profile data as json string)
|
||||
+ `Profiles` (recv profiles data as json string (map))
|
||||
+ `SetProfile` (event -> json)
|
||||
+ `NotifyProfile` (recv current profile name)
|
||||
|
||||
All `Notify*` methods are signals.
|
||||
|
||||
### SetLed
|
||||
|
||||
This method expects a string of JSON as input. The JSON is of format such:
|
||||
|
||||
```
|
||||
{
|
||||
"Static": {
|
||||
"colour": [ 255, 0, 0]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The possible contents of a mode are:
|
||||
|
||||
- `"colour": [u8, u8, u8],`
|
||||
- `"speed": <String>,` <Low, Med, High>
|
||||
- `"direction": <String>,` <Up, Down, Left, Right>
|
||||
|
||||
Modes may or may not be available for a specific laptop (TODO: dbus getter for
|
||||
supported modes). Modes are:
|
||||
|
||||
- `"Static": { "colour": <colour> },`
|
||||
- `"Pulse": { "colour": <colour> },`
|
||||
- `"Comet": { "colour": <colour> },`
|
||||
- `"Flash": { "colour": <colour> },`
|
||||
- `"Strobe": { "speed": <speed> },`
|
||||
- `"Rain": { "speed": <speed> },`
|
||||
- `"Laser": { "colour": <colour>, "speed": <speed> },`
|
||||
- `"Ripple": { "colour": <colour>, "speed": <speed> },`
|
||||
- `"Highlight": { "colour": <colour>, "speed": <speed> },`
|
||||
- `"Rainbow": { "direction": <direction>, "speed": <speed> },`
|
||||
- `"Breathe": { "colour": <colour>, "colour2": <colour>, "speed": <speed> },`
|
||||
- `"Star": { "colour": <colour>, "colour2": <colour>, "speed": <speed> },`
|
||||
- `"MultiStatic": { "colour1": <colour>, "colour2": <colour>, , "colour3": <colour>, "colour4": <colour> },`
|
||||
|
||||
Additionally to the above there is `"RGB": [[u8; 64]; 11]` which is for per-key
|
||||
setting of LED's but this requires some refactoring to make it easily useable over
|
||||
dbus.
|
||||
|
||||
Lastly, there is `"LedBrightness": <u8>` which accepts 0-3 for off, low, med, high.
|
||||
|
||||
### SetFanMode
|
||||
|
||||
Accepts an integer from the following:
|
||||
|
||||
- `0`: Normal
|
||||
- `1`: Boost mode
|
||||
- `2`: Silent mode
|
||||
|
||||
## dbus-send examples:
|
||||
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Profile org.asuslinux.Daemon.NextProfile
|
||||
```
|
||||
|
||||
## dbus-send examples OUTDATED
|
||||
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Static": {"colour": [ 80, 0, 40]}}'
|
||||
```
|
||||
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,0],"speed":"Med"}}'
|
||||
```
|
||||
|
||||
**Note:** setting colour2 to `[0,0,255]` activates random star colour. Colour2 has no effect on the
|
||||
mode otherwise.
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,255],"speed":"Med"}}'
|
||||
```
|
||||
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"LedBrightness":3}'
|
||||
```
|
||||
|
||||
```
|
||||
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetFanMode byte:'2'
|
||||
```
|
||||
|
||||
Monitoring dbus while sending commands via `rog-core` will give you the json structure if you are otherwise unsure, e.g: `dbus-monitor --system |grep -A2 asuslinux`.
|
||||
|
||||
## Getting an introspection .xml
|
||||
|
||||
```
|
||||
dbus-send --system --print-reply --dest=org.asuslinux.Daemon /org/asuslinux/Charge org.freedesktop.DBus.Introspectable.Introspect > xml/asusd-charge.xml
|
||||
```
|
||||
7
TODO.md
@@ -1,7 +0,0 @@
|
||||
# TODO
|
||||
|
||||
- There is lots of code duplication. This should be turned in to macros (dbus stuff etc)
|
||||
- Add a little more information to profile notifications such as freq min/max, fan curves
|
||||
- Finish splitting out controllers to own crates
|
||||
- Finish move to zbus in client when zbus has client signal watch
|
||||
- Consider a rename again because the project is getting a lot less ASUS centric
|
||||
@@ -10,9 +10,10 @@ edition = "2018"
|
||||
# serialisation
|
||||
serde_json = "^1.0"
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_types = { path = "../rog-types" }
|
||||
daemon = { path = "../daemon" }
|
||||
|
||||
[dependencies.notify-rust]
|
||||
version = "^4.0"
|
||||
version = "^4.3"
|
||||
default-features = false
|
||||
features = ["z"]
|
||||
@@ -1,7 +1,8 @@
|
||||
use daemon::config::Profile;
|
||||
use notify_rust::{Hint, Notification, NotificationHandle};
|
||||
use rog_dbus::{DbusProxies, Signals};
|
||||
use rog_types::profile::Profile;
|
||||
use std::error::Error;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -9,9 +10,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!(" daemon version {}", daemon::VERSION);
|
||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||
|
||||
// let mut cfg = Config::read_new()?;
|
||||
// let mut last_profile = String::new();
|
||||
|
||||
let (proxies, conn) = DbusProxies::new()?;
|
||||
let signals = Signals::new(&proxies)?;
|
||||
|
||||
@@ -21,16 +19,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut last_chrg_notif: Option<NotificationHandle> = None;
|
||||
|
||||
let recv = proxies.setup_recv(conn);
|
||||
let mut err_count = 0;
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
recv.next_signal().unwrap();
|
||||
sleep(Duration::from_millis(100));
|
||||
if let Err(err) = recv.next_signal() {
|
||||
if err_count < 3 {
|
||||
err_count += 1;
|
||||
println!("{}", err);
|
||||
}
|
||||
if err_count == 3 {
|
||||
err_count += 1;
|
||||
println!("Max error count reached. Spooling silently.");
|
||||
}
|
||||
sleep(Duration::from_millis(2000));
|
||||
continue;
|
||||
}
|
||||
err_count = 0;
|
||||
|
||||
if let Ok(mut lock) = signals.gfx_vendor.lock() {
|
||||
if let Some(vendor) = lock.take() {
|
||||
if let Some(notif) = last_gfx_notif.take() {
|
||||
notif.close();
|
||||
}
|
||||
let x = do_notif(&format!("Graphics mode changed to {}", vendor))?;
|
||||
let x = do_notif(&format!(
|
||||
"Graphics mode changed to {}",
|
||||
<&str>::from(vendor)
|
||||
))?;
|
||||
last_gfx_notif = Some(x);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +81,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
let x = do_notif(&format!(
|
||||
"Keyboard LED mode changed to {}",
|
||||
<&str>::from(&ledmode)
|
||||
ledmode.mode_name()
|
||||
))?;
|
||||
last_led_notif = Some(x);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "asusctl"
|
||||
version = "3.1.3"
|
||||
version = "3.4.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -9,13 +9,15 @@ edition = "2018"
|
||||
[dependencies]
|
||||
# serialisation
|
||||
serde_json = "^1.0"
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_types = { path = "../rog-types" }
|
||||
daemon = { path = "../daemon" }
|
||||
gumdrop = "^0.8"
|
||||
yansi-term = "^0.1"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
tinybmp = "^0.2.3"
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
glam = "0.14.0"
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
gif = "^0.11.2"
|
||||
26
asusctl/examples/animatrix-diag-png.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use std::{env, error::Error, path::Path, process::exit};
|
||||
|
||||
use rog_anime::{AnimeDataBuffer, AnimeDiagonal};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let args: Vec<String> = env::args().into_iter().collect();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: <filepath> <brightness>");
|
||||
println!("e.g, asusctl/examples/doom_large.png 0.8");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
let matrix =
|
||||
AnimeDiagonal::from_png(Path::new(&args[1]), None, args[2].parse::<f32>().unwrap())?;
|
||||
|
||||
client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(<AnimeDataBuffer>::from(&matrix))
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
32
asusctl/examples/animatrix-diag.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use std::{thread::sleep, time::Duration};
|
||||
|
||||
use rog_anime::{AnimeDataBuffer, AnimeDiagonal};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
// In usable data:
|
||||
// Top row start at 1, ends at 32
|
||||
|
||||
// 74w x 36h diagonal used by the windows app
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
for step in (2..50).rev() {
|
||||
let mut matrix = AnimeDiagonal::new(None);
|
||||
for c in (0..60).into_iter().step_by(step) {
|
||||
for i in matrix.get_mut().iter_mut() {
|
||||
i[c] = 50;
|
||||
}
|
||||
}
|
||||
|
||||
for c in (0..35).into_iter().step_by(step) {
|
||||
for i in matrix.get_mut()[c].iter_mut() {
|
||||
*i = 50;
|
||||
}
|
||||
}
|
||||
|
||||
let m = <AnimeDataBuffer>::from(&matrix);
|
||||
client.proxies().anime().write(m).unwrap();
|
||||
sleep(Duration::from_millis(300));
|
||||
}
|
||||
}
|
||||
42
asusctl/examples/animatrix-gif.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use std::{env, path::Path, thread::sleep};
|
||||
|
||||
use rog_anime::{ActionData, AnimeAction, Sequences};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let args: Vec<String> = env::args().into_iter().collect();
|
||||
if args.len() != 3 {
|
||||
println!("Please supply filepath and brightness");
|
||||
return;
|
||||
}
|
||||
|
||||
let path = Path::new(&args[1]);
|
||||
let brightness = args[2].parse::<f32>().unwrap();
|
||||
let mut seq = Sequences::new();
|
||||
seq.insert(
|
||||
0,
|
||||
&AnimeAction::AsusAnimation {
|
||||
file: path.into(),
|
||||
time: rog_anime::AnimTime::Infinite,
|
||||
brightness,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
for action in seq.iter() {
|
||||
if let ActionData::Animation(frames) = action {
|
||||
for frame in frames.frames() {
|
||||
client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(frame.frame().clone())
|
||||
.unwrap();
|
||||
sleep(frame.delay());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
asusctl/examples/animatrix-grid.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use rog_anime::{AnimeDataBuffer, AnimeGrid};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
// In usable data:
|
||||
// Top row start at 1, ends at 32
|
||||
|
||||
// 74w x 36h diagonal used by the windows app
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let mut matrix = AnimeGrid::new(None);
|
||||
let tmp = matrix.get_mut();
|
||||
|
||||
let mut i = 0;
|
||||
for (y, row) in tmp.iter_mut().enumerate() {
|
||||
if y % 2 == 0 && i + 1 != row.len() - 1 {
|
||||
i += 1;
|
||||
dbg!(i);
|
||||
}
|
||||
row[row.len() - i] = 0x22;
|
||||
if i > 5 {
|
||||
row[row.len() - i + 5] = 0x22;
|
||||
}
|
||||
if i > 10 {
|
||||
row[row.len() - i + 10] = 0x22;
|
||||
}
|
||||
|
||||
if i > 15 {
|
||||
row[row.len() - i + 15] = 0x22;
|
||||
}
|
||||
|
||||
if i > 20 {
|
||||
row[row.len() - i + 20] = 0x22;
|
||||
}
|
||||
|
||||
if i > 25 {
|
||||
row[row.len() - i + 25] = 0x22;
|
||||
}
|
||||
}
|
||||
|
||||
let matrix = <AnimeDataBuffer>::from(matrix);
|
||||
|
||||
client.proxies().anime().write(matrix).unwrap();
|
||||
}
|
||||
129
asusctl/examples/animatrix-outline.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
use rog_anime::AnimeDataBuffer;
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
// In usable data:
|
||||
// Top row start at 1, ends at 32
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let mut matrix = AnimeDataBuffer::new();
|
||||
matrix.get_mut()[1] = 100; // start = 1
|
||||
for n in matrix.get_mut()[2..32].iter_mut() {
|
||||
*n = 250;
|
||||
}
|
||||
matrix.get_mut()[32] = 100; // end
|
||||
matrix.get_mut()[34] = 100; // start x = 0
|
||||
matrix.get_mut()[66] = 100; // end
|
||||
matrix.get_mut()[69] = 100; // start x = 1
|
||||
matrix.get_mut()[101] = 100; // end
|
||||
matrix.get_mut()[102] = 100; // start
|
||||
matrix.get_mut()[134] = 100; // end
|
||||
matrix.get_mut()[137] = 100; // start
|
||||
matrix.get_mut()[169] = 100; // end
|
||||
matrix.get_mut()[170] = 100; // start
|
||||
matrix.get_mut()[202] = 100; // end
|
||||
matrix.get_mut()[204] = 100; // start
|
||||
matrix.get_mut()[236] = 100; // end
|
||||
matrix.get_mut()[237] = 100; // start
|
||||
matrix.get_mut()[268] = 100; // end
|
||||
matrix.get_mut()[270] = 100; // start
|
||||
matrix.get_mut()[301] = 100; // end
|
||||
matrix.get_mut()[302] = 100; // start
|
||||
matrix.get_mut()[332] = 100; // end
|
||||
matrix.get_mut()[334] = 100; // start
|
||||
matrix.get_mut()[364] = 100; // end
|
||||
matrix.get_mut()[365] = 100; // start
|
||||
matrix.get_mut()[394] = 100; // end
|
||||
matrix.get_mut()[396] = 100; // start
|
||||
matrix.get_mut()[425] = 100; // end
|
||||
matrix.get_mut()[426] = 100; // start
|
||||
matrix.get_mut()[454] = 100; // end
|
||||
matrix.get_mut()[456] = 100; // start
|
||||
matrix.get_mut()[484] = 100; // end
|
||||
matrix.get_mut()[485] = 100; // start
|
||||
matrix.get_mut()[512] = 100; // end
|
||||
matrix.get_mut()[514] = 100; // start
|
||||
matrix.get_mut()[541] = 100; // end
|
||||
matrix.get_mut()[542] = 100; // start
|
||||
matrix.get_mut()[568] = 100; // end
|
||||
matrix.get_mut()[570] = 100; // start
|
||||
matrix.get_mut()[596] = 100; // end
|
||||
matrix.get_mut()[597] = 100; // start
|
||||
matrix.get_mut()[622] = 100; // end
|
||||
matrix.get_mut()[624] = 100; // start
|
||||
matrix.get_mut()[649] = 100; // end
|
||||
matrix.get_mut()[650] = 100; // start
|
||||
matrix.get_mut()[674] = 100; // end
|
||||
matrix.get_mut()[676] = 100; // start
|
||||
matrix.get_mut()[700] = 100; // end
|
||||
matrix.get_mut()[701] = 100; // start
|
||||
matrix.get_mut()[724] = 100; // end
|
||||
matrix.get_mut()[726] = 100; // start
|
||||
matrix.get_mut()[749] = 100; // end
|
||||
matrix.get_mut()[750] = 100; // start
|
||||
matrix.get_mut()[772] = 100; // end
|
||||
matrix.get_mut()[774] = 100; // start
|
||||
matrix.get_mut()[796] = 100; // end
|
||||
matrix.get_mut()[797] = 100; // start
|
||||
matrix.get_mut()[818] = 100; // end
|
||||
matrix.get_mut()[820] = 100; // start
|
||||
matrix.get_mut()[841] = 100; // end
|
||||
matrix.get_mut()[842] = 100; // start
|
||||
matrix.get_mut()[862] = 100; // end
|
||||
matrix.get_mut()[864] = 100; // start
|
||||
matrix.get_mut()[884] = 100; // end
|
||||
matrix.get_mut()[885] = 100; // start
|
||||
matrix.get_mut()[904] = 100; // end
|
||||
matrix.get_mut()[906] = 100; // start
|
||||
matrix.get_mut()[925] = 100; // end
|
||||
matrix.get_mut()[926] = 100; // start
|
||||
matrix.get_mut()[944] = 100; // end
|
||||
matrix.get_mut()[946] = 100; // start
|
||||
matrix.get_mut()[964] = 100; // end
|
||||
matrix.get_mut()[965] = 100; // start
|
||||
matrix.get_mut()[982] = 100; // end
|
||||
matrix.get_mut()[984] = 100; // start
|
||||
matrix.get_mut()[1001] = 100; // end
|
||||
matrix.get_mut()[1002] = 100; // start
|
||||
matrix.get_mut()[1018] = 100; // end
|
||||
matrix.get_mut()[1020] = 100; // start
|
||||
matrix.get_mut()[1036] = 100; // end
|
||||
matrix.get_mut()[1037] = 100; // start
|
||||
matrix.get_mut()[1052] = 100; // end
|
||||
matrix.get_mut()[1054] = 100; // start
|
||||
matrix.get_mut()[1069] = 100; // end
|
||||
matrix.get_mut()[1070] = 100; // start
|
||||
matrix.get_mut()[1084] = 100; // end
|
||||
matrix.get_mut()[1086] = 100; // start
|
||||
matrix.get_mut()[1100] = 100; // end
|
||||
matrix.get_mut()[1101] = 100; // start
|
||||
matrix.get_mut()[1114] = 100; // end
|
||||
matrix.get_mut()[1116] = 100; // start
|
||||
matrix.get_mut()[1129] = 100; // end
|
||||
matrix.get_mut()[1130] = 100; // start
|
||||
matrix.get_mut()[1142] = 100; // end
|
||||
matrix.get_mut()[1144] = 100; // start
|
||||
matrix.get_mut()[1156] = 100; // end
|
||||
matrix.get_mut()[1157] = 100; // start
|
||||
matrix.get_mut()[1168] = 100; // end
|
||||
matrix.get_mut()[1170] = 100; // start
|
||||
matrix.get_mut()[1181] = 100; // end
|
||||
matrix.get_mut()[1182] = 100; // start
|
||||
matrix.get_mut()[1192] = 100; // end
|
||||
matrix.get_mut()[1194] = 100; // start
|
||||
matrix.get_mut()[1204] = 100; // end
|
||||
matrix.get_mut()[1205] = 100; // start
|
||||
matrix.get_mut()[1214] = 100; // end
|
||||
matrix.get_mut()[1216] = 100; // start
|
||||
matrix.get_mut()[1225] = 100; // end
|
||||
matrix.get_mut()[1226] = 100; // start
|
||||
matrix.get_mut()[1234] = 100; // end
|
||||
matrix.get_mut()[1236] = 100; // start
|
||||
for n in matrix.get_mut()[1237..1244].iter_mut() {
|
||||
*n = 250;
|
||||
}
|
||||
matrix.get_mut()[1244] = 100; // end
|
||||
println!("{:?}", &matrix);
|
||||
|
||||
client.proxies().anime().write(matrix).unwrap();
|
||||
}
|
||||
36
asusctl/examples/animatrix-png.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use std::{env, error::Error, path::Path, process::exit};
|
||||
|
||||
use rog_anime::{
|
||||
AnimeDataBuffer, {AnimeImage, Vec2},
|
||||
};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let args: Vec<String> = env::args().into_iter().collect();
|
||||
if args.len() != 7 {
|
||||
println!("Usage: <filepath> <scale> <angle> <x pos> <y pos> <brightness>");
|
||||
println!("e.g, asusctl/examples/doom_large.png 0.9 0.4 0.0 0.0 0.8");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
let matrix = AnimeImage::from_png(
|
||||
Path::new(&args[1]),
|
||||
args[2].parse::<f32>().unwrap(),
|
||||
args[3].parse::<f32>().unwrap(),
|
||||
Vec2::new(
|
||||
args[4].parse::<f32>().unwrap(),
|
||||
args[5].parse::<f32>().unwrap(),
|
||||
),
|
||||
args[6].parse::<f32>().unwrap(),
|
||||
)?;
|
||||
|
||||
client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(<AnimeDataBuffer>::from(&matrix))
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
45
asusctl/examples/animatrix-spinning.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use std::{
|
||||
env, error::Error, f32::consts::PI, path::Path, process::exit, thread::sleep, time::Duration,
|
||||
};
|
||||
|
||||
use rog_anime::{
|
||||
AnimeDataBuffer, {AnimeImage, Vec2},
|
||||
};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let args: Vec<String> = env::args().into_iter().collect();
|
||||
if args.len() != 7 {
|
||||
println!("Usage: <filepath> <scale> <angle> <x pos> <y pos> <brightness>");
|
||||
println!("e.g, asusctl/examples/doom_large.png 0.9 0.4 0.0 0.0 0.8");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
let mut matrix = AnimeImage::from_png(
|
||||
Path::new(&args[1]),
|
||||
args[2].parse::<f32>().unwrap(),
|
||||
args[3].parse::<f32>().unwrap(),
|
||||
Vec2::new(
|
||||
args[4].parse::<f32>().unwrap(),
|
||||
args[5].parse::<f32>().unwrap(),
|
||||
),
|
||||
args[6].parse::<f32>().unwrap(),
|
||||
)?;
|
||||
|
||||
loop {
|
||||
matrix.angle += 0.05;
|
||||
if matrix.angle > PI * 2.0 {
|
||||
matrix.angle = 0.0
|
||||
}
|
||||
matrix.update();
|
||||
|
||||
client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(<AnimeDataBuffer>::from(&matrix))
|
||||
.unwrap();
|
||||
sleep(Duration::from_micros(500));
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::anime_matrix::{AniMeImageBuffer, AniMePacketType, HEIGHT, WIDTH};
|
||||
use tinybmp::{Bmp, Pixel};
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let bmp =
|
||||
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
|
||||
let pixels: Vec<Pixel> = bmp.into_iter().collect();
|
||||
//assert_eq!(pixels.len(), 56 * 56);
|
||||
|
||||
// Try an outline, top and right
|
||||
let mut matrix = AniMeImageBuffer::new();
|
||||
|
||||
// Aligned left
|
||||
for (i, px) in pixels.iter().enumerate() {
|
||||
if (px.x as usize / 2) < WIDTH && (px.y as usize) < HEIGHT && px.x % 2 == 0 {
|
||||
let mut c = px.color as u32;
|
||||
matrix.get_mut()[px.y as usize][px.x as usize / 2] = c as u8;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw an alignment border up
|
||||
// {
|
||||
// let tmp = matrix.get_mut();
|
||||
// for x in tmp[0].iter_mut() {
|
||||
// *x = 0xff;
|
||||
// }
|
||||
// for row in tmp.iter_mut() {
|
||||
// row[row.len() - 1] = 0xff;
|
||||
// }
|
||||
// }
|
||||
|
||||
matrix.debug_print();
|
||||
|
||||
let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
|
||||
// println!("{:?}", matrix[0].to_vec());
|
||||
// println!("{:?}", matrix[1].to_vec());
|
||||
|
||||
//client.proxies().anime().set_brightness(&mut matrix).unwrap();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
use std::collections::LinkedList;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
|
||||
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (dbus, _) = AuraDbusClient::new()?;
|
||||
|
||||
BIN
asusctl/examples/controller.gif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
asusctl/examples/doom.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
asusctl/examples/ferris.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
@@ -1,5 +1,5 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (dbus, _) = AuraDbusClient::new()?;
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
BIN
asusctl/examples/nudoom.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
@@ -1,5 +1,5 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::fancy::{Key, KeyColourArray};
|
||||
use rog_types::aura_perkey::{Key, KeyColourArray};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (dbus, _) = AuraDbusClient::new()?;
|
||||
@@ -10,7 +10,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
loop {
|
||||
let count = 49;
|
||||
for _ in 0..count {
|
||||
*key_colours.key(Key::ROG).unwrap().0 += 5;
|
||||
*key_colours.key(Key::Rog).unwrap().0 += 5;
|
||||
*key_colours.key(Key::L).unwrap().0 += 5;
|
||||
*key_colours.key(Key::I).unwrap().0 += 5;
|
||||
*key_colours.key(Key::N).unwrap().0 += 5;
|
||||
@@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||
}
|
||||
for _ in 0..count {
|
||||
*key_colours.key(Key::ROG).unwrap().0 -= 5;
|
||||
*key_colours.key(Key::Rog).unwrap().0 -= 5;
|
||||
*key_colours.key(Key::L).unwrap().0 -= 5;
|
||||
*key_colours.key(Key::I).unwrap().0 -= 5;
|
||||
*key_colours.key(Key::N).unwrap().0 -= 5;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
|
||||
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (dbus, _) = AuraDbusClient::new()?;
|
||||
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
BIN
asusctl/examples/rust.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
92
asusctl/src/anime_cli.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
use gumdrop::Options;
|
||||
use rog_types::error::AuraError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum AnimeStatusValue {
|
||||
On,
|
||||
Off,
|
||||
}
|
||||
impl FromStr for AnimeStatusValue {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"on" => Ok(AnimeStatusValue::On),
|
||||
"off" => Ok(AnimeStatusValue::Off),
|
||||
_ => {
|
||||
print!("Invalid argument, must be one of: on, off");
|
||||
Err(AuraError::ParseAnime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<AnimeStatusValue> for bool {
|
||||
fn from(value: AnimeStatusValue) -> Self {
|
||||
match value {
|
||||
AnimeStatusValue::On => true,
|
||||
AnimeStatusValue::Off => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct AnimeLeds {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(
|
||||
no_long,
|
||||
required,
|
||||
short = "b",
|
||||
meta = "",
|
||||
help = "set all leds brightness value"
|
||||
)]
|
||||
led_brightness: u8,
|
||||
}
|
||||
impl AnimeLeds {
|
||||
pub fn led_brightness(&self) -> u8 {
|
||||
self.led_brightness
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct AnimeCommand {
|
||||
#[options(help = "print help message")]
|
||||
pub help: bool,
|
||||
#[options(
|
||||
meta = "",
|
||||
help = "turn on/off the panel (accept/reject write requests)"
|
||||
)]
|
||||
pub turn: Option<AnimeStatusValue>,
|
||||
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")]
|
||||
pub boot: Option<AnimeStatusValue>,
|
||||
#[options(command)]
|
||||
pub command: Option<AnimeActions>,
|
||||
}
|
||||
|
||||
#[derive(Options)]
|
||||
pub enum AnimeActions {
|
||||
#[options(help = "change all leds brightness")]
|
||||
Leds(AnimeLeds),
|
||||
#[options(help = "display an 8bit greyscale png")]
|
||||
Image(AnimeImage),
|
||||
}
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct AnimeImage {
|
||||
#[options(help = "print help message")]
|
||||
pub help: bool,
|
||||
#[options(meta = "", help = "full path to the png to display")]
|
||||
pub path: String,
|
||||
#[options(meta = "", default = "1.0", help = "scale 1.0 == normal")]
|
||||
pub scale: f32,
|
||||
#[options(meta = "", default = "0.0", help = "x position (float)")]
|
||||
pub x_pos: f32,
|
||||
#[options(meta = "", default = "0.0", help = "y position (float)")]
|
||||
pub y_pos: f32,
|
||||
#[options(meta = "", default = "0.0", help = "the angle in radians")]
|
||||
pub angle: f32,
|
||||
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
|
||||
pub bright: f32,
|
||||
}
|
||||
330
asusctl/src/aura_cli.rs
Normal file
@@ -0,0 +1,330 @@
|
||||
use gumdrop::Options;
|
||||
use rog_types::{
|
||||
aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
|
||||
error::AuraError,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct LedBrightness {
|
||||
level: Option<u32>,
|
||||
}
|
||||
impl LedBrightness {
|
||||
pub fn new(level: Option<u32>) -> Self {
|
||||
LedBrightness { level }
|
||||
}
|
||||
|
||||
pub fn level(&self) -> Option<u32> {
|
||||
self.level
|
||||
}
|
||||
}
|
||||
impl FromStr for LedBrightness {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"off" => Ok(LedBrightness { level: Some(0x00) }),
|
||||
"low" => Ok(LedBrightness { level: Some(0x01) }),
|
||||
"med" => Ok(LedBrightness { level: Some(0x02) }),
|
||||
"high" => Ok(LedBrightness { level: Some(0x03) }),
|
||||
_ => {
|
||||
print!("Invalid argument, must be one of: off, low, med, high");
|
||||
Err(AuraError::ParseBrightness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToString for LedBrightness {
|
||||
fn to_string(&self) -> String {
|
||||
let s = match self.level {
|
||||
Some(0x00) => "low",
|
||||
Some(0x01) => "med",
|
||||
Some(0x02) => "high",
|
||||
_ => "unknown",
|
||||
};
|
||||
s.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Options, Default)]
|
||||
pub struct SingleSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
|
||||
pub speed: Speed,
|
||||
}
|
||||
#[derive(Debug, Clone, Options, Default)]
|
||||
pub struct SingleSpeedDirection {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(no_long, meta = "", help = "set the direction: up, down, left, right")]
|
||||
pub direction: Direction,
|
||||
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Options)]
|
||||
pub struct SingleColour {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour: Colour,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Options)]
|
||||
pub struct SingleColourSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour: Colour,
|
||||
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Options, Default)]
|
||||
pub struct TwoColourSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(no_long, meta = "", help = "set the first RGB value e.g, ff00ff")]
|
||||
pub colour: Colour,
|
||||
#[options(no_long, meta = "", help = "set the second RGB value e.g, ff00ff")]
|
||||
pub colour2: Colour,
|
||||
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Options)]
|
||||
pub struct MultiColour {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour1: Colour,
|
||||
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour2: Colour,
|
||||
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour3: Colour,
|
||||
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour4: Colour,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Options)]
|
||||
pub struct MultiColourSpeed {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour1: Colour,
|
||||
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour2: Colour,
|
||||
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour3: Colour,
|
||||
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||
pub colour4: Colour,
|
||||
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||
pub speed: Speed,
|
||||
}
|
||||
|
||||
/// Byte value for setting the built-in mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Options)]
|
||||
pub enum SetAuraBuiltin {
|
||||
#[options(help = "set a single static colour")]
|
||||
Static(SingleColour),
|
||||
#[options(help = "pulse between one or two colours")]
|
||||
Breathe(TwoColourSpeed),
|
||||
#[options(help = "strobe through all colours")]
|
||||
Strobe(SingleSpeed),
|
||||
#[options(help = "rainbow cycling in one of four directions")]
|
||||
Rainbow(SingleSpeedDirection),
|
||||
#[options(help = "rain pattern mimicking raindrops")]
|
||||
Star(TwoColourSpeed),
|
||||
#[options(help = "rain pattern of three preset colours")]
|
||||
Rain(SingleSpeed),
|
||||
#[options(help = "pressed keys are highlighted to fade")]
|
||||
Highlight(SingleColourSpeed),
|
||||
#[options(help = "pressed keys generate horizontal laser")]
|
||||
Laser(SingleColourSpeed),
|
||||
#[options(help = "pressed keys ripple outwards like a splash")]
|
||||
Ripple(SingleColourSpeed),
|
||||
#[options(help = "set a rapid pulse")]
|
||||
Pulse(SingleColour),
|
||||
#[options(help = "set a vertical line zooming from left")]
|
||||
Comet(SingleColour),
|
||||
#[options(help = "set a wide vertical line zooming from left")]
|
||||
Flash(SingleColour),
|
||||
#[options(help = "4-zone multi-colour")]
|
||||
MultiStatic(MultiColour),
|
||||
#[options(help = "4-zone multi-colour breathing")]
|
||||
MultiBreathe(MultiColourSpeed),
|
||||
}
|
||||
|
||||
impl Default for SetAuraBuiltin {
|
||||
fn default() -> Self {
|
||||
SetAuraBuiltin::Static(SingleColour::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SingleColour> for AuraEffect {
|
||||
fn from(aura: &SingleColour) -> Self {
|
||||
Self {
|
||||
colour1: aura.colour,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SingleSpeed> for AuraEffect {
|
||||
fn from(aura: &SingleSpeed) -> Self {
|
||||
Self {
|
||||
speed: aura.speed,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SingleColourSpeed> for AuraEffect {
|
||||
fn from(aura: &SingleColourSpeed) -> Self {
|
||||
Self {
|
||||
colour1: aura.colour,
|
||||
speed: aura.speed,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&TwoColourSpeed> for AuraEffect {
|
||||
fn from(aura: &TwoColourSpeed) -> Self {
|
||||
Self {
|
||||
colour1: aura.colour,
|
||||
colour2: aura.colour2,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SingleSpeedDirection> for AuraEffect {
|
||||
fn from(aura: &SingleSpeedDirection) -> Self {
|
||||
Self {
|
||||
speed: aura.speed,
|
||||
direction: aura.direction,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SetAuraBuiltin> for AuraEffect {
|
||||
fn from(aura: &SetAuraBuiltin) -> Self {
|
||||
match aura {
|
||||
SetAuraBuiltin::Static(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Static;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Breathe(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Breathe;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Strobe(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Strobe;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Rainbow(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Rainbow;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Star(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Star;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Rain(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Rain;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Highlight(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Highlight;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Laser(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Laser;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Ripple(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Ripple;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Pulse(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Pulse;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Comet(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Comet;
|
||||
data
|
||||
}
|
||||
SetAuraBuiltin::Flash(x) => {
|
||||
let mut data: AuraEffect = x.into();
|
||||
data.mode = AuraModeNum::Flash;
|
||||
data
|
||||
}
|
||||
_ => AuraEffect::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SetAuraBuiltin> for Vec<AuraEffect> {
|
||||
fn from(aura: &SetAuraBuiltin) -> Vec<AuraEffect> {
|
||||
let mut zones = vec![AuraEffect::default(); 4];
|
||||
match aura {
|
||||
SetAuraBuiltin::MultiStatic(data) => {
|
||||
zones[0].mode = AuraModeNum::Static;
|
||||
zones[0].zone = AuraZone::One;
|
||||
zones[0].colour1 = data.colour1;
|
||||
|
||||
zones[1].mode = AuraModeNum::Static;
|
||||
zones[1].zone = AuraZone::Two;
|
||||
zones[1].colour1 = data.colour2;
|
||||
|
||||
zones[2].mode = AuraModeNum::Static;
|
||||
zones[2].zone = AuraZone::Three;
|
||||
zones[2].colour1 = data.colour3;
|
||||
|
||||
zones[3].mode = AuraModeNum::Static;
|
||||
zones[3].zone = AuraZone::Four;
|
||||
zones[3].colour1 = data.colour4;
|
||||
}
|
||||
SetAuraBuiltin::MultiBreathe(data) => {
|
||||
zones[0].mode = AuraModeNum::Breathe;
|
||||
zones[0].zone = AuraZone::One;
|
||||
zones[0].colour1 = data.colour1;
|
||||
zones[0].speed = data.speed;
|
||||
|
||||
zones[1].mode = AuraModeNum::Breathe;
|
||||
zones[1].zone = AuraZone::Two;
|
||||
zones[1].colour1 = data.colour2;
|
||||
zones[1].speed = data.speed;
|
||||
|
||||
zones[2].mode = AuraModeNum::Breathe;
|
||||
zones[2].zone = AuraZone::Three;
|
||||
zones[2].colour1 = data.colour3;
|
||||
zones[2].speed = data.speed;
|
||||
|
||||
zones[3].mode = AuraModeNum::Breathe;
|
||||
zones[3].zone = AuraZone::Four;
|
||||
zones[3].colour1 = data.colour4;
|
||||
zones[3].speed = data.speed;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
zones
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,26 @@
|
||||
use daemon::{
|
||||
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
|
||||
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
|
||||
};
|
||||
mod anime_cli;
|
||||
mod aura_cli;
|
||||
|
||||
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
|
||||
use anime_cli::{AnimeActions, AnimeCommand};
|
||||
use gumdrop::{Opt, Options};
|
||||
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::{
|
||||
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
|
||||
aura_modes::AuraModes,
|
||||
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin},
|
||||
aura_modes::{self, AuraEffect, AuraModeNum},
|
||||
gfx_vendors::GfxVendors,
|
||||
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
||||
supported::{
|
||||
FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
|
||||
SupportedFunctions,
|
||||
},
|
||||
};
|
||||
use std::env::args;
|
||||
use std::{env::args, path::Path};
|
||||
use yansi_term::Colour::Green;
|
||||
use yansi_term::Colour::Red;
|
||||
|
||||
#[derive(Default, Options)]
|
||||
struct CLIStart {
|
||||
struct CliStart {
|
||||
#[options(help_flag, help = "print help message")]
|
||||
help: bool,
|
||||
#[options(help = "show program version number")]
|
||||
@@ -45,7 +49,7 @@ enum CliCommand {
|
||||
#[options(help = "Set the graphics mode")]
|
||||
Graphics(GraphicsCommand),
|
||||
#[options(name = "anime", help = "Manage AniMe Matrix")]
|
||||
AniMe(AniMeCommand),
|
||||
Anime(AnimeCommand),
|
||||
#[options(help = "Change bios settings")]
|
||||
Bios(BiosCommand),
|
||||
}
|
||||
@@ -79,21 +83,6 @@ struct GraphicsCommand {
|
||||
force: bool,
|
||||
}
|
||||
|
||||
#[derive(Options)]
|
||||
struct AniMeCommand {
|
||||
#[options(help = "print help message")]
|
||||
help: bool,
|
||||
#[options(
|
||||
meta = "",
|
||||
help = "turn on/off the panel (accept/reject write requests)"
|
||||
)]
|
||||
turn: Option<AniMeStatusValue>,
|
||||
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")]
|
||||
boot: Option<AniMeStatusValue>,
|
||||
#[options(command)]
|
||||
command: Option<AniMeActions>,
|
||||
}
|
||||
|
||||
#[derive(Options, Debug)]
|
||||
struct BiosCommand {
|
||||
#[options(help = "print help message")]
|
||||
@@ -115,14 +104,14 @@ struct BiosCommand {
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<String> = args().skip(1).collect();
|
||||
|
||||
let parsed: CLIStart;
|
||||
let parsed: CliStart;
|
||||
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
|
||||
match CLIStart::parse_args_default(&args) {
|
||||
match CliStart::parse_args_default(&args) {
|
||||
Ok(p) => {
|
||||
parsed = p;
|
||||
}
|
||||
Err(err) if err.to_string() == missing_argument_k.to_string() => {
|
||||
parsed = CLIStart {
|
||||
parsed = CliStart {
|
||||
kbd_bright: Some(LedBrightness::new(None)),
|
||||
..Default::default()
|
||||
};
|
||||
@@ -140,6 +129,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
if parsed.help {
|
||||
print_supported_help(&supported, &parsed);
|
||||
println!("\nSee https://asus-linux.org/faq/ for additional help");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -155,7 +145,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?,
|
||||
Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?,
|
||||
Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?,
|
||||
Some(CliCommand::AniMe(cmd)) => {
|
||||
Some(CliCommand::Anime(cmd)) => {
|
||||
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help {
|
||||
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||
if let Some(lst) = cmd.self_command_list() {
|
||||
@@ -170,10 +160,33 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
if let Some(action) = cmd.command {
|
||||
match action {
|
||||
AniMeActions::Leds(anime_leds) => {
|
||||
let mut data = AniMeDataBuffer::new();
|
||||
data.set([anime_leds.led_brightness(); FULL_PANE_LEN]);
|
||||
dbus.proxies().anime().write_direct(data)?;
|
||||
AnimeActions::Leds(anime_leds) => {
|
||||
let data = AnimeDataBuffer::from_vec(
|
||||
[anime_leds.led_brightness(); ANIME_DATA_LEN].to_vec(),
|
||||
);
|
||||
dbus.proxies().anime().write(data)?;
|
||||
}
|
||||
AnimeActions::Image(image) => {
|
||||
if image.help_requested() {
|
||||
println!("Missing arg or command\n\n{}", image.self_usage());
|
||||
if let Some(lst) = image.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let matrix = AnimeImage::from_png(
|
||||
Path::new(&image.path),
|
||||
image.scale,
|
||||
image.angle,
|
||||
Vec2::new(image.x_pos, image.y_pos),
|
||||
image.bright,
|
||||
)?;
|
||||
|
||||
dbus.proxies()
|
||||
.anime()
|
||||
.write(<AnimeDataBuffer>::from(&matrix))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,9 +199,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
&& parsed.chg_limit.is_none())
|
||||
|| parsed.help
|
||||
{
|
||||
println!("{}", CLIStart::usage());
|
||||
println!("{}", CliStart::usage());
|
||||
println!();
|
||||
println!("{}", CLIStart::command_list().unwrap());
|
||||
println!("{}", CliStart::command_list().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +212,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let level = dbus.proxies().led().get_led_brightness()?;
|
||||
println!("Current keyboard led brightness: {}", level.to_string());
|
||||
}
|
||||
Some(level) => dbus.proxies().led().set_brightness(level)?,
|
||||
Some(level) => dbus
|
||||
.proxies()
|
||||
.led()
|
||||
.set_led_brightness(<aura_modes::LedBrightness>::from(level))?,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +233,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) {
|
||||
fn print_supported_help(supported: &SupportedFunctions, parsed: &CliStart) {
|
||||
// As help option don't work with `parse_args_default`
|
||||
// we will call `parse_args_default_or_exit` instead
|
||||
let usage: Vec<String> = parsed.self_usage().lines().map(|s| s.to_string()).collect();
|
||||
@@ -283,26 +299,32 @@ fn do_gfx(
|
||||
std::process::exit(-1);
|
||||
}
|
||||
|
||||
println!(
|
||||
"Your display-manager will restart in requested mode when all users are logged out"
|
||||
);
|
||||
println!("If anything fails check `journalctl -b -u asusd`");
|
||||
println!("If anything fails check `journalctl -b -u asusd`\n");
|
||||
|
||||
dbus.proxies().gfx().gfx_write_mode(mode.into())?;
|
||||
dbus.proxies().gfx().gfx_write_mode(&mode).map_err(|err|{
|
||||
println!("Graphics mode change error. You may be in an invalid state.");
|
||||
println!("Check mode with `asusctl graphics -g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n");
|
||||
err
|
||||
})?;
|
||||
let res = dbus.gfx_wait_changed()?;
|
||||
println!("{}", res);
|
||||
println!(
|
||||
"Graphics mode changed to {}. User action required is: {}",
|
||||
<&str>::from(mode),
|
||||
<&str>::from(&res)
|
||||
);
|
||||
std::process::exit(0)
|
||||
}
|
||||
if command.get {
|
||||
let res = dbus.proxies().gfx().gfx_get_mode()?;
|
||||
println!("Current graphics mode: {}", res);
|
||||
println!("Current graphics mode: {}", <&str>::from(res));
|
||||
}
|
||||
if command.pow {
|
||||
let res = dbus.proxies().gfx().gfx_get_pwr()?;
|
||||
if res.contains("active") {
|
||||
println!("Current power status: {}", Red.paint(&res));
|
||||
} else {
|
||||
println!("Current power status: {}", Green.paint(&res));
|
||||
match res {
|
||||
rog_types::gfx_vendors::GfxPower::Active => {
|
||||
println!("Current power status: {}", Red.paint(<&str>::from(&res)))
|
||||
}
|
||||
_ => println!("Current power status: {}", Green.paint(<&str>::from(&res))),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -325,9 +347,12 @@ fn handle_led_mode(
|
||||
.lines()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
for (_, command) in commands.iter().enumerate().filter(|(mode_num, _)| {
|
||||
for command in commands.iter().filter(|mode| {
|
||||
if let Some(modes) = supported.stock_led_modes.as_ref() {
|
||||
return modes.contains(&(*mode_num as u8));
|
||||
return modes.contains(&<AuraModeNum>::from(mode.as_str()));
|
||||
}
|
||||
if supported.multizone_led_mode {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}) {
|
||||
@@ -351,9 +376,18 @@ fn handle_led_mode(
|
||||
println!("{}", mode.self_usage());
|
||||
return Ok(());
|
||||
}
|
||||
dbus.proxies()
|
||||
.led()
|
||||
.set_led_mode(&<AuraModes>::from(mode))?;
|
||||
match mode {
|
||||
SetAuraBuiltin::MultiStatic(_) | SetAuraBuiltin::MultiBreathe(_) => {
|
||||
let zones = <Vec<AuraEffect>>::from(mode);
|
||||
for eff in zones {
|
||||
dbus.proxies().led().set_led_mode(&eff)?
|
||||
}
|
||||
}
|
||||
_ => dbus
|
||||
.proxies()
|
||||
.led()
|
||||
.set_led_mode(&<AuraEffect>::from(mode))?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -365,6 +399,11 @@ fn handle_profile(
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if !cmd.next
|
||||
&& !cmd.create
|
||||
&& !cmd.list
|
||||
&& !cmd.active_name
|
||||
&& !cmd.active_data
|
||||
&& !cmd.profiles_data
|
||||
&& cmd.remove.is_none()
|
||||
&& cmd.curve.is_none()
|
||||
&& cmd.max_percentage.is_none()
|
||||
&& cmd.min_percentage.is_none()
|
||||
@@ -391,9 +430,37 @@ fn handle_profile(
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if cmd.next {
|
||||
dbus.proxies().profile().next_fan()?;
|
||||
} else {
|
||||
}
|
||||
if let Some(profile) = &cmd.remove {
|
||||
dbus.proxies().profile().remove(profile)?
|
||||
}
|
||||
if cmd.list {
|
||||
let profile_names = dbus.proxies().profile().profile_names()?;
|
||||
println!("Available profiles are {:?}", profile_names);
|
||||
}
|
||||
if cmd.active_name {
|
||||
println!(
|
||||
"Active profile: {:?}",
|
||||
dbus.proxies().profile().active_profile_name()?
|
||||
);
|
||||
}
|
||||
if cmd.active_data {
|
||||
println!("Active profile:");
|
||||
for s in dbus.proxies().profile().active_profile_data()?.lines() {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
if cmd.profiles_data {
|
||||
println!("Profiles:");
|
||||
for s in dbus.proxies().profile().all_profile_data()?.lines() {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.profile.is_some() {
|
||||
dbus.proxies()
|
||||
.profile()
|
||||
.write_command(&ProfileEvent::Cli(cmd.clone()))?
|
||||
|
||||
30
daemon-user/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "daemon-user"
|
||||
version = "1.0.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
description = "Usermode daemon for user settings, anime, per-key lighting"
|
||||
|
||||
[lib]
|
||||
name = "rog_user"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "asusd-user"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[dependencies]
|
||||
# serialisation
|
||||
serde = "^1.0"
|
||||
serde_json = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rog_types = { path = "../rog-types" }
|
||||
|
||||
dirs = "3.0.1"
|
||||
|
||||
zbus = "^1.9.1"
|
||||
zvariant = "^2.6"
|
||||
zvariant_derive = "^2.6"
|
||||
14
daemon-user/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# daemon-user
|
||||
|
||||
This crate is for the binary of `asusd-user` and its helper lib.
|
||||
|
||||
The purpose of `asusd-user` is to run in userland and provide the user + third-party apps an interface for such things as creating AniMe sequences (and more in future, see todo list).
|
||||
|
||||
`asusd-user` should try to be as simple as possible while allowing a decent degree of control.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] CLI for basic settings/interaction
|
||||
- [ ] RGB keyboard per-key programs
|
||||
- [ ] User profiles (fan, cpu etc). These would be replacing the system-daemon profiles only when the user is active, otherwise system-daemon defaults to system settings.
|
||||
- [ ] Audio EQ visualiser - for use with anime + keyboard lighting
|
||||
342
daemon-user/src/ctrl_anime.rs
Normal file
@@ -0,0 +1,342 @@
|
||||
use rog_anime::{ActionData, AnimTime, AnimeAction, Sequences, Vec2};
|
||||
use rog_dbus::AuraDbusClient;
|
||||
//use crate::dbus::DbusEvents;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
use std::{sync::Arc, thread::sleep, time::Instant};
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
use zvariant_derive::Type;
|
||||
|
||||
use crate::{error::Error, user_config::UserConfig};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
|
||||
pub enum TimeType {
|
||||
Timer,
|
||||
Count,
|
||||
Infinite,
|
||||
}
|
||||
|
||||
/// The inner object exists to allow the zbus proxy to share it with a runner thread
|
||||
/// and a zbus server behind `Arc<Mutex<T>>`
|
||||
pub struct CtrlAnimeInner<'a> {
|
||||
sequences: Sequences,
|
||||
client: AuraDbusClient<'a>,
|
||||
do_early_return: &'a AtomicBool,
|
||||
}
|
||||
|
||||
impl<'a> CtrlAnimeInner<'static> {
|
||||
pub fn new(
|
||||
sequences: Sequences,
|
||||
client: AuraDbusClient<'static>,
|
||||
do_early_return: &'static AtomicBool,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
sequences,
|
||||
client,
|
||||
do_early_return,
|
||||
})
|
||||
}
|
||||
/// To be called on each main loop iteration to pump out commands to the anime
|
||||
pub fn run(&self) -> Result<(), Error> {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for action in self.sequences.iter() {
|
||||
match action {
|
||||
ActionData::Animation(frames) => {
|
||||
let mut count = 0;
|
||||
let start = Instant::now();
|
||||
'animation: loop {
|
||||
for frame in frames.frames() {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
self.client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(frame.frame().clone())
|
||||
.unwrap();
|
||||
if let AnimTime::Time(time) = frames.duration() {
|
||||
if Instant::now().duration_since(start) > time {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
sleep(frame.delay());
|
||||
}
|
||||
if let AnimTime::Cycles(times) = frames.duration() {
|
||||
count += 1;
|
||||
if count >= times {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActionData::Image(image) => {
|
||||
self.client
|
||||
.proxies()
|
||||
.anime()
|
||||
.write(image.as_ref().clone())
|
||||
.unwrap();
|
||||
}
|
||||
ActionData::Pause(duration) => {
|
||||
let start = Instant::now();
|
||||
'pause: loop {
|
||||
if self.do_early_return.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
if Instant::now().duration_since(start) > *duration {
|
||||
break 'pause;
|
||||
}
|
||||
sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
ActionData::AudioEq => {}
|
||||
ActionData::SystemInfo => {}
|
||||
ActionData::TimeDate => {}
|
||||
ActionData::Matrix => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnime<'a> {
|
||||
config: Arc<Mutex<UserConfig>>,
|
||||
client: AuraDbusClient<'a>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
|
||||
/// Must be the same Atomic as in CtrlAnimeInner
|
||||
inner_early_return: &'a AtomicBool,
|
||||
}
|
||||
|
||||
impl<'a> CtrlAnime<'static> {
|
||||
pub fn new(
|
||||
config: Arc<Mutex<UserConfig>>,
|
||||
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
|
||||
client: AuraDbusClient<'static>,
|
||||
inner_early_return: &'static AtomicBool,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(CtrlAnime {
|
||||
config,
|
||||
inner,
|
||||
client,
|
||||
inner_early_return,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
println!("CtrlAnime: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The pattern for a zbus method is:
|
||||
// - Get config lock if required
|
||||
// - Set inner_early_return to stop the inner run loop temporarily
|
||||
// - Do actions
|
||||
// - Write config if required
|
||||
// - Unset inner_early_return
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlAnime<'static> {
|
||||
pub fn insert_asus_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
time: TimeType,
|
||||
count: u32,
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let time: AnimTime = match time {
|
||||
TimeType::Timer => AnimTime::Time(Duration::from_millis(count as u64)),
|
||||
TimeType::Count => AnimTime::Cycles(count),
|
||||
TimeType::Infinite => AnimTime::Infinite,
|
||||
};
|
||||
let file = Path::new(&file);
|
||||
let action = AnimeAction::AsusAnimation {
|
||||
file: file.into(),
|
||||
brightness,
|
||||
time,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json = serde_json::to_string_pretty(&*config).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn insert_image_gif(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
time: TimeType,
|
||||
count: u32,
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let time: AnimTime = match time {
|
||||
TimeType::Timer => AnimTime::Time(Duration::from_millis(count as u64)),
|
||||
TimeType::Count => AnimTime::Cycles(count),
|
||||
TimeType::Infinite => AnimTime::Infinite,
|
||||
};
|
||||
let file = Path::new(&file);
|
||||
let translation = Vec2::new(xy.0, xy.1);
|
||||
let action = AnimeAction::ImageAnimation {
|
||||
file: file.into(),
|
||||
scale,
|
||||
angle,
|
||||
translation,
|
||||
brightness,
|
||||
time,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn insert_image(
|
||||
&mut self,
|
||||
index: u32,
|
||||
file: String,
|
||||
scale: f32,
|
||||
angle: f32,
|
||||
xy: (f32, f32),
|
||||
brightness: f32,
|
||||
) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let file = Path::new(&file);
|
||||
let action = AnimeAction::Image {
|
||||
file: file.into(),
|
||||
scale,
|
||||
angle,
|
||||
translation: Vec2::new(xy.0, xy.1),
|
||||
brightness,
|
||||
};
|
||||
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn insert_pause(&mut self, index: u32, millis: u64) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
let action = AnimeAction::Pause(Duration::from_millis(millis));
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.insert(index as usize, &action)?;
|
||||
}
|
||||
config.anime.push(action);
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn remove_item(&mut self, index: u32) -> zbus::fdo::Result<String> {
|
||||
if let Ok(mut config) = self.config.try_lock() {
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Ok(mut controller) = self.inner.lock() {
|
||||
controller.sequences.remove_item(index as usize);
|
||||
}
|
||||
if (index as usize) < config.anime.len() {
|
||||
config.anime.remove(index as usize);
|
||||
}
|
||||
config.write()?;
|
||||
|
||||
let json =
|
||||
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
|
||||
|
||||
// Release the inner run loop again
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
return Ok(json);
|
||||
}
|
||||
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> {
|
||||
// Operations here need to be in specific order
|
||||
if on {
|
||||
self.client.proxies().anime().toggle_on(on)?;
|
||||
// Let the inner loop run
|
||||
self.inner_early_return.store(false, Ordering::SeqCst);
|
||||
} else {
|
||||
// Must make the inner run loop return early
|
||||
self.inner_early_return.store(true, Ordering::SeqCst);
|
||||
self.client.proxies().anime().toggle_on(on)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
67
daemon-user/src/daemon.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::supported::SupportedFunctions;
|
||||
use rog_user::{
|
||||
ctrl_anime::{CtrlAnime, CtrlAnimeInner},
|
||||
user_config::*,
|
||||
DBUS_NAME,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
use zbus::{fdo, Connection};
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// The anime loop needs an atomic to make it exit early if required
|
||||
static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let supported = client.proxies().supported().get_supported_functions()?;
|
||||
let supported = serde_json::from_str::<SupportedFunctions>(&&supported).unwrap();
|
||||
|
||||
let mut config = UserConfig::new();
|
||||
config.load_config()?;
|
||||
let anime = config.create_anime()?;
|
||||
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
// Create server
|
||||
let connection = Connection::new_session()?;
|
||||
fdo::DBusProxy::new(&connection)?
|
||||
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
||||
let mut server = zbus::ObjectServer::new(&connection);
|
||||
|
||||
// Set up the anime data and run loop/thread
|
||||
if supported.anime_ctrl.0 {
|
||||
// Inner behind mutex required for thread safety
|
||||
let inner = Arc::new(Mutex::new(CtrlAnimeInner::new(
|
||||
anime,
|
||||
client,
|
||||
&ANIME_INNER_EARLY_RETURN,
|
||||
)?));
|
||||
// Need new client object for dbus control part
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
let anime_control =
|
||||
CtrlAnime::new(config, inner.clone(), client, &ANIME_INNER_EARLY_RETURN)?;
|
||||
anime_control.add_to_server(&mut server);
|
||||
// Thread using inner
|
||||
let _anime_thread = thread::Builder::new()
|
||||
.name("Anime User".into())
|
||||
.spawn(move || loop {
|
||||
if let Ok(inner) = inner.try_lock() {
|
||||
inner.run().unwrap();
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
if supported.keyboard_led.per_key_led_mode {}
|
||||
|
||||
loop {
|
||||
if let Err(err) = server.try_handle_next() {
|
||||
println!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
daemon-user/src/error.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use std::fmt;
|
||||
|
||||
use rog_anime::error::AnimeError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Io(std::io::Error),
|
||||
ConfigLoadFail,
|
||||
ConfigLockFail,
|
||||
XdgVars,
|
||||
Anime(AnimeError),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::Io(err) => write!(f, "Failed to open: {}", err),
|
||||
Error::ConfigLoadFail => write!(f, "Failed to load user config"),
|
||||
Error::ConfigLockFail => write!(f, "Failed to lock user config"),
|
||||
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
|
||||
Error::Anime(err) => write!(f, "Anime error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnimeError> for Error {
|
||||
fn from(err: AnimeError) -> Self {
|
||||
Error::Anime(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for zbus::fdo::Error {
|
||||
fn from(err: Error) -> Self {
|
||||
zbus::fdo::Error::Failed(format!("Anime zbus error: {}", err))
|
||||
}
|
||||
}
|
||||
9
daemon-user/src/lib.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
pub mod user_config;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub mod ctrl_anime;
|
||||
|
||||
pub mod zbus_anime;
|
||||
|
||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||
121
daemon-user/src/user_config.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
use std::{
|
||||
fs::{create_dir, OpenOptions},
|
||||
io::{Read, Write},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rog_anime::{AnimTime, AnimeAction, Sequences, Vec2};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct UserConfig {
|
||||
pub anime: Vec<AnimeAction>,
|
||||
}
|
||||
|
||||
impl UserConfig {
|
||||
pub fn new() -> Self {
|
||||
let x = Self {
|
||||
anime: vec![
|
||||
AnimeAction::AsusAnimation {
|
||||
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Cycles(1),
|
||||
},
|
||||
AnimeAction::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
|
||||
scale: 0.9,
|
||||
angle: 0.65,
|
||||
translation: Vec2::default(),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Time(Duration::from_secs(5)),
|
||||
},
|
||||
AnimeAction::Image {
|
||||
file: "/usr/share/asusd/anime/custom/rust.png".into(),
|
||||
scale: 1.0,
|
||||
angle: 0.0,
|
||||
translation: Vec2::default(),
|
||||
brightness: 0.6,
|
||||
},
|
||||
AnimeAction::Pause(Duration::from_secs(6)),
|
||||
AnimeAction::ImageAnimation {
|
||||
file: "/usr/share/asusd/anime/custom/sonic-wait.gif".into(),
|
||||
scale: 0.9,
|
||||
angle: 0.0,
|
||||
translation: Vec2::new(3.0, 2.0),
|
||||
brightness: 0.5,
|
||||
time: AnimTime::Cycles(2),
|
||||
},
|
||||
],
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&x).unwrap());
|
||||
x
|
||||
}
|
||||
|
||||
pub fn load_config(&mut self) -> Result<(), Error> {
|
||||
let mut path = if let Some(dir) = dirs::config_dir() {
|
||||
dir
|
||||
} else {
|
||||
return Err(Error::XdgVars);
|
||||
};
|
||||
|
||||
path.push("rog");
|
||||
if !path.exists() {
|
||||
create_dir(path.clone())?;
|
||||
}
|
||||
|
||||
path.push("rog-user.cfg");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&path)?;
|
||||
|
||||
let mut buf = String::new();
|
||||
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||
file.write_all(json.as_bytes())?;
|
||||
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
|
||||
self.anime = data.anime;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write(&self) -> Result<(), Error> {
|
||||
let mut path = if let Some(dir) = dirs::config_dir() {
|
||||
dir
|
||||
} else {
|
||||
return Err(Error::XdgVars);
|
||||
};
|
||||
|
||||
path.push("rog");
|
||||
if !path.exists() {
|
||||
create_dir(path.clone())?;
|
||||
}
|
||||
|
||||
path.push("rog-user.cfg");
|
||||
|
||||
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(&path)?;
|
||||
|
||||
let json = serde_json::to_string_pretty(&self).unwrap();
|
||||
dbg!(&json);
|
||||
file.write_all(json.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_anime(&self) -> Result<Sequences, Error> {
|
||||
let mut seq = Sequences::new();
|
||||
|
||||
for (idx, action) in self.anime.iter().enumerate() {
|
||||
seq.insert(idx, action)?;
|
||||
}
|
||||
|
||||
Ok(seq)
|
||||
}
|
||||
}
|
||||
68
daemon-user/src/zbus_anime.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||
//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(interface = "org.asuslinux.Daemon")]
|
||||
trait Daemon {
|
||||
/// InsertAsusGif method
|
||||
fn insert_asus_gif(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
time: u32,
|
||||
count: u32,
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertImage method
|
||||
fn insert_image(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
scale: f64,
|
||||
angle: f64,
|
||||
xy: &(f64, f64),
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertImageGif method
|
||||
fn insert_image_gif(
|
||||
&self,
|
||||
index: u32,
|
||||
file: &str,
|
||||
scale: f64,
|
||||
angle: f64,
|
||||
xy: &(f64, f64),
|
||||
time: u32,
|
||||
count: u32,
|
||||
brightness: f64,
|
||||
) -> zbus::Result<String>;
|
||||
|
||||
/// InsertPause method
|
||||
fn insert_pause(&self, index: u32, millis: u64) -> zbus::Result<String>;
|
||||
|
||||
/// RemoveItem method
|
||||
fn remove_item(&self, index: u32) -> zbus::Result<String>;
|
||||
|
||||
/// SetState method
|
||||
fn set_state(&self, on: bool) -> zbus::Result<()>;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "daemon"
|
||||
version = "3.1.7"
|
||||
version = "3.4.0"
|
||||
license = "MPL-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
@@ -18,18 +18,19 @@ name = "asusd"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[dependencies]
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_types = { path = "../rog-types" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
rusb = "^0.7"
|
||||
rusb = "^0.8"
|
||||
udev = "^0.6"
|
||||
|
||||
# cli and logging
|
||||
log = "^0.4"
|
||||
env_logger = "^0.8"
|
||||
|
||||
zbus = "^2.0.0-beta.3"
|
||||
zvariant = "^2.5"
|
||||
logind-zbus = "*"
|
||||
zbus = "^1.9.1"
|
||||
zvariant = "^2.6"
|
||||
logind-zbus = "^0.7.1"
|
||||
|
||||
# serialisation
|
||||
serde = "^1.0"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use log::{error, info, warn};
|
||||
use rog_fan_curve::Curve;
|
||||
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
|
||||
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{File, OpenOptions};
|
||||
@@ -10,19 +9,18 @@ use crate::config_old::*;
|
||||
use crate::VERSION;
|
||||
|
||||
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
pub gfx_mode: GfxVendors,
|
||||
pub gfx_managed: bool,
|
||||
pub gfx_vfio_enable: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub kbd_led_brightness: u8,
|
||||
pub kbd_backlight_mode: u8,
|
||||
pub kbd_backlight_modes: Vec<AuraModes>,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
@@ -36,13 +34,11 @@ impl Default for Config {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: true,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: "normal".into(),
|
||||
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
||||
curr_fan_mode: 0,
|
||||
bat_charge_limit: 100,
|
||||
kbd_led_brightness: 1,
|
||||
kbd_backlight_mode: 0,
|
||||
kbd_backlight_modes: Vec::new(),
|
||||
power_profiles: pwr,
|
||||
}
|
||||
}
|
||||
@@ -50,7 +46,7 @@ impl Default for Config {
|
||||
|
||||
impl Config {
|
||||
/// `load` will attempt to read the config, and panic if the dir is missing
|
||||
pub fn load(supported_led_modes: &[u8]) -> Self {
|
||||
pub fn load() -> Self {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
@@ -65,10 +61,20 @@ impl Config {
|
||||
let mut buf = String::new();
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
return Config::create_default(&mut file, &supported_led_modes);
|
||||
return Config::create_default(&mut file);
|
||||
} else {
|
||||
if let Ok(data) = serde_json::from_str(&buf) {
|
||||
return data;
|
||||
} else if let Ok(data) = serde_json::from_str::<ConfigV324>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated config version to: {}", VERSION);
|
||||
return config;
|
||||
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated config version to: {}", VERSION);
|
||||
return config;
|
||||
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
@@ -89,17 +95,11 @@ impl Config {
|
||||
panic!("Please remove {} then restart asusd", CONFIG_PATH);
|
||||
}
|
||||
}
|
||||
Config::create_default(&mut file, &supported_led_modes)
|
||||
Config::create_default(&mut file)
|
||||
}
|
||||
|
||||
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
|
||||
// create a default config here
|
||||
let mut config = Config::default();
|
||||
|
||||
for n in supported_led_modes {
|
||||
config.kbd_backlight_modes.push(AuraModes::from(*n))
|
||||
}
|
||||
|
||||
fn create_default(file: &mut File) -> Self {
|
||||
let config = Config::default();
|
||||
// Should be okay to unwrap this as is since it is a Default
|
||||
let json = serde_json::to_string_pretty(&config).unwrap();
|
||||
file.write_all(json.as_bytes())
|
||||
@@ -141,66 +141,4 @@ impl Config {
|
||||
file.write_all(json.as_bytes())
|
||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||
}
|
||||
|
||||
pub fn set_mode_data(&mut self, mode: AuraModes) {
|
||||
let byte: u8 = (&mode).into();
|
||||
for (index, n) in self.kbd_backlight_modes.iter().enumerate() {
|
||||
if byte == u8::from(n) {
|
||||
// Consume it, OMNOMNOMNOM
|
||||
self.kbd_backlight_modes[index] = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
|
||||
for mode in &self.kbd_backlight_modes {
|
||||
if u8::from(mode) == num {
|
||||
return Some(mode);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Profile {
|
||||
pub min_percentage: u8,
|
||||
pub max_percentage: u8,
|
||||
pub turbo: bool,
|
||||
pub fan_preset: u8,
|
||||
pub fan_curve: Option<Curve>,
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub type CPUSettings = Profile;
|
||||
|
||||
impl Default for Profile {
|
||||
fn default() -> Self {
|
||||
Profile {
|
||||
min_percentage: 0,
|
||||
max_percentage: 100,
|
||||
turbo: false,
|
||||
fan_preset: 0,
|
||||
fan_curve: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Profile {
|
||||
pub fn new(
|
||||
min_percentage: u8,
|
||||
max_percentage: u8,
|
||||
turbo: bool,
|
||||
fan_preset: u8,
|
||||
fan_curve: Option<Curve>,
|
||||
) -> Self {
|
||||
Profile {
|
||||
min_percentage,
|
||||
max_percentage,
|
||||
turbo,
|
||||
fan_preset,
|
||||
fan_curve,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
148
daemon/src/config_aura.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use crate::laptops::LaptopLedData;
|
||||
use log::{error, info, warn};
|
||||
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct AuraConfigV320 {
|
||||
pub brightness: u32,
|
||||
pub current_mode: AuraModeNum,
|
||||
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
|
||||
pub multizone: Option<AuraMultiZone>,
|
||||
}
|
||||
|
||||
impl AuraConfigV320 {
|
||||
pub(crate) fn into_current(self) -> AuraConfig {
|
||||
AuraConfig {
|
||||
brightness: <LedBrightness>::from(self.brightness),
|
||||
current_mode: self.current_mode,
|
||||
builtins: self.builtins,
|
||||
multizone: self.multizone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct AuraConfig {
|
||||
pub brightness: LedBrightness,
|
||||
pub current_mode: AuraModeNum,
|
||||
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
|
||||
pub multizone: Option<AuraMultiZone>,
|
||||
}
|
||||
|
||||
impl Default for AuraConfig {
|
||||
fn default() -> Self {
|
||||
AuraConfig {
|
||||
brightness: LedBrightness::Med,
|
||||
current_mode: AuraModeNum::Static,
|
||||
builtins: BTreeMap::new(),
|
||||
multizone: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AuraConfig {
|
||||
/// `load` will attempt to read the config, and panic if the dir is missing
|
||||
pub fn load(supported_led_modes: &LaptopLedData) -> Self {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&AURA_CONFIG_PATH)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"The file {} or directory /etc/asusd/ is missing",
|
||||
AURA_CONFIG_PATH
|
||||
)
|
||||
}); // okay to cause panic here
|
||||
let mut buf = String::new();
|
||||
if let Ok(read_len) = file.read_to_string(&mut buf) {
|
||||
if read_len == 0 {
|
||||
return AuraConfig::create_default(&mut file, &supported_led_modes);
|
||||
} else {
|
||||
if let Ok(data) = serde_json::from_str(&buf) {
|
||||
return data;
|
||||
} else if let Ok(data) = serde_json::from_str::<AuraConfigV320>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated AuraConfig version");
|
||||
return config;
|
||||
}
|
||||
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
|
||||
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
|
||||
}
|
||||
}
|
||||
AuraConfig::create_default(&mut file, &supported_led_modes)
|
||||
}
|
||||
|
||||
fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self {
|
||||
// create a default config here
|
||||
let mut config = AuraConfig::default();
|
||||
|
||||
for n in &support_data.standard {
|
||||
config
|
||||
.builtins
|
||||
.insert(*n, AuraEffect::default_with_mode(*n));
|
||||
}
|
||||
|
||||
// Should be okay to unwrap this as is since it is a Default
|
||||
let json = serde_json::to_string(&config).unwrap();
|
||||
file.write_all(json.as_bytes())
|
||||
.unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH));
|
||||
config
|
||||
}
|
||||
|
||||
pub fn read(&mut self) {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&AURA_CONFIG_PATH)
|
||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
|
||||
let mut buf = String::new();
|
||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||
if l == 0 {
|
||||
warn!("File is empty {}", AURA_CONFIG_PATH);
|
||||
} else {
|
||||
let x: AuraConfig = serde_json::from_str(&buf)
|
||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH));
|
||||
*self = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = File::create(AURA_CONFIG_PATH).expect("Couldn't overwrite config");
|
||||
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||
file.write_all(json.as_bytes())
|
||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||
}
|
||||
|
||||
/// Multipurpose, will accecpt AuraEffect with zones and put in the correct store
|
||||
pub fn set_builtin(&mut self, effect: AuraEffect) {
|
||||
match effect.zone() {
|
||||
AuraZone::None => {
|
||||
self.builtins.insert(*effect.mode(), effect);
|
||||
}
|
||||
_ => {
|
||||
if let Some(multi) = self.multizone.as_mut() {
|
||||
multi.set(effect)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> {
|
||||
if let Some(multi) = &self.multizone {
|
||||
if aura_type == AuraModeNum::Static {
|
||||
return Some(multi.static_());
|
||||
} else if aura_type == AuraModeNum::Breathe {
|
||||
return Some(multi.breathe());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
use rog_types::{aura_modes::AuraModes, gfx_vendors::GfxVendors};
|
||||
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors, profile::Profile};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::config::{Config, Profile};
|
||||
use crate::config::Config;
|
||||
|
||||
/// for parsing old v2.1.2 config
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct ConfigV212 {
|
||||
gfx_managed: bool,
|
||||
@@ -15,7 +16,7 @@ pub(crate) struct ConfigV212 {
|
||||
power_profile: u8,
|
||||
kbd_led_brightness: u8,
|
||||
kbd_backlight_mode: u8,
|
||||
kbd_backlight_modes: Vec<AuraModes>,
|
||||
kbd_backlight_modes: Vec<AuraEffect>,
|
||||
}
|
||||
|
||||
impl ConfigV212 {
|
||||
@@ -24,18 +25,17 @@ impl ConfigV212 {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
active_profile: self.active_profile,
|
||||
gfx_vfio_enable: false,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.power_profile,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
kbd_led_brightness: self.kbd_led_brightness,
|
||||
kbd_backlight_mode: self.kbd_backlight_mode,
|
||||
kbd_backlight_modes: self.kbd_backlight_modes,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// for parsing old v2.2.2 config
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct ConfigV222 {
|
||||
gfx_managed: bool,
|
||||
@@ -46,7 +46,7 @@ pub(crate) struct ConfigV222 {
|
||||
power_profile: u8,
|
||||
kbd_led_brightness: u8,
|
||||
kbd_backlight_mode: u8,
|
||||
kbd_backlight_modes: Vec<AuraModes>,
|
||||
kbd_backlight_modes: Vec<AuraEffect>,
|
||||
}
|
||||
|
||||
impl ConfigV222 {
|
||||
@@ -54,18 +54,17 @@ impl ConfigV222 {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.power_profile,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
kbd_led_brightness: self.kbd_led_brightness,
|
||||
kbd_backlight_mode: self.kbd_backlight_mode,
|
||||
kbd_backlight_modes: self.kbd_backlight_modes,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// for parsing old v3.0.1 config
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub(crate) struct ConfigV301 {
|
||||
pub gfx_managed: bool,
|
||||
@@ -78,7 +77,7 @@ pub(crate) struct ConfigV301 {
|
||||
pub bat_charge_limit: u8,
|
||||
pub kbd_led_brightness: u8,
|
||||
pub kbd_backlight_mode: u8,
|
||||
pub kbd_backlight_modes: Vec<AuraModes>,
|
||||
pub kbd_backlight_modes: Vec<AuraEffect>,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
@@ -87,13 +86,70 @@ impl ConfigV301 {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// for parsing old v3.1.7 config
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub(crate) struct ConfigV317 {
|
||||
pub gfx_mode: GfxVendors,
|
||||
pub gfx_managed: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub kbd_led_brightness: u8,
|
||||
pub kbd_backlight_mode: u8,
|
||||
#[serde(skip)]
|
||||
pub kbd_backlight_modes: Option<bool>,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
impl ConfigV317 {
|
||||
pub(crate) fn into_current(self) -> Config {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ConfigV324 {
|
||||
pub gfx_mode: GfxVendors,
|
||||
pub gfx_managed: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
impl ConfigV324 {
|
||||
pub(crate) fn into_current(self) -> Config {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
kbd_led_brightness: self.kbd_led_brightness,
|
||||
kbd_backlight_mode: self.kbd_backlight_mode,
|
||||
kbd_backlight_modes: self.kbd_backlight_modes,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,25 @@
|
||||
const INIT_STR: &str = "ASUS Tech.Inc.";
|
||||
const PACKET_SIZE: usize = 640;
|
||||
|
||||
// Only these two packets must be 17 bytes
|
||||
const DEV_PAGE: u8 = 0x5e;
|
||||
// These bytes are in [1] position of the array
|
||||
const WRITE: u8 = 0xc0;
|
||||
const INIT: u8 = 0xc2;
|
||||
const SET: u8 = 0xc3;
|
||||
const APPLY: u8 = 0xc4;
|
||||
|
||||
// Used to turn the panel on and off
|
||||
// The next byte can be 0x03 for "on" and 0x00 for "off"
|
||||
const ON_OFF: u8 = 0x04;
|
||||
|
||||
use log::{error, info, warn};
|
||||
use rog_types::{
|
||||
anime_matrix::{
|
||||
AniMeDataBuffer, AniMeImageBuffer, AniMePacketType, ANIME_PANE1_PREFIX, ANIME_PANE2_PREFIX,
|
||||
use rog_anime::{
|
||||
usb::{
|
||||
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
|
||||
VENDOR_ID,
|
||||
},
|
||||
error::AuraError,
|
||||
AnimeDataBuffer, AnimePacketType,
|
||||
};
|
||||
use rog_types::supported::AnimeSupportedFunctions;
|
||||
use rusb::{Device, DeviceHandle};
|
||||
use std::error::Error;
|
||||
use std::time::Duration;
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::GetSupported;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AnimeSupportedFunctions(pub bool);
|
||||
|
||||
impl GetSupported for CtrlAnimeDisplay {
|
||||
type A = AnimeSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(0x0b05, 0x193b).is_ok())
|
||||
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(VENDOR_ID, PROD_ID).is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,23 +27,13 @@ pub struct CtrlAnimeDisplay {
|
||||
handle: DeviceHandle<rusb::GlobalContext>,
|
||||
}
|
||||
|
||||
//AnimatrixWrite
|
||||
pub trait Dbus {
|
||||
/// Write an image 34x56 pixels. Each pixel is 0-255 greyscale.
|
||||
fn write_image(&self, input: AniMeImageBuffer);
|
||||
|
||||
/// Write a direct stream of data
|
||||
fn write_direct(&self, input: AniMeDataBuffer);
|
||||
|
||||
fn set_on_off(&self, status: bool);
|
||||
|
||||
fn set_boot_on_off(&self, status: bool);
|
||||
}
|
||||
|
||||
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Anime", self)
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
||||
err
|
||||
@@ -69,45 +43,19 @@ impl crate::ZbusAdd for CtrlAnimeDisplay {
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl Dbus for CtrlAnimeDisplay {
|
||||
/// Writes a 34x56 image
|
||||
fn write_image(&self, input: AniMeImageBuffer) {
|
||||
self.write_image_buffer(input)
|
||||
.map_or_else(|err| warn!("{}", err), |()| info!("Writing image to Anime"));
|
||||
}
|
||||
|
||||
impl CtrlAnimeDisplay {
|
||||
/// Writes a data stream of length
|
||||
fn write_direct(&self, input: AniMeDataBuffer) {
|
||||
self.write_data_buffer(input)
|
||||
.map_or_else(|err| warn!("{}", err), |()| info!("Writing data to Anime"));
|
||||
fn write(&self, input: AnimeDataBuffer) {
|
||||
self.write_data_buffer(input);
|
||||
}
|
||||
|
||||
fn set_on_off(&self, status: bool) {
|
||||
let mut buffer = [0u8; PACKET_SIZE];
|
||||
buffer[0] = DEV_PAGE;
|
||||
buffer[1] = WRITE;
|
||||
buffer[2] = ON_OFF;
|
||||
|
||||
if status {
|
||||
buffer[3] = 0x03;
|
||||
} else {
|
||||
buffer[3] = 0x00;
|
||||
}
|
||||
|
||||
self.write_bytes(&buffer);
|
||||
self.write_bytes(&pkt_for_set_on(status));
|
||||
}
|
||||
|
||||
fn set_boot_on_off(&self, status: bool) {
|
||||
let status_str = if status { "on" } else { "off" };
|
||||
|
||||
self.do_set_boot(status).map_or_else(
|
||||
|err| warn!("{}", err),
|
||||
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
|
||||
);
|
||||
self.do_apply().map_or_else(
|
||||
|err| warn!("{}", err),
|
||||
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
|
||||
);
|
||||
fn set_boot_on_off(&self, on: bool) {
|
||||
self.write_bytes(&pkt_for_set_boot(on));
|
||||
self.write_bytes(&pkt_for_apply());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,12 +80,11 @@ impl CtrlAnimeDisplay {
|
||||
|
||||
info!("Device has an AniMe Matrix display");
|
||||
let ctrl = CtrlAnimeDisplay { handle: device };
|
||||
ctrl.do_initialization()?;
|
||||
ctrl.do_initialization();
|
||||
|
||||
Ok(ctrl)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_device(vendor: u16, product: u16) -> Result<Device<rusb::GlobalContext>, rusb::Error> {
|
||||
for device in rusb::devices()?.iter() {
|
||||
let device_desc = device.device_descriptor()?;
|
||||
@@ -148,8 +95,6 @@ impl CtrlAnimeDisplay {
|
||||
Err(rusb::Error::NoDevice)
|
||||
}
|
||||
|
||||
/// Should only be used if the bytes you are writing are verified correct
|
||||
#[inline]
|
||||
fn write_bytes(&self, message: &[u8]) {
|
||||
match self.handle.write_control(
|
||||
0x21, // request_type
|
||||
@@ -166,99 +111,18 @@ impl CtrlAnimeDisplay {
|
||||
},
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn write_data_buffer(&self, buffer: AniMeDataBuffer) -> Result<(), AuraError> {
|
||||
let mut image = AniMePacketType::from(buffer);
|
||||
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
|
||||
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
||||
|
||||
for row in image.iter() {
|
||||
fn write_data_buffer(&self, buffer: AnimeDataBuffer) {
|
||||
let data = AnimePacketType::from(buffer);
|
||||
for row in data.iter() {
|
||||
self.write_bytes(row);
|
||||
}
|
||||
self.do_flush()?;
|
||||
Ok(())
|
||||
self.write_bytes(&pkt_for_flush());
|
||||
}
|
||||
|
||||
/// Write an Animatrix image
|
||||
///
|
||||
/// The expected USB input here is *two* Vectors, 640 bytes in length. The two vectors
|
||||
/// are each one half of the full image write.
|
||||
///
|
||||
/// After each write a flush is written, it is assumed that this tells the device to
|
||||
/// go ahead and display the written bytes
|
||||
///
|
||||
/// # Note:
|
||||
/// The vectors are expected to contain the full sequence of bytes as follows
|
||||
///
|
||||
/// - Write pane 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. <led brightness>
|
||||
/// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
|
||||
///
|
||||
/// Where led brightness is 0..255, low to high
|
||||
#[inline]
|
||||
fn write_image_buffer(&self, buffer: AniMeImageBuffer) -> Result<(), AuraError> {
|
||||
let mut image = AniMePacketType::from(buffer);
|
||||
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
|
||||
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
||||
|
||||
for row in image.iter() {
|
||||
self.write_bytes(row);
|
||||
}
|
||||
self.do_flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn do_initialization(&self) -> Result<(), AuraError> {
|
||||
let mut init = [0; PACKET_SIZE];
|
||||
init[0] = DEV_PAGE; // This is the USB page we're using throughout
|
||||
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
|
||||
init[idx + 1] = *byte
|
||||
}
|
||||
self.write_bytes(&init);
|
||||
|
||||
// clear the init array and write other init message
|
||||
for ch in init.iter_mut() {
|
||||
*ch = 0;
|
||||
}
|
||||
init[0] = DEV_PAGE; // write it to be sure?
|
||||
init[1] = INIT;
|
||||
|
||||
self.write_bytes(&init);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn do_flush(&self) -> Result<(), AuraError> {
|
||||
let mut flush = [0; PACKET_SIZE];
|
||||
flush[0] = DEV_PAGE;
|
||||
flush[1] = WRITE;
|
||||
flush[2] = 0x03;
|
||||
|
||||
self.write_bytes(&flush);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn do_set_boot(&self, status: bool) -> Result<(), AuraError> {
|
||||
let mut flush = [0; PACKET_SIZE];
|
||||
flush[0] = DEV_PAGE;
|
||||
flush[1] = SET;
|
||||
flush[2] = 0x01;
|
||||
flush[3] = if status { 0x00 } else { 0x80 };
|
||||
|
||||
self.write_bytes(&flush);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn do_apply(&self) -> Result<(), AuraError> {
|
||||
let mut flush = [0; PACKET_SIZE];
|
||||
flush[0] = DEV_PAGE;
|
||||
flush[1] = APPLY;
|
||||
flush[2] = 0x01;
|
||||
flush[3] = 0x80;
|
||||
|
||||
self.write_bytes(&flush);
|
||||
Ok(())
|
||||
fn do_initialization(&self) {
|
||||
let pkts = pkts_for_init();
|
||||
self.write_bytes(&pkts[0]);
|
||||
self.write_bytes(&pkts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
//use crate::dbus::DbusEvents;
|
||||
use log::{info, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::supported::ChargeSupportedFunctions;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ChargeSupportedFunctions {
|
||||
pub charge_level_set: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlCharge {
|
||||
type A = ChargeSupportedFunctions;
|
||||
|
||||
@@ -63,7 +59,10 @@ impl CtrlCharge {
|
||||
impl crate::ZbusAdd for CtrlCharge {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Charge", self)
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: add_to_server {}", err);
|
||||
err
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
use crate::error::RogError;
|
||||
use crate::{
|
||||
config::{Config, Profile},
|
||||
GetSupported,
|
||||
};
|
||||
use crate::{config::Config, GetSupported};
|
||||
use log::{info, warn};
|
||||
use rog_types::profile::{FanLevel, ProfileEvent};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::{profile::{FanLevel, Profile, ProfileEvent}, supported::FanCpuSupportedFunctions};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::dbus_interface;
|
||||
use zbus::{dbus_interface, fdo::Error};
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
||||
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
||||
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
||||
|
||||
pub struct CtrlFanAndCPU {
|
||||
pub struct CtrlFanAndCpu {
|
||||
pub path: &'static str,
|
||||
config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FanCpuSupportedFunctions {
|
||||
pub stock_fan_modes: bool,
|
||||
pub min_max_freq: bool,
|
||||
pub fan_curve_set: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlFanAndCPU {
|
||||
impl GetSupported for CtrlFanAndCpu {
|
||||
type A = FanCpuSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
FanCpuSupportedFunctions {
|
||||
stock_fan_modes: CtrlFanAndCPU::get_fan_path().is_ok(),
|
||||
stock_fan_modes: CtrlFanAndCpu::get_fan_path().is_ok(),
|
||||
min_max_freq: intel_pstate::PState::new().is_ok(),
|
||||
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
|
||||
}
|
||||
@@ -42,11 +32,11 @@ impl GetSupported for CtrlFanAndCPU {
|
||||
}
|
||||
|
||||
pub struct DbusFanAndCpu {
|
||||
inner: Arc<Mutex<CtrlFanAndCPU>>,
|
||||
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
||||
}
|
||||
|
||||
impl DbusFanAndCpu {
|
||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCPU>>) -> Self {
|
||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
@@ -90,41 +80,90 @@ impl DbusFanAndCpu {
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn active_profile_name(&mut self) -> String {
|
||||
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
return cfg.active_profile.clone();
|
||||
return Ok(cfg.active_profile.clone());
|
||||
}
|
||||
}
|
||||
"Failed".to_string()
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile name".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: Profile can't implement Type because of Curve
|
||||
/// Fetch the active profile details
|
||||
fn profile(&mut self) -> String {
|
||||
fn profile(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string(profile) {
|
||||
return json;
|
||||
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"Failed".to_string()
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn profiles(&mut self) -> String {
|
||||
/// Fetch all profile data
|
||||
fn profiles(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Ok(json) = serde_json::to_string(&cfg.power_profiles) {
|
||||
return json;
|
||||
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
"Failed".to_string()
|
||||
Err(Error::Failed(
|
||||
"Failed to get all profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
||||
return Ok(profile_names);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to get all profile names".to_string()))
|
||||
}
|
||||
|
||||
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
|
||||
if !cfg.power_profiles.contains_key(profile) {
|
||||
return Err(Error::Failed("Invalid profile specified".to_string()));
|
||||
}
|
||||
|
||||
if cfg.power_profiles.keys().len() == 1 {
|
||||
return Err(Error::Failed("Cannot delete the last profile".to_string()));
|
||||
}
|
||||
|
||||
if cfg.active_profile == *profile {
|
||||
return Err(Error::Failed(
|
||||
"Cannot delete the active profile".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
cfg.power_profiles.remove(profile);
|
||||
cfg.write();
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to lock configuration".to_string()))
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
@@ -134,7 +173,10 @@ impl DbusFanAndCpu {
|
||||
impl crate::ZbusAdd for DbusFanAndCpu {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Profile", self)
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("DbusFanAndCpu: add_to_server {}", err);
|
||||
err
|
||||
@@ -143,7 +185,7 @@ impl crate::ZbusAdd for DbusFanAndCpu {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Reloadable for CtrlFanAndCPU {
|
||||
impl crate::Reloadable for CtrlFanAndCpu {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||
let profile = config.active_profile.clone();
|
||||
@@ -157,11 +199,11 @@ impl crate::Reloadable for CtrlFanAndCPU {
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlFanAndCPU {
|
||||
impl CtrlFanAndCpu {
|
||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||
let path = CtrlFanAndCPU::get_fan_path()?;
|
||||
let path = CtrlFanAndCpu::get_fan_path()?;
|
||||
info!("Device has thermal throttle control");
|
||||
Ok(CtrlFanAndCPU { path, config })
|
||||
Ok(CtrlFanAndCpu { path, config })
|
||||
}
|
||||
|
||||
fn get_fan_path() -> Result<&'static str, RogError> {
|
||||
|
||||
@@ -6,10 +6,16 @@ use crate::error::RogError;
|
||||
#[derive(Debug)]
|
||||
pub enum GfxError {
|
||||
ParseVendor,
|
||||
ParsePower,
|
||||
Bus(String, std::io::Error),
|
||||
DisplayManagerAction(String, ExitStatus),
|
||||
DisplayManagerTimeout(String),
|
||||
GsyncModeActive,
|
||||
VfioBuiltin,
|
||||
VfioDisabled,
|
||||
MissingModule(String),
|
||||
Modprobe(String),
|
||||
Command(String, std::io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for GfxError {
|
||||
@@ -17,6 +23,7 @@ impl fmt::Display for GfxError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
|
||||
GfxError::ParsePower => write!(f, "Could not parse dGPU power status"),
|
||||
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
|
||||
GfxError::DisplayManagerAction(action, status) => {
|
||||
write!(f, "Display-manager action {} failed: {}", action, status)
|
||||
@@ -28,6 +35,16 @@ impl fmt::Display for GfxError {
|
||||
f,
|
||||
"Can not switch gfx modes when dedicated/G-Sync mode is active"
|
||||
),
|
||||
GfxError::VfioBuiltin => write!(
|
||||
f,
|
||||
"Can not switch to vfio mode if the modules are built in to kernel"
|
||||
),
|
||||
GfxError::VfioDisabled => {
|
||||
write!(f, "Can not switch to vfio mode if disabled in config file")
|
||||
}
|
||||
GfxError::MissingModule(m) => write!(f, "The module {} is missing", m),
|
||||
GfxError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
|
||||
GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ use ctrl_gfx::*;
|
||||
use ctrl_rog_bios::CtrlRogBios;
|
||||
use log::{error, info, warn};
|
||||
use logind_zbus::{
|
||||
types::{SessionClass, SessionInfo, SessionType},
|
||||
types::{SessionClass, SessionInfo, SessionState, SessionType},
|
||||
ManagerProxy, SessionProxy,
|
||||
};
|
||||
use rog_types::gfx_vendors::GfxVendors;
|
||||
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
|
||||
use std::{io::Write, ops::Add, path::Path, time::Instant};
|
||||
use std::{iter::FromIterator, thread::JoinHandle};
|
||||
use std::{process::Command, thread::sleep, time::Duration};
|
||||
@@ -15,6 +15,7 @@ use std::{sync::Arc, sync::Mutex};
|
||||
use sysfs_class::{PciDevice, SysClass};
|
||||
use system::{GraphicsDevice, PciBus};
|
||||
use zbus::{dbus_interface, Connection};
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::*;
|
||||
|
||||
@@ -32,50 +33,53 @@ pub struct CtrlGraphics {
|
||||
}
|
||||
|
||||
trait Dbus {
|
||||
fn vendor(&self) -> String;
|
||||
fn power(&self) -> String;
|
||||
fn set_vendor(&mut self, vendor: String);
|
||||
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
|
||||
fn notify_action(&self, action: &str) -> zbus::Result<()>;
|
||||
fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
|
||||
fn power(&self) -> zbus::fdo::Result<GfxPower>;
|
||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
|
||||
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
|
||||
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl Dbus for CtrlGraphics {
|
||||
fn vendor(&self) -> String {
|
||||
self.get_gfx_mode()
|
||||
.map(|gfx| gfx.into())
|
||||
.unwrap_or_else(|err| format!("Get vendor failed: {}", err))
|
||||
fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
|
||||
self.get_gfx_mode().map_err(|err| {
|
||||
error!("GFX: {}", err);
|
||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||
})
|
||||
}
|
||||
|
||||
fn power(&self) -> String {
|
||||
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
|
||||
fn power(&self) -> zbus::fdo::Result<GfxPower> {
|
||||
Self::get_runtime_status().map_err(|err| {
|
||||
error!("GFX: {}", err);
|
||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||
})
|
||||
}
|
||||
|
||||
fn set_vendor(&mut self, vendor: String) {
|
||||
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
|
||||
info!("GFX: Switching gfx mode to {}", vendor);
|
||||
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| {
|
||||
error!("GFX: {}", err);
|
||||
format!("Failed: {}", err.to_string())
|
||||
});
|
||||
self.notify_gfx(&vendor)
|
||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||
self.notify_action(&msg)
|
||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||
}
|
||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
|
||||
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
|
||||
let msg = self.set_gfx_config(vendor).map_err(|err| {
|
||||
error!("GFX: {}", err);
|
||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||
})?;
|
||||
self.notify_gfx(&vendor)
|
||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||
self.notify_action(&msg)
|
||||
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()> {}
|
||||
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
fn notify_action(&self, action: &str) -> zbus::Result<()> {}
|
||||
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
|
||||
}
|
||||
|
||||
impl ZbusAdd for CtrlGraphics {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Gfx", self)
|
||||
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self)
|
||||
.map_err(|err| {
|
||||
warn!("GFX: CtrlGraphics: add_to_server {}", err);
|
||||
err
|
||||
@@ -95,10 +99,8 @@ impl Reloadable for CtrlGraphics {
|
||||
impl CtrlGraphics {
|
||||
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
||||
let bus = PciBus::new()?;
|
||||
|
||||
info!("GFX: Rescanning PCI bus");
|
||||
bus.rescan()?;
|
||||
|
||||
let devs = PciDevice::all()?;
|
||||
|
||||
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
|
||||
@@ -163,12 +165,12 @@ impl CtrlGraphics {
|
||||
self.nvidia.clone()
|
||||
}
|
||||
|
||||
/// Save the selected `Vendor` mode to config
|
||||
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
|
||||
if let Ok(mut config) = config.lock() {
|
||||
config.gfx_mode = vendor;
|
||||
config.write();
|
||||
}
|
||||
// TODO: Error here
|
||||
}
|
||||
|
||||
/// Associated method to get which vendor mode is set
|
||||
@@ -180,12 +182,22 @@ impl CtrlGraphics {
|
||||
Ok(GfxVendors::Hybrid)
|
||||
}
|
||||
|
||||
fn get_runtime_status() -> Result<String, RogError> {
|
||||
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
|
||||
let buf = std::fs::read_to_string(PATH).map_err(|err| RogError::Read(PATH.into(), err))?;
|
||||
Ok(buf)
|
||||
fn get_runtime_status() -> Result<GfxPower, RogError> {
|
||||
let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status");
|
||||
if path.exists() {
|
||||
let buf = std::fs::read_to_string(path).map_err(|err| {
|
||||
RogError::Read(
|
||||
"/sys/bus/pci/devices/0000:01:00.0/power/runtime_status".to_string(),
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
Ok(GfxPower::from_str(&buf)?)
|
||||
} else {
|
||||
Ok(GfxPower::Off)
|
||||
}
|
||||
}
|
||||
|
||||
/// Some systems have a fallback service to load nouveau if nvidia fails
|
||||
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
|
||||
let action = if vendor == GfxVendors::Nvidia {
|
||||
info!("GFX: Enabling nvidia-fallback.service");
|
||||
@@ -212,6 +224,7 @@ impl CtrlGraphics {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write the appropriate xorg config for the chosen mode
|
||||
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
|
||||
let text = if vendor == GfxVendors::Nvidia {
|
||||
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
|
||||
@@ -238,8 +251,41 @@ impl CtrlGraphics {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_modprobe_conf() -> Result<(), RogError> {
|
||||
/// Creates the full modprobe.conf required for vfio pass-through
|
||||
fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
|
||||
let mut vifo = MODPROBE_VFIO.to_vec();
|
||||
for (d_count, dev) in devices.iter().enumerate() {
|
||||
for (f_count, func) in dev.functions().iter().enumerate() {
|
||||
let vendor = func.vendor().unwrap();
|
||||
let device = func.device().unwrap();
|
||||
unsafe {
|
||||
vifo.append(format!("{:x}", vendor).as_mut_vec());
|
||||
}
|
||||
vifo.append(&mut vec![b':']);
|
||||
unsafe {
|
||||
vifo.append(format!("{:x}", device).as_mut_vec());
|
||||
}
|
||||
if f_count < dev.functions().len() - 1 {
|
||||
vifo.append(&mut vec![b',']);
|
||||
}
|
||||
}
|
||||
if d_count < dev.functions().len() - 1 {
|
||||
vifo.append(&mut vec![b',']);
|
||||
}
|
||||
}
|
||||
let mut conf = MODPROBE_INTEGRATED.to_vec();
|
||||
conf.append(&mut vifo);
|
||||
conf
|
||||
}
|
||||
|
||||
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
||||
info!("GFX: Writing {}", MODPROBE_PATH);
|
||||
let content = match vendor {
|
||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => MODPROBE_BASE.to_vec(),
|
||||
GfxVendors::Vfio => Self::get_vfio_conf(devices),
|
||||
// GfxVendors::Compute => {}
|
||||
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
|
||||
};
|
||||
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
@@ -248,7 +294,7 @@ impl CtrlGraphics {
|
||||
.open(MODPROBE_PATH)
|
||||
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
|
||||
|
||||
file.write_all(MODPROBE_BASE)
|
||||
file.write_all(&content)
|
||||
.and_then(|_| file.sync_all())
|
||||
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
|
||||
|
||||
@@ -258,37 +304,19 @@ impl CtrlGraphics {
|
||||
fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
||||
// Unbind NVIDIA graphics devices and their functions
|
||||
let unbinds = devices.iter().map(|dev| dev.unbind());
|
||||
|
||||
// Remove NVIDIA graphics devices and their functions
|
||||
let removes = devices.iter().map(|dev| dev.remove());
|
||||
|
||||
Result::from_iter(unbinds.chain(removes))
|
||||
.map_err(|err| RogError::Command("device unbind error".into(), err))?;
|
||||
|
||||
Ok(())
|
||||
.map_err(|err| RogError::Command("device unbind error".into(), err))
|
||||
}
|
||||
|
||||
fn log_uses_of_nvidia() {
|
||||
// lsof /dev/nvidia*
|
||||
let mut cmd = Command::new("lsof");
|
||||
cmd.arg("/dev/nvidia*");
|
||||
|
||||
match cmd.output() {
|
||||
Ok(output) => {
|
||||
if !output.status.success() {
|
||||
error!(
|
||||
"Failed to list uses of nvidia devices: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
} else if output.status.success() {
|
||||
warn!("GFX: {}", String::from_utf8_lossy(&output.stdout));
|
||||
}
|
||||
}
|
||||
Err(err) => error!("GFX: Failed to list uses of nvidia devices: {}", err),
|
||||
}
|
||||
fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
||||
let unbinds = devices.iter().map(|dev| dev.unbind());
|
||||
Result::from_iter(unbinds)
|
||||
.map_err(|err| RogError::Command("device unbind error".into(), err))
|
||||
}
|
||||
|
||||
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
|
||||
fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> {
|
||||
let mut cmd = Command::new(action);
|
||||
cmd.arg(driver);
|
||||
|
||||
@@ -303,7 +331,7 @@ impl CtrlGraphics {
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||
.map_err(|err| GfxError::Command(format!("{:?}", cmd), err))?;
|
||||
if !output.status.success() {
|
||||
if output
|
||||
.stderr
|
||||
@@ -311,17 +339,24 @@ impl CtrlGraphics {
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
if output.stderr.ends_with("is builtin.\n".as_bytes()) {
|
||||
return Err(GfxError::VfioBuiltin);
|
||||
}
|
||||
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
|
||||
let msg = format!(
|
||||
warn!(
|
||||
"{} {} failed: {:?}",
|
||||
action,
|
||||
driver,
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
warn!("GFX: {}", msg);
|
||||
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded");
|
||||
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
|
||||
return Ok(());
|
||||
}
|
||||
if String::from_utf8_lossy(&output.stderr)
|
||||
.contains(&format!("Module {} not found", driver))
|
||||
{
|
||||
return Err(GfxError::MissingModule(driver.into()));
|
||||
}
|
||||
if count >= MAX_TRIES {
|
||||
let msg = format!(
|
||||
"{} {} failed: {:?}",
|
||||
@@ -329,14 +364,14 @@ impl CtrlGraphics {
|
||||
driver,
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
return Err(RogError::Modprobe(msg));
|
||||
return Err(GfxError::Modprobe(msg));
|
||||
}
|
||||
} else if output.status.success() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
count += 1;
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,6 +413,20 @@ impl CtrlGraphics {
|
||||
Err(GfxError::DisplayManagerTimeout(state.into()).into())
|
||||
}
|
||||
|
||||
/// Determine if we need to logout/thread. Integrated<->Vfio mode does not
|
||||
/// require logout.
|
||||
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
|
||||
if let Ok(config) = self.config.lock() {
|
||||
let current = config.gfx_mode;
|
||||
if matches!(current, GfxVendors::Integrated | GfxVendors::Vfio)
|
||||
&& matches!(vendor, GfxVendors::Integrated | GfxVendors::Vfio)
|
||||
{
|
||||
return GfxRequiredUserAction::None;
|
||||
}
|
||||
}
|
||||
GfxRequiredUserAction::Logout
|
||||
}
|
||||
|
||||
/// Write the config changes and add/remove drivers and devices depending
|
||||
/// on selected mode:
|
||||
///
|
||||
@@ -387,51 +436,73 @@ impl CtrlGraphics {
|
||||
/// - rescan for devices
|
||||
/// + add drivers
|
||||
/// + or remove drivers and devices
|
||||
///
|
||||
/// The daemon needs direct access to this function when it detects that the
|
||||
pub fn do_vendor_tasks(
|
||||
vendor: GfxVendors,
|
||||
vfio_enable: bool,
|
||||
devices: &[GraphicsDevice],
|
||||
bus: &PciBus,
|
||||
) -> Result<(), RogError> {
|
||||
Self::write_xorg_conf(vendor)?;
|
||||
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup?
|
||||
|
||||
// Rescan before doing remove or add drivers
|
||||
bus.rescan()
|
||||
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
|
||||
bus.rescan()?;
|
||||
//
|
||||
Self::write_xorg_conf(vendor)?;
|
||||
// Write different modprobe to enable boot control to work
|
||||
Self::write_modprobe_conf(vendor, devices)?;
|
||||
|
||||
match vendor {
|
||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
||||
if vfio_enable {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
}
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "modprobe").map_err(|err| {
|
||||
Self::log_uses_of_nvidia();
|
||||
err
|
||||
})?;
|
||||
Self::do_driver_action(driver, "modprobe")?;
|
||||
}
|
||||
}
|
||||
GfxVendors::Vfio => {
|
||||
if vfio_enable {
|
||||
Self::do_driver_action("nouveau", "rmmod")?;
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
Self::unbind_only(&devices)?;
|
||||
Self::do_driver_action("vfio-pci", "modprobe")?;
|
||||
} else {
|
||||
return Err(GfxError::VfioDisabled.into());
|
||||
}
|
||||
}
|
||||
// TODO: compute mode, needs different setup
|
||||
// GfxVendors::Compute => {}
|
||||
GfxVendors::Integrated => {
|
||||
Self::do_driver_action("nouveau", "rmmod")?;
|
||||
if vfio_enable {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
}
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
Self::unbind_remove_nvidia(&devices)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn graphical_session_active(
|
||||
/// Check if the user has any graphical uiser sessions that are active or online
|
||||
fn graphical_user_sessions_exist(
|
||||
connection: &Connection,
|
||||
sessions: &[SessionInfo],
|
||||
) -> Result<bool, RogError> {
|
||||
for session in sessions {
|
||||
let session_proxy = SessionProxy::new(&connection, session)?;
|
||||
let session_proxy = SessionProxy::new(connection, session)?;
|
||||
if session_proxy.get_class()? == SessionClass::User {
|
||||
match session_proxy.get_type()? {
|
||||
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
|
||||
if session_proxy.get_active()? {
|
||||
return Ok(true);
|
||||
match session_proxy.get_state()? {
|
||||
SessionState::Online | SessionState::Active => return Ok(true),
|
||||
SessionState::Closing | SessionState::Invalid => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -447,6 +518,7 @@ impl CtrlGraphics {
|
||||
devices: Vec<GraphicsDevice>,
|
||||
bus: PciBus,
|
||||
thread_stop: mpsc::Receiver<bool>,
|
||||
config: Arc<Mutex<Config>>,
|
||||
) -> Result<String, RogError> {
|
||||
info!("GFX: display-manager thread started");
|
||||
|
||||
@@ -460,12 +532,11 @@ impl CtrlGraphics {
|
||||
loop {
|
||||
let tmp = manager.list_sessions()?;
|
||||
if !tmp.iter().eq(&sessions) {
|
||||
warn!("GFX: Sessions list changed");
|
||||
warn!("GFX: Old list:\n{:?}\nNew list:\n{:?}", &sessions, &tmp);
|
||||
info!("GFX thread: Sessions list changed");
|
||||
sessions = tmp;
|
||||
}
|
||||
|
||||
if !Self::graphical_session_active(&connection, &sessions)? {
|
||||
if !Self::graphical_user_sessions_exist(&connection, &sessions)? {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -484,58 +555,45 @@ impl CtrlGraphics {
|
||||
sleep(SLEEP_PERIOD);
|
||||
}
|
||||
|
||||
info!("GFX: all graphical user sessions ended, continuing");
|
||||
info!("GFX thread: all graphical user sessions ended, continuing");
|
||||
Self::do_display_manager_action("stop")?;
|
||||
Self::wait_display_manager_state("inactive")?;
|
||||
|
||||
match Self::wait_display_manager_state("inactive") {
|
||||
Ok(_) => info!("GFX: display-manager stopped"),
|
||||
Err(err) => {
|
||||
warn!("GFX: {}", err);
|
||||
warn!("GFX: Retry stop display manager");
|
||||
Self::do_display_manager_action("stop")?;
|
||||
Self::wait_display_manager_state("inactive")?;
|
||||
}
|
||||
}
|
||||
let vfio_enable = if let Ok(config) = config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||
Self::do_display_manager_action("start")?;
|
||||
|
||||
if Self::wait_display_manager_state("active").is_err() {
|
||||
error!("GFX: display-manager failed to start normally, attempting restart");
|
||||
Self::do_display_manager_action("restart")?;
|
||||
Self::wait_display_manager_state("active")?;
|
||||
}
|
||||
info!("GFX: display-manager started");
|
||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
Self::do_display_manager_action("restart")?;
|
||||
// Save selected mode in case of reboot
|
||||
Self::save_gfx_mode(vendor, config);
|
||||
info!("GFX thread: display-manager started");
|
||||
|
||||
let v: &str = vendor.into();
|
||||
info!("GFX: Graphics mode changed to {} successfully", v);
|
||||
info!("GFX thread: Graphics mode changed to {} successfully", v);
|
||||
Ok(format!("Graphics mode changed to {} successfully", v))
|
||||
}
|
||||
|
||||
/// Initiates a mode change by starting a thread that will wait until all
|
||||
/// graphical sessions are exited before performing the tasks required
|
||||
/// to switch modes.
|
||||
///
|
||||
/// For manually calling (not on boot/startup) via dbus
|
||||
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
|
||||
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
|
||||
if gsync == 1 {
|
||||
return Err(GfxError::GsyncModeActive.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// Before starting a new thread the old one *must* be cancelled
|
||||
fn cancel_thread(&self) {
|
||||
if let Ok(lock) = self.thread_kill.lock() {
|
||||
if let Some(tx) = lock.as_ref() {
|
||||
// Cancel the running thread
|
||||
info!("GFX: Cancelling previous thread");
|
||||
tx.send(true)
|
||||
.map_err(|err| {
|
||||
warn!("GFX: {}", err);
|
||||
warn!("GFX thread: {}", err);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The thread is used only in cases where a logout is required
|
||||
fn setup_thread(&mut self, vendor: GfxVendors) {
|
||||
let config = self.config.clone();
|
||||
let devices = self.nvidia.clone();
|
||||
let bus = self.bus.clone();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
@@ -544,11 +602,8 @@ impl CtrlGraphics {
|
||||
}
|
||||
let killer = self.thread_kill.clone();
|
||||
|
||||
// Save selected mode in case of reboot
|
||||
Self::save_gfx_mode(vendor, self.config.clone());
|
||||
|
||||
let _join: JoinHandle<()> = std::thread::spawn(move || {
|
||||
Self::fire_starter(vendor, devices, bus, rx)
|
||||
Self::fire_starter(vendor, devices, bus, rx, config)
|
||||
.map_err(|err| {
|
||||
error!("GFX: {}", err);
|
||||
})
|
||||
@@ -558,33 +613,66 @@ impl CtrlGraphics {
|
||||
*lock = None;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: undo if failed? Save last mode, catch errors...
|
||||
let v: &str = vendor.into();
|
||||
Ok(format!("Graphics mode changed to {} successfully", v))
|
||||
}
|
||||
|
||||
// if CtrlRogBios::has_dedicated_gfx_toggle() {
|
||||
// if let Ok(config) = self.config.clone().try_lock() {
|
||||
// // Switch to dedicated if config says to do so
|
||||
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia {
|
||||
// CtrlRogBios::set_gfx_mode(true)
|
||||
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err));
|
||||
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||
// // otherwise if switching to non-Nvidia mode turn off dedicated mode
|
||||
// if ded == 1 && vendor != GfxVendors::Nvidia {
|
||||
// CtrlRogBios::set_gfx_mode(false)
|
||||
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/// Initiates a mode change by starting a thread that will wait until all
|
||||
/// graphical sessions are exited before performing the tasks required
|
||||
/// to switch modes.
|
||||
///
|
||||
/// For manually calling (not on boot/startup) via dbus
|
||||
pub fn set_gfx_config(
|
||||
&mut self,
|
||||
vendor: GfxVendors,
|
||||
) -> Result<GfxRequiredUserAction, RogError> {
|
||||
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
|
||||
if gsync == 1 {
|
||||
return Err(GfxError::GsyncModeActive.into());
|
||||
}
|
||||
}
|
||||
|
||||
let vfio_enable = if let Ok(config) = self.config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !vfio_enable && matches!(vendor, GfxVendors::Vfio) {
|
||||
return Err(GfxError::VfioDisabled.into());
|
||||
}
|
||||
|
||||
// Must always cancel any thread running
|
||||
self.cancel_thread();
|
||||
// determine which method we need here
|
||||
let action_required = self.logout_required(vendor);
|
||||
if matches!(action_required, GfxRequiredUserAction::Logout) {
|
||||
// Yeah need the thread to check if all users are logged out
|
||||
info!("GFX: mode change requires a logout to complete");
|
||||
self.setup_thread(vendor);
|
||||
} else {
|
||||
// Okay cool, we can switch on/off vfio
|
||||
info!("GFX: mode change does not require logout");
|
||||
let devices = self.nvidia.clone();
|
||||
let bus = self.bus.clone();
|
||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
||||
}
|
||||
// TODO: undo if failed? Save last mode, catch errors...
|
||||
Ok(action_required)
|
||||
}
|
||||
|
||||
/// Used only on boot to set correct mode
|
||||
fn auto_power(&mut self) -> Result<(), RogError> {
|
||||
let vendor = self.get_gfx_mode()?;
|
||||
let devices = self.nvidia.clone();
|
||||
let bus = self.bus.clone();
|
||||
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||
|
||||
let vfio_enable = if let Ok(config) = self.config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
Self::toggle_fallback_service(vendor)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@ pub mod system;
|
||||
|
||||
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
|
||||
|
||||
const VFIO_DRIVERS: [&str; 5] = [
|
||||
"vfio-pci",
|
||||
"vfio_iommu_type1",
|
||||
"vfio_virqfd",
|
||||
"vfio_mdev",
|
||||
"vfio",
|
||||
];
|
||||
|
||||
const DISPLAY_MANAGER: &str = "display-manager.service";
|
||||
|
||||
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
||||
@@ -21,6 +29,17 @@ options nvidia NVreg_DynamicPowerManagement=0x02
|
||||
options nvidia-drm modeset=1
|
||||
"#;
|
||||
|
||||
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
|
||||
blacklist i2c_nvidia_gpu
|
||||
blacklist nvidia
|
||||
blacklist nvidia-drm
|
||||
blacklist nvidia-modeset
|
||||
blacklist nouveau
|
||||
alias nouveau off
|
||||
"#;
|
||||
|
||||
static MODPROBE_VFIO: &[u8] = br#"options vfio-pci ids="#;
|
||||
|
||||
const XORG_FILE: &str = "90-nvidia-primary.conf";
|
||||
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";
|
||||
|
||||
@@ -29,8 +48,7 @@ Section "OutputClass"
|
||||
Identifier "nvidia"
|
||||
MatchDriver "nvidia-drm"
|
||||
Driver "nvidia"
|
||||
Option "AllowEmptyInitialConfiguration"
|
||||
Option "AllowExternalGpus""#;
|
||||
Option "AllowEmptyInitialConfiguration" "true""#;
|
||||
|
||||
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
|
||||
Option "PrimaryGPU" "true""#;
|
||||
|
||||
@@ -72,6 +72,10 @@ impl GraphicsDevice {
|
||||
self.functions.iter().any(|func| func.path().exists())
|
||||
}
|
||||
|
||||
pub fn functions(&self) -> &[PciDevice] {
|
||||
&self.functions
|
||||
}
|
||||
|
||||
pub fn unbind(&self) -> Result<(), std::io::Error> {
|
||||
for func in self.functions.iter() {
|
||||
if func.path().exists() {
|
||||
|
||||
@@ -5,55 +5,40 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
config_aura::AuraConfig,
|
||||
error::RogError,
|
||||
laptops::{match_laptop, HELP_ADDRESS},
|
||||
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||
};
|
||||
use log::{error, info, warn};
|
||||
use rog_types::{
|
||||
aura_brightness_bytes,
|
||||
aura_modes::{AuraModes, PER_KEY},
|
||||
fancy::KeyColourArray,
|
||||
LED_MSG_LEN,
|
||||
};
|
||||
use rog_types::{LED_MSG_LEN, aura_modes::{AuraEffect, AuraModeNum, LedBrightness}, supported::LedSupportedFunctions};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::GetSupported;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LedSupportedFunctions {
|
||||
pub brightness_set: bool,
|
||||
pub stock_led_modes: Option<Vec<u8>>,
|
||||
pub per_key_led_mode: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlKbdBacklight {
|
||||
type A = LedSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
// let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||
let mut stock_led_modes = None;
|
||||
let mut per_key_led_mode = false;
|
||||
if let Some(laptop) = match_laptop() {
|
||||
let modes = laptop.supported_modes().to_vec();
|
||||
if modes.contains(&PER_KEY) {
|
||||
per_key_led_mode = true;
|
||||
let modes = modes.iter().filter(|x| **x != PER_KEY).copied().collect();
|
||||
stock_led_modes = Some(modes);
|
||||
} else {
|
||||
stock_led_modes = Some(modes);
|
||||
}
|
||||
}
|
||||
let multizone_led_mode = false;
|
||||
let per_key_led_mode = false;
|
||||
let laptop = LaptopLedData::get_data();
|
||||
let stock_led_modes = if laptop.standard.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(laptop.standard)
|
||||
};
|
||||
|
||||
LedSupportedFunctions {
|
||||
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
|
||||
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
|
||||
stock_led_modes,
|
||||
multizone_led_mode,
|
||||
per_key_led_mode,
|
||||
}
|
||||
}
|
||||
@@ -61,12 +46,10 @@ impl GetSupported for CtrlKbdBacklight {
|
||||
|
||||
pub struct CtrlKbdBacklight {
|
||||
led_node: Option<String>,
|
||||
#[allow(dead_code)]
|
||||
kbd_node: Option<String>,
|
||||
pub bright_node: String,
|
||||
supported_modes: Vec<u8>,
|
||||
supported_modes: LaptopLedData,
|
||||
flip_effect_write: bool,
|
||||
config: Arc<Mutex<Config>>,
|
||||
config: AuraConfig,
|
||||
}
|
||||
|
||||
pub struct DbusKbdBacklight {
|
||||
@@ -79,16 +62,10 @@ impl DbusKbdBacklight {
|
||||
}
|
||||
}
|
||||
|
||||
trait Dbus {
|
||||
fn set_led(&mut self, data: String);
|
||||
fn ledmode(&self) -> String;
|
||||
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
impl crate::ZbusAdd for DbusKbdBacklight {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Led", self)
|
||||
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
|
||||
.map_err(|err| {
|
||||
error!("DbusKbdBacklight: add_to_server {}", err);
|
||||
})
|
||||
@@ -96,48 +73,42 @@ impl crate::ZbusAdd for DbusKbdBacklight {
|
||||
}
|
||||
}
|
||||
|
||||
/// The main interface for changing, reading, or notfying signals
|
||||
///
|
||||
/// LED commands are split between Brightness, Modes, Per-Key
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl DbusKbdBacklight {
|
||||
fn set_led_mode(&mut self, data: String) {
|
||||
if let Ok(data) = serde_json::from_str(&data) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
match &data {
|
||||
AuraModes::PerKey(_) => {
|
||||
ctrl.do_command(data, &mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
_ => {
|
||||
if let Ok(json) = serde_json::to_string(&data) {
|
||||
match ctrl.do_command(data, &mut cfg) {
|
||||
Ok(_) => {
|
||||
self.notify_led(&json).ok();
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn set_brightness(&mut self, brightness: LedBrightness) {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
ctrl.set_brightness(brightness)
|
||||
.map_err(|err| warn!("{}", err))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_led_mode(&mut self, effect: AuraEffect) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
let mode_name = effect.mode_name();
|
||||
match ctrl.do_command(effect) {
|
||||
Ok(_) => {
|
||||
self.notify_led(&mode_name).ok();
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("SetKeyBacklight could not deserialise");
|
||||
}
|
||||
}
|
||||
|
||||
fn next_led_mode(&self) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
ctrl.toggle_mode(false, &mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
ctrl.toggle_mode(false)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
|
||||
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
self.notify_led(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
self.notify_led(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,40 +116,24 @@ impl DbusKbdBacklight {
|
||||
|
||||
fn prev_led_mode(&self) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
ctrl.toggle_mode(true, &mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
ctrl.toggle_mode(true)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
|
||||
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
self.notify_led(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
self.notify_led(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current mode data
|
||||
#[dbus_interface(property)]
|
||||
fn led_mode(&self) -> String {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
warn!("SetKeyBacklight could not deserialise");
|
||||
"SetKeyBacklight could not deserialise".to_string()
|
||||
}
|
||||
|
||||
/// Return a list of available modes
|
||||
fn led_modes(&self) -> String {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||
if let Ok(json) = serde_json::to_string(&cfg.kbd_backlight_modes) {
|
||||
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
|
||||
if let Ok(json) = serde_json::to_string(&mode) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -187,14 +142,25 @@ impl DbusKbdBacklight {
|
||||
"SetKeyBacklight could not deserialise".to_string()
|
||||
}
|
||||
|
||||
/// Return the current LED brightness
|
||||
fn led_brightness(&self) -> i8 {
|
||||
/// Return a list of available modes
|
||||
#[dbus_interface(property)]
|
||||
fn led_modes(&self) -> String {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||
return cfg.kbd_led_brightness as i8;
|
||||
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
warn!("SetKeyBacklight could not deserialise");
|
||||
"SetKeyBacklight could not serialise".to_string()
|
||||
}
|
||||
|
||||
/// Return the current LED brightness
|
||||
#[dbus_interface(property)]
|
||||
fn led_brightness(&self) -> i8 {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
|
||||
}
|
||||
warn!("SetKeyBacklight could not serialise");
|
||||
-1
|
||||
}
|
||||
|
||||
@@ -205,44 +171,40 @@ impl DbusKbdBacklight {
|
||||
impl crate::Reloadable for CtrlKbdBacklight {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
// set current mode (if any)
|
||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||
if self.supported_modes.len() > 1 {
|
||||
if self.supported_modes.contains(&config.kbd_backlight_mode) {
|
||||
let mode = config
|
||||
.get_led_mode_data(config.kbd_backlight_mode)
|
||||
.ok_or(RogError::NotSupported)?
|
||||
.to_owned();
|
||||
self.write_mode(&mode)?;
|
||||
info!("Reloaded last used mode");
|
||||
} else {
|
||||
warn!(
|
||||
"An unsupported mode was set: {}, reset to first mode available",
|
||||
<&str>::from(&<AuraModes>::from(config.kbd_backlight_mode))
|
||||
);
|
||||
for (idx, mode) in config.kbd_backlight_modes.iter_mut().enumerate() {
|
||||
if !self.supported_modes.contains(&mode.into()) {
|
||||
config.kbd_backlight_modes.remove(idx);
|
||||
config.write();
|
||||
break;
|
||||
}
|
||||
}
|
||||
config.kbd_backlight_mode = self.supported_modes[0];
|
||||
// TODO: do a recursive call with a boxed dyn future later
|
||||
let mode = config
|
||||
.get_led_mode_data(config.kbd_backlight_mode)
|
||||
.ok_or(RogError::NotSupported)?
|
||||
.to_owned();
|
||||
self.write_mode(&mode)?;
|
||||
info!("Reloaded last used mode");
|
||||
}
|
||||
if self.supported_modes.standard.len() > 1 {
|
||||
let current_mode = self.config.current_mode;
|
||||
if self.supported_modes.standard.contains(&(current_mode)) {
|
||||
let mode = self
|
||||
.config
|
||||
.builtins
|
||||
.get(¤t_mode)
|
||||
.ok_or(RogError::NotSupported)?
|
||||
.to_owned();
|
||||
self.write_mode(&mode)?;
|
||||
info!("Reloaded last used mode");
|
||||
} else {
|
||||
warn!(
|
||||
"An unsupported mode was set: {}, reset to first mode available",
|
||||
<&str>::from(&self.config.current_mode)
|
||||
);
|
||||
self.config.builtins.remove(¤t_mode);
|
||||
self.config.current_mode = AuraModeNum::Static;
|
||||
// TODO: do a recursive call with a boxed dyn future later
|
||||
let mode = self
|
||||
.config
|
||||
.builtins
|
||||
.get(¤t_mode)
|
||||
.ok_or(RogError::NotSupported)?
|
||||
.to_owned();
|
||||
self.write_mode(&mode)?;
|
||||
info!("Reloaded last used mode");
|
||||
}
|
||||
|
||||
// Reload brightness
|
||||
let bright = config.kbd_led_brightness;
|
||||
let bytes = aura_brightness_bytes(bright);
|
||||
self.write_bytes(&bytes)?;
|
||||
info!("Reloaded last used brightness");
|
||||
}
|
||||
|
||||
// Reload brightness
|
||||
let bright = self.config.brightness;
|
||||
self.set_brightness(bright)?;
|
||||
info!("Reloaded last used brightness");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -262,61 +224,50 @@ impl crate::CtrlTask for CtrlKbdBacklight {
|
||||
file.read_exact(&mut buf)
|
||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||
if config.kbd_led_brightness != num as u8 {
|
||||
config.read();
|
||||
config.kbd_led_brightness = num as u8;
|
||||
config.write();
|
||||
}
|
||||
if self.config.brightness != num.into() {
|
||||
self.config.read();
|
||||
self.config.brightness = num.into();
|
||||
self.config.write();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
Err(RogError::ParseLED)
|
||||
Err(RogError::ParseLed)
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlKbdBacklight {
|
||||
#[inline]
|
||||
pub fn new(
|
||||
id_product: &str,
|
||||
condev_iface: Option<&String>,
|
||||
supported_modes: Vec<u8>,
|
||||
config: Arc<Mutex<Config>>,
|
||||
) -> Result<Self, RogError> {
|
||||
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
|
||||
// TODO: return error if *all* nodes are None
|
||||
let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else(
|
||||
|err| {
|
||||
warn!("led_node: {}", err);
|
||||
None
|
||||
},
|
||||
Some,
|
||||
);
|
||||
|
||||
let kbd_node = Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node)
|
||||
.map_or_else(
|
||||
|err| {
|
||||
warn!("kbd_node: {}", err);
|
||||
None
|
||||
},
|
||||
Some,
|
||||
);
|
||||
let mut led_node = None;
|
||||
for prod in ASUS_KEYBOARD_DEVICES.iter() {
|
||||
match Self::find_led_node(prod) {
|
||||
Ok(node) => {
|
||||
led_node = Some(node);
|
||||
break;
|
||||
}
|
||||
Err(err) => warn!("led_node: {}", err),
|
||||
}
|
||||
}
|
||||
|
||||
let bright_node = Self::get_kbd_bright_path();
|
||||
|
||||
if led_node.is_none() && kbd_node.is_none() && Self::get_kbd_bright_path().is_err() {
|
||||
if led_node.is_none() && bright_node.is_none() {
|
||||
return Err(RogError::MissingFunction(
|
||||
"All keyboard features missing, you may require a v5.11 series kernel or newer"
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
|
||||
if bright_node.is_none() {
|
||||
return Err(RogError::MissingFunction(
|
||||
"No brightness control, you may require a v5.11 series kernel or newer".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let ctrl = CtrlKbdBacklight {
|
||||
// Using `ok` here so we can continue without keyboard features but
|
||||
// still get brightness control at least... maybe...
|
||||
led_node,
|
||||
kbd_node,
|
||||
// TODO: Check for existance
|
||||
bright_node: bright_node?.to_owned(),
|
||||
bright_node: bright_node.unwrap(), // If was none then we already returned above
|
||||
supported_modes,
|
||||
flip_effect_write: false,
|
||||
config,
|
||||
@@ -324,31 +275,47 @@ impl CtrlKbdBacklight {
|
||||
Ok(ctrl)
|
||||
}
|
||||
|
||||
fn get_kbd_bright_path() -> Result<&'static str, RogError> {
|
||||
fn get_kbd_bright_path() -> Option<String> {
|
||||
if Path::new(KBD_BRIGHT_PATH).exists() {
|
||||
Ok(KBD_BRIGHT_PATH)
|
||||
} else {
|
||||
Err(RogError::MissingFunction(
|
||||
"Keyboard features missing, you may require a v5.11 series kernel or newer".into(),
|
||||
))
|
||||
return Some(KBD_BRIGHT_PATH.to_string());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_node_failover(
|
||||
id_product: &str,
|
||||
iface: Option<&String>,
|
||||
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
|
||||
) -> Result<String, RogError> {
|
||||
match fun(id_product, iface) {
|
||||
Ok(o) => return Ok(o),
|
||||
Err(e) => {
|
||||
warn!("Looking for node: {}", e.to_string());
|
||||
}
|
||||
}
|
||||
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
|
||||
pub fn get_brightness(&self) -> Result<u8, RogError> {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&self.bright_node)
|
||||
.map_err(|err| match err.kind() {
|
||||
std::io::ErrorKind::NotFound => {
|
||||
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
|
||||
}
|
||||
_ => RogError::Path((&self.bright_node).into(), err),
|
||||
})?;
|
||||
let mut buf = [0u8; 1];
|
||||
file.read_exact(&mut buf)
|
||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||
Ok(buf[0])
|
||||
}
|
||||
|
||||
fn scan_led_node(id_product: &str, _: Option<&String>) -> Result<String, RogError> {
|
||||
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
|
||||
let path = Path::new(&self.bright_node);
|
||||
let mut file =
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.open(&path)
|
||||
.map_err(|err| match err.kind() {
|
||||
std::io::ErrorKind::NotFound => {
|
||||
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
|
||||
}
|
||||
_ => RogError::Path((&self.bright_node).into(), err),
|
||||
})?;
|
||||
file.write_all(&[brightness.as_char_code()])
|
||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_led_node(id_product: &str) -> Result<String, RogError> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("enumerator failed".into(), err)
|
||||
@@ -381,59 +348,13 @@ impl CtrlKbdBacklight {
|
||||
}
|
||||
}
|
||||
}
|
||||
warn!("Did not find a hidraw node for LED control, your device may be unsupported or require a kernel patch, see: {}", HELP_ADDRESS);
|
||||
Err(RogError::MissingFunction(
|
||||
"ASUS LED device node not found".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn scan_kbd_node(id_product: &str, iface: Option<&String>) -> Result<String, RogError> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
enumerator.match_subsystem("input").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
enumerator
|
||||
.match_property("ID_MODEL_ID", id_product)
|
||||
.map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("match_property failed".into(), err)
|
||||
})?;
|
||||
|
||||
for device in enumerator
|
||||
.scan_devices()
|
||||
.map_err(|err| {
|
||||
warn!("{}", err);
|
||||
err
|
||||
})
|
||||
.map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("scan_devices failed".into(), err)
|
||||
})?
|
||||
{
|
||||
if let Some(dev_node) = device.devnode() {
|
||||
if let Some(inum) = device.property_value("ID_USB_INTERFACE_NUM") {
|
||||
if let Some(iface) = iface {
|
||||
if inum == iface.as_str() {
|
||||
info!("Using device at: {:?} for keyboard polling", dev_node);
|
||||
return Ok(dev_node.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warn!("Did not find keyboard consumer device node, if expected functions are missing please file an issue at {}", HELP_ADDRESS);
|
||||
Err(RogError::MissingFunction(
|
||||
"ASUS keyboard 'Consumer Device' node not found".into(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn do_command(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
|
||||
self.set_and_save(mode, config)
|
||||
pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
|
||||
self.set_and_save(mode)
|
||||
}
|
||||
|
||||
/// Should only be used if the bytes you are writing are verified correct
|
||||
@@ -470,100 +391,61 @@ impl CtrlKbdBacklight {
|
||||
///
|
||||
/// This needs to be universal so that settings applied by dbus stick
|
||||
#[inline]
|
||||
fn set_and_save(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
|
||||
match mode {
|
||||
AuraModes::LedBrightness(n) => {
|
||||
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
|
||||
self.write_bytes(&bytes)?;
|
||||
config.read();
|
||||
config.kbd_led_brightness = n;
|
||||
config.write();
|
||||
info!("LED brightness set to {:#?}", n);
|
||||
}
|
||||
AuraModes::PerKey(v) => {
|
||||
if v.is_empty() || v[0].is_empty() {
|
||||
let bytes = KeyColourArray::get_init_msg();
|
||||
self.write_bytes(&bytes)?;
|
||||
} else {
|
||||
self.write_effect(&v)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
config.read();
|
||||
let mode_num: u8 = u8::from(&mode);
|
||||
self.write_mode(&mode)?;
|
||||
config.kbd_backlight_mode = mode_num;
|
||||
config.set_mode_data(mode);
|
||||
config.write();
|
||||
}
|
||||
}
|
||||
fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> {
|
||||
self.config.read();
|
||||
self.write_mode(&mode)?;
|
||||
self.config.current_mode = *mode.mode();
|
||||
self.config.set_builtin(mode);
|
||||
self.config.write();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
|
||||
let current = config.kbd_backlight_mode;
|
||||
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
|
||||
fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> {
|
||||
let current = self.config.current_mode;
|
||||
if let Some(idx) = self
|
||||
.supported_modes
|
||||
.standard
|
||||
.iter()
|
||||
.position(|v| *v == current)
|
||||
{
|
||||
let mut idx = idx;
|
||||
// goes past end of array
|
||||
if reverse {
|
||||
if idx == 0 {
|
||||
idx = self.supported_modes.len() - 1;
|
||||
idx = self.supported_modes.standard.len() - 1;
|
||||
} else {
|
||||
idx -= 1;
|
||||
}
|
||||
} else {
|
||||
idx += 1;
|
||||
if idx == self.supported_modes.len() {
|
||||
if idx == self.supported_modes.standard.len() {
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
let next = self.supported_modes[idx];
|
||||
let next = self.supported_modes.standard[idx];
|
||||
|
||||
config.read();
|
||||
if let Some(data) = config.get_led_mode_data(next) {
|
||||
self.config.read();
|
||||
if let Some(data) = self.config.builtins.get(&next) {
|
||||
self.write_mode(&data)?;
|
||||
config.kbd_backlight_mode = next;
|
||||
self.config.current_mode = next;
|
||||
}
|
||||
config.write();
|
||||
self.config.write();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
|
||||
let mode_num: u8 = u8::from(mode);
|
||||
if !self.supported_modes.contains(&mode_num) {
|
||||
fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> {
|
||||
if !self.supported_modes.standard.contains(&mode.mode()) {
|
||||
return Err(RogError::NotSupported);
|
||||
}
|
||||
match mode {
|
||||
AuraModes::PerKey(v) => {
|
||||
if v.is_empty() || v[0].is_empty() {
|
||||
let bytes = KeyColourArray::get_init_msg();
|
||||
self.write_bytes(&bytes)?;
|
||||
} else {
|
||||
self.write_effect(v)?;
|
||||
}
|
||||
}
|
||||
AuraModes::MultiStatic(_) | AuraModes::MultiBreathe(_) => {
|
||||
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
|
||||
for array in bytes.iter() {
|
||||
self.write_bytes(array)?;
|
||||
}
|
||||
self.write_bytes(&LED_SET)?;
|
||||
// Changes won't persist unless apply is set
|
||||
self.write_bytes(&LED_APPLY)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
||||
self.write_bytes(&bytes)?;
|
||||
self.write_bytes(&LED_SET)?;
|
||||
// Changes won't persist unless apply is set
|
||||
self.write_bytes(&LED_APPLY)?;
|
||||
}
|
||||
}
|
||||
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
||||
self.write_bytes(&bytes)?;
|
||||
self.write_bytes(&LED_SET)?;
|
||||
// Changes won't persist unless apply is set
|
||||
self.write_bytes(&LED_APPLY)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
use log::{error, info, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use rog_types::supported::RogBiosSupportedFunctions;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::BufRead;
|
||||
use std::io::{Read, Write};
|
||||
@@ -9,6 +9,7 @@ use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
|
||||
const DRACUT_PATH: &str = "/usr/bin/dracut";
|
||||
@@ -22,12 +23,6 @@ pub struct CtrlRogBios {
|
||||
_config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RogBiosSupportedFunctions {
|
||||
pub post_sound_toggle: bool,
|
||||
pub dedicated_gfx_toggle: bool,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlRogBios {
|
||||
type A = RogBiosSupportedFunctions;
|
||||
|
||||
@@ -101,7 +96,10 @@ impl CtrlRogBios {
|
||||
impl crate::ZbusAdd for CtrlRogBios {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/RogBios", self)
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/RogBios"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlRogBios: add_to_server {}", err);
|
||||
err
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use log::warn;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::{
|
||||
ctrl_anime::{AnimeSupportedFunctions, CtrlAnimeDisplay},
|
||||
ctrl_charge::{ChargeSupportedFunctions, CtrlCharge},
|
||||
ctrl_fan_cpu::{CtrlFanAndCPU, FanCpuSupportedFunctions},
|
||||
ctrl_leds::{CtrlKbdBacklight, LedSupportedFunctions},
|
||||
ctrl_rog_bios::{CtrlRogBios, RogBiosSupportedFunctions},
|
||||
GetSupported,
|
||||
ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
|
||||
ctrl_leds::CtrlKbdBacklight, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
||||
};
|
||||
|
||||
use rog_types::supported::{
|
||||
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
||||
LedSupportedFunctions, RogBiosSupportedFunctions,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -30,7 +32,10 @@ impl SupportedFunctions {
|
||||
impl crate::ZbusAdd for SupportedFunctions {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at("/org/asuslinux/Supported", self)
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Supported"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("SupportedFunctions: add_to_server {}", err);
|
||||
err
|
||||
@@ -47,7 +52,7 @@ impl GetSupported for SupportedFunctions {
|
||||
keyboard_led: CtrlKbdBacklight::get_supported(),
|
||||
anime_ctrl: CtrlAnimeDisplay::get_supported(),
|
||||
charge_ctrl: CtrlCharge::get_supported(),
|
||||
fan_cpu_ctrl: CtrlFanAndCPU::get_supported(),
|
||||
fan_cpu_ctrl: CtrlFanAndCpu::get_supported(),
|
||||
rog_bios_ctrl: CtrlRogBios::get_supported(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use daemon::ctrl_charge::CtrlCharge;
|
||||
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
|
||||
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
||||
use daemon::laptops::match_laptop;
|
||||
use daemon::{
|
||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||
};
|
||||
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
||||
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
|
||||
use daemon::{
|
||||
ctrl_fan_cpu::{CtrlFanAndCpu, DbusFanAndCpu},
|
||||
laptops::LaptopLedData,
|
||||
};
|
||||
|
||||
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||
use log::LevelFilter;
|
||||
@@ -21,6 +23,7 @@ use daemon::ctrl_rog_bios::CtrlRogBios;
|
||||
use std::convert::Into;
|
||||
use zbus::fdo;
|
||||
use zbus::Connection;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut logger = env_logger::Builder::new();
|
||||
@@ -50,12 +53,9 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
print_board_info();
|
||||
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
|
||||
|
||||
let laptop = match_laptop();
|
||||
let config = if let Some(laptop) = laptop.as_ref() {
|
||||
Config::load(laptop.supported_modes())
|
||||
} else {
|
||||
Config::load(&[])
|
||||
};
|
||||
let config = Config::load();
|
||||
let enable_gfx_switching = config.gfx_managed;
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
let connection = Connection::new_system()?;
|
||||
fdo::DBusProxy::new(&connection)?
|
||||
@@ -64,9 +64,6 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
supported.add_to_server(&mut object_server);
|
||||
|
||||
let enable_gfx_switching = config.gfx_managed;
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
match CtrlRogBios::new(config.clone()) {
|
||||
Ok(mut ctrl) => {
|
||||
// Do a reload of any settings
|
||||
@@ -113,7 +110,12 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||
let devices = ctrl.devices();
|
||||
let bus = ctrl.bus();
|
||||
CtrlGraphics::do_vendor_tasks(GfxVendors::Nvidia, &devices, &bus)?;
|
||||
CtrlGraphics::do_vendor_tasks(
|
||||
GfxVendors::Nvidia,
|
||||
false,
|
||||
&devices,
|
||||
&bus,
|
||||
)?;
|
||||
} else if ded == 0 {
|
||||
info!("Dedicated GFX toggle is off");
|
||||
}
|
||||
@@ -133,7 +135,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
// Collect tasks for task thread
|
||||
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
|
||||
|
||||
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config.clone()).map_err(|err| {
|
||||
if let Ok(mut ctrl) = CtrlFanAndCpu::new(config).map_err(|err| {
|
||||
error!("Profile control: {}", err);
|
||||
}) {
|
||||
ctrl.reload()
|
||||
@@ -142,27 +144,21 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
|
||||
};
|
||||
|
||||
if let Some(laptop) = laptop {
|
||||
if let Ok(ctrl) = CtrlKbdBacklight::new(
|
||||
laptop.usb_product(),
|
||||
laptop.condev_iface(),
|
||||
laptop.supported_modes().to_owned(),
|
||||
config,
|
||||
)
|
||||
.map_err(|err| {
|
||||
error!("Keyboard control: {}", err);
|
||||
err
|
||||
}) {
|
||||
let tmp = Arc::new(Mutex::new(ctrl));
|
||||
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
||||
tasks.push(tmp);
|
||||
}
|
||||
let laptop = LaptopLedData::get_data();
|
||||
let aura_config = AuraConfig::load(&laptop);
|
||||
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
|
||||
error!("Keyboard control: {}", err);
|
||||
err
|
||||
}) {
|
||||
let tmp = Arc::new(Mutex::new(ctrl));
|
||||
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
||||
tasks.push(tmp);
|
||||
}
|
||||
|
||||
// TODO: implement messaging between threads to check fails
|
||||
// These tasks generally read a sys path or file to check for a
|
||||
// change
|
||||
let _handle = std::thread::Builder::new()
|
||||
let handle = std::thread::Builder::new()
|
||||
.name("asusd watch".to_string())
|
||||
.spawn(move || loop {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
@@ -179,18 +175,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
});
|
||||
|
||||
object_server
|
||||
.with("/org/asuslinux/Charge", |obj: &CtrlCharge| {
|
||||
let x = obj.limit();
|
||||
obj.notify_charge(x as u8)
|
||||
})
|
||||
.with(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
|
||||
|obj: &CtrlCharge| {
|
||||
let x = obj.limit();
|
||||
obj.notify_charge(x as u8)
|
||||
},
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("object_server notify_charge error: {}", err);
|
||||
})
|
||||
.ok();
|
||||
|
||||
loop {
|
||||
if let Err(err) = &handle {
|
||||
error!("{}", err);
|
||||
}
|
||||
if let Err(err) = object_server.try_handle_next() {
|
||||
eprintln!("{}", err);
|
||||
error!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::ctrl_gfx::error::GfxError;
|
||||
pub enum RogError {
|
||||
ParseFanLevel,
|
||||
ParseVendor,
|
||||
ParseLED,
|
||||
ParseLed,
|
||||
MissingProfile(String),
|
||||
Udev(String, std::io::Error),
|
||||
Path(String, std::io::Error),
|
||||
@@ -28,6 +28,7 @@ pub enum RogError {
|
||||
Initramfs(String),
|
||||
Modprobe(String),
|
||||
Command(String, std::io::Error),
|
||||
Io(std::io::Error),
|
||||
Zbus(zbus::Error),
|
||||
}
|
||||
|
||||
@@ -37,7 +38,7 @@ impl fmt::Display for RogError {
|
||||
match self {
|
||||
RogError::ParseFanLevel => write!(f, "Parse profile error"),
|
||||
RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
|
||||
RogError::ParseLED => write!(f, "Parse LED error"),
|
||||
RogError::ParseLed => write!(f, "Parse LED error"),
|
||||
RogError::MissingProfile(profile) => write!(f, "Profile does not exist {}", profile),
|
||||
RogError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
|
||||
RogError::Path(path, error) => write!(f, "Path {}: {}", path, error),
|
||||
@@ -55,6 +56,7 @@ impl fmt::Display for RogError {
|
||||
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
|
||||
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
|
||||
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
||||
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
|
||||
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,7 @@ impl From<GraphicsError> for RogError {
|
||||
fn from(err: GraphicsError) -> Self {
|
||||
match err {
|
||||
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
|
||||
GraphicsError::ParsePower => RogError::GfxSwitching(GfxError::ParsePower),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,3 +90,9 @@ impl From<zbus::Error> for RogError {
|
||||
RogError::Zbus(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for RogError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
RogError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +1,11 @@
|
||||
use log::{info, warn};
|
||||
use rog_types::aura_modes::{AuraModes, BREATHING, STATIC};
|
||||
use rog_types::aura_modes::AuraModeNum;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Read;
|
||||
|
||||
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
|
||||
|
||||
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
||||
|
||||
static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LaptopBase {
|
||||
usb_product: String,
|
||||
condev_iface: Option<String>, // required for finding the Consumer Device interface
|
||||
supported_modes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl LaptopBase {
|
||||
pub fn usb_product(&self) -> &str {
|
||||
&self.usb_product
|
||||
}
|
||||
pub fn condev_iface(&self) -> Option<&String> {
|
||||
self.condev_iface.as_ref()
|
||||
}
|
||||
pub fn supported_modes(&self) -> &[u8] {
|
||||
&self.supported_modes
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_laptop() -> Option<LaptopBase> {
|
||||
for device in rusb::devices().expect("Couldn't get device").iter() {
|
||||
let device_desc = device
|
||||
.device_descriptor()
|
||||
.expect("Couldn't get device descriptor");
|
||||
if device_desc.vendor_id() == 0x0b05 && LAPTOP_DEVICES.contains(&device_desc.product_id()) {
|
||||
let prod_str = format!("{:x?}", device_desc.product_id());
|
||||
|
||||
if device_desc.product_id() == 0x1854 {
|
||||
let mut laptop = laptop(prod_str, None);
|
||||
if laptop.supported_modes.is_empty() {
|
||||
laptop.supported_modes = vec![STATIC, BREATHING];
|
||||
}
|
||||
return Some(laptop);
|
||||
}
|
||||
|
||||
let laptop = laptop(prod_str, Some("02".to_owned()));
|
||||
return Some(laptop);
|
||||
}
|
||||
}
|
||||
warn!(
|
||||
"Unsupported laptop, please request support at {}",
|
||||
HELP_ADDRESS
|
||||
);
|
||||
warn!("Continuing with minimal support");
|
||||
None
|
||||
}
|
||||
|
||||
fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||
|
||||
let mut laptop = LaptopBase {
|
||||
usb_product: prod,
|
||||
condev_iface,
|
||||
supported_modes: vec![],
|
||||
};
|
||||
|
||||
if let Some(modes) = LEDModeGroup::load_from_config() {
|
||||
if let Some(led_modes) = modes.matcher(&prod_family, &board_name) {
|
||||
laptop.supported_modes = led_modes;
|
||||
return laptop;
|
||||
}
|
||||
}
|
||||
laptop
|
||||
}
|
||||
pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml";
|
||||
pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"];
|
||||
|
||||
pub fn print_board_info() {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
@@ -92,12 +22,12 @@ pub fn print_modes(supported_modes: &[u8]) {
|
||||
if !supported_modes.is_empty() {
|
||||
info!("Supported Keyboard LED modes are:");
|
||||
for mode in supported_modes {
|
||||
let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||
let mode = <&str>::from(&<AuraModeNum>::from(*mode));
|
||||
info!("- {}", mode);
|
||||
}
|
||||
info!(
|
||||
"If these modes are incorrect or missing please request support at {}",
|
||||
HELP_ADDRESS
|
||||
"If these modes are incorrect you can edit {}",
|
||||
ASUS_LED_MODE_CONF
|
||||
);
|
||||
} else {
|
||||
info!("No RGB control available");
|
||||
@@ -105,19 +35,50 @@ pub fn print_modes(supported_modes: &[u8]) {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct LEDModeGroup {
|
||||
led_modes: Vec<LEDModes>,
|
||||
struct LedSupportFile {
|
||||
led_data: Vec<LaptopLedData>,
|
||||
}
|
||||
|
||||
impl LEDModeGroup {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct LaptopLedData {
|
||||
pub prod_family: String,
|
||||
pub board_names: Vec<String>,
|
||||
pub standard: Vec<AuraModeNum>,
|
||||
pub multizone: bool,
|
||||
pub per_key: bool,
|
||||
}
|
||||
|
||||
impl LaptopLedData {
|
||||
pub fn get_data() -> Self {
|
||||
let dmi = sysfs_class::DmiId::default();
|
||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||
|
||||
if let Some(modes) = LedSupportFile::load_from_config() {
|
||||
if let Some(data) = modes.matcher(&prod_family, &board_name) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
info!("Using generic LED control for keyboard brightness only");
|
||||
LaptopLedData {
|
||||
prod_family,
|
||||
board_names: vec![board_name],
|
||||
standard: vec![],
|
||||
multizone: false,
|
||||
per_key: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LedSupportFile {
|
||||
/// Consumes the LEDModes
|
||||
fn matcher(self, prod_family: &str, board_name: &str) -> Option<Vec<u8>> {
|
||||
for led_modes in self.led_modes {
|
||||
if prod_family.contains(&led_modes.prod_family) {
|
||||
for board in led_modes.board_names {
|
||||
if board_name.contains(&board) {
|
||||
info!("Matched to {} {}", led_modes.prod_family, board);
|
||||
return Some(led_modes.led_modes);
|
||||
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
|
||||
for config in self.led_data {
|
||||
if prod_family.contains(&config.prod_family) {
|
||||
for board in &config.board_names {
|
||||
if board_name.contains(board) {
|
||||
info!("Matched to {} {}", config.prod_family, board);
|
||||
return Some(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,26 +87,19 @@ impl LEDModeGroup {
|
||||
}
|
||||
|
||||
fn load_from_config() -> Option<Self> {
|
||||
if let Ok(mut file) = OpenOptions::new().read(true).open(&LEDMODE_CONFIG_PATH) {
|
||||
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_CONF) {
|
||||
let mut buf = String::new();
|
||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||
if l == 0 {
|
||||
warn!("{} is empty", LEDMODE_CONFIG_PATH);
|
||||
warn!("{} is empty", ASUS_LED_MODE_CONF);
|
||||
} else {
|
||||
return Some(toml::from_str(&buf).unwrap_or_else(|_| {
|
||||
panic!("Could not deserialise {}", LEDMODE_CONFIG_PATH)
|
||||
panic!("Could not deserialise {}", ASUS_LED_MODE_CONF)
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
warn!("Does {} exist?", LEDMODE_CONFIG_PATH);
|
||||
warn!("Does {} exist?", ASUS_LED_MODE_CONF);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct LEDModes {
|
||||
prod_family: String,
|
||||
board_names: Vec<String>,
|
||||
led_modes: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![deny(unused_must_use)]
|
||||
/// Configuration loading, saving
|
||||
pub mod config;
|
||||
pub mod config_aura;
|
||||
pub(crate) mod config_old;
|
||||
/// Control of AniMe matrix display
|
||||
pub mod ctrl_anime;
|
||||
|
||||
BIN
data/anime/asus/festive/Cupid.gif
Executable file
|
After Width: | Height: | Size: 72 KiB |
BIN
data/anime/asus/festive/Firework.gif
Executable file
|
After Width: | Height: | Size: 61 KiB |
BIN
data/anime/asus/festive/Halloween.gif
Executable file
|
After Width: | Height: | Size: 137 KiB |
BIN
data/anime/asus/festive/Happy Holiday.gif
Executable file
|
After Width: | Height: | Size: 109 KiB |
BIN
data/anime/asus/festive/Happy new year.gif
Executable file
|
After Width: | Height: | Size: 99 KiB |
BIN
data/anime/asus/festive/Lantern.gif
Executable file
|
After Width: | Height: | Size: 85 KiB |
BIN
data/anime/asus/festive/Valentine's Day.gif
Executable file
|
After Width: | Height: | Size: 48 KiB |
BIN
data/anime/asus/festive/Year of the Ox.gif
Executable file
|
After Width: | Height: | Size: 60 KiB |
BIN
data/anime/asus/gaming/Bird.gif
Executable file
|
After Width: | Height: | Size: 96 KiB |
BIN
data/anime/asus/gaming/Controller.gif
Executable file
|
After Width: | Height: | Size: 32 KiB |
BIN
data/anime/asus/gaming/FPS.gif
Executable file
|
After Width: | Height: | Size: 54 KiB |
BIN
data/anime/asus/gaming/Fight.gif
Executable file
|
After Width: | Height: | Size: 234 KiB |
BIN
data/anime/asus/gaming/Keyboard.gif
Executable file
|
After Width: | Height: | Size: 34 KiB |
BIN
data/anime/asus/gaming/MOBA.gif
Executable file
|
After Width: | Height: | Size: 49 KiB |
BIN
data/anime/asus/gaming/UFO.gif
Executable file
|
After Width: | Height: | Size: 63 KiB |
BIN
data/anime/asus/music/DJ.gif
Executable file
|
After Width: | Height: | Size: 119 KiB |
BIN
data/anime/asus/music/Music-player.gif
Executable file
|
After Width: | Height: | Size: 132 KiB |
BIN
data/anime/asus/rog/For-those-who-dare.gif
Executable file
|
After Width: | Height: | Size: 90 KiB |
BIN
data/anime/asus/rog/For-those-who-dare_2.gif
Executable file
|
After Width: | Height: | Size: 64 KiB |
BIN
data/anime/asus/rog/Fragment.gif
Executable file
|
After Width: | Height: | Size: 16 KiB |
BIN
data/anime/asus/rog/Infinite-triangle.gif
Executable file
|
After Width: | Height: | Size: 56 KiB |
BIN
data/anime/asus/rog/Kaleidoscope1.gif
Executable file
|
After Width: | Height: | Size: 31 KiB |
BIN
data/anime/asus/rog/Kaleidoscope2.gif
Executable file
|
After Width: | Height: | Size: 46 KiB |
BIN
data/anime/asus/rog/Kaleidoscope2.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
data/anime/asus/rog/Sunset.gif
Executable file
|
After Width: | Height: | Size: 40 KiB |
BIN
data/anime/asus/trend/Dog.gif
Executable file
|
After Width: | Height: | Size: 120 KiB |
BIN
data/anime/asus/trend/Ski.gif
Executable file
|
After Width: | Height: | Size: 112 KiB |
BIN
data/anime/asus/trend/Wave.gif
Executable file
|
After Width: | Height: | Size: 73 KiB |
BIN
data/anime/custom/nyancat_zombie.gif
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
data/anime/custom/rust.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
data/anime/custom/sonic-run.gif
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
data/anime/custom/sonic-wait.gif
Normal file
|
After Width: | Height: | Size: 28 KiB |
@@ -1,59 +1,90 @@
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus S"
|
||||
board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
|
||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 255]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus M"
|
||||
board_names = ["GU502GV"]
|
||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 255]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus M15"
|
||||
board_names = ["GU502LW"]
|
||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 255]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus M15"
|
||||
board_names = ["GU502LU"]
|
||||
led_modes = [0, 1, 2, 10]
|
||||
standard = ["Static", "Breathe", "Strobe", "Pulse"]
|
||||
multizone = false
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Zephyrus"
|
||||
board_names = ["GM501GM", "GX531"]
|
||||
led_modes = [0, 1, 2, 3, 10, 13]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = true
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G531GW"]
|
||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 255]
|
||||
board_names = ["G531GW", "G733QS", "G733QR"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
per_key = true
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["GX531", "G512LV", "G712LV"]
|
||||
led_modes = [0, 1, 2, 3, 10, 13, 14]
|
||||
board_names = ["GX531", "G512LV", "G712LV", "G712LW"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = true
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G512LI", "G712LI", "G531GD"]
|
||||
led_modes = [0, 1, 2, 3, 10]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||
multizone = false
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["G731GV", "G731GW", "G531GV"]
|
||||
led_modes = [0, 1, 2, 3, 13, 14]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow"]
|
||||
multizone = true
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Strix"
|
||||
board_names = ["G731GT", "G731GU", "G531GT", "G531GU"]
|
||||
led_modes = [0, 1, 2, 3]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow"]
|
||||
multizone = false
|
||||
per_key = false
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "Strix Scar"
|
||||
board_names = ["G531", "G731"]
|
||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 255]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = true
|
||||
per_key = true
|
||||
|
||||
[[led_modes]]
|
||||
[[led_data]]
|
||||
prod_family = "ROG"
|
||||
board_names = ["GL553VE"]
|
||||
led_modes = [0, 1, 2, 13, 14]
|
||||
standard = ["Static", "Breathe", "Strobe"]
|
||||
multizone = true
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G14"
|
||||
board_names = ["GA401Q"]
|
||||
standard = ["Static", "Breathe", "Pulse"]
|
||||
multizone = false
|
||||
per_key = false
|
||||
14
data/asusd-user.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ASUS User Daemon
|
||||
StartLimitInterval=200
|
||||
StartLimitBurst=2
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/sleep 2
|
||||
ExecStart=/usr/bin/asusd-user
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
Type=simple
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
64
data/user-example.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"anime": [
|
||||
{
|
||||
"AsusAnimation": {
|
||||
"file": "/usr/share/asusd/anime/asus/rog/Sunset.gif",
|
||||
"time": {
|
||||
"Cycles": 1
|
||||
},
|
||||
"brightness": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"ImageAnimation": {
|
||||
"file": "/usr/share/asusd/anime/custom/sonic-run.gif",
|
||||
"scale": 0.9,
|
||||
"angle": 0.65,
|
||||
"translation": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"time": {
|
||||
"Time": {
|
||||
"secs": 5,
|
||||
"nanos": 0
|
||||
}
|
||||
},
|
||||
"brightness": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"Image": {
|
||||
"file": "/usr/share/asusd/anime/custom/rust.png",
|
||||
"scale": 1.0,
|
||||
"angle": 0.0,
|
||||
"translation": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"brightness": 0.6
|
||||
}
|
||||
},
|
||||
{
|
||||
"Pause": {
|
||||
"secs": 6,
|
||||
"nanos": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"ImageAnimation": {
|
||||
"file": "/usr/share/asusd/anime/custom/sonic-wait.gif",
|
||||
"scale": 0.9,
|
||||
"angle": 0.0,
|
||||
"translation": [
|
||||
3.0,
|
||||
2.0
|
||||
],
|
||||
"time": {
|
||||
"Cycles": 2
|
||||
},
|
||||
"brightness": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
31
rog-anime/Cargo.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "rog_anime"
|
||||
version = "1.0.2"
|
||||
license = "MPL-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||
documentation = "https://docs.rs/rog-anime"
|
||||
description = "Types useful for translating images and other data for display on the ASUS AniMe Matrix display"
|
||||
keywords = ["ROG", "ASUS", "AniMe"]
|
||||
edition = "2018"
|
||||
exclude = ["data"]
|
||||
|
||||
[features]
|
||||
default = ["dbus"]
|
||||
dbus = ["zbus", "zvariant", "zvariant_derive"]
|
||||
|
||||
[dependencies]
|
||||
png_pong = "^0.8.0"
|
||||
pix = "0.13"
|
||||
gif = "^0.11.2"
|
||||
|
||||
serde = "^1.0"
|
||||
serde_derive = "^1.0"
|
||||
|
||||
glam = { version = "0.14.0", features = ["serde"] }
|
||||
|
||||
zbus = { version = "^1.9.1", optional = true }
|
||||
zvariant = { version = "^2.6", optional = true }
|
||||
zvariant_derive = { version = "^2.6", optional = true }
|
||||
373
rog-anime/LICENSE
Normal file
@@ -0,0 +1,373 @@
|
||||
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.
|
||||