Compare commits

...

91 Commits

Author SHA1 Message Date
Luke D. Jones 5403c5fb4f Update changelog 2022-06-20 23:16:25 +12:00
Luke D. Jones 65986c3114 prep new release 2022-06-20 23:13:17 +12:00
Luke D. Jones 13a90b00f3 Adjust how thread exit is handled for anime controller 2022-06-20 22:43:12 +12:00
Luke Jones 2ee7fc9910 Merge branch '191-full-power-states-combinations' into 'main'
Combination for power state leds boot/sleep/all/keys/side LEDS

Closes #191

See merge request asus-linux/asusctl!111
2022-06-19 22:03:23 +00:00
mpiffault a0a0efabbb Combination for power state leds boot/sleep/all/keys/side LEDS 2022-06-19 22:03:23 +00:00
Luke Jones 9a50278b98 Merge branch 'fluke/async-tasks' into 'main'
Fixes to tasks

See merge request asus-linux/asusctl!110
2022-06-12 03:42:09 +00:00
Luke D. Jones 9519a35e32 Fixes to tasks 2022-06-12 15:34:38 +12:00
Luke Jones 578d5fd541 Merge branch 'fix/199-multizone-commands-not-displayed' into 'main'
Fixes #199 multizone commands not displayed

Closes #199

See merge request asus-linux/asusctl!109
2022-06-12 03:32:11 +00:00
Martin Piffault 642bc5dda1 output multizone commands required 2022-06-07 22:31:53 +02:00
Martin Piffault 88274abdb5 init multizone_led_mode and per_key_led_mode from LaptopLedData 2022-06-07 22:30:37 +02:00
Luke Jones aea65f5c5f Merge branch 'fluke/async-tasks' into 'main'
Re-enable notif for profile change

See merge request asus-linux/asusctl!108
2022-06-07 00:13:24 +00:00
Luke D. Jones edfbfde13b Re-enable notif for profile change 2022-06-07 12:08:36 +12:00
Luke Jones dcc676d60a Merge branch 'fluke/async-tasks' into 'main'
Added tasks for reload keyboard bright, and for charge control

See merge request asus-linux/asusctl!107
2022-06-06 23:53:41 +00:00
Luke D. Jones 561f61116c Added tasks for reload keyboard bright, and for charge control 2022-06-07 11:49:12 +12:00
Luke Jones 6a4594466b Merge branch 'fluke/async-tasks' into 'main'
Async tasks

See merge request asus-linux/asusctl!106
2022-06-06 13:00:10 +00:00
Luke D. Jones af216ee08c Async tasks 2022-06-07 00:54:33 +12:00
Luke D. Jones e493113450 update changelog 2022-06-06 18:25:27 +12:00
Luke D. Jones 74e1d5bdc4 Add brightness to anime zbus notif 2022-06-06 18:24:08 +12:00
Luke D. Jones 5c0ad3e590 Re-enable notification on anime power-state change 2022-06-06 18:18:35 +12:00
Luke D. Jones 6e872ecab9 Add diagonal-template.png to rog-anime/data/anime/custom/
Closes #163
2022-06-06 17:20:38 +12:00
Luke D. Jones 46a4cde77f Add G512 to LED support list
Closes #174
2022-06-06 17:02:41 +12:00
Luke D. Jones fc7c444107 Add GU502LV LED support
Closes #187
2022-06-06 16:57:50 +12:00
Luke D. Jones 822438e0d2 Version bumps 2022-06-06 14:53:30 +12:00
Luke D. Jones de43a37e9e Use smol async for daemon and daemon-user 2022-06-06 14:34:59 +12:00
Luke D. Jones d4b2d2f403 Use smol async for asus-notify 2022-06-06 13:57:03 +12:00
Luke D. Jones 6e33eab136 Update anime examples 2022-06-06 13:11:54 +12:00
Luke D. Jones 1e4bc85fee Partial asusd-user update 2022-06-06 01:33:14 +12:00
Luke D. Jones 31fff75f08 Update more deps 2022-06-06 00:41:07 +12:00
Luke D. Jones f0620154c8 Update changelog 2022-06-06 00:21:05 +12:00
Luke D. Jones 711aa1e4be Add support for GA402R
Closes #196
2022-06-06 00:14:28 +12:00
Luke D. Jones 854f2d75b3 Format 2022-06-06 00:09:23 +12:00
Luke D. Jones a85e2f6130 Finalise zbus3 conversion 2022-06-06 00:08:59 +12:00
Luke Jones bac2ba6f09 Merge branch 'mpiffault-main-patch-00521' into 'main'
Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QM

See merge request asus-linux/asusctl!103
2022-06-05 02:58:49 +00:00
Luke Jones 47e5270f9c Merge branch 'feat/side-leds-toggle-support' into 'main'
Adds support to enable/disable side leds #191

See merge request asus-linux/asusctl!104
2022-06-05 02:58:24 +00:00
Luke Jones 68cbf09e9f Merge branch 'fix/aura-help-options-display' into 'main'
Fixes all available led-mode commands not displaying with `asusctl led-mode --help`

See merge request asus-linux/asusctl!105
2022-06-05 02:54:31 +00:00
Martin Piffault 9f18c88153 fix all available options not being displayed in led-mode help 2022-06-04 14:47:40 +02:00
Martin Piffault c6caafdcb7 adds support to enable/disable side leds 2022-05-31 17:00:21 +02:00
mpiffault b22a3e1a59 Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QM 2022-05-30 08:06:26 +00:00
Luke Jones b6934bbf63 Merge branch 'as/issue_176_1' into 'main'
Fix for fan_curve related integer divison bug

Closes #176

See merge request asus-linux/asusctl!102
2022-04-08 21:18:47 +00:00
Armas Spann 3cd6eb13a9 fixed interger division bug and related tests, as well as a comment bug 2022-04-07 01:16:06 +02:00
Luke Jones 272be2aaad Merge branch 'as/issue_176' into 'main'
fix for #176 - fancurve percentage check not handled correctly

Closes #176

See merge request asus-linux/asusctl!101
2022-04-05 21:37:23 +00:00
Armas Spann 99dd6ce77f fix for #176 - fancurve percentage check not handled correctly 2022-04-05 23:33:43 +02:00
Luke Jones fc14455da4 Merge branch 'ankushmishra9-main-patch-66732' into 'main'
Fixed formatting of install instructions

See merge request asus-linux/asusctl!96
2022-02-07 22:59:34 +00:00
Luke Jones 26a52dae23 Merge branch 'main' into 'main'
add g513ic led

See merge request asus-linux/asusctl!94
2022-01-19 20:13:34 +00:00
Ankush Mishra 75864d33a6 Fixed formatting of install instructions 2022-01-19 17:57:06 +00:00
Luke Jones 63a97b6665 Merge branch 'main' into 'main'
fixed a small typo

See merge request asus-linux/asusctl!95
2022-01-15 20:51:52 +00:00
AlenPaulVarghese 21a37a3bb0 fixed a small typo 2022-01-14 18:49:15 +00:00
dada513 de586b5368 add g513ic led 2022-01-11 10:08:45 +00:00
Luke D. Jones ba40c3f739 Update dependencies 2021-12-19 21:01:47 +13:00
Luke D. Jones 31eff037a2 Bump to version 4.0.7 2021-12-19 21:00:58 +13:00
Luke D. Jones 630dee0b2a Update notes in CLI tool 2021-12-19 20:57:50 +13:00
Luke Jones 9110f06ed5 Update README.md
Remove whitespace and rustup from fedora build section
2021-12-17 21:18:00 +00:00
Luke Jones 2b0eceaa9d Merge branch 'main' into 'main'
Update of README for building and installing

See merge request asus-linux/asusctl!93
2021-12-17 21:16:56 +00:00
Peter Ross c96e1babe5 Update README.md 2021-12-16 15:23:08 +00:00
Peter Ross 9388cbde5d Update README.md 2021-12-16 15:16:35 +00:00
Luke D. Jones e739cddd6a Update patch links 2021-12-04 16:04:56 +13:00
Luke Jones 8cee6e0fc4 Remove Ubuntu repo instructions 2021-11-14 21:51:56 +00:00
Luke Jones bcf516afeb Merge branch 'sonnyp-main-patch-01923' into 'main'
Update kernel support for Linux 5.15

See merge request asus-linux/asusctl!88
2021-11-12 00:23:54 +00:00
Luke Jones b0e3e81b7f Merge branch 'fix/platform-functions/profile-support' into 'main'
Fix incorrect power profile support validation.

See merge request asus-linux/asusctl!89
2021-11-12 00:23:22 +00:00
Luke Jones ce6a1215a3 Merge branch 'LordVicky-main-patch-24845' into 'main'
Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QE

See merge request asus-linux/asusctl!90
2021-11-12 00:22:51 +00:00
LordVicky f54c1dc7d0 Fix typo 2021-11-09 07:32:39 +00:00
LordVicky 43aaae8d47 Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QE 2021-11-09 07:28:57 +00:00
Alexander Narsudinov ca463a2944 Fix incorrect power profile support validation.
Before this patch power profile support validation used wrong flag from PlatformProfileFunctions struct.
2021-11-07 15:11:31 +03:00
Sonny Piers 20e22589dc Update kernel support for Linux 5.15 2021-11-04 11:47:47 +00:00
Luke D. Jones 38d047cb8a Update changelog 2021-11-01 16:03:40 +13:00
Luke D. Jones 1d977199f3 Fix cli for bios/g-sync 2021-11-01 10:57:40 +13:00
Luke Jones 5041019d77 Merge branch 'fluke/anime-cli' into 'main'
Fluke/anime cli

See merge request asus-linux/asusctl!87
2021-10-30 20:28:36 +00:00
Luke D. Jones aa3835d3b3 Bump versions 2021-10-31 09:24:07 +13:00
Luke D. Jones 678505811d Add additional anime cli commands for image types 2021-10-28 23:43:50 +13:00
Luke D. Jones a925cbaed5 Bump version 2021-10-27 23:19:31 +13:00
Luke Jones 7d2201d873 Merge branch 'fluke/bugfixes' into 'main'
Add led modes for G513QR

Closes #144 and #143

See merge request asus-linux/asusctl!86
2021-10-27 10:18:31 +00:00
Luke D. Jones c0c1608d44 Update deps 2021-10-27 23:15:25 +13:00
Luke D. Jones 7bc6c83a04 Check and pass error if charge limit not in 20-100 range
Closes #144
2021-10-27 23:04:44 +13:00
Luke D. Jones 3f0df82f2d Parse percentages in fan curve only if '%' provided otherwise range is 0-255 2021-10-27 22:42:32 +13:00
Luke D. Jones 328ff0251b Add led modes for G513QR
Closes #143
2021-10-27 22:35:48 +13:00
Luke Jones c52582a413 Merge branch 'fluke/bugfixes' into 'main'
Bugfixes

Closes #139 and #140

See merge request asus-linux/asusctl!85
2021-10-02 07:34:55 +00:00
Luke D. Jones 3aa6eee306 Bugfixes
- Spawn tasks on individual threads
- Don't force a default of fan-curve on reload
- Add missing profile commands
- Begin obsoleting the graphics switch command in favour of supergfxctl
- Slim down the notification daemon to pure ASUS notifications

Bad behaviour in fan-curve new function that was forcing a re-init
to default on reload. Remove this and only save config again after
loading the config file and writing a curve (hidden side effect of
write is that a zeroed array is defaulted to read-from-system - this
needs to be changed too).

Closes #140, #139
2021-10-02 20:31:14 +13:00
Luke Jones 7d47faba0e Merge branch 'plasma-logout' into 'main'
Add kde logout prompt as fallback to gnome-session-quit

See merge request asus-linux/asusctl!82
2021-09-21 08:07:43 +00:00
Luke Jones f6fb477898 Merge branch 'main' into 'main'
Updated asusd-ledmodes.toml with ROG Strix G713QM

See merge request asus-linux/asusctl!83
2021-09-21 08:06:59 +00:00
Abhijith M 8963960d4b Updated asusd-ledmodes.toml with ROG Strix G713QM 2021-09-21 02:09:53 +00:00
Janghyub Seo ef973f676b Add kde logout prompt as fallback to gnome-session-quit 2021-09-19 02:13:11 +09:00
Luke D. Jones 812f9ea30e Add lock update 2021-09-16 22:38:09 +12:00
Luke Jones ff843b1241 Merge branch 'main' into 'main'
Add G533QS to supported models

See merge request asus-linux/asusctl!81
2021-09-16 10:30:09 +00:00
George Dumitrescu 59e7af149d Add G533QS to supported models 2021-09-16 10:07:48 +03:00
Luke D. Jones 6f14c85287 Revert supergfxctl deps to git 2021-09-16 16:03:41 +12:00
Luke D. Jones ac0dec4dbf Bump daemon version for release 2021-09-16 11:20:17 +12:00
Luke D. Jones e3d192412e Bugfixes 2021-09-16 11:19:05 +12:00
Luke Jones 9fadb6db30 Merge branch 'necessary129-main-patch-69023' into 'main'
Add another Strix G17 model

See merge request asus-linux/asusctl!80
2021-09-15 00:06:31 +00:00
Shamil K f8a1b71866 Add another Strix G17 model 2021-09-14 12:00:04 +00:00
Luke Jones c0a55acba7 Merge branch 'main' into 'main'
Adding ROG Flow X13 to LED modes known devices

See merge request asus-linux/asusctl!79
2021-09-14 11:45:56 +00:00
Joseph Ferano 4f232de634 Adding ROG Flow X13 to LED modes known devices 2021-09-14 18:05:42 +07:00
59 changed files with 2343 additions and 1949 deletions
+54 -1
View File
@@ -4,7 +4,60 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased ]
## [4.1.0] - 2022-06-20
### Changed
- Huge refactor to use zbus 2.2 + zvariant 3.0 in system-daemon.
- Daemons with tasks now use `smol` for async ops.
- Fixes to fan-curve settings from CLI (Author: Armas Span)
- Add brightness to anime zbus notification
- Adjust how threads in AniMe matrix controller work
- Use proper power-state packet for keyboard LED's (Author: Martin Piffault)
### Added
- Support for GA402R LED modes
- Support for GU502LV LED modes
- Support for G512 LED modes
- Support for G513IC LED modes (Author: dada513)
- Support for G513QM LED modes (Author: Martin Piffault)
- Add side-LED toggle support (Author: Martin Piffault)
- Support reloading keyboard mode on wake (from sleep/hiber)
- Support reloading charge-level on wake (from sleep/hiber)
- Support running AniMe animation blocks on wake/sleep and boot/shutdown events
# [4.0.7] - 2021-12-19
### Changed
- Fix incorrect power-profile validation
- Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QE (@LordVicky)
- Update patch notes and links
# [4.0.6] - 2021-11-01
### Changed
- Fix CLI for bios toggles
### Added
- Extra commands for AniMe: pixel-image, gif, pixel-gif
# [4.0.5] - 2021-10-27
### Changed
- Convert fan curve percentage to 0-255 expected by kernel driver only if '%' char is used, otherwise the expected range for fan power is 0-255
- Use correct error in daemon for invalid charging limit
- Enforce charging limit values in range 20-100
### Added
- LED modes for G513QR
# [4.0.4] - 2021-10-02
### Changed
- Add missing Profile commands
- Spawn tasks on individual threads to prevent blocking
- Don't force fan-curve default on reload
- Begin obsoleting the graphics switch command in favour of supergfxctl
- Slim down the notification daemon to pure ASUS notifications
# [4.0.3] - 2021-09-16
### Changed
- Don't show fan-curve warning if fan-curve available
- Add G713QR to Strix led-modes
- Fix part of CLI fan-curve control
# [4.0.2] - 2021-09-14 # [4.0.2] - 2021-09-14
### Changed ### Changed
Generated
+678 -481
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -97,7 +97,7 @@ These options are not written to the config file as they are stored in efivars.
### Profiles ### Profiles
asusctl can support setting a power profile via platform_profile drivers. This requires [power-profiles-daemon](https://gitlab.freedesktop.org/hadess/power-profiles-daemon) v0.9.0 minimum. It also requires the kernel patch for platform_profile support to be applied form [here](https://lkml.org/lkml/2021/8/18/1022) - this patch is included in the "rog" kernels we build for fedora and arch, and will hit kernel 5.15 upstream. asusctl can support setting a power profile via platform_profile drivers. This requires [power-profiles-daemon](https://gitlab.freedesktop.org/hadess/power-profiles-daemon) v0.10.0 minimum. It also requires the kernel patch for platform_profile support to be applied form [here](https://lkml.org/lkml/2021/8/18/1022) - this patch is merged to 5.15 kernel upstream.
A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n` to cycle through the 3 profiles: A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n` to cycle through the 3 profiles:
1. Balanced 1. Balanced
@@ -106,7 +106,7 @@ A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n`
#### Fan curves #### Fan curves
Fan curve support requires a laptop that supports it (this is detected automatically) and the kernel patch from [here](https://lkml.org/lkml/2021/8/29/50) which is still in review as of 29/09/21. As with Profiles, this is included in the kernels we build, and will hit 5.15 kernel upstream. Fan curve support requires a laptop that supports it (this is detected automatically) and the kernel patch from [here](https://lkml.org/lkml/2021/10/23/250) which is accepted for the 5.17 kernel release .
The fan curve format can be of varying formats: The fan curve format can be of varying formats:
@@ -356,4 +356,4 @@ Reference to any ASUS products, services, processes, or other information and/or
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops. The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
--- ---
+20 -23
View File
@@ -5,10 +5,11 @@
`asusd` is a utility for Linux to control many aspects of various ASUS laptops `asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features. but can also be used with non-asus laptops with reduced features.
## Kernel patches required ## Kernel support
1. https://lkml.org/lkml/2021/8/20/232 **The minimum supported kernel version is 5.15**
2. https://lkml.org/lkml/2021/8/18/1022
Fan curve control on laptops with this feature require [this patch](https://lkml.org/lkml/2021/10/23/250) which has been merged for 5.17 upstream.
## Goals ## Goals
@@ -24,10 +25,6 @@ supported (while asusd might still run fine on them). For best support use fedor
Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way
a system-level daemon should. a system-level daemon should.
**NOTICE:**
Various patches are required for keyboard support. See [this post](https://asus-linux.org/blog/updates-2021-05-06/) for details on status and which kernels will have which patches.
## Discord ## Discord
[Discord server link](https://discord.gg/4ZKGd7Un5t) [Discord server link](https://discord.gg/4ZKGd7Un5t)
@@ -61,27 +58,27 @@ will probably suffer another rename once it becomes generic enough to do so.
# BUILDING # BUILDING
Requirements are rust >= 1.47 installed from rustup.io if the distro provided version is too old, and `make`. Requirements are rust >= 1.57 installed from rustup.io if the distro provided version is too old, and `make`.
**Ubuntu:** `apt install libclang-dev libudev-dev` **Ubuntu (unsuported):**
**fedora:** `dnf install clang-devel systemd-devel` apt install libclang-dev libudev-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
make
sudo make install
**fedora:**
dnf install clang-devel systemd-devel
make
sudo make install
## Installing ## Installing
- Fedora copr = https://copr.fedorainfracloud.org/coprs/lukenukem/asus-linux/
- openSUSE = https://download.opensuse.org/repositories/home:/luke_nukem:/asus/
- Ubuntu = not supported due to packaging woes, but you can build and install on your own.
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/) for the latest versions of Fedora, Ubuntu, and openSUSE. =======
### Ubuntu
sudo su -c "echo 'deb https://download.opensuse.org/repositories/home:/luke_nukem:/asus/xUbuntu_21.04/ /' > /etc/apt/sources.list.d/luke_nukem.list"
curl -fsSL https://download.opensuse.org/repositories/home:/luke_nukem:/asus/xUbuntu_21.04/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_luke_nukem.gpg > /dev/null
sudo apt-get update
sudo apt-get install asusctl dkms-hid-asus-rog
---
Run `make` then `sudo make install` then reboot.
The default init method is to use the udev rule, this ensures that the service is The default init method is to use the udev rule, this ensures that the service is
started when the device is initialised and ready. started when the device is initialised and ready.
+4 -4
View File
@@ -1,22 +1,22 @@
[package] [package]
name = "asus-notify" name = "asus-notify"
version = "3.0.2" version = "3.1.0"
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
zbus = "^1.9" zbus = "^2.2"
# serialisation # serialisation
serde_json = "^1.0" serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_supported = { path = "../rog-supported" } rog_supported = { path = "../rog-supported" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" } smol = "^1.2"
[dependencies.notify-rust] [dependencies.notify-rust]
version = "^4.3" version = "^4.3"
default-features = false default-features = false
features = ["z"] features = ["z"]
+94 -138
View File
@@ -1,15 +1,16 @@
use notify_rust::{Hint, Notification, NotificationHandle}; use notify_rust::{Hint, Notification, NotificationHandle};
use rog_aura::AuraEffect; use rog_aura::AuraEffect;
use rog_dbus::{DbusProxies, Signals}; use rog_dbus::{
zbus_charge::ChargeProxy, zbus_led::LedProxy, zbus_profile::ProfileProxy,
zbus_rogbios::RogBiosProxy,
};
use rog_profiles::Profile; use rog_profiles::Profile;
use std::error::Error; use smol::{future, Executor};
use std::sync::mpsc::channel; use std::{
use std::thread::sleep; error::Error,
use std::time::Duration; sync::{Arc, Mutex},
use std::{process, thread}; };
use supergfxctl::gfx_vendors::{GfxRequiredUserAction, GfxVendors}; use zbus::export::futures_util::StreamExt;
use supergfxctl::zbus_proxy::GfxProxy;
use zbus::Connection;
const NOTIF_HEADER: &str = "ROG Control"; const NOTIF_HEADER: &str = "ROG Control";
@@ -19,7 +20,7 @@ macro_rules! notify {
notif.close(); notif.close();
} }
if let Ok(x) = $notifier($data) { if let Ok(x) = $notifier($data) {
$last_notif = Some(x); $last_notif.replace(x);
} }
}; };
} }
@@ -34,99 +35,99 @@ macro_rules! base_notification {
}; };
} }
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("asus-notify version {}", env!("CARGO_PKG_VERSION")); println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
println!(" rog-dbus version {}", rog_dbus::VERSION); println!(" rog-dbus version {}", rog_dbus::VERSION);
println!("supergfxctl version {}", supergfxctl::VERSION);
let (proxies, conn) = DbusProxies::new()?; let last_notification: SharedHandle = Arc::new(Mutex::new(None));
let signals = Signals::new(&proxies)?;
let mut last_notification: Option<NotificationHandle> = None; let executor = Executor::new();
// BIOS notif
let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = RogBiosProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_post_boot_sound().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_post_sound_notif, lock, &out.sound());
}
}
future::ready(())
})
.await;
};
})
.detach();
let recv = proxies.setup_recv(conn); // Charge notif
let mut err_count = 0; let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = ChargeProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_charge().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_charge_notif, lock, &out.limit);
}
}
future::ready(())
})
.await;
};
})
.detach();
gfx_thread()?; // Profile notif
let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = ProfileProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_profile().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_thermal_notif, lock, &out.profile);
}
}
future::ready(())
})
.await;
};
})
.detach();
// LED notif
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_led().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = last_notification.try_lock() {
notify!(do_led_notif, lock, &out.data);
}
}
future::ready(())
})
.await;
};
})
.detach();
loop { loop {
sleep(Duration::from_millis(100)); smol::block_on(executor.tick());
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(data) = signals.led_mode.try_recv() {
notify!(do_led_notif, last_notification, &data);
}
if let Ok(data) = signals.profile.try_recv() {
notify!(do_thermal_notif, last_notification, &data);
}
if let Ok(data) = signals.charge.try_recv() {
notify!(do_charge_notif, last_notification, &data);
}
} }
} }
fn gfx_thread() -> Result<(), Box<dyn std::error::Error>> {
let mut last_notification: Option<NotificationHandle> = None;
let conn = Connection::new_system()?;
let proxy = GfxProxy::new(&conn)?;
let (tx1, rx1) = channel();
proxy.connect_notify_gfx(tx1)?;
let (tx2, rx2) = channel();
proxy.connect_notify_action(tx2)?;
thread::spawn(move || loop {
if proxy
.next_signal()
.map_err(|e| println!("Error: {}", e))
.is_err()
{
break;
}
if let Ok(data) = rx1.try_recv() {
notify!(do_gfx_notif, last_notification, &data);
}
if let Ok(data) = rx2.try_recv() {
match data {
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
do_gfx_action_notif(&data)
.map_err(|e| {
println!("Error: {}", e);
})
.ok();
}
GfxRequiredUserAction::Integrated => {
base_notification!(
"You must be in integrated mode first to switch to the requested mode"
)
.map_err(|e| {
println!("Error: {}", e);
})
.ok();
}
GfxRequiredUserAction::None => {}
}
}
});
Ok(())
}
fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> { fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {
let icon = match profile { let icon = match profile {
Profile::Balanced => "asus_notif_yellow", Profile::Balanced => "asus_notif_yellow",
@@ -160,51 +161,6 @@ fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error:
base_notification!(&format!("Battery charge limit changed to {}", limit)) base_notification!(&format!("Battery charge limit changed to {}", limit))
} }
fn do_gfx_notif(vendor: &GfxVendors) -> Result<NotificationHandle, notify_rust::error::Error> { fn do_post_sound_notif(on: &bool) -> Result<NotificationHandle, notify_rust::error::Error> {
let icon = match vendor { base_notification!(&format!("BIOS Post sound {}", on))
GfxVendors::Nvidia => "/usr/share/icons/hicolor/scalable/status/gpu-nvidia.svg",
GfxVendors::Integrated => "/usr/share/icons/hicolor/scalable/status/gpu-integrated.svg",
GfxVendors::Compute => "/usr/share/icons/hicolor/scalable/status/gpu-compute.svg",
GfxVendors::Vfio => "/usr/share/icons/hicolor/scalable/status/gpu-vfio.svg",
GfxVendors::Hybrid => "/usr/share/icons/hicolor/scalable/status/gpu-hybrid.svg",
};
Notification::new()
.summary(NOTIF_HEADER)
.body(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))
.timeout(2000)
.icon(icon)
.show()
}
fn do_gfx_action_notif(vendor: &GfxRequiredUserAction) -> Result<(), notify_rust::error::Error> {
let mut notif = Notification::new()
.summary(NOTIF_HEADER)
.timeout(2000)
.urgency(notify_rust::Urgency::Critical)
.icon("/usr/share/icons/hicolor/scalable/status/notification-reboot.svg")
.finalize();
if matches!(vendor, GfxRequiredUserAction::Logout) {
notif.action("logout", "Logout now?");
} else if matches!(vendor, GfxRequiredUserAction::Reboot) {
notif.action("reboot", "Reboot now?");
}
notif.body("Graphics mode changed");
notif.show()?.wait_for_action(|action| match action {
"logout" => {
process::Command::new("gnome-session-quit").spawn().ok();
}
"reboot" => {
process::Command::new("systemctl")
.arg("reboot")
.spawn()
.ok();
}
_ => (),
});
Ok(())
} }
+5 -6
View File
@@ -1,13 +1,13 @@
[package] [package]
name = "asusctl" name = "asusctl"
version = "4.0.2" version = "4.0.7"
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
zbus = "^1.9.1" zbus = "^2.2"
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
@@ -15,13 +15,12 @@ rog_profiles = { path = "../rog-profiles" }
rog_supported = { path = "../rog-supported" } rog_supported = { path = "../rog-supported" }
daemon = { path = "../daemon" } daemon = { path = "../daemon" }
gumdrop = "^0.8" gumdrop = "^0.8"
supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" }
toml = "^0.5.8" toml = "^0.5.8"
sysfs-class = "^0.1.2" sysfs-class = "^0.1.2"
[dev-dependencies] [dev-dependencies]
tinybmp = "^0.2.3" tinybmp = "^0.3.3"
glam = "0.14.0" glam = "0.20.5"
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
gif = "^0.11.2" gif = "^0.11.2"
+2 -2
View File
@@ -1,10 +1,10 @@
use std::{env, error::Error, path::Path, process::exit}; use std::{env, error::Error, path::Path, process::exit};
use rog_anime::{AnimeDataBuffer, AnimeDiagonal}; use rog_anime::{AnimeDataBuffer, AnimeDiagonal};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect(); let args: Vec<String> = env::args().into_iter().collect();
if args.len() != 3 { if args.len() != 3 {
+2 -2
View File
@@ -1,7 +1,7 @@
use std::{thread::sleep, time::Duration}; use std::{thread::sleep, time::Duration};
use rog_anime::{AnimeDataBuffer, AnimeDiagonal}; use rog_anime::{AnimeDataBuffer, AnimeDiagonal};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
@@ -9,7 +9,7 @@ use rog_dbus::RogDbusClient;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
for step in (2..50).rev() { for step in (2..50).rev() {
let mut matrix = AnimeDiagonal::new(None); let mut matrix = AnimeDiagonal::new(None);
+2 -2
View File
@@ -1,10 +1,10 @@
use std::{env, path::Path, thread::sleep}; use std::{env, path::Path, thread::sleep};
use rog_anime::{ActionData, ActionLoader, Sequences}; use rog_anime::{ActionData, ActionLoader, Sequences};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
fn main() { fn main() {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect(); let args: Vec<String> = env::args().into_iter().collect();
if args.len() != 3 { if args.len() != 3 {
+2 -2
View File
@@ -1,5 +1,5 @@
use rog_anime::{AnimeDataBuffer, AnimeGrid}; use rog_anime::{AnimeDataBuffer, AnimeGrid};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
@@ -7,7 +7,7 @@ use rog_dbus::RogDbusClient;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let mut matrix = AnimeGrid::new(None); let mut matrix = AnimeGrid::new(None);
let tmp = matrix.get_mut(); let tmp = matrix.get_mut();
+2 -2
View File
@@ -1,11 +1,11 @@
use rog_anime::AnimeDataBuffer; use rog_anime::AnimeDataBuffer;
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
// In usable data: // In usable data:
// Top row start at 1, ends at 32 // Top row start at 1, ends at 32
fn main() { fn main() {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let mut matrix = AnimeDataBuffer::new(); let mut matrix = AnimeDataBuffer::new();
matrix.get_mut()[1] = 100; // start = 1 matrix.get_mut()[1] = 100; // start = 1
for n in matrix.get_mut()[2..32].iter_mut() { for n in matrix.get_mut()[2..32].iter_mut() {
+2 -2
View File
@@ -3,10 +3,10 @@ use std::{env, error::Error, path::Path, process::exit};
use rog_anime::{ use rog_anime::{
AnimeDataBuffer, {AnimeImage, Vec2}, AnimeDataBuffer, {AnimeImage, Vec2},
}; };
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect(); let args: Vec<String> = env::args().into_iter().collect();
if args.len() != 7 { if args.len() != 7 {
+2 -2
View File
@@ -5,10 +5,10 @@ use std::{
use rog_anime::{ use rog_anime::{
AnimeDataBuffer, {AnimeImage, Vec2}, AnimeDataBuffer, {AnimeImage, Vec2},
}; };
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = RogDbusClient::new().unwrap(); let (client, _) = RogDbusClientBlocking::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect(); let args: Vec<String> = env::args().into_iter().collect();
if args.len() != 7 { if args.len() != 7 {
+66 -57
View File
@@ -1,54 +1,4 @@
use gumdrop::Options; 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)] #[derive(Options)]
pub struct AnimeCommand { pub struct AnimeCommand {
@@ -56,21 +6,30 @@ pub struct AnimeCommand {
pub help: bool, pub help: bool,
#[options( #[options(
meta = "", meta = "",
help = "turn on/off the panel (accept/reject write requests)" help = "enable/disable the panel LEDs (does not erase last image)"
)] )]
pub turn: Option<AnimeStatusValue>, pub enable: Option<bool>,
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")] #[options(
pub boot: Option<AnimeStatusValue>, meta = "",
help = "enable/disable system animations (boot/sleep/shutdown)"
)]
pub boot_enable: Option<bool>,
#[options(meta = "", help = "set global AniMe brightness value")]
pub brightness: Option<f32>,
#[options(command)] #[options(command)]
pub command: Option<AnimeActions>, pub command: Option<AnimeActions>,
} }
#[derive(Options)] #[derive(Options)]
pub enum AnimeActions { pub enum AnimeActions {
#[options(help = "change all leds brightness")] #[options(help = "display a PNG image")]
Leds(AnimeLeds),
#[options(help = "display an image png")]
Image(AnimeImage), Image(AnimeImage),
#[options(help = "display a diagonal/pixel-perfect PNG")]
PixelImage(AnimeImageDiagonal),
#[options(help = "display an animated GIF")]
Gif(AnimeGif),
#[options(help = "display an animated diagonal/pixel-perfect GIF")]
PixelGif(AnimeGifDiagonal),
} }
#[derive(Options)] #[derive(Options)]
@@ -90,3 +49,53 @@ pub struct AnimeImage {
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")] #[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32, pub bright: f32,
} }
#[derive(Options)]
pub struct AnimeImageDiagonal {
#[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 = "brightness 0.0-1.0")]
pub bright: f32,
}
#[derive(Options)]
pub struct AnimeGif {
#[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,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}
#[derive(Options)]
pub struct AnimeGifDiagonal {
#[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 = "brightness 0.0-1.0")]
pub bright: f32,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}
+13 -16
View File
@@ -4,7 +4,6 @@ use crate::{
profiles_cli::{FanCurveCommand, ProfileCommand}, profiles_cli::{FanCurveCommand, ProfileCommand},
}; };
use gumdrop::Options; use gumdrop::Options;
use supergfxctl::gfx_vendors::GfxVendors;
#[derive(Default, Options)] #[derive(Default, Options)]
pub struct CliStart { pub struct CliStart {
@@ -20,7 +19,7 @@ pub struct CliStart {
pub next_kbd_bright: bool, pub next_kbd_bright: bool,
#[options(help = "Toggle to previous keyboard brightness")] #[options(help = "Toggle to previous keyboard brightness")]
pub prev_kbd_bright: bool, pub prev_kbd_bright: bool,
#[options(meta = "", help = "<20-100>")] #[options(meta = "", help = "Set your battery charge limit <20-100>")]
pub chg_limit: Option<u8>, pub chg_limit: Option<u8>,
#[options(command)] #[options(command)]
pub command: Option<CliCommand>, pub command: Option<CliCommand>,
@@ -32,9 +31,9 @@ pub enum CliCommand {
LedMode(LedModeCommand), LedMode(LedModeCommand),
#[options(help = "Set or select platform_profile")] #[options(help = "Set or select platform_profile")]
Profile(ProfileCommand), Profile(ProfileCommand),
#[options(help = "Set, select, or modify fan curves if suported")] #[options(help = "Set, select, or modify fan curves if supported")]
FanCurve(FanCurveCommand), FanCurve(FanCurveCommand),
#[options(help = "Set the graphics mode")] #[options(help = "Set the graphics mode (obsoleted by supergfxctl)")]
Graphics(GraphicsCommand), Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")] #[options(name = "anime", help = "Manage AniMe Matrix")]
Anime(AnimeCommand), Anime(AnimeCommand),
@@ -54,12 +53,21 @@ pub struct LedModeCommand {
meta = "", meta = "",
help = "set the keyboard LED to enabled while the device is awake" help = "set the keyboard LED to enabled while the device is awake"
)] )]
pub awake_enable: Option<bool>, pub boot_enable: Option<bool>,
#[options( #[options(
meta = "", meta = "",
help = "set the keyboard LED suspend animation to enabled while the device is suspended" help = "set the keyboard LED suspend animation to enabled while the device is suspended"
)] )]
pub sleep_enable: Option<bool>, pub sleep_enable: Option<bool>,
#[options(
meta = "",
help = "set the full keyboard LEDs (keys and side) to enabled"
)]
pub all_leds_enable: Option<bool>,
#[options(meta = "", help = "set the keyboard keys LEDs to enabled")]
pub keys_leds_enable: Option<bool>,
#[options(meta = "", help = "set the keyboard side LEDs to enabled")]
pub side_leds_enable: Option<bool>,
#[options(command)] #[options(command)]
pub command: Option<SetAuraBuiltin>, pub command: Option<SetAuraBuiltin>,
} }
@@ -68,17 +76,6 @@ pub struct LedModeCommand {
pub struct GraphicsCommand { pub struct GraphicsCommand {
#[options(help = "print help message")] #[options(help = "print help message")]
pub help: bool, pub help: bool,
#[options(
meta = "",
help = "Set graphics mode: <nvidia, hybrid, compute, integrated>"
)]
pub mode: Option<GfxVendors>,
#[options(help = "Get the current mode")]
pub get: bool,
#[options(help = "Get the current power status")]
pub pow: bool,
#[options(help = "Do not ask for confirmation")]
pub force: bool,
} }
#[derive(Options, Debug)] #[derive(Options, Debug)]
+175 -133
View File
@@ -1,29 +1,28 @@
mod anime_cli; use std::process::Command;
mod aura_cli; use std::thread::sleep;
mod cli_opts; use std::{env::args, path::Path};
mod profiles_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use crate::cli_opts::*;
use anime_cli::{AnimeActions, AnimeCommand};
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use anime_cli::{AnimeActions, AnimeCommand};
use profiles_cli::{FanCurveCommand, ProfileCommand}; use profiles_cli::{FanCurveCommand, ProfileCommand};
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2};
use rog_aura::{self, AuraEffect}; use rog_aura::{self, AuraEffect};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
use rog_profiles::error::ProfileError;
use rog_supported::SupportedFunctions; use rog_supported::SupportedFunctions;
use rog_supported::{ use rog_supported::{
AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions,
RogBiosSupportedFunctions, RogBiosSupportedFunctions,
}; };
use std::process::Command;
use std::{env::args, path::Path, sync::mpsc::channel}; use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use supergfxctl::{ use crate::cli_opts::*;
gfx_vendors::GfxRequiredUserAction,
special::{get_asus_gsync_gfx_mode, has_asus_gsync_gfx_mode}, mod anime_cli;
zbus_proxy::GfxProxy, mod aura_cli;
}; mod cli_opts;
use zbus::Connection; mod profiles_cli;
const CONFIG_ADVICE: &str = "A config file need to be removed so a new one can be generated"; const CONFIG_ADVICE: &str = "A config file need to be removed so a new one can be generated";
@@ -48,7 +47,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
let (dbus, _) = RogDbusClient::new() let (dbus, _) = RogDbusClientBlocking::new()
.map_err(|e| { .map_err(|e| {
print_error_help(Box::new(e), None); print_error_help(Box::new(e), None);
std::process::exit(3); std::process::exit(3);
@@ -58,7 +57,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let supported = dbus let supported = dbus
.proxies() .proxies()
.supported() .supported()
.get_supported_functions() .supported_functions()
.map_err(|e| { .map_err(|e| {
print_error_help(Box::new(e), None); print_error_help(Box::new(e), None);
std::process::exit(4); std::process::exit(4);
@@ -102,7 +101,6 @@ fn print_versions() {
println!(" rog-dbus v{}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!(" rog-profiles v{}", rog_profiles::VERSION); println!(" rog-profiles v{}", rog_profiles::VERSION);
println!("rog-supported v{}", rog_supported::VERSION); println!("rog-supported v{}", rog_supported::VERSION);
println!(" supergfxctl v{}", supergfxctl::VERSION);
} }
fn print_laptop_info() { fn print_laptop_info() {
@@ -141,7 +139,7 @@ fn do_diagnose(name: &str) -> bool {
fn do_parsed( fn do_parsed(
parsed: &CliStart, parsed: &CliStart,
supported: &SupportedFunctions, supported: &SupportedFunctions,
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
match &parsed.command { match &parsed.command {
Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?, Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?,
@@ -149,10 +147,7 @@ fn do_parsed(
Some(CliCommand::FanCurve(cmd)) => { Some(CliCommand::FanCurve(cmd)) => {
handle_fan_curve(dbus, &supported.platform_profile, cmd)? handle_fan_curve(dbus, &supported.platform_profile, cmd)?
} }
Some(CliCommand::Graphics(cmd)) => do_gfx(cmd).map_err(|err| { Some(CliCommand::Graphics(_)) => do_gfx()?,
do_gfx_diagnose();
err
})?,
Some(CliCommand::Anime(cmd)) => handle_anime(dbus, &supported.anime_ctrl, cmd)?, Some(CliCommand::Anime(cmd)) => handle_anime(dbus, &supported.anime_ctrl, cmd)?,
Some(CliCommand::Bios(cmd)) => handle_bios_option(dbus, &supported.rog_bios_ctrl, cmd)?, Some(CliCommand::Bios(cmd)) => handle_bios_option(dbus, &supported.rog_bios_ctrl, cmd)?,
None => { None => {
@@ -175,13 +170,13 @@ fn do_parsed(
if let Some(brightness) = &parsed.kbd_bright { if let Some(brightness) = &parsed.kbd_bright {
match brightness.level() { match brightness.level() {
None => { None => {
let level = dbus.proxies().led().get_led_brightness()?; let level = dbus.proxies().led().led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string()); println!("Current keyboard led brightness: {}", level);
} }
Some(level) => dbus Some(level) => dbus
.proxies() .proxies()
.led() .led()
.set_led_brightness(<rog_aura::LedBrightness>::from(level))?, .set_brightness(<rog_aura::LedBrightness>::from(level))?,
} }
} }
@@ -198,107 +193,45 @@ fn do_parsed(
} }
if let Some(chg_limit) = parsed.chg_limit { if let Some(chg_limit) = parsed.chg_limit {
dbus.proxies().charge().write_limit(chg_limit)?; dbus.proxies().charge().set_limit(chg_limit)?;
} }
Ok(()) Ok(())
} }
fn do_gfx_diagnose() { fn do_gfx() -> Result<(), Box<dyn std::error::Error>> {
println!("\nGraphics mode change error."); println!("Please use supergfxctl for graphics switching. supergfxctl is the result of making asusctl graphics switching generic so all laptops can use it");
do_diagnose("supergfxd"); println!("This command will be removed in future");
println!();
}
fn do_gfx(command: &GraphicsCommand) -> Result<(), Box<dyn std::error::Error>> {
if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help {
println!("{}", command.self_usage());
}
let conn = Connection::new_system()?;
let proxy = GfxProxy::new(&conn)?;
let (tx, rx) = channel();
proxy.connect_notify_action(tx)?;
if let Some(mode) = command.mode {
if has_asus_gsync_gfx_mode() && get_asus_gsync_gfx_mode()? == 1 {
println!("You can not change modes until you turn dedicated/G-Sync off and reboot");
std::process::exit(-1);
}
println!(
"If anything fails check `journalctl -b -u asusd` and `journalctl -b -u supergfxd`\n"
);
proxy.gfx_write_mode(&mode)?;
loop {
proxy.next_signal()?;
if let Ok(res) = rx.try_recv() {
match res {
GfxRequiredUserAction::Integrated => {
println!(
"You must change to Integrated before you can change to {}",
<&str>::from(mode)
);
}
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
}
GfxRequiredUserAction::None => {
println!("Graphics mode changed to {}", <&str>::from(mode));
}
}
}
std::process::exit(0)
}
}
if command.get {
let res = proxy.gfx_get_mode()?;
println!("Current graphics mode: {}", <&str>::from(res));
}
if command.pow {
let res = proxy.gfx_get_pwr()?;
println!("Current power status: {}", <&str>::from(&res));
}
Ok(()) Ok(())
} }
fn handle_anime( fn handle_anime(
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
_supported: &AnimeSupportedFunctions, _supported: &AnimeSupportedFunctions,
cmd: &AnimeCommand, cmd: &AnimeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help { if (cmd.command.is_none()
&& cmd.enable.is_none()
&& cmd.boot_enable.is_none()
&& cmd.brightness.is_none())
|| cmd.help
{
println!("Missing arg or command\n\n{}", cmd.self_usage()); println!("Missing arg or command\n\n{}", cmd.self_usage());
if let Some(lst) = cmd.self_command_list() { if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst); println!("\n{}", lst);
} }
} }
if let Some(anime_turn) = cmd.turn { if let Some(anime_turn) = cmd.enable {
dbus.proxies().anime().set_led_power(anime_turn.into())? dbus.proxies().anime().set_on_off(anime_turn)?
} }
if let Some(anime_boot) = cmd.boot { if let Some(anime_boot) = cmd.boot_enable {
dbus.proxies() dbus.proxies().anime().set_boot_on_off(anime_boot)?
.anime() }
.set_system_animations(anime_boot.into())? if let Some(bright) = cmd.brightness {
dbus.proxies().anime().set_brightness(bright as f32)?
} }
if let Some(action) = cmd.command.as_ref() { if let Some(action) = cmd.command.as_ref() {
match action { match action {
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) => { AnimeActions::Image(image) => {
if image.help_requested() || image.path.is_empty() { if image.help_requested() || image.path.is_empty() {
println!("Missing arg or command\n\n{}", image.self_usage()); println!("Missing arg or command\n\n{}", image.self_usage());
@@ -320,21 +253,100 @@ fn handle_anime(
.anime() .anime()
.write(<AnimeDataBuffer>::from(&matrix))?; .write(<AnimeDataBuffer>::from(&matrix))?;
} }
AnimeActions::PixelImage(image) => {
if image.help_requested() || image.path.is_empty() {
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 = AnimeDiagonal::from_png(Path::new(&image.path), None, image.bright)?;
dbus.proxies()
.anime()
.write(<AnimeDataBuffer>::from(&matrix))?;
}
AnimeActions::Gif(gif) => {
if gif.help_requested() || gif.path.is_empty() {
println!("Missing arg or command\n\n{}", gif.self_usage());
if let Some(lst) = gif.self_command_list() {
println!("\n{}", lst);
}
std::process::exit(1);
}
let matrix = AnimeGif::from_gif(
Path::new(&gif.path),
gif.scale,
gif.angle,
Vec2::new(gif.x_pos, gif.y_pos),
AnimTime::Count(1),
gif.bright,
)?;
let mut loops = gif.loops as i32;
loop {
for frame in matrix.frames() {
dbus.proxies().anime().write(frame.frame().clone())?;
sleep(frame.delay());
}
if loops >= 0 {
loops -= 1;
}
if loops == 0 {
break;
}
}
}
AnimeActions::PixelGif(gif) => {
if gif.help_requested() || gif.path.is_empty() {
println!("Missing arg or command\n\n{}", gif.self_usage());
if let Some(lst) = gif.self_command_list() {
println!("\n{}", lst);
}
std::process::exit(1);
}
let matrix = AnimeGif::from_diagonal_gif(
Path::new(&gif.path),
AnimTime::Count(1),
gif.bright,
)?;
let mut loops = gif.loops as i32;
loop {
for frame in matrix.frames() {
dbus.proxies().anime().write(frame.frame().clone())?;
sleep(frame.delay());
}
if loops >= 0 {
loops -= 1;
}
if loops == 0 {
break;
}
}
}
} }
} }
Ok(()) Ok(())
} }
fn handle_led_mode( fn handle_led_mode(
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
mode: &LedModeCommand, mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if mode.command.is_none() if mode.command.is_none()
&& !mode.prev_mode && !mode.prev_mode
&& !mode.next_mode && !mode.next_mode
&& mode.boot_enable.is_none()
&& mode.sleep_enable.is_none() && mode.sleep_enable.is_none()
&& mode.awake_enable.is_none() && mode.all_leds_enable.is_none()
&& mode.keys_leds_enable.is_none()
&& mode.side_leds_enable.is_none()
{ {
if !mode.help { if !mode.help {
println!("Missing arg or command\n"); println!("Missing arg or command\n");
@@ -346,11 +358,14 @@ fn handle_led_mode(
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect();
for command in commands.iter().filter(|command| { for command in commands.iter().filter(|command| {
for mode in &supported.stock_led_modes { for mode in &supported.stock_led_modes {
if command.contains(&<&str>::from(mode).to_lowercase()) { if command
.trim()
.starts_with(&<&str>::from(mode).to_lowercase())
{
return true; return true;
} }
} }
if supported.multizone_led_mode { if supported.multizone_led_mode && command.trim().starts_with("multi") {
return true; return true;
} }
false false
@@ -390,25 +405,38 @@ fn handle_led_mode(
} }
} }
if let Some(enable) = mode.awake_enable { if let Some(enable) = mode.boot_enable {
dbus.proxies().led().set_awake_enabled(enable)?; dbus.proxies().led().set_boot_enabled(enable)?;
} }
if let Some(enable) = mode.sleep_enable { if let Some(enable) = mode.sleep_enable {
dbus.proxies().led().set_sleep_enabled(enable)?; dbus.proxies().led().set_sleep_enabled(enable)?;
} }
if let Some(enable) = mode.all_leds_enable {
dbus.proxies().led().set_all_leds_enabled(enable)?;
}
if let Some(enable) = mode.keys_leds_enable {
dbus.proxies().led().set_keys_leds_enabled(enable)?;
}
if let Some(enable) = mode.side_leds_enable {
dbus.proxies().led().set_side_leds_enabled(enable)?;
}
Ok(()) Ok(())
} }
fn handle_profile( fn handle_profile(
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
_supported: &PlatformProfileFunctions, supported: &PlatformProfileFunctions,
cmd: &ProfileCommand, cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
println!("Warning: Profiles now depend on power-profiles-daemon v0.9+"); if !supported.platform_profile {
println!("Warning: Fan-curve support is coming in a 4.1.x release"); println!("Profiles not supported by either this kernel or by the laptop.");
if !cmd.next && !cmd.list { return Err(ProfileError::NotSupported.into());
}
if !cmd.next && !cmd.list && cmd.profile_set.is_none() && !cmd.profile_get {
if !cmd.help { if !cmd.help {
println!("Missing arg or command\n"); println!("Missing arg or command\n");
} }
@@ -417,28 +445,41 @@ fn handle_profile(
if let Some(lst) = cmd.self_command_list() { if let Some(lst) = cmd.self_command_list() {
println!("\n{}", lst); 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); std::process::exit(1);
} }
if cmd.next { if cmd.next {
dbus.proxies().profile().next_profile()?; dbus.proxies().profile().next_profile()?;
} else if let Some(profile) = cmd.profile_set {
dbus.proxies().profile().set_active_profile(profile)?;
} }
if cmd.list { if cmd.list {
let res = dbus.proxies().profile().profiles()?; let res = dbus.proxies().profile().profiles()?;
res.iter().for_each(|p| println!("{:?}", p)); res.iter().for_each(|p| println!("{:?}", p));
} }
if cmd.profile_get {
let res = dbus.proxies().profile().active_profile()?;
println!("Active profile is {:?}", res);
}
Ok(()) Ok(())
} }
fn handle_fan_curve( fn handle_fan_curve(
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
_supported: &PlatformProfileFunctions, supported: &PlatformProfileFunctions,
cmd: &FanCurveCommand, cmd: &FanCurveCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if !supported.fan_curves {
println!("Fan-curves not supported by either this kernel or by the laptop.");
println!(
"This requires kernel 5.17 (unlreleased) or the fan curve patch listed in the readme."
);
return Err(ProfileError::NotSupported.into());
}
if !cmd.get_enabled && !cmd.default && cmd.mod_profile.is_none() { if !cmd.get_enabled && !cmd.default && cmd.mod_profile.is_none() {
if !cmd.help { if !cmd.help {
println!("Missing arg or command\n"); println!("Missing arg or command\n");
@@ -451,7 +492,8 @@ fn handle_fan_curve(
std::process::exit(1); std::process::exit(1);
} }
if cmd.enabled.is_some() || cmd.fan.is_some() || cmd.data.is_some() && cmd.mod_profile.is_none() if (cmd.enabled.is_some() || cmd.fan.is_some() || cmd.data.is_some())
&& cmd.mod_profile.is_none()
{ {
println!("--enabled, --fan, and --data options require --mod-profile"); println!("--enabled, --fan, and --data options require --mod-profile");
std::process::exit(666); std::process::exit(666);
@@ -482,7 +524,7 @@ fn handle_fan_curve(
if let Some(mut curve) = cmd.data.clone() { if let Some(mut curve) = cmd.data.clone() {
let fan = cmd.fan.unwrap_or_default(); let fan = cmd.fan.unwrap_or_default();
curve.set_fan(fan); curve.set_fan(fan);
dbus.proxies().profile().set_fan_curve(curve, profile)?; dbus.proxies().profile().set_fan_curve(profile, curve)?;
} }
} }
@@ -490,7 +532,7 @@ fn handle_fan_curve(
} }
fn handle_bios_option( fn handle_bios_option(
dbus: &RogDbusClient, dbus: &RogDbusClientBlocking,
supported: &RogBiosSupportedFunctions, supported: &RogBiosSupportedFunctions,
cmd: &BiosCommand, cmd: &BiosCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -509,23 +551,23 @@ fn handle_bios_option(
.collect(); .collect();
for line in usage.iter().filter(|line| { for line in usage.iter().filter(|line| {
!line.contains("sound") && !supported.post_sound_toggle line.contains("sound") && supported.post_sound_toggle
|| !line.contains("GPU") && !supported.dedicated_gfx_toggle || line.contains("GPU") && supported.dedicated_gfx_toggle
}) { }) {
println!("{}", line); println!("{}", line);
} }
} }
if let Some(opt) = cmd.post_sound_set { if let Some(opt) = cmd.post_sound_set {
dbus.proxies().rog_bios().set_post_sound(opt)?; dbus.proxies().rog_bios().set_post_boot_sound(opt)?;
} }
if cmd.post_sound_get { if cmd.post_sound_get {
let res = dbus.proxies().rog_bios().get_post_sound()? == 1; let res = dbus.proxies().rog_bios().post_boot_sound()? == 1;
println!("Bios POST sound on: {}", res); println!("Bios POST sound on: {}", res);
} }
if let Some(opt) = cmd.dedicated_gfx_set { if let Some(opt) = cmd.dedicated_gfx_set {
println!("Rebuilding initrd to include drivers"); println!("Rebuilding initrd to include drivers");
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?; dbus.proxies().rog_bios().set_dedicated_graphic_mode(opt)?;
println!("The mode change is not active until you reboot, on boot the bios will make the required change"); println!("The mode change is not active until you reboot, on boot the bios will make the required change");
if opt { if opt {
println!( println!(
@@ -536,7 +578,7 @@ fn handle_bios_option(
} }
} }
if cmd.dedicated_gfx_get { if cmd.dedicated_gfx_get {
let res = dbus.proxies().rog_bios().get_dedicated_gfx()? == 1; let res = dbus.proxies().rog_bios().dedicated_graphic_mode()? == 1;
println!("Bios dedicated GPU on: {}", res); println!("Bios dedicated GPU on: {}", res);
} }
} }
+3 -2
View File
@@ -12,7 +12,7 @@ pub struct ProfileCommand {
#[options(help = "get profile")] #[options(help = "get profile")]
pub profile_get: bool, pub profile_get: bool,
#[options(help = "set the active profile")] #[options(meta = "", help = "set the active profile")]
pub profile_set: Option<Profile>, pub profile_set: Option<Profile>,
} }
@@ -44,7 +44,8 @@ pub struct FanCurveCommand {
#[options( #[options(
meta = "", meta = "",
help = "data format = 30c:1%,49c:2%,59c:3%,69c:4%,79c:31%,89c:49%,99c:56%,109c:58%. `mod-profile` required" help = "data format = 30c:1%,49c:2%,59c:3%,69c:4%,79c:31%,89c:49%,99c:56%,109c:58%.
`--mod-profile` required. If '%' is omitted the fan range is 0-255"
)] )]
pub data: Option<CurveData>, pub data: Option<CurveData>,
} }
+7 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "daemon-user" name = "daemon-user"
version = "1.2.0" version = "1.3.0"
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018" edition = "2018"
description = "Usermode daemon for user settings, anime, per-key lighting" description = "Usermode daemon for user settings, anime, per-key lighting"
@@ -23,8 +23,10 @@ rog_anime = { path = "../rog-anime" }
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rog_supported = { path = "../rog-supported" } rog_supported = { path = "../rog-supported" }
dirs = "3.0.1" dirs = "^4.0"
zbus = "^1.9.1" zbus = "^2.2"
zvariant = "^2.6" zvariant = "^3.0"
zvariant_derive = "^2.6" zvariant_derive = "^3.0"
smol = "^1.2"
+15 -9
View File
@@ -1,6 +1,6 @@
use rog_anime::error::AnimeError; use rog_anime::error::AnimeError;
use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2}; use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2};
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use std::{ use std::{
@@ -66,14 +66,14 @@ pub enum TimeType {
/// and a zbus server behind `Arc<Mutex<T>>` /// and a zbus server behind `Arc<Mutex<T>>`
pub struct CtrlAnimeInner<'a> { pub struct CtrlAnimeInner<'a> {
sequences: Sequences, sequences: Sequences,
client: RogDbusClient<'a>, client: RogDbusClientBlocking<'a>,
do_early_return: Arc<AtomicBool>, do_early_return: Arc<AtomicBool>,
} }
impl<'a> CtrlAnimeInner<'static> { impl<'a> CtrlAnimeInner<'static> {
pub fn new( pub fn new(
sequences: Sequences, sequences: Sequences,
client: RogDbusClient<'static>, client: RogDbusClientBlocking<'static>,
do_early_return: Arc<AtomicBool>, do_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
@@ -91,12 +91,16 @@ impl<'a> CtrlAnimeInner<'static> {
for action in self.sequences.iter() { for action in self.sequences.iter() {
match action { match action {
ActionData::Animation(frames) => { ActionData::Animation(frames) => {
rog_anime::run_animation(frames, self.do_early_return.clone(), &|output| { rog_anime::run_animation(frames, &|output| {
if self.do_early_return.load(Ordering::Acquire) {
return Ok(true); // Do safe exit
}
self.client self.client
.proxies() .proxies()
.anime() .anime()
.write(output) .write(output)
.map_err(|e| AnimeError::Dbus(format!("{}", e))) .map_err(|e| AnimeError::Dbus(format!("{}", e)))
.map(|_| false)
})?; })?;
} }
ActionData::Image(image) => { ActionData::Image(image) => {
@@ -131,7 +135,7 @@ impl<'a> CtrlAnimeInner<'static> {
pub struct CtrlAnime<'a> { pub struct CtrlAnime<'a> {
config: Arc<Mutex<UserAnimeConfig>>, config: Arc<Mutex<UserAnimeConfig>>,
client: RogDbusClient<'a>, client: RogDbusClientBlocking<'a>,
inner: Arc<Mutex<CtrlAnimeInner<'a>>>, inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
/// Must be the same Atomic as in CtrlAnimeInner /// Must be the same Atomic as in CtrlAnimeInner
inner_early_return: Arc<AtomicBool>, inner_early_return: Arc<AtomicBool>,
@@ -141,7 +145,7 @@ impl<'a> CtrlAnime<'static> {
pub fn new( pub fn new(
config: Arc<Mutex<UserAnimeConfig>>, config: Arc<Mutex<UserAnimeConfig>>,
inner: Arc<Mutex<CtrlAnimeInner<'static>>>, inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
client: RogDbusClient<'static>, client: RogDbusClientBlocking<'static>,
inner_early_return: Arc<AtomicBool>, inner_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(CtrlAnime { Ok(CtrlAnime {
@@ -152,12 +156,14 @@ impl<'a> CtrlAnime<'static> {
}) })
} }
pub fn add_to_server(self, server: &mut zbus::ObjectServer) { pub async fn add_to_server(self, server: &mut zbus::Connection) {
server server
.object_server()
.at( .at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), &ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self, self,
) )
.await
.map_err(|err| { .map_err(|err| {
println!("CtrlAnime: add_to_server {}", err); println!("CtrlAnime: add_to_server {}", err);
err err
@@ -353,13 +359,13 @@ impl CtrlAnime<'static> {
pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> { pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> {
// Operations here need to be in specific order // Operations here need to be in specific order
if on { if on {
self.client.proxies().anime().set_led_power(on)?; self.client.proxies().anime().set_on_off(on).ok();
// Let the inner loop run // Let the inner loop run
self.inner_early_return.store(false, Ordering::SeqCst); self.inner_early_return.store(false, Ordering::SeqCst);
} else { } else {
// Must make the inner run loop return early // Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
self.client.proxies().anime().set_led_power(on)?; self.client.proxies().anime().set_on_off(on).ok();
} }
Ok(()) Ok(())
} }
+40 -37
View File
@@ -1,13 +1,13 @@
use rog_dbus::RogDbusClient; use rog_dbus::RogDbusClientBlocking;
use rog_user::{ use rog_user::{
ctrl_anime::{CtrlAnime, CtrlAnimeInner}, ctrl_anime::{CtrlAnime, CtrlAnimeInner},
user_config::*, user_config::*,
DBUS_NAME, DBUS_NAME,
}; };
use smol::Executor;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::thread; use zbus::Connection;
use zbus::{fdo, Connection};
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
@@ -17,51 +17,54 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" rog-dbus v{}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!("rog-supported v{}", rog_supported::VERSION); println!("rog-supported v{}", rog_supported::VERSION);
let (client, _) = RogDbusClient::new()?; let (client, _) = RogDbusClientBlocking::new()?;
let supported = client.proxies().supported().get_supported_functions()?; let supported = client.proxies().supported().supported_functions()?;
let mut config = UserConfig::new(); let mut config = UserConfig::new();
config.load_config()?; config.load_config()?;
let anime_config = UserAnimeConfig::load_config(config.active_anime)?; let executor = Executor::new();
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);
let early_return = Arc::new(AtomicBool::new(false));
// Set up the anime data and run loop/thread // Set up the anime data and run loop/thread
if supported.anime_ctrl.0 { if supported.anime_ctrl.0 {
let early_return = Arc::new(AtomicBool::new(false)); let anime_config = UserAnimeConfig::load_config(config.active_anime)?;
// Inner behind mutex required for thread safety let anime = anime_config.create_anime()?;
let inner = Arc::new(Mutex::new(CtrlAnimeInner::new( let anime_config = Arc::new(Mutex::new(anime_config));
anime,
client, executor
early_return.clone(), .spawn(async move {
)?)); // Create server
// Need new client object for dbus control part let mut connection = Connection::session().await.unwrap();
let (client, _) = RogDbusClient::new()?; connection.request_name(DBUS_NAME).await.unwrap();
let anime_control = CtrlAnime::new(anime_config, inner.clone(), client, early_return)?;
anime_control.add_to_server(&mut server); // Inner behind mutex required for thread safety
// Thread using inner let inner = Arc::new(Mutex::new(
let _anime_thread = thread::Builder::new() CtrlAnimeInner::new(anime, client, early_return.clone()).unwrap(),
.name("Anime User".into()) ));
.spawn(move || loop { // Need new client object for dbus control part
if let Ok(inner) = inner.try_lock() { let (client, _) = RogDbusClientBlocking::new().unwrap();
inner.run().ok(); let anime_control =
CtrlAnime::new(anime_config, inner.clone(), client, early_return).unwrap();
anime_control.add_to_server(&mut connection).await;
loop {
if let Ok(inner) = inner.clone().try_lock() {
inner.run().ok();
}
} }
})?; })
.detach();
} }
if supported.keyboard_led.per_key_led_mode {} // if supported.keyboard_led.per_key_led_mode {
// executor
// .spawn(async move {
// //
// })
// .detach();
// }
loop { loop {
if let Err(err) = server.try_handle_next() { smol::block_on(executor.tick());
println!("{}", err);
}
} }
} }
+12 -9
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "daemon" name = "daemon"
version = "4.0.2" version = "4.1.0"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
@@ -18,22 +18,25 @@ name = "asusd"
path = "src/daemon.rs" path = "src/daemon.rs"
[dependencies] [dependencies]
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime", features = ["dbus"] }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura", features = ["dbus"] }
rog_supported = { path = "../rog-supported" } rog_supported = { path = "../rog-supported" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rusb = "^0.8"
async-trait = "^0.1"
smol = "^1.2"
rusb = "^0.9"
udev = "^0.6" udev = "^0.6"
# cli and logging # cli and logging
log = "^0.4" log = "^0.4"
env_logger = "^0.8" env_logger = "^0.9"
zbus = "^1.9.1" zbus = "^2.2"
zvariant = "^2.6" zvariant = "^3.2"
zvariant_derive = { version = "^2.6" } logind-zbus = { version = "^3.0" } #, default-features = false, features = ["non_blocking"] }
logind-zbus = "^0.7.1"
# serialisation # serialisation
serde = "^1.0" serde = "^1.0"
+3 -2
View File
@@ -2,6 +2,7 @@ use log::{error, warn};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::PathBuf;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
@@ -24,8 +25,8 @@ impl Config {
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.open(&CONFIG_PATH) .open(&PathBuf::from(CONFIG_PATH))
.unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here .unwrap_or_else(|e| panic!("Error opening {}, {}", CONFIG_PATH, e)); // okay to cause panic here
let mut buf = String::new(); let mut buf = String::new();
let config; let config;
if let Ok(read_len) = file.read_to_string(&mut buf) { if let Ok(read_len) = file.read_to_string(&mut buf) {
+135 -113
View File
@@ -2,8 +2,9 @@ pub mod config;
pub mod zbus; pub mod zbus;
use ::zbus::Connection; use ::zbus::Connection;
use async_trait::async_trait;
use log::{error, info, warn}; use log::{error, info, warn};
use logind_zbus::ManagerProxy; use logind_zbus::manager::ManagerProxy;
use rog_anime::{ use rog_anime::{
error::AnimeError, error::AnimeError,
usb::{ usb::{
@@ -14,6 +15,7 @@ use rog_anime::{
}; };
use rog_supported::AnimeSupportedFunctions; use rog_supported::AnimeSupportedFunctions;
use rusb::{Device, DeviceHandle}; use rusb::{Device, DeviceHandle};
use smol::{stream::StreamExt, Executor};
use std::{ use std::{
cell::RefCell, cell::RefCell,
error::Error, error::Error,
@@ -139,6 +141,7 @@ impl CtrlAnime {
warn!("AniMe system actions was empty"); warn!("AniMe system actions was empty");
return; return;
} }
// Loop rules: // Loop rules:
// - Lock the mutex **only when required**. That is, the lock must be held for the shortest duration possible. // - 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 // - An AtomicBool used for thread exit should be checked in every loop, including nested
@@ -148,60 +151,57 @@ impl CtrlAnime {
std::thread::Builder::new() std::thread::Builder::new()
.name("AniMe system thread start".into()) .name("AniMe system thread start".into())
.spawn(move || { .spawn(move || {
info!("AniMe system thread started"); info!("AniMe new system thread started");
// Getting copies of these Atomics is done *in* the thread to ensure // Getting copies of these Atomics is done *in* the thread to ensure
// we don't block other threads/main // we don't block other threads/main
let thread_exit; let thread_exit;
let thread_running; 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 { loop {
if let Ok(lock) = inner.try_lock() { if let Ok(lock) = inner.try_lock() {
thread_exit = lock.thread_exit.clone(); thread_exit = lock.thread_exit.clone();
thread_running = lock.thread_running.clone(); thread_running = lock.thread_running.clone();
// Make any running loop exit first
thread_exit.store(true, Ordering::SeqCst);
break; break;
} }
} }
// 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.
while thread_running.load(Ordering::SeqCst) {
// Make any running loop exit first
thread_exit.store(true, Ordering::SeqCst);
break;
}
loop { info!("AniMe no previous system thread running (now)");
// wait for other threads to set not running so we know they exited thread_exit.store(false, Ordering::SeqCst);
if !thread_running.load(Ordering::SeqCst) {
thread_exit.store(false, Ordering::SeqCst);
info!("AniMe forced a thread to exit");
break;
}
}
'main: loop { 'main: loop {
if thread_exit.load(Ordering::SeqCst) { thread_running.store(true, Ordering::SeqCst);
break 'main;
}
for action in actions.iter() { for action in actions.iter() {
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
match action { match action {
ActionData::Animation(frames) => { ActionData::Animation(frames) => {
if let Err(err) = rog_anime::run_animation( if let Err(err) = rog_anime::run_animation(frames, &|frame| {
frames, if thread_exit.load(Ordering::Acquire) {
thread_exit.clone(), info!("rog-anime: frame-loop was asked to exit");
&|frame| { return Ok(true); // Do safe exit
inner }
.try_lock() inner
.map(|lock| lock.write_data_buffer(frame)) .try_lock()
.map_err(|err| { .map(|lock| {
warn!("rog_anime::run_animation: {}", err); lock.write_data_buffer(frame);
AnimeError::NoFrames false // Don't exit yet
}) })
}, .map_err(|err| {
) { warn!("rog_anime::run_animation:callback {}", err);
warn!("rog_anime::run_animation: {}", err); AnimeError::NoFrames
})
}) {
warn!("rog_anime::run_animation:Animation {}", err);
break 'main; break 'main;
}; };
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
} }
ActionData::Image(image) => { ActionData::Image(image) => {
once = false; once = false;
@@ -226,7 +226,6 @@ impl CtrlAnime {
lock.write_data_buffer(data); lock.write_data_buffer(data);
} }
// Loop ended, set the atmonics // Loop ended, set the atmonics
thread_exit.store(false, Ordering::SeqCst);
thread_running.store(false, Ordering::SeqCst); thread_running.store(false, Ordering::SeqCst);
info!("AniMe system thread exited"); info!("AniMe system thread exited");
}) })
@@ -297,89 +296,112 @@ impl CtrlAnime {
} }
} }
pub struct CtrlAnimeTask<'a> { pub struct CtrlAnimeTask {
inner: Arc<Mutex<CtrlAnime>>, inner: Arc<Mutex<CtrlAnime>>,
_c: Connection,
manager: ManagerProxy<'a>,
} }
impl<'a> CtrlAnimeTask<'a> { impl CtrlAnimeTask {
pub fn new(inner: Arc<Mutex<CtrlAnime>>) -> Self { pub async fn new(inner: Arc<Mutex<CtrlAnime>>) -> CtrlAnimeTask {
let connection = Self { inner }
Connection::new_system().expect("CtrlAnimeTask could not create dbus connection");
let manager =
ManagerProxy::new(&connection).expect("CtrlAnimeTask could not create ManagerProxy");
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,
}
} }
} }
impl<'a> crate::CtrlTask for CtrlAnimeTask<'a> { #[async_trait]
fn do_task(&self) -> Result<(), RogError> { impl crate::CtrlTask for CtrlAnimeTask {
if let Ok(mut lock) = self.inner.try_lock() { async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
// Refresh the config and cache incase the user has edited it let connection = Connection::system()
let config = AnimeConfig::load(); .await
lock.cache .expect("CtrlAnimeTask could not create dbus connection");
.init_from_config(&config)
.map_err(|err| { let manager = ManagerProxy::new(&connection)
warn!("CtrlAnimeTask: do_task {}", err); .await
err .expect("CtrlAnimeTask could not create ManagerProxy");
})
.ok(); let inner = self.inner.clone();
} executor
.spawn(async move {
if let Ok(notif) = manager.receive_prepare_for_sleep().await {
notif
.for_each(|event| {
if let Ok(args) = event.args() {
if args.start {
loop {
// Loop is required to try an attempt to get the mutex *without* blocking
// other threads - it is possible to end up with deadlocks otherwise.
if let Ok(lock) = inner.clone().try_lock() {
info!("CtrlAnimeTask running sleep animation");
CtrlAnime::run_thread(
inner.clone(),
lock.cache.shutdown.clone(),
true,
);
break;
}
}
} else {
loop {
if let Ok(lock) = inner.clone().try_lock() {
info!("CtrlAnimeTask running wake animation");
CtrlAnime::run_thread(
inner.clone(),
lock.cache.wake.clone(),
true,
);
break;
}
}
}
}
})
.await;
}
})
.detach();
let manager = ManagerProxy::new(&connection)
.await
.expect("CtrlAnimeTask could not create ManagerProxy");
let inner = self.inner.clone();
executor
.spawn(async move {
if let Ok(notif) = manager.receive_prepare_for_shutdown().await {
notif
.for_each(|event| {
if let Ok(args) = event.args() {
if args.start {
loop {
if let Ok(lock) = inner.clone().try_lock() {
info!("CtrlAnimeTask running sleep animation");
CtrlAnime::run_thread(
inner.clone(),
lock.cache.shutdown.clone(),
true,
);
break;
}
}
} else {
// If waking up - intention is to catch hibernation event
loop {
if let Ok(lock) = inner.clone().lock() {
info!("CtrlAnimeTask running wake animation");
CtrlAnime::run_thread(
inner.clone(),
lock.cache.wake.clone(),
true,
);
break;
}
}
}
}
})
.await;
}
})
.detach();
// Check for signals on each task iteration, this will run the callbacks
// if any signal is recieved
self.manager.next_signal()?;
Ok(()) Ok(())
} }
} }
+26 -26
View File
@@ -1,12 +1,11 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use log::warn; use async_trait::async_trait;
use rog_anime::{ use rog_anime::{
usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on},
AnimeDataBuffer, AnimePowerStates, AnimeDataBuffer, AnimePowerStates,
}; };
use zbus::dbus_interface; use zbus::{dbus_interface, Connection, SignalContext};
use zvariant::ObjectPath;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
@@ -15,18 +14,10 @@ use super::CtrlAnime;
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>); pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
/// The struct with the main dbus methods requires this trait /// The struct with the main dbus methods requires this trait
#[async_trait]
impl crate::ZbusAdd for CtrlAnimeZbus { impl crate::ZbusAdd for CtrlAnimeZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await;
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
} }
} }
@@ -64,26 +55,30 @@ impl CtrlAnimeZbus {
} }
/// Set whether the AniMe is displaying images/data /// Set whether the AniMe is displaying images/data
fn set_on_off(&self, status: bool) { async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) {
let states;
'outer: loop { 'outer: loop {
if let Ok(mut lock) = self.0.try_lock() { if let Ok(mut lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_on(status)); lock.write_bytes(&pkt_for_set_on(status));
lock.config.awake_enabled = status; lock.config.awake_enabled = status;
lock.config.write(); lock.config.write();
let states = AnimePowerStates { states = Some(AnimePowerStates {
brightness: lock.config.brightness.floor() as u8,
enabled: lock.config.awake_enabled, enabled: lock.config.awake_enabled,
boot_anim_enabled: lock.config.boot_anim_enabled, boot_anim_enabled: lock.config.boot_anim_enabled,
}; });
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
break 'outer; break 'outer;
} }
} }
if let Some(state) = states {
Self::notify_power_states(&ctxt, state).await.ok();
}
} }
/// Set whether the AniMe will show boot, suspend, or off animations /// Set whether the AniMe will show boot, suspend, or off animations
fn set_boot_on_off(&self, on: bool) { async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) {
let states;
'outer: loop { 'outer: loop {
if let Ok(mut lock) = self.0.try_lock() { if let Ok(mut lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_boot(on)); lock.write_bytes(&pkt_for_set_boot(on));
@@ -91,15 +86,17 @@ impl CtrlAnimeZbus {
lock.config.boot_anim_enabled = on; lock.config.boot_anim_enabled = on;
lock.config.write(); lock.config.write();
let states = AnimePowerStates { states = Some(AnimePowerStates {
brightness: lock.config.brightness.floor() as u8,
enabled: lock.config.awake_enabled, enabled: lock.config.awake_enabled,
boot_anim_enabled: lock.config.boot_anim_enabled, boot_anim_enabled: lock.config.boot_anim_enabled,
}; });
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
break 'outer; break 'outer;
} }
} }
if let Some(state) = states {
Self::notify_power_states(&ctxt, state).await.ok();
}
} }
/// The main loop is the base system set action if the user isn't running /// The main loop is the base system set action if the user isn't running
@@ -116,7 +113,7 @@ impl CtrlAnimeZbus {
} }
} }
/// Get status of if the AniMe LEDs are on /// Get status of if the AniMe LEDs are on/displaying while system is awake
#[dbus_interface(property)] #[dbus_interface(property)]
fn awake_enabled(&self) -> bool { fn awake_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
@@ -136,5 +133,8 @@ impl CtrlAnimeZbus {
/// Notify listeners of the status of AniMe LED power and factory system-status animations /// Notify listeners of the status of AniMe LED power and factory system-status animations
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_power_states(&self, data: &AnimePowerStates) -> zbus::Result<()>; async fn notify_power_states(
ctxt: &SignalContext<'_>,
data: AnimePowerStates,
) -> zbus::Result<()>;
} }
+47 -30
View File
@@ -1,6 +1,6 @@
use crate::laptops::LaptopLedData; use crate::laptops::LaptopLedData;
use log::{error, info, warn}; use log::{error, info, warn};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness, LedPowerStates};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
@@ -8,27 +8,6 @@ use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
#[derive(Deserialize, Serialize)]
pub struct AuraConfigV320 {
pub brightness: u32,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl AuraConfigV320 {
pub(crate) fn into_current(self) -> AuraConfig {
AuraConfig {
brightness: <LedBrightness>::from(self.brightness),
current_mode: self.current_mode,
builtins: self.builtins,
multizone: self.multizone,
awake_enabled: true,
sleep_anim_enabled: true,
}
}
}
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct AuraConfigV352 { pub struct AuraConfigV352 {
pub brightness: LedBrightness, pub brightness: LedBrightness,
@@ -44,8 +23,42 @@ impl AuraConfigV352 {
current_mode: self.current_mode, current_mode: self.current_mode,
builtins: self.builtins, builtins: self.builtins,
multizone: self.multizone, multizone: self.multizone,
awake_enabled: true, power_states: LedPowerStates {
sleep_anim_enabled: true, boot_anim: true,
sleep_anim: true,
all_leds: true,
keys_leds: true,
side_leds: true,
},
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraConfigV407 {
pub brightness: LedBrightness,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
pub awake_enabled: bool,
pub sleep_anim_enabled: bool,
pub side_leds_enabled: bool,
}
impl AuraConfigV407 {
pub(crate) fn into_current(self) -> AuraConfig {
AuraConfig {
brightness: self.brightness,
current_mode: self.current_mode,
builtins: self.builtins,
multizone: self.multizone,
power_states: LedPowerStates {
boot_anim: true,
sleep_anim: self.sleep_anim_enabled,
all_leds: self.awake_enabled,
keys_leds: self.awake_enabled,
side_leds: self.side_leds_enabled,
},
} }
} }
} }
@@ -56,8 +69,7 @@ pub struct AuraConfig {
pub current_mode: AuraModeNum, pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>, pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>, pub multizone: Option<AuraMultiZone>,
pub awake_enabled: bool, pub power_states: LedPowerStates,
pub sleep_anim_enabled: bool,
} }
impl Default for AuraConfig { impl Default for AuraConfig {
@@ -67,8 +79,13 @@ impl Default for AuraConfig {
current_mode: AuraModeNum::Static, current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(), builtins: BTreeMap::new(),
multizone: None, multizone: None,
awake_enabled: true, power_states: LedPowerStates {
sleep_anim_enabled: true, boot_anim: true,
sleep_anim: true,
all_leds: true,
keys_leds: true,
side_leds: true,
},
} }
} }
} }
@@ -94,12 +111,12 @@ impl AuraConfig {
} else { } else {
if let Ok(data) = serde_json::from_str(&buf) { if let Ok(data) = serde_json::from_str(&buf) {
return data; return data;
} else if let Ok(data) = serde_json::from_str::<AuraConfigV320>(&buf) { } else if let Ok(data) = serde_json::from_str::<AuraConfigV352>(&buf) {
let config = data.into_current(); let config = data.into_current();
config.write(); config.write();
info!("Updated AuraConfig version"); info!("Updated AuraConfig version");
return config; return config;
} else if let Ok(data) = serde_json::from_str::<AuraConfigV352>(&buf) { } else if let Ok(data) = serde_json::from_str::<AuraConfigV407>(&buf) {
let config = data.into_current(); let config = data.into_current();
config.write(); config.write();
info!("Updated AuraConfig version"); info!("Updated AuraConfig version");
+88 -72
View File
@@ -6,21 +6,21 @@ use crate::{
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
CtrlTask, CtrlTask,
}; };
use log::{info, warn}; use async_trait::async_trait;
use logind_zbus::ManagerProxy; use log::{error, info, warn};
use logind_zbus::manager::ManagerProxy;
use rog_aura::usb::leds_message;
use rog_aura::{ use rog_aura::{
usb::{ usb::{LED_APPLY, LED_SET},
LED_APPLY, LED_AWAKE_OFF_SLEEP_OFF, LED_AWAKE_OFF_SLEEP_ON, LED_AWAKE_ON_SLEEP_OFF,
LED_AWAKE_ON_SLEEP_ON, LED_SET,
},
AuraEffect, LedBrightness, LED_MSG_LEN, AuraEffect, LedBrightness, LED_MSG_LEN,
}; };
use rog_supported::LedSupportedFunctions; use rog_supported::LedSupportedFunctions;
use smol::{stream::StreamExt, Executor};
use std::fs::OpenOptions;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::{fs::OpenOptions, thread::spawn};
use zbus::Connection; use zbus::Connection;
use crate::GetSupported; use crate::GetSupported;
@@ -32,10 +32,10 @@ impl GetSupported for CtrlKbdLed {
fn get_supported() -> Self::A { fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode)); // let mode = <&str>::from(&<AuraModes>::from(*mode));
let multizone_led_mode = false;
let per_key_led_mode = false;
let laptop = LaptopLedData::get_data(); let laptop = LaptopLedData::get_data();
let stock_led_modes = laptop.standard; let stock_led_modes = laptop.standard;
let multizone_led_mode = laptop.multizone;
let per_key_led_mode = laptop.per_key;
LedSupportedFunctions { LedSupportedFunctions {
brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(),
@@ -54,50 +54,13 @@ pub struct CtrlKbdLed {
pub config: AuraConfig, pub config: AuraConfig,
} }
pub struct CtrlKbdLedTask<'a> { pub struct CtrlKbdLedTask {
inner: Arc<Mutex<CtrlKbdLed>>, inner: Arc<Mutex<CtrlKbdLed>>,
_c: Connection,
manager: ManagerProxy<'a>,
} }
impl<'a> CtrlKbdLedTask<'a> { impl CtrlKbdLedTask {
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self { pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
let connection = Self { inner }
Connection::new_system().expect("CtrlKbdLedTask could not create dbus connection");
let manager =
ManagerProxy::new(&connection).expect("CtrlKbdLedTask could not create ManagerProxy");
let c1 = inner.clone();
// Run this action when the system wakes up from sleep
manager
.connect_prepare_for_sleep(move |sleep| {
if !sleep {
let c1 = c1.clone();
spawn(move || {
// wait a fraction for things to wake up properly
//std::thread::sleep(Duration::from_millis(100));
loop {
if let Ok(ref mut lock) = c1.try_lock() {
lock.set_brightness(lock.config.brightness).ok();
break;
}
}
});
}
Ok(())
})
.map_err(|err| {
warn!("CtrlAnimeTask: new() {}", err);
err
})
.ok();
Self {
inner,
_c: connection,
manager,
}
} }
fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> {
@@ -125,12 +88,62 @@ impl<'a> CtrlKbdLedTask<'a> {
} }
} }
impl<'a> CtrlTask for CtrlKbdLedTask<'a> { #[async_trait]
fn do_task(&self) -> Result<(), RogError> { impl CtrlTask for CtrlKbdLedTask {
self.manager.next_signal()?; async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
if let Ok(ref mut lock) = self.inner.try_lock() { let connection = Connection::system()
return Self::update_config(lock); .await
} .expect("CtrlKbdLedTask could not create dbus connection");
let manager = ManagerProxy::new(&connection)
.await
.expect("CtrlKbdLedTask could not create ManagerProxy");
let inner = self.inner.clone();
executor
.spawn(async move {
if let Ok(notif) = manager.receive_prepare_for_sleep().await {
notif
.for_each(|event| {
if let Ok(args) = event.args() {
// If waking up
if !args.start {
info!("CtrlKbdLedTask reloading brightness and modes");
loop {
// Loop so that we do aquire the lock but also don't block other
// threads (prevents potential deadlocks)
if let Ok(lock) = inner.clone().try_lock() {
// Can't reload brightness due to system setting the brightness on sleep/wake
// and the config update task saving that change.
// lock.set_brightness(lock.config.brightness)
// .map_err(|e| error!("CtrlKbdLedTask: {e}"))
// .ok();
if let Some(mode) =
lock.config.builtins.get(&lock.config.current_mode)
{
lock.write_mode(mode)
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
.ok();
}
break;
}
}
}
}
})
.await;
}
})
.detach();
let inner = self.inner.clone();
self.repeating_task(500, executor, move || loop {
if let Ok(ref mut lock) = inner.try_lock() {
Self::update_config(lock).unwrap();
break;
}
})
.await;
Ok(()) Ok(())
} }
} }
@@ -145,8 +158,8 @@ impl crate::Reloadable for CtrlKbdLedReloader {
ctrl.do_command(mode).ok(); ctrl.do_command(mode).ok();
} }
ctrl.set_states_enabled(ctrl.config.awake_enabled, ctrl.config.sleep_anim_enabled) ctrl.set_power_states(&ctrl.config)
.map_err(|err| warn!("{}", err)) .map_err(|err| warn!("{err}"))
.ok(); .ok();
} }
Ok(()) Ok(())
@@ -170,9 +183,10 @@ impl CtrlKbdLed {
match Self::find_led_node(prod) { match Self::find_led_node(prod) {
Ok(node) => { Ok(node) => {
led_node = Some(node); led_node = Some(node);
info!("Looked for keyboard controller 0x{prod}: Found");
break; break;
} }
Err(err) => warn!("led_node: {}", err), Err(err) => info!("Looked for keyboard controller 0x{prod}: {err}"),
} }
} }
@@ -263,20 +277,22 @@ impl CtrlKbdLed {
self.set_brightness(self.config.brightness) self.set_brightness(self.config.brightness)
} }
/// Set if awake/on LED active, and/or sleep animation active /// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active
pub(super) fn set_states_enabled(&self, awake: bool, sleep: bool) -> Result<(), RogError> { pub(super) fn set_power_states(&self, config: &AuraConfig) -> Result<(), RogError> {
let bytes = if awake && sleep { let bytes = leds_message(
LED_AWAKE_ON_SLEEP_ON config.power_states.boot_anim,
} else if awake && !sleep { config.power_states.sleep_anim,
LED_AWAKE_ON_SLEEP_OFF config.power_states.all_leds,
} else if !awake && sleep { config.power_states.keys_leds,
LED_AWAKE_OFF_SLEEP_ON config.power_states.side_leds,
} else if !awake && !sleep { );
LED_AWAKE_OFF_SLEEP_OFF
} else { // Quite ugly, must be a more idiomatic way to do
LED_AWAKE_ON_SLEEP_ON let message = [
}; 0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
self.write_bytes(&bytes)?; ];
self.write_bytes(&message)?;
self.write_bytes(&LED_SET)?; self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set // Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?; self.write_bytes(&LED_APPLY)?;
+185 -52
View File
@@ -1,18 +1,14 @@
use log::{error, warn}; use async_trait::async_trait;
use log::warn;
use rog_aura::{AuraEffect, LedBrightness, LedPowerStates}; use rog_aura::{AuraEffect, LedBrightness, LedPowerStates};
use zbus::dbus_interface; use zbus::{dbus_interface, Connection, SignalContext};
use zvariant::ObjectPath;
use super::controller::CtrlKbdLedZbus; use super::controller::CtrlKbdLedZbus;
#[async_trait]
impl crate::ZbusAdd for CtrlKbdLedZbus { impl crate::ZbusAdd for CtrlKbdLedZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/Led", server).await;
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
.map_err(|err| {
error!("DbusKbdLed: add_to_server {}", err);
})
.ok();
} }
} }
@@ -22,7 +18,7 @@ impl crate::ZbusAdd for CtrlKbdLedZbus {
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlKbdLedZbus { impl CtrlKbdLedZbus {
/// Set the keyboard brightness level (0-3) /// Set the keyboard brightness level (0-3)
fn set_brightness(&mut self, brightness: LedBrightness) { async fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
ctrl.set_brightness(brightness) ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err)) .map_err(|err| warn!("{}", err))
@@ -31,47 +27,142 @@ impl CtrlKbdLedZbus {
} }
/// Set the keyboard LED to enabled while the device is awake /// Set the keyboard LED to enabled while the device is awake
fn set_awake_enabled(&mut self, enabled: bool) { async fn set_boot_enabled(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: bool,
) {
let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.set_states_enabled(enabled, ctrl.config.sleep_anim_enabled) ctrl.config.power_states.boot_anim = enabled;
.map_err(|err| warn!("{}", err))
.ok();
ctrl.config.awake_enabled = enabled;
ctrl.config.write(); ctrl.config.write();
let states = LedPowerStates { ctrl.set_power_states(&ctrl.config)
enabled: ctrl.config.awake_enabled, .map_err(|err| warn!("{}", err))
sleep_anim_enabled: ctrl.config.sleep_anim_enabled, .ok();
};
self.notify_power_states(&states) states = Some(ctrl.config.power_states);
}
// Need to pull state out like this due to MutexGuard
if let Some(states) = states {
Self::notify_power_states(&ctxt, &states)
.await
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
} }
} }
/// Set the keyboard LED suspend animation to enabled while the device is suspended /// Set the keyboard LED suspend animation to enabled while the device is suspended
fn set_sleep_enabled(&mut self, enabled: bool) { async fn set_sleep_enabled(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: bool,
) {
let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.set_states_enabled(ctrl.config.awake_enabled, enabled) ctrl.config.power_states.sleep_anim = enabled;
ctrl.config.write();
ctrl.set_power_states(&ctrl.config)
.map_err(|err| warn!("{}", err)) .map_err(|err| warn!("{}", err))
.ok(); .ok();
ctrl.config.sleep_anim_enabled = enabled;
ctrl.config.write(); states = Some(ctrl.config.power_states);
let states = LedPowerStates { }
enabled: ctrl.config.awake_enabled, if let Some(states) = states {
sleep_anim_enabled: ctrl.config.sleep_anim_enabled, Self::notify_power_states(&ctxt, &states)
}; .await
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
} }
} }
fn set_led_mode(&mut self, effect: AuraEffect) { /// Set all the keyboard LEDs (keys and side) to enabled
async fn set_all_leds_enabled(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: bool,
) {
let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.config.power_states.all_leds = enabled;
ctrl.config.power_states.keys_leds = enabled;
ctrl.config.power_states.side_leds = enabled;
ctrl.config.write();
ctrl.set_power_states(&ctrl.config)
.map_err(|err| warn!("{}", err))
.ok();
states = Some(ctrl.config.power_states);
}
// Need to pull state out like this due to MutexGuard
if let Some(states) = states {
Self::notify_power_states(&ctxt, &states)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
}
/// Set the keyboard keys LEDs to enabled
async fn set_keys_leds_enabled(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: bool,
) {
let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.config.power_states.keys_leds = enabled;
ctrl.config.write();
ctrl.set_power_states(&ctrl.config)
.map_err(|err| warn!("{}", err))
.ok();
states = Some(ctrl.config.power_states);
}
// Need to pull state out like this due to MutexGuard
if let Some(states) = states {
Self::notify_power_states(&ctxt, &states)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
}
/// Set the keyboard side LEDs to enabled
async fn set_side_leds_enabled(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: bool,
) {
let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.config.power_states.side_leds = enabled;
ctrl.config.write();
ctrl.set_power_states(&ctrl.config)
.map_err(|err| warn!("{}", err))
.ok();
states = Some(ctrl.config.power_states);
}
// Need to pull state out like this due to MutexGuard
if let Some(states) = states {
Self::notify_power_states(&ctxt, &states)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
}
async fn set_led_mode(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
effect: AuraEffect,
) {
let mut led = None;
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
match ctrl.do_command(effect) { match ctrl.do_command(effect) {
Ok(_) => { Ok(_) => {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone()) led = Some(mode.clone());
.unwrap_or_else(|err| warn!("{}", err));
} }
} }
Err(err) => { Err(err) => {
@@ -79,40 +170,55 @@ impl CtrlKbdLedZbus {
} }
} }
} }
if let Some(led) = led {
Self::notify_led(&ctxt, led)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
} }
fn next_led_mode(&self) { async fn next_led_mode(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>) {
if let Ok(mut ctrl) = self.0.try_lock() { let mut led = None;
if let Ok(mut ctrl) = self.0.lock() {
ctrl.toggle_mode(false) ctrl.toggle_mode(false)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone()) led = Some(mode.clone());
.unwrap_or_else(|err| warn!("{}", err));
} }
} }
if let Some(led) = led {
Self::notify_led(&ctxt, led)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
} }
fn prev_led_mode(&self) { async fn prev_led_mode(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>) {
if let Ok(mut ctrl) = self.0.try_lock() { let mut led = None;
if let Ok(mut ctrl) = self.0.lock() {
ctrl.toggle_mode(true) ctrl.toggle_mode(true)
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone()) led = Some(mode.clone());
.unwrap_or_else(|err| warn!("{}", err));
} }
} }
if let Some(led) = led {
Self::notify_led(&ctxt, led)
.await
.unwrap_or_else(|err| warn!("{}", err));
}
} }
fn next_led_brightness(&self) { async fn next_led_brightness(&self) {
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.next_brightness() ctrl.next_brightness()
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
} }
} }
fn prev_led_brightness(&self) { async fn prev_led_brightness(&self) {
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.prev_brightness() ctrl.prev_brightness()
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
@@ -120,24 +226,48 @@ impl CtrlKbdLedZbus {
} }
#[dbus_interface(property)] #[dbus_interface(property)]
fn awake_enabled(&self) -> bool { async fn boot_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.awake_enabled; return ctrl.config.power_states.boot_anim;
} }
true true
} }
#[dbus_interface(property)] #[dbus_interface(property)]
fn sleep_enabled(&self) -> bool { async fn sleep_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.sleep_anim_enabled; return ctrl.config.power_states.sleep_anim;
}
true
}
#[dbus_interface(property)]
async fn all_leds_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.power_states.all_leds;
}
true
}
#[dbus_interface(property)]
async fn keys_leds_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.power_states.keys_leds;
}
true
}
#[dbus_interface(property)]
fn side_leds_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.power_states.side_leds;
} }
true true
} }
/// Return the current mode data /// Return the current mode data
#[dbus_interface(property)] #[dbus_interface(property)]
fn led_mode(&self) -> String { async fn led_mode(&self) -> String {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) { if let Ok(json) = serde_json::to_string(&mode) {
@@ -151,7 +281,7 @@ impl CtrlKbdLedZbus {
/// Return a list of available modes /// Return a list of available modes
#[dbus_interface(property)] #[dbus_interface(property)]
fn led_modes(&self) -> String { async fn led_modes(&self) -> String {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) { if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return json; return json;
@@ -163,7 +293,7 @@ impl CtrlKbdLedZbus {
/// Return the current LED brightness /// Return the current LED brightness
#[dbus_interface(property)] #[dbus_interface(property)]
fn led_brightness(&self) -> i8 { async fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.0.try_lock() { if let Ok(ctrl) = self.0.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
} }
@@ -172,8 +302,11 @@ impl CtrlKbdLedZbus {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; async fn notify_led(signal_ctxt: &SignalContext<'_>, data: AuraEffect) -> zbus::Result<()>;
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_power_states(&self, data: &LedPowerStates) -> zbus::Result<()>; async fn notify_power_states(
signal_ctxt: &SignalContext<'_>,
data: &LedPowerStates,
) -> zbus::Result<()>;
} }
+99 -29
View File
@@ -1,14 +1,19 @@
use crate::CtrlTask;
use crate::{config::Config, error::RogError, GetSupported}; use crate::{config::Config, error::RogError, GetSupported};
//use crate::dbus::DbusEvents; use async_trait::async_trait;
use log::{info, warn}; use log::{info, warn};
use logind_zbus::manager::ManagerProxy;
use rog_supported::ChargeSupportedFunctions; use rog_supported::ChargeSupportedFunctions;
use smol::stream::StreamExt;
use smol::Executor;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use zbus::dbus_interface; use zbus::dbus_interface;
use zvariant::ObjectPath; use zbus::Connection;
use zbus::SignalContext;
static BAT_CHARGE_PATH0: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold"; static BAT_CHARGE_PATH0: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
static BAT_CHARGE_PATH1: &str = "/sys/class/power_supply/BAT1/charge_control_end_threshold"; static BAT_CHARGE_PATH1: &str = "/sys/class/power_supply/BAT1/charge_control_end_threshold";
@@ -30,24 +35,27 @@ pub struct CtrlCharge {
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlCharge { impl CtrlCharge {
pub fn set_limit(&mut self, limit: u8) { async fn set_limit(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
limit: u8,
) -> zbus::fdo::Result<()> {
if !(20..=100).contains(&limit) {
return Err(RogError::ChargeLimit(limit))?;
}
if let Ok(mut config) = self.config.try_lock() { if let Ok(mut config) = self.config.try_lock() {
self.set(limit, &mut config) Self::set(limit, &mut config)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
self.notify_charge(limit)
.map_err(|err| { .map_err(|err| {
warn!("CtrlCharge: set_limit {}", err); warn!("CtrlCharge: set_limit {}", err);
err err
}) })
.ok(); .ok();
} }
Self::notify_charge(&ctxt, limit).await?;
Ok(())
} }
pub fn limit(&self) -> i8 { fn limit(&self) -> i8 {
if let Ok(config) = self.config.try_lock() { if let Ok(config) = self.config.try_lock() {
return config.bat_charge_limit as i8; return config.bat_charge_limit as i8;
} }
@@ -55,21 +63,13 @@ impl CtrlCharge {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()> {} async fn notify_charge(ctxt: &SignalContext<'_>, limit: u8) -> zbus::Result<()>;
} }
#[async_trait]
impl crate::ZbusAdd for CtrlCharge { impl crate::ZbusAdd for CtrlCharge {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/Charge", server).await;
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
self,
)
.map_err(|err| {
warn!("CtrlCharge: add_to_server {}", err);
err
})
.ok();
} }
} }
@@ -77,7 +77,7 @@ impl crate::Reloadable for CtrlCharge {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.try_lock() { if let Ok(mut config) = self.config.try_lock() {
config.read(); config.read();
self.set(config.bat_charge_limit, &mut config)?; Self::set(config.bat_charge_limit, &mut config)?;
} }
Ok(()) Ok(())
} }
@@ -104,12 +104,9 @@ impl CtrlCharge {
} }
} }
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> { pub(super) fn set(limit: u8, config: &mut Config) -> Result<(), RogError> {
if !(20..=100).contains(&limit) { if !(20..=100).contains(&limit) {
warn!( return Err(RogError::ChargeLimit(limit));
"Unable to set battery charge limit, must be between 20-100: requested {}",
limit
);
} }
let path = Self::get_battery_path()?; let path = Self::get_battery_path()?;
@@ -129,3 +126,76 @@ impl CtrlCharge {
Ok(()) Ok(())
} }
} }
#[async_trait]
impl CtrlTask for CtrlCharge {
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
let connection = Connection::system()
.await
.expect("CtrlCharge could not create dbus connection");
let manager = ManagerProxy::new(&connection)
.await
.expect("CtrlCharge could not create ManagerProxy");
let config1 = self.config.clone();
executor
.spawn(async move {
if let Ok(notif) = manager.receive_prepare_for_sleep().await {
notif
.for_each(|event| {
if let Ok(args) = event.args() {
// If waking up
if !args.start {
info!("CtrlCharge reloading charge limit");
if let Ok(mut lock) = config1.try_lock() {
Self::set(lock.bat_charge_limit, &mut lock)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
}
}
}
})
.await;
}
})
.detach();
let manager = ManagerProxy::new(&connection)
.await
.expect("CtrlCharge could not create ManagerProxy");
let config = self.config.clone();
executor
.spawn(async move {
if let Ok(notif) = manager.receive_prepare_for_shutdown().await {
notif
.for_each(|event| {
if let Ok(args) = event.args() {
// If waking up - intention is to catch hibernation event
if !args.start {
info!("CtrlCharge reloading charge limit");
loop {
if let Ok(mut lock) = config.clone().try_lock() {
Self::set(lock.bat_charge_limit, &mut lock)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
break;
}
}
}
}
})
.await;
}
})
.detach();
Ok(())
}
}
+25 -19
View File
@@ -2,10 +2,12 @@ use std::sync::{Arc, Mutex};
use crate::error::RogError; use crate::error::RogError;
use crate::{CtrlTask, GetSupported}; use crate::{CtrlTask, GetSupported};
use async_trait::async_trait;
use log::{info, warn}; use log::{info, warn};
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
use rog_profiles::{FanCurveProfiles, Profile}; use rog_profiles::{FanCurveProfiles, Profile};
use rog_supported::PlatformProfileFunctions; use rog_supported::PlatformProfileFunctions;
use smol::Executor;
use super::config::ProfileConfig; use super::config::ProfileConfig;
@@ -21,8 +23,7 @@ impl GetSupported for CtrlPlatformProfile {
warn!( warn!(
r#" r#"
platform_profile kernel interface not found, your laptop does not support this, or the interface is missing. platform_profile kernel interface not found, your laptop does not support this, or the interface is missing.
To enable profile support you require a kernel with the following patch applied: To enable profile support you require a kernel version 5.15.2 minimum.
https://lkml.org/lkml/2021/8/18/1022
"# "#
); );
} }
@@ -33,13 +34,13 @@ https://lkml.org/lkml/2021/8/18/1022
fan_curve_supported = r; fan_curve_supported = r;
}; };
if fan_curve_supported { if !fan_curve_supported {
info!( info!(
r#" r#"
fan curves kernel interface not found, your laptop does not support this, or the interface is missing. fan curves kernel interface not found, your laptop does not support this, or the interface is missing.
To enable fan-curve support you require a kernel with the following patch applied: To enable fan-curve support you require a kernel with the following patch applied:
https://lkml.org/lkml/2021/8/20/232 https://lkml.org/lkml/2021/10/23/250
Please note that as of 24/08/2021 this is not final. This patch has been accepted upstream for 5.17 kernel release.
"# "#
); );
} }
@@ -56,7 +57,10 @@ impl crate::Reloadable for CtrlPlatformProfile {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
if let Some(curves) = &mut self.config.fan_curves { if let Some(curves) = &mut self.config.fan_curves {
if let Ok(mut device) = FanCurveProfiles::get_device() { if let Ok(mut device) = FanCurveProfiles::get_device() {
// There is a possibility that the curve was default zeroed, so this call initialises
// the data from system read and we need to save it after
curves.write_profile_curve_to_platform(self.config.active_profile, &mut device)?; curves.write_profile_curve_to_platform(self.config.active_profile, &mut device)?;
self.config.write();
} }
} }
Ok(()) Ok(())
@@ -64,17 +68,13 @@ impl crate::Reloadable for CtrlPlatformProfile {
} }
impl CtrlPlatformProfile { impl CtrlPlatformProfile {
pub fn new(mut config: ProfileConfig) -> Result<Self, RogError> { pub fn new(config: ProfileConfig) -> Result<Self, RogError> {
if Profile::is_platform_profile_supported() { if Profile::is_platform_profile_supported() {
info!("Device has profile control available"); info!("Device has profile control available");
if let Ok(ref device) = FanCurveProfiles::get_device() { if FanCurveProfiles::get_device().is_ok() {
let profile = config.active_profile; info!("Device has fan curves available");
if let Some(curve) = config.fan_curves.as_mut() {
curve.read_from_dev_profile(profile, device);
}
} }
config.write();
return Ok(CtrlPlatformProfile { config }); return Ok(CtrlPlatformProfile { config });
} }
@@ -137,15 +137,21 @@ impl CtrlProfileTask {
} }
} }
#[async_trait]
impl CtrlTask for CtrlProfileTask { impl CtrlTask for CtrlProfileTask {
fn do_task(&self) -> Result<(), RogError> { async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
if let Ok(ref mut lock) = self.ctrl.try_lock() { let ctrl = self.ctrl.clone();
let new_profile = Profile::get_active_profile().unwrap(); self.repeating_task(666, executor, move || {
if new_profile != lock.config.active_profile { if let Ok(ref mut lock) = ctrl.try_lock() {
lock.config.active_profile = new_profile; let new_profile = Profile::get_active_profile().unwrap();
lock.save_config(); if new_profile != lock.config.active_profile {
lock.config.active_profile = new_profile;
lock.write_profile_curve_to_platform().unwrap();
lock.save_config();
}
} }
} })
.await;
Ok(()) Ok(())
} }
} }
+27 -29
View File
@@ -1,12 +1,14 @@
use async_trait::async_trait;
use log::warn; use log::warn;
use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::fan_curve_set::FanCurveSet;
use rog_profiles::Profile; use rog_profiles::Profile;
use zbus::Connection;
use zbus::SignalContext;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use zbus::{dbus_interface, fdo::Error}; use zbus::{dbus_interface, fdo::Error};
use zvariant::ObjectPath;
use super::controller::CtrlPlatformProfile; use super::controller::CtrlPlatformProfile;
@@ -37,13 +39,17 @@ impl ProfileZbus {
/// Toggle to next platform_profile. Names provided by `Profiles`. /// Toggle to next platform_profile. Names provided by `Profiles`.
/// If fan-curves are supported will also activate a fan curve for profile. /// If fan-curves are supported will also activate a fan curve for profile.
fn next_profile(&mut self) { async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) {
let mut profile = None;
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.set_next_profile() ctrl.set_next_profile()
.unwrap_or_else(|err| warn!("{}", err)); .unwrap_or_else(|err| warn!("{}", err));
ctrl.save_config(); ctrl.save_config();
profile = Some(ctrl.config.active_profile);
}
if let Some(profile) = profile {
Self::notify_profile(&ctxt, profile).await.ok();
} }
self.do_notification();
} }
/// Fetch the active profile name /// Fetch the active profile name
@@ -58,7 +64,12 @@ impl ProfileZbus {
} }
/// Set this platform_profile name as active /// Set this platform_profile name as active
fn set_active_profile(&self, profile: Profile) { async fn set_active_profile(
&self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
profile: Profile,
) {
let mut tmp = None;
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
// Read first just incase the user has modified the config before calling this // Read first just incase the user has modified the config before calling this
ctrl.config.read(); ctrl.config.read();
@@ -71,8 +82,11 @@ impl ProfileZbus {
.ok(); .ok();
ctrl.save_config(); ctrl.save_config();
tmp = Some(ctrl.config.active_profile);
}
if let Some(profile) = tmp {
Self::notify_profile(&ctxt, profile).await.ok();
} }
self.do_notification();
} }
/// Get a list of profiles that have fan-curves enabled. /// Get a list of profiles that have fan-curves enabled.
@@ -94,7 +108,7 @@ impl ProfileZbus {
fn set_fan_curve_enabled(&mut self, profile: Profile, enabled: bool) -> zbus::fdo::Result<()> { fn set_fan_curve_enabled(&mut self, profile: Profile, enabled: bool) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.config.read(); ctrl.config.read();
if let Some(curves) = &mut ctrl.config.fan_curves { return if let Some(curves) = &mut ctrl.config.fan_curves {
curves.set_profile_curve_enabled(profile, enabled); curves.set_profile_curve_enabled(profile, enabled);
ctrl.write_profile_curve_to_platform() ctrl.write_profile_curve_to_platform()
@@ -102,10 +116,10 @@ impl ProfileZbus {
.ok(); .ok();
ctrl.save_config(); ctrl.save_config();
return Ok(()); Ok(())
} else { } else {
return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); Err(Error::Failed(UNSUPPORTED_MSG.to_string()))
} };
} }
Err(Error::Failed( Err(Error::Failed(
"Failed to get enabled fan curve names".to_string(), "Failed to get enabled fan curve names".to_string(),
@@ -161,29 +175,13 @@ impl ProfileZbus {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_profile(&self, profile: &Profile) -> zbus::Result<()> {} async fn notify_profile(signal_ctxt: &SignalContext<'_>, profile: Profile) -> zbus::Result<()> {
}
impl ProfileZbus {
fn do_notification(&self) {
if let Ok(ctrl) = self.inner.try_lock() {
self.notify_profile(&ctrl.config.active_profile)
.unwrap_or_else(|err| warn!("{}", err));
}
} }
} }
#[async_trait]
impl crate::ZbusAdd for ProfileZbus { impl crate::ZbusAdd for ProfileZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await;
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
self,
)
.map_err(|err| {
warn!("DbusFanAndCpu: add_to_server {}", err);
err
})
.ok();
} }
} }
+27 -30
View File
@@ -1,4 +1,5 @@
use crate::{config::Config, error::RogError, GetSupported}; use crate::{config::Config, error::RogError, GetSupported};
use async_trait::async_trait;
use log::{error, info, warn}; use log::{error, info, warn};
use rog_supported::RogBiosSupportedFunctions; use rog_supported::RogBiosSupportedFunctions;
use std::fs::OpenOptions; use std::fs::OpenOptions;
@@ -8,8 +9,8 @@ use std::path::Path;
use std::process::Command; use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use zbus::dbus_interface; use zbus::Connection;
use zvariant::ObjectPath; use zbus::{dbus_interface, SignalContext};
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs"; const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
const DRACUT_PATH: &str = "/usr/bin/dracut"; const DRACUT_PATH: &str = "/usr/bin/dracut";
@@ -36,22 +37,23 @@ impl GetSupported for CtrlRogBios {
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlRogBios { impl CtrlRogBios {
pub fn set_dedicated_graphic_mode(&mut self, dedicated: bool) { async fn set_dedicated_graphic_mode(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
dedicated: bool,
) {
self.set_gfx_mode(dedicated) self.set_gfx_mode(dedicated)
.map_err(|err| { .map_err(|err| {
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err); warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
err err
}) })
.ok(); .ok();
self.notify_dedicated_graphic_mode(dedicated) Self::notify_dedicated_graphic_mode(&ctxt, dedicated)
.map_err(|err| { .await
warn!("CtrlRogBios: notify_asus_switch_graphic_mode {}", err);
err
})
.ok(); .ok();
} }
pub fn dedicated_graphic_mode(&self) -> i8 { fn dedicated_graphic_mode(&self) -> i8 {
Self::get_gfx_mode() Self::get_gfx_mode()
.map_err(|err| { .map_err(|err| {
warn!("CtrlRogBios: get_gfx_mode {}", err); warn!("CtrlRogBios: get_gfx_mode {}", err);
@@ -61,24 +63,27 @@ impl CtrlRogBios {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
pub fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()> {} async fn notify_dedicated_graphic_mode(
signal_ctxt: &SignalContext<'_>,
dedicated: bool,
) -> zbus::Result<()> {
}
pub fn set_post_boot_sound(&mut self, on: bool) { async fn set_post_boot_sound(
&mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>,
on: bool,
) {
Self::set_boot_sound(on) Self::set_boot_sound(on)
.map_err(|err| { .map_err(|err| {
warn!("CtrlRogBios: set_post_boot_sound {}", err); warn!("CtrlRogBios: set_post_boot_sound {}", err);
err err
}) })
.ok(); .ok();
self.notify_post_boot_sound(on) Self::notify_post_boot_sound(&ctxt, on).await.ok();
.map_err(|err| {
warn!("CtrlRogBios: notify_post_boot_sound {}", err);
err
})
.ok();
} }
pub fn post_boot_sound(&self) -> i8 { fn post_boot_sound(&self) -> i8 {
Self::get_boot_sound() Self::get_boot_sound()
.map_err(|err| { .map_err(|err| {
warn!("CtrlRogBios: get_boot_sound {}", err); warn!("CtrlRogBios: get_boot_sound {}", err);
@@ -88,21 +93,13 @@ impl CtrlRogBios {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
pub fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()> {} async fn notify_post_boot_sound(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()> {}
} }
#[async_trait]
impl crate::ZbusAdd for CtrlRogBios { impl crate::ZbusAdd for CtrlRogBios {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/RogBios", server).await;
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/RogBios"),
self,
)
.map_err(|err| {
warn!("CtrlRogBios: add_to_server {}", err);
err
})
.ok();
} }
} }
+6 -14
View File
@@ -1,8 +1,8 @@
use log::warn; use async_trait::async_trait;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface; use zbus::dbus_interface;
use zvariant::ObjectPath; use zbus::Connection;
use zvariant_derive::Type; use zvariant::Type;
use crate::{ use crate::{
ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_charge::CtrlCharge, ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_charge::CtrlCharge,
@@ -30,18 +30,10 @@ impl SupportedFunctions {
} }
} }
#[async_trait]
impl crate::ZbusAdd for SupportedFunctions { impl crate::ZbusAdd for SupportedFunctions {
fn add_to_server(self, server: &mut zbus::ObjectServer) { async fn add_to_server(self, server: &mut Connection) {
server Self::add_to_server_helper(self, "/org/asuslinux/Supported", server).await;
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Supported"),
self,
)
.map_err(|err| {
warn!("SupportedFunctions: add_to_server {}", err);
err
})
.ok();
} }
} }
+38 -55
View File
@@ -1,3 +1,14 @@
use std::env;
use std::error::Error;
use std::io::Write;
use std::sync::{Arc, Mutex};
use ::zbus::Connection;
use daemon::ctrl_profiles::controller::CtrlProfileTask;
use log::LevelFilter;
use log::{error, info, warn};
use smol::Executor;
use daemon::ctrl_anime::config::AnimeConfig; use daemon::ctrl_anime::config::AnimeConfig;
use daemon::ctrl_anime::zbus::CtrlAnimeZbus; use daemon::ctrl_anime::zbus::CtrlAnimeZbus;
use daemon::ctrl_anime::*; use daemon::ctrl_anime::*;
@@ -7,7 +18,7 @@ use daemon::ctrl_aura::controller::{
}; };
use daemon::ctrl_charge::CtrlCharge; use daemon::ctrl_charge::CtrlCharge;
use daemon::ctrl_profiles::config::ProfileConfig; use daemon::ctrl_profiles::config::ProfileConfig;
use daemon::ctrl_profiles::controller::CtrlProfileTask; use daemon::ctrl_rog_bios::CtrlRogBios;
use daemon::{ use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
}; };
@@ -15,20 +26,9 @@ use daemon::{
ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus},
laptops::LaptopLedData, laptops::LaptopLedData,
}; };
use ::zbus::{fdo, Connection, ObjectServer};
use daemon::{CtrlTask, Reloadable, ZbusAdd}; use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
use log::{error, info, warn};
use rog_dbus::DBUS_NAME; use rog_dbus::DBUS_NAME;
use rog_profiles::Profile; use rog_profiles::Profile;
use std::env;
use std::error::Error;
use std::io::Write;
use std::sync::Arc;
use std::sync::Mutex;
use daemon::ctrl_rog_bios::CtrlRogBios;
static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf";
@@ -61,27 +61,25 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
info!(" rog-profiles v{}", rog_profiles::VERSION); info!(" rog-profiles v{}", rog_profiles::VERSION);
info!("rog-supported v{}", rog_supported::VERSION); info!("rog-supported v{}", rog_supported::VERSION);
start_daemon()?; let mut executor = Executor::new();
smol::block_on(start_daemon(&mut executor))?;
Ok(()) Ok(())
} }
/// The actual main loop for the daemon /// The actual main loop for the daemon
fn start_daemon() -> Result<(), Box<dyn Error>> { async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box<dyn Error>> {
let supported = SupportedFunctions::get_supported(); let supported = SupportedFunctions::get_supported();
print_board_info(); print_board_info();
println!("{}", serde_json::to_string_pretty(&supported)?); println!("{}", serde_json::to_string_pretty(&supported)?);
// Collect tasks for task thread
let mut tasks: Vec<Box<dyn CtrlTask + Send>> = Vec::new();
// Start zbus server // Start zbus server
let connection = Connection::new_system()?; let mut connection = Connection::system().await?;
let fdo_connection = fdo::DBusProxy::new(&connection)?;
let mut object_server = ObjectServer::new(&connection);
let config = Config::load(); let config = Config::load();
let config = Arc::new(Mutex::new(config)); let config = Arc::new(Mutex::new(config));
supported.add_to_server(&mut object_server); supported.add_to_server(&mut connection).await;
match CtrlRogBios::new(config.clone()) { match CtrlRogBios::new(config.clone()) {
Ok(mut ctrl) => { Ok(mut ctrl) => {
@@ -89,20 +87,23 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
ctrl.reload() ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err)); .unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server // Then register to dbus server
ctrl.add_to_server(&mut object_server); ctrl.add_to_server(&mut connection).await;
} }
Err(err) => { Err(err) => {
error!("rog_bios_control: {}", err); error!("rog_bios_control: {}", err);
} }
} }
match CtrlCharge::new(config) { match CtrlCharge::new(config.clone()) {
Ok(mut ctrl) => { Ok(mut ctrl) => {
// Do a reload of any settings // Do a reload of any settings
ctrl.reload() ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err)); .unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server // Then register to dbus server
ctrl.add_to_server(&mut object_server); ctrl.add_to_server(&mut connection).await;
let task = CtrlCharge::new(config)?;
task.create_tasks(executor).await.ok();
} }
Err(err) => { Err(err) => {
error!("charge_control: {}", err); error!("charge_control: {}", err);
@@ -117,9 +118,11 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.unwrap_or_else(|err| warn!("Profile control: {}", err)); .unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl)); let tmp = Arc::new(Mutex::new(ctrl));
ProfileZbus::new(tmp.clone()).add_to_server(&mut object_server); let task = CtrlProfileTask::new(tmp.clone());
task.create_tasks(executor).await.ok();
tasks.push(Box::new(CtrlProfileTask::new(tmp))); let task = ProfileZbus::new(tmp.clone());
task.add_to_server(&mut connection).await;
} }
Err(err) => { Err(err) => {
error!("Profile control: {}", err); error!("Profile control: {}", err);
@@ -139,9 +142,10 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.unwrap_or_else(|err| warn!("AniMe: {}", err)); .unwrap_or_else(|err| warn!("AniMe: {}", err));
let zbus = CtrlAnimeZbus(inner.clone()); let zbus = CtrlAnimeZbus(inner.clone());
zbus.add_to_server(&mut object_server); zbus.add_to_server(&mut connection).await;
tasks.push(Box::new(CtrlAnimeTask::new(inner))); let task = CtrlAnimeTask::new(inner).await;
task.create_tasks(executor).await.ok();
} }
Err(err) => { Err(err) => {
error!("AniMe control: {}", err); error!("AniMe control: {}", err);
@@ -159,42 +163,21 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.reload() .reload()
.unwrap_or_else(|err| warn!("Keyboard LED control: {}", err)); .unwrap_or_else(|err| warn!("Keyboard LED control: {}", err));
CtrlKbdLedZbus::new(inner.clone()).add_to_server(&mut object_server); CtrlKbdLedZbus::new(inner.clone())
.add_to_server(&mut connection)
.await;
let task = CtrlKbdLedTask::new(inner); let task = CtrlKbdLedTask::new(inner);
tasks.push(Box::new(task)); task.create_tasks(executor).await.ok();
} }
Err(err) => { Err(err) => {
error!("Keyboard control: {}", err); error!("Keyboard control: {}", err);
} }
} }
// TODO: implement messaging between threads to check fails
// 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() {
ctrl.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
});
// Request dbus name after finishing initalizing all functions // Request dbus name after finishing initalizing all functions
fdo_connection.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?; connection.request_name(DBUS_NAME).await?;
// Loop to check errors and iterate zbus server
loop { loop {
if let Err(err) = &handle { smol::block_on(executor.tick());
error!("{}", err);
}
if let Err(err) = object_server.try_handle_next() {
error!("{}", err);
}
} }
} }
+2
View File
@@ -22,6 +22,7 @@ pub enum RogError {
Modprobe(String), Modprobe(String),
Io(std::io::Error), Io(std::io::Error),
Zbus(zbus::Error), Zbus(zbus::Error),
ChargeLimit(u8),
} }
impl fmt::Display for RogError { impl fmt::Display for RogError {
@@ -46,6 +47,7 @@ impl fmt::Display for RogError {
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Io(detail) => write!(f, "std::io error: {}", detail), RogError::Io(detail) => write!(f, "std::io error: {}", detail),
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail), RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
RogError::ChargeLimit(value) => write!(f, "Invalid charging limit, not in range 20-100%: {}", value),
} }
} }
} }
+46 -4
View File
@@ -27,11 +27,17 @@ pub mod laptops;
/// Fetch all supported functions for the laptop /// Fetch all supported functions for the laptop
pub mod ctrl_supported; pub mod ctrl_supported;
mod error; pub mod error;
use std::time::Duration;
use crate::error::RogError; use crate::error::RogError;
use async_trait::async_trait;
use config::Config; use config::Config;
use zbus::ObjectServer; use log::warn;
use smol::{stream::StreamExt, Executor, Timer};
use zbus::Connection;
use zvariant::ObjectPath;
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -39,12 +45,48 @@ pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>; fn reload(&mut self) -> Result<(), RogError>;
} }
#[async_trait]
pub trait ZbusAdd { pub trait ZbusAdd {
fn add_to_server(self, server: &mut ObjectServer); async fn add_to_server(self, server: &mut Connection);
async fn add_to_server_helper(
iface: impl zbus::Interface,
path: &str,
server: &mut Connection,
) {
server
.object_server()
.at(&ObjectPath::from_str_unchecked(path), iface)
.await
.map_err(|err| {
warn!("{}: add_to_server {}", path, err);
err
})
.ok();
}
} }
/// Set up a task to run on the async executor
#[async_trait]
pub trait CtrlTask { pub trait CtrlTask {
fn do_task(&self) -> Result<(), RogError>; /// Implement to set up various tasks that may be required, using the `Executor`.
/// No blocking loops are allowed, or they must be run on a separate thread.
async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError>;
/// Create a timed repeating task
async fn repeating_task(
&self,
millis: u64,
executor: &mut Executor,
mut task: impl FnMut() + Send + 'static,
) {
let timer = Timer::interval(Duration::from_millis(millis));
executor
.spawn(async move {
timer.for_each(|_| task()).await;
})
.detach();
}
} }
pub trait CtrlTaskComplex { pub trait CtrlTaskComplex {
+25 -4
View File
@@ -21,7 +21,7 @@ per_key = false
[[led_data]] [[led_data]]
prod_family = "ROG Zephyrus M15" prod_family = "ROG Zephyrus M15"
board_names = ["GU502LW"] board_names = ["GU502LW", "GU502LV"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false multizone = false
per_key = true per_key = true
@@ -42,14 +42,14 @@ per_key = false
[[led_data]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["G531GW", "G533QR", "G733QS", "G733QR"] board_names = ["G531GW", "G533QR", "G533QS", "G733QS", "G733QR", "G513QR", "G713QR", "G513QM"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false multizone = false
per_key = true per_key = true
[[led_data]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY"] board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = true multizone = true
per_key = false per_key = false
@@ -96,6 +96,13 @@ standard = ["Static", "Breathe", "Pulse"]
multizone = false multizone = false
per_key = false per_key = false
[[led_data]]
prod_family = "ROG Zephyrus G14"
board_names = ["GA402R"]
standard = ["Static", "Breathe", "Pulse", "Rainbow"]
multizone = false
per_key = false
# GA503QE at higher priority (first match) than GA503Q # GA503QE at higher priority (first match) than GA503Q
[[led_data]] [[led_data]]
prod_family = "ROG Zephyrus G15" prod_family = "ROG Zephyrus G15"
@@ -123,4 +130,18 @@ prod_family = "ROG Zephyrus Duo 15 SE"
board_names = ["GX551Q"] board_names = ["GX551Q"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = false multizone = false
per_key = true per_key = true
[[led_data]]
prod_family = "ROG Flow X13"
board_names = ["GV301QH", "GV301QE"]
standard = ["Static", "Breathe", "Pulse"]
multizone = false
per_key = false
[[led_data]]
prod_family = "ROG Strix"
board_names = ["G513IC"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = false
per_key = false
+40 -12
View File
@@ -28,18 +28,53 @@ impl CtrlAnime {
} }
``` ```
The task trait: The task trait. There are three ways to implement this:
```rust ```rust
pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>); pub struct CtrlAnimeTask(Arc<Mutex<CtrlAnime>>);
impl crate::CtrlTask for CtrlAnimeTask { impl crate::CtrlTask for CtrlAnimeTask {
fn do_task(&self) -> Result<(), RogError> { // This will run once only
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
if let Ok(lock) = self.inner.try_lock() { if let Ok(lock) = self.inner.try_lock() {
<some action> <some action>
} }
Ok(()) Ok(())
} }
// This will run until the notification stream closes (which in most cases will be never)
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
let connection = Connection::system().await.unwrap();
let manager = ManagerProxy::new(&connection).await.unwrap();
let inner = self.inner.clone();
executor
.spawn(async move {
// A notification from logind dbus interface
if let Ok(p) = manager.receive_prepare_for_sleep().await {
// A stream that will continuously output events
p.for_each(|_| {
if let Ok(lock) = inner.try_lock() {
// Do stuff here
}
})
.await;
}
})
.detach();
}
// This task will run every 500 milliseconds
fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> {
let inner = self.inner.clone();
// This is a provided free trait to help set up a repeating task
self.repeating_task(500, executor, move || {
if let Ok(lock) = inner.try_lock() {
// Do stuff here
}
})
.await;
}
} }
``` ```
@@ -61,18 +96,11 @@ The Zbus requirements:
```rust ```rust
pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>); pub struct CtrlAnimeZbus(Arc<Mutex<CtrlAnime>>);
#[async_trait]
impl crate::ZbusAdd for CtrlAnimeZbus { impl crate::ZbusAdd for CtrlAnimeZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) { fn add_to_server(self, server: &mut zbus::ObjectServer) {
server // This is a provided free helper trait with pre-set body. It will move self in-to.
.at( Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await;
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
} }
} }
+5 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_anime" name = "rog_anime"
version = "1.1.0" version = "1.3.3"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
@@ -14,17 +14,17 @@ exclude = ["data"]
[features] [features]
default = ["dbus"] default = ["dbus"]
dbus = ["zvariant", "zvariant_derive"] dbus = ["zvariant"]
[dependencies] [dependencies]
png_pong = "^0.8.0" png_pong = "^0.8.0"
pix = "0.13" pix = "0.13"
gif = "^0.11.2" gif = "^0.11.2"
log = "*"
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
glam = { version = "0.14.0", features = ["serde"] } glam = { version = "0.20.5", features = ["serde"] }
zvariant = { version = "^2.6", optional = true } zvariant = { version = "^3.0", optional = true }
zvariant_derive = { version = "^2.6", optional = true }
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

+10 -13
View File
@@ -1,15 +1,12 @@
use std::{ use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::sleep, thread::sleep,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use log::info;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant_derive::Type; use zvariant::Type;
use crate::{error::AnimeError, AnimTime, AnimeGif}; use crate::{error::AnimeError, AnimTime, AnimeGif};
@@ -27,8 +24,8 @@ const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub struct AnimePowerStates { pub struct AnimePowerStates {
pub brightness: u8,
pub enabled: bool, pub enabled: bool,
pub boot_anim_enabled: bool, pub boot_anim_enabled: bool,
} }
@@ -92,10 +89,11 @@ impl From<AnimeDataBuffer> for AnimePacketType {
} }
/// This runs the animations as a blocking loop by using the `callback` to write data /// This runs the animations as a blocking loop by using the `callback` to write data
///
/// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early.
pub fn run_animation( pub fn run_animation(
frames: &AnimeGif, frames: &AnimeGif,
do_early_return: Arc<AtomicBool>, callback: &dyn Fn(AnimeDataBuffer) -> Result<bool, AnimeError>,
callback: &dyn Fn(AnimeDataBuffer) -> Result<(), AnimeError>,
) -> Result<(), AnimeError> { ) -> Result<(), AnimeError> {
let mut count = 0; let mut count = 0;
let start = Instant::now(); let start = Instant::now();
@@ -140,9 +138,6 @@ pub fn run_animation(
'animation: loop { 'animation: loop {
for frame in frames.frames() { for frame in frames.frames() {
let frame_start = Instant::now(); let frame_start = Instant::now();
if do_early_return.load(Ordering::SeqCst) {
return Ok(());
}
let mut output = frame.frame().clone(); let mut output = frame.frame().clone();
if let AnimTime::Fade(_) = frames.duration() { if let AnimTime::Fade(_) = frames.duration() {
@@ -164,12 +159,14 @@ pub fn run_animation(
} }
} }
callback(output)?; if matches!(callback(output), Ok(true)) {
info!("rog-anime: frame-loop callback asked to exit early");
return Ok(());
}
if timed && Instant::now().duration_since(start) > run_time { if timed && Instant::now().duration_since(start) > run_time {
break 'animation; break 'animation;
} }
sleep(frame.delay()); sleep(frame.delay());
} }
if let AnimTime::Count(times) = frames.duration() { if let AnimTime::Count(times) = frames.duration() {
+4 -4
View File
@@ -88,7 +88,7 @@ pub struct AnimeGif(Vec<AnimeFrame>, AnimTime);
impl AnimeGif { impl AnimeGif {
/// Create an animation using the 74x36 ASUS gif format /// Create an animation using the 74x36 ASUS gif format
#[inline] #[inline]
pub fn create_diagonal_gif( pub fn from_diagonal_gif(
file_name: &Path, file_name: &Path,
duration: AnimTime, duration: AnimTime,
brightness: f32, brightness: f32,
@@ -130,7 +130,7 @@ impl AnimeGif {
/// Create an animation using the 74x36 ASUS gif format from a png /// Create an animation using the 74x36 ASUS gif format from a png
#[inline] #[inline]
pub fn create_diagonal_png( pub fn from_diagonal_png(
file_name: &Path, file_name: &Path,
duration: AnimTime, duration: AnimTime,
brightness: f32, brightness: f32,
@@ -159,7 +159,7 @@ impl AnimeGif {
/// Create an animation using a gif of any size. This method must precompute the /// Create an animation using a gif of any size. This method must precompute the
/// result. /// result.
#[inline] #[inline]
pub fn create_png_gif( pub fn from_gif(
file_name: &Path, file_name: &Path,
scale: f32, scale: f32,
angle: f32, angle: f32,
@@ -231,7 +231,7 @@ impl AnimeGif {
/// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can /// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can
/// be considered how many seconds the image will show for. /// be considered how many seconds the image will show for.
#[inline] #[inline]
pub fn create_png_static( pub fn from_png(
file_name: &Path, file_name: &Path,
scale: f32, scale: f32,
angle: f32, angle: f32,
+5 -7
View File
@@ -69,7 +69,7 @@ impl ActionData {
file, file,
time, time,
brightness, brightness,
} => ActionData::Animation(AnimeGif::create_diagonal_gif(file, *time, *brightness)?), } => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?),
ActionLoader::AsusImage { ActionLoader::AsusImage {
file, file,
time, time,
@@ -80,9 +80,7 @@ impl ActionData {
let data = <AnimeDataBuffer>::from(&image); let data = <AnimeDataBuffer>::from(&image);
ActionData::Image(Box::new(data)) ActionData::Image(Box::new(data))
} }
_ => { _ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?),
ActionData::Animation(AnimeGif::create_diagonal_png(file, *time, *brightness)?)
}
}, },
ActionLoader::ImageAnimation { ActionLoader::ImageAnimation {
file, file,
@@ -94,7 +92,7 @@ impl ActionData {
} => { } => {
if let Some(ext) = file.extension() { if let Some(ext) = file.extension() {
if ext.to_string_lossy().to_lowercase() == "png" { if ext.to_string_lossy().to_lowercase() == "png" {
return Ok(ActionData::Animation(AnimeGif::create_png_static( return Ok(ActionData::Animation(AnimeGif::from_png(
file, file,
*scale, *scale,
*angle, *angle,
@@ -104,7 +102,7 @@ impl ActionData {
)?)); )?));
} }
} }
ActionData::Animation(AnimeGif::create_png_gif( ActionData::Animation(AnimeGif::from_gif(
file, file,
*scale, *scale,
*angle, *angle,
@@ -129,7 +127,7 @@ impl ActionData {
let data = <AnimeDataBuffer>::from(&image); let data = <AnimeDataBuffer>::from(&image);
ActionData::Image(Box::new(data)) ActionData::Image(Box::new(data))
} }
_ => ActionData::Animation(AnimeGif::create_png_static( _ => ActionData::Animation(AnimeGif::from_png(
file, file,
*scale, *scale,
*angle, *angle,
+2 -3
View File
@@ -14,11 +14,10 @@ exclude = ["data"]
[features] [features]
default = ["dbus"] default = ["dbus"]
dbus = ["zvariant", "zvariant_derive"] dbus = ["zvariant"]
[dependencies] [dependencies]
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
zvariant = { version = "^2.6", optional = true } zvariant = { version = "^3.0", optional = true }
zvariant_derive = { version = "^2.6", optional = true }
+17 -14
View File
@@ -7,15 +7,18 @@ pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant_derive::Type; use zvariant::Type;
use crate::{error::Error, LED_MSG_LEN}; use crate::{error::Error, LED_MSG_LEN};
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub struct LedPowerStates { pub struct LedPowerStates {
pub enabled: bool, pub boot_anim: bool,
pub sleep_anim_enabled: bool, pub sleep_anim: bool,
pub all_leds: bool,
pub keys_leds: bool,
pub side_leds: bool,
} }
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
@@ -149,14 +152,14 @@ impl From<&AuraModeNum> for &str {
fn from(mode: &AuraModeNum) -> Self { fn from(mode: &AuraModeNum) -> Self {
match mode { match mode {
AuraModeNum::Static => "Static", AuraModeNum::Static => "Static",
AuraModeNum::Breathe => "Breathing", AuraModeNum::Breathe => "Breathe",
AuraModeNum::Strobe => "Strobing", AuraModeNum::Strobe => "Strobe",
AuraModeNum::Rainbow => "Rainbow", AuraModeNum::Rainbow => "Rainbow",
AuraModeNum::Star => "Stars", AuraModeNum::Star => "Stars",
AuraModeNum::Rain => "Rain", AuraModeNum::Rain => "Rain",
AuraModeNum::Highlight => "Keypress Highlight", AuraModeNum::Highlight => "Highlight",
AuraModeNum::Laser => "Keypress Laser", AuraModeNum::Laser => "Laser",
AuraModeNum::Ripple => "Keypress Ripple", AuraModeNum::Ripple => "Ripple",
AuraModeNum::Pulse => "Pulse", AuraModeNum::Pulse => "Pulse",
AuraModeNum::Comet => "Comet", AuraModeNum::Comet => "Comet",
AuraModeNum::Flash => "Flash", AuraModeNum::Flash => "Flash",
@@ -167,14 +170,14 @@ impl From<&str> for AuraModeNum {
fn from(mode: &str) -> Self { fn from(mode: &str) -> Self {
match mode { match mode {
"Static" => AuraModeNum::Static, "Static" => AuraModeNum::Static,
"Breathing" => AuraModeNum::Breathe, "Breathe" => AuraModeNum::Breathe,
"Strobing" => AuraModeNum::Strobe, "Strobe" => AuraModeNum::Strobe,
"Rainbow" => AuraModeNum::Rainbow, "Rainbow" => AuraModeNum::Rainbow,
"Stars" => AuraModeNum::Star, "Stars" => AuraModeNum::Star,
"Rain" => AuraModeNum::Rain, "Rain" => AuraModeNum::Rain,
"Keypress Highlight" => AuraModeNum::Highlight, "Highlight" => AuraModeNum::Highlight,
"Keypress Laser" => AuraModeNum::Laser, "Laser" => AuraModeNum::Laser,
"Keypress Ripple" => AuraModeNum::Ripple, "Ripple" => AuraModeNum::Ripple,
"Pulse" => AuraModeNum::Pulse, "Pulse" => AuraModeNum::Pulse,
"Comet" => AuraModeNum::Comet, "Comet" => AuraModeNum::Comet,
"Flash" => AuraModeNum::Flash, "Flash" => AuraModeNum::Flash,
@@ -216,7 +219,7 @@ pub enum AuraZone {
/// Default factory modes structure. This easily converts to an USB HID packet with: /// Default factory modes structure. This easily converts to an USB HID packet with:
/// ```rust /// ```rust
/// let bytes: [u8; LED_MSG_LEN] = mode.into(); /// // let bytes: [u8; LED_MSG_LEN] = mode.into();
/// ``` /// ```
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
+118 -12
View File
@@ -1,3 +1,7 @@
use crate::usb::LedCfgState::{Off, On};
use std::convert::TryFrom;
use std::ops::{BitAnd, BitOr};
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9]; pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
@@ -8,6 +12,13 @@ pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
pub const LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; pub const LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pub const BOOT_MASK: i32 = 0xc31309;
pub const SLEEP_MASK: i32 = 0x300904;
pub const ALL_LEDS_MASK: i32 = 0x000002;
pub const KBD_LEDS_MASK: i32 = 0x080000;
pub const SIDE_LEDS_MASK: i32 = 0x040500;
pub const LEDS_STATE_MASK: i32 = ALL_LEDS_MASK | KBD_LEDS_MASK | SIDE_LEDS_MASK;
/// Writes out the correct byte string for brightness /// Writes out the correct byte string for brightness
pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
[ [
@@ -15,18 +26,113 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
] ]
} }
pub const LED_AWAKE_ON_SLEEP_OFF: [u8; 17] = [ #[derive(Clone, Copy)]
0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pub enum LedCfgState {
]; On = 0xffffff,
Off = 0x0,
}
pub const LED_AWAKE_ON_SLEEP_ON: [u8; 17] = [ impl From<i32> for LedCfgState {
0x5d, 0xbd, 0x01, 0xff, 0x1f, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn from(state: i32) -> Self {
]; match state {
0xffffff => On,
0x0 => Off,
_ => Off,
}
}
}
pub const LED_AWAKE_OFF_SLEEP_OFF: [u8; 17] = [ impl From<bool> for LedCfgState {
0x5d, 0xbd, 0x01, 0xc3, 0x13, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn from(state: bool) -> Self {
]; match state {
true => On,
false => Off,
}
}
}
pub const LED_AWAKE_OFF_SLEEP_ON: [u8; 17] = [ impl TryFrom<[u8; 3]> for LedCfgState {
0x5d, 0xbd, 0x01, 0xf3, 0x1b, 0x0d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, type Error = &'static str;
];
fn try_from(value: [u8; 3]) -> Result<Self, Self::Error> {
match value {
[0xff, 0xff, 0xff] => Ok(On),
[0, 0, 0] => Ok(Off),
_ => Err("Unconvertible value"),
}
}
}
impl BitAnd<LedCfgState> for i32 {
type Output = i32;
fn bitand(self, rhs: LedCfgState) -> i32 {
return self & rhs as i32;
}
}
impl BitOr<LedCfgState> for i32 {
type Output = i32;
fn bitor(self, rhs: LedCfgState) -> Self::Output {
return self | rhs as i32;
}
}
impl BitOr<LedCfgState> for LedCfgState {
type Output = i32;
fn bitor(self, rhs: LedCfgState) -> i32 {
return self as i32 | rhs as i32;
}
}
impl BitAnd<LedCfgState> for LedCfgState {
type Output = LedCfgState;
fn bitand(self, rhs: LedCfgState) -> LedCfgState {
return (self as i32 & rhs as i32).into();
}
}
pub fn leds_message(
boot_state: bool,
sleep_state: bool,
all_leds_state: bool,
kbd_leds_state: bool,
side_leds_state: bool,
) -> [u8; 3] {
let raw_message = _leds_message(
boot_state.into(),
sleep_state.into(),
all_leds_state.into(),
kbd_leds_state.into(),
side_leds_state.into(),
);
let [_, lows @ ..] = i32::to_be_bytes(raw_message);
return lows;
}
fn _leds_message(
boot_state: LedCfgState,
sleep_state: LedCfgState,
all_leds_state: LedCfgState,
kbd_leds_state: LedCfgState,
side_leds_state: LedCfgState,
) -> i32 {
let full_leds_state = match all_leds_state {
On => {
(ALL_LEDS_MASK & all_leds_state)
| (KBD_LEDS_MASK & kbd_leds_state)
| (SIDE_LEDS_MASK & side_leds_state)
}
Off => 0x0100 & side_leds_state,
};
let boot_xor_sleep = (BOOT_MASK & boot_state) ^ (SLEEP_MASK & sleep_state);
return match (all_leds_state | kbd_leds_state | side_leds_state).into() {
On => boot_xor_sleep ^ ((boot_xor_sleep ^ full_leds_state) & LEDS_STATE_MASK),
_ => boot_xor_sleep,
};
}
+4 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_dbus" name = "rog_dbus"
version = "4.0.2" version = "4.1.0"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
@@ -14,7 +14,6 @@ rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
rog_supported = { path = "../rog-supported" } rog_supported = { path = "../rog-supported" }
supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" } zbus = "^2.2"
zbus = "^1.9" zbus_macros = "^2.0"
zbus_macros = "^1.9" zvariant = "^3.0"
zvariant = "^2.8"
+87 -102
View File
@@ -1,5 +1,4 @@
pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static DBUS_NAME_GFX: &str = "org.supergfxctl.Daemon";
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
@@ -10,51 +9,109 @@ pub mod zbus_profile;
pub mod zbus_rogbios; pub mod zbus_rogbios;
pub mod zbus_supported; pub mod zbus_supported;
use rog_anime::AnimePowerStates; // use rog_anime::AnimePowerStates;
use rog_aura::{AuraEffect, LedPowerStates}; // use rog_aura::{AuraEffect, LedPowerStates};
use rog_profiles::Profile; // use rog_profiles::Profile;
use std::sync::mpsc::{channel, Receiver}; // use std::sync::mpsc::{channel, Receiver};
use zbus::{Connection, Result, SignalReceiver}; use zbus::{blocking, Connection, Result};
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub struct DbusProxiesBlocking<'a> {
anime: zbus_anime::AnimeProxyBlocking<'a>,
charge: zbus_charge::ChargeProxyBlocking<'a>,
led: zbus_led::LedProxyBlocking<'a>,
profile: zbus_profile::ProfileProxyBlocking<'a>,
rog_bios: zbus_rogbios::RogBiosProxyBlocking<'a>,
supported: zbus_supported::SupportedProxyBlocking<'a>,
}
impl<'a> DbusProxiesBlocking<'a> {
#[inline]
pub fn new() -> Result<(Self, blocking::Connection)> {
let conn = blocking::Connection::system()?;
Ok((
DbusProxiesBlocking {
anime: zbus_anime::AnimeProxyBlocking::new(&conn)?,
led: zbus_led::LedProxyBlocking::new(&conn)?,
charge: zbus_charge::ChargeProxyBlocking::new(&conn)?,
profile: zbus_profile::ProfileProxyBlocking::new(&conn)?,
rog_bios: zbus_rogbios::RogBiosProxyBlocking::new(&conn)?,
supported: zbus_supported::SupportedProxyBlocking::new(&conn)?,
},
conn,
))
}
pub fn anime(&self) -> &zbus_anime::AnimeProxyBlocking<'a> {
&self.anime
}
pub fn charge(&self) -> &zbus_charge::ChargeProxyBlocking<'a> {
&self.charge
}
pub fn led(&self) -> &zbus_led::LedProxyBlocking<'a> {
&self.led
}
pub fn profile(&self) -> &zbus_profile::ProfileProxyBlocking<'a> {
&self.profile
}
pub fn rog_bios(&self) -> &zbus_rogbios::RogBiosProxyBlocking<'a> {
&self.rog_bios
}
pub fn supported(&self) -> &zbus_supported::SupportedProxyBlocking<'a> {
&self.supported
}
}
/// This is the main way to communicate with the DBUS interface
pub struct RogDbusClientBlocking<'a> {
proxies: DbusProxiesBlocking<'a>,
}
impl<'a> RogDbusClientBlocking<'a> {
#[inline]
pub fn new() -> Result<(Self, blocking::Connection)> {
let (proxies, conn) = DbusProxiesBlocking::new()?;
Ok((RogDbusClientBlocking { proxies }, conn))
}
pub fn proxies(&self) -> &DbusProxiesBlocking {
&self.proxies
}
}
pub struct DbusProxies<'a> { pub struct DbusProxies<'a> {
anime: zbus_anime::AnimeProxy<'a>, anime: zbus_anime::AnimeProxy<'a>,
charge: zbus_charge::ChargeProxy<'a>, charge: zbus_charge::ChargeProxy<'a>,
led: zbus_led::LedProxy<'a>, led: zbus_led::LedProxy<'a>,
profile: zbus_profile::ProfileProxy<'a>, profile: zbus_profile::ProfileProxy<'a>,
rog_bios: zbus_rogbios::RogBiosProxy<'a>, rog_bios: zbus_rogbios::RogBiosProxy<'a>,
supported: zbus_supported::SupportProxy<'a>, supported: zbus_supported::SupportedProxy<'a>,
} }
impl<'a> DbusProxies<'a> { impl<'a> DbusProxies<'a> {
#[inline] #[inline]
pub fn new() -> Result<(Self, Connection)> { pub async fn new() -> Result<(DbusProxies<'a>, Connection)> {
let conn = Connection::new_system()?; let conn = Connection::system().await?;
Ok(( Ok((
DbusProxies { DbusProxies {
anime: zbus_anime::AnimeProxy::new(&conn)?, anime: zbus_anime::AnimeProxy::new(&conn).await?,
led: zbus_led::LedProxy::new(&conn)?, led: zbus_led::LedProxy::new(&conn).await?,
charge: zbus_charge::ChargeProxy::new(&conn)?, charge: zbus_charge::ChargeProxy::new(&conn).await?,
profile: zbus_profile::ProfileProxy::new(&conn)?, profile: zbus_profile::ProfileProxy::new(&conn).await?,
rog_bios: zbus_rogbios::RogBiosProxy::new(&conn)?, rog_bios: zbus_rogbios::RogBiosProxy::new(&conn).await?,
supported: zbus_supported::SupportProxy::new(&conn)?, supported: zbus_supported::SupportedProxy::new(&conn).await?,
}, },
conn, conn,
)) ))
} }
pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver<'a, 'a> {
let mut recv = SignalReceiver::new(conn);
recv.receive_for(self.anime.proxy());
recv.receive_for(self.led.proxy());
recv.receive_for(self.charge.proxy());
recv.receive_for(self.profile.proxy());
recv.receive_for(self.rog_bios.proxy());
recv.receive_for(self.supported.proxy());
recv
}
pub fn anime(&self) -> &zbus_anime::AnimeProxy<'a> { pub fn anime(&self) -> &zbus_anime::AnimeProxy<'a> {
&self.anime &self.anime
} }
@@ -75,96 +132,24 @@ impl<'a> DbusProxies<'a> {
&self.rog_bios &self.rog_bios
} }
pub fn supported(&self) -> &zbus_supported::SupportProxy<'a> { pub fn supported(&self) -> &zbus_supported::SupportedProxy<'a> {
&self.supported &self.supported
} }
} }
// Signals separated out
pub struct Signals {
pub profile: Receiver<Profile>,
pub led_mode: Receiver<AuraEffect>,
pub led_power_state: Receiver<LedPowerStates>,
pub anime_power_state: Receiver<AnimePowerStates>,
pub charge: Receiver<u8>,
pub bios_gsync: Receiver<bool>,
pub bios_sound: Receiver<bool>,
}
impl Signals {
#[inline]
pub fn new(proxies: &DbusProxies) -> Result<Self> {
Ok(Signals {
profile: {
let (tx, rx) = channel();
proxies.profile.connect_notify_profile(tx)?;
rx
},
charge: {
let (tx, rx) = channel();
proxies.charge.connect_notify_charge(tx)?;
rx
},
led_mode: {
let (tx, rx) = channel();
proxies.led.connect_notify_led(tx)?;
rx
},
led_power_state: {
let (tx, rx) = channel();
proxies.led.connect_notify_power_states(tx)?;
rx
},
anime_power_state: {
let (tx, rx) = channel();
proxies.anime.connect_notify_power_states(tx)?;
rx
},
bios_gsync: {
let (tx, rx) = channel();
proxies.rog_bios.connect_notify_dedicated_graphic_mode(tx)?;
rx
},
bios_sound: {
let (tx, rx) = channel();
proxies.rog_bios.connect_notify_post_boot_sound(tx)?;
rx
},
})
}
}
/// This is the main way to communicate with the DBUS interface /// This is the main way to communicate with the DBUS interface
pub struct RogDbusClient<'a> { pub struct RogDbusClient<'a> {
proxies: DbusProxies<'a>, proxies: DbusProxies<'a>,
signals: Signals,
} }
impl<'a> RogDbusClient<'a> { impl<'a> RogDbusClient<'a> {
#[inline] #[inline]
pub fn new() -> Result<(Self, Connection)> { pub async fn new() -> Result<(RogDbusClient<'a>, Connection)> {
let (proxies, conn) = DbusProxies::new()?; let (proxies, conn) = DbusProxies::new().await?;
let signals = Signals::new(&proxies)?; Ok((RogDbusClient { proxies }, conn))
Ok((RogDbusClient { proxies, signals }, conn))
} }
pub fn proxies(&self) -> &DbusProxies { pub fn proxies(&self) -> &DbusProxies {
&self.proxies &self.proxies
} }
pub fn signals(&self) -> &Signals {
&self.signals
}
pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver<'a, 'a> {
let mut recv = SignalReceiver::new(conn);
recv.receive_for(self.proxies.anime.proxy());
recv.receive_for(self.proxies.led.proxy());
recv.receive_for(self.proxies.charge.proxy());
recv.receive_for(self.proxies.profile.proxy());
recv.receive_for(self.proxies.rog_bios.proxy());
recv.receive_for(self.proxies.supported.proxy());
recv
}
} }
+4 -61
View File
@@ -1,12 +1,11 @@
use rog_anime::{AnimeDataBuffer, AnimePowerStates}; use rog_anime::{AnimeDataBuffer, AnimePowerStates};
use std::sync::mpsc::Sender; use zbus_macros::dbus_proxy;
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Anime" default_path = "/org/asuslinux/Anime"
)] )]
trait Daemon { trait Anime {
/// Set whether the AniMe will show boot, suspend, or off animations /// Set whether the AniMe will show boot, suspend, or off animations
fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>; fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>;
@@ -17,7 +16,7 @@ trait Daemon {
fn set_on_off(&self, status: bool) -> zbus::Result<()>; fn set_on_off(&self, status: bool) -> zbus::Result<()>;
/// Writes a data stream of length. Will force system thread to exit until it is restarted /// Writes a data stream of length. Will force system thread to exit until it is restarted
fn write(&self, input: &[u8]) -> zbus::Result<()>; fn write(&self, input: AnimeDataBuffer) -> zbus::Result<()>;
/// Get status of if the AniMe LEDs are on /// Get status of if the AniMe LEDs are on
#[dbus_proxy(property)] #[dbus_proxy(property)]
@@ -29,61 +28,5 @@ trait Daemon {
/// Notify listeners of the status of AniMe LED power and factory system-status animations /// Notify listeners of the status of AniMe LED power and factory system-status animations
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_power_states(&self, data: AnimePowerStates) -> zbus::Result<()>; fn power_states(&self, data: AnimePowerStates) -> zbus::Result<()>;
}
pub struct AnimeProxy<'a>(DaemonProxy<'a>);
impl<'a> AnimeProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(AnimeProxy(DaemonProxy::new(conn)?))
}
#[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
/// Set whether the AniMe will show boot, suspend, or off animations
#[inline]
pub fn set_system_animations(&self, on: bool) -> Result<()> {
self.0.set_boot_on_off(on)
}
/// Set whether the AniMe is displaying images/data
#[inline]
pub fn set_led_power(&self, on: bool) -> Result<()> {
self.0.set_on_off(on)
}
/// Writes a data stream of length. Will force system thread to exit until it is restarted
#[inline]
pub fn write(&self, input: AnimeDataBuffer) -> Result<()> {
self.0.write(input.get())
}
/// Get status of if the AniMe LEDs are on
#[inline]
pub fn awake_enabled(&self) -> Result<bool> {
self.0.awake_enabled()
}
/// Get the status of if factory system-status animations are enabled
#[inline]
pub fn boot_enabled(&self) -> Result<bool> {
self.0.boot_enabled()
}
#[inline]
pub fn connect_notify_power_states(
&self,
send: Sender<AnimePowerStates>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_power_states(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
} }
+3 -38
View File
@@ -19,15 +19,13 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::mpsc::Sender; use zbus_macros::dbus_proxy;
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Charge" default_path = "/org/asuslinux/Charge"
)] )]
trait Daemon { trait Charge {
/// Limit method /// Limit method
fn limit(&self) -> zbus::Result<i16>; fn limit(&self) -> zbus::Result<i16>;
@@ -36,38 +34,5 @@ trait Daemon {
/// NotifyCharge signal /// NotifyCharge signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_charge(&self, limit: u8) -> zbus::Result<()>; fn notify_charge(&self, limit: u8) -> zbus::Result<u8>;
}
pub struct ChargeProxy<'a>(DaemonProxy<'a>);
impl<'a> ChargeProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(ChargeProxy(DaemonProxy::new(conn)?))
}
#[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn write_limit(&self, level: u8) -> Result<()> {
self.0.set_limit(level)
}
#[inline]
pub fn get_limit(&self) -> Result<i16> {
self.0.limit()
}
#[inline]
pub fn connect_notify_charge(&self, send: Sender<u8>) -> zbus::fdo::Result<()> {
self.0.connect_notify_charge(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
} }
+20 -90
View File
@@ -19,9 +19,8 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::mpsc::Sender; use zbus::{blocking::Connection, Result};
use zbus_macros::dbus_proxy;
use zbus::{dbus_proxy, Connection, Result};
use rog_aura::{AuraEffect, KeyColourArray, LedBrightness, LedPowerStates}; use rog_aura::{AuraEffect, KeyColourArray, LedBrightness, LedPowerStates};
@@ -31,7 +30,7 @@ const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 F
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Led" default_path = "/org/asuslinux/Led"
)] )]
trait Daemon { trait Led {
/// NextLedMode method /// NextLedMode method
fn next_led_mode(&self) -> zbus::Result<()>; fn next_led_mode(&self) -> zbus::Result<()>;
@@ -51,11 +50,20 @@ trait Daemon {
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
/// SetAwakeEnabled method /// SetAwakeEnabled method
fn set_awake_enabled(&self, enabled: bool) -> zbus::Result<()>; fn set_boot_enabled(&self, enabled: bool) -> zbus::Result<()>;
/// SetSleepEnabled method /// SetSleepEnabled method
fn set_sleep_enabled(&self, enabled: bool) -> zbus::Result<()>; fn set_sleep_enabled(&self, enabled: bool) -> zbus::Result<()>;
/// SetSideLedsEnabled method
fn set_all_leds_enabled(&self, enabled: bool) -> Result<()>;
/// SetSideLedsEnabled method
fn set_keys_leds_enabled(&self, enabled: bool) -> Result<()>;
/// SetSideLedsEnabled method
fn set_side_leds_enabled(&self, enabled: bool) -> Result<()>;
/// NotifyLed signal /// NotifyLed signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
@@ -80,81 +88,24 @@ trait Daemon {
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn sleep_enabled(&self) -> zbus::Result<bool>; fn sleep_enabled(&self) -> zbus::Result<bool>;
#[dbus_proxy(property)]
fn side_leds_enabled(&self) -> zbus::Result<bool>;
} }
pub struct LedProxy<'a>(DaemonProxy<'a>); pub struct LedProxyPerkey<'a>(LedProxyBlocking<'a>);
impl<'a> LedProxy<'a> { impl<'a> LedProxyPerkey<'a> {
#[inline] #[inline]
pub fn new(conn: &Connection) -> Result<Self> { pub fn new(conn: &Connection) -> Result<Self> {
Ok(LedProxy(DaemonProxy::new(conn)?)) Ok(LedProxyPerkey(LedProxyBlocking::new(conn)?))
} }
#[inline] #[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> { pub fn proxy(&self) -> &LedProxyBlocking<'a> {
&self.0 &self.0
} }
#[inline]
pub fn get_led_brightness(&self) -> Result<i16> {
self.0.led_brightness()
}
#[inline]
pub fn set_led_brightness(&self, level: LedBrightness) -> Result<()> {
self.0.set_brightness(level)?;
Ok(())
}
/// Set the keyboard LED to enabled while the device is awake
#[inline]
pub fn set_awake_enabled(&self, enabled: bool) -> Result<()> {
self.0.set_awake_enabled(enabled)?;
Ok(())
}
/// Set the keyboard LED suspend animation to enabled while the device is suspended
#[inline]
pub fn set_sleep_enabled(&self, enabled: bool) -> Result<()> {
self.0.set_sleep_enabled(enabled)?;
Ok(())
}
#[inline]
pub fn next_led_mode(&self) -> Result<()> {
self.0.next_led_mode()
}
#[inline]
pub fn prev_led_mode(&self) -> Result<()> {
self.0.prev_led_mode()
}
#[inline]
pub fn next_led_brightness(&self) -> Result<()> {
self.0.next_led_brightness()
}
#[inline]
pub fn prev_led_brightness(&self) -> Result<()> {
self.0.prev_led_brightness()
}
#[inline]
pub fn set_led_mode(&self, mode: &AuraEffect) -> Result<()> {
self.0.set_led_mode(mode)
}
#[inline]
pub fn awake_enabled(&self) -> Result<bool> {
self.0.awake_enabled()
}
#[inline]
pub fn sleep_enabled(&self) -> Result<bool> {
self.0.sleep_enabled()
}
/// Write a single colour block. /// Write a single colour block.
/// ///
/// Intentionally blocks for 10ms after sending to allow the block to /// Intentionally blocks for 10ms after sending to allow the block to
@@ -186,25 +137,4 @@ impl<'a> LedProxy<'a> {
// self.0.set_led_mode(&serde_json::to_string(&mode).unwrap()) // self.0.set_led_mode(&serde_json::to_string(&mode).unwrap())
Ok(()) Ok(())
} }
#[inline]
pub fn connect_notify_led(&self, send: Sender<AuraEffect>) -> zbus::fdo::Result<()> {
self.0.connect_notify_led(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
#[inline]
pub fn connect_notify_power_states(
&self,
send: Sender<LedPowerStates>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_power_states(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
} }
+3 -73
View File
@@ -19,19 +19,17 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::mpsc::Sender;
use rog_profiles::{ use rog_profiles::{
fan_curve_set::{CurveData, FanCurveSet}, fan_curve_set::{CurveData, FanCurveSet},
Profile, Profile,
}; };
use zbus::{dbus_proxy, Connection, Result}; use zbus_macros::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Profile" default_path = "/org/asuslinux/Profile"
)] )]
trait Daemon { trait Profile {
/// Get the fan-curve data for the currently active Profile /// Get the fan-curve data for the currently active Profile
fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet>; fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet>;
@@ -66,73 +64,5 @@ trait Daemon {
/// NotifyProfile signal /// NotifyProfile signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_profile(&self, profile: Profile) -> zbus::Result<()>; fn notify_profile(&self, profile: Profile) -> zbus::Result<Profile>;
}
pub struct ProfileProxy<'a>(DaemonProxy<'a>);
impl<'a> ProfileProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(ProfileProxy(DaemonProxy::new(conn)?))
}
#[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn active_profile(&self) -> zbus::Result<Profile> {
self.0.active_profile()
}
#[inline]
pub fn enabled_fan_profiles(&self) -> zbus::Result<Vec<Profile>> {
self.0.enabled_fan_profiles()
}
#[inline]
pub fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet> {
self.0.fan_curve_data(profile)
}
#[inline]
pub fn next_profile(&self) -> Result<()> {
self.0.next_profile()
}
#[inline]
pub fn profiles(&self) -> Result<Vec<Profile>> {
self.0.profiles()
}
#[inline]
pub fn set_active_profile(&self, profile: Profile) -> zbus::Result<()> {
self.0.set_active_profile(profile)
}
#[inline]
pub fn set_fan_curve_enabled(&self, profile: Profile, enabled: bool) -> zbus::Result<()> {
self.0.set_fan_curve_enabled(profile, enabled)
}
#[inline]
pub fn set_fan_curve(&self, curve: CurveData, profile: Profile) -> zbus::Result<()> {
self.0.set_fan_curve(profile, curve)
}
#[inline]
pub fn set_active_curve_to_defaults(&self) -> zbus::Result<()> {
self.0.set_active_curve_to_defaults()
}
#[inline]
pub fn connect_notify_profile(&self, send: Sender<Profile>) -> zbus::fdo::Result<()> {
self.0.connect_notify_profile(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
} }
+3 -60
View File
@@ -19,15 +19,13 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::mpsc::Sender; use zbus_macros::dbus_proxy;
use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/RogBios" default_path = "/org/asuslinux/RogBios"
)] )]
trait Daemon { trait RogBios {
/// DedicatedGraphicMode method /// DedicatedGraphicMode method
fn dedicated_graphic_mode(&self) -> zbus::Result<i16>; fn dedicated_graphic_mode(&self) -> zbus::Result<i16>;
@@ -46,60 +44,5 @@ trait Daemon {
/// NotifyPostBootSound signal /// NotifyPostBootSound signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()>; fn notify_post_boot_sound(&self, sound: bool) -> zbus::Result<()>;
}
pub struct RogBiosProxy<'a>(DaemonProxy<'a>);
impl<'a> RogBiosProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(RogBiosProxy(DaemonProxy::new(conn)?))
}
#[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn get_dedicated_gfx(&self) -> Result<i16> {
self.0.dedicated_graphic_mode()
}
#[inline]
pub fn set_dedicated_gfx(&self, on: bool) -> Result<()> {
self.0.set_dedicated_graphic_mode(on)
}
#[inline]
pub fn get_post_sound(&self) -> Result<i16> {
self.0.post_boot_sound()
}
#[inline]
pub fn set_post_sound(&self, on: bool) -> Result<()> {
self.0.set_post_boot_sound(on)
}
#[inline]
pub fn connect_notify_dedicated_graphic_mode(
&self,
send: Sender<bool>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_dedicated_graphic_mode(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
#[inline]
pub fn connect_notify_post_boot_sound(&self, send: Sender<bool>) -> zbus::fdo::Result<()> {
self.0.connect_notify_post_boot_sound(move |data| {
send.send(data)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
Ok(())
})
}
} }
+2 -21
View File
@@ -20,32 +20,13 @@
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_supported::SupportedFunctions; use rog_supported::SupportedFunctions;
use zbus::{dbus_proxy, Connection, Result}; use zbus_macros::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Supported" default_path = "/org/asuslinux/Supported"
)] )]
trait Daemon { trait Supported {
/// SupportedFunctions method /// SupportedFunctions method
fn supported_functions(&self) -> zbus::Result<SupportedFunctions>; fn supported_functions(&self) -> zbus::Result<SupportedFunctions>;
} }
pub struct SupportProxy<'a>(DaemonProxy<'a>);
impl<'a> SupportProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(SupportProxy(DaemonProxy::new(conn)?))
}
#[inline]
pub fn proxy(&self) -> &DaemonProxy<'a> {
&self.0
}
#[inline]
pub fn get_supported_functions(&self) -> Result<SupportedFunctions> {
self.0.supported_functions()
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_profiles" name = "rog_profiles"
version = "1.1.2" version = "1.1.3"
authors = ["Luke D. Jones <luke@ljones.dev>"] authors = ["Luke D. Jones <luke@ljones.dev>"]
edition = "2018" edition = "2018"
@@ -13,5 +13,5 @@ udev = "^0.6"
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
zvariant = { version = "^2.6", optional = true } zvariant = { version = "^3.0", optional = true }
zvariant_derive = { version = "^2.6", optional = true } zvariant_derive = { version = "^3.0", optional = true }
+4 -1
View File
@@ -12,6 +12,7 @@ pub enum ProfileError {
ParseFanCurveDigit(std::num::ParseIntError), ParseFanCurveDigit(std::num::ParseIntError),
/// (pwm/temp, prev, next) /// (pwm/temp, prev, next)
ParseFanCurvePrevHigher(&'static str, u8, u8), ParseFanCurvePrevHigher(&'static str, u8, u8),
ParseFanCurvePercentOver100(u8),
// Zbus(zbus::Error), // Zbus(zbus::Error),
} }
@@ -34,7 +35,9 @@ impl fmt::Display for ProfileError {
"Invalid {}, previous value {} is higher than next value {}", "Invalid {}, previous value {} is higher than next value {}",
part, prev, next part, prev, next
), ),
// Error::Zbus(detail) => write!(f, "Zbus error: {}", detail), ProfileError::ParseFanCurvePercentOver100(value) => {
write!(f, "Invalid percentage, {} is higher than 100", value)
} // Error::Zbus(detail) => write!(f, "Zbus error: {}", detail),
} }
} }
} }
+22 -5
View File
@@ -37,14 +37,24 @@ pub struct CurveData {
impl std::str::FromStr for CurveData { impl std::str::FromStr for CurveData {
type Err = ProfileError; type Err = ProfileError;
/// Parse a string to the correct values that the fan curve kernel driver expects
///
/// If the fan curve is given with percentage char '%' then the fan power values are converted
/// otherwise the expected fan power range is 0-255.
///
/// Temperature range is 0-255 in degrees C. You don't want to be setting over 100.
fn from_str(input: &str) -> Result<Self, Self::Err> { fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut temp = [0u8; 8]; let mut temp = [0u8; 8];
let mut pwm = [0u8; 8]; let mut pwm = [0u8; 8];
let mut temp_prev = 0; let mut temp_prev = 0;
let mut pwm_prev = 0; let mut pwm_prev = 0;
let mut percentages = false;
for (index, value) in input.split(',').enumerate() { for (index, value) in input.split(',').enumerate() {
for (select, num) in value.splitn(2, |c| c == 'c' || c == ':').enumerate() { for (select, num) in value.splitn(2, |c| c == 'c' || c == ':').enumerate() {
if num.contains('%') {
percentages = true;
}
let r = num.trim_matches(|c| c == 'c' || c == ':' || c == '%'); let r = num.trim_matches(|c| c == 'c' || c == ':' || c == '%');
let r = r.parse::<u8>().map_err(ProfileError::ParseFanCurveDigit)?; let r = r.parse::<u8>().map_err(ProfileError::ParseFanCurveDigit)?;
@@ -59,15 +69,22 @@ impl std::str::FromStr for CurveData {
temp_prev = r; temp_prev = r;
temp[index] = r; temp[index] = r;
} else { } else {
if pwm_prev > r { let mut p = r;
if percentages {
if r > 100 {
return Err(ProfileError::ParseFanCurvePercentOver100(r));
}
p = (p as f32 * 2.55).round() as u8;
}
if pwm_prev > p {
return Err(ProfileError::ParseFanCurvePrevHigher( return Err(ProfileError::ParseFanCurvePrevHigher(
"percentage", "percentage",
pwm_prev, pwm_prev,
r, p,
)); ));
} }
pwm_prev = r; pwm_prev = p;
pwm[index] = r; pwm[index] = p;
} }
} }
} }
@@ -205,7 +222,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(curve.fan, FanCurvePU::CPU); assert_eq!(curve.fan, FanCurvePU::CPU);
assert_eq!(curve.temp, [30, 49, 59, 69, 79, 89, 99, 109]); assert_eq!(curve.temp, [30, 49, 59, 69, 79, 89, 99, 109]);
assert_eq!(curve.pwm, [1, 2, 3, 4, 31, 49, 56, 58]); assert_eq!(curve.pwm, [3, 5, 8, 10, 79, 125, 143, 148]);
} }
#[test] #[test]
+3 -1
View File
@@ -219,7 +219,9 @@ impl FanCurveProfiles {
} }
/// Write the curves for the selected profile to the device. If the curve is /// Write the curves for the selected profile to the device. If the curve is
/// in the enabled list it will become active. /// in the enabled list it will become active. If the curve is zeroed it will be initialised
/// to a default read from the system.
// TODO: Make this return an error if curve is zeroed
pub fn write_profile_curve_to_platform( pub fn write_profile_curve_to_platform(
&mut self, &mut self,
profile: Profile, profile: Profile,
+2 -2
View File
@@ -13,5 +13,5 @@ edition = "2018"
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
zvariant = "^2.6" zvariant = "^3.0"
zvariant_derive = "^2.6" zvariant_derive = "^3.0"