Compare commits

...

13 Commits

Author SHA1 Message Date
Luke D. Jones 36bba75c50 bugfix: fix profile fan modes and creating 2021-05-26 09:24:18 +12:00
Luke Jones b2dc610c0b Merge branch 'fluke/extras' into 'main'
bugfix: fix profile cycling

See merge request asus-linux/asusctl!60
2021-05-25 09:46:26 +00:00
Luke D. Jones 42d0eb0aba bugfix: fix profile cycling 2021-05-25 21:44:01 +12:00
Luke Jones c14768182c Merge branch 'fluke/extras' into 'main'
Update config & dbus parts, cleanup deps, device power states

See merge request asus-linux/asusctl!59
2021-05-24 10:13:46 +00:00
Luke D. Jones ef7e2135bf Prep for release 2021-05-24 22:10:30 +12:00
Luke D. Jones 2b58e259de Update config & dbus parts, cleanup deps, device power states
- Add extra config options and dbus methods
- Add power state signals for anime and led
- Refactor to use channels for dbus signal handler send/recv
- Split out profiles independant parts to a rog-profiles crate
- Cleanup dependencies
- Fix some dbus Supported issues
2021-05-24 18:56:21 +12:00
Luke D. Jones ba03e8feb8 gfx: tmp informational only store of vfio/compute mode 2021-05-18 09:54:26 +12:00
Luke D. Jones 7771c6b8da gfx: Remove option for vfio/compute save 2021-05-18 09:18:36 +12:00
Luke D. Jones 04c9285ee6 add GX550L led modes 2021-05-17 12:25:16 +12:00
Luke D. Jones bf4141e4b8 Additional info in manual 2021-05-16 15:59:39 +12:00
Luke D. Jones 233315f668 Small fix to heading in manual 2021-05-16 15:24:30 +12:00
Luke D. Jones 8332fb12f1 Update documents 2021-05-16 15:17:46 +12:00
Luke D. Jones 594e69f9b7 Minor readme update 2021-05-15 22:58:42 +12:00
72 changed files with 1755 additions and 1308 deletions
+5 -1
View File
@@ -1,2 +1,6 @@
/target /target
vendor.tar.xz vendor.tar.xz
cargo-config
.idea
vendor-*
vendor_*
+24
View File
@@ -6,6 +6,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
# [3.6.1] - 2021-05-25
### Changed
- Bugfix: write correct fan modes for profiles
- Bugfix: apply created profiles
# [3.6.1] - 2021-05-25
### Changed
- Bugfix for cycling through profiles
# [3.6.0] - 2021-05-24
### Changed
- Add GX550L led modes
- Don't save compute/vfio modes. Option in config for this is removed.
- Store a temporary non-serialised option in config for if compute/vfio is active
for informational purposes only (will not apply on boot)
- Save state for LEDs enabled + sleep animation enabled
- Save state for AnimMe enabled + boot animation enabled
- Add extra config options and dbus methods
- Add power state signals for anime and led
- Refactor to use channels for dbus signal handler send/recv
- Split out profiles independant parts to a rog-profiles crate
- Cleanup dependencies
- Fix some dbus Supported issues
# [3.5.2] - 2021-05-15 # [3.5.2] - 2021-05-15
### Changed ### Changed
- Bugfix: prevent the hang on compute/integrated mode change - Bugfix: prevent the hang on compute/integrated mode change
Generated
+44 -71
View File
@@ -36,6 +36,7 @@ dependencies = [
"daemon", "daemon",
"notify-rust", "notify-rust",
"rog_dbus", "rog_dbus",
"rog_profiles",
"rog_types", "rog_types",
"serde_json", "serde_json",
] ]
@@ -44,15 +45,15 @@ dependencies = [
name = "asusctl" name = "asusctl"
version = "3.5.0" version = "3.5.0"
dependencies = [ dependencies = [
"daemon",
"gif", "gif",
"glam", "glam",
"gumdrop", "gumdrop",
"rog_anime", "rog_anime",
"rog_aura", "rog_aura",
"rog_dbus", "rog_dbus",
"rog_fan_curve",
"rog_profiles",
"rog_types", "rog_types",
"serde_json",
"tinybmp", "tinybmp",
"yansi-term", "yansi-term",
] ]
@@ -206,16 +207,16 @@ dependencies = [
[[package]] [[package]]
name = "daemon" name = "daemon"
version = "3.5.2" version = "3.6.2"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"intel-pstate",
"log", "log",
"logind-zbus", "logind-zbus",
"rog_anime", "rog_anime",
"rog_aura", "rog_aura",
"rog_dbus", "rog_dbus",
"rog_fan_curve", "rog_fan_curve",
"rog_profiles",
"rog_types", "rog_types",
"rusb", "rusb",
"serde", "serde",
@@ -226,6 +227,7 @@ dependencies = [
"udev", "udev",
"zbus", "zbus",
"zvariant", "zvariant",
"zvariant_derive",
] ]
[[package]] [[package]]
@@ -320,20 +322,6 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "err-derive"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote 1.0.9",
"rustversion",
"syn 1.0.69",
"synstructure",
]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.4.0" version = "1.4.0"
@@ -526,12 +514,12 @@ dependencies = [
[[package]] [[package]]
name = "intel-pstate" name = "intel-pstate"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0e7f68d8a6d149a5b2195ab645923c63ee35928fff58895b3c1d21541afe90c" checksum = "0dbd48c2f4886e44c137f4acb6ba3cf8df15154a2c996a65ee5e57c54a04c01f"
dependencies = [ dependencies = [
"err-derive",
"smart-default", "smart-default",
"thiserror",
] ]
[[package]] [[package]]
@@ -803,30 +791,6 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.69",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"version_check",
]
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.19" version = "0.5.19"
@@ -907,31 +871,28 @@ dependencies = [
"png_pong", "png_pong",
"serde", "serde",
"serde_derive", "serde_derive",
"zbus",
"zvariant", "zvariant",
"zvariant_derive", "zvariant_derive",
] ]
[[package]] [[package]]
name = "rog_aura" name = "rog_aura"
version = "1.0.1" version = "1.1.0"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"zbus",
"zvariant", "zvariant",
"zvariant_derive", "zvariant_derive",
] ]
[[package]] [[package]]
name = "rog_dbus" name = "rog_dbus"
version = "3.2.0" version = "3.4.0"
dependencies = [ dependencies = [
"rog_anime", "rog_anime",
"rog_aura", "rog_aura",
"rog_fan_curve", "rog_profiles",
"rog_types", "rog_types",
"serde_json",
"zbus", "zbus",
"zbus_macros", "zbus_macros",
"zvariant", "zvariant",
@@ -946,13 +907,23 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "rog_profiles"
version = "0.1.0"
dependencies = [
"intel-pstate",
"rog_fan_curve",
"serde",
"serde_derive",
"zvariant",
"zvariant_derive",
]
[[package]] [[package]]
name = "rog_types" name = "rog_types"
version = "3.2.0" version = "3.2.0"
dependencies = [ dependencies = [
"gumdrop",
"rog_aura", "rog_aura",
"rog_fan_curve",
"serde", "serde",
"serde_derive", "serde_derive",
"zvariant", "zvariant",
@@ -981,12 +952,6 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "rustversion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@@ -1115,18 +1080,6 @@ dependencies = [
"unicode-xid 0.0.4", "unicode-xid 0.0.4",
] ]
[[package]]
name = "synstructure"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.69",
"unicode-xid 0.2.1",
]
[[package]] [[package]]
name = "sysfs-class" name = "sysfs-class"
version = "0.1.3" version = "0.1.3"
@@ -1145,6 +1098,26 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.69",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.44" version = "0.1.44"
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-types", "rog-dbus", "rog-anime"] members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-types", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles"]
[profile.release] [profile.release]
lto = true lto = true
+395
View File
@@ -0,0 +1,395 @@
# asusctrl manual
`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.
## Programs Available
- `asusd`: The main system daemon. It is autostarted by a udev rule and systemd unit.
- `asusd-user`: The user level daemon. Currently will run an anime sequence, with RGB keyboard sequences soon.
- `asusctl`: The CLI for interacting with the system daemon
- `asus-notify`: A notification daemon with a user systemd unit that can be enabled.
## `asusd`
`asusd` is the main system-level daemon which will control/load/save various settings in a safe way for the user, along with exposing a *safe* dbus interface for these interactions. This section covers only the daemon plus the various configuration file options.
The functionality that `asusd` exposes is:
- graphics switching
- anime control
- led keyboard control (aura)
- charge limiting
- bios/efivar control
- profiles (fan/cpu)
each of these will be detailed in sections.
### Graphics switching
`asusd` can switch graphics modes between:
- `integrated`, uses the iGPU only and force-disables the dGPU
- `compute`, enables Nvidia without Xorg. Useful for ML/Cuda
- `hybrid`, enables Nvidia prime-offload mode
- `nvidia`, uses the Nvidia gpu only
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
Switching to/from Hybrid and Nvidia modes requires a logout only (no reboot). Switching between integrated/compute/vfio does not require a logout and is instant.
#### Required actions in distro
**Rebootless note:** You must edit `/etc/default/grub` to remove `nvidia-drm.modeset=1`
from the line `GRUB_CMDLINE_LINUX=` and then recreate your grub config. In fedora
you can do this with `sudo grub2-mkconfig -o /etc/grub2.cfg` - other distro may be
similar but with a different config location. It's possible that graphics driver updates
may change this.
This switcher conflicts with other gpu switchers like optimus-manager, suse-prime
or ubuntu-prime, system76-power, and bbswitch. If you have issues with `asusd`
always defaulting to `integrated` mode on boot then you will need to check for
stray configs blocking nvidia modules from loading in:
- `/etc/modprobe.d/`
- `/usr/lib/modprope.d/`
#### Config options
1. `"gfx_mode": "<MODE>",`: MODE can be <Integrated, Hybrid, Compute, Nvidia, vfio>
2. `"gfx_last_mode": "Nvidia",`: currently unused
3. `"gfx_managed": true,`: enable or disable graphics switching controller
4. `"gfx_vfio_enable": false,`: enable vfio switching for Nvidia GPU passthrough
5. `"gfx_save_compute_vfio": false,`: wether or not to save the vfio state (so it sticks between boots)
#### Graphics switching notes
**G-Sync note:** Some laptops are capable of using the dGPU as the sole GPU in the system which is generally to enable g-sync on the laptop display panel. This is controlled by the bios/efivar control and will be covered in that section.
**vfio note:** The vfio modules *must not* be compiled into the kernel, they need
to be separate modules. If you don't plan to use vfio mode then you can ignore this
otherwise you may need a custom built kernel.
### AniMe control
Controller for the fancy AniMe matrix display on the lid of some machines. This controller is a work in progress.
#### Config options
If you have an AniMe device a few system-level config options are enabled for you in `/etc/asusd/anime.conf`;
1. `"system": [],`: currently unused, is intended to be a default continuous sequence in future versions
2. `"boot": [],`: a sequence that plays on system boot (when asusd is loaded)
3. `"wake": [],`: a sequence that plays when waking from suspend
4. `"shutdown": [],`: a sequence that plays when shutdown begins
5. `"brightness": <FLOAT>`: global brightness control, where `<FLOAT> is 0.0-1.0
Some default examples are provided but are minimal. The full range of configuration options will be covered in another section of this manual.
### Led keyboard control
The LED controller (e.g, aura) enables setting many of the factory modes available if a laptop supports them. It also enables per-key RGB settings but this is a WIP and will likely be similar to how AniMe sequences can be created.
#### Supported laptops
Models GA401, GA502, GU502 support LED brightness change only (no RGB). However the GA401Q model can actually use three modes; static, breathe, and pulse, plus also use red to control the LED brightness intensity.
All models that have any form of LED mode control need to be enabled via the config file at `/etc/asusd/asusd-ledmodes.toml`. Unfortunately ASUS doesn't provide any easy way to find all the supported modes for all laptops (not even through Armory Crate and its various files, that progrma downloads only the required settings for the laptop it runs on) so each model must be added as needed.
#### Config options
The defaults are located at `/etc/asusd/asusd-ledmodes.toml`, and on `asusd` start it creates `/etc/asusd/aura.conf` whcih stores the per-mode settings. If you edit the defaults file you must remove `/etc/asusd/aura.conf` and restart `asusd.service` with `systemctl restart asusd`.
##### /etc/asusd/asusd-ledmodes.toml
Example:
```toml
[[led_data]]
prod_family = "ROG Zephyrus M15"
board_names = ["GU502LU"]
standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = false
per_key = false
```
1. `prod_family`: you can find this in `journalctl -b -u asusd`, or `cat /sys/class/dmi/id/product_name`. It should be copied as written. There can be multiple `led-data` groups of the same `prod_family` with differing `board_names`.
2. `board_names`: is an array of board names in this product family. Find this in the journal as above or by `cat /sys/class/dmi/id/board_name`.
3. `standard` are the factory preset modes, the names should corrospond to Armory Crate names
4. `multizone`: some keyboards have 4 zones of LED control, this enables setting a colour in each zone. The keyboard must support this or it has no effect.
5. `per_key`: enable per-key RGB effects. The keyboard must support this or it has no effect.
##### /etc/asusd/aura.conf
This file can be manually edited if desired, but the `asusctl` CLI tool, or dbus methods are the preferred method. Any manual changes to this file mean that the `asusd.service` will need to be restarted, or you need to cycle between modes to force a reload.
### Charge control
Almost all modern ASUS laptops have charging limit control now. This can be controlled in `/etc/asusd/asusd.conf`.
```json
"bat_charge_limit": 80,
```
where the number is a percentage.
### Bios control
Some options that you find in Armory Crate are available under this controller, so far there is:
- POST sound: this is the sound you here on bios boot post
- G-Sync: this controls if the dGPU (Nvidia) is the *only* GPU, making it the main GPU and disabling the iGPU
These options are not written to the config file as they are stored in efivars. The only way to change these is to use the exposed safe dbus methods, or use the `asusctl` CLI tool.
### Profiles
Profiles provide a method setting up various basic CPU and fan settings in profile blocks which can then be switched between or cycled through. The CPU controls so far are:
- Min/Max percentage of CPU frequency (Intel only for now)
- CPU turbo boost enable or disable
- Fan presets. These are 0: Normal, 1: Boost, 2: Silent.
- Fan curves, override fan-preset. AMD only.
#### Config options
Example:
```json
"toggle_profiles": [
"normal",
"boost",
"silent"
],
"power_profiles": {
"boost": {
"min_percentage": 0,
"max_percentage": 100,
"turbo": true,
"fan_preset": 1,
"fan_curve": null
},
"normal": {
"min_percentage": 0,
"max_percentage": 100,
"turbo": true,
"fan_preset": 0,
"fan_curve": null
},
"silent": {
"min_percentage": 0,
"max_percentage": 100,
"turbo": true,
"fan_preset": 2,
"fan_curve": null
}
}
```
1. `"toggle_profiles": [],`: these are the profile names that will be cycled through when using a provided next/prev dbus method.
2. `"power_profiles": {}`: all the available profiles.
#### Fan curves
**fan_curve note:** This is a WIP. Currently it relies on `acpi_call` kernel module which is ancient and hacky, not intended for this purpose. A proper kernel driver is in progress.
See [this document](https://github.com/cronosun/atrofac/blob/master/ADVANCED.md#limits) for details on the string format required, e.g, `"fan_curve": "30c:0%,40c:5%,50c:10%,60c:20%,70c:35%,80c:55%,90c:65%,100c:65%"`.
### Support controller
There is one more controller; the support controller. The sole pupose of this controller is to querie all the other controllers for information about their support level for the host laptop. Returns a json string.
## asusd-user
`asusd-user` is a usermode daemon. The intended purpose is to provide a method for users to run there own custom per-key keyboard effects and modes, AniMe sequences, and possibly their own profiles - all without overwriting the *base* system config. As such some parts of the system daemon will migrate to the user daemon over time with the expectation that the Linux system runs both.
As of now only AniMe is active in this with configuration in `~/.config/rog/`. On first run defaults are created that are intended to work as examples.
The main config is `~/.config/rog/rog-user.cfg`
#### Config options: AniMe
`~/.config/rog/rog-user.cfg` contains a setting `"active_anime": "<FILENAME>"` where `<FILENAME>` is the name of the AniMe config to use, located in the same directory and without the file postfix, e.g, `"active_anime": "anime-doom"`
An AniMe config itself is a file with contents:
```json
{
"name": "<FILENAME>",
"anime": []
}
```
`<FILENAME>` is used as a reference internally. `"anime": []` is an array of sequences (WIP).
##### "anime" array options
Each object in the array can be one of:
1. AsusAnimation
2. ImageAnimation
3. Image
4. Pause
##### AsusAnimation
`AsusAnimation` is specifically for running the gif files that Armory Crate comes with. `asusctl` includes all of these in `/usr/share/asusd/anime/asus/`
```json
"AsusAnimation": {
"file": "<FILE_PATH>",
"time": <TIME>,
"brightness": <FLOAT>
}
```
##### ImageAnimation
`ImageAnimation` can play *any* gif of any size.
```json
"ImageAnimation": {
"file": "<FILE_PATH>",
"scale": <FLOAT>,
"angle": <FLOAT>,
"translation": [
<FLOAT>,
<FLOAT>
],
"time": <TIME>,
"brightness": <FLOAT>
}
},
```
##### Image
`Image` currently requires 8bit greyscale png. It will be able to use most in future.
```json
{
"Image": {
"file": "<FILE_PATH>",
"scale": <FLOAT>,
"angle": <FLOAT>,
"translation": [
<FLOAT>,
<FLOAT>
],
"brightness": <FLOAT>
}
},
```
##### Pause
A `Pause` is handy for after an `Image` to hold the `Image` on the AniMe for a period.
```json
{
"Pause": {
"secs": <INT>,
"nanos": <INT>
}
},
```
##### Options for objects
**<FILE_PATH>**
Must be full path: `"/usr/share/asusd/anime/asus/gaming/Controller.gif"` or `/home/luke/Downloads/random.gif`.
**<FLOAT>**
A number from 0.0-1.0.
- `brightness`: If it is brightness it is combined with the system daemon global brightness
- `scale`: 1.0 is the original size with lower number shrinking, larger growing
- `angle`: Rotation angle in radians
- `translation`: Shift the image X -/+, and y -/+
**<TIME>**
Time is the length of time to run the gif for:
```json
"time": {
"Time": {
"secs": 5,
"nanos": 0
}
},
```
A cycle is how many gif loops to run:
```json
"time": {
"Cycles": 2
},
```
`Infinite` means that this gif will never end:
```json
"time": "Infinite",
```
**<INT>**
A plain non-float integer.
## asusctl
`asusctl` is a commandline interface which intends to be the main method of interacting with `asusd`. I can be used in any place a terminal app can be used.
This program will query `asusd` for the `Support` level of the laptop and show or hide options according to this support level.
Most commands are self-explanatory.
### CLI Usage and help
Commands are given by:
```
asusctl <option> <command> <command-options>
```
Help is available through:
```
asusctl --help
asusctl <command> --help
```
Some commands may have subcommands:
```
asusctl <command> <subcommand> --help
```
### Keybinds
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next**
```
asusctl led-mode -n
```
**Previous**
```
asusctl led-mode -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
can enable the user service to get basic notifications when something changes.
```
systemctl --user enable asus-notify.service
systemctl --user start asus-notify.service
```
# License & Trademarks
Mozilla Public License 2 (MPL-2.0)
---
ASUS and ROG Trademark is either a US registered trademark or trademark of ASUSTeK Computer Inc. in the United States and/or other countries.
Reference to any ASUS products, services, processes, or other information and/or use of ASUS Trademarks does not constitute or imply endorsement, sponsorship, or recommendation thereof by ASUS.
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.
---
+8 -152
View File
@@ -1,4 +1,4 @@
# ASUS NB Ctrl # `asusctl` for ASUS ROG
[![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/) [![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/)
@@ -10,21 +10,18 @@ but can also be used with non-asus laptops with reduced features.
1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes. 1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes.
2. Enable third-party apps to use the above with dbus methods 2. Enable third-party apps to use the above with dbus methods
3. To make the above as easy as possible for new users 3. To make the above as easy as possible for new users
4. Respect the users resources: be small, light, and fast
Point 3 means that the list of supported distros is very narrow - fedora is explicitly Point 3 means that the list of supported distros is very narrow - fedora is explicitly
supported, while Ubuntu and openSUSE are level-2 support. All other distros are *not* supported, while Ubuntu and openSUSE are level-2 support. All other distros are *not*
supported (while asusd might still run fine on them). For best support use fedora 32+ Workstation. supported (while asusd might still run fine on them). For best support use fedora 32+ Workstation.
Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way
a system-level daemon should.
**NOTICE:** **NOTICE:**
1. The following is *not* required for 5.11 kernel versions, as this version includes all the required patches.
2. 2021 hardware has a new keyboard prod_id and the patch is included in 5.12+
'hid-asus-rog` DKMS module from [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/). 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.
The module enables the following in kernel:
- Initialising the keyboard
- All hotkeys (FN+Key combos)
## Discord ## Discord
@@ -60,99 +57,9 @@ will probably suffer another rename once it becomes generic enough to do so.
- [X] Toggle bios setting for boot/POST sound - [X] Toggle bios setting for boot/POST sound
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync) - [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
# FUNCTIONS
## Graphics switching
`asusd` can switch graphics modes between:
- `integrated`, uses the iGPU only and force-disables the dGPU
- `hybrid`, enables Nvidia prime-offload mode
- `nvidia`, uses the Nvidia gpu only
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
**Rebootless note:** You must edit `/etc/default/grub` to remove `nvidia-drm.modeset=1`
from the line `GRUB_CMDLINE_LINUX=` and then recreate your grub config. In fedora
you can do this with `sudo grub2-mkconfig -o /etc/grub2.cfg` - other distro may be
similar but with a different config location.
This can be disabled in the config with `"manage_gfx": false,`. Additionally there
is an extra setting for laptops capable of g-sync dedicated gfx mode to enable the
graphics switching to switch on dedicated gfx for "nvidia" mode.
This switcher conflicts with other gpu switchers like optimus-manager, suse-prime
or ubuntu-prime, system76-power, and bbswitch. If you have issues with `asusd`
always defaulting to `integrated` mode on boot then you will need to check for
stray configs blocking nvidia modules from loading in:
- `/etc/modprobe.d/`
- `/usr/lib/modprope.d/`
**VFIO NOTE:** The vfio modules *must not* be compiled into the kernel, they need
to be separate modules. If you don't plan to use vfio mode then you can ignore this
otherwise you may need a custom built kernel.
To enable vfio switching you need to edit `/etc/asusd/asusd.conf` and change `"gfx_vfio_enable": false,` to true.
### Power management udev rule
If you have installed the Nvidia driver manually you will require the
`data/90-asusd-nvidia-pm.rules` udev rule to be installed in `/etc/udev/rules.d/`.
### fedora and openSUSE
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
to stop dracut including the nvidia modules in the ramdisk if you manually
installed the nvidia drivers.
```
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
and run `dracut -f` after creating it.
## KEYBOARD BACKLIGHT MODES
Models GA401, GA502, GU502 support LED brightness change only (no RGB).
If you model isn't getting the correct led modes, you can edit the file
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
- Static
- Breathe
- Strobe
- Rainbow
- Star
- Rain
- Highlight
- Laser
- Ripple
- Pulse
- Comet
- Flash
use `cat /sys/class/dmi/id/product_name` to get details about your laptop. You
must restart the `asusd.service` after editing.
# Keybinds
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next**
```
asusctl led-mode -n
```
**Previous**
```
asusctl led-mode -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
# BUILDING # BUILDING
Requirements are rust >= 1.40 installed from rustup.io if the distro provided version is too old, and `make`. Requirements are rust >= 1.47 installed from rustup.io if the distro provided version is too old, and `make`.
**Ubuntu*:** `apt install libclang-dev libudev-dev` **Ubuntu*:** `apt install libclang-dev libudev-dev`
@@ -160,9 +67,7 @@ Requirements are rust >= 1.40 installed from rustup.io if the distro provided ve
## Installing ## Installing
Packaging and auto-builds are available [here](https://build.opensuse.org/package/show/home:luke_nukem:asus/asusctl) Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/) for the latest versions of Fedora, Ubuntu, and openSUSE.
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
--- ---
@@ -188,61 +93,12 @@ can be added on request). You will need to install the alternative service from
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`. Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
# USAGE
Commands are given by:
```
asusctl <option> <command> <command-options>
```
Help is available through:
```
asusctl --help
asusctl <command> --help
```
Some commands may have subcommands:
```
asusctl <command> <subcommand> --help
```
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
can enable the user service to get basic notifications when something changes.
```
systemctl --user enable asus-notify.service
systemctl --user start asus-notify.service
```
# OTHER # OTHER
## AniMe input
You will want to look at what MeuMeu has done with [https://github.com/Meumeu/ZephyrusBling/](https://github.com/Meumeu/ZephyrusBling/)
## Supporting more laptops ## Supporting more laptops
Please file a support request. Please file a support request.
## Notes:
- If charge limit or fan modes are not working, then you may require a kernel newer than 5.6.10.
- AniMe device check is performed on start, if your device has one it will be detected.
- GA14/GA401 and GA15/GA502/GU502, You will need kernel [patches](https://lab.retarded.farm/zappel/asus-rog-zephyrus-g14/-/tree/master/kernel_patches), these are on their way to the kernel upstream.
- On fedora manually installed Nvidia driver requires a dracut config as follows:
```
# filename/etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
# License & Trademarks # License & Trademarks
Mozilla Public License 2 (MPL-2.0) Mozilla Public License 2 (MPL-2.0)
+1
View File
@@ -10,6 +10,7 @@ edition = "2018"
# serialisation # serialisation
serde_json = "^1.0" serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rog_profiles = { path = "../rog-profiles" }
rog_types = { path = "../rog-types" } rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" } daemon = { path = "../daemon" }
+32 -46
View File
@@ -1,6 +1,6 @@
use notify_rust::{Hint, Notification, NotificationHandle}; use notify_rust::{Hint, Notification, NotificationHandle};
use rog_dbus::{DbusProxies, Signals}; use rog_dbus::{DbusProxies, Signals};
use rog_types::profile::Profile; use rog_profiles::profiles::{FanLevel, Profile};
use std::error::Error; use std::error::Error;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
@@ -36,73 +36,59 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
err_count = 0; err_count = 0;
if let Ok(mut lock) = signals.gfx_vendor.lock() { if let Ok(vendor) = signals.gfx_vendor.try_recv() {
if let Some(vendor) = lock.take() { if let Some(notif) = last_gfx_notif.take() {
if let Some(notif) = last_gfx_notif.take() { notif.close();
notif.close();
}
let x = do_notif(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))?;
last_gfx_notif = Some(x);
} }
let x = do_notif(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))?;
last_gfx_notif = Some(x);
} }
if let Ok(mut lock) = signals.charge.lock() { if let Ok(limit) = signals.charge.try_recv() {
if let Some(limit) = lock.take() { if let Some(notif) = last_chrg_notif.take() {
if let Some(notif) = last_chrg_notif.take() { notif.close();
notif.close();
}
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
last_chrg_notif = Some(x);
} }
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
last_chrg_notif = Some(x);
} }
if let Ok(mut lock) = signals.profile.lock() { if let Ok(profile) = signals.profile.try_recv() {
if let Some(profile) = lock.take() { if let Some(notif) = last_profile_notif.take() {
if let Some(notif) = last_profile_notif.take() { notif.close();
notif.close();
}
if let Ok(profile) = serde_json::from_str(&profile) {
let profile: Profile = profile;
if let Ok(name) = proxies.profile().active_profile_name() {
let x = do_thermal_notif(&profile, &name)?;
last_profile_notif = Some(x);
}
}
} }
let x = do_thermal_notif(&profile)?;
last_profile_notif = Some(x);
} }
if let Ok(mut lock) = signals.led_mode.lock() { if let Ok(ledmode) = signals.led_mode.try_recv() {
if let Some(ledmode) = lock.take() { if let Some(notif) = last_led_notif.take() {
if let Some(notif) = last_led_notif.take() { notif.close();
notif.close();
}
let x = do_notif(&format!(
"Keyboard LED mode changed to {}",
ledmode.mode_name()
))?;
last_led_notif = Some(x);
} }
let x = do_notif(&format!(
"Keyboard LED mode changed to {}",
ledmode.mode_name()
))?;
last_led_notif = Some(x);
} }
} }
} }
fn do_thermal_notif(profile: &Profile, label: &str) -> Result<NotificationHandle, Box<dyn Error>> { fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {
let fan = profile.fan_preset; let fan = profile.fan_preset;
let turbo = if profile.turbo { "enabled" } else { "disabled" }; let turbo = if profile.turbo { "enabled" } else { "disabled" };
let icon = match fan { let icon = match fan {
0 => "asus_notif_yellow", FanLevel::Normal => "asus_notif_yellow",
1 => "asus_notif_red", FanLevel::Boost => "asus_notif_red",
2 => "asus_notif_green", FanLevel::Silent => "asus_notif_green",
_ => "asus_notif_red",
}; };
let x = Notification::new() let x = Notification::new()
.summary("ASUS ROG") .summary("ASUS ROG")
.body(&format!( .body(&format!(
"Thermal profile changed to {}, turbo {}", "Thermal profile changed to {}, turbo {}",
label.to_uppercase(), profile.name.to_uppercase(),
turbo turbo
)) ))
.hint(Hint::Resident(true)) .hint(Hint::Resident(true))
+2 -3
View File
@@ -7,13 +7,12 @@ 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]
# serialisation
serde_json = "^1.0"
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" }
rog_profiles = { path = "../rog-profiles" }
rog_types = { path = "../rog-types" } rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" } rog_fan_curve = { version = "^0.1", features = ["serde"] }
gumdrop = "^0.8" gumdrop = "^0.8"
yansi-term = "^0.1" yansi-term = "^0.1"
+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::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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::AuraDbusClient; use rog_dbus::RogDbusClient;
// 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::AuraDbusClient;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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, AnimeAction, Sequences}; use rog_anime::{ActionData, AnimeAction, Sequences};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() { fn main() {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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::AuraDbusClient; use rog_dbus::RogDbusClient;
// 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::AuraDbusClient;
// 74w x 36h diagonal used by the windows app // 74w x 36h diagonal used by the windows app
fn main() { fn main() {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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::AuraDbusClient; use rog_dbus::RogDbusClient;
// 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, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::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
@@ -1,5 +1,5 @@
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout}; use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
use std::collections::LinkedList; use std::collections::LinkedList;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -52,7 +52,7 @@ impl Ball {
} }
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let mut colours = KeyColourArray::new(); let mut colours = KeyColourArray::new();
+2 -2
View File
@@ -1,8 +1,8 @@
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout}; use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let layout = GX502Layout::default(); let layout = GX502Layout::default();
+2 -2
View File
@@ -1,8 +1,8 @@
use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout}; use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let mut key_colours = KeyColourArray::new(); let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default(); let layout = GX502Layout::default();
@@ -1,8 +1,8 @@
use rog_aura::{Key, KeyColourArray}; use rog_aura::{Key, KeyColourArray};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let mut key_colours = KeyColourArray::new(); let mut key_colours = KeyColourArray::new();
+2 -2
View File
@@ -1,8 +1,8 @@
use rog_aura::{GX502Layout, KeyColourArray, KeyLayout}; use rog_aura::{GX502Layout, KeyColourArray, KeyLayout};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let mut key_colours = KeyColourArray::new(); let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default(); let layout = GX502Layout::default();
+48 -55
View File
@@ -1,15 +1,17 @@
mod anime_cli; mod anime_cli;
mod aura_cli; mod aura_cli;
mod profiles_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use anime_cli::{AnimeActions, AnimeCommand}; use anime_cli::{AnimeActions, AnimeCommand};
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use profiles_cli::ProfileCommand;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
use rog_aura::{self, AuraEffect}; use rog_aura::{self, AuraEffect};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
use rog_profiles::profiles::Profile;
use rog_types::{ use rog_types::{
gfx_vendors::GfxVendors, gfx_vendors::GfxVendors,
profile::{FanLevel, ProfileCommand, ProfileEvent},
supported::{ supported::{
FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions, FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
SupportedFunctions, SupportedFunctions,
@@ -29,11 +31,6 @@ struct CliStart {
show_supported: bool, show_supported: bool,
#[options(meta = "", help = "<off, low, med, high>")] #[options(meta = "", help = "<off, low, med, high>")]
kbd_bright: Option<LedBrightness>, kbd_bright: Option<LedBrightness>,
#[options(
meta = "",
help = "<silent, normal, boost>, set fan mode independent of profile"
)]
fan_mode: Option<FanLevel>,
#[options(meta = "", help = "<20-100>")] #[options(meta = "", help = "<20-100>")]
chg_limit: Option<u8>, chg_limit: Option<u8>,
#[options(command)] #[options(command)]
@@ -132,10 +129,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
let (dbus, _) = AuraDbusClient::new()?; let (dbus, _) = RogDbusClient::new()?;
let supported_tmp = dbus.proxies().supported().get_supported_functions()?; let supported = dbus.proxies().supported().get_supported_functions()?;
let supported = serde_json::from_str::<SupportedFunctions>(&supported_tmp)?;
if parsed.help { if parsed.help {
print_supported_help(&supported, &parsed); print_supported_help(&supported, &parsed);
@@ -147,7 +143,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" asusctl v{}", env!("CARGO_PKG_VERSION")); println!(" asusctl v{}", env!("CARGO_PKG_VERSION"));
println!(" rog-dbus v{}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!("rog-types v{}", rog_types::VERSION); println!("rog-types v{}", rog_types::VERSION);
println!(" daemon v{}", daemon::VERSION);
return Ok(()); return Ok(());
} }
@@ -203,10 +198,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
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 => {
if (!parsed.show_supported if (!parsed.show_supported && parsed.kbd_bright.is_none() && parsed.chg_limit.is_none())
&& parsed.kbd_bright.is_none()
&& parsed.fan_mode.is_none()
&& parsed.chg_limit.is_none())
|| parsed.help || parsed.help
{ {
println!("{}", CliStart::usage()); println!("{}", CliStart::usage());
@@ -231,15 +223,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if parsed.show_supported { if parsed.show_supported {
let dat = dbus.proxies().supported().get_supported_functions()?; let dat = dbus.proxies().supported().get_supported_functions()?;
println!("Supported laptop functions:\n{}", dat); println!("Supported laptop functions:\n{:?}", dat);
} }
if let Some(fan_level) = parsed.fan_mode {
dbus.proxies().profile().write_fan_mode(fan_level.into())?;
}
if let Some(chg_limit) = parsed.chg_limit { if let Some(chg_limit) = parsed.chg_limit {
dbus.proxies().charge().write_limit(chg_limit)?; dbus.proxies().charge().write_limit(chg_limit)?;
} }
Ok(()) Ok(())
} }
@@ -269,7 +259,7 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CliStart) {
{ {
return false; return false;
} }
if line.contains("led-mode") && supported.keyboard_led.stock_led_modes.is_none() { if line.contains("led-mode") && !supported.keyboard_led.stock_led_modes.is_empty() {
return false; return false;
} }
if line.contains("bios") if line.contains("bios")
@@ -295,7 +285,7 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CliStart) {
} }
fn do_gfx( fn do_gfx(
dbus: &AuraDbusClient, dbus: &RogDbusClient,
supported: &RogBiosSupportedFunctions, supported: &RogBiosSupportedFunctions,
command: GraphicsCommand, command: GraphicsCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -341,7 +331,7 @@ fn do_gfx(
} }
fn handle_led_mode( fn handle_led_mode(
dbus: &AuraDbusClient, dbus: &RogDbusClient,
supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
mode: &LedModeCommand, mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -363,11 +353,9 @@ fn handle_led_mode(
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(); .collect();
for command in commands.iter().filter(|command| { for command in commands.iter().filter(|command| {
if let Some(modes) = supported.stock_led_modes.as_ref() { for mode in &supported.stock_led_modes {
for mode in modes { if command.contains(<&str>::from(mode)) {
if command.contains(&(<&str>::from(mode)).to_lowercase()) { return true;
return true;
}
} }
} }
if supported.multizone_led_mode { if supported.multizone_led_mode {
@@ -421,7 +409,7 @@ fn handle_led_mode(
} }
fn handle_profile( fn handle_profile(
dbus: &AuraDbusClient, dbus: &RogDbusClient,
supported: &FanCpuSupportedFunctions, supported: &FanCpuSupportedFunctions,
cmd: &ProfileCommand, cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -476,57 +464,62 @@ fn handle_profile(
if cmd.active_name { if cmd.active_name {
println!( println!(
"Active profile: {:?}", "Active profile: {:?}",
dbus.proxies().profile().active_profile_name()? dbus.proxies().profile().active_name()?
); );
} }
if cmd.active_data { if cmd.active_data {
println!("Active profile:"); println!("Active profile:");
for s in dbus.proxies().profile().active_profile_data()?.lines() { println!("{:?}", dbus.proxies().profile().active_data()?);
println!("{}", s);
}
} }
if cmd.profiles_data { if cmd.profiles_data {
println!("Profiles:"); println!("Profiles:");
for s in dbus.proxies().profile().all_profile_data()?.lines() { for s in dbus.proxies().profile().all_profile_data()? {
println!("{}", s); println!("{:?}", s);
} }
} }
// This must come before the next block of actions so that changing a specific let mut set_profile = false;
// profile can be done let mut profile;
if cmd.profile.is_some() { if cmd.create {
dbus.proxies() profile = Profile::default();
.profile() set_profile = true;
.write_command(&ProfileEvent::Cli(cmd.clone()))?; } else {
return Ok(()); profile = dbus.proxies().profile().active_data()?;
} }
if let Some(turbo) = cmd.turbo { if let Some(turbo) = cmd.turbo {
dbus.proxies().profile().set_turbo(turbo)?; set_profile = true;
profile.turbo = turbo;
} }
if let Some(min) = cmd.min_percentage { if let Some(min) = cmd.min_percentage {
dbus.proxies().profile().set_min_frequency(min)?; set_profile = true;
profile.min_percentage = min;
} }
if let Some(max) = cmd.max_percentage { if let Some(max) = cmd.max_percentage {
dbus.proxies().profile().set_max_frequency(max)?; set_profile = true;
profile.max_percentage = max;
} }
if let Some(preset) = cmd.fan_preset {
if let Some(ref preset) = cmd.fan_preset { set_profile = true;
dbus.proxies().profile().set_fan_preset(preset.into())?; profile.fan_preset = preset;
} }
if let Some(ref curve) = cmd.curve { if let Some(ref curve) = cmd.curve {
let s = curve.as_config_string(); set_profile = true;
dbus.proxies().profile().set_fan_curve(&s)?; profile.fan_curve = curve.as_config_string();
}
if let Some(ref name) = cmd.profile {
set_profile = true;
profile.name = name.clone();
}
if set_profile {
dbus.proxies().profile().new_or_modify(&profile)?;
} }
Ok(()) Ok(())
} }
fn handle_bios_option( fn handle_bios_option(
dbus: &AuraDbusClient, dbus: &RogDbusClient,
supported: &RogBiosSupportedFunctions, supported: &RogBiosSupportedFunctions,
cmd: &BiosCommand, cmd: &BiosCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -545,8 +538,8 @@ 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);
} }
+53
View File
@@ -0,0 +1,53 @@
use gumdrop::Options;
use rog_fan_curve::{Curve, Fan};
use rog_profiles::profiles::FanLevel;
#[derive(Debug, Clone, Options)]
pub struct ProfileCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "toggle to next profile in list")]
pub next: bool,
#[options(help = "create the profile if it doesn't exist")]
pub create: bool,
#[options(meta = "", help = "remove a profile by name")]
pub remove: Option<String>,
#[options(help = "list available profiles")]
pub list: bool,
#[options(help = "get active profile name")]
pub active_name: bool,
#[options(help = "get active profile data")]
pub active_data: bool,
#[options(help = "get all profile data")]
pub profiles_data: bool,
// Options for profile
#[options(meta = "", help = "enable or disable cpu turbo")]
pub turbo: Option<bool>,
#[options(meta = "", help = "set min cpu scaling (intel)")]
pub min_percentage: Option<u8>,
#[options(meta = "", help = "set max cpu scaling (intel)")]
pub max_percentage: Option<u8>,
#[options(meta = "", help = "<silent, normal, boost>")]
pub fan_preset: Option<FanLevel>,
#[options(
meta = "",
parse(try_from_str = "parse_fan_curve"),
help = "set fan curve"
)]
pub curve: Option<Curve>,
#[options(free)]
pub profile: Option<String>,
}
fn parse_fan_curve(data: &str) -> Result<Curve, String> {
let curve = Curve::from_config_str(data)?;
if let Err(err) = curve.check_safety(Fan::Cpu) {
return Err(format!("Unsafe curve {:?}", err));
}
if let Err(err) = curve.check_safety(Fan::Gpu) {
return Err(format!("Unsafe curve {:?}", err));
}
Ok(curve)
}
+22 -10
View File
@@ -1,5 +1,5 @@
use rog_anime::{ActionData, AnimTime, AnimeAction, Sequences, Vec2}; use rog_anime::{ActionData, AnimTime, AnimeAction, Sequences, Vec2};
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
//use crate::dbus::DbusEvents; //use crate::dbus::DbusEvents;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
@@ -28,14 +28,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: AuraDbusClient<'a>, client: RogDbusClient<'a>,
do_early_return: &'a AtomicBool, do_early_return: &'a AtomicBool,
} }
impl<'a> CtrlAnimeInner<'static> { impl<'a> CtrlAnimeInner<'static> {
pub fn new( pub fn new(
sequences: Sequences, sequences: Sequences,
client: AuraDbusClient<'static>, client: RogDbusClient<'static>,
do_early_return: &'static AtomicBool, do_early_return: &'static AtomicBool,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
@@ -112,7 +112,7 @@ impl<'a> CtrlAnimeInner<'static> {
pub struct CtrlAnime<'a> { pub struct CtrlAnime<'a> {
config: Arc<Mutex<UserAnimeConfig>>, config: Arc<Mutex<UserAnimeConfig>>,
client: AuraDbusClient<'a>, client: RogDbusClient<'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: &'a AtomicBool, inner_early_return: &'a AtomicBool,
@@ -122,13 +122,13 @@ 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: AuraDbusClient<'static>, client: RogDbusClient<'static>,
inner_early_return: &'static AtomicBool, inner_early_return: &'static AtomicBool,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(CtrlAnime { Ok(CtrlAnime {
config, config,
inner,
client, client,
inner,
inner_early_return, inner_early_return,
}) })
} }
@@ -180,7 +180,10 @@ impl CtrlAnime<'static> {
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() { if let Ok(mut controller) = self.inner.lock() {
controller.sequences.insert(index as usize, &action)?; controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
} }
config.anime.push(action); config.anime.push(action);
config.write()?; config.write()?;
@@ -227,7 +230,10 @@ impl CtrlAnime<'static> {
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() { if let Ok(mut controller) = self.inner.lock() {
controller.sequences.insert(index as usize, &action)?; controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
} }
config.anime.push(action); config.anime.push(action);
config.write()?; config.write()?;
@@ -265,7 +271,10 @@ impl CtrlAnime<'static> {
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() { if let Ok(mut controller) = self.inner.lock() {
controller.sequences.insert(index as usize, &action)?; controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
} }
config.anime.push(action); config.anime.push(action);
config.write()?; config.write()?;
@@ -287,7 +296,10 @@ impl CtrlAnime<'static> {
self.inner_early_return.store(true, Ordering::SeqCst); self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() { if let Ok(mut controller) = self.inner.lock() {
controller.sequences.insert(index as usize, &action)?; controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
} }
config.anime.push(action); config.anime.push(action);
config.write()?; config.write()?;
+7 -8
View File
@@ -1,5 +1,4 @@
use rog_dbus::AuraDbusClient; use rog_dbus::RogDbusClient;
use rog_types::supported::SupportedFunctions;
use rog_user::{ use rog_user::{
ctrl_anime::{CtrlAnime, CtrlAnimeInner}, ctrl_anime::{CtrlAnime, CtrlAnimeInner},
user_config::*, user_config::*,
@@ -16,13 +15,13 @@ use std::sync::atomic::AtomicBool;
static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false); static ANIME_INNER_EARLY_RETURN: AtomicBool = AtomicBool::new(false);
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("user daemon v{}", rog_user::VERSION); println!(" user daemon v{}", rog_user::VERSION);
println!(" rog-anime v{}", rog_anime::VERSION); println!(" rog-anime v{}", rog_anime::VERSION);
println!(" rog-dbus v{}", rog_dbus::VERSION); println!(" rog-dbus v{}", rog_dbus::VERSION);
println!(" rog-types v{}", rog_types::VERSION);
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::new().unwrap();
let supported = client.proxies().supported().get_supported_functions()?; let supported = client.proxies().supported().get_supported_functions()?;
let supported = serde_json::from_str::<SupportedFunctions>(&&supported).unwrap();
let mut config = UserConfig::new(); let mut config = UserConfig::new();
config.load_config()?; config.load_config()?;
@@ -47,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
&ANIME_INNER_EARLY_RETURN, &ANIME_INNER_EARLY_RETURN,
)?)); )?));
// Need new client object for dbus control part // Need new client object for dbus control part
let (client, _) = AuraDbusClient::new().unwrap(); let (client, _) = RogDbusClient::new().unwrap();
let anime_control = CtrlAnime::new( let anime_control = CtrlAnime::new(
anime_config, anime_config,
inner.clone(), inner.clone(),
+1 -1
View File
@@ -8,4 +8,4 @@ pub mod zbus_anime;
pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
+4 -1
View File
@@ -75,7 +75,10 @@ impl UserAnimeConfig {
if let Ok(read_len) = file.read_to_string(&mut buf) { if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 { if read_len == 0 {
let default = UserAnimeConfig { name, ..Default::default() }; let default = UserAnimeConfig {
name,
..Default::default()
};
let json = serde_json::to_string_pretty(&default).unwrap(); let json = serde_json::to_string_pretty(&default).unwrap();
file.write_all(json.as_bytes())?; file.write_all(json.as_bytes())?;
return Ok(default); return Ok(default);
+1
View File
@@ -18,6 +18,7 @@
//! * [`zbus::fdo::PropertiesProxy`] //! * [`zbus::fdo::PropertiesProxy`]
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
#![allow(clippy::too_many_arguments)]
use zbus::dbus_proxy; use zbus::dbus_proxy;
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "daemon" name = "daemon"
version = "3.5.2" version = "3.6.2"
license = "MPL-2.0" license = "MPL-2.0"
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
@@ -21,6 +21,7 @@ path = "src/daemon.rs"
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_types = { path = "../rog-types" } rog_types = { path = "../rog-types" }
rog_profiles = { path = "../rog-profiles" }
rog_dbus = { path = "../rog-dbus" } rog_dbus = { path = "../rog-dbus" }
rusb = "^0.8" rusb = "^0.8"
udev = "^0.6" udev = "^0.6"
@@ -31,6 +32,7 @@ env_logger = "^0.8"
zbus = "^1.9.1" zbus = "^1.9.1"
zvariant = "^2.6" zvariant = "^2.6"
zvariant_derive = { version = "^2.6" }
logind-zbus = "^0.7.1" logind-zbus = "^0.7.1"
# serialisation # serialisation
@@ -42,5 +44,3 @@ toml = "^0.5"
# Device control # Device control
sysfs-class = "^0.1.2" # used for backlight control and baord ID sysfs-class = "^0.1.2" # used for backlight control and baord ID
rog_fan_curve = { version = "0.1", features = ["serde"] } rog_fan_curve = { version = "0.1", features = ["serde"] }
# cpu power management
intel-pstate = "^0.2"
+45 -14
View File
@@ -1,5 +1,6 @@
use log::{error, info, warn}; use log::{error, info, warn};
use rog_types::{gfx_vendors::GfxVendors, profile::Profile}; use rog_profiles::profiles::{FanLevel, Profile};
use rog_types::gfx_vendors::GfxVendors;
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};
@@ -14,10 +15,11 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Config { pub struct Config {
pub gfx_mode: GfxVendors, pub gfx_mode: GfxVendors,
pub gfx_last_mode: GfxVendors, /// Only for informational purposes.
#[serde(skip)]
pub gfx_tmp_mode: Option<GfxVendors>,
pub gfx_managed: bool, pub gfx_managed: bool,
pub gfx_vfio_enable: bool, pub gfx_vfio_enable: bool,
pub gfx_save_compute_vfio: bool,
pub active_profile: String, pub active_profile: String,
pub toggle_profiles: Vec<String>, pub toggle_profiles: Vec<String>,
#[serde(skip)] #[serde(skip)]
@@ -29,16 +31,45 @@ pub struct Config {
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
let mut pwr = BTreeMap::new(); let mut pwr = BTreeMap::new();
pwr.insert("normal".into(), Profile::new(0, 100, true, 0, None)); pwr.insert(
pwr.insert("boost".into(), Profile::new(0, 100, true, 1, None)); "normal".into(),
pwr.insert("silent".into(), Profile::new(0, 100, true, 2, None)); Profile::new(
"normal".into(),
0,
100,
true,
FanLevel::Normal,
"".to_string(),
),
);
pwr.insert(
"boost".into(),
Profile::new(
"boost".into(),
0,
100,
true,
FanLevel::Boost,
"".to_string(),
),
);
pwr.insert(
"silent".into(),
Profile::new(
"silent".into(),
0,
100,
true,
FanLevel::Silent,
"".to_string(),
),
);
Config { Config {
gfx_mode: GfxVendors::Hybrid, gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid, gfx_tmp_mode: None,
gfx_managed: true, gfx_managed: true,
gfx_vfio_enable: false, gfx_vfio_enable: false,
gfx_save_compute_vfio: true,
active_profile: "normal".into(), active_profile: "normal".into(),
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()], toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0, curr_fan_mode: 0,
@@ -56,12 +87,7 @@ impl Config {
.write(true) .write(true)
.create(true) .create(true)
.open(&CONFIG_PATH) .open(&CONFIG_PATH)
.unwrap_or_else(|_| { .unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here
panic!(
"The file {} or directory /etc/asusd/ is missing",
CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new(); let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) { if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 { if read_len == 0 {
@@ -69,6 +95,11 @@ impl Config {
} 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::<ConfigV352>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV341>(&buf) { } else if let Ok(data) = serde_json::from_str::<ConfigV341>(&buf) {
let config = data.into_current(); let config = data.into_current();
config.write(); config.write();
+36
View File
@@ -41,6 +41,31 @@ impl AnimeConfigV341 {
vec![] vec![]
}, },
brightness: 1.0, brightness: 1.0,
awake_enabled: true,
boot_anim_enabled: true,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AnimeConfigV352 {
pub system: Vec<AnimeAction>,
pub boot: Vec<AnimeAction>,
pub wake: Vec<AnimeAction>,
pub shutdown: Vec<AnimeAction>,
pub brightness: f32,
}
impl AnimeConfigV352 {
pub(crate) fn into_current(self) -> AnimeConfig {
AnimeConfig {
system: self.system,
boot: self.boot,
wake: self.wake,
shutdown: self.shutdown,
brightness: 1.0,
awake_enabled: true,
boot_anim_enabled: true,
} }
} }
} }
@@ -90,6 +115,8 @@ pub struct AnimeConfig {
pub wake: Vec<AnimeAction>, pub wake: Vec<AnimeAction>,
pub shutdown: Vec<AnimeAction>, pub shutdown: Vec<AnimeAction>,
pub brightness: f32, pub brightness: f32,
pub awake_enabled: bool,
pub boot_anim_enabled: bool,
} }
impl Default for AnimeConfig { impl Default for AnimeConfig {
@@ -100,6 +127,8 @@ impl Default for AnimeConfig {
wake: Vec::new(), wake: Vec::new(),
shutdown: Vec::new(), shutdown: Vec::new(),
brightness: 1.0, brightness: 1.0,
awake_enabled: true,
boot_anim_enabled: true,
} }
} }
} }
@@ -130,6 +159,11 @@ impl AnimeConfig {
config.write(); config.write();
info!("Updated config version to: {}", VERSION); info!("Updated config version to: {}", VERSION);
return config; return config;
} else if let Ok(data) = serde_json::from_str::<AnimeConfigV352>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} }
warn!("Could not deserialise {}", ANIME_CONFIG_PATH); warn!("Could not deserialise {}", ANIME_CONFIG_PATH);
panic!("Please remove {} then restart asusd", ANIME_CONFIG_PATH); panic!("Please remove {} then restart asusd", ANIME_CONFIG_PATH);
@@ -167,6 +201,8 @@ impl AnimeConfig {
time: AnimTime::Infinite, time: AnimTime::Infinite,
}], }],
brightness: 1.0, brightness: 1.0,
awake_enabled: true,
boot_anim_enabled: true,
}; };
// Should be okay to unwrap this as is since it is a Default // Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string_pretty(&config).unwrap(); let json = serde_json::to_string_pretty(&config).unwrap();
+32
View File
@@ -23,6 +23,29 @@ impl AuraConfigV320 {
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,
sleep_anim_enabled: true,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraConfigV352 {
pub brightness: LedBrightness,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl AuraConfigV352 {
pub(crate) fn into_current(self) -> AuraConfig {
AuraConfig {
brightness: self.brightness,
current_mode: self.current_mode,
builtins: self.builtins,
multizone: self.multizone,
awake_enabled: true,
sleep_anim_enabled: true,
} }
} }
} }
@@ -33,6 +56,8 @@ 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 sleep_anim_enabled: bool,
} }
impl Default for AuraConfig { impl Default for AuraConfig {
@@ -42,6 +67,8 @@ 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,
sleep_anim_enabled: true,
} }
} }
} }
@@ -72,6 +99,11 @@ impl AuraConfig {
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) {
let config = data.into_current();
config.write();
info!("Updated AuraConfig version");
return config;
} }
warn!("Could not deserialise {}", AURA_CONFIG_PATH); warn!("Could not deserialise {}", AURA_CONFIG_PATH);
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH); panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
+76 -14
View File
@@ -1,11 +1,13 @@
use rog_types::{gfx_vendors::GfxVendors, profile::Profile}; use rog_fan_curve::Curve;
use rog_profiles::profiles::Profile;
use rog_types::gfx_vendors::GfxVendors;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::config::Config; use crate::config::Config;
/// for parsing old v3.1.7 config /// for parsing old v3.1.7 config
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub(crate) struct ConfigV317 { pub(crate) struct ConfigV317 {
pub gfx_mode: GfxVendors, pub gfx_mode: GfxVendors,
pub gfx_managed: bool, pub gfx_managed: bool,
@@ -18,22 +20,21 @@ pub(crate) struct ConfigV317 {
pub kbd_backlight_mode: u8, pub kbd_backlight_mode: u8,
#[serde(skip)] #[serde(skip)]
pub kbd_backlight_modes: Option<bool>, pub kbd_backlight_modes: Option<bool>,
pub power_profiles: BTreeMap<String, Profile>, pub power_profiles: BTreeMap<String, ProfileV317>,
} }
impl ConfigV317 { impl ConfigV317 {
pub(crate) fn into_current(self) -> Config { pub(crate) fn into_current(self) -> Config {
Config { Config {
gfx_mode: GfxVendors::Hybrid, gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid, gfx_tmp_mode: None,
gfx_managed: self.gfx_managed, gfx_managed: self.gfx_managed,
gfx_vfio_enable: false, gfx_vfio_enable: false,
gfx_save_compute_vfio: false,
active_profile: self.active_profile, active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode, curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles, power_profiles: ProfileV317::transform_map(self.power_profiles),
} }
} }
} }
@@ -47,22 +48,21 @@ pub struct ConfigV324 {
#[serde(skip)] #[serde(skip)]
pub curr_fan_mode: u8, pub curr_fan_mode: u8,
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, Profile>, pub power_profiles: BTreeMap<String, ProfileV317>,
} }
impl ConfigV324 { impl ConfigV324 {
pub(crate) fn into_current(self) -> Config { pub(crate) fn into_current(self) -> Config {
Config { Config {
gfx_mode: GfxVendors::Hybrid, gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid, gfx_tmp_mode: None,
gfx_managed: self.gfx_managed, gfx_managed: self.gfx_managed,
gfx_vfio_enable: false, gfx_vfio_enable: false,
gfx_save_compute_vfio: false,
active_profile: self.active_profile, active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode, curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles, power_profiles: ProfileV317::transform_map(self.power_profiles),
} }
} }
} }
@@ -77,22 +77,84 @@ pub struct ConfigV341 {
#[serde(skip)] #[serde(skip)]
pub curr_fan_mode: u8, pub curr_fan_mode: u8,
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, Profile>, pub power_profiles: BTreeMap<String, ProfileV317>,
} }
impl ConfigV341 { impl ConfigV341 {
pub(crate) fn into_current(self) -> Config { pub(crate) fn into_current(self) -> Config {
Config { Config {
gfx_mode: GfxVendors::Hybrid, gfx_mode: GfxVendors::Hybrid,
gfx_last_mode: GfxVendors::Hybrid, gfx_tmp_mode: None,
gfx_managed: self.gfx_managed, gfx_managed: self.gfx_managed,
gfx_vfio_enable: false, gfx_vfio_enable: false,
gfx_save_compute_vfio: false,
active_profile: self.active_profile, active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles, toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode, curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit, bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles, power_profiles: ProfileV317::transform_map(self.power_profiles),
} }
} }
} }
#[derive(Deserialize, Serialize)]
pub struct ConfigV352 {
pub gfx_mode: GfxVendors,
pub gfx_last_mode: GfxVendors,
pub gfx_managed: bool,
pub gfx_vfio_enable: bool,
pub gfx_save_compute_vfio: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, ProfileV317>,
}
impl ConfigV352 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_tmp_mode: None,
gfx_managed: self.gfx_managed,
gfx_vfio_enable: false,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
power_profiles: ProfileV317::transform_map(self.power_profiles),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProfileV317 {
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: u8,
pub fan_curve: Option<Curve>,
}
impl ProfileV317 {
fn into_current(self, name: String) -> Profile {
Profile {
name,
min_percentage: self.min_percentage,
max_percentage: self.max_percentage,
turbo: self.turbo,
fan_preset: self.fan_preset.into(),
fan_curve: self
.fan_curve
.map_or_else(|| "".to_string(), |c| c.as_config_string()),
}
}
fn transform_map(map: BTreeMap<String, ProfileV317>) -> BTreeMap<String, Profile> {
let mut new_map = BTreeMap::new();
map.iter().for_each(|(k, v)| {
new_map.insert(k.to_string(), v.clone().into_current(k.to_string()));
});
new_map
}
}
+45 -3
View File
@@ -5,7 +5,7 @@ use rog_anime::{
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
VENDOR_ID, VENDOR_ID,
}, },
ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN, ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, AnimePowerStates, ANIME_DATA_LEN,
}; };
use rog_types::supported::AnimeSupportedFunctions; use rog_types::supported::AnimeSupportedFunctions;
use rusb::{Device, DeviceHandle}; use rusb::{Device, DeviceHandle};
@@ -333,6 +333,11 @@ pub struct CtrlAnimeReloader(pub Arc<Mutex<CtrlAnime>>);
impl crate::Reloadable for CtrlAnimeReloader { impl crate::Reloadable for CtrlAnimeReloader {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
if let Ok(lock) = self.0.try_lock() { if let Ok(lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_on(lock.config.awake_enabled));
lock.write_bytes(&pkt_for_apply());
lock.write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled));
lock.write_bytes(&pkt_for_apply());
let action = lock.cache.boot.clone(); let action = lock.cache.boot.clone();
CtrlAnime::run_thread(self.0.clone(), action, true); CtrlAnime::run_thread(self.0.clone(), action, true);
} }
@@ -392,8 +397,17 @@ impl CtrlAnimeZbus {
fn set_on_off(&self, status: bool) { fn set_on_off(&self, status: bool) {
'outer: loop { 'outer: loop {
if let Ok(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.write();
let states = AnimePowerStates {
enabled: lock.config.awake_enabled,
boot_anim_enabled: lock.config.boot_anim_enabled,
};
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
break 'outer; break 'outer;
} }
} }
@@ -401,9 +415,18 @@ impl CtrlAnimeZbus {
fn set_boot_on_off(&self, on: bool) { fn set_boot_on_off(&self, on: bool) {
'outer: loop { 'outer: loop {
if let Ok(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));
lock.write_bytes(&pkt_for_apply()); lock.write_bytes(&pkt_for_apply());
lock.config.boot_anim_enabled = on;
lock.config.write();
let states = AnimePowerStates {
enabled: lock.config.awake_enabled,
boot_anim_enabled: lock.config.boot_anim_enabled,
};
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
break 'outer; break 'outer;
} }
} }
@@ -422,4 +445,23 @@ impl CtrlAnimeZbus {
} }
} }
} }
#[dbus_interface(property)]
fn awake_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.awake_enabled;
}
true
}
#[dbus_interface(property)]
fn boot_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.boot_anim_enabled;
}
true
}
#[dbus_interface(signal)]
fn notify_power_states(&self, data: &AnimePowerStates) -> zbus::Result<()>;
} }
+13 -12
View File
@@ -111,7 +111,6 @@ impl CtrlGraphics {
/// Save the selected `Vendor` mode to config /// Save the selected `Vendor` mode to config
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) { fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
if let Ok(mut config) = config.lock() { if let Ok(mut config) = config.lock() {
config.gfx_last_mode = config.gfx_mode;
config.gfx_mode = vendor; config.gfx_mode = vendor;
config.write(); config.write();
} }
@@ -120,6 +119,9 @@ impl CtrlGraphics {
/// Associated method to get which vendor mode is set /// Associated method to get which vendor mode is set
pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> { pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
if let Ok(config) = self.config.lock() { if let Ok(config) = self.config.lock() {
if let Some(mode) = config.gfx_tmp_mode {
return Ok(mode);
}
return Ok(config.gfx_mode); return Ok(config.gfx_mode);
} }
// TODO: Error here // TODO: Error here
@@ -511,7 +513,11 @@ impl CtrlGraphics {
Self::do_display_manager_action("stop")?; Self::do_display_manager_action("stop")?;
Self::wait_display_manager_state("inactive")?; Self::wait_display_manager_state("inactive")?;
let vfio_enable = if let Ok(config) = config.lock() { let vfio_enable = if let Ok(mut config) = config.try_lock() {
// Since we have a lock, reset tmp to none. This thread should only ever run
// for Integrated, Hybrid, or Nvidia. Tmp is also only for informational
config.gfx_tmp_mode = None;
//
config.gfx_vfio_enable config.gfx_vfio_enable
} else { } else {
false false
@@ -582,7 +588,7 @@ impl CtrlGraphics {
} }
} }
let vfio_enable = if let Ok(config) = self.config.lock() { let vfio_enable = if let Ok(config) = self.config.try_lock() {
config.gfx_vfio_enable config.gfx_vfio_enable
} else { } else {
false false
@@ -607,15 +613,10 @@ impl CtrlGraphics {
let bus = self.bus.clone(); let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?; Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) { if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) {
loop { if let Ok(mut config) = self.config.try_lock() {
if let Ok(config) = self.config.try_lock() { config.gfx_tmp_mode = Some(vendor);
if config.gfx_save_compute_vfio { };
Self::save_gfx_mode(vendor, self.config.clone());
}
return Ok(action_required);
}
}
} }
} }
// TODO: undo if failed? Save last mode, catch errors... // TODO: undo if failed? Save last mode, catch errors...
+3 -3
View File
@@ -1,7 +1,7 @@
use ::zbus::dbus_interface;
use log::{error, info, warn};
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use ::zbus::{dbus_interface};
use zvariant::ObjectPath; use zvariant::ObjectPath;
use log::{error, warn, info};
use crate::ZbusAdd; use crate::ZbusAdd;
@@ -53,4 +53,4 @@ impl ZbusAdd for CtrlGraphics {
}) })
.ok(); .ok();
} }
} }
@@ -6,9 +6,12 @@ use crate::{
error::RogError, error::RogError,
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
}; };
use log::{error, info, warn}; use log::{info, warn};
use rog_aura::{ use rog_aura::{
usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON}, usb::{
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_types::supported::LedSupportedFunctions; use rog_types::supported::LedSupportedFunctions;
@@ -17,8 +20,6 @@ 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 zbus::dbus_interface;
use zvariant::ObjectPath;
use crate::GetSupported; use crate::GetSupported;
@@ -30,11 +31,7 @@ impl GetSupported for CtrlKbdLed {
let multizone_led_mode = false; let multizone_led_mode = false;
let per_key_led_mode = false; let per_key_led_mode = false;
let laptop = LaptopLedData::get_data(); let laptop = LaptopLedData::get_data();
let stock_led_modes = if laptop.standard.is_empty() { let stock_led_modes = laptop.standard;
None
} else {
Some(laptop.standard)
};
LedSupportedFunctions { LedSupportedFunctions {
brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(),
@@ -46,11 +43,11 @@ impl GetSupported for CtrlKbdLed {
} }
pub struct CtrlKbdLed { pub struct CtrlKbdLed {
led_node: Option<String>, pub led_node: Option<String>,
pub bright_node: String, pub bright_node: String,
supported_modes: LaptopLedData, pub supported_modes: LaptopLedData,
flip_effect_write: bool, pub flip_effect_write: bool,
config: AuraConfig, pub config: AuraConfig,
} }
pub struct CtrlKbdLedTask(pub Arc<Mutex<CtrlKbdLed>>); pub struct CtrlKbdLedTask(pub Arc<Mutex<CtrlKbdLed>>);
@@ -88,151 +85,28 @@ pub struct CtrlKbdLedReloader(pub Arc<Mutex<CtrlKbdLed>>);
impl crate::Reloadable for CtrlKbdLedReloader { impl crate::Reloadable for CtrlKbdLedReloader {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut lock) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
let current = lock.config.current_mode; let current = ctrl.config.current_mode;
if let Some(mode) = lock.config.builtins.get(&current).cloned() { if let Some(mode) = ctrl.config.builtins.get(&current).cloned() {
lock.do_command(mode).ok(); ctrl.do_command(mode).ok();
} }
ctrl.set_states_enabled(ctrl.config.awake_enabled, ctrl.config.sleep_anim_enabled)
.map_err(|err| warn!("{}", err))
.ok();
} }
Ok(()) Ok(())
} }
} }
pub struct CtrlKbdLedZbus { pub struct CtrlKbdLedZbus(pub Arc<Mutex<CtrlKbdLed>>);
inner: Arc<Mutex<CtrlKbdLed>>,
}
impl CtrlKbdLedZbus { impl CtrlKbdLedZbus {
pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self { pub fn new(inner: Arc<Mutex<CtrlKbdLed>>) -> Self {
Self { inner } Self(inner)
} }
} }
impl crate::ZbusAdd for CtrlKbdLedZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
.map_err(|err| {
error!("DbusKbdLed: add_to_server {}", err);
})
.ok();
}
}
/// The main interface for changing, reading, or notfying signals
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlKbdLedZbus {
/// Set the keyboard brightness level (0-3)
fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err))
.ok();
}
}
/// Set the keyboard LED to enabled while the device is awake
fn set_awake_enabled(&mut self, enabled: bool) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_awake_enable(enabled)
.map_err(|err| warn!("{}", err))
.ok();
}
}
/// Set the keyboard LED suspend animation to enabled while the device is suspended
fn set_sleep_enabled(&mut self, enabled: bool) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_sleep_anim_enable(enabled)
.map_err(|err| warn!("{}", err))
.ok();
}
}
fn set_led_mode(&mut self, effect: AuraEffect) {
if let Ok(mut ctrl) = self.inner.try_lock() {
let mode_name = effect.mode_name();
match ctrl.do_command(effect) {
Ok(_) => {
self.notify_led(&mode_name).ok();
}
Err(err) => {
warn!("{}", err);
}
}
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.toggle_mode(false)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.toggle_mode(true)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
/// Return the current mode data
#[dbus_interface(property)]
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
#[dbus_interface(property)]
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return json;
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not serialise".to_string()
}
/// Return the current LED brightness
#[dbus_interface(property)]
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
}
warn!("SetKeyBacklight could not serialise");
-1
}
#[dbus_interface(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
impl CtrlKbdLed { impl CtrlKbdLed {
#[inline] #[inline]
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> { pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
@@ -280,7 +154,7 @@ impl CtrlKbdLed {
None None
} }
fn get_brightness(&self) -> Result<u8, RogError> { pub(super) fn get_brightness(&self) -> Result<u8, RogError> {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
.open(&self.bright_node) .open(&self.bright_node)
@@ -296,7 +170,7 @@ impl CtrlKbdLed {
Ok(buf[0]) Ok(buf[0])
} }
fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> { pub(super) fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
let path = Path::new(&self.bright_node); let path = Path::new(&self.bright_node);
let mut file = let mut file =
OpenOptions::new() OpenOptions::new()
@@ -313,19 +187,19 @@ impl CtrlKbdLed {
Ok(()) Ok(())
} }
/// Set the keyboard LED to active if laptop is awake /// Set if awake/on LED active, and/or sleep animation active
fn set_awake_enable(&self, enabled: bool) -> Result<(), RogError> { pub(super) fn set_states_enabled(&self, awake: bool, sleep: bool) -> Result<(), RogError> {
let bytes = if enabled { LED_AWAKE_ON } else { LED_AWAKE_OFF }; let bytes = if awake && sleep {
self.write_bytes(&bytes)?; LED_AWAKE_ON_SLEEP_ON
self.write_bytes(&LED_SET)?; } else if awake && !sleep {
// Changes won't persist unless apply is set LED_AWAKE_ON_SLEEP_OFF
self.write_bytes(&LED_APPLY)?; } else if !awake && sleep {
Ok(()) LED_AWAKE_OFF_SLEEP_ON
} } else if !awake && !sleep {
LED_AWAKE_OFF_SLEEP_OFF
/// Set the keyboard suspend animation to on if plugged in } else {
fn set_sleep_anim_enable(&self, enabled: bool) -> Result<(), RogError> { LED_AWAKE_ON_SLEEP_ON
let bytes = if enabled { LED_SLEEP_ON } else { LED_SLEEP_OFF }; };
self.write_bytes(&bytes)?; self.write_bytes(&bytes)?;
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
@@ -391,7 +265,7 @@ impl CtrlKbdLed {
/// Write an effect block /// Write an effect block
#[inline] #[inline]
fn write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), RogError> { fn _write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), RogError> {
if self.flip_effect_write { if self.flip_effect_write {
for row in effect.iter().rev() { for row in effect.iter().rev() {
self.write_bytes(row)?; self.write_bytes(row)?;
@@ -419,7 +293,7 @@ impl CtrlKbdLed {
} }
#[inline] #[inline]
fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> { pub(super) fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> {
let current = self.config.current_mode; let current = self.config.current_mode;
if let Some(idx) = self if let Some(idx) = self
.supported_modes .supported_modes
+2
View File
@@ -0,0 +1,2 @@
pub mod controller;
pub mod zbus;
+165
View File
@@ -0,0 +1,165 @@
use log::{error, warn};
use rog_aura::{AuraEffect, LedBrightness, LedPowerStates};
use zbus::dbus_interface;
use zvariant::ObjectPath;
use super::controller::CtrlKbdLedZbus;
impl crate::ZbusAdd for CtrlKbdLedZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Led"), self)
.map_err(|err| {
error!("DbusKbdLed: add_to_server {}", err);
})
.ok();
}
}
/// The main interface for changing, reading, or notfying signals
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlKbdLedZbus {
/// Set the keyboard brightness level (0-3)
fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.0.try_lock() {
ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err))
.ok();
}
}
/// Set the keyboard LED to enabled while the device is awake
fn set_awake_enabled(&mut self, enabled: bool) {
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.set_states_enabled(enabled, ctrl.config.sleep_anim_enabled)
.map_err(|err| warn!("{}", err))
.ok();
ctrl.config.awake_enabled = enabled;
ctrl.config.write();
let states = LedPowerStates {
enabled: ctrl.config.awake_enabled,
sleep_anim_enabled: ctrl.config.sleep_anim_enabled,
};
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
}
}
/// Set the keyboard LED suspend animation to enabled while the device is suspended
fn set_sleep_enabled(&mut self, enabled: bool) {
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.set_states_enabled(ctrl.config.awake_enabled, enabled)
.map_err(|err| warn!("{}", err))
.ok();
ctrl.config.sleep_anim_enabled = enabled;
ctrl.config.write();
let states = LedPowerStates {
enabled: ctrl.config.awake_enabled,
sleep_anim_enabled: ctrl.config.sleep_anim_enabled,
};
self.notify_power_states(&states)
.unwrap_or_else(|err| warn!("{}", err));
}
}
fn set_led_mode(&mut self, effect: AuraEffect) {
if let Ok(mut ctrl) = self.0.try_lock() {
match ctrl.do_command(effect) {
Ok(_) => {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone())
.unwrap_or_else(|err| warn!("{}", err));
}
}
Err(err) => {
warn!("{}", err);
}
}
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.toggle_mode(false)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone())
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.0.try_lock() {
ctrl.toggle_mode(true)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
self.notify_led(mode.clone())
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
#[dbus_interface(property)]
fn awake_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.awake_enabled;
}
true
}
#[dbus_interface(property)]
fn sleep_enabled(&self) -> bool {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.config.sleep_anim_enabled;
}
true
}
/// Return the current mode data
#[dbus_interface(property)]
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.0.try_lock() {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
#[dbus_interface(property)]
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.0.try_lock() {
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return json;
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not serialise".to_string()
}
/// Return the current LED brightness
#[dbus_interface(property)]
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.0.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
}
warn!("SetKeyBacklight could not serialise");
-1
}
#[dbus_interface(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
#[dbus_interface(signal)]
fn notify_power_states(&self, data: &LedPowerStates) -> zbus::Result<()>;
}
+50 -188
View File
@@ -1,21 +1,12 @@
use crate::error::RogError; use crate::error::RogError;
use crate::{config::Config, GetSupported}; use crate::{config::Config, GetSupported};
use log::{info, warn}; use log::info;
use rog_types::{ use rog_profiles::profiles::Profile;
profile::{FanLevel, Profile, ProfileEvent}, use rog_types::supported::FanCpuSupportedFunctions;
supported::FanCpuSupportedFunctions,
};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use super::*;
pub struct CtrlFanAndCpu { pub struct CtrlFanAndCpu {
pub path: &'static str,
pub config: Arc<Mutex<Config>>, pub config: Arc<Mutex<Config>>,
} }
@@ -24,8 +15,8 @@ impl GetSupported for CtrlFanAndCpu {
fn get_supported() -> Self::A { fn get_supported() -> Self::A {
FanCpuSupportedFunctions { FanCpuSupportedFunctions {
stock_fan_modes: CtrlFanAndCpu::get_fan_path().is_ok(), stock_fan_modes: Profile::get_fan_path().is_ok(),
min_max_freq: intel_pstate::PState::new().is_ok(), min_max_freq: Profile::get_intel_supported(),
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(), fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
} }
} }
@@ -33,13 +24,12 @@ impl GetSupported for CtrlFanAndCpu {
impl crate::Reloadable for CtrlFanAndCpu { impl crate::Reloadable for CtrlFanAndCpu {
fn reload(&mut self) -> Result<(), RogError> { fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.clone().try_lock() { if let Ok(mut cfg) = self.config.clone().try_lock() {
let profile = config.active_profile.clone(); let active = cfg.active_profile.clone();
self.set(&profile, &mut config)?; if let Some(existing) = cfg.power_profiles.get_mut(&active) {
// info!( existing.set_system_all()?;
// "Reloaded fan mode: {:?}", cfg.write();
// FanLevel::from(config.power_profile) }
// );
} }
Ok(()) Ok(())
} }
@@ -47,194 +37,66 @@ impl crate::Reloadable for CtrlFanAndCpu {
impl CtrlFanAndCpu { impl CtrlFanAndCpu {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> { pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
let path = CtrlFanAndCpu::get_fan_path()?; Profile::get_fan_path()?;
info!("Device has thermal throttle control"); info!("Device has thermal throttle control");
Ok(CtrlFanAndCpu { path, config }) Ok(CtrlFanAndCpu { config })
}
fn get_fan_path() -> Result<&'static str, RogError> {
if Path::new(FAN_TYPE_1_PATH).exists() {
Ok(FAN_TYPE_1_PATH)
} else if Path::new(FAN_TYPE_2_PATH).exists() {
Ok(FAN_TYPE_2_PATH)
} else {
Err(RogError::MissingFunction(
"Fan mode not available, you may require a v5.8.10 series kernel or newer".into(),
))
}
} }
/// Toggle to next profile in list /// Toggle to next profile in list
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> { pub(super) fn do_next_profile(&mut self) -> Result<(), RogError> {
config.read(); if let Ok(mut config) = self.config.clone().try_lock() {
config.read();
let mut i = config let mut i = config
.toggle_profiles .toggle_profiles
.iter() .binary_search(&config.active_profile)
.position(|x| x == &config.active_profile) .unwrap_or(0)
.map(|i| i + 1) + 1;
.unwrap_or(0); if i >= config.toggle_profiles.len() {
if i >= config.toggle_profiles.len() { i = 0;
i = 0;
}
let new_profile = config
.toggle_profiles
.get(i)
.unwrap_or(&config.active_profile)
.clone();
self.set(&new_profile, config)?;
info!("Profile was changed: {}", &new_profile);
Ok(())
}
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
let mode = config.active_profile.clone();
let mut fan_ctrl = OpenOptions::new()
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
config.read();
let mut mode_config = config
.power_profiles
.get_mut(&mode)
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
config.curr_fan_mode = preset;
mode_config.fan_preset = preset;
config.write();
fan_ctrl
.write_all(format!("{}\n", preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
info!("Fan mode set to: {:?}", FanLevel::from(preset));
Ok(())
}
pub(super) fn handle_profile_event(
&mut self,
event: &ProfileEvent,
config: &mut Config,
) -> Result<(), RogError> {
match event {
ProfileEvent::Toggle => self.do_next_profile(config)?,
ProfileEvent::ChangeMode(mode) => {
self.set_fan_mode(*mode, config)?;
let mode = config.active_profile.clone();
self.set_pstate_for_fan_mode(&mode, config)?;
self.set_fan_curve_for_fan_mode(&mode, config)?;
} }
ProfileEvent::Cli(command) => {
let profile_key = match command.profile.as_ref() {
Some(k) => k.clone(),
None => config.active_profile.clone(),
};
let mut profile = if command.create { let profile = config.toggle_profiles[i].clone();
config
.power_profiles
.entry(profile_key.clone())
.or_insert_with(Profile::default)
} else {
config
.power_profiles
.get_mut(&profile_key)
.ok_or_else(|| RogError::MissingProfile(profile_key.clone()))?
};
if command.turbo.is_some() { if let Some(existing) = config.power_profiles.get(&profile) {
profile.turbo = command.turbo.unwrap(); existing.set_system_all()?;
} config.active_profile = existing.name.clone();
if let Some(min_perc) = command.min_percentage { config.write();
profile.min_percentage = min_perc; info!("Profile was changed to: {}", profile);
}
if let Some(max_perc) = command.max_percentage {
profile.max_percentage = max_perc;
}
if let Some(ref preset) = command.fan_preset {
profile.fan_preset = preset.into();
}
if let Some(ref curve) = command.curve {
profile.fan_curve = Some(curve.clone());
}
self.set(&profile_key, config)?;
} }
} }
Ok(()) Ok(())
} }
pub(super) fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> { pub(super) fn set_active(&mut self, profile: &str) -> Result<(), RogError> {
let mode_config = config if let Ok(mut config) = self.config.clone().try_lock() {
.power_profiles config.read();
.get(profile) if let Some(existing) = config.power_profiles.get(profile) {
.ok_or_else(|| RogError::MissingProfile(profile.into()))?; existing.set_system_all()?;
let mut fan_ctrl = OpenOptions::new() config.active_profile = existing.name.clone();
.write(true) config.write();
.open(self.path) info!("Profile was changed to: {}", profile);
.map_err(|err| RogError::Path(self.path.into(), err))?; }
config.curr_fan_mode = mode_config.fan_preset;
fan_ctrl
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
self.set_pstate_for_fan_mode(profile, config)?;
self.set_fan_curve_for_fan_mode(profile, config)?;
config.active_profile = profile.into();
config.write();
Ok(())
}
fn set_pstate_for_fan_mode(&self, mode: &str, config: &mut Config) -> Result<(), RogError> {
info!("Setting pstate");
let mode_config = config
.power_profiles
.get(mode)
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
// Set CPU pstate
if let Ok(pstate) = intel_pstate::PState::new() {
pstate.set_min_perf_pct(mode_config.min_percentage)?;
pstate.set_max_perf_pct(mode_config.max_percentage)?;
pstate.set_no_turbo(!mode_config.turbo)?;
info!(
"Intel CPU Power: min: {}%, max: {}%, turbo: {}",
mode_config.min_percentage, mode_config.max_percentage, mode_config.turbo
);
} else {
info!("Setting pstate for AMD CPU");
// must be AMD CPU
let mut file = OpenOptions::new()
.write(true)
.open(AMD_BOOST_PATH)
.map_err(|err| RogError::Path(self.path.into(), err))?;
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
file.write_all(boost.as_bytes())
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
info!("AMD CPU Turbo: {}", boost);
} }
Ok(()) Ok(())
} }
fn set_fan_curve_for_fan_mode(&self, mode: &str, config: &Config) -> Result<(), RogError> { pub(super) fn new_or_modify(&mut self, profile: &Profile) -> Result<(), RogError> {
let mode_config = &config if let Ok(mut config) = self.config.clone().try_lock() {
.power_profiles config.read();
.get(mode)
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
if let Some(ref curve) = mode_config.fan_curve { if let Some(existing) = config.power_profiles.get_mut(&profile.name) {
use rog_fan_curve::{Board, Fan}; *existing = profile.clone();
if let Some(board) = Board::from_board_name() { existing.set_system_all()?;
curve.apply(board, Fan::Cpu)?;
curve.apply(board, Fan::Gpu)?;
} else { } else {
warn!("Fan curve unsupported on this board.") config.power_profiles
.insert(profile.name.clone(), profile.clone());
profile.set_system_all()?;
} }
config.active_profile = profile.name.clone();
config.write();
} }
Ok(()) Ok(())
} }
} }
-4
View File
@@ -1,7 +1,3 @@
pub mod zbus; pub mod zbus;
pub mod controller; pub mod controller;
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
+33 -125
View File
@@ -1,5 +1,5 @@
use log::warn; use log::warn;
use rog_fan_curve::Curve; use rog_profiles::profiles::Profile;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
@@ -20,136 +20,35 @@ impl FanAndCpuZbus {
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl FanAndCpuZbus { impl FanAndCpuZbus {
/// Set profile details /// Create new profile and make active
fn set_profile(&self, profile: String) { fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut ctrl) = self.inner.try_lock() { ctrl.set_active(&profile)
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { .unwrap_or_else(|err| warn!("{}", err));
cfg.read();
ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
} }
self.do_notification();
} }
/// Modify the active profile /// New or modify profile details and make active, will create if it does not exist
fn set_turbo(&self, enable: bool) -> zbus::fdo::Result<()> { fn new_or_modify(&self, profile: Profile) {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { ctrl.new_or_modify(&profile)
// Update the profile then set it .unwrap_or_else(|err| warn!("{}", err));
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.turbo = enable;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
} }
Ok(()) self.do_notification();
}
/// Modify the active profile
fn set_min_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.min_percentage = percentage;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_max_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.max_percentage = percentage;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_fan_preset(&self, preset: u8) -> zbus::fdo::Result<()> {
if preset > 2 {
return Err(zbus::fdo::Error::InvalidArgs(
"Fan preset must be 0, 1, or 2".to_string(),
));
}
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.fan_preset = preset;
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
}
/// Modify the active profile
fn set_fan_curve(&self, curve: String) -> zbus::fdo::Result<()> {
let curve = Curve::from_config_str(&curve)
.map_err(|err| zbus::fdo::Error::InvalidArgs(format!("Fan curve error: {}", err)))?;
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
// Update the profile then set it
cfg.read();
let profile = cfg.active_profile.clone();
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
profile.fan_curve = Some(curve);
}
ctrl.set(&profile, &mut cfg)?;
return Ok(());
}
}
Ok(())
} }
/// Fetch the active profile name /// Fetch the active profile name
fn next_profile(&mut self) { fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() { if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() { ctrl.do_next_profile()
cfg.read(); .unwrap_or_else(|err| warn!("{}", err));
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
} }
self.do_notification();
} }
/// Fetch the active profile name /// Fetch the active profile name
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> { fn active_name(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read(); cfg.read();
@@ -163,14 +62,12 @@ impl FanAndCpuZbus {
// TODO: Profile can't implement Type because of Curve // TODO: Profile can't implement Type because of Curve
/// Fetch the active profile details /// Fetch the active profile details
fn profile(&mut self) -> zbus::fdo::Result<String> { fn active_data(&mut self) -> zbus::fdo::Result<Profile> {
if let Ok(ctrl) = self.inner.try_lock() { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read(); cfg.read();
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) { if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string_pretty(profile) { return Ok(profile.clone());
return Ok(json);
}
} }
} }
} }
@@ -180,13 +77,11 @@ impl FanAndCpuZbus {
} }
/// Fetch all profile data /// Fetch all profile data
fn profiles(&mut self) -> zbus::fdo::Result<String> { fn profiles(&mut self) -> zbus::fdo::Result<Vec<Profile>> {
if let Ok(ctrl) = self.inner.try_lock() { if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read(); cfg.read();
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) { return Ok(cfg.power_profiles.values().cloned().collect());
return Ok(json);
}
} }
} }
Err(Error::Failed( Err(Error::Failed(
@@ -236,7 +131,20 @@ impl FanAndCpuZbus {
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {} fn notify_profile(&self, profile: &Profile) -> zbus::Result<()> {}
}
impl FanAndCpuZbus {
fn do_notification(&self) {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
self.notify_profile(&profile)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
} }
impl crate::ZbusAdd for FanAndCpuZbus { impl crate::ZbusAdd for FanAndCpuZbus {
+3 -5
View File
@@ -309,11 +309,9 @@ impl CtrlRogBios {
let mut buf = Vec::new(); let mut buf = Vec::new();
// remove modules // remove modules
for line in std::io::BufReader::new(file).lines() { for line in std::io::BufReader::new(file).lines().flatten() {
if let Ok(l) = line { if !modules.contains(&line.as_str()) {
if !modules.contains(&l.as_ref()) { buf.append(&mut line.as_bytes().to_vec());
buf.append(&mut l.as_bytes().to_vec());
}
} }
} }
+9 -5
View File
@@ -2,15 +2,19 @@ use log::warn;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface; use zbus::dbus_interface;
use zvariant::ObjectPath; use zvariant::ObjectPath;
use zvariant_derive::Type;
use crate::{GetSupported, ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed, ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios}; use crate::{
ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::controller::CtrlKbdLed,
ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios, GetSupported,
};
use rog_types::supported::{ use rog_types::supported::{
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions, AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
LedSupportedFunctions, RogBiosSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
}; };
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type)]
pub struct SupportedFunctions { pub struct SupportedFunctions {
pub anime_ctrl: AnimeSupportedFunctions, pub anime_ctrl: AnimeSupportedFunctions,
pub charge_ctrl: ChargeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions,
@@ -21,8 +25,8 @@ pub struct SupportedFunctions {
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl SupportedFunctions { impl SupportedFunctions {
fn supported_functions(&self) -> String { fn supported_functions(&self) -> &SupportedFunctions {
serde_json::to_string_pretty(self).unwrap() self
} }
} }
@@ -46,8 +50,8 @@ impl GetSupported for SupportedFunctions {
fn get_supported() -> Self::A { fn get_supported() -> Self::A {
SupportedFunctions { SupportedFunctions {
keyboard_led: CtrlKbdLed::get_supported(),
anime_ctrl: CtrlAnime::get_supported(), anime_ctrl: CtrlAnime::get_supported(),
keyboard_led: CtrlKbdLed::get_supported(),
charge_ctrl: CtrlCharge::get_supported(), charge_ctrl: CtrlCharge::get_supported(),
fan_cpu_ctrl: CtrlFanAndCpu::get_supported(), fan_cpu_ctrl: CtrlFanAndCpu::get_supported(),
rog_bios_ctrl: CtrlRogBios::get_supported(), rog_bios_ctrl: CtrlRogBios::get_supported(),
+12 -8
View File
@@ -1,11 +1,13 @@
use daemon::ctrl_leds::{CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus}; use daemon::ctrl_leds::controller::{
CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus,
};
use daemon::{ use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
}; };
use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge}; use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics}; use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics};
use daemon::{ use daemon::{
ctrl_profiles::{zbus::FanAndCpuZbus, controller::CtrlFanAndCpu}, ctrl_profiles::{controller::CtrlFanAndCpu, zbus::FanAndCpuZbus},
laptops::LaptopLedData, laptops::LaptopLedData,
}; };
@@ -33,9 +35,12 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
.filter(None, LevelFilter::Info) .filter(None, LevelFilter::Info)
.init(); .init();
info!(" daemon v{}", daemon::VERSION); info!(" daemon v{}", daemon::VERSION);
info!(" rog-dbus v{}", rog_dbus::VERSION); info!(" rog-anime v{}", rog_anime::VERSION);
info!("rog-types v{}", rog_types::VERSION); info!(" rog-aura v{}", rog_aura::VERSION);
info!(" rog-dbus v{}", rog_dbus::VERSION);
info!("rog-profiles v{}", rog_profiles::VERSION);
info!(" rog-types v{}", rog_types::VERSION);
start_daemon()?; start_daemon()?;
Ok(()) Ok(())
@@ -145,10 +150,9 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
// Need to check if a laptop has the dedicated gfx switch // Need to check if a laptop has the dedicated gfx switch
if CtrlRogBios::has_dedicated_gfx_toggle() { if CtrlRogBios::has_dedicated_gfx_toggle() {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() { if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(mut config) = config.lock() { if let Ok(config) = config.lock() {
if ded == 1 { if ded == 1 {
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
config.gfx_last_mode = config.gfx_mode;
let devices = ctrl.devices(); let devices = ctrl.devices();
let bus = ctrl.bus(); let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks( CtrlGraphics::do_vendor_tasks(
@@ -162,7 +166,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
let devices = ctrl.devices(); let devices = ctrl.devices();
let bus = ctrl.bus(); let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks( CtrlGraphics::do_vendor_tasks(
config.gfx_last_mode, config.gfx_mode,
false, false,
&devices, &devices,
&bus, &bus,
+9 -9
View File
@@ -1,5 +1,5 @@
use intel_pstate::PStateError;
use rog_fan_curve::CurveError; use rog_fan_curve::CurveError;
use rog_profiles::error::ProfileError;
use rog_types::error::GraphicsError; use rog_types::error::GraphicsError;
use std::convert::From; use std::convert::From;
use std::fmt; use std::fmt;
@@ -18,13 +18,13 @@ pub enum RogError {
Write(String, std::io::Error), Write(String, std::io::Error),
NotSupported, NotSupported,
NotFound(String), NotFound(String),
IntelPstate(PStateError),
FanCurve(CurveError), FanCurve(CurveError),
DoTask(String), DoTask(String),
MissingFunction(String), MissingFunction(String),
MissingLedBrightNode(String, std::io::Error), MissingLedBrightNode(String, std::io::Error),
ReloadFail(String), ReloadFail(String),
GfxSwitching(GfxError), GfxSwitching(GfxError),
Profiles(ProfileError),
Initramfs(String), Initramfs(String),
Modprobe(String), Modprobe(String),
Command(String, std::io::Error), Command(String, std::io::Error),
@@ -46,13 +46,13 @@ impl fmt::Display for RogError {
RogError::Write(path, error) => write!(f, "Write {}: {}", path, error), RogError::Write(path, error) => write!(f, "Write {}: {}", path, error),
RogError::NotSupported => write!(f, "Not supported"), RogError::NotSupported => write!(f, "Not supported"),
RogError::NotFound(deets) => write!(f, "Not found: {}", deets), RogError::NotFound(deets) => write!(f, "Not found: {}", deets),
RogError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err),
RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err), RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err),
RogError::DoTask(deets) => write!(f, "Task error: {}", deets), RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets), RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets),
RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets), RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets),
RogError::Profiles(deets) => write!(f, "Profile error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error), RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
@@ -64,12 +64,6 @@ impl fmt::Display for RogError {
impl std::error::Error for RogError {} impl std::error::Error for RogError {}
impl From<PStateError> for RogError {
fn from(err: PStateError) -> Self {
RogError::IntelPstate(err)
}
}
impl From<CurveError> for RogError { impl From<CurveError> for RogError {
fn from(err: CurveError) -> Self { fn from(err: CurveError) -> Self {
RogError::FanCurve(err) RogError::FanCurve(err)
@@ -85,6 +79,12 @@ impl From<GraphicsError> for RogError {
} }
} }
impl From<ProfileError> for RogError {
fn from(err: ProfileError) -> Self {
RogError::Profiles(err)
}
}
impl From<zbus::Error> for RogError { impl From<zbus::Error> for RogError {
fn from(err: zbus::Error) -> Self { fn from(err: zbus::Error) -> Self {
RogError::Zbus(err) RogError::Zbus(err)
+8 -1
View File
@@ -87,4 +87,11 @@ prod_family = "ROG Zephyrus G14"
board_names = ["GA401Q"] board_names = ["GA401Q"]
standard = ["Static", "Breathe", "Pulse"] standard = ["Static", "Breathe", "Pulse"]
multizone = false multizone = false
per_key = false per_key = false
[[led_data]]
prod_family = "ROG Zephyrus"
board_names = ["GX550L"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = false
per_key = true
+1 -2
View File
@@ -14,7 +14,7 @@ exclude = ["data"]
[features] [features]
default = ["dbus"] default = ["dbus"]
dbus = ["zbus", "zvariant", "zvariant_derive"] dbus = ["zvariant", "zvariant_derive"]
[dependencies] [dependencies]
png_pong = "^0.8.0" png_pong = "^0.8.0"
@@ -26,6 +26,5 @@ serde_derive = "^1.0"
glam = { version = "0.14.0", features = ["serde"] } glam = { version = "0.14.0", features = ["serde"] }
zbus = { version = "^1.9.1", optional = true }
zvariant = { version = "^2.6", optional = true } zvariant = { version = "^2.6", optional = true }
zvariant_derive = { version = "^2.6", optional = true } zvariant_derive = { version = "^2.6", optional = true }
+8
View File
@@ -14,6 +14,14 @@ pub const ANIME_DATA_LEN: usize = PANE_LEN * 2;
const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02]; const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02]; const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub struct AnimePowerStates {
pub enabled: bool,
pub boot_anim_enabled: bool,
}
/// The minimal serializable data that can be transferred over wire types. /// The minimal serializable data that can be transferred over wire types.
/// Other data structures in `rog_anime` will convert to this. /// Other data structures in `rog_anime` will convert to this.
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
-15
View File
@@ -3,9 +3,6 @@ use png_pong::decode::Error as PngError;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
#[cfg(feature = "dbus")]
use zbus::fdo;
#[derive(Debug)] #[derive(Debug)]
pub enum AnimeError { pub enum AnimeError {
NoFrames, NoFrames,
@@ -15,8 +12,6 @@ pub enum AnimeError {
Format, Format,
/// The input was incorrect size, expected size is `IncorrectSize(width, height)` /// The input was incorrect size, expected size is `IncorrectSize(width, height)`
IncorrectSize(u32, u32), IncorrectSize(u32, u32),
#[cfg(feature = "dbus")]
Zbus(fdo::Error),
} }
impl fmt::Display for AnimeError { impl fmt::Display for AnimeError {
@@ -33,8 +28,6 @@ impl fmt::Display for AnimeError {
"The input image size is incorrect, expected {}x{}", "The input image size is incorrect, expected {}x{}",
width, height width, height
), ),
#[cfg(feature = "dbus")]
AnimeError::Zbus(e) => write!(f, "ZBUS error: {}", e),
} }
} }
} }
@@ -61,11 +54,3 @@ impl From<DecodingError> for AnimeError {
AnimeError::Gif(err) AnimeError::Gif(err)
} }
} }
#[cfg(feature = "dbus")]
impl From<AnimeError> for fdo::Error {
#[inline]
fn from(err: AnimeError) -> Self {
fdo::Error::Failed(format!("{}", err))
}
}
+22 -24
View File
@@ -180,36 +180,34 @@ impl AnimeImage {
let du = led_from_px * Vec3::new(-0.5, 0.5, 0.0); let du = led_from_px * Vec3::new(-0.5, 0.5, 0.0);
let dv = led_from_px * Vec3::new(0.5, 0.5, 0.0); let dv = led_from_px * Vec3::new(0.5, 0.5, 0.0);
for led in self.led_pos.iter_mut() { for led in self.led_pos.iter_mut().flatten() {
if let Some(led) = led { let mut sum = 0.0;
let mut sum = 0.0; let mut alpha = 0.0;
let mut alpha = 0.0; let mut count = 0;
let mut count = 0;
let pos = Vec3::new(led.x(), led.y(), 1.0); let pos = Vec3::new(led.x(), led.y(), 1.0);
let x0 = led_from_px.mul_vec3(pos + Vec3::new(0.0, -0.5, 0.0)); let x0 = led_from_px.mul_vec3(pos + Vec3::new(0.0, -0.5, 0.0));
const GROUP: [f32; 4] = [0.0, 0.5, 1.0, 1.5]; const GROUP: [f32; 4] = [0.0, 0.5, 1.0, 1.5];
for u in GROUP.iter() { for u in GROUP.iter() {
for v in GROUP.iter() { for v in GROUP.iter() {
let sample = x0 + *u * du + *v * dv; let sample = x0 + *u * du + *v * dv;
let x = sample.x as i32; let x = sample.x as i32;
let y = sample.y as i32; let y = sample.y as i32;
if x > width - 1 || y > height - 1 || x < 0 || y < 0 { if x > width - 1 || y > height - 1 || x < 0 || y < 0 {
continue; continue;
}
let p = self.img_pixels[(x + (y * width)) as usize];
sum += p.color as f32;
alpha += p.alpha;
count += 1;
} }
let p = self.img_pixels[(x + (y * width)) as usize];
sum += p.color as f32;
alpha += p.alpha;
count += 1;
} }
alpha /= count as f32;
sum /= count as f32;
led.set_bright((sum * self.bright * alpha) as u8);
} }
alpha /= count as f32;
sum /= count as f32;
led.set_bright((sum * self.bright * alpha) as u8);
} }
} }
+1 -1
View File
@@ -32,4 +32,4 @@ pub mod error;
/// Provides const methods to create the USB HID control packets /// Provides const methods to create the USB HID control packets
pub mod usb; pub mod usb;
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
+2 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_aura" name = "rog_aura"
version = "1.0.1" version = "1.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,12 +14,11 @@ exclude = ["data"]
[features] [features]
default = ["dbus"] default = ["dbus"]
dbus = ["zbus", "zvariant", "zvariant_derive"] dbus = ["zvariant", "zvariant_derive"]
[dependencies] [dependencies]
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
zbus = { version = "^1.9.1", optional = true }
zvariant = { version = "^2.6", optional = true } zvariant = { version = "^2.6", optional = true }
zvariant_derive = { version = "^2.6", optional = true } zvariant_derive = { version = "^2.6", optional = true }
+7
View File
@@ -11,6 +11,13 @@ use zvariant_derive::Type;
use crate::{error::Error, LED_MSG_LEN}; use crate::{error::Error, LED_MSG_LEN};
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub struct LedPowerStates {
pub enabled: bool,
pub sleep_anim_enabled: bool,
}
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
pub enum LedBrightness { pub enum LedBrightness {
+2
View File
@@ -14,3 +14,5 @@ pub mod usb;
pub mod error; pub mod error;
pub const LED_MSG_LEN: usize = 17; pub const LED_MSG_LEN: usize = 17;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
+8 -12
View File
@@ -15,22 +15,18 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
] ]
} }
/// Enable the keyboard when laptop is awake pub const LED_AWAKE_ON_SLEEP_OFF: [u8; 17] = [
pub const LED_AWAKE_ON: [u8; 17] = [
0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]; ];
/// Disable the keyboard when laptop is awake pub const LED_AWAKE_ON_SLEEP_ON: [u8; 17] = [
pub const LED_AWAKE_OFF: [u8; 17] = [
0x5d, 0xbd, 0x01, 0xc3, 0x13, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
/// Enable animations when the laptop is suspended while plugged in
pub const LED_SLEEP_ON: [u8; 17] = [
0x5d, 0xbd, 0x01, 0xff, 0x1f, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5d, 0xbd, 0x01, 0xff, 0x1f, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]; ];
/// Disable animations when the laptop is suspended while plugged in pub const LED_AWAKE_OFF_SLEEP_OFF: [u8; 17] = [
pub const LED_SLEEP_OFF: [u8; 17] = [ 0x5d, 0xbd, 0x01, 0xc3, 0x13, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
pub const LED_AWAKE_OFF_SLEEP_ON: [u8; 17] = [
0x5d, 0xbd, 0x01, 0xf3, 0x1b, 0x0d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]; ];
+4 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rog_dbus" name = "rog_dbus"
version = "3.2.0" version = "3.4.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>"]
@@ -10,11 +10,10 @@ description = "dbus interface methods for asusctl"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
serde_json = "^1.0"
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_profiles = { path = "../rog-profiles" }
rog_types = { path = "../rog-types" } rog_types = { path = "../rog-types" }
rog_fan_curve = { version = "^0.1", features = ["serde"] } zbus = "^1.9"
zbus = "^1.8" zbus_macros = "^1.9"
zbus_macros = "^1.8"
zvariant = "^2.5" zvariant = "^2.5"
+67 -44
View File
@@ -10,9 +10,11 @@ pub mod zbus_profile;
pub mod zbus_rogbios; pub mod zbus_rogbios;
pub mod zbus_supported; pub mod zbus_supported;
use rog_aura::AuraEffect; use rog_anime::AnimePowerStates;
use rog_aura::{AuraEffect, LedPowerStates};
use rog_profiles::profiles::Profile;
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors}; use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver};
use zbus::{Connection, Result, SignalReceiver}; use zbus::{Connection, Result, SignalReceiver};
pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub static VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -45,9 +47,9 @@ impl<'a> DbusProxies<'a> {
)) ))
} }
pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver { pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver<'a, 'a> {
let mut recv = SignalReceiver::new(conn); let mut recv = SignalReceiver::new(conn);
//recv.receive_for(&self.proxy_anime); recv.receive_for(self.anime.proxy());
recv.receive_for(self.led.proxy()); recv.receive_for(self.led.proxy());
recv.receive_for(self.charge.proxy()); recv.receive_for(self.charge.proxy());
recv.receive_for(self.gfx.proxy()); recv.receive_for(self.gfx.proxy());
@@ -86,68 +88,91 @@ impl<'a> DbusProxies<'a> {
// Signals separated out // Signals separated out
pub struct Signals { pub struct Signals {
pub gfx_vendor: Arc<Mutex<Option<GfxVendors>>>, pub gfx_vendor: Receiver<GfxVendors>,
pub gfx_action: Arc<Mutex<Option<GfxRequiredUserAction>>>, pub gfx_action: Receiver<GfxRequiredUserAction>,
pub profile: Arc<Mutex<Option<String>>>, pub profile: Receiver<Profile>,
pub led_mode: Arc<Mutex<Option<AuraEffect>>>, pub led_mode: Receiver<AuraEffect>,
pub charge: Arc<Mutex<Option<u8>>>, pub led_power_state: Receiver<LedPowerStates>,
pub anime_power_state: Receiver<AnimePowerStates>,
pub charge: Receiver<u8>,
} }
impl Signals { impl Signals {
#[inline] #[inline]
pub fn new(proxies: &DbusProxies) -> Result<Self> { pub fn new(proxies: &DbusProxies) -> Result<Self> {
//
let charge_signal = Arc::new(Mutex::new(None));
proxies
.charge
.connect_notify_charge(charge_signal.clone())?;
//
let ledmode_signal = Arc::new(Mutex::new(None));
proxies.led.connect_notify_led(ledmode_signal.clone())?;
let gfx_action_signal = Arc::new(Mutex::new(None));
proxies
.gfx
.connect_notify_action(gfx_action_signal.clone())?;
let gfx_vendor_signal = Arc::new(Mutex::new(None));
proxies.gfx.connect_notify_gfx(gfx_vendor_signal.clone())?;
let profile_signal = Arc::new(Mutex::new(None));
proxies
.profile
.connect_notify_profile(profile_signal.clone())?;
Ok(Signals { Ok(Signals {
gfx_vendor: gfx_vendor_signal, gfx_vendor: {
gfx_action: gfx_action_signal, let (tx, rx) = channel();
profile: profile_signal, proxies.gfx.connect_notify_gfx(tx)?;
led_mode: ledmode_signal, rx
charge: charge_signal, },
gfx_action: {
let (tx, rx) = channel();
proxies.gfx.connect_notify_action(tx)?;
rx
},
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
},
}) })
} }
} }
/// This is the main way to communicate with the DBUS interface /// This is the main way to communicate with the DBUS interface
pub struct AuraDbusClient<'a> { pub struct RogDbusClient<'a> {
proxies: DbusProxies<'a>, proxies: DbusProxies<'a>,
signals: Signals, signals: Signals,
} }
impl<'a> AuraDbusClient<'a> { impl<'a> RogDbusClient<'a> {
#[inline] #[inline]
pub fn new() -> Result<(Self, Connection)> { pub fn new() -> Result<(Self, Connection)> {
let (proxies, conn) = DbusProxies::new()?; let (proxies, conn) = DbusProxies::new()?;
let signals = Signals::new(&proxies)?; let signals = Signals::new(&proxies)?;
Ok((AuraDbusClient { proxies, signals }, 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.gfx.proxy());
recv.receive_for(self.proxies.profile.proxy());
recv
}
/* /*
* GFX * GFX
*/ */
@@ -155,10 +180,8 @@ impl<'a> AuraDbusClient<'a> {
loop { loop {
if let Ok(res) = self.proxies.gfx.proxy().next_signal() { if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
if res.is_none() { if res.is_none() {
if let Ok(lock) = self.signals.gfx_action.lock() { if let Ok(stuff) = self.signals.gfx_action.try_recv() {
if let Some(stuff) = lock.as_ref() { return Ok(stuff);
return Ok(*stuff);
}
} }
// return Ok("Failed for unknown reason".to_owned()); // return Ok("Failed for unknown reason".to_owned());
} }
+34 -1
View File
@@ -19,7 +19,9 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_anime::AnimeDataBuffer; use std::sync::mpsc::Sender;
use rog_anime::{AnimeDataBuffer, AnimePowerStates};
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
@@ -35,6 +37,15 @@ trait Daemon {
/// WriteDirect method /// WriteDirect method
fn write(&self, input: &[u8]) -> zbus::Result<()>; fn write(&self, input: &[u8]) -> zbus::Result<()>;
#[dbus_proxy(property)]
fn awake_enabled(&self) -> zbus::Result<bool>;
#[dbus_proxy(property)]
fn boot_enabled(&self) -> zbus::Result<bool>;
#[dbus_proxy(signal)]
fn notify_power_states(&self, data: AnimePowerStates) -> zbus::Result<()>;
} }
pub struct AnimeProxy<'a>(DaemonProxy<'a>); pub struct AnimeProxy<'a>(DaemonProxy<'a>);
@@ -63,4 +74,26 @@ impl<'a> AnimeProxy<'a> {
pub fn write(&self, input: AnimeDataBuffer) -> Result<()> { pub fn write(&self, input: AnimeDataBuffer) -> Result<()> {
self.0.write(input.get()) self.0.write(input.get())
} }
#[inline]
pub fn awake_enabled(&self) -> Result<bool> {
self.0.awake_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(())
})
}
} }
+4 -5
View File
@@ -19,7 +19,7 @@
//! //!
//! …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::{Arc, Mutex}; use std::sync::mpsc::Sender;
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
@@ -62,11 +62,10 @@ impl<'a> ChargeProxy<'a> {
} }
#[inline] #[inline]
pub fn connect_notify_charge(&self, charge: Arc<Mutex<Option<u8>>>) -> zbus::fdo::Result<()> { pub fn connect_notify_charge(&self, send: Sender<u8>) -> zbus::fdo::Result<()> {
self.0.connect_notify_charge(move |data| { self.0.connect_notify_charge(move |data| {
if let Ok(mut lock) = charge.lock() { send.send(data)
*lock = Some(data); .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
Ok(()) Ok(())
}) })
} }
+7 -12
View File
@@ -19,7 +19,7 @@
//! //!
//! …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::{Arc, Mutex}; use std::sync::mpsc::Sender;
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
@@ -77,25 +77,20 @@ impl<'a> GfxProxy<'a> {
#[inline] #[inline]
pub fn connect_notify_action( pub fn connect_notify_action(
&self, &self,
action: Arc<Mutex<Option<GfxRequiredUserAction>>>, send: Sender<GfxRequiredUserAction>,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.0.connect_notify_action(move |data| { self.0.connect_notify_action(move |data| {
if let Ok(mut lock) = action.lock() { send.send(data)
*lock = Some(data); .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
Ok(()) Ok(())
}) })
} }
#[inline] #[inline]
pub fn connect_notify_gfx( pub fn connect_notify_gfx(&self, send: Sender<GfxVendors>) -> zbus::fdo::Result<()> {
&self,
vendor: Arc<Mutex<Option<GfxVendors>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_gfx(move |data| { self.0.connect_notify_gfx(move |data| {
if let Ok(mut lock) = vendor.lock() { send.send(data)
*lock = Some(data); .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
Ok(()) Ok(())
}) })
} }
+37 -9
View File
@@ -19,11 +19,11 @@
//! //!
//! …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::{Arc, Mutex}; use std::sync::mpsc::Sender;
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
use rog_aura::{AuraEffect, KeyColourArray, LedBrightness}; use rog_aura::{AuraEffect, KeyColourArray, LedBrightness, LedPowerStates};
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
@@ -52,7 +52,10 @@ trait Daemon {
/// NotifyLed signal /// NotifyLed signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>; fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
#[dbus_proxy(signal)]
fn notify_power_states(&self, data: LedPowerStates) -> zbus::Result<()>;
/// LedBrightness property /// LedBrightness property
#[dbus_proxy(property)] #[dbus_proxy(property)]
@@ -65,6 +68,12 @@ trait Daemon {
/// LedModes property /// LedModes property
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn led_modes(&self) -> zbus::Result<String>; fn led_modes(&self) -> zbus::Result<String>;
#[dbus_proxy(property)]
fn awake_enabled(&self) -> zbus::Result<bool>;
#[dbus_proxy(property)]
fn sleep_enabled(&self) -> zbus::Result<bool>;
} }
pub struct LedProxy<'a>(DaemonProxy<'a>); pub struct LedProxy<'a>(DaemonProxy<'a>);
@@ -119,6 +128,16 @@ impl<'a> LedProxy<'a> {
self.0.set_led_mode(mode) 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
@@ -152,13 +171,22 @@ impl<'a> LedProxy<'a> {
} }
#[inline] #[inline]
pub fn connect_notify_led(&self, led: Arc<Mutex<Option<AuraEffect>>>) -> zbus::fdo::Result<()> { pub fn connect_notify_led(&self, send: Sender<AuraEffect>) -> zbus::fdo::Result<()> {
self.0.connect_notify_led(move |data| { self.0.connect_notify_led(move |data| {
if let Ok(mut lock) = led.lock() { send.send(data)
if let Ok(dat) = serde_json::from_str(&data) { .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
*lock = Some(dat); 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(()) Ok(())
}) })
} }
+22 -79
View File
@@ -19,9 +19,9 @@
//! //!
//! …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::{Arc, Mutex}; use std::sync::mpsc::Sender;
use rog_types::profile::ProfileEvent; use rog_profiles::profiles::Profile;
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
@@ -29,17 +29,17 @@ use zbus::{dbus_proxy, Connection, Result};
default_path = "/org/asuslinux/Profile" default_path = "/org/asuslinux/Profile"
)] )]
trait Daemon { trait Daemon {
/// ActiveProfileName method
fn active_profile_name(&self) -> zbus::Result<String>;
/// NextProfile method /// NextProfile method
fn next_profile(&self) -> zbus::Result<()>; fn next_profile(&self) -> zbus::Result<()>;
/// Profile, get the active profile /// Profile, get the active profile
fn profile(&self) -> zbus::Result<String>; fn active_name(&self) -> zbus::Result<String>;
/// Get the active `Profile` data
fn active_data(&self) -> zbus::Result<Profile>;
/// Profiles method /// Profiles method
fn profiles(&self) -> zbus::Result<String>; fn profiles(&self) -> zbus::Result<Vec<Profile>>;
/// ProfileNames method /// ProfileNames method
fn profile_names(&self) -> zbus::Result<Vec<String>>; fn profile_names(&self) -> zbus::Result<Vec<String>>;
@@ -48,26 +48,11 @@ trait Daemon {
fn remove(&self, profile: &str) -> zbus::Result<()>; fn remove(&self, profile: &str) -> zbus::Result<()>;
/// SetProfile method /// SetProfile method
fn set_profile(&self, profile: &str) -> zbus::Result<()>; fn new_or_modify(&self, profile: &Profile) -> zbus::Result<()>;
/// SetFanCurve method
fn set_fan_curve(&self, curve: &str) -> zbus::Result<()>;
/// SetFanPreset method
fn set_fan_preset(&self, preset: u8) -> zbus::Result<()>;
/// SetMaxFrequency method
fn set_max_frequency(&self, percentage: u8) -> zbus::Result<()>;
/// SetMinFrequency method
fn set_min_frequency(&self, percentage: u8) -> zbus::Result<()>;
/// SetTurbo method
fn set_turbo(&self, enable: bool) -> zbus::Result<()>;
/// NotifyProfile signal /// NotifyProfile signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()>; fn notify_profile(&self, profile: Profile) -> zbus::Result<()>;
} }
pub struct ProfileProxy<'a>(DaemonProxy<'a>); pub struct ProfileProxy<'a>(DaemonProxy<'a>);
@@ -83,17 +68,17 @@ impl<'a> ProfileProxy<'a> {
} }
#[inline] #[inline]
pub fn active_profile_name(&self) -> Result<String> { pub fn active_name(&self) -> Result<String> {
self.0.active_profile_name() self.0.active_name()
} }
#[inline] #[inline]
pub fn active_profile_data(&self) -> Result<String> { pub fn active_data(&self) -> Result<Profile> {
self.0.profile() self.0.active_data()
} }
#[inline] #[inline]
pub fn all_profile_data(&self) -> Result<String> { pub fn all_profile_data(&self) -> Result<Vec<Profile>> {
self.0.profiles() self.0.profiles()
} }
@@ -102,49 +87,6 @@ impl<'a> ProfileProxy<'a> {
self.0.next_profile() self.0.next_profile()
} }
/// SetFanCurve, set fan curve for active profile
#[inline]
pub fn set_fan_curve(&self, curve: &str) -> zbus::Result<()> {
self.0.set_fan_curve(curve)
}
/// SetFanPreset, set fan preset for active profile
#[inline]
pub fn set_fan_preset(&self, preset: u8) -> zbus::Result<()> {
self.0.set_fan_preset(preset)
}
/// SetMaxFrequency, set max percentage of frequency for active profile
#[inline]
pub fn set_max_frequency(&self, percentage: u8) -> zbus::Result<()> {
self.0.set_max_frequency(percentage)
}
/// SetMinFrequency, set min percentage of frequency for active profile
#[inline]
pub fn set_min_frequency(&self, percentage: u8) -> zbus::Result<()> {
self.0.set_min_frequency(percentage)
}
/// SetTurbo, set turbo enable for active profile
#[inline]
pub fn set_turbo(&self, enable: bool) -> zbus::Result<()> {
self.0.set_turbo(enable)
}
// TODO: remove
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<()> {
self.0
.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level)).unwrap())
}
// TODO: remove
#[inline]
pub fn write_command(&self, cmd: &ProfileEvent) -> Result<()> {
self.0.set_profile(&serde_json::to_string(cmd).unwrap())
}
#[inline] #[inline]
pub fn profile_names(&self) -> Result<Vec<String>> { pub fn profile_names(&self) -> Result<Vec<String>> {
self.0.profile_names() self.0.profile_names()
@@ -156,14 +98,15 @@ impl<'a> ProfileProxy<'a> {
} }
#[inline] #[inline]
pub fn connect_notify_profile( pub fn new_or_modify(&self, profile: &Profile) -> Result<()> {
&self, self.0.new_or_modify(profile)
charge: Arc<Mutex<Option<String>>>, }
) -> zbus::fdo::Result<()> {
#[inline]
pub fn connect_notify_profile(&self, send: Sender<Profile>) -> zbus::fdo::Result<()> {
self.0.connect_notify_profile(move |data| { self.0.connect_notify_profile(move |data| {
if let Ok(mut lock) = charge.lock() { send.send(data)
*lock = Some(data.to_owned()); .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
Ok(()) Ok(())
}) })
} }
+3 -2
View File
@@ -19,6 +19,7 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_types::supported::SupportedFunctions;
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
@@ -27,7 +28,7 @@ use zbus::{dbus_proxy, Connection, Result};
)] )]
trait Daemon { trait Daemon {
/// SupportedFunctions method /// SupportedFunctions method
fn supported_functions(&self) -> zbus::Result<String>; fn supported_functions(&self) -> zbus::Result<SupportedFunctions>;
} }
pub struct SupportProxy<'a>(DaemonProxy<'a>); pub struct SupportProxy<'a>(DaemonProxy<'a>);
@@ -43,7 +44,7 @@ impl<'a> SupportProxy<'a> {
} }
#[inline] #[inline]
pub fn get_supported_functions(&self) -> Result<String> { pub fn get_supported_functions(&self) -> Result<SupportedFunctions> {
self.0.supported_functions() self.0.supported_functions()
} }
} }
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "rog_profiles"
version = "0.1.0"
authors = ["Luke D. Jones <luke@ljones.dev>"]
edition = "2018"
[features]
default = ["dbus"]
dbus = ["zvariant", "zvariant_derive"]
[dependencies]
rog_fan_curve = { version = "^0.1", features = ["serde"] }
serde = "^1.0"
serde_derive = "^1.0"
intel-pstate = "^0.2"
zvariant = { version = "^2.6", optional = true }
zvariant_derive = { version = "^2.6", optional = true }
+54
View File
@@ -0,0 +1,54 @@
use std::fmt;
use intel_pstate::PStateError;
use rog_fan_curve::CurveError;
#[derive(Debug)]
pub enum ProfileError {
ParseFanLevel,
MissingProfile(String),
Path(String, std::io::Error),
Read(String, std::io::Error),
Write(String, std::io::Error),
NotSupported,
NotFound(String),
IntelPstate(PStateError),
FanCurve(CurveError),
Io(std::io::Error),
//Zbus(zbus::Error),
}
impl fmt::Display for ProfileError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ProfileError::ParseFanLevel => write!(f, "Parse profile error"),
ProfileError::MissingProfile(profile) => {
write!(f, "Profile does not exist {}", profile)
}
ProfileError::Path(path, error) => write!(f, "Path {}: {}", path, error),
ProfileError::Read(path, error) => write!(f, "Read {}: {}", path, error),
ProfileError::Write(path, error) => write!(f, "Write {}: {}", path, error),
ProfileError::NotSupported => write!(f, "Not supported"),
ProfileError::NotFound(deets) => write!(f, "Not found: {}", deets),
ProfileError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err),
ProfileError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err),
ProfileError::Io(detail) => write!(f, "std::io error: {}", detail),
//Error::Zbus(detail) => write!(f, "Zbus error: {}", detail),
}
}
}
impl std::error::Error for ProfileError {}
impl From<PStateError> for ProfileError {
fn from(err: PStateError) -> Self {
ProfileError::IntelPstate(err)
}
}
impl From<CurveError> for ProfileError {
fn from(err: CurveError) -> Self {
ProfileError::FanCurve(err)
}
}
+8
View File
@@ -0,0 +1,8 @@
pub mod error;
pub mod profiles;
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
+185
View File
@@ -0,0 +1,185 @@
use rog_fan_curve::{Curve, Fan};
use serde_derive::{Deserialize, Serialize};
use std::io::Write;
use std::{fs::OpenOptions, path::Path, str::FromStr};
#[cfg(feature = "dbus")]
use zvariant_derive::Type;
use crate::{error::ProfileError, AMD_BOOST_PATH, FAN_TYPE_1_PATH, FAN_TYPE_2_PATH};
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Profile {
pub name: String,
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: FanLevel,
pub fan_curve: String,
}
impl Default for Profile {
fn default() -> Self {
Profile {
name: "new".into(),
min_percentage: 0,
max_percentage: 100,
turbo: false,
fan_preset: FanLevel::Normal,
fan_curve: "".to_string(),
}
}
}
impl Profile {
pub fn new(
name: String,
min_percentage: u8,
max_percentage: u8,
turbo: bool,
fan_preset: FanLevel,
fan_curve: String,
) -> Self {
Profile {
name,
min_percentage,
max_percentage,
turbo,
fan_preset,
fan_curve,
}
}
pub fn get_intel_supported() -> bool {
intel_pstate::PState::new().is_ok()
}
pub fn get_fan_path() -> Result<&'static str, ProfileError> {
if Path::new(FAN_TYPE_1_PATH).exists() {
Ok(FAN_TYPE_1_PATH)
} else if Path::new(FAN_TYPE_2_PATH).exists() {
Ok(FAN_TYPE_2_PATH)
} else {
Err(ProfileError::NotSupported)
}
}
pub fn set_system_pstate(&self) -> Result<(), ProfileError> {
// Set CPU pstate
if let Ok(pstate) = intel_pstate::PState::new() {
pstate.set_min_perf_pct(self.min_percentage)?;
pstate.set_max_perf_pct(self.max_percentage)?;
pstate.set_no_turbo(!self.turbo)?;
} else {
// must be AMD CPU
let mut file = OpenOptions::new()
.write(true)
.open(AMD_BOOST_PATH)
.map_err(|err| ProfileError::Path(AMD_BOOST_PATH.into(), err))?;
let boost = if self.turbo { "1" } else { "0" }; // opposite of Intel
file.write_all(boost.as_bytes())
.map_err(|err| ProfileError::Write(AMD_BOOST_PATH.into(), err))?;
}
Ok(())
}
pub fn set_system_fan_mode(&self) -> Result<(), ProfileError> {
let path = Profile::get_fan_path()?;
let mut fan_ctrl = OpenOptions::new()
.write(true)
.open(path)
.map_err(|err| ProfileError::Path(path.into(), err))?;
fan_ctrl
.write_all(format!("{}\n", <u8>::from(self.fan_preset)).as_bytes())
.map_err(|err| ProfileError::Write(path.into(), err))?;
Ok(())
}
pub fn set_system_fan_curve(&self) -> Result<(), ProfileError> {
if !self.fan_curve.is_empty() {
if let Ok(curve) = Profile::parse_fan_curve(&self.fan_curve) {
use rog_fan_curve::Board;
if let Some(board) = Board::from_board_name() {
curve.apply(board, Fan::Cpu)?;
curve.apply(board, Fan::Gpu)?;
}
}
}
Ok(())
}
pub fn set_system_all(&self) -> Result<(), ProfileError> {
self.set_system_pstate()?;
if self.fan_curve.is_empty() {
self.set_system_fan_mode()?;
} else {
self.set_system_fan_curve()?;
}
Ok(())
}
fn parse_fan_curve(data: &str) -> Result<Curve, String> {
let curve = Curve::from_config_str(data)?;
if let Err(err) = curve.check_safety(Fan::Cpu) {
return Err(format!("Unsafe curve {:?}", err));
}
if let Err(err) = curve.check_safety(Fan::Gpu) {
return Err(format!("Unsafe curve {:?}", err));
}
Ok(curve)
}
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum FanLevel {
Normal,
Boost,
Silent,
}
impl FromStr for FanLevel {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"normal" => Ok(FanLevel::Normal),
"boost" => Ok(FanLevel::Boost),
"silent" => Ok(FanLevel::Silent),
_ => Err("Invalid fan level"),
}
}
}
impl From<u8> for FanLevel {
fn from(n: u8) -> Self {
match n {
0 => FanLevel::Normal,
1 => FanLevel::Boost,
2 => FanLevel::Silent,
_ => FanLevel::Normal,
}
}
}
impl From<FanLevel> for u8 {
fn from(n: FanLevel) -> Self {
match n {
FanLevel::Normal => 0,
FanLevel::Boost => 1,
FanLevel::Silent => 2,
}
}
}
impl From<&FanLevel> for u8 {
fn from(n: &FanLevel) -> Self {
match n {
FanLevel::Normal => 0,
FanLevel::Boost => 1,
FanLevel::Silent => 2,
}
}
}
-2
View File
@@ -10,9 +10,7 @@ description = "A small library of effect types and conversions for ROG Aura"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
gumdrop = "^0.8"
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
rog_fan_curve = { version = "^0.1", features = ["serde"] }
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
zvariant = "^2.6" zvariant = "^2.6"
-2
View File
@@ -6,8 +6,6 @@ pub static DBUS_NAME: &str = "org.asuslinux.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";
pub mod profile;
pub mod gfx_vendors; pub mod gfx_vendors;
pub mod supported; pub mod supported;
-153
View File
@@ -1,153 +0,0 @@
use gumdrop::Options;
use rog_fan_curve::{Curve, Fan};
use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Profile {
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: u8,
pub fan_curve: Option<Curve>,
}
#[deprecated]
pub type CpuSettings = Profile;
impl Default for Profile {
fn default() -> Self {
Profile {
min_percentage: 0,
max_percentage: 100,
turbo: false,
fan_preset: 0,
fan_curve: None,
}
}
}
impl Profile {
pub fn new(
min_percentage: u8,
max_percentage: u8,
turbo: bool,
fan_preset: u8,
fan_curve: Option<Curve>,
) -> Self {
Profile {
min_percentage,
max_percentage,
turbo,
fan_preset,
fan_curve,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ProfileEvent {
Cli(ProfileCommand),
ChangeMode(u8),
Toggle,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FanLevel {
Normal,
Boost,
Silent,
}
impl FromStr for FanLevel {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"normal" => Ok(FanLevel::Normal),
"boost" => Ok(FanLevel::Boost),
"silent" => Ok(FanLevel::Silent),
_ => Err("Invalid fan level"),
}
}
}
impl From<u8> for FanLevel {
fn from(n: u8) -> Self {
match n {
0 => FanLevel::Normal,
1 => FanLevel::Boost,
2 => FanLevel::Silent,
_ => FanLevel::Normal,
}
}
}
impl From<FanLevel> for u8 {
fn from(n: FanLevel) -> Self {
match n {
FanLevel::Normal => 0,
FanLevel::Boost => 1,
FanLevel::Silent => 2,
}
}
}
impl From<&FanLevel> for u8 {
fn from(n: &FanLevel) -> Self {
match n {
FanLevel::Normal => 0,
FanLevel::Boost => 1,
FanLevel::Silent => 2,
}
}
}
fn parse_fan_curve(data: &str) -> Result<Curve, String> {
let curve = Curve::from_config_str(data)?;
if let Err(err) = curve.check_safety(Fan::Cpu) {
return Err(format!("Unsafe curve {:?}", err));
}
if let Err(err) = curve.check_safety(Fan::Gpu) {
return Err(format!("Unsafe curve {:?}", err));
}
Ok(curve)
}
#[derive(Debug, Clone, Options, Serialize, Deserialize)]
pub struct ProfileCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "toggle to next profile in list")]
pub next: bool,
#[options(help = "create the profile if it doesn't exist")]
pub create: bool,
#[options(meta = "", help = "remove a profile by name")]
pub remove: Option<String>,
#[options(help = "list available profiles")]
pub list: bool,
#[options(help = "get active profile name")]
pub active_name: bool,
#[options(help = "get active profile data")]
pub active_data: bool,
#[options(help = "get all profile data")]
pub profiles_data: bool,
#[options(meta = "", help = "enable or disable cpu turbo")]
pub turbo: Option<bool>,
#[options(meta = "", help = "set min cpu scaling (intel)")]
pub min_percentage: Option<u8>,
#[options(meta = "", help = "set max cpu scaling (intel)")]
pub max_percentage: Option<u8>,
#[options(meta = "", help = "<silent, normal, boost>")]
pub fan_preset: Option<FanLevel>,
#[options(
meta = "",
parse(try_from_str = "parse_fan_curve"),
help = "set fan curve"
)]
pub curve: Option<Curve>,
#[options(free)]
pub profile: Option<String>,
}
+8 -7
View File
@@ -1,7 +1,8 @@
use rog_aura::AuraModeNum; use rog_aura::AuraModeNum;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zvariant_derive::Type;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct SupportedFunctions { pub struct SupportedFunctions {
pub anime_ctrl: AnimeSupportedFunctions, pub anime_ctrl: AnimeSupportedFunctions,
pub charge_ctrl: ChargeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions,
@@ -10,30 +11,30 @@ pub struct SupportedFunctions {
pub rog_bios_ctrl: RogBiosSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct AnimeSupportedFunctions(pub bool); pub struct AnimeSupportedFunctions(pub bool);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct ChargeSupportedFunctions { pub struct ChargeSupportedFunctions {
pub charge_level_set: bool, pub charge_level_set: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct FanCpuSupportedFunctions { pub struct FanCpuSupportedFunctions {
pub stock_fan_modes: bool, pub stock_fan_modes: bool,
pub min_max_freq: bool, pub min_max_freq: bool,
pub fan_curve_set: bool, pub fan_curve_set: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct LedSupportedFunctions { pub struct LedSupportedFunctions {
pub brightness_set: bool, pub brightness_set: bool,
pub stock_led_modes: Option<Vec<AuraModeNum>>, pub stock_led_modes: Vec<AuraModeNum>,
pub multizone_led_mode: bool, pub multizone_led_mode: bool,
pub per_key_led_mode: bool, pub per_key_led_mode: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct RogBiosSupportedFunctions { pub struct RogBiosSupportedFunctions {
pub post_sound_toggle: bool, pub post_sound_toggle: bool,
pub dedicated_gfx_toggle: bool, pub dedicated_gfx_toggle: bool,