Compare commits

...

23 Commits

Author SHA1 Message Date
Luke D. Jones 2cd1ee02ee Prep release 4.5.0 2022-11-07 21:35:42 +13:00
Luke D. Jones 5f4e950819 Update deps. Fixes to runtime 2022-11-07 09:47:15 +13:00
Luke D. Jones efc752cce6 ROGCC: Use tokio instead of smol 2022-11-07 09:00:46 +13:00
Luke D. Jones 37553a5fdd Remove some dbg! statements 2022-11-06 22:28:00 +13:00
Luke D. Jones cd5a85a843 Clarify gpu mux notif 2022-11-06 22:17:46 +13:00
Luke D. Jones 7385844a9b Fix rogcc not closing when run-in-background 2022-11-06 21:58:33 +13:00
Luke D. Jones 0b71104833 Fix rog-control-center notifs 2022-11-06 15:21:43 +13:00
Luke D. Jones 688e3a7358 Send signals using the correct context for each 2022-11-06 12:48:19 +13:00
Luke D. Jones 58ff566d65 Fix inclusion of supergfxctl lib 2022-11-04 21:31:45 +13:00
Luke D. Jones 1332ac803c Add notification of dGPU state change 2022-11-04 21:29:47 +13:00
Luke D. Jones ba1d3f045d Add missing file 2022-10-11 22:25:49 +13:00
Luke D. Jones e0ed52092a Refined AC monitoring 2022-10-11 22:13:54 +13:00
Luke D. Jones 921637f979 Make some ledmodes more generic matched across models 2022-10-10 13:19:15 +13:00
Luke D. Jones f6498337fe RCC: disable vsync due to NoAvailablePixelFormat error: 2022-10-04 11:37:23 +13:00
Luke D. Jones 3a640a3269 Bump rc version 2022-10-01 14:57:49 +13:00
Luke D. Jones e938f1f9ec Minor fixes to attr writes 2022-10-01 14:57:25 +13:00
Luke D. Jones 600d0ae3d9 Clippy run 2022-09-30 15:10:56 +13:00
Luke D. Jones 8569edf684 Try official latest docker image 2022-09-29 18:17:28 +13:00
Luke D. Jones 52af4ad2b2 Use 'latest' rustdocker image 2022-09-29 18:06:54 +13:00
Luke D. Jones cde1b4f252 Shift all deps to workspace versioning 2022-09-29 17:08:28 +13:00
Luke Jones 2a4754cfc4 Merge branch 'ledmodes_for_rogflowx16' into 'main'
Added LED modes for ROG Flow X16

See merge request asus-linux/asusctl!134
2022-09-27 20:05:12 +00:00
Rino 51c97fa350 Added LED modes for ROG Flow X16 2022-09-27 12:44:49 +00:00
Luke D. Jones c968dce009 Cleanup notifications some 2022-09-24 18:44:10 +12:00
65 changed files with 1431 additions and 1255 deletions
+4 -2
View File
@@ -1,4 +1,4 @@
image: rustdocker/rust:stable
image: rust:latest
before_script:
- apt-get update -qq && apt-get install -y -qq libdbus-1-dev libclang-dev libudev-dev libfontconfig1-dev
@@ -9,7 +9,9 @@ stages:
test:
script:
- cargo check #+nightly check --features "clippy"
- rustup component add clippy
- cargo check
- cargo clippy
- cargo test
build:
+8 -1
View File
@@ -22,15 +22,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `NotifyEgpuEnable`
- `MainsOnline` (This is AC, check if plugged in or not)
- `NotifyMainsOnline`
- `nvidia-powerd.service` will now enable or disable depending on the AC power state
and on resume/boot (hybrid boot). It has been proven that this nvidia daemon can be
problematic when on battery, not allowing the dgpu to suspend within decent time and
sometimes blocking it completely.
- Notification to rog-control-center of dGPU state change
### Changed
- Use loops to ensure that mutex is gained for LED changes.
- asusctl now uses tokio for async runtime. This helps simplify some code.
- Properly fix notifs used in rog-control-center
### Breaking
- DBUS: all charge control methods renamed to:
- `ChargeControlEndThreshold`
- `SetChargeControlEndThreshold`
- `NotifyChargeControlEndThreshold`
- `PanelOd` (form PanelOverdrive)
- DBUS: all panel overdrive methods renamed to:
- `PanelOd` (from PanelOverdrive)
- `SetPanelOd`
- `NotifyPanelOd`
- Path `/org/asuslinux/Charge` changed to `/org/asuslinux/Power`
Generated
+437 -366
View File
File diff suppressed because it is too large Load Diff
+40 -2
View File
@@ -1,5 +1,43 @@
[workspace]
members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"]
members = ["asusctl", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"]
[workspace.package]
version = "4.5.0"
[workspace.dependencies]
async-trait = "^0.1"
tokio = { version = "^1.21.2", features = ["macros", "rt-multi-thread", "time"]}
concat-idents = "^1.1"
dirs = "^4.0"
smol = "^1.2"
zbus = "^3.4"
zbus_macros = "^3.4"
zvariant = "^3.7"
zvariant_derive = "^3.7"
logind-zbus = { version = "^3.0" } #, default-features = false, features = ["non_blocking"] }
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
toml = "^0.5.9"
log = "^0.4"
env_logger = "^0.9"
glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8"
udev = "^0.6"
rusb = "^0.9"
sysfs-class = "^0.1.2"
inotify = "^0.10.0"
png_pong = "^0.8"
pix = "^0.13"
tinybmp = "^0.3"
gif = "^0.11"
notify-rust = { git = "https://github.com/flukejones/notify-rust.git", default-features = false, features = ["z"] }
[profile.release]
# thin = 57s, asusd = 9.0M
@@ -10,7 +48,7 @@ opt-level = 3
panic = "abort"
[profile.dev]
debug = false
debug = true
opt-level = 1
[profile.bench]
+4 -5
View File
@@ -15,7 +15,6 @@ BIN_ROG := rog-control-center
BIN_C := asusctl
BIN_D := asusd
BIN_U := asusd-user
BIN_N := asus-notify
LEDCFG := asusd-ledmodes.toml
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
@@ -48,14 +47,12 @@ install:
$(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
$(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)"
$(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
@@ -78,12 +75,10 @@ uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
rm -f "$(DESTDIR)/etc/asusd/$(LEDCFG)"
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
rm -r "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
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"
@@ -114,5 +109,9 @@ ifeq ($(VENDORED),1)
tar pxf vendor_asusctl_$(VERSION).tar.xz
endif
cargo build $(ARGS)
strip -s ./target/release/$(BIN_C)
strip -s ./target/release/$(BIN_D)
strip -s ./target/release/$(BIN_U)
strip -s ./target/release/$(BIN_ROG)
.PHONY: all clean distclean install uninstall update build
-22
View File
@@ -1,22 +0,0 @@
[package]
name = "asus-notify"
version = "3.1.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]
zbus = "^2.2"
# serialisation
serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" }
rog_aura = { path = "../rog-aura" }
rog_platform = { path = "../rog-platform" }
rog_profiles = { path = "../rog-profiles" }
smol = "^1.2"
[dependencies.notify-rust]
version = "^4.3"
default-features = false
features = ["z"]
-166
View File
@@ -1,166 +0,0 @@
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_aura::AuraEffect;
use rog_dbus::{
zbus_led::LedProxy, zbus_platform::RogBiosProxy, zbus_power::PowerProxy,
zbus_profile::ProfileProxy,
};
use rog_profiles::Profile;
use smol::{future, Executor};
use std::{
error::Error,
sync::{Arc, Mutex},
};
use zbus::export::futures_util::StreamExt;
const NOTIF_HEADER: &str = "ROG Control";
macro_rules! notify {
($notifier:ident, $last_notif:ident, $data:expr) => {
if let Some(notif) = $last_notif.take() {
notif.close();
}
if let Ok(x) = $notifier($data) {
$last_notif.replace(x);
}
};
}
macro_rules! base_notification {
($body:expr) => {
Notification::new()
.summary(NOTIF_HEADER)
.body($body)
.timeout(2000)
.show()
};
}
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
println!(" rog-dbus version {}", rog_dbus::VERSION);
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
let executor = Executor::new();
// BIOS notif
let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = RogBiosProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_post_boot_sound().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_post_sound_notif, lock, &out.on());
}
}
future::ready(())
})
.await;
};
})
.detach();
// Charge notif
let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = PowerProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_charge_control_end_threshold().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_charge_notif, lock, &out.limit);
}
}
future::ready(())
})
.await;
};
})
.detach();
// Profile notif
let x = last_notification.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = ProfileProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_profile().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = x.try_lock() {
notify!(do_thermal_notif, lock, &out.profile);
}
}
future::ready(())
})
.await;
};
})
.detach();
// LED notif
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_led().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if let Ok(ref mut lock) = last_notification.try_lock() {
notify!(do_led_notif, lock, &out.data);
}
}
future::ready(())
})
.await;
};
})
.detach();
loop {
smol::block_on(executor.tick());
}
}
fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {
let icon = match profile {
Profile::Balanced => "asus_notif_yellow",
Profile::Performance => "asus_notif_red",
Profile::Quiet => "asus_notif_green",
};
let profile: &str = (*profile).into();
let x = Notification::new()
.summary("ASUS ROG")
.body(&format!(
"Thermal profile changed to {}",
profile.to_uppercase(),
))
.hint(Hint::Resident(true))
.timeout(2000)
.hint(Hint::Category("device".into()))
//.hint(Hint::Transient(true))
.icon(icon)
.show()?;
Ok(x)
}
fn do_led_notif(ledmode: &AuraEffect) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!(
"Keyboard LED mode changed to {}",
ledmode.mode_name()
))
}
fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!("Battery charge limit changed to {}", limit))
}
fn do_post_sound_notif(on: &bool) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!("BIOS Post sound {}", on))
}
+8 -11
View File
@@ -1,26 +1,23 @@
[package]
name = "asusctl"
version = "4.3.3"
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
edition = "2021"
version.workspace = true
[dependencies]
zbus = "^2.2"
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" }
rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" }
daemon = { path = "../daemon" }
gumdrop = "^0.8"
toml = "^0.5.8"
sysfs-class = "^0.1.2"
gumdrop.workspace = true
toml.workspace = true
sysfs-class.workspace = true
[dev-dependencies]
tinybmp = "^0.3.3"
glam = "^0.21.2"
gif.workspace = true
tinybmp.workspace = true
glam.workspace = true
rog_dbus = { path = "../rog-dbus" }
gif = "^0.11.2"
+9 -14
View File
@@ -29,23 +29,18 @@ mod profiles_cli;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = args().skip(1).collect();
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()
};
}
let parsed = match CliStart::parse_args_default(&args) {
Ok(p) => p,
Err(err) if err.to_string() == missing_argument_k.to_string() => CliStart {
kbd_bright: Some(LedBrightness::new(None)),
..Default::default()
},
Err(err) => {
eprintln!("source {}", err);
std::process::exit(2);
}
}
};
let (dbus, _) = RogDbusClientBlocking::new()
.map_err(|e| {
@@ -376,7 +371,7 @@ fn handle_anime(
}
fn verify_brightness(brightness: f32) {
if brightness < 0.0 || brightness > 1.0 {
if !(0.0..=1.0).contains(&brightness) {
println!(
"Image and global brightness must be between 0.0 and 1.0 (inclusive), was {}",
brightness
@@ -474,7 +469,7 @@ fn handle_led_power1(
}
println!("These options are for keyboards of product ID 0x1866 or TUF only");
return Ok(());
Ok(())
}
fn handle_led_power_1_do_1866(
+11 -12
View File
@@ -1,8 +1,8 @@
[package]
name = "daemon-user"
version = "1.3.1"
version.workspace = true
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
edition = "2021"
description = "Usermode daemon for user settings, anime, per-key lighting"
[lib]
@@ -14,20 +14,19 @@ name = "asusd-user"
path = "src/daemon.rs"
[dependencies]
dirs.workspace = true
smol.workspace = true
# serialisation
serde = "^1.0"
serde_json = "^1.0"
serde_derive = "^1.0"
serde.workspace = true
serde_json.workspace = true
serde_derive.workspace = true
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" }
rog_platform = { path = "../rog-platform" }
dirs = "^4.0"
zbus = "^2.2"
zvariant = "^3.0"
zvariant_derive = "^3.0"
smol = "^1.2"
zbus.workspace = true
zvariant.workspace = true
zvariant_derive.workspace = true
+1 -1
View File
@@ -86,7 +86,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_err(|e| {
println!("{BOARD_NAME}, {e}");
})
.unwrap_or(KeyLayout::ga401_layout());
.unwrap_or_else(|_| KeyLayout::ga401_layout());
executor
.spawn(async move {
+2 -2
View File
@@ -30,7 +30,7 @@ pub trait ConfigLoadSave<T: DeserializeOwned + serde::Serialize> {
if !path.exists() {
create_dir(path.clone())?;
}
let name = self.name().clone();
let name = self.name();
path.push(name + ".cfg");
let mut file = OpenOptions::new()
@@ -230,7 +230,7 @@ impl Default for UserAuraConfig {
80,
40,
));
seq.push(key.clone());
seq.push(key);
Self {
name: "default".to_string(),
+15 -15
View File
@@ -1,13 +1,13 @@
[package]
name = "daemon"
version = "4.5.0-rc3"
version.workspace = true
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 = "A daemon app for ASUS GX502 and similar laptops to control missing features"
edition = "2018"
edition = "2021"
[lib]
name = "daemon"
@@ -24,24 +24,24 @@ rog_platform = { path = "../rog-platform" }
rog_profiles = { path = "../rog-profiles" }
rog_dbus = { path = "../rog-dbus" }
async-trait = "^0.1"
tokio = { version = "^1.21.1", features = ["macros", "rt-multi-thread", "time"]}
async-trait.workspace = true
tokio.workspace = true
# cli and logging
log = "^0.4"
env_logger = "^0.9"
log.workspace = true
env_logger.workspace = true
zbus = "^2.2"
zvariant = "^3.2"
logind-zbus = { version = "^3.0" } #, default-features = false, features = ["non_blocking"] }
zbus.workspace = true
zvariant.workspace = true
logind-zbus.workspace = true
# serialisation
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
toml = "^0.5.8"
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
toml.workspace = true
# Device control
sysfs-class = "^0.1.2" # used for backlight control and baord ID
sysfs-class.workspace = true # used for backlight control and baord ID
concat-idents = "1.1.3"
concat-idents.workspace = true
+1 -1
View File
@@ -130,7 +130,7 @@ impl CtrlAnime {
.ok();
false // Don't exit yet
})
.map(|r| Ok(r))
.map(Ok)
.unwrap_or_else(|| {
warn!("rog_anime::run_animation:callback failed");
Err(AnimeError::NoFrames)
+4 -4
View File
@@ -123,14 +123,14 @@ impl CtrlAnimeZbus {
#[dbus_interface(property)]
async fn awake_enabled(&self) -> bool {
let lock = self.0.lock().await;
return lock.config.awake_enabled;
lock.config.awake_enabled
}
/// Get the status of if factory system-status animations are enabled
#[dbus_interface(property)]
async fn boot_enabled(&self) -> bool {
let lock = self.0.lock().await;
return lock.config.boot_anim_enabled;
lock.config.boot_anim_enabled
}
/// Notify listeners of the status of AniMe LED power and factory system-status animations
@@ -152,10 +152,10 @@ impl crate::CtrlTask for CtrlAnimeZbus {
|start: bool, lock: MutexGuard<CtrlAnime>, inner: Arc<Mutex<CtrlAnime>>| {
if start {
info!("CtrlAnimeTask running sleep animation");
CtrlAnime::run_thread(inner.clone(), lock.cache.shutdown.clone(), true);
CtrlAnime::run_thread(inner, lock.cache.shutdown.clone(), true);
} else {
info!("CtrlAnimeTask running wake animation");
CtrlAnime::run_thread(inner.clone(), lock.cache.wake.clone(), true);
CtrlAnime::run_thread(inner, lock.cache.wake.clone(), true);
}
};
+45 -29
View File
@@ -27,11 +27,11 @@ impl AuraPowerConfig {
match control {
AuraPowerConfig::AuraDevTuf(_) => [0, 0, 0],
AuraPowerConfig::AuraDev1866(c) => {
let c: Vec<AuraDev1866> = c.iter().map(|v| *v).collect();
let c: Vec<AuraDev1866> = c.iter().copied().collect();
AuraDev1866::to_bytes(&c)
}
AuraPowerConfig::AuraDev19b6(c) => {
let c: Vec<AuraDev19b6> = c.iter().map(|v| *v).collect();
let c: Vec<AuraDev19b6> = c.iter().copied().collect();
AuraDev19b6::to_bytes(&c)
}
}
@@ -95,19 +95,19 @@ impl From<&AuraPowerConfig> for AuraPowerDev {
fn from(config: &AuraPowerConfig) -> Self {
match config {
AuraPowerConfig::AuraDevTuf(d) => AuraPowerDev {
tuf: d.iter().map(|o| *o).collect(),
tuf: d.iter().copied().collect(),
x1866: vec![],
x19b6: vec![],
},
AuraPowerConfig::AuraDev1866(d) => AuraPowerDev {
tuf: vec![],
x1866: d.iter().map(|o| *o).collect(),
x1866: d.iter().copied().collect(),
x19b6: vec![],
},
AuraPowerConfig::AuraDev19b6(d) => AuraPowerDev {
tuf: vec![],
x1866: vec![],
x19b6: d.iter().map(|o| *o).collect(),
x19b6: d.iter().copied().collect(),
},
}
}
@@ -128,7 +128,7 @@ impl Default for AuraConfig {
fn default() -> Self {
let mut prod_id = AuraDevice::Unknown;
for prod in ASUS_KEYBOARD_DEVICES.iter() {
if let Ok(_) = HidRaw::new(prod) {
if HidRaw::new(prod).is_ok() {
prod_id = AuraDevice::from(*prod);
break;
}
@@ -335,26 +335,34 @@ mod tests {
fn set_multizone_4key_config() {
let mut config = AuraConfig::default();
let mut effect = AuraEffect::default();
effect.colour1 = Colour(0xff, 0x00, 0xff);
effect.zone = AuraZone::Key1;
let effect = AuraEffect {
colour1: Colour(0xff, 0x00, 0xff),
zone: AuraZone::Key1,
..Default::default()
};
config.set_builtin(effect);
assert!(config.multizone.is_some());
let mut effect = AuraEffect::default();
effect.colour1 = Colour(0x00, 0xff, 0xff);
effect.zone = AuraZone::Key2;
let effect = AuraEffect {
colour1: Colour(0x00, 0xff, 0xff),
zone: AuraZone::Key2,
..Default::default()
};
config.set_builtin(effect);
let mut effect = AuraEffect::default();
effect.colour1 = Colour(0xff, 0xff, 0x00);
effect.zone = AuraZone::Key3;
let effect = AuraEffect {
colour1: Colour(0xff, 0xff, 0x00),
zone: AuraZone::Key3,
..Default::default()
};
config.set_builtin(effect);
let mut effect = AuraEffect::default();
effect.colour1 = Colour(0x00, 0xff, 0x00);
effect.zone = AuraZone::Key4;
let effect = AuraEffect {
colour1: Colour(0x00, 0xff, 0x00),
zone: AuraZone::Key4,
..Default::default()
};
let effect_clone = effect.clone();
config.set_builtin(effect);
// This should replace existing
@@ -373,25 +381,33 @@ mod tests {
fn set_multizone_multimode_config() {
let mut config = AuraConfig::default();
let mut effect = AuraEffect::default();
effect.zone = AuraZone::Key1;
let effect = AuraEffect {
zone: AuraZone::Key1,
..Default::default()
};
config.set_builtin(effect);
assert!(config.multizone.is_some());
let mut effect = AuraEffect::default();
effect.zone = AuraZone::Key2;
effect.mode = AuraModeNum::Breathe;
let effect = AuraEffect {
zone: AuraZone::Key2,
mode: AuraModeNum::Breathe,
..Default::default()
};
config.set_builtin(effect);
let mut effect = AuraEffect::default();
effect.zone = AuraZone::Key3;
effect.mode = AuraModeNum::Comet;
let effect = AuraEffect {
zone: AuraZone::Key3,
mode: AuraModeNum::Comet,
..Default::default()
};
config.set_builtin(effect);
let mut effect = AuraEffect::default();
effect.zone = AuraZone::Key4;
effect.mode = AuraModeNum::Pulse;
let effect = AuraEffect {
zone: AuraZone::Key4,
mode: AuraModeNum::Pulse,
..Default::default()
};
config.set_builtin(effect);
let res = config.multizone.unwrap();
+13 -15
View File
@@ -27,7 +27,7 @@ impl GetSupported for CtrlKbdLed {
let mut prod_id = AuraDevice::Unknown;
for prod in ASUS_KEYBOARD_DEVICES.iter() {
if let Ok(_) = HidRaw::new(prod) {
if HidRaw::new(prod).is_ok() {
prod_id = AuraDevice::from(*prod);
break;
}
@@ -50,7 +50,7 @@ impl GetSupported for CtrlKbdLed {
}
}
#[derive(Debug, PartialEq, PartialOrd)]
#[derive(Debug, PartialEq, Eq, PartialOrd)]
pub enum LEDNode {
KbdLed(KeyboardLed),
Rog(HidRaw),
@@ -121,13 +121,13 @@ impl CtrlKbdLed {
pub(super) fn get_brightness(&self) -> Result<u8, RogError> {
self.kd_brightness
.get_brightness()
.map_err(|e| RogError::Platform(e))
.map_err(RogError::Platform)
}
pub(super) fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
self.kd_brightness
.set_brightness(brightness as u8)
.map_err(|e| RogError::Platform(e))
.map_err(RogError::Platform)
}
pub fn next_brightness(&mut self) -> Result<(), RogError> {
@@ -176,10 +176,9 @@ impl CtrlKbdLed {
/// On success the aura config file is read to refresh cached values, then the effect is
/// stored and config written to disk.
pub(crate) fn set_effect(&mut self, effect: AuraEffect) -> Result<(), RogError> {
if !self.supported_modes.standard.contains(&effect.mode) {
return Err(RogError::AuraEffectNotSupported);
} else if effect.zone != AuraZone::None
&& !self.supported_modes.multizone.contains(&effect.zone)
if !self.supported_modes.standard.contains(&effect.mode)
|| effect.zone != AuraZone::None
&& !self.supported_modes.multizone.contains(&effect.zone)
{
return Err(RogError::AuraEffectNotSupported);
}
@@ -387,9 +386,11 @@ mod tests {
config,
};
let mut effect = AuraEffect::default();
effect.colour1 = Colour(0xff, 0x00, 0xff);
effect.zone = AuraZone::None;
let mut effect = AuraEffect {
colour1: Colour(0xff, 0x00, 0xff),
zone: AuraZone::None,
..Default::default()
};
// This error comes from write_bytes because we don't have a keyboard node stored
assert_eq!(
@@ -421,10 +422,7 @@ mod tests {
controller.supported_modes.multizone.push(AuraZone::Key2);
assert_eq!(
controller
.set_effect(effect.clone())
.unwrap_err()
.to_string(),
controller.set_effect(effect).unwrap_err().to_string(),
"No supported Aura keyboard"
);
}
+4 -4
View File
@@ -26,7 +26,7 @@ impl CtrlKbdLedZbus {
lock.config.read();
lock.config.brightness = (bright as u32).into();
lock.config.write();
return Ok(());
Ok(())
}
}
@@ -192,19 +192,19 @@ impl CtrlKbdLedZbus {
// #[dbus_interface(property)]
async fn leds_enabled(&self) -> AuraPowerDev {
let ctrl = self.0.lock().await;
return AuraPowerDev::from(&ctrl.config.enabled);
AuraPowerDev::from(&ctrl.config.enabled)
}
/// Return the current mode data
async fn led_mode(&self) -> AuraModeNum {
let ctrl = self.0.lock().await;
return ctrl.config.current_mode;
ctrl.config.current_mode
}
/// Return a list of available modes
async fn led_modes(&self) -> BTreeMap<AuraModeNum, AuraEffect> {
let ctrl = self.0.lock().await;
return ctrl.config.builtins.clone();
ctrl.config.builtins.clone()
}
async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> {
+24 -39
View File
@@ -78,7 +78,7 @@ impl CtrlPlatform {
}
fn set_gfx_mode(&self, mode: GpuMode) -> Result<(), RogError> {
self.platform.set_gpu_mux_mode(mode.to_mux())?;
self.platform.set_gpu_mux_mode(mode.to_mux_attr())?;
// self.update_initramfs(enable)?;
if mode == GpuMode::Discrete {
info!("Set system-level graphics mode: Dedicated Nvidia");
@@ -147,7 +147,7 @@ impl CtrlPlatform {
) {
self.set_gfx_mode(mode)
.map_err(|err| {
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
warn!("CtrlRogBios: set_gpu_mux_mode {}", err);
err
})
.ok();
@@ -156,7 +156,7 @@ impl CtrlPlatform {
fn gpu_mux_mode(&self) -> GpuMode {
match self.platform.get_gpu_mux_mode() {
Ok(m) => GpuMode::from_mux(m),
Ok(m) => GpuMode::from_mux(m as u8),
Err(e) => {
warn!("CtrlRogBios: get_gfx_mode {}", e);
GpuMode::Error
@@ -202,21 +202,16 @@ impl CtrlPlatform {
#[zbus(signal_context)] ctxt: SignalContext<'_>,
overdrive: bool,
) {
if self
.platform
.set_panel_od(overdrive)
.map_err(|err| {
warn!("CtrlRogBios: set_panel_overdrive {}", err);
err
})
.is_ok()
{
if let Some(mut lock) = self.config.try_lock() {
lock.panel_od = overdrive;
lock.write();
match self.platform.set_panel_od(overdrive) {
Ok(_) => {
if let Some(mut lock) = self.config.try_lock() {
lock.panel_od = overdrive;
lock.write();
}
Self::notify_panel_od(&ctxt, overdrive).await.ok();
}
Self::notify_panel_od(&ctxt, overdrive).await.ok();
}
Err(err) => warn!("CtrlRogBios: set_panel_overdrive {}", err),
};
}
/// Get the `panel_od` value from platform. Updates the stored value in internal config also.
@@ -245,17 +240,12 @@ impl CtrlPlatform {
#[zbus(signal_context)] ctxt: SignalContext<'_>,
disable: bool,
) {
if self
.platform
.set_dgpu_disable(disable)
.map_err(|err| {
warn!("CtrlRogBios: set_dgpu_disable {}", err);
err
})
.is_ok()
{
Self::notify_dgpu_disable(&ctxt, disable).await.ok();
}
match self.platform.set_dgpu_disable(disable) {
Ok(_) => {
Self::notify_dgpu_disable(&ctxt, disable).await.ok();
}
Err(err) => warn!("CtrlRogBios: set_dgpu_disable {}", err),
};
}
fn dgpu_disable(&self) -> bool {
@@ -280,17 +270,12 @@ impl CtrlPlatform {
#[zbus(signal_context)] ctxt: SignalContext<'_>,
enable: bool,
) {
if self
.platform
.set_egpu_enable(enable)
.map_err(|err| {
warn!("CtrlRogBios: set_egpu_enable {}", err);
err
})
.is_ok()
{
Self::notify_egpu_enable(&ctxt, enable).await.ok();
}
match self.platform.set_egpu_enable(enable) {
Ok(_) => {
Self::notify_egpu_enable(&ctxt, enable).await.ok();
}
Err(err) => warn!("CtrlRogBios: set_egpu_enable {}", err),
};
}
fn egpu_enable(&self) -> bool {
+56 -26
View File
@@ -1,3 +1,4 @@
use crate::systemd::{do_systemd_unit_action, SystemdUnitAction};
use crate::{config::Config, error::RogError, GetSupported};
use crate::{task_watch_item, CtrlTask};
use async_trait::async_trait;
@@ -5,13 +6,15 @@ use log::{info, warn};
use rog_platform::power::AsusPower;
use rog_platform::supported::ChargeSupportedFunctions;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;
use zbus::dbus_interface;
use zbus::export::futures_util::lock::Mutex;
use zbus::export::futures_util::StreamExt;
use zbus::Connection;
use zbus::SignalContext;
const ZBUS_PATH: &str = "/org/asuslinux/Power";
const NVIDIA_POWERD: &str = "nvidia-powerd.service";
impl GetSupported for CtrlPower {
type A = ChargeSupportedFunctions;
@@ -49,13 +52,15 @@ impl CtrlPower {
err
})
.ok();
Self::notify_charge_control_end_threshold(&ctxt, limit).await?;
Self::notify_charge_control_end_threshold(&ctxt, limit)
.await
.ok();
Ok(())
}
fn charge_control_end_threshold(&self) -> u8 {
loop {
if let Some(config) = self.config.try_lock() {
if let Some(mut config) = self.config.try_lock() {
let limit = self
.power
.get_charge_control_end_threshold()
@@ -64,11 +69,10 @@ impl CtrlPower {
err
})
.unwrap_or(100);
if let Some(mut config) = self.config.try_lock() {
config.read();
config.bat_charge_limit = limit;
config.write();
}
config.read();
config.bat_charge_limit = limit;
config.write();
return config.bat_charge_limit;
}
@@ -163,6 +167,16 @@ impl CtrlTask for CtrlPower {
})
.ok();
}
if let Ok(value) = power1.power.get_online() {
let action = if value == 1 {
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
}
}
},
move || {},
move || {
@@ -176,6 +190,16 @@ impl CtrlTask for CtrlPower {
})
.ok();
}
if let Ok(value) = power2.power.get_online() {
let action = if value == 1 {
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
}
}
},
)
.await;
@@ -184,25 +208,31 @@ impl CtrlTask for CtrlPower {
.await?;
let ctrl = self.clone();
match ctrl.power.monitor_online() {
Ok(mut watch) => {
tokio::spawn(async move {
let mut buffer = [0; 32];
watch
.event_stream(&mut buffer)
.unwrap()
.for_each(|_| async {
if let Ok(value) = ctrl.power.get_online() {
Self::notify_mains_online(&signal_ctxt, value == 1)
.await
.unwrap();
}
})
.await;
});
tokio::spawn(async move {
let mut online = 10;
loop {
if let Ok(value) = ctrl.power.get_online() {
if online != value {
online = value;
let action = if value == 1 {
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
}
Self::notify_mains_online(&signal_ctxt, value == 1)
.await
.unwrap();
}
}
// The inotify doesn't pick up events when the kernel changes internal value
// so we need to watch it with a thread and sleep unfortunately
sleep(Duration::from_secs(1)).await;
}
Err(e) => info!("inotify watch failed: {}", e),
}
});
Ok(())
}
+4 -5
View File
@@ -87,7 +87,7 @@ impl ProfileZbus {
if let Some(curves) = &ctrl.config.fan_curves {
return Ok(curves.get_enabled_curve_profiles().to_vec());
}
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
Err(Error::Failed(UNSUPPORTED_MSG.to_string()))
}
/// Set a profile fan curve enabled status. Will also activate a fan curve if in the
@@ -99,7 +99,7 @@ impl ProfileZbus {
) -> zbus::fdo::Result<()> {
let mut ctrl = self.0.lock().await;
ctrl.config.read();
return if let Some(curves) = &mut ctrl.config.fan_curves {
if let Some(curves) = &mut ctrl.config.fan_curves {
curves.set_profile_curve_enabled(profile, enabled);
ctrl.write_profile_curve_to_platform()
@@ -110,7 +110,7 @@ impl ProfileZbus {
Ok(())
} else {
Err(Error::Failed(UNSUPPORTED_MSG.to_string()))
};
}
}
/// Get the fan-curve data for the currently active Profile
@@ -121,7 +121,7 @@ impl ProfileZbus {
let curve = curves.get_fan_curves_for(profile);
return Ok(curve.clone());
}
return Err(Error::Failed(UNSUPPORTED_MSG.to_string()));
Err(Error::Failed(UNSUPPORTED_MSG.to_string()))
}
/// Set the fan curve for the specified profile.
@@ -216,7 +216,6 @@ impl CtrlTask for ProfileZbus {
lock.write_profile_curve_to_platform().unwrap();
lock.save_config();
}
Self::notify_profile(&signal_ctxt.clone(), lock.config.active_profile)
.await
.ok();
+17 -9
View File
@@ -10,6 +10,7 @@ use daemon::ctrl_anime::CtrlAnime;
use log::LevelFilter;
use log::{error, info, warn};
use tokio::time::sleep;
use zbus::SignalContext;
use daemon::ctrl_anime::{config::AnimeConfig, trait_impls::CtrlAnimeZbus};
use daemon::ctrl_aura::{config::AuraConfig, controller::CtrlKbdLed, trait_impls::CtrlKbdLedZbus};
@@ -78,7 +79,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
match CtrlPlatform::new(config.clone()) {
Ok(ctrl) => {
start_tasks(ctrl, &mut connection).await?;
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("CtrlPlatform: {}", err);
@@ -87,7 +89,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
match CtrlPower::new(config.clone()) {
Ok(ctrl) => {
start_tasks(ctrl, &mut connection).await?;
let sig_ctx = CtrlPower::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("CtrlPower: {}", err);
@@ -99,7 +102,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
match CtrlPlatformProfile::new(profile_config) {
Ok(ctrl) => {
let zbus = ProfileZbus(Arc::new(Mutex::new(ctrl)));
start_tasks(zbus, &mut connection).await?;
let sig_ctx = ProfileZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("Profile control: {}", err);
@@ -112,7 +116,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
match CtrlAnime::new(AnimeConfig::load()) {
Ok(ctrl) => {
let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl)));
start_tasks(zbus, &mut connection).await?;
let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?;
}
Err(err) => {
info!("AniMe control: {}", err);
@@ -124,7 +129,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
match CtrlKbdLed::new(laptop, aura_config) {
Ok(ctrl) => {
let zbus = CtrlKbdLedZbus(Arc::new(Mutex::new(ctrl)));
start_tasks(zbus, &mut connection).await?;
let sig_ctx = CtrlKbdLedZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("Keyboard control: {}", err);
@@ -140,7 +146,11 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
async fn start_tasks<T>(mut zbus: T, connection: &mut Connection) -> Result<(), Box<dyn Error>>
async fn start_tasks<T>(
mut zbus: T,
connection: &mut Connection,
signal_ctx: SignalContext<'static>,
) -> Result<(), Box<dyn Error>>
where
T: ZbusRun + Reloadable + CtrlTask + Clone,
{
@@ -151,8 +161,6 @@ where
.unwrap_or_else(|err| warn!("Controller error: {}", err));
zbus.add_to_server(connection).await;
task.create_tasks(CtrlKbdLedZbus::signal_context(&connection)?)
.await
.ok();
task.create_tasks(signal_ctx).await.ok();
Ok(())
}
+14
View File
@@ -30,6 +30,9 @@ pub enum RogError {
NoAuraNode,
Anime(AnimeError),
Platform(PlatformError),
SystemdUnitAction(String),
SystemdUnitWaitTimeout(String),
Command(String, std::io::Error),
}
impl fmt::Display for RogError {
@@ -60,6 +63,17 @@ impl fmt::Display for RogError {
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
RogError::SystemdUnitAction(action) => {
write!(f, "systemd unit action {} failed", action)
}
RogError::SystemdUnitWaitTimeout(state) => {
write!(
f,
"Timed out waiting for systemd unit change {} state",
state
)
}
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
}
}
}
+4 -1
View File
@@ -14,6 +14,8 @@ pub mod ctrl_profiles;
/// Laptop matching to determine capabilities
pub mod laptops;
pub mod systemd;
/// Fetch all supported functions for the laptop
pub mod ctrl_supported;
@@ -62,8 +64,9 @@ macro_rules! task_watch_item {
let mut buffer = [0; 32];
watch.event_stream(&mut buffer).unwrap().for_each(|_| async {
let value = ctrl.$name();
dbg!(&value);
concat_idents::concat_idents!(notif_fn = notify_, $name {
Self::notif_fn(&signal_ctxt, value).await.unwrap();
Self::notif_fn(&signal_ctxt, value).await.ok();
});
}).await;
});
+90
View File
@@ -0,0 +1,90 @@
use std::process::Command;
use crate::error::RogError;
/// An action for `systemctl`
#[derive(Debug, Copy, Clone)]
pub enum SystemdUnitAction {
Stop,
Start,
Restart,
}
impl From<SystemdUnitAction> for &str {
fn from(s: SystemdUnitAction) -> Self {
match s {
SystemdUnitAction::Stop => "stop",
SystemdUnitAction::Start => "start",
SystemdUnitAction::Restart => "restart",
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum SystemdUnitState {
Active,
Inactive,
}
impl From<SystemdUnitState> for &str {
fn from(s: SystemdUnitState) -> Self {
match s {
SystemdUnitState::Active => "active",
SystemdUnitState::Inactive => "inactive",
}
}
}
/// Change the state of a systemd unit. Blocks while running command.
pub fn do_systemd_unit_action(action: SystemdUnitAction, unit: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg(<&str>::from(action));
cmd.arg(unit);
let status = cmd
.status()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if !status.success() {
let msg = format!("systemctl {action:?} {unit} failed: {status:?}",);
return Err(RogError::SystemdUnitAction(msg));
}
Ok(())
}
/// Get systemd unit state. Blocks while command is run.
pub fn is_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<bool, RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg("is-active");
cmd.arg(unit);
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
return Ok(true);
}
Ok(false)
}
/// Wait for a systemd unit to change to `state`. Checks state every 250ms for 3 seconds. Blocks while running wait.
pub fn wait_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg("is-active");
cmd.arg(unit);
let mut count = 0;
while count <= (4 * 3) {
// 3 seconds max
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
return Ok(());
}
// fine to block here, nobody doing shit now
std::thread::sleep(std::time::Duration::from_millis(250));
count += 1;
}
Err(RogError::SystemdUnitWaitTimeout(<&str>::from(state).into()))
}
-14
View File
@@ -1,14 +0,0 @@
[Unit]
Description=ASUS Notifications
StartLimitInterval=200
StartLimitBurst=2
[Service]
ExecStartPre=/usr/bin/sleep 2
ExecStart=/usr/bin/asus-notify
Restart=on-failure
RestartSec=1
Type=simple
[Install]
WantedBy=default.target
+19 -19
View File
@@ -21,21 +21,7 @@ per_key = true
[[led_data]]
prod_family = "Zephyrus M"
board_names = ["GU502GV"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = []
per_key = true
[[led_data]]
prod_family = "Zephyrus M"
board_names = ["GM501GS"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = ["Key1", "Key2", "Key3", "Key4"]
per_key = false
[[led_data]]
prod_family = "ROG Zephyrus M15"
board_names = ["GU502LW", "GU502LV"]
board_names = ["GU502G"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = []
per_key = true
@@ -47,6 +33,13 @@ standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = []
per_key = false
[[led_data]]
prod_family = "ROG Zephyrus M15"
board_names = ["GU502L"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = []
per_key = true
[[led_data]]
prod_family = "ROG Zephyrus M16"
board_names = ["GU603Z", "GU603H"]
@@ -56,7 +49,7 @@ per_key = false
[[led_data]]
prod_family = "ROG Zephyrus S17"
board_names = ["GX703HS"]
board_names = ["GX703H"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = []
per_key = false
@@ -64,14 +57,14 @@ per_key = false
[[led_data]]
prod_family = "Zephyrus"
board_names = ["GM501GM", "GX531"]
board_names = ["GM501G", "GX531"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = ["Key1", "Key2", "Key3", "Key4"]
per_key = false
[[led_data]]
prod_family = "ROG Strix"
board_names = ["G531GW", "G533QR", "G533QS", "G733QS", "G733QR", "G513QR", "G713QR", "G513QM", "G713IC", "G713RS"]
board_names = ["G531GW", "G533QR", "G533QS", "G733Q", "G513QR", "G713QR", "G513QM", "G713IC", "G713RS"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
multizone = []
per_key = true
@@ -177,7 +170,7 @@ per_key = true
[[led_data]]
prod_family = "ROG Flow X13"
board_names = ["GV301QH", "GV301QE"]
board_names = ["GV301Q"]
standard = ["Static", "Breathe", "Pulse"]
multizone = []
per_key = false
@@ -188,3 +181,10 @@ board_names = ["G513IC", "G513RC"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = []
per_key = false
[[led_data]]
prod_family = "ROG Flow X16"
board_names = ["GV601R"]
standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = []
per_key = false
+12 -12
View File
@@ -1,6 +1,6 @@
[package]
name = "rog_anime"
version = "1.3.5"
version.workspace = true
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -9,7 +9,7 @@ homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
documentation = "https://docs.rs/rog-anime"
description = "Types useful for translating images and other data for display on the ASUS AniMe Matrix display"
keywords = ["ROG", "ASUS", "AniMe"]
edition = "2018"
edition = "2021"
exclude = ["data"]
[features]
@@ -18,17 +18,17 @@ dbus = ["zvariant", "zbus"]
detect = ["sysfs-class"]
[dependencies]
png_pong = "^0.8.0"
pix = "0.13"
gif = "^0.11.2"
log = "*"
png_pong.workspace = true
pix.workspace = true
gif.workspace = true
log.workspace = true
serde = "^1.0"
serde_derive = "^1.0"
serde.workspace = true
serde_derive.workspace = true
glam = { version = "^0.21.2", features = ["serde"] }
glam.workspace = true
zvariant = { version = "^3.0", optional = true }
zbus = { version = "^2.2", optional = true }
zvariant = { workspace = true, optional = true }
zbus = { workspace = true, optional = true }
sysfs-class = { version = "^0.1", optional = true }
sysfs-class = { workspace = true, optional = true }
+1 -1
View File
@@ -29,7 +29,7 @@ const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
const USB_PREFIX3: [u8; 7] = [0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02];
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub struct AnimePowerStates {
pub brightness: u8,
pub enabled: bool,
+5 -5
View File
@@ -131,14 +131,14 @@ impl AnimeDiagonal {
#[inline]
pub fn into_data_buffer(&self, anime_type: AnimeType) -> Result<AnimeDataBuffer> {
match anime_type {
AnimeType::GA401 => self.into_ga401_packets(),
AnimeType::GA402 => self.into_ga402_packets(),
AnimeType::GA401 => self.to_ga401_packets(),
AnimeType::GA402 => self.to_ga402_packets(),
}
}
/// Do conversion from the nested Vec in AnimeMatrix to the two required
/// packets suitable for sending over USB
fn into_ga401_packets(&self) -> Result<AnimeDataBuffer> {
fn to_ga401_packets(&self) -> Result<AnimeDataBuffer> {
let mut buf = vec![0u8; AnimeType::GA401.data_length()];
buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32));
@@ -200,12 +200,12 @@ impl AnimeDiagonal {
AnimeDataBuffer::from_vec(crate::AnimeType::GA401, buf)
}
fn into_ga402_packets(&self) -> Result<AnimeDataBuffer> {
fn to_ga402_packets(&self) -> Result<AnimeDataBuffer> {
let mut buf = vec![0u8; AnimeType::GA402.data_length()];
let mut start_index: usize = 0;
fn copy_slice(
buf: &mut Vec<u8>,
buf: &mut [u8],
anime: &AnimeDiagonal,
x: usize,
y: usize,
+1 -1
View File
@@ -88,7 +88,7 @@ impl AnimeImage {
width: u32,
anime_type: AnimeType,
) -> Result<Self> {
if bright < 0.0 || bright > 1.0 {
if !(0.0..=1.0).contains(&bright) {
return Err(AnimeError::InvalidBrightness(bright));
}
+1 -3
View File
@@ -26,9 +26,7 @@ pub fn get_anime_type() -> Result<AnimeType, AnimeError> {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name()?;
if board_name.contains("GA401I") {
return Ok(AnimeType::GA401);
} else if board_name.contains("GA401Q") {
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
return Ok(AnimeType::GA401);
} else if board_name.contains("GA402R") {
return Ok(AnimeType::GA402);
+7 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "rog_aura"
version = "1.3.3"
version.workspace = true
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
@@ -9,7 +9,7 @@ homepage = "https://gitlab.com/asus-linux/asusctl"
documentation = "https://docs.rs/rog-anime"
description = "Types useful for fancy keyboards on ASUS ROG laptops"
keywords = ["ROG", "ASUS", "Aura"]
edition = "2018"
edition = "2021"
exclude = ["data"]
[features]
@@ -17,10 +17,10 @@ default = ["dbus", "toml"]
dbus = ["zvariant"]
[dependencies]
serde = "^1.0"
serde_derive = "^1.0"
toml = { version = "^0.5", optional = true }
zvariant = { version = "^3.0", optional = true }
serde.workspace = true
serde_derive.workspace = true
toml = { workspace = true, optional = true }
zvariant = { workspace = true, optional = true }
[dev-dependencies]
serde_json = "^1.0"
serde_json.workspace = true
+7 -7
View File
@@ -12,7 +12,7 @@ use zvariant::Type;
use crate::{error::Error, LED_MSG_LEN};
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum LedBrightness {
Off,
Low,
@@ -33,7 +33,7 @@ impl From<u32> for LedBrightness {
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Clone, PartialEq, PartialOrd, Copy, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Copy, Deserialize, Serialize)]
pub struct Colour(pub u8, pub u8, pub u8);
impl Default for Colour {
@@ -85,7 +85,7 @@ impl From<Colour> for [u8; 3] {
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum Speed {
Low = 0xe1,
Med = 0xeb,
@@ -123,7 +123,7 @@ impl From<Speed> for u8 {
///
/// Enum corresponds to the required integer value
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum Direction {
Right,
Left,
@@ -251,7 +251,7 @@ impl From<u8> for AuraModeNum {
/// Base effects have no zoning, while multizone is 1-4
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Default, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum AuraZone {
/// Used if keyboard has no zones, or if setting all
#[default]
@@ -325,8 +325,8 @@ impl AuraEffect {
&self.mode
}
pub fn mode_name(&self) -> String {
(<&str>::from(&self.mode)).to_string()
pub fn mode_name(&self) -> &str {
<&str>::from(&self.mode)
}
pub fn mode_num(&self) -> u8 {
+21 -28
View File
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub enum Key {
VolUp,
VolDown,
@@ -235,51 +235,44 @@ impl KeyShape {
/// A blank is used to space keys out in GUI's and can be used or ignored
/// depednign on the per-key effect
pub const fn is_blank(&self) -> bool {
match self {
matches!(
self,
Self::NormalBlank
| Self::FuncBlank
| Self::ArrowBlank
| Self::ArrowSplitBlank
| Self::ArrowRegularBlank => true,
_ => false,
}
| Self::FuncBlank
| Self::ArrowBlank
| Self::ArrowSplitBlank
| Self::ArrowRegularBlank
)
}
/// A spacer is used to space keys out in GUI's, but ignored in per-key effects
pub const fn is_spacer(&self) -> bool {
match self {
matches!(
self,
Self::FuncSpacer
| Self::NormalSpacer
| Self::ArrowSpacer
| Self::ArrowSplitSpacer
| Self::ArrowRegularSpacer => true,
_ => false,
}
| Self::NormalSpacer
| Self::ArrowSpacer
| Self::ArrowSplitSpacer
| Self::ArrowRegularSpacer
)
}
/// All keys with a postfix of some number
pub const fn is_group(&self) -> bool {
match self {
Self::LShift3 | Self::RShift3 => true,
Self::Return3 | Self::Space5 | Self::Backspace3 => true,
_ => false,
}
matches!(
self,
Self::LShift3 | Self::RShift3 | Self::Return3 | Self::Space5 | Self::Backspace3
)
}
/// Mostly intended as a helper for signalling when to draw a
/// split/compact arrow cluster
pub const fn is_arrow_cluster(&self) -> bool {
match self {
Self::Arrow | Self::ArrowBlank | Self::ArrowSpacer => true,
_ => false,
}
matches!(self, Self::Arrow | Self::ArrowBlank | Self::ArrowSpacer)
}
pub const fn is_arrow_splits(&self) -> bool {
match self {
Self::ArrowSplit | Self::ArrowSplitBlank | Self::ArrowSplitSpacer => true,
_ => false,
}
matches!(self, Self::Arrow | Self::ArrowBlank | Self::ArrowSpacer)
}
}
+2 -2
View File
@@ -35,9 +35,9 @@ impl KeyLayout {
let mut buf = String::new();
let read_len = file.read_to_string(&mut buf)?;
if read_len == 0 {
return Err(Error::Io(std::io::ErrorKind::InvalidData.into()));
Err(Error::Io(std::io::ErrorKind::InvalidData.into()))
} else {
return Ok(toml::from_str::<Self>(&buf)?);
Ok(toml::from_str::<Self>(&buf)?)
}
}
+1 -6
View File
@@ -138,16 +138,11 @@ impl EffectState for Breathe {
let speed = 4 - <u8>::from(*speed);
let colour: &mut Colour;
if *colour_actual == Colour(0, 0, 0) {
*use_colour1 = !*use_colour1;
}
if !*use_colour1 {
colour = colour2;
} else {
colour = colour1;
}
let colour = if !*use_colour1 { colour2 } else { colour1 };
let r1_scale = colour.0 / speed / 2;
let g1_scale = colour.1 / speed / 2;
+13 -13
View File
@@ -21,7 +21,7 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize, Default)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Serialize, Deserialize, Default)]
pub enum AuraDevice {
Tuf,
X1854,
@@ -127,7 +127,7 @@ impl BitOr<AuraDev1866> for AuraDev1866 {
type Output = u32;
fn bitor(self, rhs: AuraDev1866) -> Self::Output {
return self as u32 | rhs as u32;
self as u32 | rhs as u32
}
}
@@ -135,7 +135,7 @@ impl BitAnd<AuraDev1866> for AuraDev1866 {
type Output = u32;
fn bitand(self, rhs: AuraDev1866) -> Self::Output {
return self as u32 & rhs as u32;
self as u32 & rhs as u32
}
}
@@ -178,14 +178,14 @@ pub enum AuraDev19b6 {
SleepKeyb = 1 << 5,
ShutdownLogo = 1 << 6,
ShutdownKeyb = 1 << 7,
BootBar = 1 << 7 + 2,
AwakeBar = 1 << 7 + 3,
SleepBar = 1 << 7 + 4,
ShutdownBar = 1 << 7 + 5,
BootLid = 1 << 15 + 1,
AwakeLid = 1 << 15 + 2,
SleepLid = 1 << 15 + 3,
ShutdownLid = 1 << 15 + 4,
BootBar = 1 << (7 + 2),
AwakeBar = 1 << (7 + 3),
SleepBar = 1 << (7 + 4),
ShutdownBar = 1 << (7 + 5),
BootLid = 1 << (15 + 1),
AwakeLid = 1 << (15 + 2),
SleepLid = 1 << (15 + 3),
ShutdownLid = 1 << (15 + 4),
}
impl From<AuraDev19b6> for u32 {
@@ -216,7 +216,7 @@ impl BitOr<AuraDev19b6> for AuraDev19b6 {
type Output = u16;
fn bitor(self, rhs: AuraDev19b6) -> Self::Output {
return self as u16 | rhs as u16;
self as u16 | rhs as u16
}
}
@@ -224,7 +224,7 @@ impl BitAnd<AuraDev19b6> for AuraDev19b6 {
type Output = u16;
fn bitand(self, rhs: AuraDev19b6) -> Self::Output {
return self as u16 & rhs as u16;
self as u16 & rhs as u16
}
}
+14 -17
View File
@@ -1,6 +1,6 @@
[package]
name = "rog-control-center"
version = "1.1.1"
version.workspace = true
authors = ["Luke D. Jones <luke@ljones.dev>"]
edition = "2021"
@@ -8,8 +8,8 @@ edition = "2021"
mocking = []
[dependencies]
egui = { git = "https://github.com/emilk/egui" }
eframe= { git = "https://github.com/emilk/egui" }
egui = { git = "https://github.com/flukejones/egui" }
eframe= { git = "https://github.com/flukejones/egui" }
#eframe= { git = "https://github.com/emilk/egui", default-features = false, features = ["dark-light", "default_fonts", "wgpu"] }
daemon = { path = "../daemon" }
@@ -18,20 +18,17 @@ rog_dbus = { path = "../rog-dbus" }
rog_aura = { path = "../rog-aura" }
rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" }
# supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git" }
supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", default-features = false }
#supergfxctl = { path = "../../supergfxctl", default-features = false }
smol = "^1.2"
tokio.workspace = true
serde.workspace = true
toml.workspace = true
serde_json.workspace = true
serde_derive.workspace = true
zbus.workspace = true
dirs.workspace = true
notify-rust.workspace = true
serde = "^1.0"
toml = "^0.5"
serde_json = "^1.0"
serde_derive = "^1.0"
zbus = "^2.3"
nix = "^0.20.0"
tempfile = "3.2.0"
dirs = "3.0.1"
[dependencies.notify-rust]
version = "^4.3"
default-features = false
features = ["z"]
tempfile = "3.2.0"
+8
View File
@@ -10,6 +10,7 @@ pub enum Error {
ConfigLockFail,
XdgVars,
Zbus(zbus::Error),
Notification(notify_rust::error::Error),
}
impl fmt::Display for Error {
@@ -22,6 +23,7 @@ impl fmt::Display for Error {
Error::ConfigLockFail => write!(f, "Failed to lock user config"),
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
Error::Zbus(err) => write!(f, "Error: {}", err),
Error::Notification(err) => write!(f, "Notification Error: {}", err),
}
}
}
@@ -45,3 +47,9 @@ impl From<zbus::Error> for Error {
Error::Zbus(err)
}
}
impl From<notify_rust::error::Error> for Error {
fn from(err: notify_rust::error::Error) -> Self {
Error::Notification(err)
}
}
+2 -2
View File
@@ -45,7 +45,7 @@ pub fn print_versions() {
pub const SHOWING_GUI: u8 = 1;
pub const SHOW_GUI: u8 = 2;
#[derive(PartialEq, Clone, Copy)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Page {
System,
AuraEffects,
@@ -75,7 +75,7 @@ pub fn on_tmp_dir_exists() -> Result<TempDir, std::io::Error> {
// If the app is running this ends up stacked on top of SHOWING_GUI
ipc_file.write_all(&[SHOW_GUI])?;
// tiny sleep to give the app a chance to respond
sleep(Duration::from_millis(10));
sleep(Duration::from_millis(100));
ipc_file.read(&mut buf).ok();
// First entry is the actual state
+89 -61
View File
@@ -1,9 +1,12 @@
use eframe::NativeOptions;
use rog_aura::layouts::KeyLayout;
use rog_control_center::{
config::Config, get_ipc_file, notify::start_notifications, on_tmp_dir_exists,
config::Config, error::Result, get_ipc_file, notify::start_notifications, on_tmp_dir_exists,
page_states::PageDataStates, print_versions, startup_error::AppErrorShow, RogApp,
RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI,
};
use rog_platform::supported::SupportedFunctions;
use tokio::runtime::Runtime;
use std::{
fs::OpenOptions,
@@ -18,11 +21,17 @@ const DATA_DIR: &str = "/usr/share/rog-gui/";
const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> Result<()> {
print_versions();
// start tokio
let rt = Runtime::new().expect("Unable to create Runtime");
// Enter the runtime so that `tokio::spawn` is available immediately.
let _enter = rt.enter();
let native_options = eframe::NativeOptions {
decorated: false,
vsync: true,
decorated: true,
transparent: false,
min_window_size: Some(egui::vec2(840.0, 600.0)),
max_window_size: Some(egui::vec2(840.0, 600.0)),
@@ -72,8 +81,56 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_err(|e| {
println!("{BOARD_NAME}, {e}");
})
.unwrap_or(KeyLayout::ga401_layout());
.unwrap_or_else(|_| KeyLayout::ga401_layout());
// tmp-dir must live to the end of program life
let _tmp_dir = match tempfile::Builder::new()
.prefix("rog-gui")
.rand_bytes(0)
.tempdir()
{
Ok(tmp) => tmp,
Err(_) => on_tmp_dir_exists().unwrap(),
};
let states =
setup_page_state_and_notifs(layout.clone(), &config, native_options.clone(), &dbus)
.unwrap();
loop {
if !start_closed {
start_app(states.clone(), native_options.clone())?;
}
let config = Config::load().unwrap();
if !config.run_in_background {
break;
}
if config.run_in_background {
let mut buf = [0u8; 4];
// blocks until it is read, typically the read will happen after a second
// process writes to the IPC (so there is data to actually read)
if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI {
start_closed = false;
continue;
}
}
}
// loop {
// // This is just a blocker to idle and ensure the reator reacts
// sleep(Duration::from_millis(1000)).await;
// }
Ok(())
}
fn setup_page_state_and_notifs(
keyboard_layout: KeyLayout,
config: &Config,
native_options: NativeOptions,
dbus: &RogDbusClientBlocking,
) -> Result<PageDataStates> {
// Cheap method to alert to notifications rather than spinning a thread for each
// This is quite different when done in a retained mode app
let charge_notified = Arc::new(AtomicBool::new(false));
@@ -94,68 +151,39 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
notifs_enabled.clone(),
)?;
// tmp-dir must live to the end of program life
let _tmp_dir = match tempfile::Builder::new()
.prefix("rog-gui")
.rand_bytes(0)
.tempdir()
{
Ok(tmp) => tmp,
Err(_) => on_tmp_dir_exists().unwrap(),
};
loop {
let states = {
let supported = match dbus.proxies().supported().supported_functions() {
Ok(s) => s,
Err(e) => {
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
);
return Ok(());
}
};
PageDataStates::new(
layout.clone(),
notifs_enabled.clone(),
charge_notified.clone(),
bios_notified.clone(),
aura_notified.clone(),
anime_notified.clone(),
profiles_notified.clone(),
fans_notified.clone(),
&supported,
&dbus,
)?
};
if !start_closed {
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[SHOWING_GUI]).unwrap();
let supported = match dbus.proxies().supported().supported_functions() {
Ok(s) => s,
Err(e) => {
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |cc| {
Box::new(RogApp::new(Config::load().unwrap(), states, cc).unwrap())
}),
native_options,
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
);
SupportedFunctions::default()
}
};
let config = Config::load().unwrap();
if !config.run_in_background {
break;
}
PageDataStates::new(
keyboard_layout,
notifs_enabled.clone(),
charge_notified.clone(),
bios_notified.clone(),
aura_notified.clone(),
anime_notified.clone(),
profiles_notified.clone(),
fans_notified.clone(),
&supported,
&dbus,
)
}
let mut buf = [0u8; 4];
// blocks until it is read, typically the read will happen after a second
// process writes to the IPC (so there is data to actually read)
if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI {
start_closed = false;
continue;
}
}
fn start_app(states: PageDataStates, native_options: NativeOptions) -> Result<()> {
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[SHOWING_GUI]).unwrap();
eframe::run_native(
"ROG Control Center",
native_options,
Box::new(move |cc| Box::new(RogApp::new(Config::load().unwrap(), states, cc).unwrap())),
);
Ok(())
}
+227 -193
View File
@@ -1,44 +1,65 @@
//TODO: a lot of app state refresh depends on this so there needs
// to be an extra AtomicBool for checking if notifications are enabled
use crate::error::Result;
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_aura::AuraEffect;
use rog_dbus::{
zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy,
zbus_power::PowerProxy, zbus_profile::ProfileProxy,
};
use rog_platform::platform::GpuMode;
use rog_profiles::Profile;
use smol::{future, Executor};
use std::{
error::Error,
fmt::Display,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
thread::spawn,
};
use zbus::export::futures_util::StreamExt;
use supergfxctl::pci_device::GfxPower;
use zbus::export::futures_util::{future, StreamExt};
const NOTIF_HEADER: &str = "ROG Control";
macro_rules! notify {
($notifier:ident, $last_notif:ident, $data:expr) => {
($notifier:expr, $last_notif:ident) => {
if let Some(notif) = $last_notif.take() {
notif.close();
}
if let Ok(x) = $notifier($data) {
if let Ok(x) = $notifier {
$last_notif.replace(x);
}
};
}
macro_rules! base_notification {
($body:expr) => {
Notification::new()
.summary(NOTIF_HEADER)
.body($body)
.timeout(2000)
.show()
macro_rules! recv_notif {
($proxy:ident,
$signal:ident,
$was_notified:ident,
$last_notif:ident,
$notif_enabled:ident,
[$($out_arg:ident)+],
$msg:literal,
$notifier:ident) => {
let last_notif = $last_notif.clone();
let notifs_enabled1 = $notif_enabled.clone();
let notified = $was_notified.clone();
// TODO: make a macro or generic function or something...
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = $proxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.$signal().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!($notifier($msg, &out$(.$out_arg)+()), lock);
}
}
notified.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
});
};
}
@@ -52,205 +73,218 @@ pub fn start_notifications(
profiles_notified: Arc<AtomicBool>,
_fans_notified: Arc<AtomicBool>,
notifs_enabled: Arc<AtomicBool>,
) -> Result<(), Box<dyn std::error::Error>> {
) -> Result<()> {
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
let executor = Executor::new();
// BIOS notif
let last_notif = last_notification.clone();
let notifs_enabled1 = notifs_enabled.clone();
let bios_notified1 = bios_notified.clone();
// TODO: make a macro or generic function or something...
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = RogBiosProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_post_boot_sound().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!(do_post_sound_notif, lock, &out.on());
}
}
bios_notified1.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
})
.detach();
recv_notif!(
RogBiosProxy,
receive_notify_post_boot_sound,
bios_notified,
last_notification,
notifs_enabled,
[on],
"BIOS Post sound",
do_notification
);
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = RogBiosProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_panel_od().await {
p.for_each(|_| {
bios_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
})
.detach();
recv_notif!(
RogBiosProxy,
receive_notify_panel_od,
bios_notified,
last_notification,
notifs_enabled,
[overdrive],
"Panel Overdrive enabled:",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_dgpu_disable,
bios_notified,
last_notification,
notifs_enabled,
[disable],
"BIOS dGPU disabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_egpu_enable,
bios_notified,
last_notification,
notifs_enabled,
[enable],
"BIOS eGPU enabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_gpu_mux_mode,
bios_notified,
last_notification,
notifs_enabled,
[mode],
"BIOS GPU MUX mode (reboot required)",
mux_notification
);
// Charge notif
let last_notif = last_notification.clone();
let notifs_enabled1 = notifs_enabled.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = PowerProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_charge_control_end_threshold().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!(do_charge_notif, lock, &out.limit);
}
}
charge_notified.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
})
.detach();
recv_notif!(
PowerProxy,
receive_notify_charge_control_end_threshold,
charge_notified,
last_notification,
notifs_enabled,
[limit],
"Battery charge limit changed to",
do_notification
);
recv_notif!(
PowerProxy,
receive_notify_mains_online,
bios_notified,
last_notification,
notifs_enabled,
[on],
"AC Power power is",
ac_power_notification
);
// Profile notif
let last_notif = last_notification.clone();
let notifs_enabled1 = notifs_enabled.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = ProfileProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_profile().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!(do_thermal_notif, lock, &out.profile);
}
}
profiles_notified.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
})
.detach();
recv_notif!(
ProfileProxy,
receive_notify_profile,
profiles_notified,
last_notification,
notifs_enabled,
[profile],
"Profile changed to",
do_thermal_notif
);
// notify!(do_thermal_notif(&out.profile), lock);
// LED notif
let last_notif = last_notification.clone();
let aura_notif = aura_notified.clone();
recv_notif!(
LedProxy,
receive_notify_led,
aura_notified,
last_notification,
notifs_enabled,
[data mode_name],
"Keyboard LED mode changed to",
do_notification
);
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_all_signals().await {
p.for_each(|_| {
aura_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
});
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = AnimeProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_power_states().await {
p.for_each(|_| {
anime_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
});
let notifs_enabled1 = notifs_enabled.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_led().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
let last_notif = last_notification.clone();
let bios_notified1 = bios_notified.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = supergfxctl::zbus_proxy::DaemonProxy::new(&conn)
.await
.unwrap();
if let Ok(p) = proxy.receive_notify_gfx_status().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
let status = out.status();
if *status != GfxPower::Unknown {
// Required check because status cycles through active/unknown/suspended
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!(do_led_notif, lock, &out.data);
notify!(
do_notification(
"dGPU status changed:",
&format!("{status:?}",)
),
lock
);
}
}
aura_notif.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
})
.detach();
let aura_notif = aura_notified.clone();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_notify_led().await {
p.for_each(|_| {
aura_notif.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
})
.detach();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_all_signals().await {
p.for_each(|_| {
aura_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
})
.detach();
executor
.spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = AnimeProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_power_states().await {
p.for_each(|_| {
anime_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
})
.detach();
spawn(move || loop {
smol::block_on(executor.tick());
}
bios_notified1.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
});
Ok(())
}
fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {
fn base_notification<T>(message: &str, data: &T) -> Notification
where
T: Display,
{
let mut notif = Notification::new();
notif
.summary(NOTIF_HEADER)
.body(&format!("{message} {data}"))
.timeout(2000)
//.hint(Hint::Resident(true))
.hint(Hint::Category("device".into()));
notif
}
fn do_notification<T>(message: &str, data: &T) -> Result<NotificationHandle>
where
T: Display,
{
Ok(base_notification(message, data).show()?)
}
fn ac_power_notification(message: &str, on: &bool) -> Result<NotificationHandle> {
let data = if *on {
"plugged".to_string()
} else {
"unplugged".to_string()
};
Ok(base_notification(message, &data).show()?)
}
/// Actual GpuMode unused as data is never correct until switched by reboot
fn mux_notification(message: &str, _: &GpuMode) -> Result<NotificationHandle> {
Ok(base_notification(message, &"").show()?)
}
fn do_thermal_notif(message: &str, profile: &Profile) -> Result<NotificationHandle> {
let icon = match profile {
Profile::Balanced => "asus_notif_yellow",
Profile::Performance => "asus_notif_red",
Profile::Quiet => "asus_notif_green",
};
let profile: &str = (*profile).into();
let x = Notification::new()
.summary("ASUS ROG")
.body(&format!(
"Thermal profile changed to {}",
profile.to_uppercase(),
))
.hint(Hint::Resident(true))
.timeout(2000)
.hint(Hint::Category("device".into()))
//.hint(Hint::Transient(true))
.icon(icon)
.show()?;
Ok(x)
}
fn do_led_notif(ledmode: &AuraEffect) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!(
"Keyboard LED mode changed to {}",
ledmode.mode_name()
))
}
fn do_charge_notif(limit: &u8) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!("Battery charge limit changed to {}", limit))
}
fn do_post_sound_notif(on: &bool) -> Result<NotificationHandle, notify_rust::error::Error> {
base_notification!(&format!("BIOS Post sound {}", on))
let mut notif = base_notification(message, &profile.to_uppercase());
Ok(notif.icon(icon).show()?)
}
+2 -1
View File
@@ -246,7 +246,7 @@ impl AnimeState {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct PageDataStates {
pub keyboard_layout: KeyLayout,
pub notifs_enabled: Arc<AtomicBool>,
@@ -262,6 +262,7 @@ pub struct PageDataStates {
pub error: Option<String>,
}
#[allow(clippy::too_many_arguments)]
impl PageDataStates {
pub fn new(
keyboard_layout: KeyLayout,
+1 -1
View File
@@ -16,7 +16,7 @@ impl<'a> RogApp<'a> {
} = self;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Experimental application for asusd");
ui.heading("Base settings");
egui::ScrollArea::vertical().show(ui, |ui| {
ui.spacing_mut().item_spacing = egui::vec2(8.0, 10.0);
+4 -4
View File
@@ -73,10 +73,10 @@ fn aura_power1(
if ui.toggle_value(&mut keyboard, "Keyboard").changed() {
changed = true;
}
if !supported.keyboard_led.multizone_led_mode.is_empty() {
if ui.toggle_value(&mut lightbar, "Lightbar").changed() {
changed = true;
}
if !supported.keyboard_led.multizone_led_mode.is_empty()
&& ui.toggle_value(&mut lightbar, "Lightbar").changed()
{
changed = true;
}
});
ui.horizontal_wrapped(|ui| {
+22 -23
View File
@@ -54,47 +54,46 @@ pub fn rog_bios_group(
.ok();
}
if supported.rog_bios_ctrl.post_sound {
if ui
if supported.rog_bios_ctrl.post_sound
&& ui
.add(egui::Checkbox::new(
&mut states.bios.post_sound,
"POST sound",
))
.changed()
{
dbus.proxies()
.rog_bios()
.set_post_boot_sound(states.bios.post_sound)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
{
dbus.proxies()
.rog_bios()
.set_post_boot_sound(states.bios.post_sound)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
if supported.rog_bios_ctrl.post_sound {
if ui
if supported.rog_bios_ctrl.post_sound
&& ui
.add(egui::Checkbox::new(
&mut states.bios.panel_overdrive,
"Panel overdrive",
))
.changed()
{
dbus.proxies()
.rog_bios()
.set_panel_od(states.bios.panel_overdrive)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
{
dbus.proxies()
.rog_bios()
.set_panel_od(states.bios.panel_overdrive)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
if supported.rog_bios_ctrl.gpu_mux {
let mut changed = false;
ui.group(|ui| {
ui.vertical(|ui| {
ui.horizontal_wrapped(|ui| ui.label("GPU MUX mode (reboot required)"));
ui.horizontal_wrapped(|ui| ui.label("GPU MUX mode"));
ui.horizontal_wrapped(|ui| ui.label("NOTE: Value does not change until rebooted"));
ui.horizontal_wrapped(|ui| {
changed = ui
.selectable_value(
+12 -12
View File
@@ -1,4 +1,4 @@
use egui::{vec2, Align2, Button, FontId, Id, Rect, RichText, Sense, Vec2};
use egui::{vec2, Align2, FontId, Id, Sense};
use crate::{RogApp, VERSION};
@@ -27,20 +27,20 @@ impl<'a> RogApp<'a> {
let height = titlebar_rect.height();
// Paint the title:
ui.painter().text(
titlebar_rect.center_top() + vec2(0.0, height / 2.0),
Align2::CENTER_CENTER,
format!("ROG Control Center v{}", VERSION),
titlebar_rect.right_top() + vec2(0.0, height / 2.0),
Align2::RIGHT_CENTER,
format!("v{}", VERSION),
FontId::proportional(height - 2.0),
text_color,
);
// Add the close button:
let close_response = ui.put(
Rect::from_min_size(titlebar_rect.right_top(), Vec2::splat(height)),
Button::new(RichText::new("").size(height - 4.0)).frame(false),
);
if close_response.clicked() {
frame.close();
}
// // Add the close button:
// let close_response = ui.put(
// Rect::from_min_size(titlebar_rect.right_top(), Vec2::splat(height)),
// Button::new(RichText::new("❌").size(height - 4.0)).frame(false),
// );
// if close_response.clicked() {
// frame.close();
// }
});
});
}
+5 -5
View File
@@ -1,19 +1,19 @@
[package]
name = "rog_dbus"
version = "4.4.0"
version.workspace = true
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"
edition = "2021"
[dependencies]
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" }
zbus = "^2.2"
zbus_macros = "^2.0"
zvariant = "^3.0"
zbus.workspace = true
zbus_macros.workspace = true
zvariant.workspace = true
+7
View File
@@ -7,26 +7,33 @@ use zbus_macros::dbus_proxy;
)]
trait Anime {
/// Set whether the AniMe will show boot, suspend, or off animations
#[inline]
fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>;
/// Set the global AniMe brightness
#[inline]
fn set_brightness(&self, bright: f32) -> zbus::Result<()>;
/// Set whether the AniMe is displaying images/data
#[inline]
fn set_on_off(&self, status: bool) -> zbus::Result<()>;
/// Writes a data stream of length. Will force system thread to exit until it is restarted
#[inline]
fn write(&self, input: AnimeDataBuffer) -> zbus::Result<()>;
/// Get status of if the AniMe LEDs are on
#[inline]
#[dbus_proxy(property)]
fn awake_enabled(&self) -> zbus::Result<bool>;
/// Get the status of if factory system-status animations are enabled
#[inline]
#[dbus_proxy(property)]
fn boot_enabled(&self) -> zbus::Result<bool>;
/// Notify listeners of the status of AniMe LED power and factory system-status animations
#[inline]
#[dbus_proxy(signal)]
fn power_states(&self, data: AnimePowerStates) -> zbus::Result<()>;
}
+14
View File
@@ -34,46 +34,60 @@ const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 F
)]
trait Led {
/// NextLedMode method
#[inline]
fn next_led_mode(&self) -> zbus::Result<()>;
/// PrevLedMode method
#[inline]
fn prev_led_mode(&self) -> zbus::Result<()>;
/// Toggle to next led brightness
#[inline]
fn next_led_brightness(&self) -> zbus::Result<()>;
/// Toggle to previous led brightness
#[inline]
fn prev_led_brightness(&self) -> zbus::Result<()>;
/// SetBrightness method
#[inline]
fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>;
/// SetLedMode method
#[inline]
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
#[inline]
fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>;
#[inline]
fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()>;
/// NotifyLed signal
#[inline]
#[dbus_proxy(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
#[dbus_proxy(signal)]
#[inline]
fn notify_power_states(&self, data: AuraPowerDev) -> zbus::Result<()>;
/// LedBrightness property
#[inline]
#[dbus_proxy(property)]
fn led_brightness(&self) -> zbus::Result<i16>;
/// LedMode property
#[inline]
fn led_mode(&self) -> zbus::Result<AuraModeNum>;
/// LedModes property
#[inline]
fn led_modes(&self) -> zbus::Result<BTreeMap<AuraModeNum, AuraEffect>>;
// As property doesn't work for AuraPowerDev (complexity of serialization?)
// #[dbus_proxy(property)]
#[inline]
fn leds_enabled(&self) -> zbus::Result<AuraPowerDev>;
}
+15
View File
@@ -28,52 +28,67 @@ use zbus_macros::dbus_proxy;
)]
trait RogBios {
/// DgpuDisable method
#[inline]
fn dgpu_disable(&self) -> zbus::Result<bool>;
/// EgpuEnable method
#[inline]
fn egpu_enable(&self) -> zbus::Result<bool>;
/// GpuMuxMode method
#[inline]
fn gpu_mux_mode(&self) -> zbus::Result<GpuMode>;
/// PanelOd method
#[inline]
fn panel_od(&self) -> zbus::Result<bool>;
/// PostBootSound method
#[inline]
fn post_boot_sound(&self) -> zbus::Result<i16>;
/// SetDgpuDisable method
#[inline]
fn set_dgpu_disable(&self, disable: bool) -> zbus::Result<()>;
/// SetEgpuEnable method
#[inline]
fn set_egpu_enable(&self, enable: bool) -> zbus::Result<()>;
/// SetGpuMuxMode method
#[inline]
fn set_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>;
/// SetPanelOd method
#[inline]
fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>;
/// SetPostBootSound method
#[inline]
fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>;
/// NotifyDgpuDisable signal
#[inline]
#[dbus_proxy(signal)]
fn notify_dgpu_disable(&self, disable: bool) -> zbus::Result<()>;
/// NotifyEgpuEnable signal
#[inline]
#[dbus_proxy(signal)]
fn notify_egpu_enable(&self, enable: bool) -> zbus::Result<()>;
/// NotifyGpuMuxMode signal
#[inline]
#[dbus_proxy(signal)]
fn notify_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>;
/// NotifyPanelOd signal
#[inline]
#[dbus_proxy(signal)]
fn notify_panel_od(&self, overdrive: bool) -> zbus::Result<()>;
/// NotifyPostBootSound signal
#[inline]
#[dbus_proxy(signal)]
fn notify_post_boot_sound(&self, on: bool) -> zbus::Result<()>;
}
+5
View File
@@ -27,19 +27,24 @@ use zbus_macros::dbus_proxy;
)]
trait Power {
/// charge_control_end_threshold method
#[inline]
fn charge_control_end_threshold(&self) -> zbus::Result<u8>;
/// MainsOnline method
#[inline]
fn mains_online(&self) -> zbus::Result<bool>;
/// set_charge_control_end_threshold method
#[inline]
fn set_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<()>;
/// NotifyCharge signal
#[inline]
#[dbus_proxy(signal)]
fn notify_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<u8>;
/// NotifyMainsOnline signal
#[inline]
#[dbus_proxy(signal)]
fn notify_mains_online(&self, on: bool) -> zbus::Result<()>;
}
+12 -1
View File
@@ -31,44 +31,55 @@ use zbus_macros::dbus_proxy;
)]
trait Profile {
/// Get the fan-curve data for the currently active Profile
#[inline]
fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet>;
/// Fetch the active profile name
#[inline]
fn active_profile(&self) -> zbus::Result<Profile>;
/// Get a list of profiles that have fan-curves enabled.
#[inline]
fn enabled_fan_profiles(&self) -> zbus::Result<Vec<Profile>>;
/// Toggle to next platform_profile. Names provided by `Profiles`.
/// If fan-curves are supported will also activate a fan curve for profile.
#[inline]
fn next_profile(&self) -> zbus::Result<()>;
/// Fetch profile names
#[inline]
fn profiles(&self) -> zbus::Result<Vec<Profile>>;
/// Set this platform_profile name as active
#[inline]
fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>;
/// Set a profile fan curve enabled status. Will also activate a fan curve.
#[inline]
fn set_fan_curve_enabled(&self, profile: Profile, enabled: bool) -> zbus::Result<()>;
/// Set the fan curve for the specified profile, or the profile the user is
/// currently in if profile == None. Will also activate the fan curve.
#[inline]
fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::Result<()>;
/// Reset the stored (self) and device curve to the defaults of the platform.
///
/// Each platform_profile has a different default and the defualt can be read
/// only for the currently active profile.
#[inline]
fn set_active_curve_to_defaults(&self) -> zbus::Result<()>;
/// Reset the stored (self) and device curve to the defaults of the platform.
///
/// Each platform_profile has a different default and the defualt can be read
/// only for the currently active profile.
#[inline]
fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()>;
/// NotifyProfile signal
#[inline]
#[dbus_proxy(signal)]
fn notify_profile(&self, profile: Profile) -> zbus::Result<Profile>;
async fn notify_profile(&self, profile: Profile) -> zbus::Result<Profile>;
}
+1
View File
@@ -28,5 +28,6 @@ use zbus_macros::dbus_proxy;
)]
trait Supported {
/// SupportedFunctions method
#[inline]
fn supported_functions(&self) -> zbus::Result<SupportedFunctions>;
}
+11 -16
View File
@@ -1,23 +1,18 @@
[package]
name = "rog_platform"
version = "0.1.1"
version.workspace = true
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "*"
log.workspace = true
rog_aura = { path = "../rog-aura" }
serde = "^1.0"
serde_derive = "^1.0"
zvariant = "^3.0"
zvariant_derive = "^3.0"
serde.workspace = true
serde_derive.workspace = true
zvariant.workspace = true
zvariant_derive.workspace = true
sysfs-class.workspace = true
concat-idents.workspace = true
udev.workspace = true
inotify.workspace = true
udev = "^0.6"
rusb = "^0.9"
sysfs-class = "^0.1"
inotify = "^0.10.0"
# inotify = { version = "0.10.0", default-features = false }
concat-idents = "1.1.3"
rusb.workspace = true
+1 -1
View File
@@ -4,7 +4,7 @@ use log::{info, warn};
use crate::error::{PlatformError, Result};
#[derive(Debug, PartialEq, PartialOrd, Clone)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
pub struct HidRaw(PathBuf);
impl HidRaw {
+5 -3
View File
@@ -8,7 +8,7 @@ use crate::{
has_attr, set_attr_u8_array, to_device,
};
#[derive(Debug, Default, PartialEq, PartialOrd, Clone)]
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Clone)]
pub struct KeyboardLed {
path: PathBuf,
}
@@ -32,10 +32,12 @@ impl KeyboardLed {
PlatformError::Udev("match_subsystem failed".into(), err)
})?;
for device in enumerator.scan_devices().map_err(|err| {
if let Some(device) = (enumerator.scan_devices().map_err(|err| {
warn!("{}", err);
PlatformError::Udev("scan_devices failed".into(), err)
})? {
})?)
.next()
{
info!("Found keyboard LED controls at {:?}", device.sysname());
return Ok(Self {
path: device.syspath().to_owned(),
+3 -3
View File
@@ -51,7 +51,7 @@ pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<(
pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result<u8> {
if let Some(value) = device.attribute_value(attr_name) {
let tmp = value.to_string_lossy();
return Ok(tmp.parse::<u8>().map_err(|_| PlatformError::ParseNum)?);
return tmp.parse::<u8>().map_err(|_| PlatformError::ParseNum);
}
Err(PlatformError::AttrNotFound(attr_name.to_string()))
}
@@ -67,7 +67,7 @@ pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result<Vec<u8>> {
let tmp = value.to_string_lossy();
let tmp = tmp
.split(' ')
.map(|v| u8::from_str_radix(v, 10).unwrap_or(0))
.map(|v| v.parse::<u8>().unwrap_or(0))
.collect();
return Ok(tmp);
}
@@ -94,7 +94,7 @@ mod tests {
let tmp: Vec<u8> = tmp
.split(' ')
.map(|v| u8::from_str_radix(v, 10).unwrap_or(0))
.map(|v| v.parse::<u8>().unwrap_or(0))
.collect();
assert_eq!(tmp, &[1, 2, 3, 4, 5]);
}
+21 -20
View File
@@ -5,7 +5,7 @@ macro_rules! has_attr {
$(#[$doc_comment])*
pub fn fn_name(&self) -> bool {
match to_device(&self.$item) {
Ok(p) => crate::has_attr(&p, $attr_name),
Ok(p) => $crate::has_attr(&p, $attr_name),
Err(_) => false,
}
}
@@ -23,7 +23,7 @@ macro_rules! watch_attr {
path.push($attr_name);
if let Some(path) = path.to_str() {
let mut inotify = inotify::Inotify::init()?;
inotify.add_watch(path, inotify::WatchMask::MODIFY)
inotify.add_watch(path, inotify::WatchMask::CLOSE_WRITE)
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
PlatformError::AttrNotFound(format!("{}", $attr_name))
@@ -45,7 +45,7 @@ macro_rules! get_attr_bool {
concat_idents::concat_idents!(fn_name = get_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self) -> Result<bool> {
crate::read_attr_bool(&to_device(&self.$item)?, $attr_name)
$crate::read_attr_bool(&to_device(&self.$item)?, $attr_name)
}
});
};
@@ -57,7 +57,7 @@ macro_rules! set_attr_bool {
concat_idents::concat_idents!(fn_name = set_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self, value: bool) -> Result<()> {
crate::write_attr_bool(&mut to_device(&self.$item)?, $attr_name, value)
$crate::write_attr_bool(&mut to_device(&self.$item)?, $attr_name, value)
}
});
};
@@ -66,10 +66,10 @@ macro_rules! set_attr_bool {
#[macro_export]
macro_rules! attr_bool {
($attr_name:literal, $item:ident) => {
crate::has_attr!($attr_name $item);
crate::get_attr_bool!( $attr_name $item);
crate::set_attr_bool!($attr_name $item);
crate::watch_attr!($attr_name $item);
$crate::has_attr!($attr_name $item);
$crate::get_attr_bool!( $attr_name $item);
$crate::set_attr_bool!($attr_name $item);
$crate::watch_attr!($attr_name $item);
};
}
@@ -79,19 +79,20 @@ macro_rules! get_attr_u8 {
concat_idents::concat_idents!(fn_name = get_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self) -> Result<u8> {
crate::read_attr_u8(&to_device(&self.$item)?, $attr_name)
$crate::read_attr_u8(&to_device(&self.$item)?, $attr_name)
}
});
};
}
/// Most attributes expect `u8` as a char, so `1` should be written as `b'1'`.
#[macro_export]
macro_rules! set_attr_u8 {
($(#[$doc_comment:meta])? $attr_name:literal $item:ident) => {
concat_idents::concat_idents!(fn_name = set_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self, value: u8) -> Result<()> {
crate::write_attr_u8(&mut to_device(&self.$item)?, $attr_name, value)
$crate::write_attr_u8(&mut to_device(&self.$item)?, $attr_name, value)
}
});
};
@@ -100,10 +101,10 @@ macro_rules! set_attr_u8 {
#[macro_export]
macro_rules! attr_u8 {
($attr_name:literal, $item:ident) => {
crate::has_attr!($attr_name $item);
crate::get_attr_u8!($attr_name $item);
crate::set_attr_u8!($attr_name $item);
crate::watch_attr!($attr_name $item);
$crate::has_attr!($attr_name $item);
$crate::get_attr_u8!($attr_name $item);
$crate::set_attr_u8!($attr_name $item);
$crate::watch_attr!($attr_name $item);
};
}
@@ -113,7 +114,7 @@ macro_rules! get_attr_u8_array {
concat_idents::concat_idents!(fn_name = get_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self) -> Result<Vec<u8>> {
crate::read_attr_u8_array(&to_device(&self.$item)?, $attr_name)
$crate::read_attr_u8_array(&to_device(&self.$item)?, $attr_name)
}
});
};
@@ -125,7 +126,7 @@ macro_rules! set_attr_u8_array {
concat_idents::concat_idents!(fn_name = set_, $attr_name {
$(#[$doc_comment])*
pub fn fn_name(&self, values: &[u8]) -> Result<()> {
crate::write_attr_u8_array(&mut to_device(&self.$item)?, $attr_name, values)
$crate::write_attr_u8_array(&mut to_device(&self.$item)?, $attr_name, values)
}
});
};
@@ -134,9 +135,9 @@ macro_rules! set_attr_u8_array {
#[macro_export]
macro_rules! attr_u8_array {
($attr_name:literal, $item:ident) => {
crate::has_attr!($attr_name $item);
crate::get_attr_u8_array!($attr_name $item);
crate::set_attr_u8_array!($attr_name $item);
crate::watch_attr!($attr_name $item);
$crate::has_attr!($attr_name $item);
$crate::get_attr_u8_array!($attr_name $item);
$crate::set_attr_u8_array!($attr_name $item);
$crate::watch_attr!($attr_name $item);
};
}
+27 -11
View File
@@ -1,4 +1,4 @@
use std::{path::PathBuf, str::FromStr};
use std::{fmt::Display, path::PathBuf, str::FromStr};
use log::{info, warn};
use serde::{Deserialize, Serialize};
@@ -17,7 +17,7 @@ use crate::{
/// - gpu_mux
/// - keyboard_mode, set keyboard RGB mode and speed
/// - keyboard_state, set keyboard power states
#[derive(Debug, PartialEq, PartialOrd, Clone)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
pub struct AsusPlatform {
path: PathBuf,
pp_path: PathBuf,
@@ -38,10 +38,12 @@ impl AsusPlatform {
PlatformError::Udev("match_subsystem failed".into(), err)
})?;
for device in enumerator.scan_devices().map_err(|err| {
if let Some(device) = (enumerator.scan_devices().map_err(|err| {
warn!("{}", err);
PlatformError::Udev("scan_devices failed".into(), err)
})? {
})?)
.next()
{
info!("Found platform support at {:?}", device.sysname());
return Ok(Self {
path: device.syspath().to_owned(),
@@ -56,14 +58,14 @@ impl AsusPlatform {
attr_bool!("dgpu_disable", path);
attr_bool!("egpu_enable", path);
attr_bool!("panel_od", path);
attr_u8!("gpu_mux_mode", path);
attr_bool!("gpu_mux_mode", path);
// This is technically the same as `platform_profile` since both are tied in-kernel
attr_u8!("throttle_thermal_policy", path);
// The acpi platform_profile support
attr_u8!("platform_profile", pp_path);
}
#[derive(Serialize, Deserialize, Type, Debug, PartialEq, Clone, Copy)]
#[derive(Serialize, Deserialize, Type, Debug, PartialEq, Eq, Clone, Copy)]
pub enum GpuMode {
Discrete,
Optimus,
@@ -74,21 +76,22 @@ pub enum GpuMode {
}
impl GpuMode {
pub fn to_mux(&self) -> u8 {
/// For writing to `gpu_mux_mode` attribute
pub fn to_mux_attr(&self) -> bool {
if *self == Self::Discrete {
return 0;
return false;
}
1
true
}
pub fn to_dgpu(&self) -> u8 {
pub fn to_dgpu_attr(&self) -> u8 {
if *self == Self::Integrated {
return 1;
}
0
}
pub fn to_egpu(&self) -> u8 {
pub fn to_egpu_attr(&self) -> u8 {
if *self == Self::Egpu {
return 1;
}
@@ -118,3 +121,16 @@ impl GpuMode {
Self::Optimus
}
}
impl Display for GpuMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GpuMode::Discrete => write!(f, "Discrete"),
GpuMode::Optimus => write!(f, "Optimus"),
GpuMode::Integrated => write!(f, "Integrated"),
GpuMode::Egpu => write!(f, "eGPU"),
GpuMode::Error => write!(f, "Error"),
GpuMode::NotSupported => write!(f, "Not Supported"),
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ use crate::{
/// - gpu_mux
/// - keyboard_mode, set keyboard RGB mode and speed
/// - keyboard_state, set keyboard power states
#[derive(Debug, PartialEq, PartialOrd, Clone)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
pub struct AsusPower {
mains: PathBuf,
battery: PathBuf,
+2 -2
View File
@@ -3,7 +3,7 @@ use std::time::Duration;
use crate::error::{PlatformError, Result};
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
pub struct USBRaw(DeviceHandle<rusb::GlobalContext>);
impl USBRaw {
@@ -43,6 +43,6 @@ impl USBRaw {
message,
Duration::from_millis(200),
)
.map_err(|e| PlatformError::USB(e))
.map_err(PlatformError::USB)
}
}
+7 -7
View File
@@ -1,17 +1,17 @@
[package]
name = "rog_profiles"
version = "1.1.3"
version.workspace = true
authors = ["Luke D. Jones <luke@ljones.dev>"]
edition = "2018"
edition = "2021"
[features]
default = ["dbus"]
dbus = ["zvariant", "zvariant_derive"]
[dependencies]
udev = "^0.6"
serde = "^1.0"
serde_derive = "^1.0"
udev.workspace = true
serde.workspace = true
serde_derive.workspace = true
zvariant = { version = "^3.0", optional = true }
zvariant_derive = { version = "^3.0", optional = true }
zvariant = { workspace = true, optional = true }
zvariant_derive = { workspace = true, optional = true }
+8 -1
View File
@@ -2,6 +2,7 @@ pub mod error;
pub mod fan_curve_set;
use std::{
fmt::Display,
fs::OpenOptions,
io::{Read, Write},
path::Path,
@@ -113,8 +114,14 @@ impl std::str::FromStr for Profile {
}
}
impl Display for Profile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Copy)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, Copy)]
pub enum FanCurvePU {
CPU,
GPU,