From 62c7338b2de7065e291604a585686b2c959dbdfc Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 15 Sep 2022 13:28:53 +1200 Subject: [PATCH 01/11] Use loops to ensure settings apply where a mutex is tried --- daemon/src/ctrl_aura/zbus.rs | 135 ++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 56 deletions(-) diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 4abc406e..5392ef08 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -65,25 +65,28 @@ impl CtrlKbdLedZbus { enabled: bool, ) -> zbus::fdo::Result<()> { let mut states = None; - if let Ok(mut ctrl) = self.0.try_lock() { - for p in options.tuf { - ctrl.config.enabled.set_tuf(p, enabled); - } - for p in options.x1866 { - ctrl.config.enabled.set_0x1866(p, enabled); - } - for p in options.x19b6 { - ctrl.config.enabled.set_0x19b6(p, enabled); - } + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + for p in options.tuf { + ctrl.config.enabled.set_tuf(p, enabled); + } + for p in options.x1866 { + ctrl.config.enabled.set_0x1866(p, enabled); + } + for p in options.x19b6 { + ctrl.config.enabled.set_0x19b6(p, enabled); + } - ctrl.config.write(); + ctrl.config.write(); - ctrl.set_power_states().map_err(|e| { - warn!("{}", e); - e - })?; + ctrl.set_power_states().map_err(|e| { + warn!("{}", e); + e + })?; - states = Some(AuraPowerDev::from(&ctrl.config.enabled)); + states = Some(AuraPowerDev::from(&ctrl.config.enabled)); + } + break; } // Need to pull state out like this due to MutexGuard if let Some(states) = states { @@ -100,13 +103,16 @@ impl CtrlKbdLedZbus { effect: AuraEffect, ) -> zbus::fdo::Result<()> { let mut led = None; - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.set_effect(effect).map_err(|e| { - warn!("{}", e); - e - })?; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.set_effect(effect).map_err(|e| { + warn!("{}", e); + e + })?; + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + led = Some(mode.clone()); + } + break; } } if let Some(led) = led { @@ -122,14 +128,17 @@ impl CtrlKbdLedZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { let mut led = None; - if let Ok(mut ctrl) = self.0.lock() { - ctrl.toggle_mode(false).map_err(|e| { - warn!("{}", e); - e - })?; + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.toggle_mode(false).map_err(|e| { + warn!("{}", e); + e + })?; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + led = Some(mode.clone()); + } + break; } } if let Some(led) = led { @@ -137,6 +146,7 @@ impl CtrlKbdLedZbus { .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } @@ -145,14 +155,17 @@ impl CtrlKbdLedZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { let mut led = None; - if let Ok(mut ctrl) = self.0.lock() { - ctrl.toggle_mode(true).map_err(|e| { - warn!("{}", e); - e - })?; + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.toggle_mode(true).map_err(|e| { + warn!("{}", e); + e + })?; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + led = Some(mode.clone()); + } + break; } } if let Some(led) = led { @@ -164,21 +177,27 @@ impl CtrlKbdLedZbus { } async fn next_led_brightness(&self) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.next_brightness().map_err(|e| { - warn!("{}", e); - e - })?; + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.next_brightness().map_err(|e| { + warn!("{}", e); + e + })?; + break; + } } Ok(()) } async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.prev_brightness().map_err(|e| { - warn!("{}", e); - e - })?; + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.prev_brightness().map_err(|e| { + warn!("{}", e); + e + })?; + break; + } } Ok(()) } @@ -195,10 +214,11 @@ impl CtrlKbdLedZbus { /// Return the current mode data async fn led_mode(&self) -> AuraModeNum { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.current_mode; + loop { + if let Ok(ctrl) = self.0.try_lock() { + return ctrl.config.current_mode; + } } - AuraModeNum::Static } /// Return a list of available modes @@ -211,8 +231,11 @@ impl CtrlKbdLedZbus { } async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.write_effect_block(&data)?; + loop { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.write_effect_block(&data)?; + break; + } } Ok(()) } @@ -220,11 +243,11 @@ impl CtrlKbdLedZbus { /// Return the current LED brightness #[dbus_interface(property)] async fn led_brightness(&self) -> i8 { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); + loop { + if let Ok(ctrl) = self.0.try_lock() { + return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); + } } - warn!("SetKeyBacklight could not serialise"); - -1 } #[dbus_interface(signal)] From 0c97cf710de13a07c8cbacfdf52d84e967d09b20 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 20 Sep 2022 20:57:39 +1200 Subject: [PATCH 02/11] Trial single inotify test --- CHANGELOG.md | 4 ++- Cargo.lock | 1 + daemon/Cargo.toml | 2 ++ daemon/src/ctrl_anime/mod.rs | 7 +++- daemon/src/ctrl_aura/controller.rs | 7 +++- daemon/src/ctrl_platform.rs | 6 +++- daemon/src/ctrl_power.rs | 6 +++- daemon/src/ctrl_profiles/controller.rs | 34 +----------------- daemon/src/ctrl_profiles/zbus.rs | 49 ++++++++++++++++++++++++++ daemon/src/daemon.rs | 21 ++++++----- daemon/src/lib.rs | 37 +++++++++++++++++-- 11 files changed, 126 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 629f9f47..8224a9c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased ] +## [Unreleased - 4.4.1] +### Changed +- Use loops to ensure that mutex is gained for LED changes. ## [v4.4.0] - 2022-08-29 ### Added diff --git a/Cargo.lock b/Cargo.lock index 3fb39f30..82668193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -576,6 +576,7 @@ version = "4.4.0" dependencies = [ "async-trait", "env_logger", + "inotify", "log", "logind-zbus", "rog_anime", diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index c0c10929..135c8f46 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -43,3 +43,5 @@ toml = "^0.5.8" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID + +inotify = "0.10.0" diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 01291047..c734b8f9 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -1,6 +1,7 @@ pub mod config; pub mod zbus; +use ::zbus::SignalContext; use async_trait::async_trait; use log::{error, info, warn}; use rog_anime::{ @@ -229,7 +230,11 @@ impl CtrlAnimeTask { #[async_trait] impl crate::CtrlTask for CtrlAnimeTask { - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + _: SignalContext<'a>, + ) -> Result<(), RogError> { let run_action = |start: bool, lock: MutexGuard, inner: Arc>| { if start { diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index b7f09336..2545e2ae 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -16,6 +16,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use std::sync::Mutex; use std::sync::MutexGuard; +use zbus::SignalContext; use crate::GetSupported; @@ -94,7 +95,11 @@ impl CtrlKbdLedTask { #[async_trait] impl CtrlTask for CtrlKbdLedTask { - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + _: SignalContext<'a>, + ) -> Result<(), RogError> { let load_save = |start: bool, mut lock: MutexGuard| { // If waking up if !start { diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index fa3e251d..117d91fe 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -259,7 +259,11 @@ impl crate::Reloadable for CtrlRogBios { #[async_trait] impl CtrlTask for CtrlRogBios { - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + _: SignalContext<'a>, + ) -> Result<(), RogError> { let platform1 = self.clone(); let platform2 = self.clone(); self.create_sys_event_tasks( diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 6f01fd30..5100bbdc 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -108,7 +108,11 @@ impl CtrlPower { #[async_trait] impl CtrlTask for CtrlPower { - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + _: SignalContext<'a>, + ) -> Result<(), RogError> { let power1 = self.clone(); let power2 = self.clone(); self.create_sys_event_tasks( diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index 80b9a60d..4666bbfe 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,12 +1,9 @@ use crate::error::RogError; -use crate::{CtrlTask, GetSupported}; -use async_trait::async_trait; +use crate::GetSupported; use log::{info, warn}; use rog_platform::supported::PlatformProfileFunctions; use rog_profiles::error::ProfileError; use rog_profiles::{FanCurveProfiles, Profile}; -use smol::Executor; -use std::sync::{Arc, Mutex}; use super::config::ProfileConfig; @@ -129,32 +126,3 @@ impl CtrlPlatformProfile { Ok(()) } } - -pub struct CtrlProfileTask { - ctrl: Arc>, -} - -impl CtrlProfileTask { - pub fn new(ctrl: Arc>) -> Self { - Self { ctrl } - } -} - -#[async_trait] -impl CtrlTask for CtrlProfileTask { - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - let ctrl = self.ctrl.clone(); - self.repeating_task(666, executor, move || { - if let Ok(ref mut lock) = ctrl.try_lock() { - let new_profile = Profile::get_active_profile().unwrap(); - if new_profile != lock.config.active_profile { - lock.config.active_profile = new_profile; - lock.write_profile_curve_to_platform().unwrap(); - lock.save_config(); - } - } - }) - .await; - Ok(()) - } -} diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 91fdcd08..36ca471e 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -1,8 +1,12 @@ use async_trait::async_trait; +use inotify::Inotify; +use inotify::WatchMask; use log::warn; use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::Profile; +use rog_profiles::PLATFORM_PROFILE; +use smol::Executor; use zbus::Connection; use zbus::SignalContext; @@ -10,6 +14,9 @@ use std::sync::Arc; use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; +use crate::error::RogError; +use crate::CtrlTask; + use super::controller::CtrlPlatformProfile; static UNSUPPORTED_MSG: &str = @@ -209,3 +216,45 @@ impl crate::ZbusAdd for ProfileZbus { Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await; } } + +#[async_trait] +impl CtrlTask for ProfileZbus { + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + signal: SignalContext<'a>, + ) -> Result<(), RogError> { + let ctrl = self.inner.clone(); + let mut inotify = Inotify::init()?; + inotify.add_watch(PLATFORM_PROFILE, WatchMask::MODIFY)?; + + executor + .spawn(async move { + let mut buffer = [0; 1024]; + loop { + if let Ok(events) = inotify.read_events_blocking(&mut buffer) { + for _ in events { + let mut active_profile = None; + + if let Ok(ref mut lock) = ctrl.try_lock() { + let new_profile = Profile::get_active_profile().unwrap(); + if new_profile != lock.config.active_profile { + lock.config.active_profile = new_profile; + lock.write_profile_curve_to_platform().unwrap(); + lock.save_config(); + active_profile = Some(lock.config.active_profile); + } + } + + if let Some(active_profile) = active_profile { + Self::notify_profile(&signal, active_profile).await.ok(); + } + } + } + } + }) + .detach(); + + Ok(()) + } +} diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index d0a39896..2bb39275 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -3,8 +3,7 @@ use std::error::Error; use std::io::Write; use std::sync::{Arc, Mutex}; -use ::zbus::Connection; -use daemon::ctrl_profiles::controller::CtrlProfileTask; +use ::zbus::{Connection, SignalContext}; use log::LevelFilter; use log::{error, info, warn}; use smol::Executor; @@ -90,7 +89,8 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> ctrl.add_to_server(&mut connection).await; let task = CtrlRogBios::new(config.clone())?; - task.create_tasks(executor).await.ok(); + let sig = SignalContext::new(&connection, "/org/asuslinux/Platform")?; + task.create_tasks(executor, sig).await.ok(); } Err(err) => { error!("rog_bios_control: {}", err); @@ -106,7 +106,8 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> ctrl.add_to_server(&mut connection).await; let task = CtrlPower::new(config)?; - task.create_tasks(executor).await.ok(); + let sig = SignalContext::new(&connection, "/org/asuslinux/Charge")?; + task.create_tasks(executor, sig).await.ok(); } Err(err) => { error!("charge_control: {}", err); @@ -121,10 +122,12 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> .unwrap_or_else(|err| warn!("Profile control: {}", err)); let tmp = Arc::new(Mutex::new(ctrl)); - let task = CtrlProfileTask::new(tmp.clone()); - task.create_tasks(executor).await.ok(); + //let task = CtrlProfileTask::new(tmp.clone()); + //task.create_tasks(executor).await.ok(); + let sig = SignalContext::new(&connection, "/org/asuslinux/Profile")?; let task = ProfileZbus::new(tmp.clone()); + task.create_tasks(executor, sig).await.ok(); task.add_to_server(&mut connection).await; } Err(err) => { @@ -148,7 +151,8 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> zbus.add_to_server(&mut connection).await; let task = CtrlAnimeTask::new(inner).await; - task.create_tasks(executor).await.ok(); + let sig = SignalContext::new(&connection, "/org/asuslinux/Anime")?; + task.create_tasks(executor, sig).await.ok(); } Err(err) => { error!("AniMe control: {}", err); @@ -171,7 +175,8 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> .await; let task = CtrlKbdLedTask::new(inner); - task.create_tasks(executor).await.ok(); + let sig = SignalContext::new(&connection, "/org/asuslinux/Aura")?; + task.create_tasks(executor, sig).await.ok(); } Err(err) => { error!("Keyboard control: {}", err); diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 1009f8be..87f1b14c 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -24,10 +24,11 @@ use std::time::Duration; use crate::error::RogError; use async_trait::async_trait; use config::Config; +use inotify::{Inotify, WatchMask}; use log::warn; use logind_zbus::manager::ManagerProxy; use smol::{stream::StreamExt, Executor, Timer}; -use zbus::Connection; +use zbus::{Connection, SignalContext}; use zvariant::ObjectPath; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -62,7 +63,39 @@ pub trait ZbusAdd { pub trait CtrlTask { /// Implement to set up various tasks that may be required, using the `Executor`. /// No blocking loops are allowed, or they must be run on a separate thread. - async fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError>; + async fn create_tasks<'a>( + &self, + executor: &mut Executor<'a>, + signal: SignalContext<'a>, + ) -> Result<(), RogError>; + + /// Free method to run a task when the path is modified + /// + /// Not very useful if you need to also do a zbus notification. + fn create_tasks_inotify( + &self, + executor: &mut Executor, + path: &str, + mut task: impl FnMut() + Send + 'static, + ) -> Result<(), RogError> { + let mut inotify = Inotify::init()?; + inotify.add_watch(path, WatchMask::MODIFY)?; + let mut buffer = [0; 1024]; + + executor + .spawn(async move { + loop { + if let Ok(events) = inotify.read_events_blocking(&mut buffer) { + for _ in events { + task() + } + } + } + }) + .detach(); + + Ok(()) + } /// Create a timed repeating task async fn repeating_task( From a44a1bfa891945cdab0cefa222a5cc95c8b3270d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 20 Sep 2022 21:02:58 +1200 Subject: [PATCH 03/11] Add GU603Z to ledmodes --- data/asusd-ledmodes.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/asusd-ledmodes.toml b/data/asusd-ledmodes.toml index 46c4de80..8e625a62 100644 --- a/data/asusd-ledmodes.toml +++ b/data/asusd-ledmodes.toml @@ -49,7 +49,7 @@ per_key = false [[led_data]] prod_family = "ROG Zephyrus M16" -board_names = ["GU603HR", "GU603HE", "GU603HM"] +board_names = ["GU603Z", "GU603H"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] multizone = [] per_key = false From 56285916cd79bb93a47cacb76b24b92e76fc4a7f Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 21 Sep 2022 19:04:28 +1200 Subject: [PATCH 04/11] daemon: inotify for panel_od and gu_mux_mode --- Cargo.lock | 1 + daemon/Cargo.toml | 1 + daemon/src/ctrl_platform.rs | 67 +++++++++++++++++++++++++++----- daemon/src/ctrl_profiles/zbus.rs | 6 ++- rog-control-center/src/notify.rs | 2 +- rog-dbus/src/zbus_platform.rs | 2 +- rog-platform/src/macros.rs | 1 + rog-platform/src/platform.rs | 8 +++- 8 files changed, 73 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82668193..c43a1218 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,6 +575,7 @@ name = "daemon" version = "4.4.0" dependencies = [ "async-trait", + "concat-idents", "env_logger", "inotify", "log", diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 135c8f46..7e94e8c0 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -45,3 +45,4 @@ toml = "^0.5.8" sysfs-class = "^0.1.2" # used for backlight control and baord ID inotify = "0.10.0" +concat-idents = "1.1.3" \ No newline at end of file diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 117d91fe..81565e44 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -154,7 +154,7 @@ impl CtrlRogBios { Self::notify_gpu_mux_mode(&ctxt, mode).await.ok(); } - fn gpu_mux_mode(&self) -> GpuMode { + fn get_gpu_mux_mode(&self) -> GpuMode { match self.platform.get_gpu_mux_mode() { Ok(m) => GpuMode::from_mux(m), Err(e) => { @@ -203,6 +203,7 @@ impl CtrlRogBios { overdrive: bool, ) { if self + .platform .set_panel_od(overdrive) .map_err(|err| { warn!("CtrlRogBios: set_panel_overdrive {}", err); @@ -214,25 +215,29 @@ impl CtrlRogBios { lock.panel_od = overdrive; lock.write(); } - Self::notify_panel_overdrive(&ctxt, overdrive).await.ok(); + Self::notify_panel_od(&ctxt, overdrive).await.ok(); } } - fn panel_overdrive(&self) -> bool { - self.platform + /// Get the `panel_od` value from platform. Updates the stored value in internal config also. + fn get_panel_od(&self) -> bool { + let od = self + .platform .get_panel_od() .map_err(|err| { warn!("CtrlRogBios: get panel overdrive {}", err); err }) - .unwrap_or(false) + .unwrap_or(false); + if let Ok(mut lock) = self.config.try_lock() { + lock.panel_od = od; + lock.write(); + } + od } #[dbus_interface(signal)] - async fn notify_panel_overdrive( - signal_ctxt: &SignalContext<'_>, - overdrive: bool, - ) -> zbus::Result<()> { + async fn notify_panel_od(signal_ctxt: &SignalContext<'_>, overdrive: bool) -> zbus::Result<()> { } } @@ -257,12 +262,50 @@ impl crate::Reloadable for CtrlRogBios { } } +macro_rules! watch_item { + ($name:ident) => { + concat_idents::concat_idents!(fn_name = watch_, $name { + async fn fn_name<'a>( + &self, + executor: &mut Executor<'a>, + signal_ctxt: SignalContext<'a>, + ) -> Result<(), RogError> { + let ctrl = self.clone(); + concat_idents::concat_idents!(watch_fn = monitor_, $name { + let mut watch = self.platform.watch_fn()?; + executor + .spawn(async move { + let mut buffer = [0; 1024]; + loop { + if let Ok(events) = watch.read_events_blocking(&mut buffer) { + for _ in events { + let value = concat_idents::concat_idents!(get_fn = get_, $name { ctrl.get_fn() }); + concat_idents::concat_idents!(notif_fn = notify_, $name { + Self::notif_fn(&signal_ctxt, value).await.unwrap(); + }); + } + } + } + }) + .detach(); + }); + Ok(()) + } + }); + }; +} + +impl CtrlRogBios { + watch_item!(panel_od); + watch_item!(gpu_mux_mode); +} + #[async_trait] impl CtrlTask for CtrlRogBios { async fn create_tasks<'a>( &self, executor: &mut Executor<'a>, - _: SignalContext<'a>, + signal_ctxt: SignalContext<'a>, ) -> Result<(), RogError> { let platform1 = self.clone(); let platform2 = self.clone(); @@ -301,6 +344,10 @@ impl CtrlTask for CtrlRogBios { ) .await; + self.watch_panel_od(executor, signal_ctxt.clone()).await?; + self.watch_gpu_mux_mode(executor, signal_ctxt.clone()) + .await?; + Ok(()) } } diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 36ca471e..389e8b3d 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -222,7 +222,7 @@ impl CtrlTask for ProfileZbus { async fn create_tasks<'a>( &self, executor: &mut Executor<'a>, - signal: SignalContext<'a>, + signal_ctxt: SignalContext<'a>, ) -> Result<(), RogError> { let ctrl = self.inner.clone(); let mut inotify = Inotify::init()?; @@ -247,7 +247,9 @@ impl CtrlTask for ProfileZbus { } if let Some(active_profile) = active_profile { - Self::notify_profile(&signal, active_profile).await.ok(); + Self::notify_profile(&signal_ctxt, active_profile) + .await + .ok(); } } } diff --git a/rog-control-center/src/notify.rs b/rog-control-center/src/notify.rs index 2012ba96..8a106217 100644 --- a/rog-control-center/src/notify.rs +++ b/rog-control-center/src/notify.rs @@ -86,7 +86,7 @@ pub fn start_notifications( .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_overdrive().await { + if let Ok(p) = proxy.receive_notify_panel_od().await { p.for_each(|_| { bios_notified.store(true, Ordering::SeqCst); future::ready(()) diff --git a/rog-dbus/src/zbus_platform.rs b/rog-dbus/src/zbus_platform.rs index 9009dc65..d8452b94 100644 --- a/rog-dbus/src/zbus_platform.rs +++ b/rog-dbus/src/zbus_platform.rs @@ -55,5 +55,5 @@ trait RogBios { /// NotifyPanelOverdrive signal #[dbus_proxy(signal)] - fn notify_panel_overdrive(&self, overdrive: bool) -> zbus::Result<()>; + fn notify_panel_od(&self, overdrive: bool) -> zbus::Result<()>; } diff --git a/rog-platform/src/macros.rs b/rog-platform/src/macros.rs index 244fdb94..e9bf431a 100644 --- a/rog-platform/src/macros.rs +++ b/rog-platform/src/macros.rs @@ -127,5 +127,6 @@ macro_rules! attr_u8_array { 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); }; } diff --git a/rog-platform/src/platform.rs b/rog-platform/src/platform.rs index 46aee4bd..580ac83b 100644 --- a/rog-platform/src/platform.rs +++ b/rog-platform/src/platform.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{path::PathBuf, str::FromStr}; use log::{info, warn}; use serde::{Deserialize, Serialize}; @@ -20,6 +20,7 @@ use crate::{ #[derive(Debug, PartialEq, PartialOrd, Clone)] pub struct AsusPlatform { path: PathBuf, + pp_path: PathBuf, } impl AsusPlatform { @@ -44,6 +45,7 @@ impl AsusPlatform { info!("Found platform support at {:?}", device.sysname()); return Ok(Self { path: device.syspath().to_owned(), + pp_path: PathBuf::from_str("/sys/firmware/acpi").unwrap(), }); } Err(PlatformError::MissingFunction( @@ -55,6 +57,10 @@ impl AsusPlatform { attr_bool!("egpu_enable", path); attr_bool!("panel_od", path); attr_u8!("gpu_mux_mode", path); + 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)] From 5d87747d96666d118eb5a2e782c4960f36b36370 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 21 Sep 2022 22:17:55 +1200 Subject: [PATCH 05/11] Is smol blocking or inotify blocking it? --- CHANGELOG.md | 12 +++++ asus-notify/src/main.rs | 2 +- asusctl/src/main.rs | 6 +-- daemon/src/ctrl_aura/controller.rs | 21 ++++++++- daemon/src/ctrl_platform.rs | 48 +++----------------- daemon/src/ctrl_power.rs | 41 +++++++++++++---- daemon/src/lib.rs | 52 ++++++++++++++++++++++ rog-control-center/src/notify.rs | 2 +- rog-control-center/src/page_states.rs | 8 ++-- rog-control-center/src/widgets/rog_bios.rs | 4 +- rog-dbus/src/zbus_charge.rs | 10 ++--- rog-dbus/src/zbus_platform.rs | 4 +- rog-platform/src/macros.rs | 1 + 13 files changed, 142 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8224a9c9..46a9775d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased - 4.4.1] +### Added +- intofy watches on: + - `charge_control_end_threshold` + - `panel_od` + - `gpu_mux_mode` + - `platform_profile` + - These allow for updating any associated config and sending dbus notifications. ### Changed - Use loops to ensure that mutex is gained for LED changes. +### Breaking +- DBUS: all charge control methods renamed: + - `ChargeControlEndThreshold` + - `SetChargeControlEndThreshold` + - `NotifyChargeControlEndThreshold` ## [v4.4.0] - 2022-08-29 ### Added diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index 7c02c917..95654357 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -70,7 +70,7 @@ fn main() -> Result<(), Box> { .spawn(async move { let conn = zbus::Connection::system().await.unwrap(); let proxy = ChargeProxy::new(&conn).await.unwrap(); - if let Ok(p) = proxy.receive_notify_charge().await { + 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() { diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index dc8881bf..fea79752 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -211,7 +211,7 @@ fn do_parsed( } if let Some(chg_limit) = parsed.chg_limit { - dbus.proxies().charge().set_limit(chg_limit)?; + dbus.proxies().charge().set_charge_control_end_threshold(chg_limit)?; } Ok(()) @@ -803,10 +803,10 @@ fn handle_bios_option( } if let Some(opt) = cmd.panel_overdrive_set { - dbus.proxies().rog_bios().set_panel_overdrive(opt)?; + dbus.proxies().rog_bios().set_panel_od(opt)?; } if cmd.panel_overdrive_get { - let res = dbus.proxies().rog_bios().panel_overdrive()?; + let res = dbus.proxies().rog_bios().panel_od()?; println!("Panel overdrive on: {}", res); } } diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index 2545e2ae..c1a82c8b 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -140,7 +140,7 @@ impl CtrlTask for CtrlKbdLedTask { }, move || loop { if let Ok(lock) = inner3.clone().try_lock() { - load_save(false, lock); + load_save(true, lock); break; } }, @@ -153,6 +153,25 @@ impl CtrlTask for CtrlKbdLedTask { ) .await; + let ctrl2 = self.inner.clone(); + if let Ok(ctrl) = self.inner.lock() { + let mut watch = ctrl.kd_brightness.monitor_brightness()?; + executor + .spawn(async move { + let mut buffer = [0; 1024]; + loop { + if let Ok(events) = watch.read_events_blocking(&mut buffer) { + for _ in events { + if let Ok(lock) = ctrl2.try_lock() { + load_save(true, lock); + } + } + } + } + }) + .detach(); + } + Ok(()) } } diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 81565e44..71e63c56 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -1,4 +1,4 @@ -use crate::CtrlTask; +use crate::{CtrlTask, task_watch_item}; use crate::{config::Config, error::RogError, GetSupported}; use async_trait::async_trait; use log::{info, warn}; @@ -154,7 +154,7 @@ impl CtrlRogBios { Self::notify_gpu_mux_mode(&ctxt, mode).await.ok(); } - fn get_gpu_mux_mode(&self) -> GpuMode { + fn gpu_mux_mode(&self) -> GpuMode { match self.platform.get_gpu_mux_mode() { Ok(m) => GpuMode::from_mux(m), Err(e) => { @@ -220,7 +220,7 @@ impl CtrlRogBios { } /// Get the `panel_od` value from platform. Updates the stored value in internal config also. - fn get_panel_od(&self) -> bool { + fn panel_od(&self) -> bool { let od = self .platform .get_panel_od() @@ -262,42 +262,9 @@ impl crate::Reloadable for CtrlRogBios { } } -macro_rules! watch_item { - ($name:ident) => { - concat_idents::concat_idents!(fn_name = watch_, $name { - async fn fn_name<'a>( - &self, - executor: &mut Executor<'a>, - signal_ctxt: SignalContext<'a>, - ) -> Result<(), RogError> { - let ctrl = self.clone(); - concat_idents::concat_idents!(watch_fn = monitor_, $name { - let mut watch = self.platform.watch_fn()?; - executor - .spawn(async move { - let mut buffer = [0; 1024]; - loop { - if let Ok(events) = watch.read_events_blocking(&mut buffer) { - for _ in events { - let value = concat_idents::concat_idents!(get_fn = get_, $name { ctrl.get_fn() }); - concat_idents::concat_idents!(notif_fn = notify_, $name { - Self::notif_fn(&signal_ctxt, value).await.unwrap(); - }); - } - } - } - }) - .detach(); - }); - Ok(()) - } - }); - }; -} - impl CtrlRogBios { - watch_item!(panel_od); - watch_item!(gpu_mux_mode); + task_watch_item!(panel_od platform); + task_watch_item!(gpu_mux_mode platform); } #[async_trait] @@ -344,9 +311,8 @@ impl CtrlTask for CtrlRogBios { ) .await; - self.watch_panel_od(executor, signal_ctxt.clone()).await?; - self.watch_gpu_mux_mode(executor, signal_ctxt.clone()) - .await?; + self.watch_panel_od(executor, signal_ctxt.clone())?; + self.watch_gpu_mux_mode(executor, signal_ctxt.clone())?; Ok(()) } diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 5100bbdc..814f04ee 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -1,5 +1,5 @@ -use crate::CtrlTask; use crate::{config::Config, error::RogError, GetSupported}; +use crate::{task_watch_item, CtrlTask}; use async_trait::async_trait; use log::{info, warn}; use rog_platform::power::AsusPower; @@ -33,7 +33,7 @@ pub struct CtrlPower { #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlPower { - async fn set_limit( + async fn set_charge_control_end_threshold( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, limit: u8, @@ -47,19 +47,38 @@ impl CtrlPower { err }) .ok(); - Self::notify_charge(&ctxt, limit).await?; + Self::notify_charge_control_end_threshold(&ctxt, limit).await?; Ok(()) } - fn limit(&self) -> i8 { - if let Ok(config) = self.config.try_lock() { - return config.bat_charge_limit as i8; + fn charge_control_end_threshold(&self) -> u8 { + loop { + if let Ok(config) = self.config.try_lock() { + let limit = self + .power + .get_charge_control_end_threshold() + .map_err(|err| { + warn!("CtrlCharge: get_charge_control_end_threshold {}", err); + err + }) + .unwrap_or(100); + self.set(limit) + .map_err(|err| { + warn!("CtrlCharge: set_limit {}", err); + err + }) + .ok(); + + return config.bat_charge_limit; + } } - -1 } #[dbus_interface(signal)] - async fn notify_charge(ctxt: &SignalContext<'_>, limit: u8) -> zbus::Result<()>; + async fn notify_charge_control_end_threshold( + ctxt: &SignalContext<'_>, + limit: u8, + ) -> zbus::Result<()>; } #[async_trait] @@ -104,6 +123,8 @@ impl CtrlPower { Ok(()) } + + task_watch_item!(charge_control_end_threshold power); } #[async_trait] @@ -111,7 +132,7 @@ impl CtrlTask for CtrlPower { async fn create_tasks<'a>( &self, executor: &mut Executor<'a>, - _: SignalContext<'a>, + signal_ctxt: SignalContext<'a>, ) -> Result<(), RogError> { let power1 = self.clone(); let power2 = self.clone(); @@ -146,6 +167,8 @@ impl CtrlTask for CtrlPower { ) .await; + self.watch_charge_control_end_threshold(executor, signal_ctxt)?; + Ok(()) } } diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 87f1b14c..c59747c2 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -58,6 +58,58 @@ pub trait ZbusAdd { } } +/// This macro adds a function which spawns an `inotify` task on the passed in `Executor`. +/// +/// The generated function is `watch_()`. Self requires the following methods to be available: +/// - `() -> SomeValue`, functionally is a getter, but is allowed to have side effects. +/// - `notify_(SignalContext, SomeValue)` +/// +/// In most cases if `SomeValue` is stored in a config then `()` getter is expected to update it. +/// +/// # Example +/// +/// ```ignore +/// impl CtrlRogBios { +/// task_watch_item!(panel_od platform); +/// task_watch_item!(gpu_mux_mode platform); +/// } +/// ``` +#[macro_export] +macro_rules! task_watch_item { + ($name:ident $self_inner:ident) => { + concat_idents::concat_idents!(fn_name = watch_, $name { + fn fn_name<'a>( + &self, + executor: &mut Executor<'a>, + signal_ctxt: SignalContext<'a>, + ) -> Result<(), RogError> { + let ctrl = self.clone(); + concat_idents::concat_idents!(watch_fn = monitor_, $name { + let mut watch = self.$self_inner.watch_fn()?; + executor + .spawn(async move { + let mut buffer = [0; 1024]; + loop { + if let Ok(events) = watch.read_events_blocking(&mut buffer) { + for _ in events { + let value = ctrl.$name(); + dbg!(value); + concat_idents::concat_idents!(notif_fn = notify_, $name { + Self::notif_fn(&signal_ctxt, value).await.unwrap(); + }); + } + } + } + }) + .detach(); + dbg!("SPWADEWFWEFE"); + }); + Ok(()) + } + }); + }; +} + /// Set up a task to run on the async executor #[async_trait] pub trait CtrlTask { diff --git a/rog-control-center/src/notify.rs b/rog-control-center/src/notify.rs index 8a106217..80092770 100644 --- a/rog-control-center/src/notify.rs +++ b/rog-control-center/src/notify.rs @@ -103,7 +103,7 @@ pub fn start_notifications( .spawn(async move { let conn = zbus::Connection::system().await.unwrap(); let proxy = ChargeProxy::new(&conn).await.unwrap(); - if let Ok(p) = proxy.receive_notify_charge().await { + 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) { diff --git a/rog-control-center/src/page_states.rs b/rog-control-center/src/page_states.rs index 2148f52e..82d19706 100644 --- a/rog-control-center/src/page_states.rs +++ b/rog-control-center/src/page_states.rs @@ -45,7 +45,7 @@ impl BiosState { GpuMode::NotSupported }, panel_overdrive: if supported.rog_bios_ctrl.panel_overdrive { - dbus.proxies().rog_bios().panel_overdrive()? + dbus.proxies().rog_bios().panel_od()? } else { false }, @@ -258,7 +258,7 @@ pub struct PageDataStates { pub anime: AnimeState, pub profiles: ProfilesState, pub fan_curves: FanCurvesState, - pub charge_limit: i16, + pub charge_limit: u8, pub error: Option, } @@ -279,7 +279,7 @@ impl PageDataStates { keyboard_layout, notifs_enabled, was_notified: charge_notified, - charge_limit: dbus.proxies().charge().limit()?, + charge_limit: dbus.proxies().charge().charge_control_end_threshold()?, bios: BiosState::new(bios_notified, supported, dbus)?, aura: AuraState::new(aura_notified, supported, dbus)?, anime: AnimeState::new(anime_notified, supported, dbus)?, @@ -296,7 +296,7 @@ impl PageDataStates { ) -> Result { let mut notified = false; if self.was_notified.load(Ordering::SeqCst) { - self.charge_limit = dbus.proxies().charge().limit()?; + self.charge_limit = dbus.proxies().charge().charge_control_end_threshold()?; self.was_notified.store(false, Ordering::SeqCst); notified = true; } diff --git a/rog-control-center/src/widgets/rog_bios.rs b/rog-control-center/src/widgets/rog_bios.rs index 82cc0398..7754c065 100644 --- a/rog-control-center/src/widgets/rog_bios.rs +++ b/rog-control-center/src/widgets/rog_bios.rs @@ -47,7 +47,7 @@ pub fn rog_bios_group( if ui.add(slider).drag_released() { dbus.proxies() .charge() - .set_limit(states.charge_limit as u8) + .set_charge_control_end_threshold(states.charge_limit as u8) .map_err(|err| { states.error = Some(err.to_string()); }) @@ -82,7 +82,7 @@ pub fn rog_bios_group( { dbus.proxies() .rog_bios() - .set_panel_overdrive(states.bios.panel_overdrive) + .set_panel_od(states.bios.panel_overdrive) .map_err(|err| { states.error = Some(err.to_string()); }) diff --git a/rog-dbus/src/zbus_charge.rs b/rog-dbus/src/zbus_charge.rs index eba1c1d2..ca93550b 100644 --- a/rog-dbus/src/zbus_charge.rs +++ b/rog-dbus/src/zbus_charge.rs @@ -26,13 +26,13 @@ use zbus_macros::dbus_proxy; default_path = "/org/asuslinux/Charge" )] trait Charge { - /// Limit method - fn limit(&self) -> zbus::Result; + /// charge_control_end_threshold method + fn charge_control_end_threshold(&self) -> zbus::Result; - /// SetLimit method - fn set_limit(&self, limit: u8) -> zbus::Result<()>; + /// set_charge_control_end_threshold method + fn set_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<()>; /// NotifyCharge signal #[dbus_proxy(signal)] - fn notify_charge(&self, limit: u8) -> zbus::Result; + fn notify_charge_control_end_threshold(&self, limit: u8) -> zbus::Result; } diff --git a/rog-dbus/src/zbus_platform.rs b/rog-dbus/src/zbus_platform.rs index d8452b94..404f3f37 100644 --- a/rog-dbus/src/zbus_platform.rs +++ b/rog-dbus/src/zbus_platform.rs @@ -40,10 +40,10 @@ trait RogBios { fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>; /// PanelOverdrive method - fn panel_overdrive(&self) -> zbus::Result; + fn panel_od(&self) -> zbus::Result; /// SetPanelOverdrive method - fn set_panel_overdrive(&self, overdrive: bool) -> zbus::Result<()>; + fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>; /// NotifyDedicatedGraphicMode signal #[dbus_proxy(signal)] diff --git a/rog-platform/src/macros.rs b/rog-platform/src/macros.rs index e9bf431a..3c58b2e5 100644 --- a/rog-platform/src/macros.rs +++ b/rog-platform/src/macros.rs @@ -21,6 +21,7 @@ macro_rules! watch_attr { pub fn fn_name(&self) -> Result { let mut path = self.$item.clone(); path.push($attr_name); + dbg!(&path); let mut inotify = inotify::Inotify::init().unwrap(); inotify.add_watch(path.to_str().unwrap(), inotify::WatchMask::MODIFY).unwrap(); Ok(inotify) From 283cb7e589447dc6303ece65dc166e53d6816ca7 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 21 Sep 2022 22:41:24 +1200 Subject: [PATCH 06/11] Previous inotify macro was blocking. Needs async closures... --- daemon/src/lib.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index c59747c2..c0b98700 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -83,23 +83,22 @@ macro_rules! task_watch_item { executor: &mut Executor<'a>, signal_ctxt: SignalContext<'a>, ) -> Result<(), RogError> { + use zbus::export::futures_util::StreamExt; + let ctrl = self.clone(); concat_idents::concat_idents!(watch_fn = monitor_, $name { let mut watch = self.$self_inner.watch_fn()?; executor .spawn(async move { let mut buffer = [0; 1024]; - loop { - if let Ok(events) = watch.read_events_blocking(&mut buffer) { - for _ in events { - let value = ctrl.$name(); - dbg!(value); - concat_idents::concat_idents!(notif_fn = notify_, $name { - Self::notif_fn(&signal_ctxt, value).await.unwrap(); - }); - } - } - } + watch.event_stream(&mut buffer).unwrap().for_each(|e|{ + let value = ctrl.$name(); + dbg!(value); + concat_idents::concat_idents!(notif_fn = notify_, $name { + Self::notif_fn(&signal_ctxt, value).await.unwrap(); + }); + smol::future::ready(()) + }).await; }) .detach(); dbg!("SPWADEWFWEFE"); From 3b9cf474a79ba49ec5296908680d8b0184387f51 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 22 Sep 2022 12:55:15 +1200 Subject: [PATCH 07/11] inotify relies on tokio, so a switch is required.. --- Cargo.lock | 4 ++-- asusctl/src/main.rs | 4 +++- daemon/Cargo.toml | 2 +- daemon/src/ctrl_platform.rs | 7 ++++--- daemon/src/ctrl_power.rs | 3 ++- daemon/src/lib.rs | 6 ++---- rog-platform/Cargo.toml | 1 + 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c43a1218..4a19b7cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2530,9 +2530,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95" dependencies = [ "autocfg", "libc", diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index fea79752..c3e127b2 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -211,7 +211,9 @@ fn do_parsed( } if let Some(chg_limit) = parsed.chg_limit { - dbus.proxies().charge().set_charge_control_end_threshold(chg_limit)?; + dbus.proxies() + .charge() + .set_charge_control_end_threshold(chg_limit)?; } Ok(()) diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 7e94e8c0..983411c6 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -44,5 +44,5 @@ toml = "^0.5.8" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID -inotify = "0.10.0" +inotify = { version = "0.10.0", default-features = false } concat-idents = "1.1.3" \ No newline at end of file diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 71e63c56..444c3550 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -1,5 +1,5 @@ -use crate::{CtrlTask, task_watch_item}; use crate::{config::Config, error::RogError, GetSupported}; +use crate::{task_watch_item, CtrlTask}; use async_trait::async_trait; use log::{info, warn}; use rog_platform::platform::{AsusPlatform, GpuMode}; @@ -311,8 +311,9 @@ impl CtrlTask for CtrlRogBios { ) .await; - self.watch_panel_od(executor, signal_ctxt.clone())?; - self.watch_gpu_mux_mode(executor, signal_ctxt.clone())?; + self.watch_panel_od(executor, signal_ctxt.clone()).await?; + self.watch_gpu_mux_mode(executor, signal_ctxt.clone()) + .await?; Ok(()) } diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 814f04ee..19f6dace 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -167,7 +167,8 @@ impl CtrlTask for CtrlPower { ) .await; - self.watch_charge_control_end_threshold(executor, signal_ctxt)?; + self.watch_charge_control_end_threshold(executor, signal_ctxt) + .await?; Ok(()) } diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index c0b98700..de0001dd 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -78,7 +78,7 @@ pub trait ZbusAdd { macro_rules! task_watch_item { ($name:ident $self_inner:ident) => { concat_idents::concat_idents!(fn_name = watch_, $name { - fn fn_name<'a>( + async fn fn_name<'a>( &self, executor: &mut Executor<'a>, signal_ctxt: SignalContext<'a>, @@ -91,17 +91,15 @@ macro_rules! task_watch_item { executor .spawn(async move { let mut buffer = [0; 1024]; - watch.event_stream(&mut buffer).unwrap().for_each(|e|{ + 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(); }); - smol::future::ready(()) }).await; }) .detach(); - dbg!("SPWADEWFWEFE"); }); Ok(()) } diff --git a/rog-platform/Cargo.toml b/rog-platform/Cargo.toml index 2d9be5b5..4eb73f07 100644 --- a/rog-platform/Cargo.toml +++ b/rog-platform/Cargo.toml @@ -18,5 +18,6 @@ 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" \ No newline at end of file From 9608d190b9fc49534c4cbd145ccd4dcd7149186e Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 22 Sep 2022 22:36:16 +1200 Subject: [PATCH 08/11] Use tokio in asusctl --- CHANGELOG.md | 4 +- Cargo.lock | 26 +++- daemon/Cargo.toml | 2 +- daemon/src/ctrl_anime/mod.rs | 8 +- daemon/src/ctrl_aura/config.rs | 4 +- daemon/src/ctrl_aura/controller.rs | 34 ++---- daemon/src/ctrl_platform.rs | 23 ++-- daemon/src/ctrl_power.rs | 22 ++-- daemon/src/ctrl_profiles/zbus.rs | 62 +++++----- daemon/src/daemon.rs | 26 ++-- daemon/src/lib.rs | 140 +++++++--------------- rog-control-center/src/main.rs | 1 - rog-control-center/src/startup_error.rs | 2 +- rog-control-center/src/widgets/top_bar.rs | 2 +- rog-platform/src/macros.rs | 1 - 15 files changed, 148 insertions(+), 209 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46a9775d..ecbca84c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased - 4.4.1] +## [Unreleased - 4.5.0] ### Added - intofy watches on: - `charge_control_end_threshold` - `panel_od` - `gpu_mux_mode` - `platform_profile` + - keyboard brightness - These allow for updating any associated config and sending dbus notifications. ### Changed - Use loops to ensure that mutex is gained for LED changes. +- asusctl now uses tokio for async runtime. This helps simplify some code. ### Breaking - DBUS: all charge control methods renamed: - `ChargeControlEndThreshold` diff --git a/Cargo.lock b/Cargo.lock index 4a19b7cd..cb05ba50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,8 +588,8 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "smol", "sysfs-class", + "tokio", "toml", "zbus", "zvariant", @@ -1705,6 +1705,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" version = "0.5.7" @@ -2537,11 +2547,25 @@ dependencies = [ "autocfg", "libc", "mio", + "num_cpus", + "once_cell", "pin-project-lite", "socket2", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.5.9" diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 983411c6..7098e423 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -25,7 +25,7 @@ rog_profiles = { path = "../rog-profiles" } rog_dbus = { path = "../rog-dbus" } async-trait = "^0.1" -smol = "^1.2" +tokio = { version = "^1.21.1", features = ["macros", "rt-multi-thread", "time"]} # cli and logging log = "^0.4" diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index c734b8f9..221ee250 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -13,7 +13,6 @@ use rog_anime::{ ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, }; use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw}; -use smol::Executor; use std::sync::atomic::{AtomicBool, Ordering}; use std::{ convert::TryFrom, @@ -230,11 +229,7 @@ impl CtrlAnimeTask { #[async_trait] impl crate::CtrlTask for CtrlAnimeTask { - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - _: SignalContext<'a>, - ) -> Result<(), RogError> { + async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { let run_action = |start: bool, lock: MutexGuard, inner: Arc>| { if start { @@ -251,7 +246,6 @@ impl crate::CtrlTask for CtrlAnimeTask { let inner3 = self.inner.clone(); let inner4 = self.inner.clone(); self.create_sys_event_tasks( - executor, // Loop is required to try an attempt to get the mutex *without* blocking // other threads - it is possible to end up with deadlocks otherwise. move || loop { diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 428e3cab..50098af8 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -114,7 +114,7 @@ impl From<&AuraPowerConfig> for AuraPowerDev { } #[derive(Deserialize, Serialize)] -#[serde(default)] +// #[serde(default)] pub struct AuraConfig { pub brightness: LedBrightness, pub current_mode: AuraModeNum, @@ -271,7 +271,7 @@ impl AuraConfig { if l == 0 { warn!("File is empty {}", AURA_CONFIG_PATH); } else { - let x: AuraConfig = serde_json::from_str(&buf) + let x = serde_json::from_str(&buf) .unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH)); *self = x; } diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index c1a82c8b..fc4329de 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -11,12 +11,11 @@ use rog_aura::{ }; use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions}; -use smol::Executor; use std::collections::BTreeMap; use std::sync::Arc; use std::sync::Mutex; use std::sync::MutexGuard; -use zbus::SignalContext; +use zbus::{export::futures_util::StreamExt, SignalContext}; use crate::GetSupported; @@ -95,11 +94,7 @@ impl CtrlKbdLedTask { #[async_trait] impl CtrlTask for CtrlKbdLedTask { - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - _: SignalContext<'a>, - ) -> Result<(), RogError> { + async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { let load_save = |start: bool, mut lock: MutexGuard| { // If waking up if !start { @@ -123,7 +118,6 @@ impl CtrlTask for CtrlKbdLedTask { let inner3 = self.inner.clone(); let inner4 = self.inner.clone(); self.create_sys_event_tasks( - executor, // Loop so that we do aquire the lock but also don't block other // threads (prevents potential deadlocks) move || loop { @@ -156,20 +150,18 @@ impl CtrlTask for CtrlKbdLedTask { let ctrl2 = self.inner.clone(); if let Ok(ctrl) = self.inner.lock() { let mut watch = ctrl.kd_brightness.monitor_brightness()?; - executor - .spawn(async move { - let mut buffer = [0; 1024]; - loop { - if let Ok(events) = watch.read_events_blocking(&mut buffer) { - for _ in events { - if let Ok(lock) = ctrl2.try_lock() { - load_save(true, lock); - } - } + tokio::spawn(async move { + let mut buffer = [0; 32]; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + if let Ok(lock) = ctrl2.try_lock() { + load_save(true, lock); } - } - }) - .detach(); + }) + .await; + }); } Ok(()) diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 444c3550..b22b9167 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use log::{info, warn}; use rog_platform::platform::{AsusPlatform, GpuMode}; use rog_platform::supported::RogBiosSupportedFunctions; -use smol::Executor; use std::fs::OpenOptions; use std::io::{Read, Write}; use std::path::Path; @@ -129,7 +128,7 @@ impl CtrlRogBios { Ok(()) } - fn set_panel_od(&self, enable: bool) -> Result<(), RogError> { + fn set_panel_overdrive(&self, enable: bool) -> Result<(), RogError> { self.platform.set_panel_od(enable).map_err(|err| { warn!("CtrlRogBios: set_panel_overdrive {}", err); err @@ -197,7 +196,7 @@ impl CtrlRogBios { #[dbus_interface(signal)] async fn notify_post_boot_sound(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()> {} - async fn set_panel_overdrive( + async fn set_panel_od( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, overdrive: bool, @@ -256,7 +255,7 @@ impl crate::Reloadable for CtrlRogBios { } else { false }; - self.set_panel_od(p)?; + self.set_panel_overdrive(p)?; } Ok(()) } @@ -269,22 +268,17 @@ impl CtrlRogBios { #[async_trait] impl CtrlTask for CtrlRogBios { - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - signal_ctxt: SignalContext<'a>, - ) -> Result<(), RogError> { + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let platform1 = self.clone(); let platform2 = self.clone(); self.create_sys_event_tasks( - executor, move || {}, move || { info!("CtrlRogBios reloading panel_od"); if let Ok(lock) = platform1.config.try_lock() { if platform1.platform.has_panel_od() { platform1 - .set_panel_od(lock.panel_od) + .set_panel_overdrive(lock.panel_od) .map_err(|err| { warn!("CtrlCharge: set_limit {}", err); err @@ -299,7 +293,7 @@ impl CtrlTask for CtrlRogBios { if let Ok(lock) = platform2.config.try_lock() { if platform2.platform.has_panel_od() { platform2 - .set_panel_od(lock.panel_od) + .set_panel_overdrive(lock.panel_od) .map_err(|err| { warn!("CtrlCharge: set_limit {}", err); err @@ -311,9 +305,8 @@ impl CtrlTask for CtrlRogBios { ) .await; - self.watch_panel_od(executor, signal_ctxt.clone()).await?; - self.watch_gpu_mux_mode(executor, signal_ctxt.clone()) - .await?; + self.watch_panel_od(signal_ctxt.clone()).await?; + self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; Ok(()) } diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 19f6dace..8a008898 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use log::{info, warn}; use rog_platform::power::AsusPower; use rog_platform::supported::ChargeSupportedFunctions; -use smol::Executor; use std::sync::Arc; use std::sync::Mutex; use zbus::dbus_interface; @@ -62,12 +61,11 @@ impl CtrlPower { err }) .unwrap_or(100); - self.set(limit) - .map_err(|err| { - warn!("CtrlCharge: set_limit {}", err); - err - }) - .ok(); + if let Ok(mut config) = self.config.try_lock() { + config.read(); + config.bat_charge_limit = limit; + config.write(); + } return config.bat_charge_limit; } @@ -129,15 +127,10 @@ impl CtrlPower { #[async_trait] impl CtrlTask for CtrlPower { - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - signal_ctxt: SignalContext<'a>, - ) -> Result<(), RogError> { + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let power1 = self.clone(); let power2 = self.clone(); self.create_sys_event_tasks( - executor, move || {}, move || { info!("CtrlCharge reloading charge limit"); @@ -167,8 +160,7 @@ impl CtrlTask for CtrlPower { ) .await; - self.watch_charge_control_end_threshold(executor, signal_ctxt) - .await?; + self.watch_charge_control_end_threshold(signal_ctxt).await?; Ok(()) } diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 389e8b3d..97039b64 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -6,7 +6,7 @@ use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::Profile; use rog_profiles::PLATFORM_PROFILE; -use smol::Executor; +use zbus::export::futures_util::StreamExt; use zbus::Connection; use zbus::SignalContext; @@ -219,43 +219,39 @@ impl crate::ZbusAdd for ProfileZbus { #[async_trait] impl CtrlTask for ProfileZbus { - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - signal_ctxt: SignalContext<'a>, - ) -> Result<(), RogError> { + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let ctrl = self.inner.clone(); - let mut inotify = Inotify::init()?; - inotify.add_watch(PLATFORM_PROFILE, WatchMask::MODIFY)?; + let mut watch = Inotify::init()?; + watch.add_watch(PLATFORM_PROFILE, WatchMask::CLOSE_WRITE)?; - executor - .spawn(async move { - let mut buffer = [0; 1024]; - loop { - if let Ok(events) = inotify.read_events_blocking(&mut buffer) { - for _ in events { - let mut active_profile = None; + tokio::spawn(async move { + let mut buffer = [0; 32]; + loop { + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + let mut active_profile = None; - if let Ok(ref mut lock) = ctrl.try_lock() { - let new_profile = Profile::get_active_profile().unwrap(); - if new_profile != lock.config.active_profile { - lock.config.active_profile = new_profile; - lock.write_profile_curve_to_platform().unwrap(); - lock.save_config(); - active_profile = Some(lock.config.active_profile); - } - } - - if let Some(active_profile) = active_profile { - Self::notify_profile(&signal_ctxt, active_profile) - .await - .ok(); + if let Ok(ref mut lock) = ctrl.try_lock() { + let new_profile = Profile::get_active_profile().unwrap(); + if new_profile != lock.config.active_profile { + lock.config.active_profile = new_profile; + lock.write_profile_curve_to_platform().unwrap(); + lock.save_config(); + active_profile = Some(lock.config.active_profile); } } - } - } - }) - .detach(); + + if let Some(active_profile) = active_profile { + Self::notify_profile(&signal_ctxt.clone(), active_profile) + .await + .ok(); + } + }) + .await; + } + }); Ok(()) } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 2bb39275..df608762 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -2,11 +2,12 @@ use std::env; use std::error::Error; use std::io::Write; use std::sync::{Arc, Mutex}; +use std::time::Duration; use ::zbus::{Connection, SignalContext}; use log::LevelFilter; use log::{error, info, warn}; -use smol::Executor; +use tokio::time::sleep; use daemon::ctrl_anime::config::AnimeConfig; use daemon::ctrl_anime::zbus::CtrlAnimeZbus; @@ -31,7 +32,8 @@ use rog_profiles::Profile; static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; -pub fn main() -> Result<(), Box> { +#[tokio::main] +async fn main() -> Result<(), Box> { let mut logger = env_logger::Builder::new(); logger .target(env_logger::Target::Stdout) @@ -60,14 +62,12 @@ pub fn main() -> Result<(), Box> { info!(" rog-profiles v{}", rog_profiles::VERSION); info!("rog-platform v{}", rog_platform::VERSION); - let mut executor = Executor::new(); - - smol::block_on(start_daemon(&mut executor))?; + start_daemon().await?; Ok(()) } /// The actual main loop for the daemon -async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> { +async fn start_daemon() -> Result<(), Box> { let supported = SupportedFunctions::get_supported(); print_board_info(); println!("{}", serde_json::to_string_pretty(&supported)?); @@ -90,7 +90,7 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> let task = CtrlRogBios::new(config.clone())?; let sig = SignalContext::new(&connection, "/org/asuslinux/Platform")?; - task.create_tasks(executor, sig).await.ok(); + task.create_tasks(sig).await.ok(); } Err(err) => { error!("rog_bios_control: {}", err); @@ -107,7 +107,7 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> let task = CtrlPower::new(config)?; let sig = SignalContext::new(&connection, "/org/asuslinux/Charge")?; - task.create_tasks(executor, sig).await.ok(); + task.create_tasks(sig).await.ok(); } Err(err) => { error!("charge_control: {}", err); @@ -127,7 +127,7 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> let sig = SignalContext::new(&connection, "/org/asuslinux/Profile")?; let task = ProfileZbus::new(tmp.clone()); - task.create_tasks(executor, sig).await.ok(); + task.create_tasks(sig).await.ok(); task.add_to_server(&mut connection).await; } Err(err) => { @@ -152,7 +152,7 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> let task = CtrlAnimeTask::new(inner).await; let sig = SignalContext::new(&connection, "/org/asuslinux/Anime")?; - task.create_tasks(executor, sig).await.ok(); + task.create_tasks(sig).await.ok(); } Err(err) => { error!("AniMe control: {}", err); @@ -176,7 +176,7 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> let task = CtrlKbdLedTask::new(inner); let sig = SignalContext::new(&connection, "/org/asuslinux/Aura")?; - task.create_tasks(executor, sig).await.ok(); + task.create_tasks(sig).await.ok(); } Err(err) => { error!("Keyboard control: {}", err); @@ -185,7 +185,9 @@ async fn start_daemon(executor: &mut Executor<'_>) -> Result<(), Box> // Request dbus name after finishing initalizing all functions connection.request_name(DBUS_NAME).await?; + loop { - smol::block_on(executor.tick()); + // This is just a blocker to idle and ensure the reator reacts + sleep(Duration::from_millis(1000)).await; } } diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index de0001dd..6fda88ed 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -23,12 +23,10 @@ use std::time::Duration; use crate::error::RogError; use async_trait::async_trait; -use config::Config; -use inotify::{Inotify, WatchMask}; use log::warn; use logind_zbus::manager::ManagerProxy; -use smol::{stream::StreamExt, Executor, Timer}; -use zbus::{Connection, SignalContext}; +use tokio::time; +use zbus::{export::futures_util::StreamExt, Connection, SignalContext}; use zvariant::ObjectPath; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -65,6 +63,8 @@ pub trait ZbusAdd { /// - `notify_(SignalContext, SomeValue)` /// /// In most cases if `SomeValue` is stored in a config then `()` getter is expected to update it. +/// The getter should *never* write back to the path or attribute that is being watched or an +/// infinite loop will occur. /// /// # Example /// @@ -78,28 +78,24 @@ pub trait ZbusAdd { macro_rules! task_watch_item { ($name:ident $self_inner:ident) => { concat_idents::concat_idents!(fn_name = watch_, $name { - async fn fn_name<'a>( + async fn fn_name( &self, - executor: &mut Executor<'a>, - signal_ctxt: SignalContext<'a>, + signal_ctxt: SignalContext<'static>, ) -> Result<(), RogError> { use zbus::export::futures_util::StreamExt; let ctrl = self.clone(); concat_idents::concat_idents!(watch_fn = monitor_, $name { let mut watch = self.$self_inner.watch_fn()?; - executor - .spawn(async move { - let mut buffer = [0; 1024]; + tokio::spawn(async move { + 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(); }); }).await; - }) - .detach(); + }); }); Ok(()) } @@ -112,59 +108,23 @@ macro_rules! task_watch_item { pub trait CtrlTask { /// Implement to set up various tasks that may be required, using the `Executor`. /// No blocking loops are allowed, or they must be run on a separate thread. - async fn create_tasks<'a>( - &self, - executor: &mut Executor<'a>, - signal: SignalContext<'a>, - ) -> Result<(), RogError>; - - /// Free method to run a task when the path is modified - /// - /// Not very useful if you need to also do a zbus notification. - fn create_tasks_inotify( - &self, - executor: &mut Executor, - path: &str, - mut task: impl FnMut() + Send + 'static, - ) -> Result<(), RogError> { - let mut inotify = Inotify::init()?; - inotify.add_watch(path, WatchMask::MODIFY)?; - let mut buffer = [0; 1024]; - - executor - .spawn(async move { - loop { - if let Ok(events) = inotify.read_events_blocking(&mut buffer) { - for _ in events { - task() - } - } - } - }) - .detach(); - - Ok(()) - } + async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; /// Create a timed repeating task - async fn repeating_task( - &self, - millis: u64, - executor: &mut Executor, - mut task: impl FnMut() + Send + 'static, - ) { - let timer = Timer::interval(Duration::from_millis(millis)); - executor - .spawn(async move { - timer.for_each(|_| task()).await; - }) - .detach(); + async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { + let mut timer = time::interval(Duration::from_millis(millis)); + tokio::spawn(async move { + timer.tick().await; + task(); + }); } /// Free helper method to create tasks to run on: sleep, wake, shutdown, boot + /// + /// The closures can potentially block, so execution time should be the minimal possible + /// such as save a variable. async fn create_sys_event_tasks( &self, - executor: &mut Executor, mut on_sleep: impl FnMut() + Send + 'static, mut on_wake: impl FnMut() + Send + 'static, mut on_shutdown: impl FnMut() + Send + 'static, @@ -178,54 +138,40 @@ pub trait CtrlTask { .await .expect("Controller could not create ManagerProxy"); - executor - .spawn(async move { - if let Ok(notif) = manager.receive_prepare_for_sleep().await { - notif - .for_each(|event| { - if let Ok(args) = event.args() { - if args.start { - on_sleep(); - } else if !args.start() { - on_wake(); - } - } - }) - .await; + tokio::spawn(async move { + if let Ok(mut notif) = manager.receive_prepare_for_sleep().await { + while let Some(event) = notif.next().await { + if let Ok(args) = event.args() { + if args.start { + on_sleep(); + } else if !args.start() { + on_wake(); + } + } } - }) - .detach(); + } + }); let manager = ManagerProxy::new(&connection) .await .expect("Controller could not create ManagerProxy"); - executor - .spawn(async move { - if let Ok(notif) = manager.receive_prepare_for_shutdown().await { - notif - .for_each(|event| { - if let Ok(args) = event.args() { - if args.start { - on_shutdown(); - } else if !args.start() { - on_boot(); - } - } - }) - .await; + tokio::spawn(async move { + if let Ok(mut notif) = manager.receive_prepare_for_shutdown().await { + while let Some(event) = notif.next().await { + if let Ok(args) = event.args() { + if args.start { + on_shutdown(); + } else if !args.start() { + on_boot(); + } + } } - }) - .detach(); + } + }); } } -pub trait CtrlTaskComplex { - type A; - - fn do_task(&mut self, config: &mut Config, event: Self::A); -} - pub trait GetSupported { type A; diff --git a/rog-control-center/src/main.rs b/rog-control-center/src/main.rs index 634342aa..c5bf8b46 100644 --- a/rog-control-center/src/main.rs +++ b/rog-control-center/src/main.rs @@ -156,7 +156,6 @@ fn main() -> Result<(), Box> { start_closed = false; continue; } - dbg!("asda"); } Ok(()) } diff --git a/rog-control-center/src/startup_error.rs b/rog-control-center/src/startup_error.rs index 3540c3cb..c1a6a822 100644 --- a/rog-control-center/src/startup_error.rs +++ b/rog-control-center/src/startup_error.rs @@ -27,7 +27,7 @@ impl eframe::App for AppErrorShow { .add(Button::new(RichText::new("Okay").size(20.0))) .clicked() { - frame.quit(); + frame.close(); } }); }); diff --git a/rog-control-center/src/widgets/top_bar.rs b/rog-control-center/src/widgets/top_bar.rs index f020d902..3e8af4ef 100644 --- a/rog-control-center/src/widgets/top_bar.rs +++ b/rog-control-center/src/widgets/top_bar.rs @@ -39,7 +39,7 @@ impl<'a> RogApp<'a> { Button::new(RichText::new("❌").size(height - 4.0)).frame(false), ); if close_response.clicked() { - frame.quit(); + frame.close(); } }); }); diff --git a/rog-platform/src/macros.rs b/rog-platform/src/macros.rs index 3c58b2e5..e9bf431a 100644 --- a/rog-platform/src/macros.rs +++ b/rog-platform/src/macros.rs @@ -21,7 +21,6 @@ macro_rules! watch_attr { pub fn fn_name(&self) -> Result { let mut path = self.$item.clone(); path.push($attr_name); - dbg!(&path); let mut inotify = inotify::Inotify::init().unwrap(); inotify.add_watch(path.to_str().unwrap(), inotify::WatchMask::MODIFY).unwrap(); Ok(inotify) From 7ea1f41286554b64d5fc70a039f18e13a8a6293d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 23 Sep 2022 10:50:09 +1200 Subject: [PATCH 09/11] Convert chunk of daemon to use async mutex --- CHANGELOG.md | 5 +- Cargo.lock | 3 +- daemon/Cargo.toml | 3 +- daemon/src/ctrl_anime/mod.rs | 35 ++-- daemon/src/ctrl_anime/zbus.rs | 170 +++++++--------- daemon/src/ctrl_aura/controller.rs | 57 +++--- daemon/src/ctrl_aura/zbus.rs | 193 +++++++----------- daemon/src/ctrl_platform.rs | 17 +- daemon/src/ctrl_power.rs | 19 +- daemon/src/ctrl_profiles/controller.rs | 11 +- daemon/src/ctrl_profiles/zbus.rs | 267 +++++++++++-------------- daemon/src/ctrl_supported.rs | 2 +- daemon/src/daemon.rs | 15 +- daemon/src/lib.rs | 26 +-- design-patterns.md | 110 ++++++---- rog-platform/src/platform.rs | 2 +- 16 files changed, 435 insertions(+), 500 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbca84c..aed342bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,10 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use loops to ensure that mutex is gained for LED changes. - asusctl now uses tokio for async runtime. This helps simplify some code. ### Breaking -- DBUS: all charge control methods renamed: +- DBUS: all charge control methods renamed to: - `ChargeControlEndThreshold` - `SetChargeControlEndThreshold` - `NotifyChargeControlEndThreshold` + - `PanelOd` (form PanelOverdrive) + - `SetPanelOd` + - `NotifyPanelOd` ## [v4.4.0] - 2022-08-29 ### Added diff --git a/Cargo.lock b/Cargo.lock index cb05ba50..87f21e71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,12 +572,11 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.4.0" +version = "4.5.0-rc1" dependencies = [ "async-trait", "concat-idents", "env_logger", - "inotify", "log", "logind-zbus", "rog_anime", diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 7098e423..ad498d8d 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.4.0" +version = "4.5.0-rc1" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] @@ -44,5 +44,4 @@ toml = "^0.5.8" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID -inotify = { version = "0.10.0", default-features = false } concat-idents = "1.1.3" \ No newline at end of file diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 221ee250..0de821d0 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -1,6 +1,7 @@ pub mod config; pub mod zbus; +use ::zbus::export::futures_util::lock::{Mutex, MutexGuard}; use ::zbus::SignalContext; use async_trait::async_trait; use log::{error, info, warn}; @@ -14,12 +15,7 @@ use rog_anime::{ }; use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::{ - convert::TryFrom, - error::Error, - sync::{Arc, Mutex, MutexGuard}, - thread::sleep, -}; +use std::{convert::TryFrom, error::Error, sync::Arc, thread::sleep}; use crate::{error::RogError, GetSupported}; @@ -85,6 +81,7 @@ impl CtrlAnime { // The only reason for this outer thread is to prevent blocking while waiting for the // next spawned thread to exit + // TODO: turn this in to async task (maybe? COuld still risk blocking main thread) std::thread::Builder::new() .name("AniMe system thread start".into()) .spawn(move || { @@ -95,7 +92,7 @@ impl CtrlAnime { let thread_running; let anime_type; loop { - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { thread_exit = lock.thread_exit.clone(); thread_running = lock.thread_running.clone(); anime_type = lock.anime_type; @@ -139,9 +136,10 @@ impl CtrlAnime { .ok(); false // Don't exit yet }) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - AnimeError::NoFrames + .map(|r| Ok(r)) + .unwrap_or_else(|| { + warn!("rog_anime::run_animation:callback failed"); + Err(AnimeError::NoFrames) }) }) { warn!("rog_anime::run_animation:Animation {}", err); @@ -150,7 +148,7 @@ impl CtrlAnime { } ActionData::Image(image) => { once = false; - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { lock.write_data_buffer(image.as_ref().clone()) .map_err(|e| error!("{}", e)) .ok(); @@ -171,7 +169,7 @@ impl CtrlAnime { } } // Clear the display on exit - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { if let Ok(data) = AnimeDataBuffer::from_vec(anime_type, vec![0u8; anime_type.data_length()]) .map_err(|e| error!("{}", e)) @@ -249,25 +247,25 @@ impl crate::CtrlTask for CtrlAnimeTask { // Loop is required to try an attempt to get the mutex *without* blocking // other threads - it is possible to end up with deadlocks otherwise. move || loop { - if let Ok(lock) = inner1.clone().try_lock() { + if let Some(lock) = inner1.try_lock() { run_action(true, lock, inner1.clone()); break; } }, move || loop { - if let Ok(lock) = inner2.clone().try_lock() { + if let Some(lock) = inner2.try_lock() { run_action(false, lock, inner2.clone()); break; } }, move || loop { - if let Ok(lock) = inner3.clone().try_lock() { + if let Some(lock) = inner3.try_lock() { run_action(true, lock, inner3.clone()); break; } }, move || loop { - if let Ok(lock) = inner4.clone().try_lock() { + if let Some(lock) = inner4.try_lock() { run_action(false, lock, inner4.clone()); break; } @@ -281,9 +279,10 @@ impl crate::CtrlTask for CtrlAnimeTask { pub struct CtrlAnimeReloader(pub Arc>); +#[async_trait] impl crate::Reloadable for CtrlAnimeReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(lock) = self.0.try_lock() { + async fn reload(&mut self) -> Result<(), RogError> { + if let Some(lock) = self.0.try_lock() { lock.node .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; lock.node.write_bytes(&pkt_for_apply())?; diff --git a/daemon/src/ctrl_anime/zbus.rs b/daemon/src/ctrl_anime/zbus.rs index a71c3600..a1210612 100644 --- a/daemon/src/ctrl_anime/zbus.rs +++ b/daemon/src/ctrl_anime/zbus.rs @@ -1,14 +1,12 @@ -use std::sync::{Arc, Mutex}; - use async_trait::async_trait; use log::warn; use rog_anime::{ usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, AnimeDataBuffer, AnimePowerStates, }; -use zbus::{dbus_interface, Connection, SignalContext}; +use zbus::{dbus_interface, export::futures_util::lock::Mutex, Connection, SignalContext}; -use std::sync::atomic::Ordering; +use std::sync::{atomic::Ordering, Arc}; use super::CtrlAnime; @@ -16,7 +14,7 @@ pub struct CtrlAnimeZbus(pub Arc>); /// The struct with the main dbus methods requires this trait #[async_trait] -impl crate::ZbusAdd for CtrlAnimeZbus { +impl crate::ZbusRun for CtrlAnimeZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await; } @@ -28,127 +26,105 @@ impl crate::ZbusAdd for CtrlAnimeZbus { #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlAnimeZbus { /// Writes a data stream of length. Will force system thread to exit until it is restarted - fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - lock.write_data_buffer(input).map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - err - })?; - break 'outer; - } - } + async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { + let lock = self.0.lock().await; + lock.thread_exit.store(true, Ordering::SeqCst); + lock.write_data_buffer(input).map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + err + })?; Ok(()) } /// Set the global AniMe brightness - fn set_brightness(&self, bright: f32) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - let mut bright = bright; - if bright < 0.0 { - bright = 0.0 - } else if bright > 1.0 { - bright = 1.0; - } - lock.config.brightness = bright; - lock.config.write(); - break 'outer; - } + async fn set_brightness(&self, bright: f32) { + let mut lock = self.0.lock().await; + let mut bright = bright; + if bright < 0.0 { + bright = 0.0 + } else if bright > 1.0 { + bright = 1.0; } + lock.config.brightness = bright; + lock.config.write(); } /// Set whether the AniMe is displaying images/data async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) { - let states; - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.node - .write_bytes(&pkt_for_set_on(status)) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.config.awake_enabled = status; - lock.config.write(); + let mut lock = self.0.lock().await; + lock.node + .write_bytes(&pkt_for_set_on(status)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.config.awake_enabled = status; + lock.config.write(); - states = Some(AnimePowerStates { - brightness: lock.config.brightness.floor() as u8, - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }); - break 'outer; - } - } - if let Some(state) = states { - Self::notify_power_states(&ctxt, state).await.ok(); - } + Self::notify_power_states( + &ctxt, + AnimePowerStates { + brightness: lock.config.brightness.floor() as u8, + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }, + ) + .await + .ok(); } /// Set whether the AniMe will show boot, suspend, or off animations async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) { - let states; - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.node - .write_bytes(&pkt_for_set_boot(on)) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.node - .write_bytes(&pkt_for_apply()) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.config.boot_anim_enabled = on; - lock.config.write(); + let mut lock = self.0.lock().await; + lock.node + .write_bytes(&pkt_for_set_boot(on)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.node + .write_bytes(&pkt_for_apply()) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.config.boot_anim_enabled = on; + lock.config.write(); - states = Some(AnimePowerStates { - brightness: lock.config.brightness.floor() as u8, - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }); - break 'outer; - } - } - if let Some(state) = states { - Self::notify_power_states(&ctxt, state).await.ok(); - } + Self::notify_power_states( + &ctxt, + AnimePowerStates { + brightness: lock.config.brightness.floor() as u8, + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }, + ) + .await + .ok(); } /// The main loop is the base system set action if the user isn't running /// the user daemon - fn run_main_loop(&self, start: bool) { + async fn run_main_loop(&self, start: bool) { if start { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); - break 'outer; - } - } + let lock = self.0.lock().await; + lock.thread_exit.store(true, Ordering::SeqCst); + CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); } } /// Get status of if the AniMe LEDs are on/displaying while system is awake #[dbus_interface(property)] - fn awake_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.awake_enabled; - } - true + async fn awake_enabled(&self) -> bool { + let lock = self.0.lock().await; + return lock.config.awake_enabled; } /// Get the status of if factory system-status animations are enabled #[dbus_interface(property)] - fn boot_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.boot_anim_enabled; - } - true + async fn boot_enabled(&self) -> bool { + let lock = self.0.lock().await; + return lock.config.boot_anim_enabled; } /// Notify listeners of the status of AniMe LED power and factory system-status animations diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index fc4329de..e7c1833d 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -13,9 +13,13 @@ use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions}; use std::collections::BTreeMap; use std::sync::Arc; -use std::sync::Mutex; -use std::sync::MutexGuard; -use zbus::{export::futures_util::StreamExt, SignalContext}; +use zbus::{ + export::futures_util::{ + lock::{Mutex, MutexGuard}, + StreamExt, + }, + SignalContext, +}; use crate::GetSupported; @@ -121,25 +125,25 @@ impl CtrlTask for CtrlKbdLedTask { // Loop so that we do aquire the lock but also don't block other // threads (prevents potential deadlocks) move || loop { - if let Ok(lock) = inner1.clone().try_lock() { + if let Some(lock) = inner1.try_lock() { load_save(true, lock); break; } }, move || loop { - if let Ok(lock) = inner2.clone().try_lock() { + if let Some(lock) = inner2.try_lock() { load_save(false, lock); break; } }, move || loop { - if let Ok(lock) = inner3.clone().try_lock() { + if let Some(lock) = inner3.try_lock() { load_save(true, lock); break; } }, move || loop { - if let Ok(lock) = inner4.clone().try_lock() { + if let Some(lock) = inner4.try_lock() { load_save(false, lock); break; } @@ -148,21 +152,20 @@ impl CtrlTask for CtrlKbdLedTask { .await; let ctrl2 = self.inner.clone(); - if let Ok(ctrl) = self.inner.lock() { - let mut watch = ctrl.kd_brightness.monitor_brightness()?; - tokio::spawn(async move { - let mut buffer = [0; 32]; - watch - .event_stream(&mut buffer) - .unwrap() - .for_each(|_| async { - if let Ok(lock) = ctrl2.try_lock() { - load_save(true, lock); - } - }) - .await; - }); - } + let ctrl = self.inner.lock().await; + let mut watch = ctrl.kd_brightness.monitor_brightness()?; + tokio::spawn(async move { + let mut buffer = [0; 32]; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + if let Some(lock) = ctrl2.try_lock() { + load_save(true, lock); + } + }) + .await; + }); Ok(()) } @@ -170,12 +173,12 @@ impl CtrlTask for CtrlKbdLedTask { pub struct CtrlKbdLedReloader(pub Arc>); +#[async_trait] impl crate::Reloadable for CtrlKbdLedReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.write_current_config_mode()?; - ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); - } + async fn reload(&mut self) -> Result<(), RogError> { + let mut ctrl = self.0.lock().await; + ctrl.write_current_config_mode()?; + ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); Ok(()) } } diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 5392ef08..2849b749 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -8,7 +8,7 @@ use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlKbdLedZbus; #[async_trait] -impl crate::ZbusAdd for CtrlKbdLedZbus { +impl crate::ZbusRun for CtrlKbdLedZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Aura", server).await; } @@ -21,11 +21,10 @@ impl crate::ZbusAdd for CtrlKbdLedZbus { impl CtrlKbdLedZbus { /// Set the keyboard brightness level (0-3) async fn set_brightness(&mut self, brightness: LedBrightness) { - if let Ok(ctrl) = self.0.try_lock() { - ctrl.set_brightness(brightness) - .map_err(|err| warn!("{}", err)) - .ok(); - } + let ctrl = self.0.lock().await; + ctrl.set_brightness(brightness) + .map_err(|err| warn!("{}", err)) + .ok(); } /// Set a variety of states, input is array of enum. @@ -64,36 +63,27 @@ impl CtrlKbdLedZbus { options: AuraPowerDev, enabled: bool, ) -> zbus::fdo::Result<()> { - let mut states = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - for p in options.tuf { - ctrl.config.enabled.set_tuf(p, enabled); - } - for p in options.x1866 { - ctrl.config.enabled.set_0x1866(p, enabled); - } - for p in options.x19b6 { - ctrl.config.enabled.set_0x19b6(p, enabled); - } - - ctrl.config.write(); - - ctrl.set_power_states().map_err(|e| { - warn!("{}", e); - e - })?; - - states = Some(AuraPowerDev::from(&ctrl.config.enabled)); - } - break; + let mut ctrl = self.0.lock().await; + for p in options.tuf { + ctrl.config.enabled.set_tuf(p, enabled); } - // Need to pull state out like this due to MutexGuard - if let Some(states) = states { - Self::notify_power_states(&ctxt, &states) - .await - .unwrap_or_else(|err| warn!("{}", err)); + for p in options.x1866 { + ctrl.config.enabled.set_0x1866(p, enabled); } + for p in options.x19b6 { + ctrl.config.enabled.set_0x19b6(p, enabled); + } + + ctrl.config.write(); + + ctrl.set_power_states().map_err(|e| { + warn!("{}", e); + e + })?; + + Self::notify_power_states(&ctxt, &AuraPowerDev::from(&ctrl.config.enabled)) + .await + .unwrap_or_else(|err| warn!("{}", err)); Ok(()) } @@ -102,21 +92,15 @@ impl CtrlKbdLedZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, effect: AuraEffect, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.set_effect(effect).map_err(|e| { - warn!("{}", e); - e - })?; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + let mut ctrl = self.0.lock().await; + + ctrl.set_effect(effect).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } @@ -127,22 +111,15 @@ impl CtrlKbdLedZbus { &self, #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(false).map_err(|e| { - warn!("{}", e); - e - })?; + let mut ctrl = self.0.lock().await; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + ctrl.toggle_mode(false).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } @@ -154,100 +131,70 @@ impl CtrlKbdLedZbus { &self, #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(true).map_err(|e| { - warn!("{}", e); - e - })?; + let mut ctrl = self.0.lock().await; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + ctrl.toggle_mode(true).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } async fn next_led_brightness(&self) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.next_brightness().map_err(|e| { - warn!("{}", e); - e - })?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.next_brightness().map_err(|e| { + warn!("{}", e); + e + })?; Ok(()) } async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.prev_brightness().map_err(|e| { - warn!("{}", e); - e - })?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.prev_brightness().map_err(|e| { + warn!("{}", e); + e + })?; Ok(()) } // As property doesn't work for AuraPowerDev (complexity of serialization?) // #[dbus_interface(property)] async fn leds_enabled(&self) -> AuraPowerDev { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return AuraPowerDev::from(&ctrl.config.enabled); - } - } + let ctrl = self.0.lock().await; + return AuraPowerDev::from(&ctrl.config.enabled); } /// Return the current mode data async fn led_mode(&self) -> AuraModeNum { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.current_mode; - } - } + let ctrl = self.0.lock().await; + return ctrl.config.current_mode; } /// Return a list of available modes async fn led_modes(&self) -> BTreeMap { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.builtins.clone(); - } - } + let ctrl = self.0.lock().await; + return ctrl.config.builtins.clone(); } async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.write_effect_block(&data)?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.write_effect_block(&data)?; Ok(()) } /// Return the current LED brightness #[dbus_interface(property)] async fn led_brightness(&self) -> i8 { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); - } - } + let ctrl = self.0.lock().await; + ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1) } #[dbus_interface(signal)] diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index b22b9167..7c89e158 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -9,7 +9,7 @@ use std::io::{Read, Write}; use std::path::Path; use std::process::Command; use std::sync::Arc; -use std::sync::Mutex; +use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::{dbus_interface, SignalContext}; @@ -210,7 +210,7 @@ impl CtrlRogBios { }) .is_ok() { - if let Ok(mut lock) = self.config.try_lock() { + if let Some(mut lock) = self.config.try_lock() { lock.panel_od = overdrive; lock.write(); } @@ -228,7 +228,7 @@ impl CtrlRogBios { err }) .unwrap_or(false); - if let Ok(mut lock) = self.config.try_lock() { + if let Some(mut lock) = self.config.try_lock() { lock.panel_od = od; lock.write(); } @@ -241,16 +241,17 @@ impl CtrlRogBios { } #[async_trait] -impl crate::ZbusAdd for CtrlRogBios { +impl crate::ZbusRun for CtrlRogBios { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Platform", server).await; } } +#[async_trait] impl crate::Reloadable for CtrlRogBios { - fn reload(&mut self) -> Result<(), RogError> { + async fn reload(&mut self) -> Result<(), RogError> { if self.platform.has_panel_od() { - let p = if let Ok(lock) = self.config.try_lock() { + let p = if let Some(lock) = self.config.try_lock() { lock.panel_od } else { false @@ -275,7 +276,7 @@ impl CtrlTask for CtrlRogBios { move || {}, move || { info!("CtrlRogBios reloading panel_od"); - if let Ok(lock) = platform1.config.try_lock() { + if let Some(lock) = platform1.config.try_lock() { if platform1.platform.has_panel_od() { platform1 .set_panel_overdrive(lock.panel_od) @@ -290,7 +291,7 @@ impl CtrlTask for CtrlRogBios { move || {}, move || { info!("CtrlRogBios reloading panel_od"); - if let Ok(lock) = platform2.config.try_lock() { + if let Some(lock) = platform2.config.try_lock() { if platform2.platform.has_panel_od() { platform2 .set_panel_overdrive(lock.panel_od) diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 8a008898..aef69094 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -5,8 +5,8 @@ use log::{info, warn}; use rog_platform::power::AsusPower; use rog_platform::supported::ChargeSupportedFunctions; use std::sync::Arc; -use std::sync::Mutex; use zbus::dbus_interface; +use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::SignalContext; @@ -52,7 +52,7 @@ impl CtrlPower { fn charge_control_end_threshold(&self) -> u8 { loop { - if let Ok(config) = self.config.try_lock() { + if let Some(config) = self.config.try_lock() { let limit = self .power .get_charge_control_end_threshold() @@ -61,7 +61,7 @@ impl CtrlPower { err }) .unwrap_or(100); - if let Ok(mut config) = self.config.try_lock() { + if let Some(mut config) = self.config.try_lock() { config.read(); config.bat_charge_limit = limit; config.write(); @@ -80,15 +80,16 @@ impl CtrlPower { } #[async_trait] -impl crate::ZbusAdd for CtrlPower { +impl crate::ZbusRun for CtrlPower { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Charge", server).await; } } +#[async_trait] impl crate::Reloadable for CtrlPower { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut config) = self.config.try_lock() { + async fn reload(&mut self) -> Result<(), RogError> { + if let Some(mut config) = self.config.try_lock() { config.read(); self.set(config.bat_charge_limit)?; } @@ -113,7 +114,7 @@ impl CtrlPower { info!("Battery charge limit: {}", limit); - if let Ok(mut config) = self.config.try_lock() { + if let Some(mut config) = self.config.try_lock() { config.read(); config.bat_charge_limit = limit; config.write(); @@ -134,7 +135,7 @@ impl CtrlTask for CtrlPower { move || {}, move || { info!("CtrlCharge reloading charge limit"); - if let Ok(lock) = power1.config.try_lock() { + if let Some(lock) = power1.config.try_lock() { power1 .set(lock.bat_charge_limit) .map_err(|err| { @@ -147,7 +148,7 @@ impl CtrlTask for CtrlPower { move || {}, move || { info!("CtrlCharge reloading charge limit"); - if let Ok(lock) = power2.config.try_lock() { + if let Some(lock) = power2.config.try_lock() { power2 .set(lock.bat_charge_limit) .map_err(|err| { diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index 4666bbfe..ae7a3f2f 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,6 +1,8 @@ use crate::error::RogError; use crate::GetSupported; +use async_trait::async_trait; use log::{info, warn}; +use rog_platform::platform::AsusPlatform; use rog_platform::supported::PlatformProfileFunctions; use rog_profiles::error::ProfileError; use rog_profiles::{FanCurveProfiles, Profile}; @@ -9,6 +11,7 @@ use super::config::ProfileConfig; pub struct CtrlPlatformProfile { pub config: ProfileConfig, + pub platform: AsusPlatform, } impl GetSupported for CtrlPlatformProfile { @@ -36,9 +39,10 @@ impl GetSupported for CtrlPlatformProfile { } } +#[async_trait] impl crate::Reloadable for CtrlPlatformProfile { /// Fetch the active profile and use that to set all related components up - fn reload(&mut self) -> Result<(), RogError> { + async fn reload(&mut self) -> Result<(), RogError> { if let Some(curves) = &mut self.config.fan_curves { if let Ok(mut device) = FanCurveProfiles::get_device() { // There is a possibility that the curve was default zeroed, so this call initialises @@ -53,10 +57,11 @@ impl crate::Reloadable for CtrlPlatformProfile { impl CtrlPlatformProfile { pub fn new(config: ProfileConfig) -> Result { - if Profile::is_platform_profile_supported() { + let platform = AsusPlatform::new()?; + if platform.has_platform_profile() || platform.has_throttle_thermal_policy() { info!("Device has profile control available"); - let mut controller = CtrlPlatformProfile { config }; + let mut controller = CtrlPlatformProfile { config, platform }; if FanCurveProfiles::get_device().is_ok() { info!("Device has fan curves available"); if controller.config.fan_curves.is_none() { diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 97039b64..ab8b44bf 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -1,17 +1,14 @@ use async_trait::async_trait; -use inotify::Inotify; -use inotify::WatchMask; use log::warn; use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::Profile; -use rog_profiles::PLATFORM_PROFILE; +use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::StreamExt; use zbus::Connection; use zbus::SignalContext; use std::sync::Arc; -use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; use crate::error::RogError; @@ -47,27 +44,21 @@ impl ProfileZbus { /// Toggle to next platform_profile. Names provided by `Profiles`. /// If fan-curves are supported will also activate a fan curve for profile. async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) { - let mut profile = None; - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.set_next_profile() - .unwrap_or_else(|err| warn!("{}", err)); - ctrl.save_config(); - profile = Some(ctrl.config.active_profile); - } - if let Some(profile) = profile { - Self::notify_profile(&ctxt, profile).await.ok(); - } + let mut ctrl = self.inner.lock().await; + ctrl.set_next_profile() + .unwrap_or_else(|err| warn!("{}", err)); + ctrl.save_config(); + + Self::notify_profile(&ctxt, ctrl.config.active_profile) + .await + .ok(); } /// Fetch the active profile name - fn active_profile(&mut self) -> zbus::fdo::Result { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - return Ok(ctrl.config.active_profile); - } - Err(Error::Failed( - "Failed to get active profile name".to_string(), - )) + async fn active_profile(&mut self) -> zbus::fdo::Result { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + Ok(ctrl.config.active_profile) } /// Set this platform_profile name as active @@ -76,93 +67,85 @@ impl ProfileZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, profile: Profile, ) { - let mut tmp = None; - if let Ok(mut ctrl) = self.inner.try_lock() { - // Read first just incase the user has modified the config before calling this - ctrl.config.read(); - Profile::set_profile(profile) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.config.active_profile = profile; + let mut ctrl = self.inner.lock().await; + // Read first just incase the user has modified the config before calling this + ctrl.config.read(); + Profile::set_profile(profile) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.config.active_profile = profile; + ctrl.write_profile_curve_to_platform() + .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) + .ok(); + + ctrl.save_config(); + + Self::notify_profile(&ctxt, ctrl.config.active_profile) + .await + .ok(); + } + + /// Get a list of profiles that have fan-curves enabled. + async fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + 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())); + } + + /// Set a profile fan curve enabled status. Will also activate a fan curve if in the + /// same profile mode + async fn set_fan_curve_enabled( + &mut self, + profile: Profile, + enabled: bool, + ) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + return if let Some(curves) = &mut ctrl.config.fan_curves { + curves.set_profile_curve_enabled(profile, enabled); + ctrl.write_profile_curve_to_platform() .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) .ok(); ctrl.save_config(); - tmp = Some(ctrl.config.active_profile); - } - if let Some(profile) = tmp { - Self::notify_profile(&ctxt, profile).await.ok(); - } - } - - /// Get a list of profiles that have fan-curves enabled. - fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - 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( - "Failed to get enabled fan curve names".to_string(), - )) - } - - /// Set a profile fan curve enabled status. Will also activate a fan curve if in the - /// same profile mode - fn set_fan_curve_enabled(&mut self, profile: Profile, enabled: bool) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - return if let Some(curves) = &mut ctrl.config.fan_curves { - curves.set_profile_curve_enabled(profile, enabled); - - ctrl.write_profile_curve_to_platform() - .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) - .ok(); - - ctrl.save_config(); - Ok(()) - } else { - Err(Error::Failed(UNSUPPORTED_MSG.to_string())) - }; - } - Err(Error::Failed( - "Failed to get enabled fan curve names".to_string(), - )) + Ok(()) + } else { + Err(Error::Failed(UNSUPPORTED_MSG.to_string())) + }; } /// Get the fan-curve data for the currently active Profile - fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - if let Some(curves) = &ctrl.config.fan_curves { - let curve = curves.get_fan_curves_for(profile); - return Ok(curve.clone()); - } - return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); + async fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + if let Some(curves) = &ctrl.config.fan_curves { + let curve = curves.get_fan_curves_for(profile); + return Ok(curve.clone()); } - Err(Error::Failed("Failed to get fan curve data".to_string())) + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } /// Set the fan curve for the specified profile. /// Will also activate the fan curve if the user is in the same mode. - fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - if let Some(curves) = &mut ctrl.config.fan_curves { - curves - .save_fan_curve(curve, profile) - .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; - } else { - return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); - } - ctrl.write_profile_curve_to_platform() - .map_err(|e| warn!("Profile::set_profile, {}", e)) - .ok(); - ctrl.save_config(); + async fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + if let Some(curves) = &mut ctrl.config.fan_curves { + curves + .save_fan_curve(curve, profile) + .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; + } else { + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } + ctrl.write_profile_curve_to_platform() + .map_err(|e| warn!("Profile::set_profile, {}", e)) + .ok(); + ctrl.save_config(); + Ok(()) } @@ -170,14 +153,13 @@ impl ProfileZbus { /// /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. - fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - ctrl.set_active_curve_to_defaults() - .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) - .ok(); - ctrl.save_config(); - } + async fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + ctrl.set_active_curve_to_defaults() + .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) + .ok(); + ctrl.save_config(); Ok(()) } @@ -185,23 +167,22 @@ impl ProfileZbus { /// /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. - fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - let active = Profile::get_active_profile().unwrap_or(Profile::Balanced); + async fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + let active = Profile::get_active_profile().unwrap_or(Profile::Balanced); - Profile::set_profile(profile) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.set_active_curve_to_defaults() - .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) - .ok(); + Profile::set_profile(profile) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.set_active_curve_to_defaults() + .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) + .ok(); - Profile::set_profile(active) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.save_config(); - } + Profile::set_profile(active) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.save_config(); Ok(()) } @@ -211,7 +192,7 @@ impl ProfileZbus { } #[async_trait] -impl crate::ZbusAdd for ProfileZbus { +impl crate::ZbusRun for ProfileZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await; } @@ -221,36 +202,32 @@ impl crate::ZbusAdd for ProfileZbus { impl CtrlTask for ProfileZbus { async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let ctrl = self.inner.clone(); - let mut watch = Inotify::init()?; - watch.add_watch(PLATFORM_PROFILE, WatchMask::CLOSE_WRITE)?; + let mut watch = self + .inner + .lock() + .await + .platform + .monitor_platform_profile()?; tokio::spawn(async move { let mut buffer = [0; 32]; - loop { - watch - .event_stream(&mut buffer) - .unwrap() - .for_each(|_| async { - let mut active_profile = None; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + let mut lock = ctrl.lock().await; + let new_profile = Profile::get_active_profile().unwrap(); + if new_profile != lock.config.active_profile { + lock.config.active_profile = new_profile; + lock.write_profile_curve_to_platform().unwrap(); + lock.save_config(); + } - if let Ok(ref mut lock) = ctrl.try_lock() { - let new_profile = Profile::get_active_profile().unwrap(); - if new_profile != lock.config.active_profile { - lock.config.active_profile = new_profile; - lock.write_profile_curve_to_platform().unwrap(); - lock.save_config(); - active_profile = Some(lock.config.active_profile); - } - } - - if let Some(active_profile) = active_profile { - Self::notify_profile(&signal_ctxt.clone(), active_profile) - .await - .ok(); - } - }) - .await; - } + Self::notify_profile(&signal_ctxt.clone(), lock.config.active_profile) + .await + .ok(); + }) + .await; }); Ok(()) diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 4c4bec3d..9fe99a15 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -28,7 +28,7 @@ impl SupportedFunctions { } #[async_trait] -impl crate::ZbusAdd for SupportedFunctions { +impl crate::ZbusRun for SupportedFunctions { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Supported", server).await; } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index df608762..9796f7d3 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -1,9 +1,10 @@ use std::env; use std::error::Error; use std::io::Write; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::Duration; +use ::zbus::export::futures_util::lock::Mutex; use ::zbus::{Connection, SignalContext}; use log::LevelFilter; use log::{error, info, warn}; @@ -26,7 +27,7 @@ use daemon::{ ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, laptops::LaptopLedData, }; -use daemon::{CtrlTask, Reloadable, ZbusAdd}; +use daemon::{CtrlTask, Reloadable, ZbusRun}; use rog_dbus::DBUS_NAME; use rog_profiles::Profile; @@ -84,6 +85,7 @@ async fn start_daemon() -> Result<(), Box> { Ok(mut ctrl) => { // Do a reload of any settings ctrl.reload() + .await .unwrap_or_else(|err| warn!("CtrlRogBios: {}", err)); // Then register to dbus server ctrl.add_to_server(&mut connection).await; @@ -101,6 +103,7 @@ async fn start_daemon() -> Result<(), Box> { Ok(mut ctrl) => { // Do a reload of any settings ctrl.reload() + .await .unwrap_or_else(|err| warn!("CtrlPower: {}", err)); // Then register to dbus server ctrl.add_to_server(&mut connection).await; @@ -119,14 +122,12 @@ async fn start_daemon() -> Result<(), Box> { match CtrlPlatformProfile::new(profile_config) { Ok(mut ctrl) => { ctrl.reload() + .await .unwrap_or_else(|err| warn!("Profile control: {}", err)); - let tmp = Arc::new(Mutex::new(ctrl)); - //let task = CtrlProfileTask::new(tmp.clone()); - //task.create_tasks(executor).await.ok(); let sig = SignalContext::new(&connection, "/org/asuslinux/Profile")?; - let task = ProfileZbus::new(tmp.clone()); + let task = ProfileZbus::new(Arc::new(Mutex::new(ctrl))); task.create_tasks(sig).await.ok(); task.add_to_server(&mut connection).await; } @@ -145,6 +146,7 @@ async fn start_daemon() -> Result<(), Box> { let mut reload = CtrlAnimeReloader(inner.clone()); reload .reload() + .await .unwrap_or_else(|err| warn!("AniMe: {}", err)); let zbus = CtrlAnimeZbus(inner.clone()); @@ -168,6 +170,7 @@ async fn start_daemon() -> Result<(), Box> { let mut reload = CtrlKbdLedReloader(inner.clone()); reload .reload() + .await .unwrap_or_else(|err| warn!("Keyboard LED control: {}", err)); CtrlKbdLedZbus::new(inner.clone()) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 6fda88ed..bb6c41c1 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -19,24 +19,22 @@ pub mod ctrl_supported; pub mod error; -use std::time::Duration; - use crate::error::RogError; use async_trait::async_trait; use log::warn; use logind_zbus::manager::ManagerProxy; -use tokio::time; use zbus::{export::futures_util::StreamExt, Connection, SignalContext}; use zvariant::ObjectPath; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +#[async_trait] pub trait Reloadable { - fn reload(&mut self) -> Result<(), RogError>; + async fn reload(&mut self) -> Result<(), RogError>; } #[async_trait] -pub trait ZbusAdd { +pub trait ZbusRun { async fn add_to_server(self, server: &mut Connection); async fn add_to_server_helper( @@ -110,14 +108,16 @@ pub trait CtrlTask { /// No blocking loops are allowed, or they must be run on a separate thread. async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; - /// Create a timed repeating task - async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { - let mut timer = time::interval(Duration::from_millis(millis)); - tokio::spawn(async move { - timer.tick().await; - task(); - }); - } + // /// Create a timed repeating task + // async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { + // use std::time::Duration; + // use tokio::time; + // let mut timer = time::interval(Duration::from_millis(millis)); + // tokio::spawn(async move { + // timer.tick().await; + // task(); + // }); + // } /// Free helper method to create tasks to run on: sleep, wake, shutdown, boot /// diff --git a/design-patterns.md b/design-patterns.md index 25b59b52..8b21e1bf 100644 --- a/design-patterns.md +++ b/design-patterns.md @@ -19,80 +19,103 @@ Then for each trait that is required a new struct is required that can have the Main controller: ```rust +/// For a very simple controller that doesn't need exclusive access you can clone across threads +#[derive(Clone)] +pub struct CtrlAnime { + + config: Arc>, +} + +impl crate::CtrlTask for CtrlAnime {} +impl crate::ZbusAdd for CtrlAnime {} + +impl CtrlAnime {} +``` + +```rust +/// Otherwise, you will need to share the controller via mutex pub struct CtrlAnime { } +// Like this +#[derive(Clone)] +pub struct CtrlAnimeTask(Arc>); +#[derive(Clone)] +pub struct CtrlAnimeZbus(Arc>); -impl CtrlAnime { - -} +impl CtrlAnime {} ``` The task trait. There are three ways to implement this: ```rust +// Mutex should always be async mutex pub struct CtrlAnimeTask(Arc>); impl crate::CtrlTask for CtrlAnimeTask { // This will run once only - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { + let lock self.inner.lock().await; + Ok(()) } // This will run until the notification stream closes (which in most cases will be never) - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - let connection = Connection::system().await.unwrap(); - let manager = ManagerProxy::new(&connection).await.unwrap(); - - let inner = self.inner.clone(); - executor - .spawn(async move { - // A notification from logind dbus interface - if let Ok(p) = manager.receive_prepare_for_sleep().await { - // A stream that will continuously output events - p.for_each(|_| { - if let Ok(lock) = inner.try_lock() { - // Do stuff here - } - }) - .await; + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { + let inner1 = self.inner.clone(); + let inner2 = self.inner.clone(); + let inner3 = self.inner.clone(); + let inner4 = self.inner.clone(); + // This is a free method on CtrlTask trait + self.create_sys_event_tasks( + // Loop is required to try an attempt to get the mutex *without* blocking + // other threads - it is possible to end up with deadlocks otherwise. + move || loop { + if let Some(lock) = inner1.try_lock() { + run_action(true, lock, inner1.clone()); + break; } - }) - .detach(); - } - - // This task will run every 500 milliseconds - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - let inner = self.inner.clone(); - // This is a provided free trait to help set up a repeating task - self.repeating_task(500, executor, move || { - if let Ok(lock) = inner.try_lock() { - // Do stuff here - } - }) + }, + move || loop { + if let Some(lock) = inner2.try_lock() { + run_action(false, lock, inner2.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner3.try_lock() { + run_action(true, lock, inner3.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner4.try_lock() { + run_action(false, lock, inner4.clone()); + break; + } + }, + ) .await; } } ``` The reloader trait + ```rust pub struct CtrlAnimeReloader(Arc>); impl crate::Reloadable for CtrlAnimeReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn reload(&mut self) -> Result<(), RogError> { + let lock = self.inner.lock().await; + Ok(()) } } ``` The Zbus requirements: + ```rust pub struct CtrlAnimeZbus(Arc>); @@ -106,10 +129,9 @@ impl crate::ZbusAdd for CtrlAnimeZbus { #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlAnimeZbus { - fn () { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn () { + let lock = self.inner.lock().await; + } } ``` diff --git a/rog-platform/src/platform.rs b/rog-platform/src/platform.rs index 580ac83b..8658a28b 100644 --- a/rog-platform/src/platform.rs +++ b/rog-platform/src/platform.rs @@ -57,8 +57,8 @@ impl AsusPlatform { attr_bool!("egpu_enable", path); attr_bool!("panel_od", path); attr_u8!("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); } From 30550aaa91fb78e42fa2185f737ecd1603b84300 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 23 Sep 2022 20:07:43 +1200 Subject: [PATCH 10/11] Further improve the daemon controller pattern and reduce cloned code --- CHANGELOG.md | 1 + Cargo.lock | 2 +- asus-notify/src/main.rs | 4 +- daemon/Cargo.toml | 2 +- daemon/src/ctrl_anime/mod.rs | 100 +------------- .../ctrl_anime/{zbus.rs => trait_impls.rs} | 90 ++++++++++++- daemon/src/ctrl_aura/controller.rs | 127 +----------------- daemon/src/ctrl_aura/mod.rs | 3 +- .../src/ctrl_aura/{zbus.rs => trait_impls.rs} | 124 ++++++++++++++++- daemon/src/ctrl_platform.rs | 27 ++-- daemon/src/ctrl_power.rs | 8 +- daemon/src/ctrl_profiles/controller.rs | 17 --- daemon/src/ctrl_profiles/mod.rs | 3 +- .../ctrl_profiles/{zbus.rs => trait_impls.rs} | 66 +++++---- daemon/src/ctrl_supported.rs | 4 +- daemon/src/daemon.rs | 120 ++++++----------- daemon/src/lib.rs | 62 +++++---- design-patterns.md | 14 +- rog-control-center/src/notify.rs | 6 +- rog-dbus/src/lib.rs | 14 +- .../src/{zbus_charge.rs => zbus_power.rs} | 4 +- 21 files changed, 382 insertions(+), 416 deletions(-) rename daemon/src/ctrl_anime/{zbus.rs => trait_impls.rs} (60%) rename daemon/src/ctrl_aura/{zbus.rs => trait_impls.rs} (60%) rename daemon/src/ctrl_profiles/{zbus.rs => trait_impls.rs} (81%) rename rog-dbus/src/{zbus_charge.rs => zbus_power.rs} (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index aed342bd..7a203535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `PanelOd` (form PanelOverdrive) - `SetPanelOd` - `NotifyPanelOd` + - Path `/org/asuslinux/Charge` changed to `/org/asuslinux/Power` ## [v4.4.0] - 2022-08-29 ### Added diff --git a/Cargo.lock b/Cargo.lock index 87f21e71..ac355b19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,7 +572,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.5.0-rc1" +version = "4.5.0-rc2" dependencies = [ "async-trait", "concat-idents", diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index 95654357..3d0016d1 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -1,7 +1,7 @@ use notify_rust::{Hint, Notification, NotificationHandle}; use rog_aura::AuraEffect; use rog_dbus::{ - zbus_charge::ChargeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy, + zbus_led::LedProxy, zbus_platform::RogBiosProxy, zbus_power::PowerProxy, zbus_profile::ProfileProxy, }; use rog_profiles::Profile; @@ -69,7 +69,7 @@ fn main() -> Result<(), Box> { executor .spawn(async move { let conn = zbus::Connection::system().await.unwrap(); - let proxy = ChargeProxy::new(&conn).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() { diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index ad498d8d..d1f69bcf 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.5.0-rc1" +version = "4.5.0-rc2" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 0de821d0..96959350 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -1,26 +1,20 @@ pub mod config; -pub mod zbus; +/// Implements CtrlTask, Reloadable, ZbusRun +pub mod trait_impls; -use ::zbus::export::futures_util::lock::{Mutex, MutexGuard}; -use ::zbus::SignalContext; -use async_trait::async_trait; +use self::config::{AnimeConfig, AnimeConfigCached}; +use crate::{error::RogError, GetSupported}; +use ::zbus::export::futures_util::lock::Mutex; use log::{error, info, warn}; use rog_anime::{ error::AnimeError, - usb::{ - get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, - pkts_for_init, - }, + usb::{get_anime_type, pkt_for_flush, pkts_for_init}, ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, }; use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw}; use std::sync::atomic::{AtomicBool, Ordering}; use std::{convert::TryFrom, error::Error, sync::Arc, thread::sleep}; -use crate::{error::RogError, GetSupported}; - -use self::config::{AnimeConfig, AnimeConfigCached}; - impl GetSupported for CtrlAnime { type A = AnimeSupportedFunctions; @@ -214,85 +208,3 @@ impl CtrlAnime { Ok(()) } } - -pub struct CtrlAnimeTask { - inner: Arc>, -} - -impl CtrlAnimeTask { - pub async fn new(inner: Arc>) -> CtrlAnimeTask { - Self { inner } - } -} - -#[async_trait] -impl crate::CtrlTask for CtrlAnimeTask { - async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { - let run_action = - |start: bool, lock: MutexGuard, inner: Arc>| { - if start { - info!("CtrlAnimeTask running sleep animation"); - CtrlAnime::run_thread(inner.clone(), lock.cache.shutdown.clone(), true); - } else { - info!("CtrlAnimeTask running wake animation"); - CtrlAnime::run_thread(inner.clone(), lock.cache.wake.clone(), true); - } - }; - - let inner1 = self.inner.clone(); - let inner2 = self.inner.clone(); - let inner3 = self.inner.clone(); - let inner4 = self.inner.clone(); - self.create_sys_event_tasks( - // Loop is required to try an attempt to get the mutex *without* blocking - // other threads - it is possible to end up with deadlocks otherwise. - move || loop { - if let Some(lock) = inner1.try_lock() { - run_action(true, lock, inner1.clone()); - break; - } - }, - move || loop { - if let Some(lock) = inner2.try_lock() { - run_action(false, lock, inner2.clone()); - break; - } - }, - move || loop { - if let Some(lock) = inner3.try_lock() { - run_action(true, lock, inner3.clone()); - break; - } - }, - move || loop { - if let Some(lock) = inner4.try_lock() { - run_action(false, lock, inner4.clone()); - break; - } - }, - ) - .await; - - Ok(()) - } -} - -pub struct CtrlAnimeReloader(pub Arc>); - -#[async_trait] -impl crate::Reloadable for CtrlAnimeReloader { - async fn reload(&mut self) -> Result<(), RogError> { - if let Some(lock) = self.0.try_lock() { - lock.node - .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; - lock.node.write_bytes(&pkt_for_apply())?; - lock.node - .write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?; - lock.node.write_bytes(&pkt_for_apply())?; - - let action = lock.cache.boot.clone(); - CtrlAnime::run_thread(self.0.clone(), action, true); - } - Ok(()) - } -} diff --git a/daemon/src/ctrl_anime/zbus.rs b/daemon/src/ctrl_anime/trait_impls.rs similarity index 60% rename from daemon/src/ctrl_anime/zbus.rs rename to daemon/src/ctrl_anime/trait_impls.rs index a1210612..e005e4c0 100644 --- a/daemon/src/ctrl_anime/zbus.rs +++ b/daemon/src/ctrl_anime/trait_impls.rs @@ -1,22 +1,28 @@ +use super::CtrlAnime; +use crate::error::RogError; use async_trait::async_trait; -use log::warn; +use log::{info, warn}; use rog_anime::{ usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, AnimeDataBuffer, AnimePowerStates, }; -use zbus::{dbus_interface, export::futures_util::lock::Mutex, Connection, SignalContext}; - use std::sync::{atomic::Ordering, Arc}; +use zbus::{ + dbus_interface, + export::futures_util::lock::{Mutex, MutexGuard}, + Connection, SignalContext, +}; -use super::CtrlAnime; +pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Anime"; +#[derive(Clone)] pub struct CtrlAnimeZbus(pub Arc>); /// The struct with the main dbus methods requires this trait #[async_trait] impl crate::ZbusRun for CtrlAnimeZbus { async fn add_to_server(self, server: &mut Connection) { - Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await; + Self::add_to_server_helper(self, ZBUS_PATH, server).await; } } @@ -134,3 +140,77 @@ impl CtrlAnimeZbus { data: AnimePowerStates, ) -> zbus::Result<()>; } + +#[async_trait] +impl crate::CtrlTask for CtrlAnimeZbus { + fn zbus_path() -> &'static str { + ZBUS_PATH + } + + async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { + let run_action = + |start: bool, lock: MutexGuard, inner: Arc>| { + if start { + info!("CtrlAnimeTask running sleep animation"); + CtrlAnime::run_thread(inner.clone(), lock.cache.shutdown.clone(), true); + } else { + info!("CtrlAnimeTask running wake animation"); + CtrlAnime::run_thread(inner.clone(), lock.cache.wake.clone(), true); + } + }; + + let inner1 = self.0.clone(); + let inner2 = self.0.clone(); + let inner3 = self.0.clone(); + let inner4 = self.0.clone(); + self.create_sys_event_tasks( + // Loop is required to try an attempt to get the mutex *without* blocking + // other threads - it is possible to end up with deadlocks otherwise. + move || loop { + if let Some(lock) = inner1.try_lock() { + run_action(true, lock, inner1.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner2.try_lock() { + run_action(false, lock, inner2.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner3.try_lock() { + run_action(true, lock, inner3.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner4.try_lock() { + run_action(false, lock, inner4.clone()); + break; + } + }, + ) + .await; + + Ok(()) + } +} + +#[async_trait] +impl crate::Reloadable for CtrlAnimeZbus { + async fn reload(&mut self) -> Result<(), RogError> { + if let Some(lock) = self.0.try_lock() { + lock.node + .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; + lock.node.write_bytes(&pkt_for_apply())?; + lock.node + .write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?; + lock.node.write_bytes(&pkt_for_apply())?; + + let action = lock.cache.boot.clone(); + CtrlAnime::run_thread(self.0.clone(), action, true); + } + Ok(()) + } +} diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index e7c1833d..4ad21fad 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -1,10 +1,8 @@ use crate::{ error::RogError, laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, - CtrlTask, }; -use async_trait::async_trait; -use log::{error, info, warn}; +use log::{info, warn}; use rog_aura::{ usb::{AuraDevice, LED_APPLY, LED_SET}, AuraEffect, KeyColourArray, LedBrightness, PerKeyRaw, LED_MSG_LEN, @@ -12,14 +10,6 @@ use rog_aura::{ use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions}; use std::collections::BTreeMap; -use std::sync::Arc; -use zbus::{ - export::futures_util::{ - lock::{Mutex, MutexGuard}, - StreamExt, - }, - SignalContext, -}; use crate::GetSupported; @@ -78,119 +68,6 @@ pub struct CtrlKbdLed { pub config: AuraConfig, } -pub struct CtrlKbdLedTask { - inner: Arc>, -} - -impl CtrlKbdLedTask { - pub fn new(inner: Arc>) -> Self { - Self { inner } - } - - fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { - let bright = lock.kd_brightness.get_brightness()?; - lock.config.read(); - lock.config.brightness = (bright as u32).into(); - lock.config.write(); - return Ok(()); - } -} - -#[async_trait] -impl CtrlTask for CtrlKbdLedTask { - async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { - let load_save = |start: bool, mut lock: MutexGuard| { - // If waking up - if !start { - info!("CtrlKbdLedTask reloading brightness and modes"); - lock.set_brightness(lock.config.brightness) - .map_err(|e| error!("CtrlKbdLedTask: {e}")) - .ok(); - lock.write_current_config_mode() - .map_err(|e| error!("CtrlKbdLedTask: {e}")) - .ok(); - } else if start { - info!("CtrlKbdLedTask saving last brightness"); - Self::update_config(&mut lock) - .map_err(|e| error!("CtrlKbdLedTask: {e}")) - .ok(); - } - }; - - let inner1 = self.inner.clone(); - let inner2 = self.inner.clone(); - let inner3 = self.inner.clone(); - let inner4 = self.inner.clone(); - self.create_sys_event_tasks( - // Loop so that we do aquire the lock but also don't block other - // threads (prevents potential deadlocks) - move || loop { - if let Some(lock) = inner1.try_lock() { - load_save(true, lock); - break; - } - }, - move || loop { - if let Some(lock) = inner2.try_lock() { - load_save(false, lock); - break; - } - }, - move || loop { - if let Some(lock) = inner3.try_lock() { - load_save(true, lock); - break; - } - }, - move || loop { - if let Some(lock) = inner4.try_lock() { - load_save(false, lock); - break; - } - }, - ) - .await; - - let ctrl2 = self.inner.clone(); - let ctrl = self.inner.lock().await; - let mut watch = ctrl.kd_brightness.monitor_brightness()?; - tokio::spawn(async move { - let mut buffer = [0; 32]; - watch - .event_stream(&mut buffer) - .unwrap() - .for_each(|_| async { - if let Some(lock) = ctrl2.try_lock() { - load_save(true, lock); - } - }) - .await; - }); - - Ok(()) - } -} - -pub struct CtrlKbdLedReloader(pub Arc>); - -#[async_trait] -impl crate::Reloadable for CtrlKbdLedReloader { - async fn reload(&mut self) -> Result<(), RogError> { - let mut ctrl = self.0.lock().await; - ctrl.write_current_config_mode()?; - ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); - Ok(()) - } -} - -pub struct CtrlKbdLedZbus(pub Arc>); - -impl CtrlKbdLedZbus { - pub fn new(inner: Arc>) -> Self { - Self(inner) - } -} - impl CtrlKbdLed { pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result { let mut led_prod = None; @@ -412,7 +289,7 @@ impl CtrlKbdLed { Ok(()) } - fn write_current_config_mode(&mut self) -> Result<(), RogError> { + pub(super) fn write_current_config_mode(&mut self) -> Result<(), RogError> { if self.config.multizone_on { let mode = self.config.current_mode; let mut create = false; diff --git a/daemon/src/ctrl_aura/mod.rs b/daemon/src/ctrl_aura/mod.rs index 85a4d229..9c365c20 100644 --- a/daemon/src/ctrl_aura/mod.rs +++ b/daemon/src/ctrl_aura/mod.rs @@ -1,3 +1,4 @@ pub mod config; pub mod controller; -pub mod zbus; +/// Implements CtrlTask, Reloadable, ZbusRun +pub mod trait_impls; diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/trait_impls.rs similarity index 60% rename from daemon/src/ctrl_aura/zbus.rs rename to daemon/src/ctrl_aura/trait_impls.rs index 2849b749..39b24afd 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/trait_impls.rs @@ -1,16 +1,39 @@ -use std::collections::BTreeMap; - use async_trait::async_trait; -use log::warn; +use log::{error, info, warn}; use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw}; -use zbus::{dbus_interface, Connection, SignalContext}; +use std::{collections::BTreeMap, sync::Arc}; +use zbus::{ + dbus_interface, + export::futures_util::{ + lock::{Mutex, MutexGuard}, + StreamExt, + }, + Connection, SignalContext, +}; -use super::controller::CtrlKbdLedZbus; +use crate::{error::RogError, CtrlTask}; + +use super::controller::CtrlKbdLed; + +pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Aura"; + +#[derive(Clone)] +pub struct CtrlKbdLedZbus(pub Arc>); + +impl CtrlKbdLedZbus { + fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { + let bright = lock.kd_brightness.get_brightness()?; + lock.config.read(); + lock.config.brightness = (bright as u32).into(); + lock.config.write(); + return Ok(()); + } +} #[async_trait] impl crate::ZbusRun for CtrlKbdLedZbus { async fn add_to_server(self, server: &mut Connection) { - Self::add_to_server_helper(self, "/org/asuslinux/Aura", server).await; + Self::add_to_server_helper(self, ZBUS_PATH, server).await; } } @@ -206,3 +229,92 @@ impl CtrlKbdLedZbus { data: &AuraPowerDev, ) -> zbus::Result<()>; } + +#[async_trait] +impl CtrlTask for CtrlKbdLedZbus { + fn zbus_path() -> &'static str { + ZBUS_PATH + } + + async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { + let load_save = |start: bool, mut lock: MutexGuard| { + // If waking up + if !start { + info!("CtrlKbdLedTask reloading brightness and modes"); + lock.set_brightness(lock.config.brightness) + .map_err(|e| error!("CtrlKbdLedTask: {e}")) + .ok(); + lock.write_current_config_mode() + .map_err(|e| error!("CtrlKbdLedTask: {e}")) + .ok(); + } else if start { + info!("CtrlKbdLedTask saving last brightness"); + Self::update_config(&mut lock) + .map_err(|e| error!("CtrlKbdLedTask: {e}")) + .ok(); + } + }; + + let inner1 = self.0.clone(); + let inner2 = self.0.clone(); + let inner3 = self.0.clone(); + let inner4 = self.0.clone(); + self.create_sys_event_tasks( + // Loop so that we do aquire the lock but also don't block other + // threads (prevents potential deadlocks) + move || loop { + if let Some(lock) = inner1.try_lock() { + load_save(true, lock); + break; + } + }, + move || loop { + if let Some(lock) = inner2.try_lock() { + load_save(false, lock); + break; + } + }, + move || loop { + if let Some(lock) = inner3.try_lock() { + load_save(true, lock); + break; + } + }, + move || loop { + if let Some(lock) = inner4.try_lock() { + load_save(false, lock); + break; + } + }, + ) + .await; + + let ctrl2 = self.0.clone(); + let ctrl = self.0.lock().await; + let mut watch = ctrl.kd_brightness.monitor_brightness()?; + tokio::spawn(async move { + let mut buffer = [0; 32]; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + if let Some(lock) = ctrl2.try_lock() { + load_save(true, lock); + } + }) + .await; + }); + + Ok(()) + } +} + +#[async_trait] +impl crate::Reloadable for CtrlKbdLedZbus { + async fn reload(&mut self) -> Result<(), RogError> { + let mut ctrl = self.0.lock().await; + ctrl.write_current_config_mode()?; + ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); + Ok(()) + } +} diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 7c89e158..27c00e7d 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -13,16 +13,17 @@ use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::{dbus_interface, SignalContext}; -static ASUS_POST_LOGO_SOUND: &str = +const ZBUS_PATH: &str = "/org/asuslinux/Platform"; +const ASUS_POST_LOGO_SOUND: &str = "/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e"; #[derive(Clone)] -pub struct CtrlRogBios { +pub struct CtrlPlatform { platform: AsusPlatform, config: Arc>, } -impl GetSupported for CtrlRogBios { +impl GetSupported for CtrlPlatform { type A = RogBiosSupportedFunctions; fn get_supported() -> Self::A { @@ -48,7 +49,7 @@ impl GetSupported for CtrlRogBios { } } -impl CtrlRogBios { +impl CtrlPlatform { pub fn new(config: Arc>) -> Result { let platform = AsusPlatform::new()?; @@ -58,12 +59,12 @@ impl CtrlRogBios { } if Path::new(ASUS_POST_LOGO_SOUND).exists() { - CtrlRogBios::set_path_mutable(ASUS_POST_LOGO_SOUND)?; + CtrlPlatform::set_path_mutable(ASUS_POST_LOGO_SOUND)?; } else { info!("Switch for POST boot sound not detected"); } - Ok(CtrlRogBios { platform, config }) + Ok(CtrlPlatform { platform, config }) } fn set_path_mutable(path: &str) -> Result<(), RogError> { @@ -138,7 +139,7 @@ impl CtrlRogBios { } #[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlRogBios { +impl CtrlPlatform { async fn set_gpu_mux_mode( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, @@ -241,14 +242,14 @@ impl CtrlRogBios { } #[async_trait] -impl crate::ZbusRun for CtrlRogBios { +impl crate::ZbusRun for CtrlPlatform { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Platform", server).await; } } #[async_trait] -impl crate::Reloadable for CtrlRogBios { +impl crate::Reloadable for CtrlPlatform { async fn reload(&mut self) -> Result<(), RogError> { if self.platform.has_panel_od() { let p = if let Some(lock) = self.config.try_lock() { @@ -262,13 +263,17 @@ impl crate::Reloadable for CtrlRogBios { } } -impl CtrlRogBios { +impl CtrlPlatform { task_watch_item!(panel_od platform); task_watch_item!(gpu_mux_mode platform); } #[async_trait] -impl CtrlTask for CtrlRogBios { +impl CtrlTask for CtrlPlatform { + fn zbus_path() -> &'static str { + ZBUS_PATH + } + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let platform1 = self.clone(); let platform2 = self.clone(); diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index aef69094..268a3c0b 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -10,6 +10,8 @@ use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::SignalContext; +const ZBUS_PATH: &str = "/org/asuslinux/Power"; + impl GetSupported for CtrlPower { type A = ChargeSupportedFunctions; @@ -82,7 +84,7 @@ impl CtrlPower { #[async_trait] impl crate::ZbusRun for CtrlPower { async fn add_to_server(self, server: &mut Connection) { - Self::add_to_server_helper(self, "/org/asuslinux/Charge", server).await; + Self::add_to_server_helper(self, ZBUS_PATH, server).await; } } @@ -128,6 +130,10 @@ impl CtrlPower { #[async_trait] impl CtrlTask for CtrlPower { + fn zbus_path() -> &'static str { + ZBUS_PATH + } + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let power1 = self.clone(); let power2 = self.clone(); diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index ae7a3f2f..331a1458 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,6 +1,5 @@ use crate::error::RogError; use crate::GetSupported; -use async_trait::async_trait; use log::{info, warn}; use rog_platform::platform::AsusPlatform; use rog_platform::supported::PlatformProfileFunctions; @@ -39,22 +38,6 @@ impl GetSupported for CtrlPlatformProfile { } } -#[async_trait] -impl crate::Reloadable for CtrlPlatformProfile { - /// Fetch the active profile and use that to set all related components up - async fn reload(&mut self) -> Result<(), RogError> { - if let Some(curves) = &mut self.config.fan_curves { - if let Ok(mut device) = FanCurveProfiles::get_device() { - // There is a possibility that the curve was default zeroed, so this call initialises - // the data from system read and we need to save it after - curves.write_profile_curve_to_platform(self.config.active_profile, &mut device)?; - self.config.write(); - } - } - Ok(()) - } -} - impl CtrlPlatformProfile { pub fn new(config: ProfileConfig) -> Result { let platform = AsusPlatform::new()?; diff --git a/daemon/src/ctrl_profiles/mod.rs b/daemon/src/ctrl_profiles/mod.rs index 85a4d229..9c365c20 100644 --- a/daemon/src/ctrl_profiles/mod.rs +++ b/daemon/src/ctrl_profiles/mod.rs @@ -1,3 +1,4 @@ pub mod config; pub mod controller; -pub mod zbus; +/// Implements CtrlTask, Reloadable, ZbusRun +pub mod trait_impls; diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/trait_impls.rs similarity index 81% rename from daemon/src/ctrl_profiles/zbus.rs rename to daemon/src/ctrl_profiles/trait_impls.rs index ab8b44bf..b8f1f8eb 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/trait_impls.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use log::warn; use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::FanCurveSet; +use rog_profiles::FanCurveProfiles; use rog_profiles::Profile; use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::StreamExt; @@ -16,18 +17,12 @@ use crate::CtrlTask; use super::controller::CtrlPlatformProfile; -static UNSUPPORTED_MSG: &str = +const ZBUS_PATH: &str = "/org/asuslinux/Profile"; +const UNSUPPORTED_MSG: &str = "Fan curves are not supported on this laptop or you require a patched kernel"; -pub struct ProfileZbus { - inner: Arc>, -} - -impl ProfileZbus { - pub fn new(inner: Arc>) -> Self { - Self { inner } - } -} +#[derive(Clone)] +pub struct ProfileZbus(pub Arc>); #[dbus_interface(name = "org.asuslinux.Daemon")] impl ProfileZbus { @@ -44,7 +39,7 @@ impl ProfileZbus { /// Toggle to next platform_profile. Names provided by `Profiles`. /// If fan-curves are supported will also activate a fan curve for profile. async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.set_next_profile() .unwrap_or_else(|err| warn!("{}", err)); ctrl.save_config(); @@ -56,7 +51,7 @@ impl ProfileZbus { /// Fetch the active profile name async fn active_profile(&mut self) -> zbus::fdo::Result { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); Ok(ctrl.config.active_profile) } @@ -67,7 +62,7 @@ impl ProfileZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, profile: Profile, ) { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; // Read first just incase the user has modified the config before calling this ctrl.config.read(); Profile::set_profile(profile) @@ -87,7 +82,7 @@ impl ProfileZbus { /// Get a list of profiles that have fan-curves enabled. async fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); if let Some(curves) = &ctrl.config.fan_curves { return Ok(curves.get_enabled_curve_profiles().to_vec()); @@ -102,7 +97,7 @@ impl ProfileZbus { profile: Profile, enabled: bool, ) -> zbus::fdo::Result<()> { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); return if let Some(curves) = &mut ctrl.config.fan_curves { curves.set_profile_curve_enabled(profile, enabled); @@ -120,7 +115,7 @@ impl ProfileZbus { /// Get the fan-curve data for the currently active Profile async fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); if let Some(curves) = &ctrl.config.fan_curves { let curve = curves.get_fan_curves_for(profile); @@ -132,7 +127,7 @@ impl ProfileZbus { /// Set the fan curve for the specified profile. /// Will also activate the fan curve if the user is in the same mode. async fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); if let Some(curves) = &mut ctrl.config.fan_curves { curves @@ -154,7 +149,7 @@ impl ProfileZbus { /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. async fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); ctrl.set_active_curve_to_defaults() .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) @@ -168,7 +163,7 @@ impl ProfileZbus { /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. async fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { - let mut ctrl = self.inner.lock().await; + let mut ctrl = self.0.lock().await; ctrl.config.read(); let active = Profile::get_active_profile().unwrap_or(Profile::Balanced); @@ -194,20 +189,19 @@ impl ProfileZbus { #[async_trait] impl crate::ZbusRun for ProfileZbus { async fn add_to_server(self, server: &mut Connection) { - Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await; + Self::add_to_server_helper(self, ZBUS_PATH, server).await; } } #[async_trait] impl CtrlTask for ProfileZbus { + fn zbus_path() -> &'static str { + ZBUS_PATH + } + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { - let ctrl = self.inner.clone(); - let mut watch = self - .inner - .lock() - .await - .platform - .monitor_platform_profile()?; + let ctrl = self.0.clone(); + let mut watch = self.0.lock().await.platform.monitor_platform_profile()?; tokio::spawn(async move { let mut buffer = [0; 32]; @@ -233,3 +227,21 @@ impl CtrlTask for ProfileZbus { Ok(()) } } + +#[async_trait] +impl crate::Reloadable for ProfileZbus { + /// Fetch the active profile and use that to set all related components up + async fn reload(&mut self) -> Result<(), RogError> { + let mut ctrl = self.0.lock().await; + let active = ctrl.config.active_profile; + if let Some(curves) = &mut ctrl.config.fan_curves { + if let Ok(mut device) = FanCurveProfiles::get_device() { + // There is a possibility that the curve was default zeroed, so this call initialises + // the data from system read and we need to save it after + curves.write_profile_curve_to_platform(active, &mut device)?; + ctrl.config.write(); + } + } + Ok(()) + } +} diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 9fe99a15..993d8271 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -5,7 +5,7 @@ use zbus::Connection; use zvariant::Type; use crate::{ - ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlRogBios, + ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlPlatform, ctrl_power::CtrlPower, ctrl_profiles::controller::CtrlPlatformProfile, GetSupported, }; @@ -43,7 +43,7 @@ impl GetSupported for SupportedFunctions { keyboard_led: CtrlKbdLed::get_supported(), charge_ctrl: CtrlPower::get_supported(), platform_profile: CtrlPlatformProfile::get_supported(), - rog_bios_ctrl: CtrlRogBios::get_supported(), + rog_bios_ctrl: CtrlPlatform::get_supported(), } } } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 9796f7d3..e093dc1e 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -5,28 +5,23 @@ use std::sync::Arc; use std::time::Duration; use ::zbus::export::futures_util::lock::Mutex; -use ::zbus::{Connection, SignalContext}; +use ::zbus::Connection; +use daemon::ctrl_anime::CtrlAnime; use log::LevelFilter; use log::{error, info, warn}; use tokio::time::sleep; -use daemon::ctrl_anime::config::AnimeConfig; -use daemon::ctrl_anime::zbus::CtrlAnimeZbus; -use daemon::ctrl_anime::*; -use daemon::ctrl_aura::config::AuraConfig; -use daemon::ctrl_aura::controller::{ - CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus, -}; -use daemon::ctrl_platform::CtrlRogBios; +use daemon::ctrl_anime::{config::AnimeConfig, trait_impls::CtrlAnimeZbus}; +use daemon::ctrl_aura::{config::AuraConfig, controller::CtrlKbdLed, trait_impls::CtrlKbdLedZbus}; +use daemon::ctrl_platform::CtrlPlatform; use daemon::ctrl_power::CtrlPower; -use daemon::ctrl_profiles::config::ProfileConfig; +use daemon::ctrl_profiles::{ + config::ProfileConfig, controller::CtrlPlatformProfile, trait_impls::ProfileZbus, +}; +use daemon::laptops::LaptopLedData; use daemon::{ config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, }; -use daemon::{ - ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, - laptops::LaptopLedData, -}; use daemon::{CtrlTask, Reloadable, ZbusRun}; use rog_dbus::DBUS_NAME; use rog_profiles::Profile; @@ -81,80 +76,43 @@ async fn start_daemon() -> Result<(), Box> { supported.add_to_server(&mut connection).await; - match CtrlRogBios::new(config.clone()) { - Ok(mut ctrl) => { - // Do a reload of any settings - ctrl.reload() - .await - .unwrap_or_else(|err| warn!("CtrlRogBios: {}", err)); - // Then register to dbus server - ctrl.add_to_server(&mut connection).await; - - let task = CtrlRogBios::new(config.clone())?; - let sig = SignalContext::new(&connection, "/org/asuslinux/Platform")?; - task.create_tasks(sig).await.ok(); + match CtrlPlatform::new(config.clone()) { + Ok(ctrl) => { + start_tasks(ctrl, &mut connection).await?; } Err(err) => { - error!("rog_bios_control: {}", err); + error!("CtrlPlatform: {}", err); } } match CtrlPower::new(config.clone()) { - Ok(mut ctrl) => { - // Do a reload of any settings - ctrl.reload() - .await - .unwrap_or_else(|err| warn!("CtrlPower: {}", err)); - // Then register to dbus server - ctrl.add_to_server(&mut connection).await; - - let task = CtrlPower::new(config)?; - let sig = SignalContext::new(&connection, "/org/asuslinux/Charge")?; - task.create_tasks(sig).await.ok(); + Ok(ctrl) => { + start_tasks(ctrl, &mut connection).await?; } Err(err) => { - error!("charge_control: {}", err); + error!("CtrlPower: {}", err); } } if Profile::is_platform_profile_supported() { let profile_config = ProfileConfig::load(PROFILE_CONFIG_PATH.into()); match CtrlPlatformProfile::new(profile_config) { - Ok(mut ctrl) => { - ctrl.reload() - .await - .unwrap_or_else(|err| warn!("Profile control: {}", err)); - - let sig = SignalContext::new(&connection, "/org/asuslinux/Profile")?; - - let task = ProfileZbus::new(Arc::new(Mutex::new(ctrl))); - task.create_tasks(sig).await.ok(); - task.add_to_server(&mut connection).await; + Ok(ctrl) => { + let zbus = ProfileZbus(Arc::new(Mutex::new(ctrl))); + start_tasks(zbus, &mut connection).await?; } Err(err) => { error!("Profile control: {}", err); } } } else { - warn!("platform_profile support not found. This requires kernel 5.15.x or the patch applied: https://lkml.org/lkml/2021/8/18/1022"); + warn!("platform_profile support not found"); } match CtrlAnime::new(AnimeConfig::load()) { Ok(ctrl) => { - let inner = Arc::new(Mutex::new(ctrl)); - - let mut reload = CtrlAnimeReloader(inner.clone()); - reload - .reload() - .await - .unwrap_or_else(|err| warn!("AniMe: {}", err)); - - let zbus = CtrlAnimeZbus(inner.clone()); - zbus.add_to_server(&mut connection).await; - - let task = CtrlAnimeTask::new(inner).await; - let sig = SignalContext::new(&connection, "/org/asuslinux/Anime")?; - task.create_tasks(sig).await.ok(); + let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl))); + start_tasks(zbus, &mut connection).await?; } Err(err) => { error!("AniMe control: {}", err); @@ -165,21 +123,8 @@ async fn start_daemon() -> Result<(), Box> { let aura_config = AuraConfig::load(&laptop); match CtrlKbdLed::new(laptop, aura_config) { Ok(ctrl) => { - let inner = Arc::new(Mutex::new(ctrl)); - - let mut reload = CtrlKbdLedReloader(inner.clone()); - reload - .reload() - .await - .unwrap_or_else(|err| warn!("Keyboard LED control: {}", err)); - - CtrlKbdLedZbus::new(inner.clone()) - .add_to_server(&mut connection) - .await; - - let task = CtrlKbdLedTask::new(inner); - let sig = SignalContext::new(&connection, "/org/asuslinux/Aura")?; - task.create_tasks(sig).await.ok(); + let zbus = CtrlKbdLedZbus(Arc::new(Mutex::new(ctrl))); + start_tasks(zbus, &mut connection).await?; } Err(err) => { error!("Keyboard control: {}", err); @@ -194,3 +139,20 @@ async fn start_daemon() -> Result<(), Box> { sleep(Duration::from_millis(1000)).await; } } + +async fn start_tasks(mut zbus: T, connection: &mut Connection) -> Result<(), Box> +where + T: ZbusRun + Reloadable + CtrlTask + Clone, +{ + let task = zbus.clone(); + + zbus.reload() + .await + .unwrap_or_else(|err| warn!("Controller error: {}", err)); + zbus.add_to_server(connection).await; + + task.create_tasks(CtrlKbdLedZbus::signal_context(&connection)?) + .await + .ok(); + Ok(()) +} diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index bb6c41c1..31881edd 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -26,34 +26,6 @@ use logind_zbus::manager::ManagerProxy; use zbus::{export::futures_util::StreamExt, Connection, SignalContext}; use zvariant::ObjectPath; -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); - -#[async_trait] -pub trait Reloadable { - async fn reload(&mut self) -> Result<(), RogError>; -} - -#[async_trait] -pub trait ZbusRun { - async fn add_to_server(self, server: &mut Connection); - - async fn add_to_server_helper( - iface: impl zbus::Interface, - path: &str, - server: &mut Connection, - ) { - server - .object_server() - .at(&ObjectPath::from_str_unchecked(path), iface) - .await - .map_err(|err| { - warn!("{}: add_to_server {}", path, err); - err - }) - .ok(); - } -} - /// This macro adds a function which spawns an `inotify` task on the passed in `Executor`. /// /// The generated function is `watch_()`. Self requires the following methods to be available: @@ -101,9 +73,43 @@ macro_rules! task_watch_item { }; } +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[async_trait] +pub trait Reloadable { + async fn reload(&mut self) -> Result<(), RogError>; +} + +#[async_trait] +pub trait ZbusRun { + async fn add_to_server(self, server: &mut Connection); + + async fn add_to_server_helper( + iface: impl zbus::Interface, + path: &str, + server: &mut Connection, + ) { + server + .object_server() + .at(&ObjectPath::from_str_unchecked(path), iface) + .await + .map_err(|err| { + warn!("{}: add_to_server {}", path, err); + err + }) + .ok(); + } +} + /// Set up a task to run on the async executor #[async_trait] pub trait CtrlTask { + fn zbus_path() -> &'static str; + + fn signal_context(connection: &Connection) -> Result, zbus::Error> { + SignalContext::new(connection, Self::zbus_path()) + } + /// Implement to set up various tasks that may be required, using the `Executor`. /// No blocking loops are allowed, or they must be run on a separate thread. async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; diff --git a/design-patterns.md b/design-patterns.md index 8b21e1bf..abe6f135 100644 --- a/design-patterns.md +++ b/design-patterns.md @@ -18,35 +18,43 @@ Then for each trait that is required a new struct is required that can have the Main controller: +For a very simple controller that doesn't need exclusive access you can clone across threads + ```rust -/// For a very simple controller that doesn't need exclusive access you can clone across threads #[derive(Clone)] pub struct CtrlAnime { config: Arc>, } +// This is the task trait used for such things as file watches, or logind +// notifications (boot/suspend/shutdown etc) impl crate::CtrlTask for CtrlAnime {} + +// The trait to easily add the controller to Zbus to enable the zbus derived functions +// to be polled, run, react etc. impl crate::ZbusAdd for CtrlAnime {} impl CtrlAnime {} ``` + Otherwise, you will need to share the controller via mutex + ```rust -/// Otherwise, you will need to share the controller via mutex pub struct CtrlAnime { } // Like this #[derive(Clone)] pub struct CtrlAnimeTask(Arc>); + #[derive(Clone)] pub struct CtrlAnimeZbus(Arc>); impl CtrlAnime {} ``` -The task trait. There are three ways to implement this: +The task trait: ```rust // Mutex should always be async mutex diff --git a/rog-control-center/src/notify.rs b/rog-control-center/src/notify.rs index 80092770..8c6fc275 100644 --- a/rog-control-center/src/notify.rs +++ b/rog-control-center/src/notify.rs @@ -4,8 +4,8 @@ use notify_rust::{Hint, Notification, NotificationHandle}; use rog_aura::AuraEffect; use rog_dbus::{ - zbus_anime::AnimeProxy, zbus_charge::ChargeProxy, zbus_led::LedProxy, - zbus_platform::RogBiosProxy, zbus_profile::ProfileProxy, + zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy, + zbus_power::PowerProxy, zbus_profile::ProfileProxy, }; use rog_profiles::Profile; use smol::{future, Executor}; @@ -102,7 +102,7 @@ pub fn start_notifications( executor .spawn(async move { let conn = zbus::Connection::system().await.unwrap(); - let proxy = ChargeProxy::new(&conn).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() { diff --git a/rog-dbus/src/lib.rs b/rog-dbus/src/lib.rs index b44eb28b..1bd15dd7 100644 --- a/rog-dbus/src/lib.rs +++ b/rog-dbus/src/lib.rs @@ -3,9 +3,9 @@ pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; pub mod zbus_anime; -pub mod zbus_charge; pub mod zbus_led; pub mod zbus_platform; +pub mod zbus_power; pub mod zbus_profile; pub mod zbus_supported; @@ -19,7 +19,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub struct DbusProxiesBlocking<'a> { anime: zbus_anime::AnimeProxyBlocking<'a>, - charge: zbus_charge::ChargeProxyBlocking<'a>, + charge: zbus_power::PowerProxyBlocking<'a>, led: zbus_led::LedProxyBlocking<'a>, profile: zbus_profile::ProfileProxyBlocking<'a>, rog_bios: zbus_platform::RogBiosProxyBlocking<'a>, @@ -35,7 +35,7 @@ impl<'a> DbusProxiesBlocking<'a> { DbusProxiesBlocking { anime: zbus_anime::AnimeProxyBlocking::new(&conn)?, led: zbus_led::LedProxyBlocking::new(&conn)?, - charge: zbus_charge::ChargeProxyBlocking::new(&conn)?, + charge: zbus_power::PowerProxyBlocking::new(&conn)?, profile: zbus_profile::ProfileProxyBlocking::new(&conn)?, rog_bios: zbus_platform::RogBiosProxyBlocking::new(&conn)?, supported: zbus_supported::SupportedProxyBlocking::new(&conn)?, @@ -48,7 +48,7 @@ impl<'a> DbusProxiesBlocking<'a> { &self.anime } - pub fn charge(&self) -> &zbus_charge::ChargeProxyBlocking<'a> { + pub fn charge(&self) -> &zbus_power::PowerProxyBlocking<'a> { &self.charge } @@ -88,7 +88,7 @@ impl<'a> RogDbusClientBlocking<'a> { pub struct DbusProxies<'a> { anime: zbus_anime::AnimeProxy<'a>, - charge: zbus_charge::ChargeProxy<'a>, + charge: zbus_power::PowerProxy<'a>, led: zbus_led::LedProxy<'a>, profile: zbus_profile::ProfileProxy<'a>, rog_bios: zbus_platform::RogBiosProxy<'a>, @@ -104,7 +104,7 @@ impl<'a> DbusProxies<'a> { DbusProxies { anime: zbus_anime::AnimeProxy::new(&conn).await?, led: zbus_led::LedProxy::new(&conn).await?, - charge: zbus_charge::ChargeProxy::new(&conn).await?, + charge: zbus_power::PowerProxy::new(&conn).await?, profile: zbus_profile::ProfileProxy::new(&conn).await?, rog_bios: zbus_platform::RogBiosProxy::new(&conn).await?, supported: zbus_supported::SupportedProxy::new(&conn).await?, @@ -117,7 +117,7 @@ impl<'a> DbusProxies<'a> { &self.anime } - pub fn charge(&self) -> &zbus_charge::ChargeProxy<'a> { + pub fn charge(&self) -> &zbus_power::PowerProxy<'a> { &self.charge } diff --git a/rog-dbus/src/zbus_charge.rs b/rog-dbus/src/zbus_power.rs similarity index 95% rename from rog-dbus/src/zbus_charge.rs rename to rog-dbus/src/zbus_power.rs index ca93550b..4b242d83 100644 --- a/rog-dbus/src/zbus_charge.rs +++ b/rog-dbus/src/zbus_power.rs @@ -23,9 +23,9 @@ use zbus_macros::dbus_proxy; #[dbus_proxy( interface = "org.asuslinux.Daemon", - default_path = "/org/asuslinux/Charge" + default_path = "/org/asuslinux/Power" )] -trait Charge { +trait Power { /// charge_control_end_threshold method fn charge_control_end_threshold(&self) -> zbus::Result; From 7939b00aa3811b3b34326fc646e38ccc0936f496 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 24 Sep 2022 14:34:15 +1200 Subject: [PATCH 11/11] Check inotify paths are valid. Add dgu/egpu/ac_online checks --- CHANGELOG.md | 9 ++++ Cargo.lock | 2 +- asus-notify/src/main.rs | 2 +- daemon/Cargo.toml | 2 +- daemon/src/ctrl_platform.rs | 73 ++++++++++++++++++++++++++++++- daemon/src/ctrl_power.rs | 37 +++++++++++++++- daemon/src/daemon.rs | 2 +- daemon/src/lib.rs | 22 ++++++---- rog-control-center/src/mocking.rs | 6 +-- rog-control-center/src/notify.rs | 2 +- rog-dbus/src/zbus_platform.rs | 44 ++++++++++++++----- rog-dbus/src/zbus_power.rs | 7 +++ rog-platform/src/error.rs | 12 ++++- rog-platform/src/hid_raw.rs | 10 +++-- rog-platform/src/lib.rs | 6 +-- rog-platform/src/macros.rs | 16 +++++-- rog-platform/src/power.rs | 1 + 17 files changed, 210 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a203535..c4df0bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `platform_profile` - keyboard brightness - These allow for updating any associated config and sending dbus notifications. +- New dbus methods + - `DgpuDisable` + - `SetDgpuDisable` + - `NotifyDgpuDisable` + - `EgpuEnable` + - `SetEgpuEnable` + - `NotifyEgpuEnable` + - `MainsOnline` (This is AC, check if plugged in or not) + - `NotifyMainsOnline` ### Changed - Use loops to ensure that mutex is gained for LED changes. - asusctl now uses tokio for async runtime. This helps simplify some code. diff --git a/Cargo.lock b/Cargo.lock index ac355b19..ca9e659b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,7 +572,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.5.0-rc2" +version = "4.5.0-rc3" dependencies = [ "async-trait", "concat-idents", diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index 3d0016d1..bfd64f18 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -54,7 +54,7 @@ fn main() -> Result<(), Box> { p.for_each(|e| { if let Ok(out) = e.args() { if let Ok(ref mut lock) = x.try_lock() { - notify!(do_post_sound_notif, lock, &out.sound()); + notify!(do_post_sound_notif, lock, &out.on()); } } future::ready(()) diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index d1f69bcf..5177b65a 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.5.0-rc2" +version = "4.5.0-rc3" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index 27c00e7d..77063d30 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -225,7 +225,7 @@ impl CtrlPlatform { .platform .get_panel_od() .map_err(|err| { - warn!("CtrlRogBios: get panel overdrive {}", err); + warn!("CtrlRogBios: get_panel_od {}", err); err }) .unwrap_or(false); @@ -239,6 +239,73 @@ impl CtrlPlatform { #[dbus_interface(signal)] async fn notify_panel_od(signal_ctxt: &SignalContext<'_>, overdrive: bool) -> zbus::Result<()> { } + + async fn set_dgpu_disable( + &mut self, + #[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(); + } + } + + fn dgpu_disable(&self) -> bool { + self.platform + .get_dgpu_disable() + .map_err(|err| { + warn!("CtrlRogBios: get_dgpu_disable {}", err); + err + }) + .unwrap_or(false) + } + + #[dbus_interface(signal)] + async fn notify_dgpu_disable( + signal_ctxt: &SignalContext<'_>, + disable: bool, + ) -> zbus::Result<()> { + } + + async fn set_egpu_enable( + &mut self, + #[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(); + } + } + + fn egpu_enable(&self) -> bool { + self.platform + .get_egpu_enable() + .map_err(|err| { + warn!("CtrlRogBios: get_egpu_enable {}", err); + err + }) + .unwrap_or(false) + } + + #[dbus_interface(signal)] + async fn notify_egpu_enable(signal_ctxt: &SignalContext<'_>, enable: bool) -> zbus::Result<()> { + } } #[async_trait] @@ -265,6 +332,8 @@ impl crate::Reloadable for CtrlPlatform { impl CtrlPlatform { task_watch_item!(panel_od platform); + task_watch_item!(dgpu_disable platform); + task_watch_item!(egpu_enable platform); task_watch_item!(gpu_mux_mode platform); } @@ -312,6 +381,8 @@ impl CtrlTask for CtrlPlatform { .await; self.watch_panel_od(signal_ctxt.clone()).await?; + self.watch_dgpu_disable(signal_ctxt.clone()).await?; + self.watch_egpu_enable(signal_ctxt.clone()).await?; self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; Ok(()) diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 268a3c0b..dab60300 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -7,6 +7,7 @@ use rog_platform::supported::ChargeSupportedFunctions; use std::sync::Arc; use zbus::dbus_interface; use zbus::export::futures_util::lock::Mutex; +use zbus::export::futures_util::StreamExt; use zbus::Connection; use zbus::SignalContext; @@ -74,11 +75,23 @@ impl CtrlPower { } } + fn mains_online(&self) -> bool { + if self.power.has_online() { + if let Ok(v) = self.power.get_online() { + return v == 1; + } + } + false + } + #[dbus_interface(signal)] async fn notify_charge_control_end_threshold( ctxt: &SignalContext<'_>, limit: u8, ) -> zbus::Result<()>; + + #[dbus_interface(signal)] + async fn notify_mains_online(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()>; } #[async_trait] @@ -167,7 +180,29 @@ impl CtrlTask for CtrlPower { ) .await; - self.watch_charge_control_end_threshold(signal_ctxt).await?; + self.watch_charge_control_end_threshold(signal_ctxt.clone()) + .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; + }); + } + Err(e) => info!("inotify watch failed: {}", e), + } Ok(()) } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index e093dc1e..b9ced919 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -115,7 +115,7 @@ async fn start_daemon() -> Result<(), Box> { start_tasks(zbus, &mut connection).await?; } Err(err) => { - error!("AniMe control: {}", err); + info!("AniMe control: {}", err); } } diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 31881edd..281e8d3c 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -56,16 +56,20 @@ macro_rules! task_watch_item { let ctrl = self.clone(); concat_idents::concat_idents!(watch_fn = monitor_, $name { - let mut watch = self.$self_inner.watch_fn()?; - tokio::spawn(async move { - let mut buffer = [0; 32]; - watch.event_stream(&mut buffer).unwrap().for_each(|_| async { - let value = ctrl.$name(); - concat_idents::concat_idents!(notif_fn = notify_, $name { - Self::notif_fn(&signal_ctxt, value).await.unwrap(); + match self.$self_inner.watch_fn() { + Ok(mut watch) => { + tokio::spawn(async move { + let mut buffer = [0; 32]; + watch.event_stream(&mut buffer).unwrap().for_each(|_| async { + let value = ctrl.$name(); + concat_idents::concat_idents!(notif_fn = notify_, $name { + Self::notif_fn(&signal_ctxt, value).await.unwrap(); + }); + }).await; }); - }).await; - }); + } + Err(e) => info!("inotify watch failed: {}. You can ignore this if your device does not support the feature", e), + } }); Ok(()) } diff --git a/rog-control-center/src/mocking.rs b/rog-control-center/src/mocking.rs index f6cd60b8..7291c44c 100644 --- a/rog-control-center/src/mocking.rs +++ b/rog-control-center/src/mocking.rs @@ -65,7 +65,7 @@ impl Bios { pub fn gpu_mux_mode(&self) -> Result { Ok(1) } - pub fn panel_overdrive(&self) -> Result { + pub fn panel_od(&self) -> Result { Ok(1) } pub fn set_post_boot_sound(&self, _b: bool) -> Result<()> { @@ -74,7 +74,7 @@ impl Bios { pub fn set_gpu_mux_mode(&self, _b: bool) -> Result<()> { Ok(()) } - pub fn set_panel_overdrive(&self, _b: bool) -> Result<()> { + pub fn set_panel_od(&self, _b: bool) -> Result<()> { Ok(()) } } @@ -217,7 +217,7 @@ impl Supported { rog_bios_ctrl: RogBiosSupportedFunctions { post_sound: true, dedicated_gfx: true, - panel_overdrive: true, + panel_od: true, dgpu_disable: true, egpu_enable: true, }, diff --git a/rog-control-center/src/notify.rs b/rog-control-center/src/notify.rs index 8c6fc275..a8cb83f7 100644 --- a/rog-control-center/src/notify.rs +++ b/rog-control-center/src/notify.rs @@ -70,7 +70,7 @@ pub fn start_notifications( 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.sound()); + notify!(do_post_sound_notif, lock, &out.on()); } } bios_notified1.store(true, Ordering::SeqCst); diff --git a/rog-dbus/src/zbus_platform.rs b/rog-dbus/src/zbus_platform.rs index 404f3f37..b7824995 100644 --- a/rog-dbus/src/zbus_platform.rs +++ b/rog-dbus/src/zbus_platform.rs @@ -27,33 +27,53 @@ use zbus_macros::dbus_proxy; default_path = "/org/asuslinux/Platform" )] trait RogBios { - /// DedicatedGraphicMode method + /// DgpuDisable method + fn dgpu_disable(&self) -> zbus::Result; + + /// EgpuEnable method + fn egpu_enable(&self) -> zbus::Result; + + /// GpuMuxMode method fn gpu_mux_mode(&self) -> zbus::Result; + /// PanelOd method + fn panel_od(&self) -> zbus::Result; + /// PostBootSound method fn post_boot_sound(&self) -> zbus::Result; - /// SetDedicatedGraphicMode method + /// SetDgpuDisable method + fn set_dgpu_disable(&self, disable: bool) -> zbus::Result<()>; + + /// SetEgpuEnable method + fn set_egpu_enable(&self, enable: bool) -> zbus::Result<()>; + + /// SetGpuMuxMode method fn set_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>; + /// SetPanelOd method + fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>; + /// SetPostBootSound method fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>; - /// PanelOverdrive method - fn panel_od(&self) -> zbus::Result; + /// NotifyDgpuDisable signal + #[dbus_proxy(signal)] + fn notify_dgpu_disable(&self, disable: bool) -> zbus::Result<()>; - /// SetPanelOverdrive method - fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>; + /// NotifyEgpuEnable signal + #[dbus_proxy(signal)] + fn notify_egpu_enable(&self, enable: bool) -> zbus::Result<()>; - /// NotifyDedicatedGraphicMode signal + /// NotifyGpuMuxMode signal #[dbus_proxy(signal)] fn notify_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>; - /// NotifyPostBootSound signal - #[dbus_proxy(signal)] - fn notify_post_boot_sound(&self, sound: bool) -> zbus::Result<()>; - - /// NotifyPanelOverdrive signal + /// NotifyPanelOd signal #[dbus_proxy(signal)] fn notify_panel_od(&self, overdrive: bool) -> zbus::Result<()>; + + /// NotifyPostBootSound signal + #[dbus_proxy(signal)] + fn notify_post_boot_sound(&self, on: bool) -> zbus::Result<()>; } diff --git a/rog-dbus/src/zbus_power.rs b/rog-dbus/src/zbus_power.rs index 4b242d83..37359c92 100644 --- a/rog-dbus/src/zbus_power.rs +++ b/rog-dbus/src/zbus_power.rs @@ -29,10 +29,17 @@ trait Power { /// charge_control_end_threshold method fn charge_control_end_threshold(&self) -> zbus::Result; + /// MainsOnline method + fn mains_online(&self) -> zbus::Result; + /// set_charge_control_end_threshold method fn set_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<()>; /// NotifyCharge signal #[dbus_proxy(signal)] fn notify_charge_control_end_threshold(&self, limit: u8) -> zbus::Result; + + /// NotifyMainsOnline signal + #[dbus_proxy(signal)] + fn notify_mains_online(&self, on: bool) -> zbus::Result<()>; } diff --git a/rog-platform/src/error.rs b/rog-platform/src/error.rs index 9be403da..08be205b 100644 --- a/rog-platform/src/error.rs +++ b/rog-platform/src/error.rs @@ -15,7 +15,8 @@ pub enum PlatformError { AttrNotFound(String), MissingFunction(String), MissingLedBrightNode(String, std::io::Error), - Io(String, std::io::Error), + IoPath(String, std::io::Error), + Io(std::io::Error), NoAuraKeyboard, NoAuraNode, } @@ -33,9 +34,10 @@ impl fmt::Display for PlatformError { PlatformError::Write(path, error) => write!(f, "Write {}: {}", path, error), PlatformError::NotSupported => write!(f, "Not supported"), PlatformError::AttrNotFound(deets) => write!(f, "Attribute not found: {}", deets), + PlatformError::Io(deets) => write!(f, "std::io error: {}", deets), PlatformError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), PlatformError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), - PlatformError::Io(path, detail) => write!(f, "std::io error: {} {}", path, detail), + PlatformError::IoPath(path, detail) => write!(f, "{} {}", path, detail), PlatformError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), PlatformError::NoAuraNode => write!(f, "No Aura keyboard node found"), } @@ -49,3 +51,9 @@ impl From for PlatformError { PlatformError::USB(err) } } + +impl From for PlatformError { + fn from(err: std::io::Error) -> Self { + PlatformError::Io(err) + } +} diff --git a/rog-platform/src/hid_raw.rs b/rog-platform/src/hid_raw.rs index d332bb8a..a793b852 100644 --- a/rog-platform/src/hid_raw.rs +++ b/rog-platform/src/hid_raw.rs @@ -21,11 +21,13 @@ impl HidRaw { for device in enumerator .scan_devices() - .map_err(|e| PlatformError::Io("enumerator".to_owned(), e))? + .map_err(|e| PlatformError::IoPath("enumerator".to_owned(), e))? { if let Some(parent) = device .parent_with_subsystem_devtype("usb", "usb_device") - .map_err(|e| PlatformError::Io(device.devpath().to_string_lossy().to_string(), e))? + .map_err(|e| { + PlatformError::IoPath(device.devpath().to_string_lossy().to_string(), e) + })? { if let Some(parent) = parent.attribute_value("idProduct") { if parent == id_product { @@ -47,9 +49,9 @@ impl HidRaw { let mut file = OpenOptions::new() .write(true) .open(&self.0) - .map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e))?; + .map_err(|e| PlatformError::IoPath(self.0.to_string_lossy().to_string(), e))?; // println!("write: {:02x?}", &message); file.write_all(message) - .map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e)) + .map_err(|e| PlatformError::IoPath(self.0.to_string_lossy().to_string(), e)) } } diff --git a/rog-platform/src/lib.rs b/rog-platform/src/lib.rs index 88962bc8..8c118860 100644 --- a/rog-platform/src/lib.rs +++ b/rog-platform/src/lib.rs @@ -45,7 +45,7 @@ pub fn read_attr_bool(device: &Device, attr_name: &str) -> Result { pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<()> { device .set_attribute_value(attr, &(value as u8).to_string()) - .map_err(|e| PlatformError::Io(attr.into(), e)) + .map_err(|e| PlatformError::IoPath(attr.into(), e)) } pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result { @@ -59,7 +59,7 @@ pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result { pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> { device .set_attribute_value(attr, &(value).to_string()) - .map_err(|e| PlatformError::Io(attr.into(), e)) + .map_err(|e| PlatformError::IoPath(attr.into(), e)) } pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result> { @@ -79,7 +79,7 @@ pub fn write_attr_u8_array(device: &mut Device, attr: &str, values: &[u8]) -> Re let tmp = tmp.trim(); device .set_attribute_value(attr, &tmp) - .map_err(|e| PlatformError::Io(attr.into(), e)) + .map_err(|e| PlatformError::IoPath(attr.into(), e)) } #[cfg(test)] diff --git a/rog-platform/src/macros.rs b/rog-platform/src/macros.rs index e9bf431a..0989b290 100644 --- a/rog-platform/src/macros.rs +++ b/rog-platform/src/macros.rs @@ -21,9 +21,19 @@ macro_rules! watch_attr { pub fn fn_name(&self) -> Result { let mut path = self.$item.clone(); path.push($attr_name); - let mut inotify = inotify::Inotify::init().unwrap(); - inotify.add_watch(path.to_str().unwrap(), inotify::WatchMask::MODIFY).unwrap(); - Ok(inotify) + if let Some(path) = path.to_str() { + let mut inotify = inotify::Inotify::init()?; + inotify.add_watch(path, inotify::WatchMask::MODIFY) + .map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + PlatformError::AttrNotFound(format!("{}", $attr_name)) + } else { + PlatformError::IoPath(format!("{}", path), e) + } + })?; + return Ok(inotify); + } + Err(PlatformError::AttrNotFound(format!("{}", $attr_name))) } }); }; diff --git a/rog-platform/src/power.rs b/rog-platform/src/power.rs index d74633ff..ce25b525 100644 --- a/rog-platform/src/power.rs +++ b/rog-platform/src/power.rs @@ -102,4 +102,5 @@ impl AsusPower { } attr_u8!("charge_control_end_threshold", battery); + attr_u8!("online", mains); }