Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb173fc9dc | ||
|
|
50756046cf | ||
|
|
629bdc2213 | ||
|
|
39bbe33831 | ||
|
|
00bd556d7a | ||
|
|
12061ea9df | ||
|
|
580ed72e73 | ||
|
|
c01f0892a5 | ||
|
|
0fed34b12e | ||
|
|
0af68baf7b | ||
|
|
161e3c4d3b | ||
|
|
4720af2cb8 | ||
|
|
06d37aa009 | ||
|
|
c6fa860b2e | ||
|
|
4fe9ab70e5 | ||
|
|
920e4e86f5 | ||
|
|
720dc0c177 | ||
|
|
b3a555cab9 | ||
|
|
cf13b4f71b | ||
|
|
cd0b9fe350 | ||
|
|
82900f4645 | ||
|
|
703bba9ffd | ||
|
|
73706154a4 | ||
|
|
c9b2a0c777 | ||
|
|
54cc51fe5d | ||
|
|
81645d0777 | ||
|
|
d61c180ee5 | ||
|
|
a668800fd9 | ||
|
|
3bdc11c994 | ||
|
|
b496139063 | ||
|
|
607483629a | ||
|
|
5c8d138cef | ||
|
|
e3db1f7c4c |
@@ -13,7 +13,7 @@ test:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
only:
|
only:
|
||||||
- next
|
- main
|
||||||
script:
|
script:
|
||||||
- make && make vendor
|
- make && make vendor
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|||||||
48
CHANGELOG.md
@@ -5,6 +5,54 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
# [3.0.0] - 2021-02-14
|
||||||
|
### Changed
|
||||||
|
- Write set+apply after each array in multizone
|
||||||
|
- Remove misc bad logic
|
||||||
|
- Use same code path as 0x1866 device to configure led support for 0x1854 device
|
||||||
|
- Remove duplicate code
|
||||||
|
- Set correct speeds for multizone
|
||||||
|
- Remove dbus crate in favour of zbus. This removes the external dbus lib requirement.
|
||||||
|
- Huge internal refactor
|
||||||
|
- BREAKING CHANGE: Anime code refactor. DBUS method names have changed
|
||||||
|
- Cleanup fan and cpu control + configs
|
||||||
|
|
||||||
|
# [2.2.2] - 2021-01-31
|
||||||
|
### Changed
|
||||||
|
- Fix for dedicated gfx capable laptops in integrated mode
|
||||||
|
- Fix for 0x1854 device
|
||||||
|
|
||||||
|
# [2.2.1] - 2021-01-27
|
||||||
|
### Added
|
||||||
|
- Add ROG Zephyrus M15 LED config
|
||||||
|
### Changed
|
||||||
|
- Bugfixes
|
||||||
|
- Fix reboot/restartx status for GFX switching
|
||||||
|
- Update readme
|
||||||
|
- Change CLI arg tag for fan modes
|
||||||
|
- Make dracut include the nvidia modules in initramfs
|
||||||
|
|
||||||
|
# [2.2.0] - 2021-01-26
|
||||||
|
### Added
|
||||||
|
- Dbus command to fetch all supported functions of the laptop. That is, all the
|
||||||
|
functions that asusd supports for the currently running laptop.
|
||||||
|
- Bios setting toggles for:
|
||||||
|
+ Dedicated gfx toggle (support depends on the laptop)
|
||||||
|
+ Bios boot POST sound toggle
|
||||||
|
### Changed
|
||||||
|
- added config option for dedicated gfx mode on laptops with it to enable
|
||||||
|
switching directly to dedicated using `asusctl graphics -m nvidia`
|
||||||
|
|
||||||
|
# [2.1.2] - 2021-01-10
|
||||||
|
### Changed
|
||||||
|
- Adjust gfx controller to assume that the graphics driver is loaded if the
|
||||||
|
mode is set for nvidia/hybrid
|
||||||
|
|
||||||
|
# [2.1.1] - 2021-01-09
|
||||||
|
### Changed
|
||||||
|
- Updates to dependencies
|
||||||
|
|
||||||
# [2.1.0] - 2020-10-25
|
# [2.1.0] - 2020-10-25
|
||||||
### Added
|
### Added
|
||||||
- Option to turn off AniMe display (@asere)
|
- Option to turn off AniMe display (@asere)
|
||||||
|
|||||||
695
Cargo.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["asus-notify", "asus-nb-ctrl", "asus-nb", "ctrl-gfx"]
|
members = ["asusctl", "asus-notify", "daemon", "rog-types", "rog-dbus"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
90
Makefile
@@ -1,36 +1,37 @@
|
|||||||
prefix ?= /usr
|
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2)
|
||||||
sysconfdir ?= /etc
|
|
||||||
|
INSTALL = install
|
||||||
|
INSTALL_PROGRAM = ${INSTALL} -D -m 0755
|
||||||
|
INSTALL_DATA = ${INSTALL} -D -m 0644
|
||||||
|
|
||||||
|
prefix = /usr
|
||||||
exec_prefix = $(prefix)
|
exec_prefix = $(prefix)
|
||||||
bindir = $(exec_prefix)/bin
|
bindir = $(exec_prefix)/bin
|
||||||
libdir = $(exec_prefix)/lib
|
|
||||||
includedir = $(prefix)/include
|
|
||||||
datarootdir = $(prefix)/share
|
datarootdir = $(prefix)/share
|
||||||
datadir = $(datarootdir)
|
libdir = $(exec_prefix)/lib
|
||||||
|
zshcpl = $(datarootdir)/zsh/site-functions
|
||||||
|
|
||||||
SRC = Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
|
BIN_C := asusctl
|
||||||
|
BIN_D := asusd
|
||||||
|
BIN_N := asus-notify
|
||||||
|
LEDCFG := asusd-ledmodes.toml
|
||||||
|
X11CFG := 90-nvidia-screen-G05.conf
|
||||||
|
PMRULES := 90-asusd-nvidia-pm.rules
|
||||||
|
|
||||||
.PHONY: all clean distclean install uninstall update
|
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
|
||||||
|
|
||||||
BIN_C=asusctl
|
|
||||||
BIN_D=asusd
|
|
||||||
BIN_N=asus-notify
|
|
||||||
LEDCFG=asusd-ledmodes.toml
|
|
||||||
X11CFG=90-nvidia-screen-G05.conf
|
|
||||||
PMRULES=90-asusd-nvidia-pm.rules
|
|
||||||
VERSION:=$(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
|
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
ifeq ($(DEBUG),0)
|
ifeq ($(DEBUG),0)
|
||||||
ARGS += "--release"
|
ARGS += --release
|
||||||
TARGET = release
|
TARGET = release
|
||||||
endif
|
endif
|
||||||
|
|
||||||
VENDORED ?= 0
|
VENDORED ?= 0
|
||||||
ifeq ($(VENDORED),1)
|
ifeq ($(VENDORED),1)
|
||||||
ARGS += "--frozen"
|
ARGS += --frozen
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: target/release/$(BIN_D)
|
all: build
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
cargo clean
|
cargo clean
|
||||||
@@ -38,34 +39,37 @@ clean:
|
|||||||
distclean:
|
distclean:
|
||||||
rm -rf .cargo vendor vendor.tar.xz
|
rm -rf .cargo vendor vendor.tar.xz
|
||||||
|
|
||||||
install: all
|
install:
|
||||||
install -D -m 0755 "target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
$(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||||
install -D -m 0755 "target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||||
install -D -m 0755 "target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
|
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||||
install -D -m 0644 "data/$(PMRULES)" "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
|
$(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
|
||||||
install -D -m 0644 "data/$(BIN_D).rules" "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
|
||||||
install -D -m 0644 "data/$(LEDCFG)" "$(DESTDIR)$(sysconfdir)/asusd/$(LEDCFG)"
|
$(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)"
|
||||||
install -D -m 0644 "data/$(BIN_D).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
$(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||||
install -D -m 0644 "data/$(X11CFG)" "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
|
$(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
|
||||||
install -D -m 0644 "data/$(BIN_D).service" "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
|
||||||
install -D -m 0644 "data/$(BIN_N).service" "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
|
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
|
||||||
install -D -m 0644 "data/icons/asus_notif_yellow.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/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_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/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_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||||
install -D -m 0644 "data/_asusctl" "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
|
$(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl"
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||||
rm -f "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
|
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
|
||||||
rm -f "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
|
||||||
rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
rm -f "$(DESTDIR)/etc/asusd/$(LEDCFG)"
|
||||||
rm -f "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
|
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||||
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
rm -f "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
|
||||||
rm -r "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
|
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
|
||||||
rm -r "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_*"
|
rm -r "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
|
||||||
rm -f "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
|
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
||||||
|
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
|
||||||
|
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||||
|
rm -f "$(DESTDIR)$(zshcpl)/_asusctl"
|
||||||
|
|
||||||
update:
|
update:
|
||||||
cargo update
|
cargo update
|
||||||
@@ -79,9 +83,11 @@ vendor:
|
|||||||
tar pcfJ vendor_asus-nb-ctrl_$(VERSION).tar.xz vendor
|
tar pcfJ vendor_asus-nb-ctrl_$(VERSION).tar.xz vendor
|
||||||
rm -rf vendor
|
rm -rf vendor
|
||||||
|
|
||||||
target/release/$(BIN_D): $(SRC)
|
build:
|
||||||
ifeq ($(VENDORED),1)
|
ifeq ($(VENDORED),1)
|
||||||
@echo "version = $(VERSION)"
|
@echo "version = $(VERSION)"
|
||||||
tar pxf vendor_asus-nb-ctrl_$(VERSION).tar.xz
|
tar pxf vendor_asus-nb-ctrl_$(VERSION).tar.xz
|
||||||
endif
|
endif
|
||||||
cargo build $(ARGS)
|
cargo build $(ARGS)
|
||||||
|
|
||||||
|
.PHONY: all clean distclean install uninstall update build
|
||||||
|
|||||||
28
README.md
@@ -7,6 +7,10 @@ but can also be used with non-asus laptops with reduced features.
|
|||||||
|
|
||||||
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
|
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
|
||||||
|
|
||||||
|
**NOTICE:**
|
||||||
|
The following is *not* required for 5.11 kernel versions, as this version includes
|
||||||
|
all the required patches.
|
||||||
|
---
|
||||||
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
|
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
|
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/).
|
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
|
||||||
@@ -25,7 +29,7 @@ in to the kernel.
|
|||||||
|
|
||||||
## Discord
|
## Discord
|
||||||
|
|
||||||
[Discord server link](https://discord.gg/PVyFzWj)
|
[Discord server link](https://discord.gg/ngbdKabAnP)
|
||||||
|
|
||||||
## SUPPORTED LAPTOPS
|
## SUPPORTED LAPTOPS
|
||||||
|
|
||||||
@@ -53,13 +57,17 @@ will probably suffer another rename once it becomes generic enough to do so.
|
|||||||
- [X] Set battery charge limit (with kernel supporting this)
|
- [X] Set battery charge limit (with kernel supporting this)
|
||||||
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
|
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
|
||||||
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
|
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
|
||||||
|
- [X] Toggle bios setting for boot/POST sound
|
||||||
|
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
|
||||||
|
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|
||||||
## Graphics switching
|
## Graphics switching
|
||||||
|
|
||||||
A new feature has been added to enable switching graphics modes. This can be disabled
|
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.
|
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.
|
||||||
|
|
||||||
The CLI option for this does not require root until it asks for it, and provides
|
The CLI option for this does not require root until it asks for it, and provides
|
||||||
instructions.
|
instructions.
|
||||||
@@ -79,7 +87,8 @@ If you have installed the Nvidia driver manually you will require the
|
|||||||
### fedora and openSUSE
|
### fedora and openSUSE
|
||||||
|
|
||||||
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
|
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.
|
to stop dracut including the nvidia modules in the ramdisk. This is espeically
|
||||||
|
true if you manually installed the nvidia drivers.
|
||||||
|
|
||||||
```
|
```
|
||||||
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
|
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
|
||||||
@@ -133,14 +142,11 @@ To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profil
|
|||||||
|
|
||||||
# BUILDING
|
# BUILDING
|
||||||
|
|
||||||
Requirements are:
|
Requirements are rust >= 1.40 installed from rustup.io if the distro provided version is too old, and `make`.
|
||||||
|
|
||||||
- `rustc` + `cargo` + `make`
|
**Ubuntu*:** `apt install libclang-dev libudev-dev`
|
||||||
- `libusb-1.0-0-dev`
|
|
||||||
- `libdbus-1-dev`
|
**fedora:** `dnf install clang-devel systemd-devel`
|
||||||
- `llvm`
|
|
||||||
- `libclang-dev`
|
|
||||||
- `libudev-dev`
|
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@@ -148,6 +154,8 @@ Packaging and auto-builds are available [here](https://build.opensuse.org/packag
|
|||||||
|
|
||||||
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
|
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
|
||||||
|
|
||||||
|
Alternatively check the releases page for f33 RPM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Run `make` then `sudo make install` then reboot.
|
Run `make` then `sudo make install` then reboot.
|
||||||
|
|||||||
1016
asus-nb-ctrl/Cargo.lock
generated
@@ -1,168 +0,0 @@
|
|||||||
use asus_nb::aura_modes::AuraModes;
|
|
||||||
use log::{error, warn};
|
|
||||||
use rog_fan_curve::Curve;
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fs::{File, OpenOptions};
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
|
|
||||||
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
|
||||||
pub struct Config {
|
|
||||||
pub gfx_managed: bool,
|
|
||||||
pub active_profile: String,
|
|
||||||
pub toggle_profiles: Vec<String>,
|
|
||||||
// TODO: remove power_profile
|
|
||||||
pub power_profile: u8,
|
|
||||||
pub bat_charge_limit: u8,
|
|
||||||
pub kbd_led_brightness: u8,
|
|
||||||
pub kbd_backlight_mode: u8,
|
|
||||||
pub kbd_backlight_modes: Vec<AuraModes>,
|
|
||||||
pub power_profiles: BTreeMap<String, Profile>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
/// `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)
|
|
||||||
.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 {}", CONFIG_PATH);
|
|
||||||
panic!("Please remove {} then restart asusd", CONFIG_PATH);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
|
|
||||||
// create a default config here
|
|
||||||
let mut config = Config::default();
|
|
||||||
config.gfx_managed = true;
|
|
||||||
|
|
||||||
config.bat_charge_limit = 100;
|
|
||||||
config.kbd_backlight_mode = 0;
|
|
||||||
config.kbd_led_brightness = 1;
|
|
||||||
|
|
||||||
for n in supported_led_modes {
|
|
||||||
config.kbd_backlight_modes.push(AuraModes::from(*n))
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
profile.fan_preset = 2;
|
|
||||||
config.power_profiles.insert("silent".into(), profile);
|
|
||||||
|
|
||||||
config.toggle_profiles.push("normal".into());
|
|
||||||
config.toggle_profiles.push("boost".into());
|
|
||||||
config.toggle_profiles.push("silent".into());
|
|
||||||
config.active_profile = "normal".into();
|
|
||||||
|
|
||||||
// Should be okay to unwrap this as is since it is a Default
|
|
||||||
let json = serde_json::to_string_pretty(&config).unwrap();
|
|
||||||
file.write_all(json.as_bytes())
|
|
||||||
.unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH));
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self) {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.open(&CONFIG_PATH)
|
|
||||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
|
|
||||||
let mut buf = String::new();
|
|
||||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
|
||||||
if l == 0 {
|
|
||||||
warn!("File is empty {}", CONFIG_PATH);
|
|
||||||
} else {
|
|
||||||
let x: Config = serde_json::from_str(&buf)
|
|
||||||
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
|
||||||
*self = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_new() -> Result<Config, Box<dyn std::error::Error>> {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.open(&CONFIG_PATH)
|
|
||||||
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
|
|
||||||
let mut buf = String::new();
|
|
||||||
file.read_to_string(&mut buf)?;
|
|
||||||
let x: Config = serde_json::from_str(&buf)?;
|
|
||||||
Ok(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&self) {
|
|
||||||
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
|
||||||
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
|
||||||
file.write_all(json.as_bytes())
|
|
||||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_mode_data(&mut self, mode: AuraModes) {
|
|
||||||
let byte: u8 = (&mode).into();
|
|
||||||
for (index, n) in self.kbd_backlight_modes.iter().enumerate() {
|
|
||||||
if byte == u8::from(n) {
|
|
||||||
// Consume it, OMNOMNOMNOM
|
|
||||||
self.kbd_backlight_modes[index] = mode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
|
|
||||||
for mode in &self.kbd_backlight_modes {
|
|
||||||
if u8::from(mode) == num {
|
|
||||||
return Some(mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct Profile {
|
|
||||||
pub min_percentage: u8,
|
|
||||||
pub max_percentage: u8,
|
|
||||||
pub turbo: bool,
|
|
||||||
pub fan_preset: u8,
|
|
||||||
pub fan_curve: Option<Curve>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated]
|
|
||||||
pub type CPUSettings = Profile;
|
|
||||||
|
|
||||||
impl Default for Profile {
|
|
||||||
fn default() -> Self {
|
|
||||||
Profile {
|
|
||||||
min_percentage: 0,
|
|
||||||
max_percentage: 100,
|
|
||||||
turbo: false,
|
|
||||||
fan_preset: 0,
|
|
||||||
fan_curve: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#![deny(unused_must_use)]
|
|
||||||
/// Configuration loading, saving
|
|
||||||
pub mod config;
|
|
||||||
///
|
|
||||||
pub mod ctrl_anime;
|
|
||||||
///
|
|
||||||
pub mod ctrl_charge;
|
|
||||||
///
|
|
||||||
pub mod ctrl_fan_cpu;
|
|
||||||
///
|
|
||||||
pub mod ctrl_leds;
|
|
||||||
///
|
|
||||||
/// Laptop matching to determine capabilities
|
|
||||||
pub mod laptops;
|
|
||||||
|
|
||||||
mod error;
|
|
||||||
|
|
||||||
use config::Config;
|
|
||||||
use crate::error::RogError;
|
|
||||||
use zbus::ObjectServer;
|
|
||||||
|
|
||||||
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
|
|
||||||
pub trait Reloadable {
|
|
||||||
fn reload(&mut self) -> Result<(), RogError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ZbusAdd {
|
|
||||||
fn add_to_server(self, server: &mut ObjectServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CtrlTask {
|
|
||||||
fn do_task(&mut self) -> Result<(), RogError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CtrlTaskComplex {
|
|
||||||
type A;
|
|
||||||
|
|
||||||
fn do_task(&mut self, config: &mut Config, event: Self::A);
|
|
||||||
}
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
use asus_nb::{
|
|
||||||
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::{Opt, Options};
|
|
||||||
use log::LevelFilter;
|
|
||||||
use std::{env::args, io::Write, process::Command};
|
|
||||||
use yansi_term::Colour::Green;
|
|
||||||
use yansi_term::Colour::Red;
|
|
||||||
|
|
||||||
#[derive(Default, Options)]
|
|
||||||
struct CLIStart {
|
|
||||||
#[options(help_flag, help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(help = "show program version number")]
|
|
||||||
version: bool,
|
|
||||||
#[options(meta = "VAL", help = "<off, low, med, high>")]
|
|
||||||
kbd_bright: Option<LedBrightness>,
|
|
||||||
#[options(meta = "PWR", help = "<silent, normal, boost>")]
|
|
||||||
pwr_profile: Option<FanLevel>,
|
|
||||||
#[options(meta = "CHRG", help = "<20-100>")]
|
|
||||||
chg_limit: Option<u8>,
|
|
||||||
#[options(command)]
|
|
||||||
command: Option<CliCommand>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Options)]
|
|
||||||
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(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
|
|
||||||
.target(env_logger::Target::Stdout)
|
|
||||||
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
|
|
||||||
.filter(None, LevelFilter::Info)
|
|
||||||
.init();
|
|
||||||
|
|
||||||
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(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(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 {
|
|
||||||
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)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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!(
|
|
||||||
"{}",
|
|
||||||
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")
|
|
||||||
);
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
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::{thread, time::Duration};
|
|
||||||
|
|
||||||
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 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AniMeDbusWriter {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
|
||||||
let connection = Connection::new_system()?;
|
|
||||||
Ok(AniMeDbusWriter {
|
|
||||||
connection: Box::new(connection),
|
|
||||||
block_time: 25,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
///
|
|
||||||
/// After each write a flush is written, it is assumed that this tells the
|
|
||||||
/// device to go ahead and display the written bytes
|
|
||||||
///
|
|
||||||
/// # Note: The vectors are expected to contain the full sequence of bytes
|
|
||||||
/// as follows
|
|
||||||
///
|
|
||||||
/// - Write 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(&self, image: &mut AniMePacketType)
|
|
||||||
-> Result<(), Box<dyn Error>> {
|
|
||||||
let proxy = self.new_proxy();
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
use crate::error::AuraError;
|
|
||||||
use gumdrop::Options;
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[derive(Options)]
|
|
||||||
pub struct LedBrightness {
|
|
||||||
level: Option<u8>,
|
|
||||||
}
|
|
||||||
impl LedBrightness {
|
|
||||||
pub fn new(level: Option<u8>) -> Self {
|
|
||||||
LedBrightness { level }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn level(&self) -> Option<u8> {
|
|
||||||
self.level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for LedBrightness {
|
|
||||||
type Err = AuraError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let s = s.to_lowercase();
|
|
||||||
match s.as_str() {
|
|
||||||
"off" => Ok(LedBrightness { level: Some(0x00) }),
|
|
||||||
"low" => Ok(LedBrightness { level: Some(0x01) }),
|
|
||||||
"med" => Ok(LedBrightness { level: Some(0x02) }),
|
|
||||||
"high" => Ok(LedBrightness { level: Some(0x03) }),
|
|
||||||
_ => {
|
|
||||||
print!("{}\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);
|
|
||||||
impl Default for Colour {
|
|
||||||
fn default() -> Self {
|
|
||||||
Colour(255, 0, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for Colour {
|
|
||||||
type Err = AuraError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
if s.len() < 6 {
|
|
||||||
return Err(AuraError::ParseColour);
|
|
||||||
}
|
|
||||||
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
|
|
||||||
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
|
|
||||||
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
|
|
||||||
Ok(Colour(r, g, b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub enum Speed {
|
|
||||||
Low = 0xe1,
|
|
||||||
Med = 0xeb,
|
|
||||||
High = 0xf5,
|
|
||||||
}
|
|
||||||
impl Default for Speed {
|
|
||||||
fn default() -> Self {
|
|
||||||
Speed::Med
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for Speed {
|
|
||||||
type Err = AuraError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let s = s.to_lowercase();
|
|
||||||
match s.as_str() {
|
|
||||||
"low" => Ok(Speed::Low),
|
|
||||||
"med" => Ok(Speed::Med),
|
|
||||||
"high" => Ok(Speed::High),
|
|
||||||
_ => Err(AuraError::ParseSpeed),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used for Rainbow mode.
|
|
||||||
///
|
|
||||||
/// Enum corresponds to the required integer value
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub enum Direction {
|
|
||||||
Right,
|
|
||||||
Left,
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
}
|
|
||||||
impl Default for Direction {
|
|
||||||
fn default() -> Self {
|
|
||||||
Direction::Right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for Direction {
|
|
||||||
type Err = AuraError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let s = s.to_lowercase();
|
|
||||||
match s.as_str() {
|
|
||||||
"right" => Ok(Direction::Right),
|
|
||||||
"up" => Ok(Direction::Up),
|
|
||||||
"down" => Ok(Direction::Down),
|
|
||||||
"left" => Ok(Direction::Left),
|
|
||||||
_ => Err(AuraError::ParseDirection),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct TwoColourSpeed {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(no_long, meta = "HEX", help = "set the first RGB value e.g, ff00ff")]
|
|
||||||
pub colour: Colour,
|
|
||||||
#[options(no_long, meta = "HEX", help = "set the second RGB value e.g, ff00ff")]
|
|
||||||
pub colour2: Colour,
|
|
||||||
#[options(no_long, help = "set the speed: low, med, high")]
|
|
||||||
pub speed: Speed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct SingleSpeed {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
|
|
||||||
pub speed: Speed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct SingleColour {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(no_long, meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour: Colour,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct MultiColour {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour1: Colour,
|
|
||||||
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour2: Colour,
|
|
||||||
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour3: Colour,
|
|
||||||
#[options(meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour4: Colour,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct SingleSpeedDirection {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(
|
|
||||||
no_long,
|
|
||||||
meta = "DIR",
|
|
||||||
help = "set the direction: up, down, left, right"
|
|
||||||
)]
|
|
||||||
pub direction: Direction,
|
|
||||||
#[options(no_long, help = "set the speed: low, med, high")]
|
|
||||||
pub speed: Speed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Options, Deserialize, Serialize)]
|
|
||||||
pub struct SingleColourSpeed {
|
|
||||||
#[options(help = "print help message")]
|
|
||||||
help: bool,
|
|
||||||
#[options(no_long, meta = "HEX", help = "set the RGB value e.g, ff00ff")]
|
|
||||||
pub colour: Colour,
|
|
||||||
#[options(no_long, help = "set the speed: low, med, high")]
|
|
||||||
pub speed: Speed,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Byte value for setting the built-in mode.
|
|
||||||
///
|
|
||||||
/// Enum corresponds to the required integer value
|
|
||||||
#[derive(Options, Deserialize, Serialize)]
|
|
||||||
pub enum SetAuraBuiltin {
|
|
||||||
#[options(help = "set a single static colour")]
|
|
||||||
Static(SingleColour),
|
|
||||||
#[options(help = "pulse between one or two colours")]
|
|
||||||
Breathe(TwoColourSpeed),
|
|
||||||
#[options(help = "strobe through all colours")]
|
|
||||||
Strobe(SingleSpeed),
|
|
||||||
#[options(help = "rainbow cycling in one of four directions")]
|
|
||||||
Rainbow(SingleSpeedDirection),
|
|
||||||
#[options(help = "rain pattern mimicking raindrops")]
|
|
||||||
Star(TwoColourSpeed),
|
|
||||||
#[options(help = "rain pattern of three preset colours")]
|
|
||||||
Rain(SingleSpeed),
|
|
||||||
#[options(help = "pressed keys are highlighted to fade")]
|
|
||||||
Highlight(SingleColourSpeed),
|
|
||||||
#[options(help = "pressed keys generate horizontal laser")]
|
|
||||||
Laser(SingleColourSpeed),
|
|
||||||
#[options(help = "pressed keys ripple outwards like a splash")]
|
|
||||||
Ripple(SingleColourSpeed),
|
|
||||||
#[options(help = "set a rapid pulse")]
|
|
||||||
Pulse(SingleColour),
|
|
||||||
#[options(help = "set a vertical line zooming from left")]
|
|
||||||
Comet(SingleColour),
|
|
||||||
#[options(help = "set a wide vertical line zooming from left")]
|
|
||||||
Flash(SingleColour),
|
|
||||||
#[options(help = "4-zone multi-colour")]
|
|
||||||
MultiStatic(MultiColour),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SetAuraBuiltin {
|
|
||||||
fn default() -> Self {
|
|
||||||
SetAuraBuiltin::Static(SingleColour {
|
|
||||||
help: false,
|
|
||||||
colour: Colour(255, 0, 0),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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),
|
|
||||||
}
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
use crate::cli_options::LedBrightness;
|
|
||||||
use super::*;
|
|
||||||
use crate::fancy::KeyColourArray;
|
|
||||||
use crate::profile::ProfileEvent;
|
|
||||||
use ctrl_gfx::vendors::GfxVendors;
|
|
||||||
use dbus::{blocking::Connection, Message};
|
|
||||||
use std::error::Error;
|
|
||||||
use std::sync::{
|
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc, Mutex,
|
|
||||||
};
|
|
||||||
use std::{thread, time::Duration};
|
|
||||||
|
|
||||||
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_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>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CtrlSignals {
|
|
||||||
#[inline]
|
|
||||||
pub fn new(connection: &Connection) -> Result<Self, Box<dyn Error>> {
|
|
||||||
let proxy = connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Gfx",
|
|
||||||
Duration::from_secs(2),
|
|
||||||
);
|
|
||||||
|
|
||||||
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| {
|
|
||||||
if let Ok(mut lock) = gfx_res1.lock() {
|
|
||||||
*lock = Some(sig.vendor);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
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_secs(2),
|
|
||||||
);
|
|
||||||
|
|
||||||
let profile_signal = Arc::new(Mutex::new(None));
|
|
||||||
let prof_res1 = profile_signal.clone();
|
|
||||||
|
|
||||||
let _x = proxy.match_signal(
|
|
||||||
move |sig: OrgAsuslinuxDaemonNotifyProfile, _: &Connection, _: &Message| {
|
|
||||||
if let Ok(mut lock) = prof_res1.lock() {
|
|
||||||
*lock = Some(sig.profile);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
//
|
|
||||||
let proxy = connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Led",
|
|
||||||
Duration::from_secs(2),
|
|
||||||
);
|
|
||||||
|
|
||||||
let ledmode_signal = Arc::new(Mutex::new(None));
|
|
||||||
let led_res1 = ledmode_signal.clone();
|
|
||||||
|
|
||||||
let _x = proxy.match_signal(
|
|
||||||
move |sig: OrgAsuslinuxDaemonNotifyLed, _: &Connection, _: &Message| {
|
|
||||||
if let Ok(mut lock) = led_res1.lock() {
|
|
||||||
if let Ok(dat) = serde_json::from_str(&sig.data) {
|
|
||||||
*lock = Some(dat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
//
|
|
||||||
let proxy = connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Charge",
|
|
||||||
Duration::from_secs(2),
|
|
||||||
);
|
|
||||||
|
|
||||||
let charge_signal = Arc::new(Mutex::new(None));
|
|
||||||
let charge_res1 = charge_signal.clone();
|
|
||||||
|
|
||||||
let _x = proxy.match_signal(
|
|
||||||
move |sig: OrgAsuslinuxDaemonNotifyCharge, _: &Connection, _: &Message| {
|
|
||||||
if let Ok(mut lock) = charge_res1.lock() {
|
|
||||||
*lock = Some(sig.limit);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(CtrlSignals {
|
|
||||||
gfx_vendor_signal,
|
|
||||||
gfx_action_signal,
|
|
||||||
profile_signal,
|
|
||||||
ledmode_signal,
|
|
||||||
charge_signal,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simplified way to write a effect block
|
|
||||||
pub struct AuraDbusClient {
|
|
||||||
connection: Box<Connection>,
|
|
||||||
block_time: u64,
|
|
||||||
stop: Arc<AtomicBool>,
|
|
||||||
signals: CtrlSignals,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuraDbusClient {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
|
||||||
let connection = Connection::new_system()?;
|
|
||||||
|
|
||||||
let stop = Arc::new(AtomicBool::new(false));
|
|
||||||
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "NotifyLed");
|
|
||||||
let stop1 = stop.clone();
|
|
||||||
connection.add_match(match_rule, move |_: (), _, msg| {
|
|
||||||
if msg.read1::<&str>().is_ok() {
|
|
||||||
stop1.clone().store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let signals = CtrlSignals::new(&connection)?;
|
|
||||||
|
|
||||||
Ok(AuraDbusClient {
|
|
||||||
connection: Box::new(connection),
|
|
||||||
block_time: 33333,
|
|
||||||
stop,
|
|
||||||
signals,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait_gfx_changed(&self) -> Result<String, Box<dyn Error>> {
|
|
||||||
loop {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method must always be called before the very first write to initialise
|
|
||||||
/// the keyboard LED EC in the correct mode
|
|
||||||
#[inline]
|
|
||||||
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mode = AuraModes::PerKey(vec![vec![]]);
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write a single colour block.
|
|
||||||
///
|
|
||||||
/// Intentionally blocks for 10ms after sending to allow the block to
|
|
||||||
/// be written to the keyboard EC. This should not be async.
|
|
||||||
#[inline]
|
|
||||||
pub fn write_colour_block(
|
|
||||||
&mut self,
|
|
||||||
key_colour_array: &KeyColourArray,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let group = key_colour_array.get();
|
|
||||||
let mut vecs = Vec::with_capacity(group.len());
|
|
||||||
for v in group {
|
|
||||||
vecs.push(v.to_vec());
|
|
||||||
}
|
|
||||||
let mode = AuraModes::PerKey(vecs);
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
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 proxy = self.connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Profile",
|
|
||||||
Duration::from_secs(2),
|
|
||||||
);
|
|
||||||
proxy.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level))?)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn write_profile_command(
|
|
||||||
&self,
|
|
||||||
cmd: &ProfileEvent,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let proxy = self.connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Profile",
|
|
||||||
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 proxy = self.connection.with_proxy(
|
|
||||||
"org.asuslinux.Daemon",
|
|
||||||
"/org/asuslinux/Charge",
|
|
||||||
Duration::from_secs(2),
|
|
||||||
);
|
|
||||||
proxy.set_limit(level)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn write_builtin_mode(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
self.write_keyboard_leds(mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// 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, ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Charge -m None`, 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_limit(&self, limit: u8) -> Result<(), dbus::Error>;
|
|
||||||
fn limit(&self) -> Result<i16, dbus::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
|
|
||||||
|
|
||||||
fn set_limit(&self, limit: u8) -> Result<(), dbus::Error> {
|
|
||||||
self.method_call("org.asuslinux.Daemon", "SetLimit", (limit, ))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn limit(&self) -> Result<i16, dbus::Error> {
|
|
||||||
self.method_call("org.asuslinux.Daemon", "Limit", ())
|
|
||||||
.and_then(|r: (i16, )| Ok(r.0, ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct OrgAsuslinuxDaemonNotifyCharge {
|
|
||||||
pub limit: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyCharge {
|
|
||||||
fn append(&self, i: &mut arg::IterAppend) {
|
|
||||||
arg::RefArg::append(&self.limit, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyCharge {
|
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
|
||||||
Ok(OrgAsuslinuxDaemonNotifyCharge {
|
|
||||||
limit: i.read()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyCharge {
|
|
||||||
const NAME: &'static str = "NotifyCharge";
|
|
||||||
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
// 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 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> {
|
|
||||||
|
|
||||||
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, ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct OrgAsuslinuxDaemonNotifyGfx {
|
|
||||||
pub vendor: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyGfx {
|
|
||||||
fn append(&self, i: &mut arg::IterAppend) {
|
|
||||||
arg::RefArg::append(&self.vendor, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyGfx {
|
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
|
||||||
Ok(OrgAsuslinuxDaemonNotifyGfx {
|
|
||||||
vendor: i.read()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Led -m None`, 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_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> {
|
|
||||||
|
|
||||||
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error> {
|
|
||||||
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, ))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn led_modes(&self) -> Result<String, dbus::Error> {
|
|
||||||
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)]
|
|
||||||
pub struct OrgAsuslinuxDaemonNotifyLed {
|
|
||||||
pub data: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyLed {
|
|
||||||
fn append(&self, i: &mut arg::IterAppend) {
|
|
||||||
arg::RefArg::append(&self.data, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyLed {
|
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
|
||||||
Ok(OrgAsuslinuxDaemonNotifyLed {
|
|
||||||
data: i.read()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyLed {
|
|
||||||
const NAME: &'static str = "NotifyLed";
|
|
||||||
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
// 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> {
|
|
||||||
|
|
||||||
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error> {
|
|
||||||
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, ))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn profiles(&self) -> Result<String, dbus::Error> {
|
|
||||||
self.method_call("org.asuslinux.Daemon", "Profiles", ())
|
|
||||||
.and_then(|r: (String, )| Ok(r.0, ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct OrgAsuslinuxDaemonNotifyProfile {
|
|
||||||
pub profile: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyProfile {
|
|
||||||
fn append(&self, i: &mut arg::IterAppend) {
|
|
||||||
arg::RefArg::append(&self.profile, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyProfile {
|
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
|
||||||
Ok(OrgAsuslinuxDaemonNotifyProfile {
|
|
||||||
profile: i.read()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyProfile {
|
|
||||||
const NAME: &'static str = "NotifyProfile";
|
|
||||||
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asus-notify"
|
name = "asus-notify"
|
||||||
version = "2.0.4"
|
version = "3.0.0"
|
||||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -8,10 +8,11 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# serialisation
|
# serialisation
|
||||||
serde = "^1.0"
|
|
||||||
serde_derive = "^1.0"
|
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
notify-rust = "^4.0.0"
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
dbus = { version = "^0.8" }
|
daemon = { path = "../daemon" }
|
||||||
asus-nb = { path = "../asus-nb" }
|
|
||||||
asus-nb-ctrl = { path = "../asus-nb-ctrl" }
|
[dependencies.notify-rust]
|
||||||
|
version = "^4.0"
|
||||||
|
default-features = false
|
||||||
|
features = ["z"]
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
use asus_nb::core_dbus::CtrlSignals;
|
use daemon::config::Profile;
|
||||||
use daemon::config::{Config, Profile};
|
|
||||||
use dbus::blocking::Connection;
|
|
||||||
use notify_rust::{Hint, Notification, NotificationHandle};
|
use notify_rust::{Hint, Notification, NotificationHandle};
|
||||||
|
use rog_dbus::{DbusProxies, Signals};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!("Version {}", env!("CARGO_PKG_VERSION"));
|
println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
|
||||||
|
println!(" daemon version {}", daemon::VERSION);
|
||||||
let mut cfg = Config::read_new()?;
|
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||||
let mut last_profile = String::new();
|
|
||||||
|
|
||||||
let connection = Connection::new_system()?;
|
// let mut cfg = Config::read_new()?;
|
||||||
let signals = CtrlSignals::new(&connection)?;
|
// let mut last_profile = String::new();
|
||||||
|
|
||||||
|
let (proxies, conn) = DbusProxies::new()?;
|
||||||
|
let signals = Signals::new(&proxies)?;
|
||||||
|
|
||||||
let mut last_profile_notif: Option<NotificationHandle> = None;
|
let mut last_profile_notif: Option<NotificationHandle> = None;
|
||||||
let mut last_led_notif: Option<NotificationHandle> = None;
|
let mut last_led_notif: Option<NotificationHandle> = None;
|
||||||
let mut last_gfx_notif: Option<NotificationHandle> = None;
|
let mut last_gfx_notif: Option<NotificationHandle> = None;
|
||||||
let mut last_chrg_notif: Option<NotificationHandle> = None;
|
let mut last_chrg_notif: Option<NotificationHandle> = None;
|
||||||
|
|
||||||
|
let recv = proxies.setup_recv(conn);
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(Duration::from_millis(100));
|
std::thread::sleep(Duration::from_millis(100));
|
||||||
connection.process(std::time::Duration::from_millis(200))?;
|
recv.next_signal().unwrap();
|
||||||
|
|
||||||
if let Ok(mut lock) = signals.gfx_vendor_signal.lock() {
|
if let Ok(mut lock) = signals.gfx_vendor.lock() {
|
||||||
if let Some(vendor) = lock.take() {
|
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();
|
||||||
@@ -33,17 +35,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(mut lock) = signals.charge_signal.lock() {
|
if let Ok(mut lock) = signals.charge.lock() {
|
||||||
if let Some(limit) = lock.take() {
|
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))?;
|
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
|
||||||
last_led_notif = Some(x);
|
last_chrg_notif = Some(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(mut lock) = signals.ledmode_signal.lock() {
|
if let Ok(mut lock) = signals.profile.lock() {
|
||||||
|
if let Some(profile) = lock.take() {
|
||||||
|
if let Some(notif) = last_profile_notif.take() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(mut lock) = signals.led_mode.lock() {
|
||||||
if let Some(ledmode) = lock.take() {
|
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();
|
||||||
@@ -55,20 +72,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
last_led_notif = Some(x);
|
last_led_notif = Some(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to do the config read because of a limitation preventing
|
|
||||||
// easy dbus notification from the profile controller
|
|
||||||
cfg.read();
|
|
||||||
if last_profile != cfg.active_profile {
|
|
||||||
if let Some(notif) = last_profile_notif.take() {
|
|
||||||
notif.close();
|
|
||||||
}
|
|
||||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
|
||||||
let x = do_thermal_notif(&profile, &cfg.active_profile)?;
|
|
||||||
last_profile_notif = Some(x);
|
|
||||||
last_profile = cfg.active_profile.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +86,11 @@ fn do_thermal_notif(profile: &Profile, label: &str) -> Result<NotificationHandle
|
|||||||
};
|
};
|
||||||
let x = Notification::new()
|
let x = Notification::new()
|
||||||
.summary("ASUS ROG")
|
.summary("ASUS ROG")
|
||||||
.body(&format!("Thermal profile changed to {}, turbo {}", label.to_uppercase(), turbo))
|
.body(&format!(
|
||||||
|
"Thermal profile changed to {}, turbo {}",
|
||||||
|
label.to_uppercase(),
|
||||||
|
turbo
|
||||||
|
))
|
||||||
.hint(Hint::Resident(true))
|
.hint(Hint::Resident(true))
|
||||||
.timeout(2000)
|
.timeout(2000)
|
||||||
.hint(Hint::Category("device".into()))
|
.hint(Hint::Category("device".into()))
|
||||||
|
|||||||
20
asusctl/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "asusctl"
|
||||||
|
version = "3.0.0"
|
||||||
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# serialisation
|
||||||
|
serde_json = "^1.0"
|
||||||
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
|
rog_types = { path = "../rog-types" }
|
||||||
|
gumdrop = "^0.8"
|
||||||
|
yansi-term = "^0.1"
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tinybmp = "^0.2.3"
|
||||||
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use asus_nb::anime_dbus::AniMeDbusWriter;
|
use rog_dbus::AuraDbusClient;
|
||||||
use asus_nb::anime_matrix::{AniMeMatrix, AniMePacketType, HEIGHT, WIDTH};
|
use rog_types::anime_matrix::{AniMeImageBuffer, AniMePacketType, HEIGHT, WIDTH};
|
||||||
use tinybmp::{Bmp, Pixel};
|
use tinybmp::{Bmp, Pixel};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut writer = AniMeDbusWriter::new().unwrap();
|
let (client, _) = AuraDbusClient::new().unwrap();
|
||||||
|
|
||||||
let bmp =
|
let bmp =
|
||||||
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
|
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
|
||||||
@@ -11,7 +11,7 @@ fn main() {
|
|||||||
//assert_eq!(pixels.len(), 56 * 56);
|
//assert_eq!(pixels.len(), 56 * 56);
|
||||||
|
|
||||||
// Try an outline, top and right
|
// Try an outline, top and right
|
||||||
let mut matrix = AniMeMatrix::new();
|
let mut matrix = AniMeImageBuffer::new();
|
||||||
|
|
||||||
// Aligned left
|
// Aligned left
|
||||||
for (i, px) in pixels.iter().enumerate() {
|
for (i, px) in pixels.iter().enumerate() {
|
||||||
@@ -38,5 +38,5 @@ fn main() {
|
|||||||
// println!("{:?}", matrix[0].to_vec());
|
// println!("{:?}", matrix[0].to_vec());
|
||||||
// println!("{:?}", matrix[1].to_vec());
|
// println!("{:?}", matrix[1].to_vec());
|
||||||
|
|
||||||
writer.write_image(&mut matrix).unwrap();
|
//client.proxies().anime().set_brightness(&mut matrix).unwrap();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
use asus_nb::{
|
use rog_dbus::AuraDbusClient;
|
||||||
core_dbus::AuraDbusClient,
|
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||||
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
|
|
||||||
};
|
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -54,7 +52,7 @@ impl Ball {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut writer = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
let mut colours = KeyColourArray::new();
|
let mut colours = KeyColourArray::new();
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)];
|
let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)];
|
||||||
|
|
||||||
writer.init_effect()?;
|
dbus.proxies().led().init_effect()?;
|
||||||
|
|
||||||
let rows = layout.get_rows();
|
let rows = layout.get_rows();
|
||||||
loop {
|
loop {
|
||||||
@@ -89,10 +87,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
*c.2 = 255;
|
*c.2 = 255;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
dbus.proxies().led().set_per_key(&colours)?;
|
||||||
|
|
||||||
writer.write_colour_block(&colours)?;
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
|
||||||
// can change 100 times per second, so need to slow it down
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
use asus_nb::{
|
use rog_dbus::AuraDbusClient;
|
||||||
core_dbus::AuraDbusClient,
|
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
|
||||||
fancy::{GX502Layout, KeyColourArray, KeyLayout},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut writer = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
let layout = GX502Layout::default();
|
let layout = GX502Layout::default();
|
||||||
|
|
||||||
writer.init_effect()?;
|
dbus.proxies().led().init_effect()?;
|
||||||
let rows = layout.get_rows();
|
let rows = layout.get_rows();
|
||||||
|
|
||||||
let mut column = 0;
|
let mut column = 0;
|
||||||
@@ -25,7 +23,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
column += 1;
|
column += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_colour_block(&key_colours)?;
|
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
use asus_nb::{
|
use rog_dbus::AuraDbusClient;
|
||||||
core_dbus::AuraDbusClient,
|
use rog_types::fancy::{GX502Layout, Key, KeyColourArray, KeyLayout};
|
||||||
fancy::{GX502Layout, Key, KeyColourArray, KeyLayout},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut writer = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
let mut key_colours = KeyColourArray::new();
|
let mut key_colours = KeyColourArray::new();
|
||||||
let layout = GX502Layout::default();
|
let layout = GX502Layout::default();
|
||||||
|
|
||||||
writer.init_effect()?;
|
dbus.proxies().led().init_effect()?;
|
||||||
let rows = layout.get_rows();
|
let rows = layout.get_rows();
|
||||||
loop {
|
loop {
|
||||||
for (r, row) in rows.iter().enumerate() {
|
for (r, row) in rows.iter().enumerate() {
|
||||||
@@ -48,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
*key_colours.key(Key::S).unwrap().0 = 255;
|
*key_colours.key(Key::S).unwrap().0 = 255;
|
||||||
*key_colours.key(Key::D).unwrap().0 = 255;
|
*key_colours.key(Key::D).unwrap().0 = 255;
|
||||||
|
|
||||||
writer.write_colour_block(&key_colours)?;
|
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,14 +1,12 @@
|
|||||||
use asus_nb::{
|
use rog_dbus::AuraDbusClient;
|
||||||
core_dbus::AuraDbusClient,
|
use rog_types::fancy::{Key, KeyColourArray};
|
||||||
fancy::{Key, KeyColourArray},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut writer = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
let mut key_colours = KeyColourArray::new();
|
let mut key_colours = KeyColourArray::new();
|
||||||
|
|
||||||
writer.init_effect()?;
|
dbus.proxies().led().init_effect()?;
|
||||||
loop {
|
loop {
|
||||||
let count = 49;
|
let count = 49;
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
@@ -18,7 +16,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
*key_colours.key(Key::N).unwrap().0 += 5;
|
*key_colours.key(Key::N).unwrap().0 += 5;
|
||||||
*key_colours.key(Key::U).unwrap().0 += 5;
|
*key_colours.key(Key::U).unwrap().0 += 5;
|
||||||
*key_colours.key(Key::X).unwrap().0 += 5;
|
*key_colours.key(Key::X).unwrap().0 += 5;
|
||||||
writer.write_colour_block(&key_colours)?;
|
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||||
}
|
}
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
*key_colours.key(Key::ROG).unwrap().0 -= 5;
|
*key_colours.key(Key::ROG).unwrap().0 -= 5;
|
||||||
@@ -27,7 +25,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
*key_colours.key(Key::N).unwrap().0 -= 5;
|
*key_colours.key(Key::N).unwrap().0 -= 5;
|
||||||
*key_colours.key(Key::U).unwrap().0 -= 5;
|
*key_colours.key(Key::U).unwrap().0 -= 5;
|
||||||
*key_colours.key(Key::X).unwrap().0 -= 5;
|
*key_colours.key(Key::X).unwrap().0 -= 5;
|
||||||
writer.write_colour_block(&key_colours)?;
|
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
use asus_nb::{
|
use rog_dbus::AuraDbusClient;
|
||||||
core_dbus::AuraDbusClient,
|
use rog_types::fancy::{GX502Layout, KeyColourArray, KeyLayout};
|
||||||
fancy::{GX502Layout, KeyColourArray, KeyLayout},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut writer = AuraDbusClient::new()?;
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
let mut key_colours = KeyColourArray::new();
|
let mut key_colours = KeyColourArray::new();
|
||||||
let layout = GX502Layout::default();
|
let layout = GX502Layout::default();
|
||||||
|
|
||||||
writer.init_effect()?;
|
dbus.proxies().led().init_effect()?;
|
||||||
let rows = layout.get_rows();
|
let rows = layout.get_rows();
|
||||||
|
|
||||||
let mut fade = 50;
|
let mut fade = 50;
|
||||||
@@ -23,7 +21,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_colour_block(&key_colours)?;
|
dbus.proxies().led().set_per_key(&key_colours)?;
|
||||||
|
|
||||||
if flip {
|
if flip {
|
||||||
if fade > 1 {
|
if fade > 1 {
|
||||||
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
377
asusctl/src/main.rs
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
use gumdrop::{Opt, Options};
|
||||||
|
use rog_dbus::AuraDbusClient;
|
||||||
|
use rog_types::{
|
||||||
|
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
|
||||||
|
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin},
|
||||||
|
gfx_vendors::GfxVendors,
|
||||||
|
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
||||||
|
};
|
||||||
|
use std::{env::args, process::Command};
|
||||||
|
use yansi_term::Colour::Green;
|
||||||
|
use yansi_term::Colour::Red;
|
||||||
|
|
||||||
|
#[derive(Default, Options)]
|
||||||
|
struct CLIStart {
|
||||||
|
#[options(help_flag, help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(help = "show program version number")]
|
||||||
|
version: bool,
|
||||||
|
#[options(help = "show supported functions of this laptop")]
|
||||||
|
show_supported: bool,
|
||||||
|
#[options(meta = "", help = "<off, low, med, high>")]
|
||||||
|
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>")]
|
||||||
|
chg_limit: Option<u8>,
|
||||||
|
#[options(command)]
|
||||||
|
command: Option<CliCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
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),
|
||||||
|
#[options(help = "Change bios settings")]
|
||||||
|
Bios(BiosCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
struct LedModeCommand {
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[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(
|
||||||
|
meta = "",
|
||||||
|
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(
|
||||||
|
meta = "",
|
||||||
|
help = "turn on/off the panel (accept/reject write requests)"
|
||||||
|
)]
|
||||||
|
turn: Option<AniMeStatusValue>,
|
||||||
|
#[options(meta = "", help = "turn on/off the panel at boot (with Asus effect)")]
|
||||||
|
boot: Option<AniMeStatusValue>,
|
||||||
|
#[options(command)]
|
||||||
|
command: Option<AniMeActions>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Options, Debug)]
|
||||||
|
struct BiosCommand {
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(meta = "", no_long, help = "toggle bios POST sound")]
|
||||||
|
post_sound_set: Option<bool>,
|
||||||
|
#[options(no_long, help = "read bios POST sound")]
|
||||||
|
post_sound_get: bool,
|
||||||
|
#[options(meta = "", no_long, help = "toggle GPU to/from dedicated mode")]
|
||||||
|
dedicated_gfx_set: Option<bool>,
|
||||||
|
#[options(no_long, help = "get GPU mode")]
|
||||||
|
dedicated_gfx_get: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
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!(" asusctl version {}", env!("CARGO_PKG_VERSION"));
|
||||||
|
println!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||||
|
println!("rog-types version {}", rog_types::VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (dbus, _) = AuraDbusClient::new()?;
|
||||||
|
|
||||||
|
match parsed.command {
|
||||||
|
Some(CliCommand::LedMode(mode)) => {
|
||||||
|
if (mode.command.is_none() && !mode.prev_mode && !mode.next_mode) || mode.help {
|
||||||
|
println!("Missing arg or command\n\n{}", mode.self_usage());
|
||||||
|
if let Some(lst) = mode.self_command_list() {
|
||||||
|
println!("\n{}", lst);
|
||||||
|
}
|
||||||
|
println!("\nHelp can also be requested on modes, e.g: static --help");
|
||||||
|
}
|
||||||
|
if mode.next_mode && mode.prev_mode {
|
||||||
|
println!("Please specify either next or previous")
|
||||||
|
}
|
||||||
|
if mode.next_mode {
|
||||||
|
dbus.proxies().led().next_led_mode()?;
|
||||||
|
} else if mode.prev_mode {
|
||||||
|
dbus.proxies().led().prev_led_mode()?;
|
||||||
|
} else if let Some(command) = mode.command {
|
||||||
|
dbus.proxies().led().set_led_mode(&command.into())?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(CliCommand::Profile(cmd)) => {
|
||||||
|
if (!cmd.next
|
||||||
|
&& !cmd.create
|
||||||
|
&& cmd.curve.is_none()
|
||||||
|
&& cmd.max_percentage.is_none()
|
||||||
|
&& cmd.min_percentage.is_none()
|
||||||
|
&& cmd.preset.is_none()
|
||||||
|
&& cmd.profile.is_none()
|
||||||
|
&& cmd.turbo.is_none())
|
||||||
|
|| cmd.help
|
||||||
|
{
|
||||||
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
|
if let Some(lst) = cmd.self_command_list() {
|
||||||
|
println!("\n{}", lst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cmd.next {
|
||||||
|
dbus.proxies().profile().next_fan()?;
|
||||||
|
} else {
|
||||||
|
dbus.proxies()
|
||||||
|
.profile()
|
||||||
|
.write_command(&ProfileEvent::Cli(cmd))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(CliCommand::Graphics(cmd)) => do_gfx(cmd, &dbus)?,
|
||||||
|
Some(CliCommand::AniMe(cmd)) => {
|
||||||
|
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help {
|
||||||
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
|
if let Some(lst) = cmd.self_command_list() {
|
||||||
|
println!("\n{}", lst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(anime_turn) = cmd.turn {
|
||||||
|
dbus.proxies().anime().toggle_on(anime_turn.into())?
|
||||||
|
}
|
||||||
|
if let Some(anime_boot) = cmd.boot {
|
||||||
|
dbus.proxies().anime().toggle_boot_on(anime_boot.into())?
|
||||||
|
}
|
||||||
|
if let Some(action) = cmd.command {
|
||||||
|
match action {
|
||||||
|
AniMeActions::Leds(anime_leds) => {
|
||||||
|
let mut data = AniMeDataBuffer::new();
|
||||||
|
data.set([anime_leds.led_brightness(); FULL_PANE_LEN]);
|
||||||
|
dbus.proxies().anime().write_direct(data)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(CliCommand::Bios(cmd)) => {
|
||||||
|
if (cmd.dedicated_gfx_set.is_none()
|
||||||
|
&& !cmd.dedicated_gfx_get
|
||||||
|
&& cmd.post_sound_set.is_none()
|
||||||
|
&& !cmd.post_sound_get)
|
||||||
|
|| cmd.help
|
||||||
|
{
|
||||||
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
|
if let Some(lst) = cmd.self_command_list() {
|
||||||
|
println!("\n{}", lst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(opt) = cmd.post_sound_set {
|
||||||
|
dbus.proxies().rog_bios().set_post_sound(opt)?;
|
||||||
|
}
|
||||||
|
if cmd.post_sound_get {
|
||||||
|
let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
println!("Bios POST sound on: {}", res);
|
||||||
|
}
|
||||||
|
if let Some(opt) = cmd.dedicated_gfx_set {
|
||||||
|
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?;
|
||||||
|
}
|
||||||
|
if cmd.dedicated_gfx_get {
|
||||||
|
let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
println!("Bios dedicated GPU on: {}", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if (!parsed.show_supported
|
||||||
|
&& parsed.kbd_bright.is_none()
|
||||||
|
&& parsed.fan_mode.is_none()
|
||||||
|
&& parsed.chg_limit.is_none())
|
||||||
|
|| parsed.help
|
||||||
|
{
|
||||||
|
println!("{}", CLIStart::usage());
|
||||||
|
println!();
|
||||||
|
println!("{}", CLIStart::command_list().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(brightness) = parsed.kbd_bright {
|
||||||
|
match brightness.level() {
|
||||||
|
None => {
|
||||||
|
let level = dbus.proxies().led().get_led_brightness()?;
|
||||||
|
println!("Current keyboard led brightness: {}", level.to_string());
|
||||||
|
}
|
||||||
|
Some(level) => dbus.proxies().led().set_brightness(level)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed.show_supported {
|
||||||
|
let dat = dbus.proxies().supported().get_supported_functions()?;
|
||||||
|
println!("Supported laptop functions:\n{}", dat.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
dbus.proxies().charge().write_limit(chg_limit)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_gfx(
|
||||||
|
command: GraphicsCommand,
|
||||||
|
dbus_client: &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`");
|
||||||
|
|
||||||
|
dbus_client
|
||||||
|
.proxies()
|
||||||
|
.gfx()
|
||||||
|
.gfx_write_mode(<&str>::from(&mode).into())?;
|
||||||
|
let res = dbus_client.gfx_wait_changed()?;
|
||||||
|
match res.as_str() {
|
||||||
|
"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")
|
||||||
|
);
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("{}", Red.paint(&format!("\n{}\n", res.as_str())),);
|
||||||
|
std::process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::process::exit(-1)
|
||||||
|
}
|
||||||
|
if command.get {
|
||||||
|
let res = dbus_client.proxies().gfx().gfx_get_mode()?;
|
||||||
|
println!("Current graphics mode: {}", res);
|
||||||
|
}
|
||||||
|
if command.pow {
|
||||||
|
let res = dbus_client.proxies().gfx().gfx_get_pwr()?;
|
||||||
|
if res.contains("active") {
|
||||||
|
println!("Current power status: {}", Red.paint(&format!("{}", res)));
|
||||||
|
} else {
|
||||||
|
println!("Current power status: {}", Green.paint(&format!("{}", res)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(())
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "ctrl-gfx"
|
|
||||||
version = "2.1.3"
|
|
||||||
license = "MPL-2.0"
|
|
||||||
readme = "README.md"
|
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
|
||||||
description = "Fine control of laptop GPU"
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
sysfs-class = "^0.1.2"
|
|
||||||
log = "^0.4"
|
|
||||||
|
|
||||||
zbus = { version = "1.1.1", optional = true }
|
|
||||||
zvariant = { version = "2.2.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["use-zbus"]
|
|
||||||
use-zbus = ["zbus", "zvariant"]
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asus-nb-ctrl"
|
name = "daemon"
|
||||||
version = "2.1.0"
|
version = "3.0.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>"]
|
||||||
@@ -13,40 +13,31 @@ edition = "2018"
|
|||||||
name = "daemon"
|
name = "daemon"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "asusctl"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "asusd"
|
name = "asusd"
|
||||||
path = "src/daemon.rs"
|
path = "src/daemon.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ctrl-gfx = { path = "../ctrl-gfx" }
|
rog_types = { path = "../rog-types" }
|
||||||
asus-nb = { path = "../asus-nb" }
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
rusb = "^0.6.0"
|
rusb = "^0.7"
|
||||||
udev = "^0.4.0"
|
udev = "^0.6"
|
||||||
|
|
||||||
# cli and logging
|
# cli and logging
|
||||||
gumdrop = "^0.8.0"
|
log = "^0.4"
|
||||||
log = "^0.4.8"
|
env_logger = "^0.8"
|
||||||
env_logger = "^0.7.1"
|
|
||||||
|
|
||||||
# async
|
zbus = "^1.8"
|
||||||
zbus = "1.2.0"
|
zvariant = "^2.4"
|
||||||
zvariant = "2.2.0"
|
|
||||||
#tokio = { version = "^0.2.4", features = ["rt-threaded", "sync"] }
|
|
||||||
|
|
||||||
# serialisation
|
# serialisation
|
||||||
serde = "^1.0"
|
serde = "^1.0"
|
||||||
serde_derive = "^1.0"
|
serde_derive = "^1.0"
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
toml = "0.4.6"
|
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.5", features = ["serde"] }
|
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
||||||
# cpu power management
|
# cpu power management
|
||||||
intel-pstate = "^0.2.1"
|
intel-pstate = "^0.2"
|
||||||
|
|
||||||
yansi-term = "^0.1"
|
|
||||||
261
daemon/src/config.rs
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
use log::{error, info, warn};
|
||||||
|
use rog_fan_curve::Curve;
|
||||||
|
use rog_types::aura_modes::AuraModes;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use crate::VERSION;
|
||||||
|
|
||||||
|
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||||
|
|
||||||
|
/// for parsing old v2.1.2 config
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ConfigV212 {
|
||||||
|
gfx_managed: bool,
|
||||||
|
bat_charge_limit: u8,
|
||||||
|
active_profile: String,
|
||||||
|
toggle_profiles: Vec<String>,
|
||||||
|
power_profiles: BTreeMap<String, Profile>,
|
||||||
|
power_profile: u8,
|
||||||
|
kbd_led_brightness: u8,
|
||||||
|
kbd_backlight_mode: u8,
|
||||||
|
kbd_backlight_modes: Vec<AuraModes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigV212 {
|
||||||
|
fn into_current(self) -> Config {
|
||||||
|
Config {
|
||||||
|
gfx_managed: self.gfx_managed,
|
||||||
|
gfx_nv_mode_is_dedicated: true,
|
||||||
|
active_profile: self.active_profile,
|
||||||
|
toggle_profiles: self.toggle_profiles,
|
||||||
|
curr_fan_mode: self.power_profile,
|
||||||
|
bat_charge_limit: self.bat_charge_limit,
|
||||||
|
kbd_led_brightness: self.kbd_led_brightness,
|
||||||
|
kbd_backlight_mode: self.kbd_backlight_mode,
|
||||||
|
kbd_backlight_modes: self.kbd_backlight_modes,
|
||||||
|
power_profiles: self.power_profiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// for parsing old v2.2.2 config
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ConfigV222 {
|
||||||
|
gfx_managed: bool,
|
||||||
|
bat_charge_limit: u8,
|
||||||
|
active_profile: String,
|
||||||
|
toggle_profiles: Vec<String>,
|
||||||
|
power_profiles: BTreeMap<String, Profile>,
|
||||||
|
power_profile: u8,
|
||||||
|
kbd_led_brightness: u8,
|
||||||
|
kbd_backlight_mode: u8,
|
||||||
|
kbd_backlight_modes: Vec<AuraModes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigV222 {
|
||||||
|
fn into_current(self) -> Config {
|
||||||
|
Config {
|
||||||
|
gfx_managed: self.gfx_managed,
|
||||||
|
gfx_nv_mode_is_dedicated: true,
|
||||||
|
active_profile: self.active_profile,
|
||||||
|
toggle_profiles: self.toggle_profiles,
|
||||||
|
curr_fan_mode: self.power_profile,
|
||||||
|
bat_charge_limit: self.bat_charge_limit,
|
||||||
|
kbd_led_brightness: self.kbd_led_brightness,
|
||||||
|
kbd_backlight_mode: self.kbd_backlight_mode,
|
||||||
|
kbd_backlight_modes: self.kbd_backlight_modes,
|
||||||
|
power_profiles: self.power_profiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub gfx_managed: bool,
|
||||||
|
pub gfx_nv_mode_is_dedicated: bool,
|
||||||
|
pub active_profile: String,
|
||||||
|
pub toggle_profiles: Vec<String>,
|
||||||
|
// TODO: remove power_profile
|
||||||
|
#[serde(skip)]
|
||||||
|
pub curr_fan_mode: u8,
|
||||||
|
pub bat_charge_limit: u8,
|
||||||
|
pub kbd_led_brightness: u8,
|
||||||
|
pub kbd_backlight_mode: u8,
|
||||||
|
pub kbd_backlight_modes: Vec<AuraModes>,
|
||||||
|
pub power_profiles: BTreeMap<String, Profile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut pwr = BTreeMap::new();
|
||||||
|
pwr.insert("normal".into(), Profile::new(0, 100, true, 0, None));
|
||||||
|
pwr.insert("boost".into(), Profile::new(0, 100, true, 1, None));
|
||||||
|
pwr.insert("silent".into(), Profile::new(0, 100, true, 2, None));
|
||||||
|
|
||||||
|
Config {
|
||||||
|
gfx_managed: true,
|
||||||
|
gfx_nv_mode_is_dedicated: true,
|
||||||
|
active_profile: "normal".into(),
|
||||||
|
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
||||||
|
curr_fan_mode: 0,
|
||||||
|
bat_charge_limit: 100,
|
||||||
|
kbd_led_brightness: 1,
|
||||||
|
kbd_backlight_mode: 0,
|
||||||
|
kbd_backlight_modes: Vec::new(),
|
||||||
|
power_profiles: pwr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// `load` will attempt to read the config, and panic if the dir is missing
|
||||||
|
pub fn load(supported_led_modes: &[u8]) -> Self {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&CONFIG_PATH)
|
||||||
|
.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(read_len) = file.read_to_string(&mut buf) {
|
||||||
|
if read_len == 0 {
|
||||||
|
return Config::create_default(&mut file, &supported_led_modes);
|
||||||
|
} else {
|
||||||
|
if let Ok(data) = serde_json::from_str(&buf) {
|
||||||
|
return data;
|
||||||
|
} else if let Ok(data) = serde_json::from_str::<ConfigV222>(&buf) {
|
||||||
|
let config = data.into_current();
|
||||||
|
config.write();
|
||||||
|
info!("Updated config version to: {}", VERSION);
|
||||||
|
return config;
|
||||||
|
} else if let Ok(data) = serde_json::from_str::<ConfigV212>(&buf) {
|
||||||
|
let config = data.into_current();
|
||||||
|
config.write();
|
||||||
|
info!("Updated config version to: {}", VERSION);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
warn!("Could not deserialise {}", CONFIG_PATH);
|
||||||
|
panic!("Please remove {} then restart asusd", CONFIG_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Config::create_default(&mut file, &supported_led_modes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
|
||||||
|
// create a default config here
|
||||||
|
let mut config = Config::default();
|
||||||
|
|
||||||
|
for n in supported_led_modes {
|
||||||
|
config.kbd_backlight_modes.push(AuraModes::from(*n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be okay to unwrap this as is since it is a Default
|
||||||
|
let json = serde_json::to_string_pretty(&config).unwrap();
|
||||||
|
file.write_all(json.as_bytes())
|
||||||
|
.unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH));
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&CONFIG_PATH)
|
||||||
|
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||||
|
if l == 0 {
|
||||||
|
warn!("File is empty {}", CONFIG_PATH);
|
||||||
|
} else {
|
||||||
|
let x: Config = serde_json::from_str(&buf)
|
||||||
|
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
|
||||||
|
*self = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_new() -> Result<Config, Box<dyn std::error::Error>> {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&CONFIG_PATH)
|
||||||
|
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
|
||||||
|
let mut buf = String::new();
|
||||||
|
file.read_to_string(&mut buf)?;
|
||||||
|
let x: Config = serde_json::from_str(&buf)?;
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self) {
|
||||||
|
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
||||||
|
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||||
|
file.write_all(json.as_bytes())
|
||||||
|
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_mode_data(&mut self, mode: AuraModes) {
|
||||||
|
let byte: u8 = (&mode).into();
|
||||||
|
for (index, n) in self.kbd_backlight_modes.iter().enumerate() {
|
||||||
|
if byte == u8::from(n) {
|
||||||
|
// Consume it, OMNOMNOMNOM
|
||||||
|
self.kbd_backlight_modes[index] = mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_led_mode_data(&self, num: u8) -> Option<&AuraModes> {
|
||||||
|
for mode in &self.kbd_backlight_modes {
|
||||||
|
if u8::from(mode) == num {
|
||||||
|
return Some(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Profile {
|
||||||
|
pub min_percentage: u8,
|
||||||
|
pub max_percentage: u8,
|
||||||
|
pub turbo: bool,
|
||||||
|
pub fan_preset: u8,
|
||||||
|
pub fan_curve: Option<Curve>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
|
pub type CPUSettings = Profile;
|
||||||
|
|
||||||
|
impl Default for Profile {
|
||||||
|
fn default() -> Self {
|
||||||
|
Profile {
|
||||||
|
min_percentage: 0,
|
||||||
|
max_percentage: 100,
|
||||||
|
turbo: false,
|
||||||
|
fan_preset: 0,
|
||||||
|
fan_curve: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Profile {
|
||||||
|
pub fn new(
|
||||||
|
min_percentage: u8,
|
||||||
|
max_percentage: u8,
|
||||||
|
turbo: bool,
|
||||||
|
fan_preset: u8,
|
||||||
|
fan_curve: Option<Curve>,
|
||||||
|
) -> Self {
|
||||||
|
Profile {
|
||||||
|
min_percentage,
|
||||||
|
max_percentage,
|
||||||
|
turbo,
|
||||||
|
fan_preset,
|
||||||
|
fan_curve,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,41 +6,55 @@ const DEV_PAGE: u8 = 0x5e;
|
|||||||
// These bytes are in [1] position of the array
|
// These bytes are in [1] position of the array
|
||||||
const WRITE: u8 = 0xc0;
|
const WRITE: u8 = 0xc0;
|
||||||
const INIT: u8 = 0xc2;
|
const INIT: u8 = 0xc2;
|
||||||
const APPLY: u8 = 0xc3;
|
const SET: u8 = 0xc3;
|
||||||
const SET: u8 = 0xc4;
|
const APPLY: u8 = 0xc4;
|
||||||
|
|
||||||
// Used to turn the panel on and off
|
// Used to turn the panel on and off
|
||||||
// The next byte can be 0x03 for "on" and 0x00 for "off"
|
// The next byte can be 0x03 for "on" and 0x00 for "off"
|
||||||
const ON_OFF : u8 = 0x04;
|
const ON_OFF: u8 = 0x04;
|
||||||
|
|
||||||
use asus_nb::error::AuraError;
|
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
use rog_types::{
|
||||||
|
anime_matrix::{
|
||||||
|
AniMeDataBuffer, AniMeImageBuffer, AniMePacketType, ANIME_PANE1_PREFIX, ANIME_PANE2_PREFIX,
|
||||||
|
},
|
||||||
|
error::AuraError,
|
||||||
|
};
|
||||||
use rusb::{Device, DeviceHandle};
|
use rusb::{Device, DeviceHandle};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
use crate::GetSupported;
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AnimatrixCommand {
|
use serde_derive::{Deserialize, Serialize};
|
||||||
Apply,
|
#[derive(Serialize, Deserialize)]
|
||||||
Set,
|
pub struct AnimeSupportedFunctions(bool);
|
||||||
Write(Vec<u8>),
|
|
||||||
WriteImage(Vec<Vec<u8>>),
|
impl GetSupported for CtrlAnimeDisplay {
|
||||||
//ReloadLast,
|
type A = AnimeSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(0x0b05, 0x193b).is_ok())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CtrlAnimeDisplay {
|
pub struct CtrlAnimeDisplay {
|
||||||
handle: DeviceHandle<rusb::GlobalContext>,
|
handle: DeviceHandle<rusb::GlobalContext>,
|
||||||
initialised: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//AnimatrixWrite
|
//AnimatrixWrite
|
||||||
pub trait Dbus {
|
pub trait Dbus {
|
||||||
fn set_anime(&mut self, input: Vec<Vec<u8>>);
|
/// Write an image 34x56 pixels. Each pixel is 0-255 greyscale.
|
||||||
|
fn write_image(&self, input: AniMeImageBuffer);
|
||||||
|
|
||||||
fn set_on_off(&mut self, status: bool);
|
/// Write a direct stream of data
|
||||||
|
fn write_direct(&self, input: AniMeDataBuffer);
|
||||||
|
|
||||||
|
fn set_on_off(&self, status: bool);
|
||||||
|
|
||||||
|
fn set_boot_on_off(&self, status: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
||||||
@@ -57,29 +71,44 @@ impl crate::ZbusAdd for CtrlAnimeDisplay {
|
|||||||
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
impl Dbus for CtrlAnimeDisplay {
|
impl Dbus for CtrlAnimeDisplay {
|
||||||
fn set_anime(&mut self, input: Vec<Vec<u8>>) {
|
/// Writes a 34x56 image
|
||||||
self.do_command(AnimatrixCommand::WriteImage(input))
|
fn write_image(&self, input: AniMeImageBuffer) {
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
self.write_image_buffer(input)
|
||||||
|
.map_or_else(|err| warn!("{}", err), |()| info!("Writing image to Anime"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_on_off(&mut self, status: bool) {
|
/// Writes a data stream of length
|
||||||
let mut activity : Vec<u8> = vec![0; PACKET_SIZE];
|
fn write_direct(&self, input: AniMeDataBuffer) {
|
||||||
activity[0] = DEV_PAGE;
|
self.write_data_buffer(input)
|
||||||
activity[1] = WRITE;
|
.map_or_else(|err| warn!("{}", err), |()| info!("Writing data to Anime"));
|
||||||
activity[2] = ON_OFF;
|
}
|
||||||
|
|
||||||
|
fn set_on_off(&self, status: bool) {
|
||||||
|
let mut buffer = [0u8; PACKET_SIZE];
|
||||||
|
buffer[0] = DEV_PAGE;
|
||||||
|
buffer[1] = WRITE;
|
||||||
|
buffer[2] = ON_OFF;
|
||||||
|
|
||||||
let status_str;
|
|
||||||
if status {
|
if status {
|
||||||
activity[3] = 0x03;
|
buffer[3] = 0x03;
|
||||||
status_str = "on";
|
|
||||||
} else {
|
} else {
|
||||||
activity[3] = 0x00;
|
buffer[3] = 0x00;
|
||||||
status_str = "off";
|
|
||||||
}
|
}
|
||||||
info!("Turning {} the AniMe", status_str);
|
|
||||||
|
|
||||||
self.do_command(AnimatrixCommand::Write(activity))
|
self.write_bytes(&buffer);
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
}
|
||||||
|
|
||||||
|
fn set_boot_on_off(&self, status: bool) {
|
||||||
|
let status_str = if status { "on" } else { "off" };
|
||||||
|
|
||||||
|
self.do_set_boot(status).map_or_else(
|
||||||
|
|err| warn!("{}", err),
|
||||||
|
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
|
||||||
|
);
|
||||||
|
self.do_apply().map_or_else(
|
||||||
|
|err| warn!("{}", err),
|
||||||
|
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,10 +132,10 @@ impl CtrlAnimeDisplay {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("Device has an AniMe Matrix display");
|
info!("Device has an AniMe Matrix display");
|
||||||
Ok(CtrlAnimeDisplay {
|
let ctrl = CtrlAnimeDisplay { handle: device };
|
||||||
handle: device,
|
ctrl.do_initialization()?;
|
||||||
initialised: false,
|
|
||||||
})
|
Ok(ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -120,24 +149,9 @@ impl CtrlAnimeDisplay {
|
|||||||
Err(rusb::Error::NoDevice)
|
Err(rusb::Error::NoDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_command(&mut self, command: AnimatrixCommand) -> Result<(), AuraError> {
|
|
||||||
if !self.initialised {
|
|
||||||
self.do_initialization()?
|
|
||||||
}
|
|
||||||
|
|
||||||
match command {
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Should only be used if the bytes you are writing are verified correct
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
|
fn write_bytes(&self, message: &[u8]) {
|
||||||
match self.handle.write_control(
|
match self.handle.write_control(
|
||||||
0x21, // request_type
|
0x21, // request_type
|
||||||
0x09, // request
|
0x09, // request
|
||||||
@@ -152,12 +166,23 @@ impl CtrlAnimeDisplay {
|
|||||||
_ => error!("Failed to write to led interrupt: {}", err),
|
_ => error!("Failed to write to led interrupt: {}", err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn write_data_buffer(&self, buffer: AniMeDataBuffer) -> Result<(), AuraError> {
|
||||||
|
let mut image = AniMePacketType::from(buffer);
|
||||||
|
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
|
||||||
|
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
||||||
|
|
||||||
|
for row in image.iter() {
|
||||||
|
self.write_bytes(row);
|
||||||
|
}
|
||||||
|
self.do_flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an Animatrix image
|
/// Write an Animatrix image
|
||||||
///
|
///
|
||||||
/// The expected input here is *two* Vectors, 640 bytes in length. The two vectors
|
/// The expected USB input here is *two* Vectors, 640 bytes in length. The two vectors
|
||||||
/// are each one half of the full image write.
|
/// 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
|
/// After each write a flush is written, it is assumed that this tells the device to
|
||||||
@@ -171,22 +196,26 @@ impl CtrlAnimeDisplay {
|
|||||||
///
|
///
|
||||||
/// Where led brightness is 0..255, low to high
|
/// Where led brightness is 0..255, low to high
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_image(&mut self, image: Vec<Vec<u8>>) -> Result<(), AuraError> {
|
fn write_image_buffer(&self, buffer: AniMeImageBuffer) -> Result<(), AuraError> {
|
||||||
|
let mut image = AniMePacketType::from(buffer);
|
||||||
|
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
|
||||||
|
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
||||||
|
|
||||||
for row in image.iter() {
|
for row in image.iter() {
|
||||||
self.write_bytes(row)?;
|
self.write_bytes(row);
|
||||||
}
|
}
|
||||||
self.do_flush()?;
|
self.do_flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn do_initialization(&mut self) -> Result<(), AuraError> {
|
fn do_initialization(&self) -> Result<(), AuraError> {
|
||||||
let mut init = [0; PACKET_SIZE];
|
let mut init = [0; PACKET_SIZE];
|
||||||
init[0] = DEV_PAGE; // This is the USB page we're using throughout
|
init[0] = DEV_PAGE; // This is the USB page we're using throughout
|
||||||
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
|
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
|
||||||
init[idx + 1] = *byte
|
init[idx + 1] = *byte
|
||||||
}
|
}
|
||||||
self.write_bytes(&init)?;
|
self.write_bytes(&init);
|
||||||
|
|
||||||
// clear the init array and write other init message
|
// clear the init array and write other init message
|
||||||
for ch in init.iter_mut() {
|
for ch in init.iter_mut() {
|
||||||
@@ -195,43 +224,42 @@ impl CtrlAnimeDisplay {
|
|||||||
init[0] = DEV_PAGE; // write it to be sure?
|
init[0] = DEV_PAGE; // write it to be sure?
|
||||||
init[1] = INIT;
|
init[1] = INIT;
|
||||||
|
|
||||||
self.write_bytes(&init)?;
|
self.write_bytes(&init);
|
||||||
self.initialised = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn do_flush(&mut self) -> Result<(), AuraError> {
|
fn do_flush(&self) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = WRITE;
|
flush[1] = WRITE;
|
||||||
flush[2] = 0x03;
|
flush[2] = 0x03;
|
||||||
|
|
||||||
self.write_bytes(&flush)?;
|
self.write_bytes(&flush);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn do_set(&mut self) -> Result<(), AuraError> {
|
fn do_set_boot(&self, status: bool) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = SET;
|
flush[1] = SET;
|
||||||
flush[2] = 0x01;
|
flush[2] = 0x01;
|
||||||
flush[3] = 0x80;
|
flush[3] = if status { 0x00 } else { 0x80 };
|
||||||
|
|
||||||
self.write_bytes(&flush)?;
|
self.write_bytes(&flush);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn do_apply(&mut self) -> Result<(), AuraError> {
|
fn do_apply(&self) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = APPLY;
|
flush[1] = APPLY;
|
||||||
flush[2] = 0x01;
|
flush[2] = 0x01;
|
||||||
flush[3] = 0x80;
|
flush[3] = 0x80;
|
||||||
|
|
||||||
self.write_bytes(&flush)?;
|
self.write_bytes(&flush);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::{config::Config, error::RogError};
|
use crate::{config::Config, error::RogError, GetSupported};
|
||||||
//use crate::dbus::DbusEvents;
|
//use crate::dbus::DbusEvents;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -11,8 +12,22 @@ use zbus::dbus_interface;
|
|||||||
|
|
||||||
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ChargeSupportedFunctions {
|
||||||
|
pub charge_level_set: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for CtrlCharge {
|
||||||
|
type A = ChargeSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
ChargeSupportedFunctions {
|
||||||
|
charge_level_set: CtrlCharge::get_battery_path().is_ok(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CtrlCharge {
|
pub struct CtrlCharge {
|
||||||
path: &'static str,
|
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +58,7 @@ impl CtrlCharge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
#[dbus_interface(signal)]
|
||||||
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
|
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ZbusAdd for CtrlCharge {
|
impl crate::ZbusAdd for CtrlCharge {
|
||||||
@@ -62,7 +77,6 @@ impl crate::Reloadable for CtrlCharge {
|
|||||||
fn reload(&mut self) -> Result<(), RogError> {
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
if let Ok(mut config) = self.config.try_lock() {
|
if let Ok(mut config) = self.config.try_lock() {
|
||||||
config.read();
|
config.read();
|
||||||
info!("Reloaded battery charge limit");
|
|
||||||
self.set(config.bat_charge_limit, &mut config)?;
|
self.set(config.bat_charge_limit, &mut config)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -71,9 +85,8 @@ impl crate::Reloadable for CtrlCharge {
|
|||||||
|
|
||||||
impl CtrlCharge {
|
impl CtrlCharge {
|
||||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||||
let path = CtrlCharge::get_battery_path()?;
|
CtrlCharge::get_battery_path()?;
|
||||||
info!("Device has battery charge threshold control");
|
Ok(CtrlCharge { config })
|
||||||
Ok(CtrlCharge { path, config })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_battery_path() -> Result<&'static str, RogError> {
|
fn get_battery_path() -> Result<&'static str, RogError> {
|
||||||
@@ -81,13 +94,14 @@ impl CtrlCharge {
|
|||||||
Ok(BAT_CHARGE_PATH)
|
Ok(BAT_CHARGE_PATH)
|
||||||
} else {
|
} else {
|
||||||
Err(RogError::MissingFunction(
|
Err(RogError::MissingFunction(
|
||||||
"Charge control not available".into(),
|
"Charge control not available, you may require a v5.8.10 series kernel or newer"
|
||||||
|
.into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> {
|
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> {
|
||||||
if limit < 20 || limit > 100 {
|
if !(20..=100).contains(&limit) {
|
||||||
warn!(
|
warn!(
|
||||||
"Unable to set battery charge limit, must be between 20-100: requested {}",
|
"Unable to set battery charge limit, must be between 20-100: requested {}",
|
||||||
limit
|
limit
|
||||||
@@ -96,10 +110,10 @@ impl CtrlCharge {
|
|||||||
|
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(self.path)
|
.open(BAT_CHARGE_PATH)
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
.map_err(|err| RogError::Path(BAT_CHARGE_PATH.into(), err))?;
|
||||||
file.write_all(limit.to_string().as_bytes())
|
file.write_all(limit.to_string().as_bytes())
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
.map_err(|err| RogError::Write(BAT_CHARGE_PATH.into(), err))?;
|
||||||
info!("Battery charge limit: {}", limit);
|
info!("Battery charge limit: {}", limit);
|
||||||
|
|
||||||
config.read();
|
config.read();
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
use crate::config::{Config, Profile};
|
use crate::error::RogError;
|
||||||
use asus_nb::profile::ProfileEvent;
|
use crate::{
|
||||||
|
config::{Config, Profile},
|
||||||
|
GetSupported,
|
||||||
|
};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use rog_types::profile::{FanLevel, ProfileEvent};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
@@ -19,6 +23,25 @@ pub struct CtrlFanAndCPU {
|
|||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct FanCpuSupportedFunctions {
|
||||||
|
pub stock_fan_modes: bool,
|
||||||
|
pub min_max_freq: bool,
|
||||||
|
pub fan_curve_set: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for CtrlFanAndCPU {
|
||||||
|
type A = FanCpuSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
FanCpuSupportedFunctions {
|
||||||
|
stock_fan_modes: CtrlFanAndCPU::get_fan_path().is_ok(),
|
||||||
|
min_max_freq: intel_pstate::PState::new().is_ok(),
|
||||||
|
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DbusFanAndCpu {
|
pub struct DbusFanAndCpu {
|
||||||
inner: Arc<Mutex<CtrlFanAndCPU>>,
|
inner: Arc<Mutex<CtrlFanAndCPU>>,
|
||||||
}
|
}
|
||||||
@@ -39,8 +62,7 @@ impl DbusFanAndCpu {
|
|||||||
cfg.read();
|
cfg.read();
|
||||||
ctrl.handle_profile_event(&event, &mut cfg)
|
ctrl.handle_profile_event(&event, &mut cfg)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
self.notify_profile(&cfg.active_profile)
|
self.notify_profile(&cfg.active_profile).unwrap_or(());
|
||||||
.unwrap_or_else(|_| ());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +77,7 @@ impl DbusFanAndCpu {
|
|||||||
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(profile) {
|
if let Ok(json) = serde_json::to_string(profile) {
|
||||||
self.notify_profile(&json)
|
self.notify_profile(&json)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +123,7 @@ impl DbusFanAndCpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
#[dbus_interface(signal)]
|
||||||
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
|
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ZbusAdd for DbusFanAndCpu {
|
impl crate::ZbusAdd for DbusFanAndCpu {
|
||||||
@@ -109,7 +131,7 @@ impl crate::ZbusAdd for DbusFanAndCpu {
|
|||||||
server
|
server
|
||||||
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self)
|
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("DbusFanAndCpu: {}", err);
|
warn!("DbusFanAndCpu: add_to_server {}", err);
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
@@ -119,65 +141,17 @@ impl crate::ZbusAdd for DbusFanAndCpu {
|
|||||||
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 config) = self.config.clone().try_lock() {
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.open(self.path)
|
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
|
||||||
file.write_all(format!("{}\n", config.power_profile).as_bytes())
|
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
|
||||||
let profile = config.active_profile.clone();
|
let profile = config.active_profile.clone();
|
||||||
self.set(&profile, &mut config)?;
|
self.set(&profile, &mut config)?;
|
||||||
info!(
|
// info!(
|
||||||
"Reloaded fan mode: {:?}",
|
// "Reloaded fan mode: {:?}",
|
||||||
FanLevel::from(config.power_profile)
|
// FanLevel::from(config.power_profile)
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::CtrlTask for CtrlFanAndCPU {
|
|
||||||
fn do_task(&mut self) -> Result<(), RogError> {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.open(self.path)
|
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
file.read_exact(&mut buf)
|
|
||||||
.map_err(|err| RogError::Read(self.path.into(), err))?;
|
|
||||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
|
||||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
|
||||||
if config.power_profile != num as u8 {
|
|
||||||
config.read();
|
|
||||||
|
|
||||||
let mut i = config
|
|
||||||
.toggle_profiles
|
|
||||||
.iter()
|
|
||||||
.position(|x| x == &config.active_profile)
|
|
||||||
.map(|i| i + 1)
|
|
||||||
.unwrap_or(0);
|
|
||||||
if i >= config.toggle_profiles.len() {
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_profile = config
|
|
||||||
.toggle_profiles
|
|
||||||
.get(i)
|
|
||||||
.unwrap_or(&config.active_profile)
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
self.set(&new_profile, &mut config)?;
|
|
||||||
|
|
||||||
info!("Profile was changed: {}", &new_profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(RogError::DoTask("Fan-level could not be parsed".into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()?;
|
let path = CtrlFanAndCPU::get_fan_path()?;
|
||||||
@@ -192,7 +166,7 @@ impl CtrlFanAndCPU {
|
|||||||
Ok(FAN_TYPE_2_PATH)
|
Ok(FAN_TYPE_2_PATH)
|
||||||
} else {
|
} else {
|
||||||
Err(RogError::MissingFunction(
|
Err(RogError::MissingFunction(
|
||||||
"Fan mode not available, you may require a v5.8 series kernel or newer".into(),
|
"Fan mode not available, you may require a v5.8.10 series kernel or newer".into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +197,7 @@ impl CtrlFanAndCPU {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
|
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
|
||||||
let mode = config.active_profile.clone();
|
let mode = config.active_profile.clone();
|
||||||
let mut fan_ctrl = OpenOptions::new()
|
let mut fan_ctrl = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -234,15 +208,13 @@ impl CtrlFanAndCPU {
|
|||||||
.power_profiles
|
.power_profiles
|
||||||
.get_mut(&mode)
|
.get_mut(&mode)
|
||||||
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
|
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
|
||||||
config.power_profile = preset;
|
config.curr_fan_mode = preset;
|
||||||
mode_config.fan_preset = preset;
|
mode_config.fan_preset = preset;
|
||||||
config.write();
|
config.write();
|
||||||
fan_ctrl
|
fan_ctrl
|
||||||
.write_all(format!("{}\n", preset).as_bytes())
|
.write_all(format!("{}\n", preset).as_bytes())
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
||||||
self.set_pstate_for_fan_mode(&mode, config)?;
|
|
||||||
self.set_fan_curve_for_fan_mode(&mode, config)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +227,9 @@ impl CtrlFanAndCPU {
|
|||||||
ProfileEvent::Toggle => self.do_next_profile(config)?,
|
ProfileEvent::Toggle => self.do_next_profile(config)?,
|
||||||
ProfileEvent::ChangeMode(mode) => {
|
ProfileEvent::ChangeMode(mode) => {
|
||||||
self.set_fan_mode(*mode, config)?;
|
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) => {
|
ProfileEvent::Cli(command) => {
|
||||||
let profile_key = match command.profile.as_ref() {
|
let profile_key = match command.profile.as_ref() {
|
||||||
@@ -305,10 +280,10 @@ impl CtrlFanAndCPU {
|
|||||||
.write(true)
|
.write(true)
|
||||||
.open(self.path)
|
.open(self.path)
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
config.curr_fan_mode = mode_config.fan_preset;
|
||||||
fan_ctrl
|
fan_ctrl
|
||||||
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
config.power_profile = mode_config.fan_preset;
|
|
||||||
|
|
||||||
self.set_pstate_for_fan_mode(profile, config)?;
|
self.set_pstate_for_fan_mode(profile, config)?;
|
||||||
self.set_fan_curve_for_fan_mode(profile, config)?;
|
self.set_fan_curve_for_fan_mode(profile, config)?;
|
||||||
@@ -370,46 +345,3 @@ impl CtrlFanAndCPU {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::error::RogError;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FanLevel {
|
|
||||||
Normal,
|
|
||||||
Boost,
|
|
||||||
Silent,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for FanLevel {
|
|
||||||
type Err = RogError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, RogError> {
|
|
||||||
match s.to_lowercase().as_str() {
|
|
||||||
"normal" => Ok(FanLevel::Normal),
|
|
||||||
"boost" => Ok(FanLevel::Boost),
|
|
||||||
"silent" => Ok(FanLevel::Silent),
|
|
||||||
_ => Err(RogError::ParseFanLevel),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::error::RogError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GfxError {
|
pub enum GfxError {
|
||||||
ParseVendor,
|
ParseVendor,
|
||||||
@@ -28,3 +30,9 @@ impl fmt::Display for GfxError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for GfxError {}
|
impl error::Error for GfxError {}
|
||||||
|
|
||||||
|
impl From<GfxError> for RogError {
|
||||||
|
fn from(err: GfxError) -> Self {
|
||||||
|
RogError::GfxSwitching(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
|
use ctrl_gfx::error::GfxError;
|
||||||
|
use ctrl_gfx::*;
|
||||||
|
use ctrl_rog_bios::CtrlRogBios;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use std::error::Error;
|
use rog_types::gfx_vendors::{GfxCtrlAction, GfxVendors};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::{sync::Arc, sync::Mutex};
|
||||||
use sysfs_class::{PciDevice, SysClass};
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
|
use system::{GraphicsDevice, Module, PciBus};
|
||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
use crate::vendors::*;
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use crate::{error::GfxError, system::*};
|
|
||||||
|
|
||||||
pub struct CtrlGraphics {
|
pub struct CtrlGraphics {
|
||||||
bus: PciBus,
|
bus: PciBus,
|
||||||
@@ -20,6 +23,7 @@ pub struct CtrlGraphics {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
other: Vec<GraphicsDevice>,
|
other: Vec<GraphicsDevice>,
|
||||||
initfs_cmd: Option<Command>,
|
initfs_cmd: Option<Command>,
|
||||||
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dbus {
|
trait Dbus {
|
||||||
@@ -30,10 +34,8 @@ trait Dbus {
|
|||||||
fn notify_action(&self, action: &str) -> zbus::Result<()>;
|
fn notify_action(&self, action: &str) -> zbus::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "use-zbus")]
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[cfg(feature = "use-zbus")]
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
impl Dbus for CtrlGraphics {
|
impl Dbus for CtrlGraphics {
|
||||||
fn vendor(&self) -> String {
|
fn vendor(&self) -> String {
|
||||||
@@ -58,14 +60,39 @@ impl Dbus for CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
#[dbus_interface(signal)]
|
||||||
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
|
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()> {}
|
||||||
|
|
||||||
#[dbus_interface(signal)]
|
#[dbus_interface(signal)]
|
||||||
fn notify_action(&self, action: &str) -> zbus::Result<()>;
|
fn notify_action(&self, action: &str) -> zbus::Result<()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZbusAdd for CtrlGraphics {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(
|
||||||
|
&"/org/asuslinux/Gfx"
|
||||||
|
.try_into()
|
||||||
|
.expect("Couldn't add to zbus"),
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlGraphics: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reloadable for CtrlGraphics {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
self.auto_power()?;
|
||||||
|
info!("Reloaded gfx mode: {:?}", CtrlGraphics::get_vendor()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtrlGraphics {
|
impl CtrlGraphics {
|
||||||
pub fn new() -> std::io::Result<CtrlGraphics> {
|
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
||||||
let bus = PciBus::new()?;
|
let bus = PciBus::new()?;
|
||||||
|
|
||||||
info!("Rescanning PCI bus");
|
info!("Rescanning PCI bus");
|
||||||
@@ -123,13 +150,12 @@ impl CtrlGraphics {
|
|||||||
cmd.arg("-u");
|
cmd.arg("-u");
|
||||||
initfs_cmd = Some(cmd);
|
initfs_cmd = Some(cmd);
|
||||||
info!("Using initramfs update command 'update-initramfs'");
|
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 {
|
Ok(CtrlGraphics {
|
||||||
bus,
|
bus,
|
||||||
@@ -138,31 +164,11 @@ impl CtrlGraphics {
|
|||||||
nvidia,
|
nvidia,
|
||||||
other,
|
other,
|
||||||
initfs_cmd,
|
initfs_cmd,
|
||||||
|
config,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "use-zbus")]
|
fn get_prime_discrete() -> Result<String, RogError> {
|
||||||
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
|
||||||
server
|
|
||||||
.at(&"/org/asuslinux/Gfx".try_into().unwrap(), self)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!("CtrlGraphics: add_to_server {}", err);
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reload(&mut self) -> Result<(), Box<dyn Error>> {
|
|
||||||
self.auto_power()?;
|
|
||||||
info!("Reloaded gfx mode: {:?}", CtrlGraphics::get_vendor()?);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
let s = std::fs::read_to_string(PRIME_DISCRETE_PATH)
|
||||||
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?
|
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?
|
||||||
.trim()
|
.trim()
|
||||||
@@ -170,51 +176,70 @@ impl CtrlGraphics {
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_prime_discrete(mode: &str) -> Result<(), GfxError> {
|
fn set_prime_discrete(mode: &str) -> Result<(), RogError> {
|
||||||
std::fs::write(PRIME_DISCRETE_PATH, mode)
|
std::fs::write(PRIME_DISCRETE_PATH, mode)
|
||||||
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?;
|
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Associated method to get which vendor mode is set
|
/// Associated method to get which vendor mode is set
|
||||||
pub fn get_vendor() -> Result<String, GfxError> {
|
pub fn get_vendor() -> Result<String, RogError> {
|
||||||
|
let mode = match Self::get_prime_discrete() {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(_) => "nvidia".to_string(),
|
||||||
|
};
|
||||||
let modules = Module::all().map_err(|err| GfxError::Read("get_vendor".into(), err))?;
|
let modules = Module::all().map_err(|err| GfxError::Read("get_vendor".into(), err))?;
|
||||||
let vendor = if modules
|
|
||||||
.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(),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let driver_loaded = modules
|
||||||
|
.iter()
|
||||||
|
.any(|module| module.name == "nouveau" || module.name == "nvidia");
|
||||||
|
|
||||||
|
let vendor = if mode == "off" {
|
||||||
|
if driver_loaded {
|
||||||
|
info!("dGPU driver loaded for compute mode");
|
||||||
|
"compute".to_string()
|
||||||
|
} else {
|
||||||
|
info!("No dGPU driver loaded");
|
||||||
|
"integrated".to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("Assuming dGPU driver loaded");
|
||||||
if mode == "on-demand" {
|
if mode == "on-demand" {
|
||||||
"hybrid".to_string()
|
"hybrid".to_string()
|
||||||
} else if mode == "off" {
|
|
||||||
"compute".to_string()
|
|
||||||
} else {
|
} else {
|
||||||
"nvidia".to_string()
|
"nvidia".to_string()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
info!("No dGPU driver (nouveau or nvidia) loaded");
|
|
||||||
"integrated".to_string()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(vendor)
|
Ok(vendor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_switching_prime_modes(vendor: &GfxVendors) -> Result<bool, GfxError> {
|
fn is_switching_prime_modes(&self, vendor: &GfxVendors) -> Result<bool, RogError> {
|
||||||
let prev_mode = GfxVendors::from_str(&Self::get_vendor()?)?;
|
let prev_mode = GfxVendors::from_str(&Self::get_vendor()?)?;
|
||||||
let x = (prev_mode == GfxVendors::Hybrid || prev_mode == GfxVendors::Nvidia)
|
if prev_mode == GfxVendors::Integrated
|
||||||
&& (*vendor == GfxVendors::Hybrid || *vendor == GfxVendors::Nvidia);
|
&& (*vendor == GfxVendors::Hybrid || *vendor == GfxVendors::Nvidia)
|
||||||
Ok(x)
|
{
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
if (prev_mode == GfxVendors::Hybrid || prev_mode == GfxVendors::Nvidia)
|
||||||
|
&& *vendor == GfxVendors::Integrated
|
||||||
|
{
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
if let Ok(config) = self.config.clone().try_lock() {
|
||||||
|
if CtrlRogBios::has_dedicated_gfx_toggle() && config.gfx_nv_mode_is_dedicated {
|
||||||
|
if prev_mode == GfxVendors::Hybrid && *vendor == GfxVendors::Nvidia {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
if *vendor == GfxVendors::Hybrid && prev_mode == GfxVendors::Nvidia {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write out config files if required, enable/disable relevant services, and update the ramdisk
|
pub fn set_gfx_config(vendor: GfxVendors) -> Result<(), RogError> {
|
||||||
pub fn set(&mut self, vendor: GfxVendors) -> Result<String, GfxError> {
|
|
||||||
//self.switchable_or_fail()?;
|
|
||||||
|
|
||||||
let mode = if vendor == GfxVendors::Hybrid {
|
let mode = if vendor == GfxVendors::Hybrid {
|
||||||
"on-demand\n"
|
"on-demand\n"
|
||||||
} else if vendor == GfxVendors::Nvidia {
|
} else if vendor == GfxVendors::Nvidia {
|
||||||
@@ -227,10 +252,6 @@ impl CtrlGraphics {
|
|||||||
info!("Setting {} to {}", PRIME_DISCRETE_PATH, mode);
|
info!("Setting {} to {}", PRIME_DISCRETE_PATH, mode);
|
||||||
Self::set_prime_discrete(mode)?;
|
Self::set_prime_discrete(mode)?;
|
||||||
|
|
||||||
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
|
|
||||||
// or a reboot.
|
|
||||||
let no_reboot = Self::is_switching_prime_modes(&vendor)?;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
info!("Writing {}", MODPROBE_PATH);
|
info!("Writing {}", MODPROBE_PATH);
|
||||||
|
|
||||||
@@ -298,43 +319,69 @@ impl CtrlGraphics {
|
|||||||
status
|
status
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write out config files if required, enable/disable relevant services, and update the ramdisk
|
||||||
|
fn set(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
|
||||||
|
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
|
||||||
|
// or a reboot.
|
||||||
|
let reboot = self.is_switching_prime_modes(&vendor)?;
|
||||||
|
|
||||||
|
if CtrlRogBios::has_dedicated_gfx_toggle() {
|
||||||
|
if let Ok(config) = self.config.clone().try_lock() {
|
||||||
|
// Switch to dedicated if config says to do so
|
||||||
|
if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia {
|
||||||
|
CtrlRogBios::set_gfx_mode(true)
|
||||||
|
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
||||||
|
} else if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
|
// otherwise if switching to non-Nvidia mode turn off dedicated mode
|
||||||
|
if ded == 1 && vendor != GfxVendors::Nvidia {
|
||||||
|
CtrlRogBios::set_gfx_mode(false)
|
||||||
|
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::set_gfx_config(vendor.clone())?;
|
||||||
|
|
||||||
let mut required_action = GfxCtrlAction::None;
|
let mut required_action = GfxCtrlAction::None;
|
||||||
if !no_reboot {
|
if reboot {
|
||||||
info!("Updating initramfs");
|
info!("Updating initramfs");
|
||||||
if let Some(cmd) = self.initfs_cmd.as_mut() {
|
if let Some(cmd) = self.initfs_cmd.as_mut() {
|
||||||
|
// If switching to Nvidia dedicated we need these modules included
|
||||||
|
if Path::new(DRACUT_PATH).exists() && vendor == GfxVendors::Nvidia {
|
||||||
|
cmd.arg("--add-drivers");
|
||||||
|
cmd.arg("nvidia nvidia-drm nvidia-modeset nvidia-uvm");
|
||||||
|
info!("System uses dracut, forcing nvidia modules to be included in init");
|
||||||
|
}
|
||||||
|
|
||||||
let status = cmd
|
let status = cmd
|
||||||
.status()
|
.status()
|
||||||
.map_err(|err| GfxError::Write(format!("{:?}", cmd), err))?;
|
.map_err(|err| GfxError::Write(format!("{:?}", cmd), err))?;
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
error!("Ram disk update failed");
|
error!("Ram disk update failed");
|
||||||
|
return Ok("Ram disk update failed".into());
|
||||||
} else {
|
} else {
|
||||||
info!("Successfully updated iniramfs");
|
info!("Successfully updated iniramfs");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
required_action = GfxCtrlAction::Reboot;
|
required_action = GfxCtrlAction::Reboot;
|
||||||
} else if no_reboot {
|
} else if !reboot {
|
||||||
required_action = GfxCtrlAction::RestartX;
|
required_action = GfxCtrlAction::RestartX;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(required_action.into())
|
Ok(required_action.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn get_power(&self) -> Option<bool> {
|
fn get_runtime_status() -> Result<String, RogError> {
|
||||||
// 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";
|
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))?;
|
let buf = std::fs::read_to_string(PATH).map_err(|err| GfxError::Read(PATH.into(), err))?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_power(&self, power: bool) -> Result<(), GfxError> {
|
fn set_power(&self, power: bool) -> Result<(), RogError> {
|
||||||
// self.switchable_or_fail()?;
|
|
||||||
|
|
||||||
if power {
|
if power {
|
||||||
info!("Enabling graphics power");
|
info!("Enabling graphics power");
|
||||||
self.bus
|
self.bus
|
||||||
@@ -356,7 +403,7 @@ impl CtrlGraphics {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auto_power(&self) -> Result<(), GfxError> {
|
fn auto_power(&self) -> Result<(), RogError> {
|
||||||
let vendor = CtrlGraphics::get_vendor()?;
|
let vendor = CtrlGraphics::get_vendor()?;
|
||||||
self.set_power(vendor != "integrated")
|
self.set_power(vendor != "integrated")
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
pub mod vendors;
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod ctrl_gfx;
|
pub mod gfx;
|
||||||
|
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
|
||||||
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
|
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
|
||||||
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
||||||
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
|
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
|
||||||
// const DRACUT_PATH: &str = "/usr/bin/dracut";
|
const DRACUT_PATH: &str = "/usr/bin/dracut";
|
||||||
|
|
||||||
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
|
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
|
||||||
|
|
||||||
@@ -55,4 +53,3 @@ static PRIMARY_GPU_NVIDIA: &[u8] = br#"
|
|||||||
|
|
||||||
static PRIMARY_GPU_END: &[u8] = br#"
|
static PRIMARY_GPU_END: &[u8] = br#"
|
||||||
EndSection"#;
|
EndSection"#;
|
||||||
|
|
||||||
@@ -56,13 +56,13 @@ impl PciBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct GraphicsDevice {
|
pub struct GraphicsDevice {
|
||||||
id: String,
|
_id: String,
|
||||||
functions: Vec<PciDevice>,
|
functions: Vec<PciDevice>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicsDevice {
|
impl GraphicsDevice {
|
||||||
pub fn new(id: String, functions: Vec<PciDevice>) -> GraphicsDevice {
|
pub fn new(id: String, functions: Vec<PciDevice>) -> GraphicsDevice {
|
||||||
GraphicsDevice { id, functions }
|
GraphicsDevice { _id: id, functions }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists(&self) -> bool {
|
pub fn exists(&self) -> bool {
|
||||||
@@ -2,16 +2,63 @@
|
|||||||
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
use crate::{config::Config, error::RogError, laptops::HELP_ADDRESS};
|
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
|
||||||
use asus_nb::{aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN};
|
|
||||||
use log::{info, warn};
|
use crate::{
|
||||||
use std::convert::TryInto;
|
config::Config,
|
||||||
|
error::RogError,
|
||||||
|
laptops::{match_laptop, HELP_ADDRESS},
|
||||||
|
};
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use rog_types::{
|
||||||
|
aura_brightness_bytes,
|
||||||
|
aura_modes::{AuraModes, PER_KEY},
|
||||||
|
fancy::KeyColourArray,
|
||||||
|
LED_MSG_LEN,
|
||||||
|
};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
use std::{convert::TryInto, path::Path};
|
||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
|
use crate::GetSupported;
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct LedSupportedFunctions {
|
||||||
|
pub brightness_set: bool,
|
||||||
|
pub stock_led_modes: Option<Vec<u8>>,
|
||||||
|
pub per_key_led_mode: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for CtrlKbdBacklight {
|
||||||
|
type A = LedSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
// let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||||
|
let mut stock_led_modes = None;
|
||||||
|
let mut per_key_led_mode = false;
|
||||||
|
if let Some(laptop) = match_laptop() {
|
||||||
|
let modes = laptop.supported_modes().to_vec();
|
||||||
|
if modes.contains(&PER_KEY) {
|
||||||
|
per_key_led_mode = true;
|
||||||
|
let modes = modes.iter().filter(|x| **x != PER_KEY).copied().collect();
|
||||||
|
stock_led_modes = Some(modes);
|
||||||
|
} else {
|
||||||
|
stock_led_modes = Some(modes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LedSupportedFunctions {
|
||||||
|
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
|
||||||
|
stock_led_modes,
|
||||||
|
per_key_led_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CtrlKbdBacklight {
|
pub struct CtrlKbdBacklight {
|
||||||
led_node: Option<String>,
|
led_node: Option<String>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -42,6 +89,9 @@ impl crate::ZbusAdd for DbusKbdBacklight {
|
|||||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
server
|
server
|
||||||
.at(&"/org/asuslinux/Led".try_into().unwrap(), self)
|
.at(&"/org/asuslinux/Led".try_into().unwrap(), self)
|
||||||
|
.map_err(|err| {
|
||||||
|
error!("DbusKbdBacklight: add_to_server {}", err);
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,9 +109,14 @@ impl DbusKbdBacklight {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Ok(json) = serde_json::to_string(&data) {
|
if let Ok(json) = serde_json::to_string(&data) {
|
||||||
ctrl.do_command(data, &mut cfg)
|
match ctrl.do_command(data, &mut cfg) {
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
Ok(_) => {
|
||||||
self.notify_led(&json).ok();
|
self.notify_led(&json).ok();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("{}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +131,14 @@ impl DbusKbdBacklight {
|
|||||||
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() {
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
ctrl.toggle_mode(false, &mut cfg)
|
ctrl.toggle_mode(false, &mut cfg)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
|
||||||
|
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||||
|
if let Ok(json) = serde_json::to_string(&mode) {
|
||||||
|
self.notify_led(&json)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +147,14 @@ impl DbusKbdBacklight {
|
|||||||
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() {
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
ctrl.toggle_mode(true, &mut cfg)
|
ctrl.toggle_mode(true, &mut cfg)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
|
||||||
|
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||||
|
if let Ok(json) = serde_json::to_string(&mode) {
|
||||||
|
self.notify_led(&json)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,16 +282,55 @@ impl CtrlKbdBacklight {
|
|||||||
condev_iface: Option<&String>,
|
condev_iface: Option<&String>,
|
||||||
supported_modes: Vec<u8>,
|
supported_modes: Vec<u8>,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
) -> Self {
|
) -> Result<Self, RogError> {
|
||||||
// TODO: return error if *all* nodes are None
|
// TODO: return error if *all* nodes are None
|
||||||
CtrlKbdBacklight {
|
let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else(
|
||||||
led_node: Self::get_node_failover(id_product, None, Self::scan_led_node).ok(),
|
|err| {
|
||||||
kbd_node: Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node).ok(),
|
warn!("led_node: {}", err);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Some,
|
||||||
|
);
|
||||||
|
|
||||||
|
let kbd_node = Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node)
|
||||||
|
.map_or_else(
|
||||||
|
|err| {
|
||||||
|
warn!("kbd_node: {}", err);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Some,
|
||||||
|
);
|
||||||
|
|
||||||
|
let bright_node = Self::get_kbd_bright_path();
|
||||||
|
|
||||||
|
if led_node.is_none() && kbd_node.is_none() && Self::get_kbd_bright_path().is_err() {
|
||||||
|
return Err(RogError::MissingFunction(
|
||||||
|
"All keyboard features missing, you may require a v5.11 series kernel or newer"
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctrl = CtrlKbdBacklight {
|
||||||
|
// Using `ok` here so we can continue without keyboard features but
|
||||||
|
// still get brightness control at least... maybe...
|
||||||
|
led_node,
|
||||||
|
kbd_node,
|
||||||
// TODO: Check for existance
|
// TODO: Check for existance
|
||||||
bright_node: "/sys/class/leds/asus::kbd_backlight/brightness".to_string(),
|
bright_node: bright_node?.to_owned(),
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
config,
|
config,
|
||||||
|
};
|
||||||
|
Ok(ctrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_kbd_bright_path() -> Result<&'static str, RogError> {
|
||||||
|
if Path::new(KBD_BRIGHT_PATH).exists() {
|
||||||
|
Ok(KBD_BRIGHT_PATH)
|
||||||
|
} else {
|
||||||
|
Err(RogError::MissingFunction(
|
||||||
|
"Keyboard features missing, you may require a v5.11 series kernel or newer".into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,21 +339,12 @@ impl CtrlKbdBacklight {
|
|||||||
iface: Option<&String>,
|
iface: Option<&String>,
|
||||||
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
|
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
|
||||||
) -> Result<String, RogError> {
|
) -> Result<String, RogError> {
|
||||||
for n in 0..=2 {
|
match fun(id_product, iface) {
|
||||||
// 0,1,2 inclusive
|
Ok(o) => return Ok(o),
|
||||||
match fun(id_product, iface) {
|
Err(e) => {
|
||||||
Ok(o) => return Ok(o),
|
warn!("Looking for node: {}", e.to_string());
|
||||||
Err(e) => {
|
|
||||||
if n == 2 {
|
|
||||||
warn!("Looking for node: {}", e.to_string());
|
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Shouldn't be possible to reach this...
|
|
||||||
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
|
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +371,7 @@ impl CtrlKbdBacklight {
|
|||||||
{
|
{
|
||||||
if parent
|
if parent
|
||||||
.attribute_value("idProduct")
|
.attribute_value("idProduct")
|
||||||
.ok_or(RogError::NotFound("LED idProduct".into()))?
|
.ok_or_else(|| RogError::NotFound("LED idProduct".into()))?
|
||||||
== id_product
|
== id_product
|
||||||
{
|
{
|
||||||
if let Some(dev_node) = device.devnode() {
|
if let Some(dev_node) = device.devnode() {
|
||||||
@@ -342,6 +441,7 @@ impl CtrlKbdBacklight {
|
|||||||
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
||||||
if let Some(led_node) = &self.led_node {
|
if let Some(led_node) = &self.led_node {
|
||||||
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
|
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
|
||||||
|
// println!("write: {:02x?}", &message);
|
||||||
return file
|
return file
|
||||||
.write_all(message)
|
.write_all(message)
|
||||||
.map_err(|err| RogError::Write("write_bytes".into(), err));
|
.map_err(|err| RogError::Write("write_bytes".into(), err));
|
||||||
@@ -404,7 +504,6 @@ impl CtrlKbdBacklight {
|
|||||||
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
|
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
|
||||||
let current = config.kbd_backlight_mode;
|
let current = config.kbd_backlight_mode;
|
||||||
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
|
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
|
||||||
|
|
||||||
let mut idx = idx;
|
let mut idx = idx;
|
||||||
// goes past end of array
|
// goes past end of array
|
||||||
if reverse {
|
if reverse {
|
||||||
@@ -434,6 +533,10 @@ impl CtrlKbdBacklight {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
|
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
|
||||||
|
let mode_num: u8 = u8::from(mode);
|
||||||
|
if !self.supported_modes.contains(&mode_num) {
|
||||||
|
return Err(RogError::NotSupported);
|
||||||
|
}
|
||||||
match mode {
|
match mode {
|
||||||
AuraModes::PerKey(v) => {
|
AuraModes::PerKey(v) => {
|
||||||
if v.is_empty() || v[0].is_empty() {
|
if v.is_empty() || v[0].is_empty() {
|
||||||
@@ -443,27 +546,22 @@ impl CtrlKbdBacklight {
|
|||||||
self.write_effect(v)?;
|
self.write_effect(v)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
AuraModes::MultiStatic(_) | AuraModes::MultiBreathe(_) => {
|
||||||
let mode_num: u8 = u8::from(mode);
|
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
|
||||||
match mode {
|
for array in bytes.iter() {
|
||||||
AuraModes::MultiStatic(_) => {
|
self.write_bytes(array)?;
|
||||||
if self.supported_modes.contains(&mode_num) {
|
|
||||||
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
|
|
||||||
for array in bytes.iter() {
|
|
||||||
self.write_bytes(array)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if self.supported_modes.contains(&mode_num) {
|
|
||||||
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
|
||||||
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
|
||||||
self.write_bytes(&LED_APPLY)?;
|
self.write_bytes(&LED_APPLY)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
||||||
|
self.write_bytes(&bytes)?;
|
||||||
|
self.write_bytes(&LED_SET)?;
|
||||||
|
// Changes won't persist unless apply is set
|
||||||
|
self.write_bytes(&LED_APPLY)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
257
daemon/src/ctrl_rog_bios.rs
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
use crate::{config::Config, ctrl_gfx::gfx::CtrlGraphics, error::RogError, GetSupported};
|
||||||
|
//use crate::dbus::DbusEvents;
|
||||||
|
use log::{info, warn};
|
||||||
|
use rog_types::gfx_vendors::GfxVendors;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
|
static ASUS_SWITCH_GRAPHIC_MODE: &str =
|
||||||
|
"/sys/firmware/efi/efivars/AsusSwitchGraphicMode-607005d5-3f75-4b2e-98f0-85ba66797a3e";
|
||||||
|
static ASUS_POST_LOGO_SOUND: &str =
|
||||||
|
"/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e";
|
||||||
|
|
||||||
|
pub struct CtrlRogBios {
|
||||||
|
_config: Arc<Mutex<Config>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct RogBiosSupportedFunctions {
|
||||||
|
pub post_sound_toggle: bool,
|
||||||
|
pub dedicated_gfx_toggle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for CtrlRogBios {
|
||||||
|
type A = RogBiosSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
RogBiosSupportedFunctions {
|
||||||
|
post_sound_toggle: CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND).is_ok(),
|
||||||
|
dedicated_gfx_toggle: CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl CtrlRogBios {
|
||||||
|
pub fn set_dedicated_graphic_mode(&mut self, dedicated: bool) {
|
||||||
|
Self::set_gfx_mode(dedicated)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
self.notify_dedicated_graphic_mode(dedicated)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: notify_asus_switch_graphic_mode {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dedicated_graphic_mode(&self) -> i8 {
|
||||||
|
Self::get_gfx_mode()
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: get_gfx_mode {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.unwrap_or(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
pub fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()> {}
|
||||||
|
|
||||||
|
// // // // // // // // // //
|
||||||
|
|
||||||
|
pub fn set_post_boot_sound(&mut self, on: bool) {
|
||||||
|
Self::set_boot_sound(on)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: set_post_boot_sound {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
self.notify_post_boot_sound(on)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: notify_post_boot_sound {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post_boot_sound(&self) -> i8 {
|
||||||
|
Self::get_boot_sound()
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: get_boot_sound {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.unwrap_or(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
pub fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for CtrlRogBios {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&"/org/asuslinux/RogBios".try_into().unwrap(), self)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("CtrlRogBios: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlRogBios {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlRogBios {
|
||||||
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||||
|
match CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE) {
|
||||||
|
Ok(_) => {
|
||||||
|
CtrlRogBios::set_path_mutable(ASUS_SWITCH_GRAPHIC_MODE)?;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
info!("ROG Switchable Graphics (bios) not detected: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND) {
|
||||||
|
Ok(_) => {
|
||||||
|
CtrlRogBios::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
info!("ROG boot sound toggle (bios) not detected: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CtrlRogBios { _config: config })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_path_mutable(path: &str) -> Result<(), RogError> {
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
let output = Command::new("/usr/bin/chattr")
|
||||||
|
.arg("-i")
|
||||||
|
.arg(path)
|
||||||
|
.output()
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
info!("Set {} writeable: status: {}", path, output.status);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_path_exists(path: &str) -> Result<(), RogError> {
|
||||||
|
if Path::new(path).exists() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(RogError::MissingFunction(path.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_dedicated_gfx_toggle() -> bool {
|
||||||
|
if CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_gfx_mode() -> Result<i8, RogError> {
|
||||||
|
let path = ASUS_SWITCH_GRAPHIC_MODE;
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(path)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)
|
||||||
|
.map_err(|err| RogError::Read(path.into(), err))?;
|
||||||
|
|
||||||
|
let idx = data.len() - 1;
|
||||||
|
Ok(data[idx] as i8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set_gfx_mode(dedicated: bool) -> Result<(), RogError> {
|
||||||
|
let path = ASUS_SWITCH_GRAPHIC_MODE;
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open(path)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data).unwrap();
|
||||||
|
|
||||||
|
let idx = data.len() - 1;
|
||||||
|
if dedicated {
|
||||||
|
data[idx] = 1;
|
||||||
|
info!("Set system-level graphics mode: Dedicated Nvidia");
|
||||||
|
} else {
|
||||||
|
data[idx] = 0;
|
||||||
|
info!("Set system-level graphics mode: Optimus");
|
||||||
|
}
|
||||||
|
file.write_all(&data)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
|
if let Ok(vendor) = CtrlGraphics::get_vendor() {
|
||||||
|
if ded == 1 && vendor != "nvidia" {
|
||||||
|
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
|
CtrlGraphics::set_gfx_config(GfxVendors::Nvidia)
|
||||||
|
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_boot_sound() -> Result<i8, RogError> {
|
||||||
|
let path = ASUS_POST_LOGO_SOUND;
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(path)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)
|
||||||
|
.map_err(|err| RogError::Read(path.into(), err))?;
|
||||||
|
|
||||||
|
let idx = data.len() - 1;
|
||||||
|
Ok(data[idx] as i8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set_boot_sound(on: bool) -> Result<(), RogError> {
|
||||||
|
let path = ASUS_POST_LOGO_SOUND;
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open(path)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)
|
||||||
|
.map_err(|err| RogError::Read(path.into(), err))?;
|
||||||
|
|
||||||
|
let idx = data.len() - 1;
|
||||||
|
if on {
|
||||||
|
data[idx] = 1;
|
||||||
|
info!("Set boot POST sound on");
|
||||||
|
} else {
|
||||||
|
data[idx] = 0;
|
||||||
|
info!("Set boot POST sound off");
|
||||||
|
}
|
||||||
|
file.write_all(&data)
|
||||||
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
56
daemon/src/ctrl_supported.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ctrl_anime::{AnimeSupportedFunctions, CtrlAnimeDisplay},
|
||||||
|
ctrl_charge::{ChargeSupportedFunctions, CtrlCharge},
|
||||||
|
ctrl_fan_cpu::{CtrlFanAndCPU, FanCpuSupportedFunctions},
|
||||||
|
ctrl_leds::{CtrlKbdBacklight, LedSupportedFunctions},
|
||||||
|
ctrl_rog_bios::{CtrlRogBios, RogBiosSupportedFunctions},
|
||||||
|
GetSupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SupportedFunctions {
|
||||||
|
anime_ctrl: AnimeSupportedFunctions,
|
||||||
|
charge_ctrl: ChargeSupportedFunctions,
|
||||||
|
fan_cpu_ctrl: FanCpuSupportedFunctions,
|
||||||
|
keyboard_led: LedSupportedFunctions,
|
||||||
|
rog_bios_ctrl: RogBiosSupportedFunctions,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl SupportedFunctions {
|
||||||
|
fn supported_functions(&self) -> String {
|
||||||
|
serde_json::to_string_pretty(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for SupportedFunctions {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&"/org/asuslinux/Supported".try_into().unwrap(), self)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("SupportedFunctions: add_to_server {}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for SupportedFunctions {
|
||||||
|
type A = SupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
SupportedFunctions {
|
||||||
|
keyboard_led: CtrlKbdBacklight::get_supported(),
|
||||||
|
anime_ctrl: CtrlAnimeDisplay::get_supported(),
|
||||||
|
charge_ctrl: CtrlCharge::get_supported(),
|
||||||
|
fan_cpu_ctrl: CtrlFanAndCPU::get_supported(),
|
||||||
|
rog_bios_ctrl: CtrlRogBios::get_supported(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
use ctrl_gfx::ctrl_gfx::CtrlGraphics;
|
|
||||||
use daemon::config::Config;
|
|
||||||
use daemon::ctrl_anime::CtrlAnimeDisplay;
|
|
||||||
use daemon::ctrl_charge::CtrlCharge;
|
use daemon::ctrl_charge::CtrlCharge;
|
||||||
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
|
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
|
||||||
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
||||||
use daemon::laptops::match_laptop;
|
use daemon::laptops::match_laptop;
|
||||||
|
use daemon::{
|
||||||
|
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||||
|
};
|
||||||
|
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
|
||||||
|
|
||||||
use asus_nb::DBUS_NAME;
|
|
||||||
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
use rog_dbus::DBUS_NAME;
|
||||||
|
use rog_types::gfx_vendors::GfxVendors;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use daemon::ctrl_rog_bios::CtrlRogBios;
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use zbus::fdo;
|
use zbus::fdo;
|
||||||
@@ -28,7 +31,10 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.filter(None, LevelFilter::Info)
|
.filter(None, LevelFilter::Info)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
info!("Version: {}", daemon::VERSION);
|
info!("daemon version {}", daemon::VERSION);
|
||||||
|
info!(" rog-dbus version {}", rog_dbus::VERSION);
|
||||||
|
info!("rog-types version {}", rog_types::VERSION);
|
||||||
|
|
||||||
start_daemon()?;
|
start_daemon()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -40,14 +46,16 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// - to maintain constant times of 1ms, per-key colours should use
|
// - to maintain constant times of 1ms, per-key colours should use
|
||||||
// the effect endpoint so that the complete colour block is written
|
// the effect endpoint so that the complete colour block is written
|
||||||
// as fast as 1ms per row of the matrix inside it. (10ms total time)
|
// as fast as 1ms per row of the matrix inside it. (10ms total time)
|
||||||
//
|
|
||||||
// DBUS processing takes 6ms if not tokiod
|
|
||||||
fn start_daemon() -> Result<(), Box<dyn Error>> {
|
fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
|
let supported = SupportedFunctions::get_supported();
|
||||||
|
print_board_info();
|
||||||
|
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
|
||||||
|
|
||||||
let laptop = match_laptop();
|
let laptop = match_laptop();
|
||||||
let config = if let Some(laptop) = laptop.as_ref() {
|
let config = if let Some(laptop) = laptop.as_ref() {
|
||||||
Config::default().load(laptop.supported_modes())
|
Config::load(laptop.supported_modes())
|
||||||
} else {
|
} else {
|
||||||
Config::default().load(&[])
|
Config::load(&[])
|
||||||
};
|
};
|
||||||
|
|
||||||
let connection = Connection::new_system()?;
|
let connection = Connection::new_system()?;
|
||||||
@@ -55,9 +63,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
||||||
let mut object_server = zbus::ObjectServer::new(&connection);
|
let mut object_server = zbus::ObjectServer::new(&connection);
|
||||||
|
|
||||||
|
supported.add_to_server(&mut object_server);
|
||||||
|
|
||||||
let enable_gfx_switching = config.gfx_managed;
|
let enable_gfx_switching = config.gfx_managed;
|
||||||
let config = Arc::new(Mutex::new(config));
|
let config = Arc::new(Mutex::new(config));
|
||||||
|
|
||||||
|
match CtrlRogBios::new(config.clone()) {
|
||||||
|
Ok(mut ctrl) => {
|
||||||
|
// Do a reload of any settings
|
||||||
|
ctrl.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
|
||||||
|
// Then register to dbus server
|
||||||
|
ctrl.add_to_server(&mut object_server);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("rog_bios_control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match CtrlCharge::new(config.clone()) {
|
match CtrlCharge::new(config.clone()) {
|
||||||
Ok(mut ctrl) => {
|
Ok(mut ctrl) => {
|
||||||
// Do a reload of any settings
|
// Do a reload of any settings
|
||||||
@@ -81,8 +104,22 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if enable_gfx_switching {
|
if enable_gfx_switching {
|
||||||
match CtrlGraphics::new() {
|
match CtrlGraphics::new(config.clone()) {
|
||||||
Ok(mut ctrl) => {
|
Ok(mut ctrl) => {
|
||||||
|
// Need to check if a laptop has the dedicated gfx switch
|
||||||
|
if CtrlRogBios::has_dedicated_gfx_toggle() {
|
||||||
|
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
|
if let Ok(vendor) = CtrlGraphics::get_vendor() {
|
||||||
|
if ded == 1 && vendor != "nvidia" {
|
||||||
|
error!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
|
error!("You must reboot to enable Nvidia driver");
|
||||||
|
CtrlGraphics::set_gfx_config(GfxVendors::Nvidia)?;
|
||||||
|
} else if ded == 0 {
|
||||||
|
info!("Dedicated GFX toggle is off");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ctrl.reload()
|
ctrl.reload()
|
||||||
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
||||||
ctrl.add_to_server(&mut object_server);
|
ctrl.add_to_server(&mut object_server);
|
||||||
@@ -96,29 +133,30 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
// Collect tasks for task thread
|
// Collect tasks for task thread
|
||||||
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
|
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
|
||||||
|
|
||||||
match CtrlFanAndCPU::new(config.clone()) {
|
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config.clone()).map_err(|err| {
|
||||||
Ok(mut ctrl) => {
|
error!("Profile control: {}", err);
|
||||||
ctrl.reload()
|
}) {
|
||||||
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
ctrl.reload()
|
||||||
let tmp = Arc::new(Mutex::new(ctrl));
|
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
||||||
DbusFanAndCpu::new(tmp.clone()).add_to_server(&mut object_server);
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
tasks.push(tmp);
|
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("Profile control: {}", err);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(laptop) = laptop {
|
if let Some(laptop) = laptop {
|
||||||
let ctrl = CtrlKbdBacklight::new(
|
if let Ok(ctrl) = CtrlKbdBacklight::new(
|
||||||
laptop.usb_product(),
|
laptop.usb_product(),
|
||||||
laptop.condev_iface(),
|
laptop.condev_iface(),
|
||||||
laptop.supported_modes().to_owned(),
|
laptop.supported_modes().to_owned(),
|
||||||
config,
|
config,
|
||||||
);
|
)
|
||||||
let tmp = Arc::new(Mutex::new(ctrl));
|
.map_err(|err| {
|
||||||
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
error!("Keyboard control: {}", err);
|
||||||
tasks.push(tmp);
|
err
|
||||||
|
}) {
|
||||||
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
|
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
||||||
|
tasks.push(tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement messaging between threads to check fails
|
// TODO: implement messaging between threads to check fails
|
||||||
@@ -140,10 +178,15 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
object_server.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| {
|
object_server
|
||||||
let x = obj.limit();
|
.with(&"/org/asuslinux/Charge".try_into()?, |obj: &CtrlCharge| {
|
||||||
obj.notify_charge(x as u8)
|
let x = obj.limit();
|
||||||
})?;
|
obj.notify_charge(x as u8)
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("object_server notify_charge error: {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Err(err) = object_server.try_handle_next() {
|
if let Err(err) = object_server.try_handle_next() {
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
use intel_pstate::PStateError;
|
use intel_pstate::PStateError;
|
||||||
use rog_fan_curve::CurveError;
|
use rog_fan_curve::CurveError;
|
||||||
|
use rog_types::error::GraphicsError;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::ctrl_gfx::error::GfxError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RogError {
|
pub enum RogError {
|
||||||
ParseFanLevel,
|
ParseFanLevel,
|
||||||
@@ -20,6 +23,8 @@ pub enum RogError {
|
|||||||
DoTask(String),
|
DoTask(String),
|
||||||
MissingFunction(String),
|
MissingFunction(String),
|
||||||
MissingLedBrightNode(String, std::io::Error),
|
MissingLedBrightNode(String, std::io::Error),
|
||||||
|
ReloadFail(String),
|
||||||
|
GfxSwitching(GfxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RogError {
|
impl fmt::Display for RogError {
|
||||||
@@ -41,6 +46,8 @@ impl fmt::Display for RogError {
|
|||||||
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::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,3 +65,11 @@ impl From<CurveError> for RogError {
|
|||||||
RogError::FanCurve(err)
|
RogError::FanCurve(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<GraphicsError> for RogError {
|
||||||
|
fn from(err: GraphicsError) -> Self {
|
||||||
|
match err {
|
||||||
|
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use asus_nb::aura_modes::{AuraModes, BREATHING, STATIC, STROBE};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use rog_types::aura_modes::{AuraModes, BREATHING, STATIC};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@@ -8,6 +8,9 @@ pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
|
|||||||
|
|
||||||
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
||||||
|
|
||||||
|
static LAPTOP_DEVICES: [u16; 3] = [0x1866, 0x1869, 0x1854];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct LaptopBase {
|
pub struct LaptopBase {
|
||||||
usb_product: String,
|
usb_product: String,
|
||||||
condev_iface: Option<String>, // required for finding the Consumer Device interface
|
condev_iface: Option<String>, // required for finding the Consumer Device interface
|
||||||
@@ -27,25 +30,24 @@ impl LaptopBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_laptop() -> Option<LaptopBase> {
|
pub fn match_laptop() -> Option<LaptopBase> {
|
||||||
for device in rusb::devices().unwrap().iter() {
|
for device in rusb::devices().expect("Couldn't get device").iter() {
|
||||||
let device_desc = device.device_descriptor().unwrap();
|
let device_desc = device
|
||||||
|
.device_descriptor()
|
||||||
|
.expect("Couldn't get device descriptor");
|
||||||
if device_desc.vendor_id() == 0x0b05 {
|
if device_desc.vendor_id() == 0x0b05 {
|
||||||
match device_desc.product_id() {
|
if LAPTOP_DEVICES.contains(&device_desc.product_id()) {
|
||||||
0x1866 => {
|
let prod_str = format!("{:x?}", device_desc.product_id());
|
||||||
let laptop = select_1866_device("1866".to_owned());
|
|
||||||
print_modes(&laptop.supported_modes);
|
if device_desc.product_id() == 0x1854 {
|
||||||
|
let mut laptop = laptop(prod_str, None);
|
||||||
|
if laptop.supported_modes.is_empty() {
|
||||||
|
laptop.supported_modes = vec![STATIC, BREATHING];
|
||||||
|
}
|
||||||
return Some(laptop);
|
return Some(laptop);
|
||||||
}
|
}
|
||||||
0x1869 => return Some(select_1866_device("1869".to_owned())),
|
|
||||||
0x1854 => {
|
let laptop = laptop(prod_str, Some("02".to_owned()));
|
||||||
info!("Found GL753 or similar");
|
return Some(laptop);
|
||||||
return Some(LaptopBase {
|
|
||||||
usb_product: "1854".to_string(),
|
|
||||||
condev_iface: None,
|
|
||||||
supported_modes: vec![STATIC, BREATHING, STROBE],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,18 +59,14 @@ pub fn match_laptop() -> Option<LaptopBase> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_1866_device(prod: String) -> LaptopBase {
|
fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
|
||||||
let dmi = sysfs_class::DmiId::default();
|
let dmi = sysfs_class::DmiId::default();
|
||||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||||
let prod_family = dmi.product_family().expect("Could not get product_family");
|
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||||
let prod_name = dmi.product_name().expect("Could not get product_name");
|
|
||||||
|
|
||||||
info!("Product name: {}", prod_name.trim());
|
|
||||||
info!("Board name: {}", board_name.trim());
|
|
||||||
|
|
||||||
let mut laptop = LaptopBase {
|
let mut laptop = LaptopBase {
|
||||||
usb_product: prod,
|
usb_product: prod,
|
||||||
condev_iface: Some("02".to_owned()),
|
condev_iface,
|
||||||
supported_modes: vec![],
|
supported_modes: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +79,18 @@ fn select_1866_device(prod: String) -> LaptopBase {
|
|||||||
laptop
|
laptop
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_modes(supported_modes: &[u8]) {
|
pub fn print_board_info() {
|
||||||
|
let dmi = sysfs_class::DmiId::default();
|
||||||
|
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||||
|
let prod_name = dmi.product_name().expect("Could not get product_name");
|
||||||
|
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||||
|
|
||||||
|
info!("Product name: {}", prod_name.trim());
|
||||||
|
info!("Product family: {}", prod_family.trim());
|
||||||
|
info!("Board name: {}", board_name.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_modes(supported_modes: &[u8]) {
|
||||||
if !supported_modes.is_empty() {
|
if !supported_modes.is_empty() {
|
||||||
info!("Supported Keyboard LED modes are:");
|
info!("Supported Keyboard LED modes are:");
|
||||||
for mode in supported_modes {
|
for mode in supported_modes {
|
||||||
62
daemon/src/lib.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#![deny(unused_must_use)]
|
||||||
|
/// Configuration loading, saving
|
||||||
|
pub mod config;
|
||||||
|
/// Control of AniMe matrix display
|
||||||
|
pub mod ctrl_anime;
|
||||||
|
/// Control of battery charge level
|
||||||
|
pub mod ctrl_charge;
|
||||||
|
/// Control CPU min/max freq and turbo, fan mode, fan curves
|
||||||
|
///
|
||||||
|
/// Intel machines can control:
|
||||||
|
/// - CPU min/max frequency
|
||||||
|
/// - CPU turbo enable/disable
|
||||||
|
/// - Fan mode (normal, boost, silent)
|
||||||
|
///
|
||||||
|
/// AMD machines can control:
|
||||||
|
/// - CPU turbo enable/disable
|
||||||
|
/// - Fan mode (normal, boost, silent)
|
||||||
|
/// - Fan min/max RPM curve
|
||||||
|
pub mod ctrl_fan_cpu;
|
||||||
|
/// GPU switching and power
|
||||||
|
pub mod ctrl_gfx;
|
||||||
|
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||||
|
pub mod ctrl_leds;
|
||||||
|
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
||||||
|
pub mod ctrl_rog_bios;
|
||||||
|
/// Laptop matching to determine capabilities
|
||||||
|
pub mod laptops;
|
||||||
|
|
||||||
|
/// Fetch all supported functions for the laptop
|
||||||
|
pub mod ctrl_supported;
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
use crate::error::RogError;
|
||||||
|
use config::Config;
|
||||||
|
use zbus::ObjectServer;
|
||||||
|
|
||||||
|
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
pub trait Reloadable {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ZbusAdd {
|
||||||
|
fn add_to_server(self, server: &mut ObjectServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CtrlTask {
|
||||||
|
fn do_task(&mut self) -> Result<(), RogError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CtrlTaskComplex {
|
||||||
|
type A;
|
||||||
|
|
||||||
|
fn do_task(&mut self, config: &mut Config, event: Self::A);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetSupported {
|
||||||
|
type A;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A;
|
||||||
|
}
|
||||||
@@ -8,6 +8,11 @@ prod_family = "Zephyrus M"
|
|||||||
board_names = ["GU502GV"]
|
board_names = ["GU502GV"]
|
||||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
|
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "ROG Zephyrus M15"
|
||||||
|
board_names = ["GU502LW"]
|
||||||
|
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
|
||||||
|
|
||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "Zephyrus"
|
prod_family = "Zephyrus"
|
||||||
board_names = ["GM501GM", "GX531"]
|
board_names = ["GM501GM", "GX531"]
|
||||||
@@ -21,7 +26,7 @@ led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
|
|||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "ROG Strix"
|
prod_family = "ROG Strix"
|
||||||
board_names = ["GX531", "G512LV", "G712LV"]
|
board_names = ["GX531", "G512LV", "G712LV"]
|
||||||
led_modes = [0, 1, 2, 3, 10, 13]
|
led_modes = [0, 1, 2, 3, 10, 13, 14]
|
||||||
|
|
||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "ROG Strix"
|
prod_family = "ROG Strix"
|
||||||
@@ -31,7 +36,7 @@ led_modes = [0, 1, 2, 3, 10]
|
|||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "Strix"
|
prod_family = "Strix"
|
||||||
board_names = ["G731GV", "G731GW", "G531GV"]
|
board_names = ["G731GV", "G731GW", "G531GV"]
|
||||||
led_modes = [0, 1, 2, 3, 13]
|
led_modes = [0, 1, 2, 3, 13, 14]
|
||||||
|
|
||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "Strix"
|
prod_family = "Strix"
|
||||||
@@ -41,4 +46,9 @@ led_modes = [0, 1, 2, 3]
|
|||||||
[[led_modes]]
|
[[led_modes]]
|
||||||
prod_family = "Strix Scar"
|
prod_family = "Strix Scar"
|
||||||
board_names = ["G531", "G731"]
|
board_names = ["G531", "G731"]
|
||||||
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 255]
|
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 255]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "ROG"
|
||||||
|
board_names = ["GL553VE"]
|
||||||
|
led_modes = [0, 1, 2, 13, 14]
|
||||||
@@ -1 +1,2 @@
|
|||||||
ACTION=="add|change", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="18[0-9][0-9]", ENV{ID_TYPE}=="hid", TAG+="systemd", ENV{SYSTEMD_WANTS}="asusd.service"
|
ACTION=="add|change", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="18[0-9][0-9]|193b", ENV{ID_TYPE}=="hid", TAG+="systemd", ENV{SYSTEMD_WANTS}="asusd.service"
|
||||||
|
ACTION=="add|remove", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="0b05", ENV{ID_MODEL_ID}=="18[0-9][0-9]|193b", RUN+="systemctl restart asusd.service"
|
||||||
|
|||||||
18
rog-dbus/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "rog_dbus"
|
||||||
|
version = "3.0.0"
|
||||||
|
license = "MPL-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||||
|
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
|
||||||
|
description = "dbus interface methods for asusctl"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde_json = "^1.0"
|
||||||
|
rog_types = { path = "../rog-types" }
|
||||||
|
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
||||||
|
zbus = "^1.8"
|
||||||
|
zbus_macros = "^1.8"
|
||||||
|
zvariant = "^2.4"
|
||||||
168
rog-dbus/src/lib.rs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
||||||
|
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
||||||
|
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
||||||
|
pub const LED_MSG_LEN: usize = 17;
|
||||||
|
|
||||||
|
pub mod zbus_anime;
|
||||||
|
pub mod zbus_charge;
|
||||||
|
pub mod zbus_gfx;
|
||||||
|
pub mod zbus_led;
|
||||||
|
pub mod zbus_profile;
|
||||||
|
pub mod zbus_rogbios;
|
||||||
|
pub mod zbus_supported;
|
||||||
|
|
||||||
|
use rog_types::aura_modes::AuraModes;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use zbus::{Connection, Result, SignalReceiver};
|
||||||
|
|
||||||
|
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
pub struct DbusProxies<'a> {
|
||||||
|
anime: zbus_anime::AnimeProxy<'a>,
|
||||||
|
charge: zbus_charge::ChargeProxy<'a>,
|
||||||
|
gfx: zbus_gfx::GfxProxy<'a>,
|
||||||
|
led: zbus_led::LedProxy<'a>,
|
||||||
|
profile: zbus_profile::ProfileProxy<'a>,
|
||||||
|
rog_bios: zbus_rogbios::RogBiosProxy<'a>,
|
||||||
|
supported: zbus_supported::SupportProxy<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DbusProxies<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Result<(Self, Connection)> {
|
||||||
|
let conn = Connection::new_system()?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
DbusProxies {
|
||||||
|
anime: zbus_anime::AnimeProxy::new(&conn)?,
|
||||||
|
led: zbus_led::LedProxy::new(&conn)?,
|
||||||
|
charge: zbus_charge::ChargeProxy::new(&conn)?,
|
||||||
|
gfx: zbus_gfx::GfxProxy::new(&conn)?,
|
||||||
|
profile: zbus_profile::ProfileProxy::new(&conn)?,
|
||||||
|
rog_bios: zbus_rogbios::RogBiosProxy::new(&conn)?,
|
||||||
|
supported: zbus_supported::SupportProxy::new(&conn)?,
|
||||||
|
},
|
||||||
|
conn,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_recv(&'a self, conn: Connection) -> SignalReceiver {
|
||||||
|
let mut recv = SignalReceiver::new(conn);
|
||||||
|
//recv.receive_for(&self.proxy_anime);
|
||||||
|
recv.receive_for(self.led.proxy());
|
||||||
|
recv.receive_for(self.charge.proxy());
|
||||||
|
recv.receive_for(self.gfx.proxy());
|
||||||
|
recv.receive_for(self.profile.proxy());
|
||||||
|
recv
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anime(&self) -> &zbus_anime::AnimeProxy<'a> {
|
||||||
|
&self.anime
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn charge(&self) -> &zbus_charge::ChargeProxy<'a> {
|
||||||
|
&self.charge
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gfx(&self) -> &zbus_gfx::GfxProxy<'a> {
|
||||||
|
&self.gfx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn led(&self) -> &zbus_led::LedProxy<'a> {
|
||||||
|
&self.led
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn profile(&self) -> &zbus_profile::ProfileProxy<'a> {
|
||||||
|
&self.profile
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rog_bios(&self) -> &zbus_rogbios::RogBiosProxy<'a> {
|
||||||
|
&self.rog_bios
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported(&self) -> &zbus_supported::SupportProxy<'a> {
|
||||||
|
&self.supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signals separated out
|
||||||
|
pub struct Signals {
|
||||||
|
pub gfx_vendor: Arc<Mutex<Option<String>>>,
|
||||||
|
pub gfx_action: Arc<Mutex<Option<String>>>,
|
||||||
|
pub profile: Arc<Mutex<Option<String>>>,
|
||||||
|
pub led_mode: Arc<Mutex<Option<AuraModes>>>,
|
||||||
|
pub charge: Arc<Mutex<Option<u8>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signals {
|
||||||
|
#[inline]
|
||||||
|
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 {
|
||||||
|
gfx_vendor: gfx_vendor_signal,
|
||||||
|
gfx_action: gfx_action_signal,
|
||||||
|
profile: profile_signal,
|
||||||
|
led_mode: ledmode_signal,
|
||||||
|
charge: charge_signal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is the main way to communicate with the DBUS interface
|
||||||
|
pub struct AuraDbusClient<'a> {
|
||||||
|
proxies: DbusProxies<'a>,
|
||||||
|
signals: Signals,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AuraDbusClient<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Result<(Self, Connection)> {
|
||||||
|
let (proxies, conn) = DbusProxies::new()?;
|
||||||
|
let signals = Signals::new(&proxies)?;
|
||||||
|
|
||||||
|
Ok((AuraDbusClient { proxies, signals }, conn))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxies(&self) -> &DbusProxies {
|
||||||
|
&self.proxies
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GFX
|
||||||
|
*/
|
||||||
|
pub fn gfx_wait_changed(&self) -> Result<String> {
|
||||||
|
loop {
|
||||||
|
if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
|
||||||
|
if res.is_none() {
|
||||||
|
if let Ok(lock) = self.signals.gfx_action.lock() {
|
||||||
|
if let Some(stuff) = lock.as_ref() {
|
||||||
|
return Ok(stuff.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return Ok("Failed for unknown reason".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
rog-dbus/src/zbus_anime.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use rog_types::anime_matrix::{AniMeDataBuffer, AniMeImageBuffer};
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Anime"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// SetBootOnOff method
|
||||||
|
fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetOnOff method
|
||||||
|
fn set_on_off(&self, status: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// WriteDirect method
|
||||||
|
fn write_direct(&self, input: &[u8]) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// WriteImage method
|
||||||
|
fn write_image(&self, input: &[Vec<u8>]) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AnimeProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> AnimeProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(AnimeProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn toggle_boot_on(&self, on: bool) -> Result<()> {
|
||||||
|
self.0.set_boot_on_off(on)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn toggle_on(&self, on: bool) -> Result<()> {
|
||||||
|
self.0.set_on_off(on)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_direct(&self, input: AniMeDataBuffer) -> Result<()> {
|
||||||
|
self.0.write_direct(input.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_image(&self, input: AniMeImageBuffer) -> Result<()> {
|
||||||
|
self.0.write_image(input.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
73
rog-dbus/src/zbus_charge.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Charge' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Charge"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// Limit method
|
||||||
|
fn limit(&self) -> zbus::Result<i16>;
|
||||||
|
|
||||||
|
/// SetLimit method
|
||||||
|
fn set_limit(&self, limit: u8) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyCharge signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ChargeProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> ChargeProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(ChargeProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_limit(&self, level: u8) -> Result<()> {
|
||||||
|
self.0.set_limit(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_limit(&self) -> Result<i16> {
|
||||||
|
self.0.limit()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_charge(&self, charge: Arc<Mutex<Option<u8>>>) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_charge(move |data| {
|
||||||
|
if let Ok(mut lock) = charge.lock() {
|
||||||
|
*lock = Some(data);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
98
rog-dbus/src/zbus_gfx.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Gfx`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Gfx' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Gfx"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// Power method
|
||||||
|
fn power(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// SetVendor method
|
||||||
|
fn set_vendor(&self, vendor: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Vendor method
|
||||||
|
fn vendor(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// NotifyAction signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_action(&self, action: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyGfx signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GfxProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> GfxProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(GfxProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn gfx_get_pwr(&self) -> Result<String> {
|
||||||
|
self.0.power()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn gfx_get_mode(&self) -> Result<String> {
|
||||||
|
self.0.vendor()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn gfx_write_mode(&self, vendor: &str) -> Result<()> {
|
||||||
|
self.0.set_vendor(vendor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_action(
|
||||||
|
&self,
|
||||||
|
action: Arc<Mutex<Option<String>>>,
|
||||||
|
) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_action(move |data| {
|
||||||
|
if let Ok(mut lock) = action.lock() {
|
||||||
|
*lock = Some(data.to_owned());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_gfx(&self, vendor: Arc<Mutex<Option<String>>>) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_gfx(move |data| {
|
||||||
|
if let Ok(mut lock) = vendor.lock() {
|
||||||
|
*lock = Some(data.to_owned());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
142
rog-dbus/src/zbus_led.rs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Led' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
use rog_types::{aura_modes::AuraModes, cli_options::LedBrightness, fancy::KeyColourArray};
|
||||||
|
|
||||||
|
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Led"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// LedBrightness method
|
||||||
|
fn led_brightness(&self) -> zbus::Result<i16>;
|
||||||
|
|
||||||
|
/// LedMode method
|
||||||
|
fn led_mode(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// LedModes method
|
||||||
|
fn led_modes(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// NextLedMode method
|
||||||
|
fn next_led_mode(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// PrevLedMode method
|
||||||
|
fn prev_led_mode(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetLedMode method
|
||||||
|
fn set_led_mode(&self, data: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyLed signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LedProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> LedProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(LedProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_led_brightness(&self) -> Result<LedBrightness> {
|
||||||
|
match self.0.led_brightness()? {
|
||||||
|
-1 => Ok(LedBrightness::new(None)),
|
||||||
|
level => Ok(LedBrightness::new(Some(level as u8))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_brightness(&self, level: u8) -> Result<()> {
|
||||||
|
self.set_led_mode(&AuraModes::LedBrightness(level))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn next_led_mode(&self) -> Result<()> {
|
||||||
|
self.0.next_led_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn prev_led_mode(&self) -> Result<()> {
|
||||||
|
self.0.prev_led_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_led_mode(&self, mode: &AuraModes) -> Result<()> {
|
||||||
|
self.0.set_led_mode(&serde_json::to_string(mode).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a single colour block.
|
||||||
|
///
|
||||||
|
/// Intentionally blocks for 10ms after sending to allow the block to
|
||||||
|
/// be written to the keyboard EC. This should not be async.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_per_key(&self, key_colour_array: &KeyColourArray) -> Result<()> {
|
||||||
|
let group = key_colour_array.get();
|
||||||
|
let mut vecs = Vec::with_capacity(group.len());
|
||||||
|
for v in group {
|
||||||
|
vecs.push(v.to_vec());
|
||||||
|
}
|
||||||
|
let mode = AuraModes::PerKey(vecs);
|
||||||
|
|
||||||
|
self.set_led_mode(&mode)?;
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME));
|
||||||
|
|
||||||
|
// if self.stop.load(Ordering::Relaxed) {
|
||||||
|
// println!("Keyboard backlight was changed, exiting");
|
||||||
|
// std::process::exit(1)
|
||||||
|
// }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method must always be called before the very first write to initialise
|
||||||
|
/// the keyboard LED EC in the correct mode
|
||||||
|
#[inline]
|
||||||
|
pub fn init_effect(&self) -> Result<()> {
|
||||||
|
let mode = AuraModes::PerKey(vec![vec![]]);
|
||||||
|
self.0.set_led_mode(&serde_json::to_string(&mode).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_led(&self, led: Arc<Mutex<Option<AuraModes>>>) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_led(move |data| {
|
||||||
|
if let Ok(mut lock) = led.lock() {
|
||||||
|
if let Ok(dat) = serde_json::from_str(&data) {
|
||||||
|
*lock = Some(dat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
97
rog-dbus/src/zbus_profile.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Profile' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use rog_types::profile::ProfileEvent;
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Profile"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// ActiveProfileName method
|
||||||
|
fn active_profile_name(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// NextProfile method
|
||||||
|
fn next_profile(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Profile method
|
||||||
|
fn profile(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// Profiles method
|
||||||
|
fn profiles(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// SetProfile method
|
||||||
|
fn set_profile(&self, profile: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyProfile signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProfileProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> ProfileProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(ProfileProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn active_profile_name(&self) -> Result<String> {
|
||||||
|
self.0.active_profile_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn next_fan(&self) -> Result<()> {
|
||||||
|
self.0.next_profile()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_fan_mode(&self, level: u8) -> Result<()> {
|
||||||
|
self.0
|
||||||
|
.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level)).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_command(&self, cmd: &ProfileEvent) -> Result<()> {
|
||||||
|
self.0.set_profile(&serde_json::to_string(cmd).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_profile(
|
||||||
|
&self,
|
||||||
|
charge: Arc<Mutex<Option<String>>>,
|
||||||
|
) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_profile(move |data| {
|
||||||
|
if let Ok(mut lock) = charge.lock() {
|
||||||
|
*lock = Some(data.to_owned());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
109
rog-dbus/src/zbus_rogbios.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/RogBios' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/RogBios"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// DedicatedGraphicMode method
|
||||||
|
fn dedicated_graphic_mode(&self) -> zbus::Result<i16>;
|
||||||
|
|
||||||
|
/// PostBootSound method
|
||||||
|
fn post_boot_sound(&self) -> zbus::Result<i16>;
|
||||||
|
|
||||||
|
/// SetDedicatedGraphicMode method
|
||||||
|
fn set_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetPostBootSound method
|
||||||
|
fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyDedicatedGraphicMode signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// NotifyPostBootSound signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RogBiosProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> RogBiosProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(RogBiosProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_dedicated_gfx(&self) -> Result<i16> {
|
||||||
|
self.0.dedicated_graphic_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_dedicated_gfx(&self, on: bool) -> Result<()> {
|
||||||
|
self.0.set_dedicated_graphic_mode(on)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_post_sound(&self) -> Result<i16> {
|
||||||
|
self.0.post_boot_sound()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_post_sound(&self, on: bool) -> Result<()> {
|
||||||
|
self.0.set_post_boot_sound(on)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_dedicated_graphic_mode(
|
||||||
|
&self,
|
||||||
|
dedicated: Arc<Mutex<Option<bool>>>,
|
||||||
|
) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_dedicated_graphic_mode(move |data| {
|
||||||
|
if let Ok(mut lock) = dedicated.lock() {
|
||||||
|
*lock = Some(data);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn connect_notify_post_boot_sound(
|
||||||
|
&self,
|
||||||
|
sound: Arc<Mutex<Option<bool>>>,
|
||||||
|
) -> zbus::fdo::Result<()> {
|
||||||
|
self.0.connect_notify_post_boot_sound(move |data| {
|
||||||
|
if let Ok(mut lock) = sound.lock() {
|
||||||
|
*lock = Some(data);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
49
rog-dbus/src/zbus_supported.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//! # DBus interface proxy for: `org.asuslinux.Daemon`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
|
||||||
|
//! Source: `Interface '/org/asuslinux/Supported' from service 'org.asuslinux.Daemon' on system bus`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the
|
||||||
|
//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html)
|
||||||
|
//! section of the zbus documentation.
|
||||||
|
//!
|
||||||
|
//! This DBus object implements
|
||||||
|
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||||
|
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||||
|
//!
|
||||||
|
//! * [`zbus::fdo::PeerProxy`]
|
||||||
|
//! * [`zbus::fdo::PropertiesProxy`]
|
||||||
|
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||||
|
//!
|
||||||
|
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||||
|
|
||||||
|
use zbus::{dbus_proxy, Connection, Result};
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.asuslinux.Daemon",
|
||||||
|
default_path = "/org/asuslinux/Supported"
|
||||||
|
)]
|
||||||
|
trait Daemon {
|
||||||
|
/// SupportedFunctions method
|
||||||
|
fn supported_functions(&self) -> zbus::Result<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SupportProxy<'a>(DaemonProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> SupportProxy<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(conn: &Connection) -> Result<Self> {
|
||||||
|
Ok(SupportProxy(DaemonProxy::new(&conn)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_supported_functions(&self) -> Result<String> {
|
||||||
|
self.0.supported_functions()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asus-nb"
|
name = "rog_types"
|
||||||
version = "2.1.0"
|
version = "3.0.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>"]
|
||||||
@@ -11,15 +11,8 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gumdrop = "^0.8"
|
gumdrop = "^0.8"
|
||||||
dbus = { version = "^0.8" }
|
|
||||||
serde = "^1.0"
|
serde = "^1.0"
|
||||||
serde_derive = "^1.0"
|
serde_derive = "^1.0"
|
||||||
serde_json = "^1.0"
|
rog_fan_curve = { version = "^0.1", features = ["serde"] }
|
||||||
yansi-term = "^0.1"
|
zvariant = "^2.5"
|
||||||
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
zvariant_derive = "^2.5"
|
||||||
zbus = "1.1.1"
|
|
||||||
zvariant = "2.2.0"
|
|
||||||
ctrl-gfx = { path = "../ctrl-gfx" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tinybmp = "^0.2.3"
|
|
||||||
@@ -1,32 +1,76 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use zvariant_derive::Type;
|
||||||
|
|
||||||
pub const WIDTH: usize = 34; // Width is definitely 34 items
|
pub const WIDTH: usize = 34; // Width is definitely 34 items
|
||||||
pub const HEIGHT: usize = 56;
|
pub const HEIGHT: usize = 56;
|
||||||
pub type AniMeBufferType = [[u8; WIDTH]; HEIGHT];
|
|
||||||
pub type AniMePacketType = [[u8; 640]; 2];
|
pub type AniMePacketType = [[u8; 640]; 2];
|
||||||
const BLOCK_START: usize = 7;
|
const BLOCK_START: usize = 7;
|
||||||
|
/// *Not* inclusive, the byte before this is the final for each "pane"
|
||||||
const BLOCK_END: usize = 634;
|
const BLOCK_END: usize = 634;
|
||||||
use yansi_term::Colour::RGB;
|
pub const PANE_LEN: usize = BLOCK_END - BLOCK_START;
|
||||||
|
/// The length of usable data
|
||||||
|
pub const FULL_PANE_LEN: usize = PANE_LEN * 2;
|
||||||
|
|
||||||
/// Helper structure for writing images.
|
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];
|
||||||
/// See the examples for ways to write an image to `AniMeMatrix` format.
|
|
||||||
pub struct AniMeMatrix(AniMeBufferType);
|
|
||||||
|
|
||||||
impl Default for AniMeMatrix {
|
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||||
|
pub struct AniMeDataBuffer(Vec<u8>);
|
||||||
|
|
||||||
|
impl Default for AniMeDataBuffer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AniMeMatrix {
|
impl AniMeDataBuffer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
AniMeMatrix([[0u8; WIDTH]; HEIGHT])
|
AniMeDataBuffer(vec![0u8; FULL_PANE_LEN])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> &AniMeBufferType {
|
pub fn get(&self) -> &[u8] {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self) -> &mut AniMeBufferType {
|
pub fn set(&mut self, input: [u8; FULL_PANE_LEN]) {
|
||||||
|
self.0 = input.to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AniMeDataBuffer> for AniMePacketType {
|
||||||
|
#[inline]
|
||||||
|
fn from(anime: AniMeDataBuffer) -> Self {
|
||||||
|
assert!(anime.0.len() == FULL_PANE_LEN);
|
||||||
|
let mut buffers = [[0; 640]; 2];
|
||||||
|
for (idx, chunk) in anime.0.as_slice().chunks(PANE_LEN).enumerate() {
|
||||||
|
buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk);
|
||||||
|
}
|
||||||
|
buffers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper structure for writing images.
|
||||||
|
///
|
||||||
|
/// See the examples for ways to write an image to `AniMeMatrix` format.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||||
|
pub struct AniMeImageBuffer(Vec<Vec<u8>>);
|
||||||
|
|
||||||
|
impl Default for AniMeImageBuffer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AniMeImageBuffer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
AniMeImageBuffer(vec![vec![0u8; WIDTH]; HEIGHT])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> &Vec<Vec<u8>> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self) -> &mut Vec<Vec<u8>> {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +99,8 @@ impl AniMeMatrix {
|
|||||||
} else {
|
} else {
|
||||||
row.iter()
|
row.iter()
|
||||||
};
|
};
|
||||||
for x in tmp {
|
for _ in tmp {
|
||||||
print!(" {}", RGB(*x, *x, *x).paint("XY"));
|
print!(" XY");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
@@ -78,9 +122,9 @@ impl AniMeMatrix {
|
|||||||
if count % 2 == 0 {
|
if count % 2 == 0 {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
for (i, x) in row.iter().enumerate() {
|
for (i, _) in row.iter().enumerate() {
|
||||||
if i >= index {
|
if i >= index {
|
||||||
print!(" {}", RGB(*x, *x, *x).paint("XY"));
|
print!(" XY");
|
||||||
} else {
|
} else {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
@@ -91,11 +135,11 @@ impl AniMeMatrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AniMeMatrix> for AniMePacketType {
|
impl From<AniMeImageBuffer> for AniMePacketType {
|
||||||
/// Do conversion from the nested Vec in AniMeMatrix to the two required
|
/// Do conversion from the nested Vec in AniMeMatrix to the two required
|
||||||
/// packets suitable for sending over USB
|
/// packets suitable for sending over USB
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(anime: AniMeMatrix) -> Self {
|
fn from(anime: AniMeImageBuffer) -> Self {
|
||||||
let mut buffers = [[0; 640]; 2];
|
let mut buffers = [[0; 640]; 2];
|
||||||
|
|
||||||
let mut write_index = BLOCK_START;
|
let mut write_index = BLOCK_START;
|
||||||
@@ -153,15 +197,26 @@ impl From<AniMeMatrix> for AniMePacketType {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
|
use crate::anime_matrix::*;
|
||||||
|
|
||||||
|
use super::AniMeDataBuffer;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_from_data_buffer() {
|
||||||
|
let mut data = AniMeDataBuffer::new();
|
||||||
|
data.set([42u8; FULL_PANE_LEN]);
|
||||||
|
|
||||||
|
let out: AniMePacketType = data.into();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_data_alignment() {
|
fn check_data_alignment() {
|
||||||
let mut matrix = AniMeMatrix::new();
|
let mut matrix = AniMeImageBuffer::new();
|
||||||
{
|
{
|
||||||
let tmp = matrix.get_mut();
|
let tmp = matrix.get_mut();
|
||||||
for row in tmp.iter_mut() {
|
for row in tmp.iter_mut() {
|
||||||
row[row.len() - 1] = 0xff;
|
let idx = row.len() - 1;
|
||||||
|
row[idx] = 0xff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::cli_options;
|
|
||||||
use crate::cli_options::SetAuraBuiltin;
|
use crate::cli_options::SetAuraBuiltin;
|
||||||
|
use crate::error::AuraError;
|
||||||
|
use gumdrop::Options;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub const STATIC: u8 = 0x00;
|
pub const STATIC: u8 = 0x00;
|
||||||
pub const BREATHING: u8 = 0x01;
|
pub const BREATHING: u8 = 0x01;
|
||||||
@@ -15,41 +17,56 @@ pub const PULSE: u8 = 0x0a;
|
|||||||
pub const COMET: u8 = 0x0b;
|
pub const COMET: u8 = 0x0b;
|
||||||
pub const FLASH: u8 = 0x0c;
|
pub const FLASH: u8 = 0x0c;
|
||||||
pub const MULTISTATIC: u8 = 0x0d;
|
pub const MULTISTATIC: u8 = 0x0d;
|
||||||
|
pub const MULTIBREATHE: u8 = 0x0e;
|
||||||
pub const PER_KEY: u8 = 0xff;
|
pub const PER_KEY: u8 = 0xff;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
pub struct Colour(pub u8, pub u8, pub u8);
|
||||||
impl From<cli_options::Colour> for Colour {
|
|
||||||
fn from(c: cli_options::Colour) -> Self {
|
|
||||||
Colour(c.0, c.1, c.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for Colour {
|
impl Default for Colour {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Colour(128, 0, 0)
|
Colour(128, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Colour {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if s.len() < 6 {
|
||||||
|
return Err(AuraError::ParseColour);
|
||||||
|
}
|
||||||
|
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
|
||||||
|
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
|
||||||
|
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
|
||||||
|
Ok(Colour(r, g, b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||||
pub enum Speed {
|
pub enum Speed {
|
||||||
Low = 0xe1,
|
Low = 0xe1,
|
||||||
Med = 0xeb,
|
Med = 0xeb,
|
||||||
High = 0xf5,
|
High = 0xf5,
|
||||||
}
|
}
|
||||||
impl From<cli_options::Speed> for Speed {
|
|
||||||
fn from(s: cli_options::Speed) -> Self {
|
|
||||||
match s {
|
|
||||||
cli_options::Speed::Low => Speed::Low,
|
|
||||||
cli_options::Speed::Med => Speed::Med,
|
|
||||||
cli_options::Speed::High => Speed::High,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for Speed {
|
impl Default for Speed {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Speed::Med
|
Speed::Med
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl FromStr for Speed {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
match s.as_str() {
|
||||||
|
"low" => Ok(Speed::Low),
|
||||||
|
"med" => Ok(Speed::Med),
|
||||||
|
"high" => Ok(Speed::High),
|
||||||
|
_ => Err(AuraError::ParseSpeed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Used for Rainbow mode.
|
/// Used for Rainbow mode.
|
||||||
///
|
///
|
||||||
@@ -61,107 +78,108 @@ pub enum Direction {
|
|||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
}
|
}
|
||||||
impl From<cli_options::Direction> for Direction {
|
|
||||||
fn from(s: cli_options::Direction) -> Self {
|
|
||||||
match s {
|
|
||||||
cli_options::Direction::Right => Direction::Right,
|
|
||||||
cli_options::Direction::Left => Direction::Left,
|
|
||||||
cli_options::Direction::Up => Direction::Up,
|
|
||||||
cli_options::Direction::Down => Direction::Down,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for Direction {
|
impl Default for Direction {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Direction::Right
|
Direction::Right
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl FromStr for Direction {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
pub struct TwoColourSpeed {
|
let s = s.to_lowercase();
|
||||||
pub colour: Colour,
|
match s.as_str() {
|
||||||
pub colour2: Colour,
|
"right" => Ok(Direction::Right),
|
||||||
pub speed: Speed,
|
"up" => Ok(Direction::Up),
|
||||||
}
|
"down" => Ok(Direction::Down),
|
||||||
impl From<cli_options::TwoColourSpeed> for TwoColourSpeed {
|
"left" => Ok(Direction::Left),
|
||||||
fn from(mode: cli_options::TwoColourSpeed) -> Self {
|
_ => Err(AuraError::ParseDirection),
|
||||||
TwoColourSpeed {
|
|
||||||
colour: mode.colour.into(),
|
|
||||||
colour2: mode.colour2.into(),
|
|
||||||
speed: mode.speed.into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
|
||||||
pub struct SingleSpeed {
|
pub struct SingleSpeed {
|
||||||
|
#[serde(skip)]
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(no_long, meta = "WORD", help = "set the speed: low, med, high")]
|
||||||
pub speed: Speed,
|
pub speed: Speed,
|
||||||
}
|
}
|
||||||
impl From<cli_options::SingleSpeed> for SingleSpeed {
|
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
|
||||||
fn from(mode: cli_options::SingleSpeed) -> Self {
|
pub struct SingleSpeedDirection {
|
||||||
SingleSpeed {
|
#[serde(skip)]
|
||||||
speed: mode.speed.into(),
|
#[options(help = "print help message")]
|
||||||
}
|
help: bool,
|
||||||
}
|
#[options(no_long, meta = "", help = "set the direction: up, down, left, right")]
|
||||||
|
pub direction: Direction,
|
||||||
|
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||||
|
pub speed: Speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||||
pub struct SingleColour {
|
pub struct SingleColour {
|
||||||
|
#[serde(skip)]
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
pub colour: Colour,
|
pub colour: Colour,
|
||||||
}
|
}
|
||||||
impl From<cli_options::SingleColour> for SingleColour {
|
|
||||||
fn from(mode: cli_options::SingleColour) -> Self {
|
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||||
SingleColour {
|
pub struct SingleColourSpeed {
|
||||||
colour: mode.colour.into(),
|
#[serde(skip)]
|
||||||
}
|
#[options(help = "print help message")]
|
||||||
}
|
help: bool,
|
||||||
|
#[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour: Colour,
|
||||||
|
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||||
|
pub speed: Speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Options, Default, Deserialize, Serialize)]
|
||||||
pub struct MultiColour {
|
pub struct TwoColourSpeed {
|
||||||
pub colour1: Colour,
|
#[serde(skip)]
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(no_long, meta = "", help = "set the first RGB value e.g, ff00ff")]
|
||||||
|
pub colour: Colour,
|
||||||
|
#[options(no_long, meta = "", help = "set the second RGB value e.g, ff00ff")]
|
||||||
pub colour2: Colour,
|
pub colour2: Colour,
|
||||||
|
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||||
|
pub speed: Speed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||||
|
pub struct MultiColour {
|
||||||
|
#[serde(skip)]
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour1: Colour,
|
||||||
|
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour2: Colour,
|
||||||
|
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
pub colour3: Colour,
|
pub colour3: Colour,
|
||||||
|
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
pub colour4: Colour,
|
pub colour4: Colour,
|
||||||
}
|
}
|
||||||
impl From<cli_options::MultiColour> for MultiColour {
|
|
||||||
fn from(mode: cli_options::MultiColour) -> Self {
|
|
||||||
MultiColour {
|
|
||||||
colour1: mode.colour1.into(),
|
|
||||||
colour2: mode.colour2.into(),
|
|
||||||
colour3: mode.colour3.into(),
|
|
||||||
colour4: mode.colour4.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Options, Deserialize, Serialize)]
|
||||||
pub struct SingleSpeedDirection {
|
pub struct MultiColourSpeed {
|
||||||
pub direction: Direction,
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour1: Colour,
|
||||||
|
#[options(short = "b", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour2: Colour,
|
||||||
|
#[options(short = "c", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour3: Colour,
|
||||||
|
#[options(short = "d", meta = "", help = "set the RGB value e.g, ff00ff")]
|
||||||
|
pub colour4: Colour,
|
||||||
|
#[options(no_long, meta = "", help = "set the speed: low, med, high")]
|
||||||
pub speed: Speed,
|
pub speed: Speed,
|
||||||
}
|
}
|
||||||
impl From<cli_options::SingleSpeedDirection> for SingleSpeedDirection {
|
|
||||||
fn from(mode: cli_options::SingleSpeedDirection) -> Self {
|
|
||||||
SingleSpeedDirection {
|
|
||||||
direction: mode.direction.into(),
|
|
||||||
speed: mode.speed.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
|
||||||
pub struct SingleColourSpeed {
|
|
||||||
pub colour: Colour,
|
|
||||||
pub speed: Speed,
|
|
||||||
}
|
|
||||||
impl From<cli_options::SingleColourSpeed> for SingleColourSpeed {
|
|
||||||
fn from(mode: cli_options::SingleColourSpeed) -> Self {
|
|
||||||
SingleColourSpeed {
|
|
||||||
colour: mode.colour.into(),
|
|
||||||
speed: mode.speed.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub enum AuraModes {
|
pub enum AuraModes {
|
||||||
@@ -178,6 +196,7 @@ pub enum AuraModes {
|
|||||||
Comet(SingleColour),
|
Comet(SingleColour),
|
||||||
Flash(SingleColour),
|
Flash(SingleColour),
|
||||||
MultiStatic(MultiColour),
|
MultiStatic(MultiColour),
|
||||||
|
MultiBreathe(MultiColourSpeed),
|
||||||
LedBrightness(u8),
|
LedBrightness(u8),
|
||||||
// TODO: use a serializable structure for this (KeyColourArray)
|
// TODO: use a serializable structure for this (KeyColourArray)
|
||||||
PerKey(Vec<Vec<u8>>),
|
PerKey(Vec<Vec<u8>>),
|
||||||
@@ -186,19 +205,20 @@ pub enum AuraModes {
|
|||||||
impl From<SetAuraBuiltin> for AuraModes {
|
impl From<SetAuraBuiltin> for AuraModes {
|
||||||
fn from(mode: SetAuraBuiltin) -> Self {
|
fn from(mode: SetAuraBuiltin) -> Self {
|
||||||
match mode {
|
match mode {
|
||||||
SetAuraBuiltin::Static(x) => AuraModes::Static(x.into()),
|
SetAuraBuiltin::Static(x) => AuraModes::Static(x),
|
||||||
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x.into()),
|
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x),
|
||||||
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x.into()),
|
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x),
|
||||||
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x.into()),
|
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x),
|
||||||
SetAuraBuiltin::Star(x) => AuraModes::Star(x.into()),
|
SetAuraBuiltin::Star(x) => AuraModes::Star(x),
|
||||||
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x.into()),
|
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x),
|
||||||
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x.into()),
|
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x),
|
||||||
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x.into()),
|
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x),
|
||||||
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x.into()),
|
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x),
|
||||||
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x.into()),
|
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x),
|
||||||
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x.into()),
|
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x),
|
||||||
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x.into()),
|
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x),
|
||||||
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x.into()),
|
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x),
|
||||||
|
SetAuraBuiltin::MultiBreathe(x) => AuraModes::MultiBreathe(x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,6 +254,7 @@ impl From<&AuraModes> for u8 {
|
|||||||
AuraModes::Comet(_) => COMET,
|
AuraModes::Comet(_) => COMET,
|
||||||
AuraModes::Flash(_) => FLASH,
|
AuraModes::Flash(_) => FLASH,
|
||||||
AuraModes::MultiStatic(_) => MULTISTATIC,
|
AuraModes::MultiStatic(_) => MULTISTATIC,
|
||||||
|
AuraModes::MultiBreathe(_) => MULTIBREATHE,
|
||||||
AuraModes::PerKey(_) => PER_KEY,
|
AuraModes::PerKey(_) => PER_KEY,
|
||||||
_ => panic!("Invalid mode"),
|
_ => panic!("Invalid mode"),
|
||||||
}
|
}
|
||||||
@@ -256,6 +277,7 @@ impl From<&AuraModes> for &str {
|
|||||||
AuraModes::Comet(_) => "Comet",
|
AuraModes::Comet(_) => "Comet",
|
||||||
AuraModes::Flash(_) => "Flash",
|
AuraModes::Flash(_) => "Flash",
|
||||||
AuraModes::MultiStatic(_) => "4-Zone Static Colours",
|
AuraModes::MultiStatic(_) => "4-Zone Static Colours",
|
||||||
|
AuraModes::MultiBreathe(_) => "4-Zone Breathing Colours",
|
||||||
AuraModes::PerKey(_) => "RGB per-key",
|
AuraModes::PerKey(_) => "RGB per-key",
|
||||||
_ => panic!("Invalid mode"),
|
_ => panic!("Invalid mode"),
|
||||||
}
|
}
|
||||||
@@ -280,6 +302,7 @@ impl From<u8> for AuraModes {
|
|||||||
COMET => AuraModes::Comet(SingleColour::default()),
|
COMET => AuraModes::Comet(SingleColour::default()),
|
||||||
FLASH => AuraModes::Flash(SingleColour::default()),
|
FLASH => AuraModes::Flash(SingleColour::default()),
|
||||||
MULTISTATIC => AuraModes::MultiStatic(MultiColour::default()),
|
MULTISTATIC => AuraModes::MultiStatic(MultiColour::default()),
|
||||||
|
MULTIBREATHE => AuraModes::MultiBreathe(MultiColourSpeed::default()),
|
||||||
PER_KEY => AuraModes::PerKey(vec![]),
|
PER_KEY => AuraModes::PerKey(vec![]),
|
||||||
_ => panic!("Invalid mode byte"),
|
_ => panic!("Invalid mode byte"),
|
||||||
}
|
}
|
||||||
147
rog-types/src/cli_options.rs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
use crate::{
|
||||||
|
aura_modes::{
|
||||||
|
MultiColour, MultiColourSpeed, SingleColour, SingleColourSpeed, SingleSpeed,
|
||||||
|
SingleSpeedDirection, TwoColourSpeed,
|
||||||
|
},
|
||||||
|
error::AuraError,
|
||||||
|
};
|
||||||
|
use gumdrop::Options;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
pub struct LedBrightness {
|
||||||
|
level: Option<u8>,
|
||||||
|
}
|
||||||
|
impl LedBrightness {
|
||||||
|
pub fn new(level: Option<u8>) -> Self {
|
||||||
|
LedBrightness { level }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn level(&self) -> Option<u8> {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromStr for LedBrightness {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
match s.as_str() {
|
||||||
|
"off" => Ok(LedBrightness { level: Some(0x00) }),
|
||||||
|
"low" => Ok(LedBrightness { level: Some(0x01) }),
|
||||||
|
"med" => Ok(LedBrightness { level: Some(0x02) }),
|
||||||
|
"high" => Ok(LedBrightness { level: Some(0x03) }),
|
||||||
|
_ => {
|
||||||
|
print!("Invalid argument, must be one of: off, low, med, high");
|
||||||
|
Err(AuraError::ParseBrightness)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToString for LedBrightness {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
let s = match self.level {
|
||||||
|
Some(0x00) => "low",
|
||||||
|
Some(0x01) => "med",
|
||||||
|
Some(0x02) => "high",
|
||||||
|
_ => "unknown",
|
||||||
|
};
|
||||||
|
s.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Byte value for setting the built-in mode.
|
||||||
|
///
|
||||||
|
/// Enum corresponds to the required integer value
|
||||||
|
#[derive(Options, Deserialize, Serialize)]
|
||||||
|
pub enum SetAuraBuiltin {
|
||||||
|
#[options(help = "set a single static colour")]
|
||||||
|
Static(SingleColour),
|
||||||
|
#[options(help = "pulse between one or two colours")]
|
||||||
|
Breathe(TwoColourSpeed),
|
||||||
|
#[options(help = "strobe through all colours")]
|
||||||
|
Strobe(SingleSpeed),
|
||||||
|
#[options(help = "rainbow cycling in one of four directions")]
|
||||||
|
Rainbow(SingleSpeedDirection),
|
||||||
|
#[options(help = "rain pattern mimicking raindrops")]
|
||||||
|
Star(TwoColourSpeed),
|
||||||
|
#[options(help = "rain pattern of three preset colours")]
|
||||||
|
Rain(SingleSpeed),
|
||||||
|
#[options(help = "pressed keys are highlighted to fade")]
|
||||||
|
Highlight(SingleColourSpeed),
|
||||||
|
#[options(help = "pressed keys generate horizontal laser")]
|
||||||
|
Laser(SingleColourSpeed),
|
||||||
|
#[options(help = "pressed keys ripple outwards like a splash")]
|
||||||
|
Ripple(SingleColourSpeed),
|
||||||
|
#[options(help = "set a rapid pulse")]
|
||||||
|
Pulse(SingleColour),
|
||||||
|
#[options(help = "set a vertical line zooming from left")]
|
||||||
|
Comet(SingleColour),
|
||||||
|
#[options(help = "set a wide vertical line zooming from left")]
|
||||||
|
Flash(SingleColour),
|
||||||
|
#[options(help = "4-zone multi-colour")]
|
||||||
|
MultiStatic(MultiColour),
|
||||||
|
#[options(help = "4-zone multi-colour breathing")]
|
||||||
|
MultiBreathe(MultiColourSpeed),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SetAuraBuiltin {
|
||||||
|
fn default() -> Self {
|
||||||
|
SetAuraBuiltin::Static(SingleColour::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum AniMeStatusValue {
|
||||||
|
On,
|
||||||
|
Off,
|
||||||
|
}
|
||||||
|
impl FromStr for AniMeStatusValue {
|
||||||
|
type Err = AuraError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
match s.as_str() {
|
||||||
|
"on" => Ok(AniMeStatusValue::On),
|
||||||
|
"off" => Ok(AniMeStatusValue::Off),
|
||||||
|
_ => {
|
||||||
|
print!("Invalid argument, must be one of: on, off");
|
||||||
|
Err(AuraError::ParseAnime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<AniMeStatusValue> for bool {
|
||||||
|
fn from(value: AniMeStatusValue) -> Self {
|
||||||
|
match value {
|
||||||
|
AniMeStatusValue::On => true,
|
||||||
|
AniMeStatusValue::Off => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
pub struct AniMeLeds {
|
||||||
|
#[options(help = "print help message")]
|
||||||
|
help: bool,
|
||||||
|
#[options(
|
||||||
|
no_long,
|
||||||
|
required,
|
||||||
|
short = "b",
|
||||||
|
meta = "",
|
||||||
|
help = "set all leds brightness value"
|
||||||
|
)]
|
||||||
|
led_brightness: u8,
|
||||||
|
}
|
||||||
|
impl AniMeLeds {
|
||||||
|
pub fn led_brightness(&self) -> u8 {
|
||||||
|
self.led_brightness
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Options)]
|
||||||
|
pub enum AniMeActions {
|
||||||
|
#[options(help = "change all leds brightness")]
|
||||||
|
Leds(AniMeLeds),
|
||||||
|
}
|
||||||
@@ -6,13 +6,14 @@ pub enum GfxVendors {
|
|||||||
Hybrid,
|
Hybrid,
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::error::GfxError;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
impl FromStr for GfxVendors {
|
use crate::error::GraphicsError;
|
||||||
type Err = GfxError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, GfxError> {
|
impl FromStr for GfxVendors {
|
||||||
|
type Err = GraphicsError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, GraphicsError> {
|
||||||
match s.to_lowercase().as_str() {
|
match s.to_lowercase().as_str() {
|
||||||
"nvidia" => Ok(GfxVendors::Nvidia),
|
"nvidia" => Ok(GfxVendors::Nvidia),
|
||||||
"hybrid" => Ok(GfxVendors::Hybrid),
|
"hybrid" => Ok(GfxVendors::Hybrid),
|
||||||
@@ -22,7 +23,7 @@ impl FromStr for GfxVendors {
|
|||||||
"hybrid\n" => Ok(GfxVendors::Hybrid),
|
"hybrid\n" => Ok(GfxVendors::Hybrid),
|
||||||
"compute\n" => Ok(GfxVendors::Compute),
|
"compute\n" => Ok(GfxVendors::Compute),
|
||||||
"integrated\n" => Ok(GfxVendors::Integrated),
|
"integrated\n" => Ok(GfxVendors::Integrated),
|
||||||
_ => Err(GfxError::ParseVendor),
|
_ => Err(GraphicsError::ParseVendor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,14 +47,14 @@ pub enum GfxCtrlAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for GfxCtrlAction {
|
impl FromStr for GfxCtrlAction {
|
||||||
type Err = GfxError;
|
type Err = GraphicsError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, GfxError> {
|
fn from_str(s: &str) -> Result<Self, GraphicsError> {
|
||||||
match s.to_lowercase().as_str() {
|
match s.to_lowercase().as_str() {
|
||||||
"reboot" => Ok(GfxCtrlAction::Reboot),
|
"reboot" => Ok(GfxCtrlAction::Reboot),
|
||||||
"restartx" => Ok(GfxCtrlAction::RestartX),
|
"restartx" => Ok(GfxCtrlAction::RestartX),
|
||||||
"none" => Ok(GfxCtrlAction::None),
|
"none" => Ok(GfxCtrlAction::None),
|
||||||
_ => Err(GfxError::ParseVendor),
|
_ => Err(GraphicsError::ParseVendor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,23 +14,15 @@ pub mod cli_options;
|
|||||||
/// Enables you to create fancy RGB effects
|
/// Enables you to create fancy RGB effects
|
||||||
pub mod fancy;
|
pub mod fancy;
|
||||||
|
|
||||||
/// The main dbus group for system controls, e.g, fan control, keyboard LED's
|
|
||||||
pub mod core_dbus;
|
|
||||||
|
|
||||||
/// Specific dbus for writing to the AniMe Matrix display (if supported)
|
|
||||||
pub mod anime_dbus;
|
|
||||||
|
|
||||||
/// Helper functions for the AniMe display
|
/// Helper functions for the AniMe display
|
||||||
pub mod anime_matrix;
|
pub mod anime_matrix;
|
||||||
|
|
||||||
pub mod dbus_gfx;
|
pub mod gfx_vendors;
|
||||||
pub mod dbus_ledmode;
|
|
||||||
pub mod dbus_profile;
|
|
||||||
pub mod dbus_charge;
|
|
||||||
pub mod dbus_anime;
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||||
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||||
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
@@ -151,6 +143,7 @@ impl From<&AuraModes> for [u8; LED_MSG_LEN] {
|
|||||||
let mut msg = [0u8; LED_MSG_LEN];
|
let mut msg = [0u8; LED_MSG_LEN];
|
||||||
msg[0] = 0x5d;
|
msg[0] = 0x5d;
|
||||||
msg[1] = 0xb3;
|
msg[1] = 0xb3;
|
||||||
|
msg[7] = 0xeb;
|
||||||
match mode {
|
match mode {
|
||||||
AuraModes::LedBrightness(n) => return aura_brightness_bytes(*n),
|
AuraModes::LedBrightness(n) => return aura_brightness_bytes(*n),
|
||||||
AuraModes::Static(_) => msg[3] = 0x00,
|
AuraModes::Static(_) => msg[3] = 0x00,
|
||||||
@@ -232,14 +225,15 @@ impl From<&AuraModes> for [[u8; LED_MSG_LEN]; 4] {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from(mode: &AuraModes) -> Self {
|
fn from(mode: &AuraModes) -> Self {
|
||||||
let mut msg = [[0u8; LED_MSG_LEN]; 4];
|
let mut msg = [[0u8; LED_MSG_LEN]; 4];
|
||||||
for (i, row) in msg.iter_mut().enumerate() {
|
|
||||||
row[0] = 0x5d;
|
|
||||||
row[1] = 0xb3;
|
|
||||||
row[2] = i as u8 + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
AuraModes::MultiStatic(settings) => {
|
AuraModes::MultiStatic(settings) => {
|
||||||
|
for (i, row) in msg.iter_mut().enumerate() {
|
||||||
|
row[0] = 0x5d;
|
||||||
|
row[1] = 0xb3;
|
||||||
|
row[2] = i as u8 + 1; // zone
|
||||||
|
row[3] = 0x00; // mode
|
||||||
|
row[7] = 0xeb; // static needs speed?
|
||||||
|
}
|
||||||
msg[0][4] = settings.colour1.0;
|
msg[0][4] = settings.colour1.0;
|
||||||
msg[0][5] = settings.colour1.1;
|
msg[0][5] = settings.colour1.1;
|
||||||
msg[0][6] = settings.colour1.2;
|
msg[0][6] = settings.colour1.2;
|
||||||
@@ -253,6 +247,35 @@ impl From<&AuraModes> for [[u8; LED_MSG_LEN]; 4] {
|
|||||||
msg[3][5] = settings.colour4.1;
|
msg[3][5] = settings.colour4.1;
|
||||||
msg[3][6] = settings.colour4.2;
|
msg[3][6] = settings.colour4.2;
|
||||||
}
|
}
|
||||||
|
AuraModes::MultiBreathe(settings) => {
|
||||||
|
for (i, row) in msg.iter_mut().enumerate() {
|
||||||
|
row[0] = 0x5d;
|
||||||
|
row[1] = 0xb3;
|
||||||
|
row[2] = i as u8 + 1; // zone
|
||||||
|
row[3] = 0x01; // mode
|
||||||
|
}
|
||||||
|
let speed = match settings.speed {
|
||||||
|
aura_modes::Speed::Low => 0xfd,
|
||||||
|
aura_modes::Speed::Med => 0xfe,
|
||||||
|
aura_modes::Speed::High => 0xff,
|
||||||
|
};
|
||||||
|
msg[0][4] = settings.colour1.0;
|
||||||
|
msg[0][5] = settings.colour1.1;
|
||||||
|
msg[0][6] = settings.colour1.2;
|
||||||
|
msg[0][7] = speed; // fd, fe, ff
|
||||||
|
msg[1][4] = settings.colour2.0;
|
||||||
|
msg[1][5] = settings.colour2.1;
|
||||||
|
msg[1][6] = settings.colour2.2;
|
||||||
|
msg[1][7] = speed;
|
||||||
|
msg[2][4] = settings.colour3.0;
|
||||||
|
msg[2][5] = settings.colour3.1;
|
||||||
|
msg[2][6] = settings.colour3.2;
|
||||||
|
msg[2][7] = speed;
|
||||||
|
msg[3][4] = settings.colour4.0;
|
||||||
|
msg[3][5] = settings.colour4.1;
|
||||||
|
msg[3][6] = settings.colour4.2;
|
||||||
|
msg[3][7] = speed;
|
||||||
|
}
|
||||||
_ => panic!("Mode not convertable to 2D array: {}", <&str>::from(mode)),
|
_ => panic!("Mode not convertable to 2D array: {}", <&str>::from(mode)),
|
||||||
}
|
}
|
||||||
msg
|
msg
|
||||||
@@ -75,7 +75,7 @@ fn parse_fan_curve(data: &str) -> Result<Curve, String> {
|
|||||||
#[derive(Debug, Clone, Options, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Options, Serialize, Deserialize)]
|
||||||
pub struct ProfileCommand {
|
pub struct ProfileCommand {
|
||||||
#[options(help = "print help message")]
|
#[options(help = "print help message")]
|
||||||
help: bool,
|
pub help: bool,
|
||||||
#[options(help = "toggle to next profile in list")]
|
#[options(help = "toggle to next profile in list")]
|
||||||
pub next: bool,
|
pub next: bool,
|
||||||
#[options(help = "create the profile if it doesn't exist")]
|
#[options(help = "create the profile if it doesn't exist")]
|
||||||