Compare commits

...

37 Commits
2.0.0 ... 2.1.0

Author SHA1 Message Date
Luke D Jones
de3b803f14 Add DBUS methods to toggle next/previous aura mode 2020-10-25 15:49:14 +13:00
Luke D Jones
0558f919c4 Add DBUS method to toggle to next profile 2020-10-25 15:02:35 +13:00
Luke Jones
68ea73c847 Merge branch 'asere/anime_on_off' into 'next'
AniMe: adding --on and --off options to turn on/off (and accept/reject write requests)

See merge request asus-linux/asus-nb-ctrl!11
2020-10-25 01:14:12 +00:00
Luke Jones
96ddb7132d Merge branch 'asere/show_keyboard_brightness' into 'next'
Improving user experience by showing current keyboard led brightness

See merge request asus-linux/asus-nb-ctrl!10
2020-10-25 01:12:21 +00:00
Asere
d36ac44603 updating option "-k" to show current brightness: asusctl -k 2020-10-23 02:00:08 +02:00
Asere
5d06c87943 AniMe: adding --on and --off options to turn on/off (and accept/reject write requests) 2020-10-22 14:09:05 +02:00
Luke D Jones
588e3c0102 Panic if config file is bad 2020-10-22 08:28:12 +13:00
Luke D Jones
6ce32c1cab Fix one super silly bug
closes #30
2020-10-22 08:16:00 +13:00
Luke Jones
a23c51e5db Adding Anime commands to asusctl 2020-10-11 22:46:06 +00:00
Asere
3845071ba3 adding Anime feature: led brightness command to asusctl, and updating dbus client 2020-10-12 00:11:26 +02:00
Luke Jones
a48b3634bf Merge branch 'next' into 'next'
Add some basic zsh completions for asusctl

See merge request asus-linux/asus-nb-ctrl!8
2020-10-05 00:38:34 +00:00
Luke Jones
806882b2e9 Merge branch 'next' into 'next'
fixed fan presets for profiles

See merge request asus-linux/asus-nb-ctrl!7
2020-10-05 00:37:43 +00:00
Luke D Jones
9ac3c46fe6 Actually enable/disable gfx switch control 2020-10-05 09:32:46 +13:00
Luke D Jones
6817a1c027 Bump dbus autogen 2020-10-05 09:31:07 +13:00
Dylan Jones
cf2be1b12b Add some basic zsh completions for asusctl 2020-09-30 13:28:05 -04:00
Luke D Jones
9ffeb19c8c Bump version 2020-09-29 21:30:23 +13:00
Cuong
a7f6e8bd24 fixed fan presets for profiles 2020-09-28 10:04:57 +00:00
Luke Jones
f61f62c219 Merge branch 'feature/dbus-profile-name' into 'next'
 Add ActiveProfileName() dbus method returning name of current profile

See merge request asus-linux/asus-nb-ctrl!5
2020-09-26 08:50:03 +00:00
Andreas Streichardt
bb70fd7b71 Add ActiveProfileName() dbus method returning name of current profile 2020-09-26 09:05:50 +02:00
Luke D Jones
b80c860b7a Fix args to systemctl for reboot 2020-09-25 21:05:47 +12:00
Luke D Jones
3c7544f034 Explicitly state arch is not supported 2020-09-25 14:14:21 +12:00
Luke D Jones
6746c2b654 Update changelog 2020-09-24 09:04:49 +12:00
Luke D Jones
8d59f89438 Add verbose error for LED node missing 2020-09-24 08:18:10 +12:00
Luke D Jones
5753160e91 Don't throw away do_task error, log it 2020-09-24 08:10:05 +12:00
Luke D Jones
622cd9d943 Fix timeout for GFX switching 2020-09-24 08:00:37 +12:00
Luke D Jones
2daa7f0811 Git internal version from crate version 2020-09-23 22:12:47 +12:00
Luke D Jones
05c53df0ed Better description of config panic 2020-09-23 21:24:25 +12:00
Luke D Jones
a7419cbc4c Remove many unwraps or change to maps 2020-09-23 20:47:33 +12:00
Luke D Jones
67ad38a7e6 Ditch the gsync line in screen settings file. Oops
- Add force option to `systemctl reboot`. Be careful.
2020-09-23 16:51:46 +12:00
Luke Jones
e572ae2c62 Update Makefile 2020-09-23 02:32:25 +00:00
Luke Jones
24962eedc1 Merge branch 'testing' into 'next'
Bugfixes and improvements

Closes #11

See merge request asus-linux/asus-nb-ctrl!4
2020-09-23 01:05:15 +00:00
Luke D Jones
368d279ca5 Add "info" output for gfx driver check 2020-09-23 12:59:15 +12:00
Luke D Jones
9e4cc329ed Add "info" output for gfx driver check 2020-09-22 09:54:37 +12:00
Luke D Jones
d4702a166a Support Zephyrus M GU502GV
closes #11
2020-09-22 09:47:20 +12:00
Luke D Jones
925c709097 Minor CLI output correction 2020-09-21 20:55:47 +12:00
Luke D Jones
411788f72c Remove triple-buffer line 2020-09-21 20:44:31 +12:00
Luke D Jones
4e4ea0035e Add missing gfx dbus signal 2020-09-21 20:41:28 +12:00
40 changed files with 1063 additions and 322 deletions

View File

@@ -5,6 +5,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
# [2.1.0] - 2020-10-25
### Added
- Option to turn off AniMe display (@asere)
### Changed
- Change option -k to show current LED bright (@asere)
- Correctly disable GFX control via config
- Panic and exit if config can't be parsed
- Add DBUS method to toggle to next fan/thermal profile
- Add DBUS method to toggle to next/prev Aura mode
# [2.0.5] - 2020-09-29
### Changed
- Bugfixes
# [2.0.4] - 2020-09-24
### Changed
- Better and more verbose error handling and logging in many places.
- Fix timeout for client waiting on reply for graphics switching
# [2.0.2] - 2020-09-21
### Changed
- graphics options via CLI are now a command block:
+ `asusctl graphics`
+ -m Mode <nvidia, hybrid, compute, integrated>
+ -g Get current mode
+ -f Force reboot or restart display manager without confirmation
# [2.0.0] - 2020-09-21
### Changed

67
Cargo.lock generated
View File

@@ -29,7 +29,7 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "asus-nb"
version = "2.0.0"
version = "2.1.0"
dependencies = [
"ctrl-gfx",
"dbus",
@@ -46,7 +46,7 @@ dependencies = [
[[package]]
name = "asus-nb-ctrl"
version = "2.0.0"
version = "2.1.0"
dependencies = [
"asus-nb",
"ctrl-gfx",
@@ -69,7 +69,7 @@ dependencies = [
[[package]]
name = "asus-notify"
version = "1.0.0"
version = "2.0.4"
dependencies = [
"asus-nb",
"asus-nb-ctrl",
@@ -152,13 +152,15 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.15"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
checksum = "d021fddb7bd3e734370acfa4a83f34095571d8570c039f1420d77540f68d5772"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
@@ -189,7 +191,7 @@ dependencies = [
[[package]]
name = "ctrl-gfx"
version = "2.0.0"
version = "2.1.3"
dependencies = [
"log",
"sysfs-class",
@@ -215,7 +217,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -247,7 +249,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -273,7 +275,7 @@ dependencies = [
"proc-macro2",
"quote 1.0.7",
"rustversion",
"syn 1.0.41",
"syn 1.0.42",
"synstructure",
]
@@ -323,14 +325,14 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
name = "hermit-abi"
version = "0.1.15"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
dependencies = [
"libc",
]
@@ -411,9 +413,9 @@ dependencies = [
[[package]]
name = "libusb1-sys"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca5c2a82e2c56537de7d1a163575049593667af689122fafbccc117bbaa59079"
checksum = "1f02e930161703cc97c0aab3a905feb9740db03a80910f31ab0f8fa309223f39"
dependencies = [
"cc",
"libc",
@@ -577,7 +579,7 @@ dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
"version_check",
]
@@ -594,9 +596,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
checksum = "51ef7cd2518ead700af67bf9d1a658d90b6037d77110fd9c0445429d0ba1c6c9"
dependencies = [
"unicode-xid 0.2.1",
]
@@ -665,9 +667,9 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
[[package]]
name = "rog_fan_curve"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d3867a0df47bf57c6eebe8b2fb3c2e5c09586a23c715cd7963c2f090c9983f"
checksum = "da77fe4a6ad41da874d83eca6a32075a5b8f6ad4778682bc1308075e7ef856a9"
dependencies = [
"serde",
]
@@ -702,7 +704,7 @@ checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -734,7 +736,7 @@ checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -756,7 +758,7 @@ checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -767,7 +769,7 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -799,9 +801,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228"
dependencies = [
"proc-macro2",
"quote 1.0.7",
@@ -825,7 +827,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
"unicode-xid 0.2.1",
]
@@ -1040,9 +1042,9 @@ dependencies = [
[[package]]
name = "zbus"
version = "1.1.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e941349efbc28a22449be1e7bdaac074c9f9d96b465f855af018aa1a4e99d0a6"
checksum = "3f3d015ea4cb76e7f951e429086995126807372f80c9a2a29bf00fcfd31a50b0"
dependencies = [
"byteorder",
"derivative",
@@ -1055,19 +1057,18 @@ dependencies = [
"serde_repr",
"zbus_macros",
"zvariant",
"zvariant_derive",
]
[[package]]
name = "zbus_macros"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a153562b600280af9eaf6aff75132e1781e04bdcbb37ae03ebcc8286bb0ede42"
checksum = "54567d486c1ece9268173866c227ac1e168aa5cdf983ae9d13aaf45767fdf679"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]
[[package]]
@@ -1091,5 +1092,5 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.7",
"syn 1.0.41",
"syn 1.0.42",
]

View File

@@ -16,7 +16,7 @@ BIN_D=asusd
BIN_N=asus-notify
LEDCFG=asusd-ledmodes.toml
X11CFG=90-nvidia-screen-G05.conf
UDEVRULES=90-nvidia-pm.rules
PMRULES=90-asusd-nvidia-pm.rules
VERSION:=$(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
DEBUG ?= 0
@@ -42,7 +42,7 @@ install: all
install -D -m 0755 "target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
install -D -m 0755 "target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
install -D -m 0755 "target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
install -D -m 0644 "data/$(UDEVRULES)" "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
install -D -m 0644 "data/$(PMRULES)" "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
install -D -m 0644 "data/$(BIN_D).rules" "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
install -D -m 0644 "data/$(LEDCFG)" "$(DESTDIR)$(sysconfdir)/asusd/$(LEDCFG)"
install -D -m 0644 "data/$(BIN_D).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
@@ -52,18 +52,20 @@ install: all
install -D -m 0644 "data/icons/asus_notif_yellow.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_yellow.png"
install -D -m 0644 "data/icons/asus_notif_green.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_green.png"
install -D -m 0644 "data/icons/asus_notif_red.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_red.png"
install -D -m 0644 "data/_asusctl" "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
rm -f "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
rm -f "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
rm -f "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
rm -f "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
rm -r "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
rm -r "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_*"
rm -f "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
update:
cargo update

View File

@@ -1,7 +1,12 @@
# ASUS NB Ctrl
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features.
**NOTICE:**
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
Alternatively you may use the dkms module for 'hid-asus-rog` from one of the
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
@@ -12,17 +17,12 @@ The patch enables the following in kernel:
- Control of keyboard brightness using FN+Key combos (not RGB)
- FN+F5 (fan) to toggle fan modes
You will not get RGB control in kernel (yet), and asusd is still required to
change modes and RGB settings. The previous version of this program is named
`rog-core` and takes full control of the interfaces required - if you can't
apply the kernel patches then `rog-core` is still highly usable.
You will not get RGB control in kernel (yet), and `asusd` + `asusctl` is required
to change modes and RGB settings.
Many other patches for these laptops, AMD and Intel based, are working their way
in to the kernel.
---
asusd is a utility for Linux to control many aspects of various ASUS laptops.
## Discord
[Discord server link](https://discord.gg/PVyFzWj)
@@ -54,9 +54,9 @@ will probably suffer another rename once it becomes generic enough to do so.
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
## FUNCTIONS
# FUNCTIONS
### Graphics switching
## Graphics switching
A new feature has been added to enable switching graphics modes. This can be disabled
in the config with `"manage_gfx": false,`. Please be aware it is a work in progress.
@@ -64,7 +64,34 @@ in the config with `"manage_gfx": false,`. Please be aware it is a work in progr
The CLI option for this does not require root until it asks for it, and provides
instructions.
### KEYBOARD BACKLIGHT MODES
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/`
### 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.
```
# 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).
@@ -90,7 +117,23 @@ If you model isn't getting the correct led modes, you can edit the file
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
## Requirements for compiling
# 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
Requirements are:
- `rustc` + `cargo` + `make`
- `libusb-1.0-0-dev`
@@ -120,6 +163,11 @@ $ systemctl daemon-reload && systemctl restart asusd
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
If you would like to run this daemon on another non-ASUS laptop you can. You'll
have all features available except the LED and AniMe control (further controllers
can be added on request). You will need to install the alternative service from
`data/asusd-alt.service`.
## Uninstalling
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
@@ -130,7 +178,7 @@ If there has been a config file format change your config will be overwritten. T
become less of an issue once the feature set is nailed down. Work is happening to enable
parsing of older configs and transferring settings to new.
# Usage
# USAGE
**NOTE! Fan mode toggling requires a newer kernel**. I'm unsure when the patches
required for it got merged - I've tested with the 5.6.6 kernel and above only.
@@ -176,11 +224,11 @@ The daemon also saves the settings per mode as the keyboard does not do this
itself - this means cycling through modes with the Aura keys will use the
settings that were used via CLI.
Daemon mode creates a config file at `/etc/asusd/asusd.conf` which you can edit a
Daemon mode creates a config file at `/etc/asusd/asusd.conf` which you can edit a
little of. Most parts will be byte arrays, but you can adjust things like
`mode_performance`.
## User daemon for notification via dbus
## 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.
@@ -189,7 +237,7 @@ 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
## DBUS Input
@@ -208,6 +256,14 @@ Please file a support request.
- 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

View File

@@ -76,6 +76,12 @@ Accepts an integer from the following:
- `1`: Boost mode
- `2`: Silent mode
## dbus-send examples:
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Profile org.asuslinux.Daemon.NextProfile
```
## dbus-send examples OUTDATED
```

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb-ctrl"
version = "2.0.0"
version = "2.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -22,7 +22,7 @@ name = "asusd"
path = "src/daemon.rs"
[dependencies]
ctrl-gfx = { path = "../ctrl-gfx" }
ctrl-gfx = { path = "../ctrl-gfx" }
asus-nb = { path = "../asus-nb" }
rusb = "^0.6.0"
udev = "^0.4.0"
@@ -33,7 +33,7 @@ log = "^0.4.8"
env_logger = "^0.7.1"
# async
zbus = "1.1.1"
zbus = "1.2.0"
zvariant = "2.2.0"
#tokio = { version = "^0.2.4", features = ["rt-threaded", "sync"] }
@@ -49,4 +49,4 @@ rog_fan_curve = { version = "0.1.5", features = ["serde"] }
# cpu power management
intel-pstate = "^0.2.1"
yansi-term = "^0.1"
yansi-term = "^0.1"

View File

@@ -23,26 +23,25 @@ pub struct Config {
}
impl Config {
/// `load` will attempt to read the config, but if it is not found it
/// will create a new default config and write that out.
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(mut self, supported_led_modes: &[u8]) -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&CONFIG_PATH)
.unwrap(); // okay to cause panic here
.expect(&format!(
"The file {} or directory /etc/asusd/ is missing",
CONFIG_PATH
)); // okay to cause panic here
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
self = Config::create_default(&mut file, &supported_led_modes);
} else {
self = serde_json::from_str(&buf).unwrap_or_else(|_| {
warn!(
"Could not deserialise {}. Overwriting with default",
CONFIG_PATH
);
Config::create_default(&mut file, &supported_led_modes)
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);
});
}
}
@@ -62,11 +61,14 @@ impl Config {
config.kbd_backlight_modes.push(AuraModes::from(*n))
}
let profile = Profile::default();
let mut profile = Profile::default();
profile.fan_preset = 0;
profile.turbo = true;
config.power_profiles.insert("normal".into(), profile);
let mut profile = Profile::default();
profile.fan_preset = 1;
profile.turbo = true;
config.power_profiles.insert("boost".into(), profile);
let mut profile = Profile::default();

View File

@@ -9,6 +9,10 @@ const INIT: u8 = 0xc2;
const APPLY: u8 = 0xc3;
const SET: u8 = 0xc4;
// Used to turn the panel on and off
// The next byte can be 0x03 for "on" and 0x00 for "off"
const ON_OFF : u8 = 0x04;
use asus_nb::error::AuraError;
use log::{error, info, warn};
use rusb::{Device, DeviceHandle};
@@ -22,6 +26,7 @@ use zbus::dbus_interface;
pub enum AnimatrixCommand {
Apply,
Set,
Write(Vec<u8>),
WriteImage(Vec<Vec<u8>>),
//ReloadLast,
}
@@ -34,13 +39,19 @@ pub struct CtrlAnimeDisplay {
//AnimatrixWrite
pub trait Dbus {
fn set_anime(&mut self, input: Vec<Vec<u8>>);
fn set_on_off(&mut self, status: bool);
}
impl crate::ZbusAdd for CtrlAnimeDisplay {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Anime".try_into().unwrap(), self)
.unwrap();
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
@@ -50,6 +61,26 @@ impl Dbus for CtrlAnimeDisplay {
self.do_command(AnimatrixCommand::WriteImage(input))
.unwrap_or_else(|err| warn!("{}", err));
}
fn set_on_off(&mut self, status: bool) {
let mut activity : Vec<u8> = vec![0; PACKET_SIZE];
activity[0] = DEV_PAGE;
activity[1] = WRITE;
activity[2] = ON_OFF;
let status_str;
if status {
activity[3] = 0x03;
status_str = "on";
} else {
activity[3] = 0x00;
status_str = "off";
}
info!("Turning {} the AniMe", status_str);
self.do_command(AnimatrixCommand::Write(activity))
.unwrap_or_else(|err| warn!("{}", err));
}
}
impl CtrlAnimeDisplay {
@@ -95,9 +126,10 @@ impl CtrlAnimeDisplay {
}
match command {
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
AnimatrixCommand::Set => self.do_set()?,
AnimatrixCommand::Apply => self.do_apply()?,
AnimatrixCommand::Set => self.do_set()?,
AnimatrixCommand::Write(bytes) => self.write_bytes(&bytes)?,
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
//AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?,
}
Ok(())

View File

@@ -16,22 +16,26 @@ pub struct CtrlCharge {
config: Arc<Mutex<Config>>,
}
trait Dbus {
fn set_limit(&mut self, charge: u8);
fn limit(&self) -> i8;
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlCharge {
fn set_limit(&mut self, limit: u8) {
impl CtrlCharge {
pub fn set_limit(&mut self, limit: u8) {
if let Ok(mut config) = self.config.try_lock() {
self.set(limit, &mut config).unwrap();
self.notify_charge(limit).unwrap();
self.set(limit, &mut config)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
self.notify_charge(limit)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
}
}
fn limit(&self) -> i8 {
pub fn limit(&self) -> i8 {
if let Ok(config) = self.config.try_lock() {
return config.bat_charge_limit as i8;
}
@@ -39,14 +43,18 @@ impl Dbus for CtrlCharge {
}
#[dbus_interface(signal)]
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
}
impl crate::ZbusAdd for CtrlCharge {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Charge".try_into().unwrap(), self)
.unwrap();
.map_err(|err| {
warn!("CtrlCharge: add_to_server {}", err);
err
})
.ok();
}
}

View File

@@ -31,6 +31,7 @@ impl DbusFanAndCpu {
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusFanAndCpu {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
if let Ok(mut ctrl) = self.inner.try_lock() {
@@ -45,6 +46,34 @@ impl DbusFanAndCpu {
}
}
/// Fetch the active profile name
fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
/// Fetch the active profile name
fn active_profile_name(&mut self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
return cfg.active_profile.clone();
}
}
"Failed".to_string()
}
/// Fetch the active profile details
fn profile(&mut self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
@@ -79,7 +108,11 @@ impl crate::ZbusAdd for DbusFanAndCpu {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self)
.unwrap();
.map_err(|err| {
warn!("DbusFanAndCpu: {}", err);
err
})
.ok();
}
}
@@ -164,7 +197,8 @@ impl CtrlFanAndCPU {
}
}
pub(super) fn do_update(&mut self, config: &mut Config) -> Result<(), RogError> {
/// Toggle to next profile in list
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> {
config.read();
let mut i = config
@@ -218,7 +252,7 @@ impl CtrlFanAndCPU {
config: &mut Config,
) -> Result<(), RogError> {
match event {
ProfileEvent::Toggle => self.do_update(config)?,
ProfileEvent::Toggle => self.do_next_profile(config)?,
ProfileEvent::ChangeMode(mode) => {
self.set_fan_mode(*mode, config)?;
}
@@ -311,7 +345,7 @@ impl CtrlFanAndCPU {
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))?;
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
info!("AMD CPU Turbo: {}", boost);
}
Ok(())

View File

@@ -42,7 +42,7 @@ impl crate::ZbusAdd for DbusKbdBacklight {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Led".try_into().unwrap(), self)
.unwrap();
.ok();
}
}
@@ -58,10 +58,11 @@ impl DbusKbdBacklight {
.unwrap_or_else(|err| warn!("{}", err));
}
_ => {
let json = serde_json::to_string(&data).unwrap();
ctrl.do_command(data, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_led(&json).unwrap();
if let Ok(json) = serde_json::to_string(&data) {
ctrl.do_command(data, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_led(&json).ok();
}
}
}
}
@@ -71,6 +72,25 @@ impl DbusKbdBacklight {
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(false, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(true, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
/// Return the current mode data
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
@@ -85,6 +105,7 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
@@ -97,6 +118,17 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string()
}
/// Return the current LED brightness
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
return cfg.kbd_led_brightness as i8;
}
}
warn!("SetKeyBacklight could not deserialise");
-1
}
#[dbus_interface(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
@@ -151,7 +183,12 @@ impl crate::CtrlTask for CtrlKbdBacklight {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| RogError::Path((&self.bright_node).into(), err))?;
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
@@ -233,8 +270,11 @@ impl CtrlKbdBacklight {
RogError::Udev("parent_with_subsystem_devtype failed".into(), err)
})?
{
if parent.attribute_value("idProduct").unwrap() == id_product {
// && device.parent().unwrap().sysnum().unwrap() == 3
if parent
.attribute_value("idProduct")
.ok_or(RogError::NotFound("LED idProduct".into()))?
== id_product
{
if let Some(dev_node) = device.devnode() {
info!("Using device at: {:?} for LED control", dev_node);
return Ok(dev_node.to_string_lossy().to_string());
@@ -264,13 +304,17 @@ impl CtrlKbdBacklight {
RogError::Udev("match_property failed".into(), err)
})?;
for device in enumerator.scan_devices().map_err(|err| {
warn!("{}", err);
err
}).map_err(|err| {
warn!("{}", err);
RogError::Udev("scan_devices failed".into(), err)
})? {
for device in enumerator
.scan_devices()
.map_err(|err| {
warn!("{}", err);
err
})
.map_err(|err| {
warn!("{}", err);
RogError::Udev("scan_devices failed".into(), err)
})?
{
if let Some(dev_node) = device.devnode() {
if let Some(inum) = device.property_value("ID_USB_INTERFACE_NUM") {
if let Some(iface) = iface {
@@ -298,8 +342,9 @@ impl CtrlKbdBacklight {
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
if let Some(led_node) = &self.led_node {
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
file.write_all(message).unwrap();
return Ok(());
return file
.write_all(message)
.map_err(|err| RogError::Write("write_bytes".into(), err));
}
}
Err(RogError::NotSupported)
@@ -355,6 +400,38 @@ impl CtrlKbdBacklight {
Ok(())
}
#[inline]
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
let current = config.kbd_backlight_mode;
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
let mut idx = idx;
// goes past end of array
if reverse {
if idx == 0 {
idx = self.supported_modes.len() - 1;
} else {
idx -= 1;
}
} else {
idx += 1;
if idx == self.supported_modes.len() {
idx = 0;
}
}
let next = self.supported_modes[idx];
config.read();
if let Some(data) = config.get_led_mode_data(next) {
self.write_mode(&data)?;
config.kbd_backlight_mode = next;
}
config.write();
}
Ok(())
}
#[inline]
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
match mode {

View File

@@ -15,6 +15,8 @@ use std::io::Write;
use std::sync::Arc;
use std::sync::Mutex;
use std::convert::Into;
use std::convert::TryInto;
use zbus::fdo;
use zbus::Connection;
@@ -53,6 +55,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
match CtrlCharge::new(config.clone()) {
@@ -77,14 +80,16 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
match CtrlGraphics::new() {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
if enable_gfx_switching {
match CtrlGraphics::new() {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
}
@@ -126,11 +131,20 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task().unwrap();
lock.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
}
});
object_server.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| {
let x = obj.limit();
obj.notify_charge(x as u8)
})?;
loop {
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);

View File

@@ -1,7 +1,7 @@
use std::fmt;
use std::convert::From;
use intel_pstate::PStateError;
use rog_fan_curve::CurveError;
use std::convert::From;
use std::fmt;
#[derive(Debug)]
pub enum RogError {
@@ -19,6 +19,7 @@ pub enum RogError {
FanCurve(CurveError),
DoTask(String),
MissingFunction(String),
MissingLedBrightNode(String, std::io::Error),
}
impl fmt::Display for RogError {
@@ -39,6 +40,7 @@ impl fmt::Display for RogError {
RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err),
RogError::DoTask(deets) => write!(f, "Task error: {}", 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),
}
}
}
@@ -55,4 +57,4 @@ impl From<CurveError> for RogError {
fn from(err: CurveError) -> Self {
RogError::FanCurve(err)
}
}
}

View File

@@ -19,7 +19,7 @@ use config::Config;
use crate::error::RogError;
use zbus::ObjectServer;
pub static VERSION: &str = "2.0.0";
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>;

View File

@@ -1,19 +1,20 @@
use asus_nb::{
cli_options::{LedBrightness, SetAuraBuiltin},
anime_dbus::AniMeDbusWriter,
cli_options::{AniMeActions, LedBrightness, SetAuraBuiltin},
core_dbus::AuraDbusClient,
profile::{ProfileCommand, ProfileEvent},
};
use ctrl_gfx::vendors::GfxVendors;
use daemon::ctrl_fan_cpu::FanLevel;
use gumdrop::Options;
use gumdrop::{Opt, Options};
use log::LevelFilter;
use std::io::Write;
use std::{env::args, io::Write, process::Command};
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
#[derive(Options)]
#[derive(Default, Options)]
struct CLIStart {
#[options(help = "print help message")]
#[options(help_flag, help = "print help message")]
help: bool,
#[options(help = "show program version number")]
version: bool,
@@ -23,28 +24,60 @@ struct CLIStart {
pwr_profile: Option<FanLevel>,
#[options(meta = "CHRG", help = "<20-100>")]
chg_limit: Option<u8>,
#[options(help = "Set graphics mode: <nvidia, hybrid, compute, integrated>")]
graphics: Option<GfxVendors>,
#[options(command)]
command: Option<Command>,
command: Option<CliCommand>,
}
#[derive(Options)]
enum Command {
enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand),
#[options(help = "Create and configure profiles")]
Profile(ProfileCommand),
#[options(help = "Set the graphics mode")]
Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")]
AniMe(AniMeCommand),
}
#[derive(Options)]
struct LedModeCommand {
#[options(help = "print help message")]
help: bool,
#[options(command, required)]
#[options(help = "switch to next aura mode")]
next_mode: bool,
#[options(help = "switch to previous aura mode")]
prev_mode: bool,
#[options(command)]
command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
struct GraphicsCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "Set graphics mode: <nvidia, hybrid, compute, integrated>")]
mode: Option<GfxVendors>,
#[options(help = "Get the current mode")]
get: bool,
#[options(help = "Get the current power status")]
pow: bool,
#[options(help = "Do not ask for confirmation")]
force: bool,
}
#[derive(Options)]
struct AniMeCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "turn on the panel (and accept write requests)", no_short)]
on: bool,
#[options(help = "turn off the panel (and reject write requests)", no_short)]
off: bool,
#[options(command)]
command: Option<AniMeActions>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
@@ -53,81 +86,182 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.filter(None, LevelFilter::Info)
.init();
let parsed = CLIStart::parse_args_default_or_exit();
let mut args: Vec<String> = args().collect();
args.remove(0);
let parsed: CLIStart;
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
match CLIStart::parse_args_default(&args) {
Ok(p) => {
parsed = p;
}
Err(err) if err.to_string() == missing_argument_k.to_string() => {
parsed = CLIStart {
kbd_bright: Some(LedBrightness::new(None)),
..Default::default()
};
}
Err(err) => {
eprintln!("source {:?}", err);
std::process::exit(2);
}
}
if parsed.help_requested() {
// As help option don't work with `parse_args_default`
// we will call `parse_args_default_or_exit` instead
CLIStart::parse_args_default_or_exit();
}
if parsed.version {
println!("Version: {}", daemon::VERSION);
}
let writer = AuraDbusClient::new()?;
let anime_writer = AniMeDbusWriter::new()?;
match parsed.command {
Some(Command::LedMode(mode)) => {
if let Some(command) = mode.command {
Some(CliCommand::LedMode(mode)) => {
if mode.next_mode && mode.prev_mode {
println!("Please specify either next or previous")
}
if mode.next_mode {
writer.next_keyboard_led_mode()?;
} else if mode.prev_mode {
writer.prev_keyboard_led_mode()?;
} else if let Some(command) = mode.command {
writer.write_builtin_mode(&command.into())?
}
}
Some(Command::Profile(command)) => {
writer.write_profile_command(&ProfileEvent::Cli(command))?
Some(CliCommand::Profile(command)) => {
if command.next {
writer.next_fan_profile()?;
} else {
writer.write_profile_command(&ProfileEvent::Cli(command))?
}
}
Some(CliCommand::Graphics(command)) => do_gfx(command, &writer)?,
Some(CliCommand::AniMe(anime)) => {
if anime.on {
anime_writer.turn_on()?;
} else if anime.off {
anime_writer.turn_off()?;
} else if let Some(action) = anime.command {
match action {
AniMeActions::Leds(anime_leds) => {
let led_brightness = anime_leds.led_brightness();
anime_writer.set_leds_brightness(led_brightness)?;
}
}
}
}
None => (),
}
if let Some(brightness) = parsed.kbd_bright {
writer.write_brightness(brightness.level())?;
match brightness.level() {
None => {
let level = writer.get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string());
}
Some(level) => writer.write_brightness(level)?,
}
}
if let Some(fan_level) = parsed.pwr_profile {
writer.write_fan_mode(fan_level.into())?;
}
if let Some(chg_limit) = parsed.chg_limit {
writer.write_charge_limit(chg_limit)?;
}
if let Some(gfx) = parsed.graphics {
println!("Updating settings, please wait...");
println!("If this takes longer than 30s, ctrl+c then check journalctl");
Ok(())
}
writer.write_gfx_mode(gfx)?;
fn do_gfx(
command: GraphicsCommand,
writer: &AuraDbusClient,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(mode) = command.mode {
println!("Updating settings, please wait...");
println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`");
writer.write_gfx_mode(mode)?;
let res = writer.wait_gfx_changed()?;
match res.as_str() {
"reboot" => println!(
"{}\n{}",
Green.paint("\nGraphics vendor mode changed successfully\n"),
Red.paint("\nPlease reboot to complete switch to iGPU\n")
),
"reboot" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n"),
);
do_gfx_action(
command.force,
Command::new("systemctl").arg("reboot").arg("-i"),
"Reboot Linux PC",
"Please reboot when ready",
)?;
}
"restartx" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n")
);
restart_x()?;
do_gfx_action(
command.force,
Command::new("systemctl")
.arg("restart")
.arg("display-manager.service"),
"Restart display-manager server",
"Please restart display-manager when ready",
)?;
std::process::exit(1)
}
_ => std::process::exit(-1),
}
std::process::exit(-1)
}
Ok(())
}
fn restart_x() -> Result<(), Box<dyn std::error::Error>> {
println!("Restart X server? y/n");
let mut buf = String::new();
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' {
println!("Restarting X server");
let status = std::process::Command::new("systemctl")
.arg("restart")
.arg("display-manager.service")
.status()?;
if !status.success() {
println!("systemctl: display-manager returned with {}", status);
if command.get {
let res = writer.get_gfx_mode()?;
println!("Current graphics mode: {}", res);
}
if command.pow {
let res = writer.get_gfx_pwr()?;
if res.contains("active") {
println!("Current power status: {}", Red.paint(&format!("{}", res)));
} else {
println!("Current power status: {}", Green.paint(&format!("{}", res)));
}
} else {
println!("{}", Red.paint("Cancelled. Please restart X when ready"));
}
Ok(())
}
fn do_gfx_action(
no_confirm: bool,
command: &mut Command,
ask_msg: &str,
cancel_msg: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{}? y/n", ask_msg);
let mut buf = String::new();
if no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
}
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' || no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
} else {
println!("{}", Red.paint(&format!("{}", cancel_msg)));
}
Ok(())
}

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb"
version = "2.0.0"
version = "2.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]

View File

@@ -14,9 +14,10 @@ fn main() {
let mut matrix = AniMeMatrix::new();
// Aligned left
for px in pixels {
for (i, px) in pixels.iter().enumerate() {
if (px.x as usize / 2) < WIDTH && (px.y as usize) < HEIGHT && px.x % 2 == 0 {
matrix.get_mut()[px.y as usize][px.x as usize / 2] = px.color as u8;
let mut c = px.color as u32;
matrix.get_mut()[px.y as usize][px.x as usize / 2] = c as u8;
}
}

View File

@@ -1,29 +1,30 @@
use crate::anime_matrix::AniMePacketType;
use crate::{DBUS_IFACE, DBUS_NAME};
use dbus::channel::Sender;
use dbus::{blocking::Connection, Message};
const DBUS_ANIME_PATH : &str = "/org/asuslinux/Anime";
pub const ANIME_PANE1_PREFIX: [u8; 7] =
[0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] =
[0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
use crate::DBUS_NAME;
use dbus::blocking::{Connection, Proxy};
use std::error::Error;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::{thread, time::Duration};
pub const ANIME_PANE1_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
use crate::dbus_anime::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonAniMe,
};
/// Interface for the AniMe dot-matrix display
///
/// The resolution is 34x56 (1904) but only 1,215 LEDs in the top-left are used.
/// The display is available only on select GA401 models.
///
/// Actual image ration when displayed is stretched width.
/// Actual image ratio when displayed is stretched width.
///
/// Data structure should be nested array of [[u8; 33]; 56]
pub struct AniMeDbusWriter {
connection: Box<Connection>,
block_time: u64,
stop: Arc<AtomicBool>,
}
impl AniMeDbusWriter {
@@ -33,47 +34,80 @@ impl AniMeDbusWriter {
Ok(AniMeDbusWriter {
connection: Box::new(connection),
block_time: 25,
stop: Arc::new(AtomicBool::new(false)),
})
}
// Create D-Bus proxy
fn new_proxy(&self) -> Proxy<&Connection>{
self.connection.with_proxy(
DBUS_NAME,
DBUS_ANIME_PATH,
Duration::from_millis(200),
)
}
pub fn write_image_to_buf(_buf: &mut AniMePacketType, _image_data: &[u8]) {
unimplemented!("Image format is in progress of being worked out")
}
/// Write an Animatrix image
///
/// The expected input here is *two* Vectors, 640 bytes in length. The two vectors
/// are each one half of the full image write.
/// The expected input here is *two* Vectors, 640 bytes in length.
/// The two vectors are each one half of the full image write.
///
/// After each write a flush is written, it is assumed that this tells the device to
/// go ahead and display the written bytes
/// After each write a flush is written, it is assumed that this tells the
/// device to go ahead and display the written bytes
///
/// # Note:
/// The vectors are expected to contain the full sequence of bytes as follows
/// # Note: The vectors are expected to contain the full sequence of bytes
/// as follows
///
/// - Write packet 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. <led brightness>
/// - Write packet 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
pub fn write_image(&mut self, image: &mut AniMePacketType) -> Result<(), Box<dyn Error>> {
if image[0][0] != ANIME_PANE1_PREFIX[0] && image[0][6] != ANIME_PANE1_PREFIX[6] {
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
}
if image[1][0] != ANIME_PANE2_PREFIX[0] && image[1][6] != ANIME_PANE2_PREFIX[6] {
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
}
pub fn write_image(&self, image: &mut AniMePacketType)
-> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Anime", DBUS_IFACE, "SetAnime")?
.append2(image[0].to_vec(), image[1].to_vec());
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
proxy.set_anime(vec![image[0].to_vec(), image[1].to_vec()])?;
thread::sleep(Duration::from_millis(self.block_time));
if self.stop.load(Ordering::Relaxed) {
panic!("Got signal to stop!");
}
Ok(())
}
#[inline]
pub fn set_leds_brightness(&self, led_brightness: u8)
-> Result<(), Box<dyn Error>> {
let mut anime_matrix = AniMeMatrix::new();
anime_matrix.fill_with(led_brightness);
self.write_image(&mut AniMePacketType::from(anime_matrix))?;
Ok(())
}
fn turn_on_off(&self, status : bool) -> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
proxy.set_on_off(status)?;
thread::sleep(Duration::from_millis(self.block_time));
Ok(())
}
#[inline]
pub fn turn_on(&self) -> Result<(), Box<dyn Error>> {
self.turn_on_off(true)?;
Ok(())
}
#[inline]
pub fn turn_off(&self) -> Result<(), Box<dyn Error>> {
self.turn_on_off(false)?;
Ok(())
}
}

View File

@@ -46,9 +46,9 @@ impl AniMeMatrix {
// Write the top block of LEDs (first 7 rows)
if count < 6 {
if count % 2 != 0 {
print!(" ");
print!(" ");
} else {
print!(" ");
print!("");
}
let tmp = if count == 0 || count == 1 || count == 3 || count == 5 {
row[1..].iter()
@@ -56,7 +56,7 @@ impl AniMeMatrix {
row.iter()
};
for x in tmp {
print!(" {}", RGB(*x, *x, *x).paint(&format!("{:#04X}", x)));
print!(" {}", RGB(*x, *x, *x).paint("XY"));
}
println!();
@@ -76,13 +76,13 @@ impl AniMeMatrix {
let index = row.len() - prog_row_len;
if count % 2 == 0 {
print!(" ");
print!(" ");
}
for (i, x) in row.iter().enumerate() {
if i >= index {
print!(" {}", RGB(*x, *x, *x).paint(&format!("{:#04X}", x)));
print!(" {}", RGB(*x, *x, *x).paint("XY"));
} else {
print!(" ");
print!(" ");
}
}
println!();

View File

@@ -5,10 +5,14 @@ use std::str::FromStr;
#[derive(Options)]
pub struct LedBrightness {
level: u8,
level: Option<u8>,
}
impl LedBrightness {
pub fn level(&self) -> u8 {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u8> {
self.level
}
}
@@ -18,17 +22,30 @@ impl FromStr for LedBrightness {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"off" => Ok(LedBrightness { level: 0x00 }),
"low" => Ok(LedBrightness { level: 0x01 }),
"med" => Ok(LedBrightness { level: 0x02 }),
"high" => Ok(LedBrightness { level: 0x03 }),
"off" => Ok(LedBrightness { level: Some(0x00) }),
"low" => Ok(LedBrightness { level: Some(0x01) }),
"med" => Ok(LedBrightness { level: Some(0x02) }),
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
println!("Missing required argument, must be one of:\noff,low,med,high\n");
print!("{}\n{}\n",
"Invalid argument, must be one of:",
"off, low, med, high");
Err(AuraError::ParseBrightness)
}
}
}
}
impl ToString for LedBrightness {
fn to_string(&self) -> String {
let s = match self.level {
Some(0x00) => "low",
Some(0x01) => "med",
Some(0x02) => "high",
_ => "unknown",
};
s.to_string()
}
}
#[derive(Deserialize, Serialize)]
pub struct Colour(pub u8, pub u8, pub u8);
@@ -213,3 +230,25 @@ impl Default for SetAuraBuiltin {
})
}
}
#[derive(Options)]
pub struct AniMeLeds {
#[options(help = "print help message")]
help: bool,
#[options(no_long, required,
short = "b", meta = "BYTE",
help = "set all leds brightness value")]
led_brightness: u8,
}
impl AniMeLeds {
pub fn led_brightness(&self) -> u8 {
self.led_brightness
}
}
#[derive(Options)]
pub enum AniMeActions {
#[options(help = "change all leds brightness")]
Leds(AniMeLeds),
}

View File

@@ -1,8 +1,8 @@
use crate::cli_options::LedBrightness;
use super::*;
use crate::fancy::KeyColourArray;
use crate::profile::ProfileEvent;
use ctrl_gfx::vendors::GfxVendors;
use dbus::channel::Sender;
use dbus::{blocking::Connection, Message};
use std::error::Error;
use std::sync::{
@@ -11,14 +11,22 @@ use std::sync::{
};
use std::{thread, time::Duration};
use crate::dbus_gfx::OrgAsuslinuxDaemonNotifyGfx;
use crate::dbus_ledmode::OrgAsuslinuxDaemonNotifyLed;
use crate::dbus_profile::OrgAsuslinuxDaemonNotifyProfile;
use crate::dbus_charge::OrgAsuslinuxDaemonNotifyCharge;
use crate::dbus_charge::{OrgAsuslinuxDaemonNotifyCharge, OrgAsuslinuxDaemon as OrgAsuslinuxDaemonCharge};
use crate::dbus_gfx::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonGfx, OrgAsuslinuxDaemonNotifyAction,
OrgAsuslinuxDaemonNotifyGfx,
};
use crate::dbus_ledmode::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonLed, OrgAsuslinuxDaemonNotifyLed,
};
use crate::dbus_profile::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonProfile, OrgAsuslinuxDaemonNotifyProfile,
};
// Signals separated out
pub struct CtrlSignals {
pub gfx_signal: Arc<Mutex<Option<String>>>,
pub gfx_vendor_signal: Arc<Mutex<Option<String>>>,
pub gfx_action_signal: Arc<Mutex<Option<String>>>,
pub profile_signal: Arc<Mutex<Option<String>>>,
pub ledmode_signal: Arc<Mutex<Option<AuraModes>>>,
pub charge_signal: Arc<Mutex<Option<u8>>>,
@@ -30,11 +38,11 @@ impl CtrlSignals {
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_millis(5000),
Duration::from_secs(2),
);
let gfx_signal = Arc::new(Mutex::new(None));
let gfx_res1 = gfx_signal.clone();
let gfx_vendor_signal = Arc::new(Mutex::new(None));
let gfx_res1 = gfx_vendor_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyGfx, _: &Connection, _: &Message| {
@@ -45,11 +53,23 @@ impl CtrlSignals {
},
)?;
let gfx_action_signal = Arc::new(Mutex::new(None));
let gfx_res1 = gfx_action_signal.clone();
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyAction, _: &Connection, _: &Message| {
if let Ok(mut lock) = gfx_res1.lock() {
*lock = Some(sig.action);
}
true
},
)?;
//
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_millis(5000),
Duration::from_secs(2),
);
let profile_signal = Arc::new(Mutex::new(None));
@@ -68,7 +88,7 @@ impl CtrlSignals {
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_millis(5000),
Duration::from_secs(2),
);
let ledmode_signal = Arc::new(Mutex::new(None));
@@ -89,7 +109,7 @@ impl CtrlSignals {
let proxy = connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Charge",
Duration::from_millis(5000),
Duration::from_secs(2),
);
let charge_signal = Arc::new(Mutex::new(None));
@@ -98,14 +118,15 @@ impl CtrlSignals {
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyCharge, _: &Connection, _: &Message| {
if let Ok(mut lock) = charge_res1.lock() {
*lock = Some(sig.limit);
*lock = Some(sig.limit);
}
true
},
)?;
Ok(CtrlSignals {
gfx_signal,
gfx_vendor_signal,
gfx_action_signal,
profile_signal,
ledmode_signal,
charge_signal,
@@ -148,8 +169,8 @@ impl AuraDbusClient {
pub fn wait_gfx_changed(&self) -> Result<String, Box<dyn Error>> {
loop {
self.connection.process(Duration::from_micros(500))?;
if let Ok(lock) = self.signals.gfx_signal.lock() {
self.connection.process(Duration::from_millis(1))?;
if let Ok(lock) = self.signals.gfx_action_signal.lock() {
if let Some(stuff) = lock.as_ref() {
return Ok(stuff.to_string());
}
@@ -162,11 +183,12 @@ impl AuraDbusClient {
#[inline]
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
let mode = AuraModes::PerKey(vec![vec![]]);
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(&mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.set_led_mode(&serde_json::to_string(&mode)?)?;
Ok(())
}
@@ -185,13 +207,12 @@ impl AuraDbusClient {
vecs.push(v.to_vec());
}
let mode = AuraModes::PerKey(vecs);
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(&mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
self.write_keyboard_leds(&mode)?;
thread::sleep(Duration::from_micros(self.block_time));
self.connection.process(Duration::from_micros(500))?;
if self.stop.load(Ordering::Relaxed) {
println!("Keyboard backlight was changed, exiting");
std::process::exit(1)
@@ -201,35 +222,89 @@ impl AuraDbusClient {
#[inline]
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.set_led_mode(&serde_json::to_string(mode)?)?;
Ok(())
}
#[inline]
pub fn next_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.next_led_mode()?;
Ok(())
}
#[inline]
pub fn prev_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.prev_led_mode()?;
Ok(())
}
#[inline]
pub fn get_gfx_pwr(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(2),
);
let x = proxy.power()?;
Ok(x)
}
#[inline]
pub fn get_gfx_mode(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(2),
);
let x = proxy.vendor()?;
Ok(x)
}
#[inline]
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_secs(30),
);
proxy.set_vendor(<&str>::from(&vendor))?;
Ok(())
}
#[inline]
pub fn next_fan_profile(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
proxy.next_profile()?;
Ok(())
}
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let mut msg = Message::new_method_call(
DBUS_NAME,
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
DBUS_IFACE,
"SetProfile",
)?
.append1(serde_json::to_string(&ProfileEvent::ChangeMode(level))?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Ok(())
}
#[inline]
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Gfx", DBUS_IFACE, "SetVendor")?
.append1(<&str>::from(&vendor));
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Duration::from_secs(2),
);
proxy.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level))?)?;
Ok(())
}
@@ -238,25 +313,23 @@ impl AuraDbusClient {
&self,
cmd: &ProfileEvent,
) -> Result<(), Box<dyn std::error::Error>> {
let mut msg = Message::new_method_call(
DBUS_NAME,
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
DBUS_IFACE,
"SetProfile",
)?
.append1(serde_json::to_string(cmd)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Duration::from_secs(2),
);
proxy.set_profile(&serde_json::to_string(cmd)?)?;
Ok(())
}
#[inline]
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Charge", DBUS_IFACE, "SetLimit")?
.append1(level);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Charge",
Duration::from_secs(2),
);
proxy.set_limit(level)?;
Ok(())
}
@@ -266,8 +339,21 @@ impl AuraDbusClient {
}
#[inline]
pub fn write_brightness(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
pub fn get_led_brightness(&self) -> Result<LedBrightness, Box<dyn Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
match proxy.led_brightness()? {
-1 => Ok(LedBrightness::new(None)),
level => Ok(LedBrightness::new(Some(level as u8))),
}
}
#[inline]
pub fn write_brightness(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
self.write_keyboard_leds(&AuraModes::LedBrightness(level))?;
Ok(String::new())
Ok(())
}
}

21
asus-nb/src/dbus_anime.rs Normal file
View File

@@ -0,0 +1,21 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Anime -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error>;
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetAnime", (input, ))
}
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetOnOff", (status, ))
}
}

View File

@@ -1,18 +1,29 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Gfx -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus;
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn vendor(&self) -> Result<String, dbus::Error>;
fn power(&self) -> Result<String, dbus::Error>;
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn vendor(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Vendor", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn power(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Power", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetVendor", (vendor,))
self.method_call("org.asuslinux.Daemon", "SetVendor", (vendor, ))
}
}
@@ -29,7 +40,9 @@ impl arg::AppendAll for OrgAsuslinuxDaemonNotifyGfx {
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyGfx {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyGfx { vendor: i.read()? })
Ok(OrgAsuslinuxDaemonNotifyGfx {
vendor: i.read()?,
})
}
}
@@ -37,3 +50,27 @@ impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyGfx {
const NAME: &'static str = "NotifyGfx";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}
#[derive(Debug)]
pub struct OrgAsuslinuxDaemonNotifyAction {
pub action: String,
}
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyAction {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.action, i);
}
}
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyAction {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyAction {
action: i.read()?,
})
}
}
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyAction {
const NAME: &'static str = "NotifyAction";
const INTERFACE: &'static str = "org.asuslinux.Daemon";
}

View File

@@ -6,8 +6,11 @@ use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error>;
fn next_led_mode(&self) -> Result<(), dbus::Error>;
fn prev_led_mode(&self) -> Result<(), dbus::Error>;
fn led_mode(&self) -> Result<String, dbus::Error>;
fn led_modes(&self) -> Result<String, dbus::Error>;
fn led_brightness(&self) -> Result<i16, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
@@ -16,6 +19,14 @@ impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslin
self.method_call("org.asuslinux.Daemon", "SetLedMode", (data, ))
}
fn next_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextLedMode", ())
}
fn prev_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "PrevLedMode", ())
}
fn led_mode(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedMode", ())
.and_then(|r: (String, )| Ok(r.0, ))
@@ -25,6 +36,11 @@ impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslin
self.method_call("org.asuslinux.Daemon", "LedModes", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn led_brightness(&self) -> Result<i16, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedBrightness", ())
.and_then(|r: (i16, )| Ok(r.0, ))
}
}
#[derive(Debug)]

View File

@@ -1,30 +1,40 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Profile -m None`, see https://github.com/diwic/dbus-rs
use dbus;
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Profile -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error>;
fn next_profile(&self) -> Result<(), dbus::Error>;
fn active_profile_name(&self) -> Result<String, dbus::Error>;
fn profile(&self) -> Result<String, dbus::Error>;
fn profiles(&self) -> Result<String, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile,))
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile, ))
}
fn next_profile(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextProfile", ())
}
fn active_profile_name(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "ActiveProfileName", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn profile(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profile", ())
.and_then(|r: (String,)| Ok(r.0))
.and_then(|r: (String, )| Ok(r.0, ))
}
fn profiles(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profiles", ())
.and_then(|r: (String,)| Ok(r.0))
.and_then(|r: (String, )| Ok(r.0, ))
}
}
@@ -41,7 +51,9 @@ impl arg::AppendAll for OrgAsuslinuxDaemonNotifyProfile {
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyProfile {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyProfile { profile: i.read()? })
Ok(OrgAsuslinuxDaemonNotifyProfile {
profile: i.read()?,
})
}
}

View File

@@ -7,6 +7,7 @@ pub enum AuraError {
ParseSpeed,
ParseDirection,
ParseBrightness,
ParseAnime,
}
impl fmt::Display for AuraError {
@@ -17,6 +18,7 @@ impl fmt::Display for AuraError {
AuraError::ParseSpeed => write!(f, "Could not parse speed"),
AuraError::ParseDirection => write!(f, "Could not parse direction"),
AuraError::ParseBrightness => write!(f, "Could not parse brightness"),
AuraError::ParseAnime => write!(f, "Could not parse anime"),
}
}
}

View File

@@ -27,6 +27,7 @@ pub mod dbus_gfx;
pub mod dbus_ledmode;
pub mod dbus_profile;
pub mod dbus_charge;
pub mod dbus_anime;
pub mod error;

View File

@@ -76,6 +76,8 @@ fn parse_fan_curve(data: &str) -> Result<Curve, String> {
pub struct ProfileCommand {
#[options(help = "print help message")]
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,

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-notify"
version = "1.0.0"
version = "2.0.4"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"

View File

@@ -6,6 +6,8 @@ use std::error::Error;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Version {}", env!("CARGO_PKG_VERSION"));
let mut cfg = Config::read_new()?;
let mut last_profile = String::new();
@@ -21,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
std::thread::sleep(Duration::from_millis(100));
connection.process(std::time::Duration::from_millis(200))?;
if let Ok(mut lock) = signals.gfx_signal.lock() {
if let Ok(mut lock) = signals.gfx_vendor_signal.lock() {
if let Some(vendor) = lock.take() {
if let Some(notif) = last_gfx_notif.take() {
notif.close();

View File

@@ -1,6 +1,6 @@
[package]
name = "ctrl-gfx"
version = "2.0.0"
version = "2.1.3"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]

View File

@@ -14,8 +14,8 @@ use crate::{error::GfxError, system::*};
pub struct CtrlGraphics {
bus: PciBus,
amd: Vec<GraphicsDevice>,
intel: Vec<GraphicsDevice>,
_amd: Vec<GraphicsDevice>,
_intel: Vec<GraphicsDevice>,
nvidia: Vec<GraphicsDevice>,
#[allow(dead_code)]
other: Vec<GraphicsDevice>,
@@ -23,8 +23,11 @@ pub struct CtrlGraphics {
}
trait Dbus {
fn vendor(&self) -> String;
fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String);
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>;
}
#[cfg(feature = "use-zbus")]
@@ -33,19 +36,32 @@ use std::convert::TryInto;
#[cfg(feature = "use-zbus")]
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics {
fn vendor(&self) -> String {
Self::get_vendor().unwrap_or_else(|err| format!("Get vendor failed: {}", err))
}
fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
}
fn set_vendor(&mut self, vendor: String) {
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
self.set(tmp).unwrap_or_else(|err| {
let action = self.set(tmp).unwrap_or_else(|err| {
warn!("{}", err);
format!("Failed: {}", err.to_string())
});
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("{}", err));
self.notify_action(&action)
.unwrap_or_else(|err| warn!("{}", err));
}
}
#[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
#[dbus_interface(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()>;
}
impl CtrlGraphics {
@@ -107,17 +123,18 @@ impl CtrlGraphics {
cmd.arg("-u");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'update-initramfs'");
} else if Path::new(DRACUT_PATH).exists() {
let mut cmd = Command::new("dracut");
cmd.arg("-f");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'dracut'");
}
// } else if Path::new(DRACUT_PATH).exists() {
// let mut cmd = Command::new("dracut");
// cmd.arg("-f");
// initfs_cmd = Some(cmd);
// info!("Using initramfs update command 'dracut'");
// }
Ok(CtrlGraphics {
bus,
amd,
intel,
_amd: amd,
_intel: intel,
nvidia,
other,
initfs_cmd,
@@ -128,7 +145,11 @@ impl CtrlGraphics {
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&"/org/asuslinux/Gfx".try_into().unwrap(), self)
.unwrap();
.map_err(|err| {
warn!("CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
pub fn reload(&mut self) -> Result<(), Box<dyn Error>> {
@@ -137,9 +158,9 @@ impl CtrlGraphics {
Ok(())
}
fn can_switch(&self) -> bool {
!self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
}
// fn can_switch(&self) -> bool {
// !self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
// }
fn get_prime_discrete() -> Result<String, GfxError> {
let s = std::fs::read_to_string(PRIME_DISCRETE_PATH)
@@ -162,6 +183,7 @@ impl CtrlGraphics {
.iter()
.any(|module| module.name == "nouveau" || module.name == "nvidia")
{
info!("nvidia or nouveau module found");
let mode = match Self::get_prime_discrete() {
Ok(m) => m,
Err(_) => "nvidia".to_string(),
@@ -175,6 +197,7 @@ impl CtrlGraphics {
"nvidia".to_string()
}
} else {
info!("No dGPU driver (nouveau or nvidia) loaded");
"integrated".to_string()
};
@@ -206,10 +229,10 @@ impl CtrlGraphics {
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
// or a reboot.
let switching_prime_modes = Self::is_switching_prime_modes(&vendor)?;
let no_reboot = Self::is_switching_prime_modes(&vendor)?;
{
info!("Creating {}", MODPROBE_PATH);
info!("Writing {}", MODPROBE_PATH);
let mut file = std::fs::OpenOptions::new()
.create(true)
@@ -233,7 +256,7 @@ impl CtrlGraphics {
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
}
info!("Creating {}", PRIMARY_GPU_XORG_PATH);
info!("Writing {}", PRIMARY_GPU_XORG_PATH);
// begin section for non-separated Nvidia xorg modules
// eg, not put in their own directory
@@ -277,7 +300,7 @@ impl CtrlGraphics {
}
let mut required_action = GfxCtrlAction::None;
if !switching_prime_modes {
if !no_reboot {
info!("Updating initramfs");
if let Some(cmd) = self.initfs_cmd.as_mut() {
let status = cmd
@@ -290,18 +313,23 @@ impl CtrlGraphics {
}
}
required_action = GfxCtrlAction::Reboot;
} else if switching_prime_modes {
} else if no_reboot {
required_action = GfxCtrlAction::RestartX;
}
Ok(required_action.into())
}
pub fn get_power(&self) -> Option<bool> {
if self.can_switch() {
return Some(self.nvidia.iter().any(GraphicsDevice::exists));
}
None
// pub fn get_power(&self) -> Option<bool> {
// if self.can_switch() {
// return Some(self.nvidia.iter().any(GraphicsDevice::exists));
// }
// None
// }
pub fn get_runtime_status() -> Result<String, GfxError> {
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
let buf = std::fs::read_to_string(PATH).map_err(|err| GfxError::Read(PATH.into(), err))?;
Ok(buf)
}
fn set_power(&self, power: bool) -> Result<(), GfxError> {

View File

@@ -9,7 +9,7 @@ pub mod system;
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
const DRACUT_PATH: &str = "/usr/bin/dracut";
// const DRACUT_PATH: &str = "/usr/bin/dracut";
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
@@ -47,7 +47,6 @@ Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "TripleBuffer" "true"
Option "AllowEmptyInitialConfiguration"
Option "AllowExternalGpus""#;
@@ -56,3 +55,4 @@ static PRIMARY_GPU_NVIDIA: &[u8] = br#"
static PRIMARY_GPU_END: &[u8] = br#"
EndSection"#;

View File

@@ -121,7 +121,7 @@ impl GraphicsDevice {
warn!("{}: Already removed", func.id());
}
}
info!("Remmoved all gfx devices");
info!("Removed all gfx devices");
Ok(())
}
}

View File

@@ -1,5 +1,4 @@
Section "ServerLayout"
Identifier "layout"
Option "AllowNVIDIAGPUScreens"
Option "metamodes" "nvidia-auto-select +0+0 {AllowGSYNC=On, AllowGSYNCCompatible=On}"
EndSection

50
data/_asusctl Normal file
View File

@@ -0,0 +1,50 @@
function _asusctl() {
local line
_arguments -C \
{-h,--help}'[print help message]' \
{-v,--version}'[print version number]' \
{-k,--kbd-bright}':[Set keyboard brightness (off, low, med, high)]' \
{-p,--pwr-profile}':[Set power profile (silent, normal, boost)]' \
{-c,--chg-limit}':[Set charging limit (20-100)]' \
': :((led-mode\:"Set the keyboard lighting from built-in modes" profile\:"Create and configure profiles" graphics\:"Set the graphics mode"))' \
'*::arg:->args'
case $line[1] in
led-mode)
_arguments ': :((static\:"set a single static colour"
breathe\:"pulse between one or two colours"
strobe\:"strobe through all colours"
rainbow\:"rainbow cycling in one of four directions"
star\:"rain pattern mimicking raindrops"
rain\:"rain pattern of three preset colours"
highlight\:"pressed keys are highlighted to fade"
laser\:"pressed keys generate horizontal laser"
ripple\:"pressed keys ripple outwards like a splash"
pulse\:"set a rapid pulse"
comet\:"set a vertical line zooming from left"
flash\:"set a wide vertical line zooming from left"
multi-static\:"4-zone multi-colour"))' \
{-h,--help}'[print help message]' \
'-c:[set the RGB value e.g, ff00ff]' \
'-s:[set the speed (low, med, high)]'
;;
profile)
_arguments {-h,--help}'[print help message]' \
{-c,--create}"[create the profile if it doesn't exist]" \
{-t,--turbo}':[enable or disable cpu turbo]' \
{-m,--min-percentage}':[set min cpu scaling (intel)]' \
{-M,--max-percentage}':[set max cpu scaling (intel)]' \
{-p,--preset}':[<silent, normal, boost>]' \
{-C,--curve}':[set fan curve]'
;;
graphics)
_arguments {-h,--help}'[print help message]' \
{-m,--mode}':[Set graphics mode (nvidia, hybrid, compute, integrated)]' \
{-g,--get}'[Get the current mode]' \
{-p,--pow}'[Get the current power status]' \
{-f,--force}'[Do not ask for confirmation]'
;;
esac
}
compdef _asusctl asusctl

View File

@@ -4,9 +4,9 @@ StartLimitInterval=200
StartLimitBurst=2
[Service]
ExecStartPre=/usr/bin/sleep 2
ExecStart=/usr/bin/asus-notify
Restart=on-failure
Restart=always
RestartSec=1
Type=simple

12
data/asusd-alt.service Normal file
View File

@@ -0,0 +1,12 @@
[Unit]
Description=ASUS Notebook Control
After=basic.target syslog.target
[Service]
ExecStart=/usr/bin/asusd
Restart=on-failure
Type=dbus
BusName=org.asuslinux.Daemon
[Install]
WantedBy=multi-user.target

View File

@@ -3,6 +3,11 @@ prod_family = "Zephyrus S"
board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "Zephyrus M"
board_names = ["GU502GV"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "Zephyrus"
board_names = ["GM501GM", "GX531"]