Compare commits

..

43 Commits
3.3.0 ... 3.5.1

Author SHA1 Message Date
Luke Jones
3ea0737be9 Merge branch 'fluke/refactor-patterns' into 'main'
Fluke/refactor patterns

See merge request asus-linux/asusctl!55
2021-04-26 03:53:21 +00:00
Luke D. Jones
c67373a830 bugfix: add version to user daemon. Fix multiple anime config 2021-04-26 15:49:35 +12:00
Luke D. Jones
41cbf4d353 Refactor dameon gfx 2021-04-25 22:53:38 +12:00
Luke Jones
7a4c14f7b8 Merge branch 'fluke/aura-crate' into 'main'
Release prep

See merge request asus-linux/asusctl!54
2021-04-25 03:07:13 +00:00
Luke D. Jones
f52a4d464a Release prep 2021-04-25 14:52:26 +12:00
Luke Jones
aa71592a31 Merge branch 'fluke/aura-crate' into 'main'
profiles: add dbus methods to change active profile

Closes #68, #73, and #81

See merge request asus-linux/asusctl!53
2021-04-25 02:37:31 +00:00
Luke D. Jones
dc6e8f8dcb profiles: add dbus methods to change active profile
Closes #81, #73, #68
2021-04-25 14:33:41 +12:00
Luke D. Jones
1a4836246f aura: support keyboard LED enable/disable with awake/sleep 2021-04-25 12:28:09 +12:00
Luke D. Jones
ab80b0742f gfx: asusd config option to not save compute/vfio mode switch 2021-04-20 21:10:23 +12:00
Luke D. Jones
6926aeed20 gfx: enable correct rebootless compute mode switch 2021-04-20 19:33:55 +12:00
Luke D Jones
f95e42e4b9 Reload LED mode on boot 2021-04-19 10:05:37 +12:00
Luke D Jones
82bee6b86e Update asusd unit for selinux 2021-04-15 19:43:09 +12:00
Luke D Jones
bd9bc8bcff anime: services for system sequences 2021-04-14 23:14:57 +12:00
Luke D Jones
8a6d364304 anime: initial system config work 2021-04-12 17:35:04 +12:00
Luke D Jones
64d99a3e05 gfx: partial save and recover of mode change
Properly set and recover to last mode for g-sync laptops

Partial close of #75
2021-04-12 10:49:08 +12:00
Luke D Jones
59f54b76f6 aura: split out all aura related files to rog-aura crate 2021-04-12 10:31:36 +12:00
Luke D Jones
6f36d91281 Begin rog-aura crate 2021-04-12 10:31:36 +12:00
Luke D Jones
e9f1fa01fc index on anime-cli: 0657c6c anime: prep rog-anime for publish, rename *all* AniMe~ to Anime 2021-04-12 10:31:36 +12:00
Luke D Jones
0d3a5d266b Changelog 2021-04-12 10:31:07 +12:00
Luke D Jones
cc28cee8bd anime: fix init 2021-04-11 22:47:21 +12:00
Luke D Jones
6ebf0c2bb2 Update makefile 2021-04-11 20:39:15 +12:00
Luke D Jones
77c658c94e Release 3.4.0 2021-04-11 20:36:31 +12:00
Luke Jones
df64a51372 Merge branch 'fluke/anime-cli' into 'main'
anime: prep rog-anime for publish, rename *all* AniMe~ to Anime

See merge request asus-linux/asusctl!50
2021-04-11 06:54:05 +00:00
Luke D Jones
0657c6cc74 anime: prep rog-anime for publish, rename *all* AniMe~ to Anime 2021-04-11 16:26:52 +12:00
Luke Jones
f116905e85 Merge branch 'fluke/anime-cli' into 'main'
anime: add zbus methods

See merge request asus-linux/asus-nb-ctrl!49
2021-04-10 09:58:56 +00:00
Luke D Jones
e515741efa anime: add zbus methods 2021-04-10 21:54:08 +12:00
Luke Jones
d516abdc92 Merge branch 'fluke/anime-cli' into 'main'
anime: tweak gif animation time types

See merge request asus-linux/asus-nb-ctrl!48
2021-04-09 11:21:35 +00:00
Luke D Jones
ece565de1c anime: tweak gif animation time types 2021-04-09 23:17:50 +12:00
Luke Jones
eb83d1a835 Merge branch 'fluke/anime-cli' into 'main'
anime: CLI and user-daemon work

See merge request asus-linux/asus-nb-ctrl!47
2021-04-09 08:45:06 +00:00
Luke D Jones
7d0f15d738 anime: CLI and user-daemon work 2021-04-09 20:41:25 +12:00
Luke Jones
8010da0891 Merge branch 'fluke/anime-cli' into 'main'
Fluke/anime cli

See merge request asus-linux/asus-nb-ctrl!46
2021-04-07 07:28:35 +00:00
Luke D Jones
aa500c35c4 daemon: revert zbus to 1.9.1 in daemon 2021-04-07 15:05:55 +12:00
Luke D Jones
2af33a0416 daemon: revert zbus to 1.9.1 in daemon 2021-04-07 15:05:26 +12:00
Luke D Jones
9b4ed6eb62 anime: discard frames if specified 2021-04-06 22:03:06 +12:00
Luke D Jones
47c1ca9fe4 anime: gif-image 2021-04-06 21:43:57 +12:00
Luke Jones
3cd624daf0 Merge branch 'fluke/anime-cli' into 'main'
Anime: Tweak the diagonal data to be more correct

See merge request asus-linux/asus-nb-ctrl!45
2021-04-06 02:01:41 +00:00
Luke D Jones
fa16864a3e Tweak the diagonal to be more correct 2021-04-06 13:56:02 +12:00
Luke Jones
bfc31b06d5 Merge branch 'fluke/anime-diag' into 'main'
Fluke/anime diag

See merge request asus-linux/asus-nb-ctrl!44
2021-04-05 09:12:04 +00:00
Luke D Jones
d854f7da1b Prepare for user saving of anime sequences 2021-04-05 21:06:53 +12:00
Luke D Jones
6d746b21a5 Anime gifs 2021-04-05 17:12:00 +12:00
Luke D Jones
226c083a51 Diagonal data structure 2021-04-05 00:02:05 +12:00
Luke Jones
de59d00949 Merge branch 'fluke/gfx-zbus-cleanup' into 'main'
Fluke/gfx zbus cleanup (incorrectly named branch)

Closes #72

See merge request asus-linux/asus-nb-ctrl!42
2021-04-03 08:46:17 +00:00
Luke D Jones
7ff01f12e9 Add extra models to ledmodes
- Configurable anime example
- Gfx power states as enum

Closes #72
2021-04-03 21:42:39 +13:00
137 changed files with 8317 additions and 1623 deletions

View File

@@ -5,6 +5,45 @@ 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.5.1] - 2021-04-25
### Changed
+ Anime:
- Fix using multiple configs
# [3.5.0] - 2021-04-25
### Changed
+ Keyboard:
- Split out all aura functionality that isn't dependent on the daemon in to a
new crate `rog-aura` (incomplete)
- Keyboard LED control now includes:
+ Enable/disable LED's while laptop is awake
+ Enable/disable LED animation while laptop is suspended and AC plugged in
- Properly reload the last used keyboard mode on boot
+ Graphics:
- Correctly enable compute mode for nvidia plus no-reboot or logout if switching
from vfio/integrated/compute.
- Add asusd config option to not save compute/vfio mode switch.
+ Anime:
- Enable basic multiple user anime configs (asusd-user must still be restarted)
+ Profiles:
- Enable dbus methods for freq min/max, fan curve, fan preset, CPU turbo enable.
These options will apply to the active profile if no profile name is specified.
# [3.4.1] - 2021-04-11
### Changed
- Fix anime init sequence
# [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

431
Cargo.lock generated
View File

@@ -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"
@@ -34,10 +42,14 @@ dependencies = [
[[package]]
name = "asusctl"
version = "3.1.5"
version = "3.5.0"
dependencies = [
"daemon",
"gif",
"glam",
"gumdrop",
"rog_anime",
"rog_aura",
"rog_dbus",
"rog_types",
"serde_json",
@@ -65,15 +77,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"
@@ -169,6 +172,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"
@@ -197,12 +206,14 @@ dependencies = [
[[package]]
name = "daemon"
version = "3.3.0"
version = "3.5.1"
dependencies = [
"env_logger",
"intel-pstate",
"log",
"logind-zbus",
"rog_anime",
"rog_aura",
"rog_dbus",
"rog_fan_curve",
"rog_types",
@@ -213,10 +224,26 @@ dependencies = [
"sysfs-class",
"toml",
"udev",
"zbus 2.0.0-beta.3",
"zbus",
"zvariant",
]
[[package]]
name = "daemon-user"
version = "1.1.1"
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"
@@ -225,7 +252,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
]
[[package]]
@@ -239,6 +266,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"
@@ -257,7 +304,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
]
[[package]]
@@ -283,16 +330,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"
@@ -304,9 +345,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",
@@ -319,9 +360,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",
@@ -329,15 +370,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",
@@ -346,9 +387,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"
@@ -367,33 +408,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",
@@ -421,14 +462,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]]
@@ -448,7 +497,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
]
[[package]]
@@ -460,12 +509,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"
@@ -505,9 +548,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.90"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
[[package]]
name = "libudev-sys"
@@ -542,14 +585,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",
]
@@ -562,7 +605,7 @@ checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76"
dependencies = [
"cc",
"chrono",
"dirs",
"dirs 1.0.5",
"objc-foundation",
]
@@ -582,10 +625,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",
@@ -604,18 +657,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"
@@ -635,7 +676,7 @@ dependencies = [
"mac-notification-sys",
"serde",
"winrt-notification",
"zbus 1.8.0",
"zbus",
"zvariant",
"zvariant_derive",
]
@@ -718,6 +759,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"
@@ -725,24 +772,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"
@@ -761,7 +812,7 @@ dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
"version_check",
]
@@ -790,9 +841,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",
]
@@ -812,46 +863,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"
@@ -864,7 +875,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",
]
@@ -887,14 +898,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "rog_dbus"
version = "3.1.0"
name = "rog_anime"
version = "1.0.4"
dependencies = [
"gif",
"glam",
"pix",
"png_pong",
"serde",
"serde_derive",
"zbus",
"zvariant",
"zvariant_derive",
]
[[package]]
name = "rog_aura"
version = "1.0.1"
dependencies = [
"serde",
"serde_derive",
"zbus",
"zvariant",
"zvariant_derive",
]
[[package]]
name = "rog_dbus"
version = "3.2.0"
dependencies = [
"rog_anime",
"rog_aura",
"rog_fan_curve",
"rog_types",
"serde_json",
"zbus 1.8.0",
"zbus_macros 1.8.0",
"zbus",
"zbus_macros",
"zvariant",
]
@@ -912,6 +951,7 @@ name = "rog_types"
version = "3.2.0"
dependencies = [
"gumdrop",
"rog_aura",
"rog_fan_curve",
"serde",
"serde_derive",
@@ -921,9 +961,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",
@@ -961,22 +1001,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]]
@@ -998,30 +1038,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"
@@ -1030,16 +1055,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",
]
@@ -1073,9 +1097,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",
@@ -1099,7 +1123,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
"unicode-xid 0.2.1",
]
@@ -1123,11 +1147,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",
]
@@ -1151,9 +1176,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",
@@ -1180,9 +1205,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"
@@ -1210,9 +1235,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"
@@ -1296,9 +1327,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",
@@ -1307,66 +1338,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]]
@@ -1390,5 +1381,5 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.64",
"syn 1.0.69",
]

View File

@@ -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

View File

@@ -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)

View File

@@ -70,6 +70,11 @@ will probably suffer another rename once it becomes generic enough to do so.
- `nvidia`, uses the Nvidia gpu only
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
**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.

View File

@@ -14,6 +14,6 @@ rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
[dependencies.notify-rust]
version = "^4.0"
version = "^4.3"
default-features = false
features = ["z"]

View File

@@ -2,6 +2,7 @@ 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,9 +19,22 @@ 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() {

View File

@@ -1,6 +1,6 @@
[package]
name = "asusctl"
version = "3.1.5"
version = "3.5.0"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
@@ -9,13 +9,16 @@ edition = "2018"
[dependencies]
# serialisation
serde_json = "^1.0"
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
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"

View File

@@ -1,44 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::anime_matrix::{AniMeImageBuffer, HEIGHT, WIDTH};
use tinybmp::{Bmp, Pixel};
fn main() {
let (client, _) = AuraDbusClient::new().unwrap();
let bmp = Bmp::from_slice(include_bytes!("rust.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 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 (i, row) in tmp.iter_mut().enumerate() {
if i % 2 == 0 {
let l = row.len();
row[l - 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().write_image(matrix).unwrap();
}

View 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(())
}

View 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));
}
}

View 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());
}
}
}
}
}

View 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();
}

View 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();
}

View 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(())
}

View 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));
}
}

View File

@@ -1,5 +1,5 @@
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
use std::collections::LinkedList;
#[derive(Debug, Clone)]

View File

@@ -1,5 +1,5 @@
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;

View File

@@ -1,5 +1,5 @@
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;

View File

@@ -1,5 +1,5 @@
use rog_aura::{Key, KeyColourArray};
use rog_dbus::AuraDbusClient;
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;

View File

@@ -1,5 +1,5 @@
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
asusctl/examples/doom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
asusctl/examples/ferris.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
asusctl/examples/nudoom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

BIN
asusctl/examples/rust.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

92
asusctl/src/anime_cli.rs Normal file
View File

@@ -0,0 +1,92 @@
use gumdrop::Options;
use rog_aura::error::Error;
use std::str::FromStr;
#[derive(Copy, Clone, Debug)]
pub enum AnimeStatusValue {
On,
Off,
}
impl FromStr for AnimeStatusValue {
type Err = Error;
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(Error::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,
}

View File

@@ -1,8 +1,5 @@
use gumdrop::Options;
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
error::AuraError,
};
use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
use std::str::FromStr;
#[derive(Options)]
@@ -19,7 +16,7 @@ impl LedBrightness {
}
}
impl FromStr for LedBrightness {
type Err = AuraError;
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
@@ -30,7 +27,7 @@ impl FromStr for LedBrightness {
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
print!("Invalid argument, must be one of: off, low, med, high");
Err(AuraError::ParseBrightness)
Err(Error::ParseBrightness)
}
}
}

View File

@@ -1,25 +1,26 @@
mod anime_cli;
mod aura_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use daemon::{
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
};
use anime_cli::{AnimeActions, AnimeCommand};
use gumdrop::{Opt, Options};
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
use rog_aura::{self, AuraEffect};
use rog_dbus::AuraDbusClient;
use rog_types::{
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
aura_modes::{self, AuraEffect, AuraModeNum},
cli_options::{AniMeActions, AniMeStatusValue},
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")]
@@ -48,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),
}
@@ -61,6 +62,16 @@ struct LedModeCommand {
next_mode: bool,
#[options(help = "switch to previous aura mode")]
prev_mode: bool,
#[options(
meta = "",
help = "set the keyboard LED to enabled while the device is awake"
)]
awake_enable: Option<bool>,
#[options(
meta = "",
help = "set the keyboard LED suspend animation to enabled while the device is suspended"
)]
sleep_enable: Option<bool>,
#[options(command)]
command: Option<SetAuraBuiltin>,
}
@@ -82,21 +93,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")]
@@ -118,14 +114,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()
};
@@ -159,7 +155,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() {
@@ -174,10 +170,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();
}
}
}
@@ -190,9 +209,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());
}
}
}
@@ -206,7 +225,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(level) => dbus
.proxies()
.led()
.set_led_brightness(<aura_modes::LedBrightness>::from(level))?,
.set_led_brightness(<rog_aura::LedBrightness>::from(level))?,
}
}
@@ -224,7 +243,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();
@@ -311,10 +330,11 @@ fn do_gfx(
}
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,7 +345,12 @@ fn handle_led_mode(
supported: &LedSupportedFunctions,
mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if mode.command.is_none() && !mode.prev_mode && !mode.next_mode {
if mode.command.is_none()
&& !mode.prev_mode
&& !mode.next_mode
&& mode.sleep_enable.is_none()
&& mode.awake_enable.is_none()
{
if !mode.help {
println!("Missing arg or command\n");
}
@@ -337,9 +362,13 @@ fn handle_led_mode(
.lines()
.map(|s| s.to_string())
.collect();
for command in commands.iter().filter(|mode| {
for command in commands.iter().filter(|command| {
if let Some(modes) = supported.stock_led_modes.as_ref() {
return modes.contains(&<AuraModeNum>::from(mode.as_str()));
for mode in modes {
if command.contains(&(<&str>::from(mode)).to_lowercase()) {
return true;
}
}
}
if supported.multizone_led_mode {
return true;
@@ -379,6 +408,15 @@ fn handle_led_mode(
.set_led_mode(&<AuraEffect>::from(mode))?,
}
}
if let Some(enable) = mode.awake_enable {
dbus.proxies().led().set_awake_enabled(enable)?;
}
if let Some(enable) = mode.sleep_enable {
dbus.proxies().led().set_sleep_enabled(enable)?;
}
Ok(())
}
@@ -388,18 +426,19 @@ fn handle_profile(
cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> {
if !cmd.next
&& !cmd.create
&& !cmd.create // TODO
&& !cmd.list
&& cmd.profile.is_none()
&& !cmd.active_name
&& !cmd.active_data
&& !cmd.profiles_data
&& cmd.remove.is_none()
&& cmd.curve.is_none()
&& cmd.max_percentage.is_none()
&& cmd.curve.is_none() // TODO
&& cmd.fan_preset.is_none() // TODO
&& cmd.turbo.is_none() // TODO
&& cmd.max_percentage.is_none() // TODO
&& cmd.min_percentage.is_none()
&& cmd.fan_preset.is_none()
&& cmd.profile.is_none()
&& cmd.turbo.is_none()
// TODO
{
if !cmd.help {
println!("Missing arg or command\n");
@@ -418,6 +457,9 @@ fn handle_profile(
if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst);
}
println!("Note: turbo, frequency, fan preset and fan curve options will apply to");
println!(" to the currently active profile unless a profile name is specified");
std::process::exit(1);
}
@@ -450,10 +492,34 @@ fn handle_profile(
}
}
// This must come before the next block of actions so that changing a specific
// profile can be done
if cmd.profile.is_some() {
dbus.proxies()
.profile()
.write_command(&ProfileEvent::Cli(cmd.clone()))?
.write_command(&ProfileEvent::Cli(cmd.clone()))?;
return Ok(());
}
if let Some(turbo) = cmd.turbo {
dbus.proxies().profile().set_turbo(turbo)?;
}
if let Some(min) = cmd.min_percentage {
dbus.proxies().profile().set_min_frequency(min)?;
}
if let Some(max) = cmd.max_percentage {
dbus.proxies().profile().set_max_frequency(max)?;
}
if let Some(ref preset) = cmd.fan_preset {
dbus.proxies().profile().set_fan_preset(preset.into())?;
}
if let Some(ref curve) = cmd.curve {
let s = curve.as_config_string();
dbus.proxies().profile().set_fan_curve(&s)?;
}
Ok(())

30
daemon-user/Cargo.toml Normal file
View File

@@ -0,0 +1,30 @@
[package]
name = "daemon-user"
version = "1.1.1"
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
View 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

View File

@@ -0,0 +1,341 @@
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::UserAnimeConfig};
#[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<UserAnimeConfig>>,
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<UserAnimeConfig>>,
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(())
}
}

75
daemon-user/src/daemon.rs Normal file
View File

@@ -0,0 +1,75 @@
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!("user daemon v{}", rog_user::VERSION);
println!(" rog-anime v{}", rog_anime::VERSION);
println!(" rog-dbus v{}", 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 = UserAnimeConfig::load_config(config.active_anime)?;
let anime = anime_config.create_anime()?;
let anime_config = Arc::new(Mutex::new(anime_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(
anime_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
View 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))
}
}

11
daemon-user/src/lib.rs Normal file
View File

@@ -0,0 +1,11 @@
pub mod user_config;
pub mod error;
pub mod ctrl_anime;
pub mod zbus_anime;
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -0,0 +1,200 @@
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, Deserialize, Serialize)]
pub struct UserAnimeConfig {
pub name: String,
pub anime: Vec<AnimeAction>,
}
impl UserAnimeConfig {
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)
}
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())?;
}
let name = self.name.clone();
path.push(name + ".cfg");
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)?;
let json = serde_json::to_string_pretty(&self).unwrap();
file.write_all(json.as_bytes())?;
Ok(())
}
pub fn load_config(name: String) -> Result<UserAnimeConfig, 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(name.clone() + ".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 default = UserAnimeConfig { name, ..Default::default() };
let json = serde_json::to_string_pretty(&default).unwrap();
file.write_all(json.as_bytes())?;
return Ok(default);
} else if let Ok(data) = serde_json::from_str::<UserAnimeConfig>(&buf) {
return Ok(data);
}
}
Err(Error::ConfigLoadFail)
}
}
impl Default for UserAnimeConfig {
fn default() -> Self {
Self {
name: "default".to_string(),
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),
},
],
}
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct UserConfig {
/// Name of active anime config file in the user config directory
pub active_anime: String,
}
impl UserConfig {
pub fn new() -> Self {
Self {
active_anime: "anime-default".to_string(),
}
}
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.active_anime = data.active_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();
file.write_all(json.as_bytes())?;
Ok(())
}
}

View 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<()>;
}

View File

@@ -1,6 +1,6 @@
[package]
name = "daemon"
version = "3.3.0"
version = "3.5.1"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -18,18 +18,20 @@ name = "asusd"
path = "src/daemon.rs"
[dependencies]
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
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"

View File

@@ -14,8 +14,10 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize)]
pub struct Config {
pub gfx_mode: GfxVendors,
pub gfx_last_mode: GfxVendors,
pub gfx_managed: bool,
pub gfx_vfio_enable: bool,
pub gfx_save_compute_vfio: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
@@ -33,8 +35,10 @@ impl Default for Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid,
gfx_managed: true,
gfx_vfio_enable: false,
gfx_save_compute_vfio: true,
active_profile: "normal".into(),
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0,
@@ -65,6 +69,11 @@ impl Config {
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<ConfigV341>(&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::<ConfigV324>(&buf) {
let config = data.into_current();
config.write();
@@ -75,21 +84,6 @@ impl Config {
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();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV222>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV212>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
}
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);

201
daemon/src/config_anime.rs Normal file
View File

@@ -0,0 +1,201 @@
use crate::VERSION;
use log::{error, info, warn};
use rog_anime::{error::AnimeError, ActionData, AnimTime, AnimeAction, Vec2};
use serde_derive::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::time::Duration;
pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf";
pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf";
#[derive(Deserialize, Serialize)]
pub struct AnimeConfigV341 {
pub system: Option<AnimeAction>,
pub boot: Option<AnimeAction>,
pub suspend: Option<AnimeAction>,
pub shutdown: Option<AnimeAction>,
}
impl AnimeConfigV341 {
pub(crate) fn into_current(self) -> AnimeConfig {
AnimeConfig {
system: if let Some(ani) = self.system {
vec![ani]
} else {
vec![]
},
boot: if let Some(ani) = self.boot {
vec![ani]
} else {
vec![]
},
wake: if let Some(ani) = self.suspend {
vec![ani]
} else {
vec![]
},
shutdown: if let Some(ani) = self.shutdown {
vec![ani]
} else {
vec![]
},
brightness: 1.0,
}
}
}
#[derive(Deserialize, Serialize, Default)]
pub struct AnimeConfigCached {
pub system: Vec<ActionData>,
pub boot: Vec<ActionData>,
pub wake: Vec<ActionData>,
pub shutdown: Vec<ActionData>,
}
impl AnimeConfigCached {
pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> {
let mut sys = Vec::with_capacity(config.system.len());
for ani in config.system.iter() {
sys.push(ActionData::from_anime_action(ani)?);
}
self.system = sys;
let mut boot = Vec::with_capacity(config.boot.len());
for ani in config.boot.iter() {
boot.push(ActionData::from_anime_action(ani)?);
}
self.boot = boot;
let mut wake = Vec::with_capacity(config.wake.len());
for ani in config.wake.iter() {
wake.push(ActionData::from_anime_action(ani)?);
}
self.wake = wake;
let mut shutdown = Vec::with_capacity(config.shutdown.len());
for ani in config.shutdown.iter() {
shutdown.push(ActionData::from_anime_action(ani)?);
}
self.shutdown = shutdown;
Ok(())
}
}
/// Config for base system actions for the anime display
#[derive(Deserialize, Serialize)]
pub struct AnimeConfig {
pub system: Vec<AnimeAction>,
pub boot: Vec<AnimeAction>,
pub wake: Vec<AnimeAction>,
pub shutdown: Vec<AnimeAction>,
pub brightness: f32,
}
impl Default for AnimeConfig {
fn default() -> Self {
AnimeConfig {
system: Vec::new(),
boot: Vec::new(),
wake: Vec::new(),
shutdown: Vec::new(),
brightness: 1.0,
}
}
}
impl AnimeConfig {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load() -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&ANIME_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
ANIME_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 AnimeConfig::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::<AnimeConfigV341>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
}
warn!("Could not deserialise {}", ANIME_CONFIG_PATH);
panic!("Please remove {} then restart asusd", ANIME_CONFIG_PATH);
}
}
AnimeConfig::create_default(&mut file)
}
fn create_default(file: &mut File) -> Self {
// create a default config here
let config = AnimeConfig {
system: vec![],
boot: vec![AnimeAction::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Time(Duration::from_secs(5)),
}],
wake: vec![AnimeAction::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 1.0,
time: AnimTime::Time(Duration::from_secs(5)),
}],
shutdown: vec![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: 1.0,
time: AnimTime::Infinite,
}],
brightness: 1.0,
};
// 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())
.unwrap_or_else(|_| panic!("Could not write {}", ANIME_CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&ANIME_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_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 {}", ANIME_CONFIG_PATH);
} else {
let x: AnimeConfig = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", ANIME_CONFIG_PATH));
*self = x;
}
}
}
pub fn write(&self) {
let mut file = File::create(ANIME_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));
}
}

View File

@@ -1,6 +1,6 @@
use crate::laptops::LaptopLedData;
use log::{error, info, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
@@ -146,3 +146,90 @@ impl AuraConfig {
None
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraMultiZone {
static_: [AuraEffect; 4],
breathe: [AuraEffect; 4],
}
impl AuraMultiZone {
pub fn set(&mut self, effect: AuraEffect) {
if effect.mode == AuraModeNum::Static {
match effect.zone {
AuraZone::None => {}
AuraZone::One => self.static_[0] = effect,
AuraZone::Two => self.static_[1] = effect,
AuraZone::Three => self.static_[2] = effect,
AuraZone::Four => self.static_[3] = effect,
}
} else if effect.mode == AuraModeNum::Breathe {
match effect.zone {
AuraZone::None => {}
AuraZone::One => self.breathe[0] = effect,
AuraZone::Two => self.breathe[1] = effect,
AuraZone::Three => self.breathe[2] = effect,
AuraZone::Four => self.breathe[3] = effect,
}
}
}
pub fn static_(&self) -> &[AuraEffect; 4] {
&self.static_
}
pub fn breathe(&self) -> &[AuraEffect; 4] {
&self.breathe
}
}
impl Default for AuraMultiZone {
fn default() -> Self {
Self {
static_: [
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::One,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Two,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Three,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Static,
zone: AuraZone::Four,
..Default::default()
},
],
breathe: [
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::One,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Two,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Three,
..Default::default()
},
AuraEffect {
mode: AuraModeNum::Breathe,
zone: AuraZone::Four,
..Default::default()
},
],
}
}
}

View File

@@ -1,101 +1,9 @@
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors, profile::Profile};
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::config::Config;
/// for parsing old v2.1.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV212 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV212 {
pub(crate) fn into_current(self) -> Config {
Config {
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,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v2.2.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV222 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV222 {
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.power_profile,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v3.0.1 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV301 {
pub gfx_managed: bool,
pub gfx_nv_mode_is_dedicated: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
// TODO: remove power_profile
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraEffect>,
pub power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV301 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
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 {
@@ -117,8 +25,10 @@ impl ConfigV317 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
gfx_vfio_enable: false,
gfx_save_compute_vfio: false,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
@@ -144,8 +54,40 @@ impl ConfigV324 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
gfx_vfio_enable: false,
gfx_save_compute_vfio: 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 ConfigV341 {
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 power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV341 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
gfx_vfio_enable: false,
gfx_save_compute_vfio: false,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,

View File

@@ -1,121 +1,56 @@
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 logind_zbus::ManagerProxy;
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,
ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN,
};
use rog_types::supported::AnimeSupportedFunctions;
use rusb::{Device, DeviceHandle};
use std::error::Error;
use std::time::Duration;
use zbus::dbus_interface;
use std::{
error::Error,
sync::{Arc, Mutex},
thread::sleep,
time::Instant,
};
use std::{
sync::atomic::{AtomicBool, Ordering},
time::Duration,
};
use zbus::{dbus_interface, Connection};
use zvariant::ObjectPath;
use crate::GetSupported;
use crate::{
config_anime::{AnimeConfig, AnimeConfigCached},
error::RogError,
GetSupported,
};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct AnimeSupportedFunctions(pub bool);
impl GetSupported for CtrlAnimeDisplay {
impl GetSupported for CtrlAnime {
type A = AnimeSupportedFunctions;
fn get_supported() -> Self::A {
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(0x0b05, 0x193b).is_ok())
AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok())
}
}
pub struct CtrlAnimeDisplay {
pub struct CtrlAnime {
handle: DeviceHandle<rusb::GlobalContext>,
cache: AnimeConfigCached,
config: AnimeConfig,
// set to force thread to exit
thread_exit: Arc<AtomicBool>,
// Set to false when the thread exits
thread_running: Arc<AtomicBool>,
}
//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)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
#[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"));
}
/// Writes a data stream of length
fn write_direct(&self, input: AniMeDataBuffer) {
self.write_data_buffer(input)
.map_or_else(|err| warn!("{}", err), |()| info!("Writing data to Anime"));
}
fn set_on_off(&self, status: bool) {
let mut buffer = [0u8; PACKET_SIZE];
buffer[0] = DEV_PAGE;
buffer[1] = WRITE;
buffer[2] = ON_OFF;
if status {
buffer[3] = 0x03;
} else {
buffer[3] = 0x00;
}
self.write_bytes(&buffer);
}
fn set_boot_on_off(&self, status: bool) {
let status_str = if status { "on" } else { "off" };
self.do_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),
);
}
}
impl CtrlAnimeDisplay {
impl CtrlAnime {
#[inline]
pub fn new() -> Result<CtrlAnimeDisplay, Box<dyn Error>> {
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, Box<dyn Error>> {
// We don't expect this ID to ever change
let device = CtrlAnimeDisplay::get_device(0x0b05, 0x193b)?;
let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
let mut device = device.open()?;
device.reset()?;
@@ -131,13 +66,21 @@ impl CtrlAnimeDisplay {
})?;
info!("Device has an AniMe Matrix display");
let ctrl = CtrlAnimeDisplay { handle: device };
ctrl.do_initialization()?;
let mut cache = AnimeConfigCached::default();
cache.init_from_config(&config)?;
let ctrl = CtrlAnime {
handle: device,
cache,
config,
thread_exit: Arc::new(AtomicBool::new(false)),
thread_running: Arc::new(AtomicBool::new(false)),
};
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 +91,117 @@ impl CtrlAnimeDisplay {
Err(rusb::Error::NoDevice)
}
/// Should only be used if the bytes you are writing are verified correct
#[inline]
/// Start an action thread. This is classed as a singleton and there should be only
/// one running - so the thread uses atomics to signal run/exit.
///
/// Because this also writes to the usb device, other write tries (display only) *must*
/// get the mutex lock and set the thread_exit atomic.
fn run_thread(inner: Arc<Mutex<CtrlAnime>>, actions: Vec<ActionData>, mut once: bool) {
if actions.is_empty() {
warn!("AniMe system actions was empty");
return;
}
// Loop rules:
// - Lock the mutex **only when required**. That is, the lock must be held for the shortest duration possible.
// - An AtomicBool used for thread exit should be checked in every loop, including nested
// The only reason for this outer thread is to prevent blocking while waiting for the
// next spawned thread to exit
std::thread::Builder::new()
.name("AniMe system thread start".into())
.spawn(move || {
info!("AniMe system thread started");
// Getting copies of these Atomics is done *in* the thread to ensure
// we don't block other threads/main
let thread_exit;
let thread_running;
// First two loops are to ensure we *do* aquire a lock on the mutex
// The reason the loop is required is because the USB writes can block
// for up to 10ms. We can't fail to get the atomics.
loop {
if let Ok(lock) = inner.try_lock() {
thread_exit = lock.thread_exit.clone();
thread_running = lock.thread_running.clone();
// Make any running loop exit first
thread_exit.store(true, Ordering::SeqCst);
break;
}
}
loop {
// wait for other threads to set not running so we know they exited
if !thread_running.load(Ordering::SeqCst) {
thread_exit.store(false, Ordering::SeqCst);
info!("AniMe forced a thread to exit");
break;
}
}
'main: loop {
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
for action in actions.iter() {
match action {
ActionData::Animation(frames) => {
let mut count = 0;
let start = Instant::now();
'animation: loop {
for frame in frames.frames() {
if let Ok(lock) = inner.try_lock() {
lock.write_data_buffer(frame.frame().clone());
}
if let AnimTime::Time(time) = frames.duration() {
if Instant::now().duration_since(start) > time {
break 'animation;
}
}
sleep(frame.delay());
// Need to check for early exit condition here or it might run
// until end of gif or time
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
}
if let AnimTime::Cycles(times) = frames.duration() {
count += 1;
if count >= times {
break 'animation;
}
}
}
}
ActionData::Image(image) => {
once = false;
if let Ok(lock) = inner.try_lock() {
lock.write_data_buffer(image.as_ref().clone())
}
}
ActionData::Pause(duration) => sleep(*duration),
ActionData::AudioEq => {}
ActionData::SystemInfo => {}
ActionData::TimeDate => {}
ActionData::Matrix => {}
}
}
if once || actions.is_empty() {
break 'main;
}
}
// Clear the display on exit
if let Ok(lock) = inner.try_lock() {
let data = AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec());
lock.write_data_buffer(data);
}
// Loop ended, set the atmonics
thread_exit.store(false, Ordering::SeqCst);
thread_running.store(false, Ordering::SeqCst);
info!("AniMe system thread exited");
})
.map(|err| info!("AniMe system thread: {:?}", err))
.ok();
}
fn write_bytes(&self, message: &[u8]) {
match self.handle.write_control(
0x21, // request_type
@@ -166,99 +218,208 @@ 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() {
/// Write only a data packet. This will modify the leds brightness using the
/// global brightness set in config.
fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) {
for led in buffer.get_mut()[7..].iter_mut() {
let mut bright = *led as f32 * self.config.brightness;
if bright > 254.0 {
bright = 254.0;
}
*led = bright as u8;
}
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);
fn do_initialization(&self) {
let pkts = pkts_for_init();
self.write_bytes(&pkts[0]);
self.write_bytes(&pkts[1]);
}
}
for row in image.iter() {
self.write_bytes(row);
pub struct CtrlAnimeTask<'a> {
inner: Arc<Mutex<CtrlAnime>>,
_c: Connection,
manager: ManagerProxy<'a>,
}
impl<'a> CtrlAnimeTask<'a> {
pub fn new(inner: Arc<Mutex<CtrlAnime>>) -> Self {
let connection = Connection::new_system().unwrap();
let manager = ManagerProxy::new(&connection).unwrap();
let c1 = inner.clone();
// Run this action when the system starts shutting down
manager
.connect_prepare_for_shutdown(move |shutdown| {
if shutdown {
'outer: loop {
if let Ok(lock) = c1.try_lock() {
lock.thread_exit.store(true, Ordering::SeqCst);
CtrlAnime::run_thread(c1.clone(), lock.cache.shutdown.clone(), false);
break 'outer;
}
}
}
Ok(())
})
.map_err(|err| {
warn!("CtrlAnimeTask: new() {}", err);
err
})
.ok();
let c1 = inner.clone();
// Run this action when the system wakes up from sleep
manager
.connect_prepare_for_sleep(move |sleep| {
if !sleep {
// wait a fraction for things to wake up properly
std::thread::sleep(Duration::from_millis(100));
'outer: loop {
if let Ok(lock) = c1.try_lock() {
lock.thread_exit.store(true, Ordering::SeqCst);
CtrlAnime::run_thread(c1.clone(), lock.cache.wake.clone(), true);
break 'outer;
}
}
}
Ok(())
})
.map_err(|err| {
warn!("CtrlAnimeTask: new() {}", err);
err
})
.ok();
Self {
inner,
_c: connection,
manager,
}
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
impl<'a> crate::CtrlTask for CtrlAnimeTask<'a> {
fn do_task(&self) -> Result<(), RogError> {
if let Ok(mut lock) = self.inner.try_lock() {
// Refresh the config and cache incase the user has edited it
let config = AnimeConfig::load();
lock.cache
.init_from_config(&config)
.map_err(|err| {
warn!("CtrlAnimeTask: do_task {}", err);
err
})
.ok();
}
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);
// Check for signals on each task iteration, this will run the callbacks
// if any signal is recieved
self.manager.next_signal()?;
Ok(())
}
}
pub struct CtrlAnimeReloader(pub Arc<Mutex<CtrlAnime>>);
impl crate::Reloadable for CtrlAnimeReloader {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(lock) = self.0.try_lock() {
let action = lock.cache.boot.clone();
CtrlAnime::run_thread(self.0.clone(), action, true);
}
Ok(())
}
}
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
/// The struct with the main dbus methods requires this trait
impl crate::ZbusAdd for CtrlAnimeZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
// None of these calls can be guarnateed to succeed unless we loop until okay
// If the try_lock *does* succeed then any other thread trying to lock will not grab it
// until we finish.
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlAnimeZbus {
/// Writes a data stream of length. Will force system thread to exit until it is restarted
fn write(&self, input: AnimeDataBuffer) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.thread_exit.store(true, Ordering::SeqCst);
lock.write_data_buffer(input);
break 'outer;
}
}
}
fn set_brightness(&self, bright: f32) {
'outer: loop {
if let Ok(mut lock) = self.0.try_lock() {
let mut bright = bright;
if bright < 0.0 {
bright = 0.0
} else if bright > 254.0 {
bright = 254.0;
}
lock.config.brightness = bright;
lock.config.write();
break 'outer;
}
}
}
fn set_on_off(&self, status: bool) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_on(status));
break 'outer;
}
}
}
fn set_boot_on_off(&self, on: bool) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_boot(on));
lock.write_bytes(&pkt_for_apply());
break 'outer;
}
}
}
/// The main loop is the base system set action if the user isn't running
/// the user daemon
fn run_main_loop(&self, start: bool) {
if start {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.thread_exit.store(true, Ordering::SeqCst);
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false);
break 'outer;
}
}
}
}
}

View File

@@ -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

View File

@@ -6,15 +6,15 @@ use logind_zbus::{
types::{SessionClass, SessionInfo, SessionState, SessionType},
ManagerProxy, SessionProxy,
};
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::mpsc;
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};
use std::{str::FromStr, sync::mpsc};
use std::{sync::Arc, sync::Mutex};
use sysfs_class::{PciDevice, SysClass};
use system::{GraphicsDevice, PciBus};
use zbus::{dbus_interface, Connection};
use ::zbus::{Connection};
use crate::*;
@@ -31,59 +31,6 @@ pub struct CtrlGraphics {
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
}
trait Dbus {
fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
fn power(&self) -> String;
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) -> 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 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: &GfxVendors) -> zbus::Result<()> {}
#[dbus_interface(signal)]
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)
.map_err(|err| {
warn!("GFX: CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
}
impl Reloadable for CtrlGraphics {
fn reload(&mut self) -> Result<(), RogError> {
self.auto_power()?;
@@ -164,6 +111,7 @@ impl CtrlGraphics {
/// 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_last_mode = config.gfx_mode;
config.gfx_mode = vendor;
config.write();
}
@@ -178,10 +126,19 @@ 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)
pub(super) 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
@@ -268,10 +225,14 @@ impl CtrlGraphics {
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::Nvidia | GfxVendors::Hybrid => {
let mut base = MODPROBE_BASE.to_vec();
base.append(&mut MODPROBE_DRM_MODESET.to_vec());
base
}
GfxVendors::Vfio => Self::get_vfio_conf(devices),
// GfxVendors::Compute => {}
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
GfxVendors::Compute => MODPROBE_BASE.to_vec(),
};
let mut file = std::fs::OpenOptions::new()
@@ -405,9 +366,13 @@ impl CtrlGraphics {
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)
{
if matches!(
current,
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
) && matches!(
vendor,
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
) {
return GfxRequiredUserAction::None;
}
}
@@ -483,7 +448,7 @@ impl CtrlGraphics {
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 => {
@@ -642,6 +607,13 @@ impl CtrlGraphics {
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
if let Ok(config) = self.config.lock() {
if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio)
&& config.gfx_save_compute_vfio
{
Self::save_gfx_mode(vendor, self.config.clone());
}
}
}
// TODO: undo if failed? Save last mode, catch errors...
Ok(action_required)

View File

@@ -6,6 +6,7 @@ use crate::error::RogError;
#[derive(Debug)]
pub enum GfxError {
ParseVendor,
ParsePower,
Bus(String, std::io::Error),
DisplayManagerAction(String, ExitStatus),
DisplayManagerTimeout(String),
@@ -22,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)

View File

@@ -1,9 +1,11 @@
pub mod error;
pub mod gfx;
pub mod controller;
pub mod system;
pub mod zbus_gfx;
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
const VFIO_DRIVERS: [&str; 5] = [
@@ -26,6 +28,9 @@ static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
blacklist nouveau
alias nouveau off
options nvidia NVreg_DynamicPowerManagement=0x02
"#;
static MODPROBE_DRM_MODESET: &[u8] = br#"
options nvidia-drm modeset=1
"#;

View File

@@ -0,0 +1,56 @@
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use ::zbus::{dbus_interface};
use zvariant::ObjectPath;
use log::{error, warn, info};
use crate::ZbusAdd;
use super::controller::CtrlGraphics;
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlGraphics {
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) -> 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: 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: &GfxVendors) -> zbus::Result<()> {}
#[dbus_interface(signal)]
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
}
impl ZbusAdd for CtrlGraphics {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self)
.map_err(|err| {
warn!("GFX: CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
}

View File

@@ -1,7 +1,4 @@
// Only these two packets must be 17 bytes
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 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::{
@@ -10,29 +7,22 @@ use crate::{
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
};
use log::{error, info, warn};
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum, LedBrightness},
LED_MSG_LEN,
use rog_aura::{
usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON},
AuraEffect, LedBrightness, LED_MSG_LEN,
};
use rog_types::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<AuraModeNum>>,
pub multizone_led_mode: bool,
pub per_key_led_mode: bool,
}
impl GetSupported for CtrlKbdBacklight {
impl GetSupported for CtrlKbdLed {
type A = LedSupportedFunctions;
fn get_supported() -> Self::A {
@@ -47,7 +37,7 @@ impl GetSupported for CtrlKbdBacklight {
};
LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(),
stock_led_modes,
multizone_led_mode,
per_key_led_mode,
@@ -55,7 +45,7 @@ impl GetSupported for CtrlKbdBacklight {
}
}
pub struct CtrlKbdBacklight {
pub struct CtrlKbdLed {
led_node: Option<String>,
pub bright_node: String,
supported_modes: LaptopLedData,
@@ -63,28 +53,67 @@ pub struct CtrlKbdBacklight {
config: AuraConfig,
}
pub struct DbusKbdBacklight {
inner: Arc<Mutex<CtrlKbdBacklight>>,
pub struct CtrlKbdLedTask(pub Arc<Mutex<CtrlKbdLed>>);
impl crate::CtrlTask for CtrlKbdLedTask {
fn do_task(&self) -> Result<(), RogError> {
if let Ok(mut lock) = self.0.try_lock() {
let mut file = OpenOptions::new()
.read(true)
.open(&lock.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&lock.bright_node).into(), err)
}
_ => RogError::Path((&lock.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
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 lock.config.brightness != num.into() {
lock.config.read();
lock.config.brightness = num.into();
lock.config.write();
}
return Ok(());
}
return Err(RogError::ParseLed);
}
Ok(())
}
}
impl DbusKbdBacklight {
pub fn new(inner: Arc<Mutex<CtrlKbdBacklight>>) -> Self {
pub struct CtrlKbdLedReloader(pub Arc<Mutex<CtrlKbdLed>>);
impl crate::Reloadable for CtrlKbdLedReloader {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut lock) = self.0.try_lock() {
let current = lock.config.current_mode;
if let Some(mode) = lock.config.builtins.get(&current).cloned() {
lock.do_command(mode).ok();
}
}
Ok(())
}
}
pub struct CtrlKbdLedZbus {
inner: Arc<Mutex<CtrlKbdLed>>,
}
impl CtrlKbdLedZbus {
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
Self { inner }
}
}
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 {
impl crate::ZbusAdd for CtrlKbdLedZbus {
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);
error!("DbusKbdLed: add_to_server {}", err);
})
.ok();
}
@@ -94,7 +123,8 @@ impl crate::ZbusAdd for DbusKbdBacklight {
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusKbdBacklight {
impl CtrlKbdLedZbus {
/// Set the keyboard brightness level (0-3)
fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_brightness(brightness)
@@ -103,6 +133,24 @@ impl DbusKbdBacklight {
}
}
/// Set the keyboard LED to enabled while the device is awake
fn set_awake_enabled(&mut self, enabled: bool) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_awake_enable(enabled)
.map_err(|err| warn!("{}", err))
.ok();
}
}
/// Set the keyboard LED suspend animation to enabled while the device is suspended
fn set_sleep_enabled(&mut self, enabled: bool) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_sleep_anim_enable(enabled)
.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();
@@ -185,74 +233,7 @@ impl DbusKbdBacklight {
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
impl crate::Reloadable for CtrlKbdBacklight {
fn reload(&mut self) -> Result<(), RogError> {
// set current mode (if any)
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(&current_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(&current_mode);
self.config.current_mode = AuraModeNum::Static;
// TODO: do a recursive call with a boxed dyn future later
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
}
// Reload brightness
let bright = self.config.brightness;
self.set_brightness(bright)?;
info!("Reloaded last used brightness");
Ok(())
}
}
impl crate::CtrlTask for CtrlKbdBacklight {
fn do_task(&mut self) -> Result<(), 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))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if self.config.brightness != num.into() {
self.config.read();
self.config.brightness = num.into();
self.config.write();
}
return Ok(());
}
Err(RogError::ParseLED)
}
}
impl CtrlKbdBacklight {
impl CtrlKbdLed {
#[inline]
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None
@@ -282,7 +263,7 @@ impl CtrlKbdBacklight {
));
}
let ctrl = CtrlKbdBacklight {
let ctrl = CtrlKbdLed {
led_node,
bright_node: bright_node.unwrap(), // If was none then we already returned above
supported_modes,
@@ -299,7 +280,7 @@ impl CtrlKbdBacklight {
None
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
fn get_brightness(&self) -> Result<u8, RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
@@ -315,7 +296,7 @@ impl CtrlKbdBacklight {
Ok(buf[0])
}
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
let path = Path::new(&self.bright_node);
let mut file =
OpenOptions::new()
@@ -332,6 +313,26 @@ impl CtrlKbdBacklight {
Ok(())
}
/// Set the keyboard LED to active if laptop is awake
fn set_awake_enable(&self, enabled: bool) -> Result<(), RogError> {
let bytes = if enabled { LED_AWAKE_ON } else { LED_AWAKE_OFF };
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
Ok(())
}
/// Set the keyboard suspend animation to on if plugged in
fn set_sleep_anim_enable(&self, enabled: bool) -> Result<(), RogError> {
let bytes = if enabled { LED_SLEEP_ON } else { LED_SLEEP_OFF };
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
Ok(())
}
fn find_led_node(id_product: &str) -> Result<String, RogError> {
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);

View File

@@ -1,195 +1,37 @@
use crate::error::RogError;
use crate::{config::Config, GetSupported};
use log::{info, warn};
use rog_types::profile::{FanLevel, Profile, 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, fdo::Error};
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";
use super::*;
pub struct CtrlFanAndCPU {
pub struct CtrlFanAndCpu {
pub path: &'static str,
config: Arc<Mutex<Config>>,
pub 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(),
}
}
}
pub struct DbusFanAndCpu {
inner: Arc<Mutex<CtrlFanAndCPU>>,
}
impl DbusFanAndCpu {
pub fn new(inner: Arc<Mutex<CtrlFanAndCPU>>) -> Self {
Self { inner }
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusFanAndCpu {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
}
/// Fetch the active profile name
fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
/// Fetch the active profile name
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 Ok(cfg.active_profile.clone());
}
}
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) -> 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_pretty(profile) {
return Ok(json);
}
}
}
}
Err(Error::Failed(
"Failed to get active profile details".to_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_pretty(&cfg.power_profiles) {
return Ok(json);
}
}
}
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)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for DbusFanAndCpu {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Profile", self)
.map_err(|err| {
warn!("DbusFanAndCpu: add_to_server {}", err);
err
})
.ok();
}
}
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();
@@ -203,11 +45,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> {
@@ -269,7 +111,7 @@ impl CtrlFanAndCPU {
Ok(())
}
fn handle_profile_event(
pub(super) fn handle_profile_event(
&mut self,
event: &ProfileEvent,
config: &mut Config,
@@ -322,7 +164,7 @@ impl CtrlFanAndCPU {
Ok(())
}
fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
pub(super) fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
let mode_config = config
.power_profiles
.get(profile)

View File

@@ -0,0 +1,7 @@
pub mod zbus;
pub mod controller;
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";

View File

@@ -0,0 +1,255 @@
use log::warn;
use rog_fan_curve::Curve;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::{dbus_interface, fdo::Error};
use zvariant::ObjectPath;
use super::controller::CtrlFanAndCpu;
pub struct FanAndCpuZbus {
inner: Arc<Mutex<CtrlFanAndCpu>>,
}
impl FanAndCpuZbus {
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
Self { inner }
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl FanAndCpuZbus {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
}
/// Modify the active profile
fn set_turbo(&self, enable: bool) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.turbo = enable;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_min_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.min_percentage = percentage;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_max_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.max_percentage = percentage;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_fan_preset(&self, preset: u8) -> zbus::fdo::Result<()> {
if preset > 2 {
return Err(zbus::fdo::Error::InvalidArgs(
"Fan preset must be 0, 1, or 2".to_string(),
));
}
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.fan_preset = preset;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_fan_curve(&self, curve: String) -> zbus::fdo::Result<()> {
let curve = Curve::from_config_str(&curve)
.map_err(|err| zbus::fdo::Error::InvalidArgs(format!("Fan curve error: {}", err)))?;
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.fan_curve = Some(curve);
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Fetch the active profile name
fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
/// Fetch the active profile name
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 Ok(cfg.active_profile.clone());
}
}
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) -> 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_pretty(profile) {
return Ok(json);
}
}
}
}
Err(Error::Failed(
"Failed to get active profile details".to_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_pretty(&cfg.power_profiles) {
return Ok(json);
}
}
}
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)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for FanAndCpuZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
self,
)
.map_err(|err| {
warn!("DbusFanAndCpu: add_to_server {}", err);
err
})
.ok();
}
}

View File

@@ -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

View File

@@ -1,14 +1,13 @@
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,
use crate::{GetSupported, ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed, ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios};
use rog_types::supported::{
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
LedSupportedFunctions, RogBiosSupportedFunctions,
};
#[derive(Serialize, Deserialize)]
@@ -30,7 +29,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
@@ -44,10 +46,10 @@ impl GetSupported for SupportedFunctions {
fn get_supported() -> Self::A {
SupportedFunctions {
keyboard_led: CtrlKbdBacklight::get_supported(),
anime_ctrl: CtrlAnimeDisplay::get_supported(),
keyboard_led: CtrlKbdLed::get_supported(),
anime_ctrl: CtrlAnime::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(),
}
}

View File

@@ -1,11 +1,11 @@
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::ctrl_leds::{CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus};
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::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics};
use daemon::{
ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu},
ctrl_profiles::{zbus::FanAndCpuZbus, controller::CtrlFanAndCpu},
laptops::LaptopLedData,
};
@@ -23,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();
@@ -40,27 +41,24 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
// - read interrupt must timeout, minimum of 1ms
// - for a single usb packet, 2ms total.
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
/// The actual main loop for the daemon
fn start_daemon() -> Result<(), Box<dyn Error>> {
let supported = SupportedFunctions::get_supported();
print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let config = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
// Collect tasks for task thread
let mut tasks: Vec<Box<dyn CtrlTask + Send>> = Vec::new();
// Start zbus server
let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)?
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
let config = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
supported.add_to_server(&mut object_server);
match CtrlRogBios::new(config.clone()) {
@@ -89,24 +87,68 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
match CtrlAnimeDisplay::new() {
match CtrlFanAndCpu::new(config.clone()) {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
FanAndCpuZbus::new(tmp).add_to_server(&mut object_server);
}
Err(err) => {
error!("Profile control: {}", err);
}
}
match CtrlAnime::new(AnimeConfig::load()) {
Ok(ctrl) => {
ctrl.add_to_server(&mut object_server);
let inner = Arc::new(Mutex::new(ctrl));
let mut reload = CtrlAnimeReloader(inner.clone());
reload
.reload()
.unwrap_or_else(|err| warn!("AniMe: {}", err));
let zbus = CtrlAnimeZbus(inner.clone());
zbus.add_to_server(&mut object_server);
tasks.push(Box::new(CtrlAnimeTask::new(inner)));
}
Err(err) => {
error!("AniMe control: {}", err);
}
}
let laptop = LaptopLedData::get_data();
let aura_config = AuraConfig::load(&laptop);
match CtrlKbdLed::new(laptop, aura_config) {
Ok(ctrl) => {
let inner = Arc::new(Mutex::new(ctrl));
let mut reload = CtrlKbdLedReloader(inner.clone());
reload
.reload()
.unwrap_or_else(|err| warn!("Keyboard LED control: {}", err));
CtrlKbdLedZbus::new(inner.clone()).add_to_server(&mut object_server);
let task = CtrlKbdLedTask(inner);
tasks.push(Box::new(task));
}
Err(err) => {
error!("Keyboard control: {}", err);
}
}
// Graphics switching requires some checks on boot specifically for g-sync capable laptops
if enable_gfx_switching {
match CtrlGraphics::new(config.clone()) {
Ok(mut ctrl) => {
// Need to check if a laptop has the dedicated gfx switch
if CtrlRogBios::has_dedicated_gfx_toggle() {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(vendor) = ctrl.get_gfx_mode() {
if ded == 1 && vendor != GfxVendors::Nvidia {
if let Ok(mut config) = config.lock() {
if ded == 1 {
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
config.gfx_last_mode = config.gfx_mode;
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks(
@@ -117,6 +159,14 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
)?;
} else if ded == 0 {
info!("Dedicated GFX toggle is off");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks(
config.gfx_last_mode,
false,
&devices,
&bus,
)?;
}
}
}
@@ -131,61 +181,44 @@ 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).map_err(|err| {
error!("Profile control: {}", err);
}) {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
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()
// Run tasks
let handle = std::thread::Builder::new()
.name("asusd watch".to_string())
.spawn(move || loop {
std::thread::sleep(std::time::Duration::from_millis(100));
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
ctrl.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
});
// Run zbus server
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 to check errors and iterate zbus server
loop {
if let Err(err) = &handle {
error!("{}", err);
}
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);
error!("{}", err);
}
}
}

View File

@@ -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),
@@ -38,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),
@@ -80,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),
}
}
}
@@ -95,3 +96,10 @@ impl From<std::io::Error> for RogError {
RogError::Io(err)
}
}
impl From<RogError> for zbus::fdo::Error {
#[inline]
fn from(err: RogError) -> Self {
zbus::fdo::Error::Failed(format!("{}", err))
}
}

View File

@@ -1,5 +1,5 @@
use log::{info, warn};
use rog_types::aura_modes::AuraModeNum;
use rog_aura::AuraModeNum;
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Read;

View File

@@ -1,12 +1,17 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub mod config_anime;
pub mod config_aura;
pub(crate) mod config_old;
/// Control of AniMe matrix display
pub mod ctrl_anime;
/// Control of battery charge level
pub mod ctrl_charge;
/// GPU switching and power
pub mod ctrl_gfx;
/// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_leds;
/// Control CPU min/max freq and turbo, fan mode, fan curves
///
/// Intel machines can control:
@@ -18,11 +23,7 @@ pub mod ctrl_charge;
/// - CPU turbo enable/disable
/// - Fan mode (normal, boost, silent)
/// - Fan min/max RPM curve
pub mod ctrl_fan_cpu;
/// GPU switching and power
pub mod ctrl_gfx;
/// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_leds;
pub mod ctrl_profiles;
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
pub mod ctrl_rog_bios;
/// Laptop matching to determine capabilities
@@ -48,7 +49,7 @@ pub trait ZbusAdd {
}
pub trait CtrlTask {
fn do_task(&mut self) -> Result<(), RogError>;
fn do_task(&self) -> Result<(), RogError>;
}
pub trait CtrlTaskComplex {

BIN
data/anime/asus/festive/Cupid.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
data/anime/asus/gaming/Bird.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
data/anime/asus/gaming/FPS.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
data/anime/asus/gaming/Fight.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
data/anime/asus/gaming/MOBA.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
data/anime/asus/gaming/UFO.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
data/anime/asus/music/DJ.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
data/anime/asus/rog/Fragment.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
data/anime/asus/rog/Sunset.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
data/anime/asus/trend/Dog.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
data/anime/asus/trend/Ski.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
data/anime/asus/trend/Wave.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
data/anime/custom/rust.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

14
data/asusd-user.service Normal file
View 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

View File

@@ -10,4 +10,6 @@ Restart=on-failure
Restart=always
RestartSec=1
Type=dbus
BusName=org.asuslinux.Daemon
BusName=org.asuslinux.Daemon
SELinuxContext=system_u:system_r:unconfined_t:s0
#SELinuxContext=system_u:object_r:modules_object_t:s0

64
data/user-example.json Normal file
View 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
}
}
]
}

89
design-patterns.md Normal file
View File

@@ -0,0 +1,89 @@
# Daemon
## Controller pattern
There are a series of traits in the daemon for use with controller objects. Not all traits are required:
- `Reloadable`, for controllers that need the ability to reload (typically on start)
- `ZbusAdd`, for controllers that have zbus derive. These need to run on the zbus server.
- `CtrlTask`, for controllers that need to run tasks every loop.
- `GetSupported`, see if the hardware/functions this controller requires are supported.
The first 3 trait objects get owned by the daemon methods that required them, which is why an `Arc<Mutex<T>>` is required.
Generally the actual controller object will need to live in its own world as its own struct.
Then for each trait that is required a new struct is required that can have the trait implemented, and that struct would have a reference to the main controller via `Arc<Mutex<T>>`.
### Example
Main controller:
```rust
pub struct CtrlAnime {
<things the controller requires>
}
impl CtrlAnime {
<functions the controller exposes>
}
```
The task trait:
```rust
pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>);
impl crate::CtrlTask for CtrlAnimeTask {
fn do_task(&self) -> Result<(), RogError> {
if let Ok(lock) = self.inner.try_lock() {
<some action>
}
Ok(())
}
}
```
The reloader trait
```rust
pub struct CtrlAnimeReloader(Arc<Mutex<CtrlAnime>>);
impl crate::Reloadable for CtrlAnimeReloader {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(lock) = self.inner.try_lock() {
<some action>
}
Ok(())
}
}
```
The Zbus requirements:
```rust
pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>);
impl crate::ZbusAdd for CtrlAnimeZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlAnimeZbus {
fn <zbus method>() {
if let Ok(lock) = self.inner.try_lock() {
<some action>
}
}
}
```
The controller can then be added to the daemon parts as required.

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