From 0dba22529c0fc8268ca6b9edbc77e2a909a95466 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Sat, 11 Oct 2025 20:51:57 +0200 Subject: [PATCH] feat: change limits dynamically --- asusd/src/asus_armoury.rs | 76 +++++++++++++++++++----- asusd/src/ctrl_platform.rs | 54 ++++++++++++++--- asusd/src/daemon.rs | 14 +++-- rog-control-center/ui/pages/system.slint | 18 +++--- rog-platform/src/asus_armoury.rs | 16 +++++ 5 files changed, 143 insertions(+), 35 deletions(-) diff --git a/asusd/src/asus_armoury.rs b/asusd/src/asus_armoury.rs index bb78130e..2e03a651 100644 --- a/asusd/src/asus_armoury.rs +++ b/asusd/src/asus_armoury.rs @@ -55,6 +55,25 @@ impl AsusArmouryAttribute { String::from(self.attr.name()) } + fn resolve_i32_value(refreshed: Option, cached: &AttrValue) -> i32 { + refreshed + .or_else(|| match cached { + AttrValue::Integer(i) => Some(*i), + _ => None, + }) + .unwrap_or(-1) + } + + pub async fn emit_limits(&self, connection: &Connection) -> Result<(), RogError> { + let path = dbus_path_for_attr(self.attr.name()); + let signal = SignalEmitter::new(connection, path)?; + self.min_value_changed(&signal).await?; + self.max_value_changed(&signal).await?; + self.scalar_increment_changed(&signal).await?; + self.current_value_changed(&signal).await?; + Ok(()) + } + pub async fn move_to_zbus(self, connection: &Connection) -> Result<(), RogError> { let path = dbus_path_for_attr(self.attr.name()); connection @@ -117,6 +136,35 @@ impl AsusArmouryAttribute { } } +#[derive(Clone, Default)] +pub struct ArmouryAttributeRegistry { + attrs: Vec, +} + +impl ArmouryAttributeRegistry { + pub fn push(&mut self, attr: AsusArmouryAttribute) { + self.attrs.push(attr); + } + + pub async fn emit_limits(&self, connection: &Connection) -> Result<(), RogError> { + let mut last_err: Option = None; + for attr in &self.attrs { + if let Err(e) = attr.emit_limits(connection).await { + error!( + "Failed to emit updated limits for attribute '{}': {e:?}", + attr.attribute_name() + ); + last_err = Some(e); + } + } + if let Some(err) = last_err { + Err(err) + } else { + Ok(()) + } + } +} + impl crate::Reloadable for AsusArmouryAttribute { async fn reload(&mut self) -> Result<(), RogError> { info!("Reloading {}", self.attr.name()); @@ -256,26 +304,20 @@ impl AsusArmouryAttribute { #[zbus(property)] async fn min_value(&self) -> i32 { - match self.attr.min_value() { - AttrValue::Integer(i) => *i, - _ => -1, - } + Self::resolve_i32_value(self.attr.refresh_min_value(), self.attr.min_value()) } #[zbus(property)] async fn max_value(&self) -> i32 { - match self.attr.max_value() { - AttrValue::Integer(i) => *i, - _ => -1, - } + Self::resolve_i32_value(self.attr.refresh_max_value(), self.attr.max_value()) } #[zbus(property)] async fn scalar_increment(&self) -> i32 { - match self.attr.scalar_increment() { - AttrValue::Integer(i) => *i, - _ => -1, - } + Self::resolve_i32_value( + self.attr.refresh_scalar_increment(), + self.attr.scalar_increment(), + ) } #[zbus(property)] @@ -393,7 +435,8 @@ pub async fn start_attributes_zbus( power: AsusPower, attributes: FirmwareAttributes, config: Arc>, -) -> Result<(), RogError> { +) -> Result { + let mut registry = ArmouryAttributeRegistry::default(); for attr in attributes.attributes() { let mut attr = AsusArmouryAttribute::new( attr.clone(), @@ -402,6 +445,8 @@ pub async fn start_attributes_zbus( config.clone(), ); + let registry_attr = attr.clone(); + if let Err(e) = attr.reload().await { error!( "Skipping attribute '{}' due to reload error: {e:?}", @@ -430,9 +475,12 @@ pub async fn start_attributes_zbus( if let Err(e) = attr.move_to_zbus(conn).await { error!("Failed to register attribute '{attr_name}' on zbus: {e:?}"); + continue; } + + registry.push(registry_attr); } - Ok(()) + Ok(registry) } pub async fn set_config_or_default( diff --git a/asusd/src/ctrl_platform.rs b/asusd/src/ctrl_platform.rs index f3dc369c..b5b896ee 100644 --- a/asusd/src/ctrl_platform.rs +++ b/asusd/src/ctrl_platform.rs @@ -13,7 +13,7 @@ use zbus::fdo::Error as FdoErr; use zbus::object_server::SignalEmitter; use zbus::{interface, Connection}; -use crate::asus_armoury::set_config_or_default; +use crate::asus_armoury::{set_config_or_default, ArmouryAttributeRegistry}; use crate::config::Config; use crate::error::RogError; use crate::{task_watch_item, CtrlTask, ReloadAndNotify}; @@ -46,6 +46,8 @@ pub struct CtrlPlatform { attributes: FirmwareAttributes, cpu_control: Option, config: Arc>, + connection: Connection, + armoury_registry: ArmouryAttributeRegistry, } impl CtrlPlatform { @@ -56,6 +58,8 @@ impl CtrlPlatform { config: Arc>, config_path: &Path, signal_context: SignalEmitter<'static>, + connection: Connection, + armoury_registry: ArmouryAttributeRegistry, ) -> Result { let config1 = config.clone(); let config_path = config_path.to_owned(); @@ -68,6 +72,8 @@ impl CtrlPlatform { cpu_control: CPUControl::new() .map_err(|e| error!("Couldn't get CPU control sysfs: {e}")) .ok(), + connection, + armoury_registry, }; let mut inotify_self = ret_self.clone(); @@ -729,6 +735,31 @@ impl CtrlTask for CtrlPlatform { } if !sleeping { platform1.run_ac_or_bat_cmd(power_plugged > 0).await; + if let Ok(profile) = + platform1.platform.get_platform_profile().map(|p| p.into()) + { + let attrs = FirmwareAttributes::new(); + { + let mut cfg = platform1.config.lock().await; + set_config_or_default( + &attrs, + &mut *cfg, + power_plugged > 0, + profile, + ) + .await; + } + if let Err(e) = platform1 + .armoury_registry + .emit_limits(&platform1.connection) + .await + { + error!( + "Failed to emit armoury updates after power change: \ + {e:?}" + ); + } + } } platform1.config.lock().await.last_power_plugged = power_plugged; } @@ -789,13 +820,17 @@ impl CtrlTask for CtrlPlatform { { // TODO: manage this better, shouldn't need to create every time let attrs = FirmwareAttributes::new(); - set_config_or_default( - &attrs, - &mut *platform3.config.lock().await, - power_plugged, - profile, - ) - .await; + { + let mut cfg = platform3.config.lock().await; + set_config_or_default(&attrs, &mut *cfg, power_plugged, profile).await; + } + if let Err(e) = platform3 + .armoury_registry + .emit_limits(&platform3.connection) + .await + { + error!("Failed to emit armoury updates after AC/DC toggle: {e:?}"); + } platform3 .enable_ppt_group_changed(&signal_ctxt_copy) .await @@ -852,6 +887,9 @@ impl CtrlTask for CtrlPlatform { profile, ) .await; + if let Err(e) = ctrl.armoury_registry.emit_limits(&ctrl.connection).await { + error!("Failed to emit armoury updates after profile change: {e:?}"); + } } } } diff --git a/asusd/src/daemon.rs b/asusd/src/daemon.rs index 10b8f371..455b7c89 100644 --- a/asusd/src/daemon.rs +++ b/asusd/src/daemon.rs @@ -3,7 +3,7 @@ use std::error::Error; use std::sync::Arc; use ::zbus::Connection; -use asusd::asus_armoury::start_attributes_zbus; +use asusd::asus_armoury::{start_attributes_zbus, ArmouryAttributeRegistry}; use asusd::aura_manager::DeviceManager; use asusd::config::Config; use asusd::ctrl_backlight::CtrlBacklight; @@ -74,7 +74,7 @@ async fn start_daemon() -> Result<(), Box> { let platform = RogPlatform::new()?; // TODO: maybe needs async mutex? let power = AsusPower::new()?; // TODO: maybe needs async mutex? let attributes = FirmwareAttributes::new(); - if let Err(e) = start_attributes_zbus( + let armoury_registry = match start_attributes_zbus( &server, platform.clone(), power.clone(), @@ -83,8 +83,12 @@ async fn start_daemon() -> Result<(), Box> { ) .await { - error!("Failed to initialize firmware attributes over zbus: {e:?}"); - } + Ok(registry) => registry, + Err(e) => { + error!("Failed to initialize firmware attributes over zbus: {e:?}"); + ArmouryAttributeRegistry::default() + } + }; match CtrlFanCurveZbus::new() { Ok(ctrl) => { @@ -113,6 +117,8 @@ async fn start_daemon() -> Result<(), Box> { config.clone(), &cfg_path, CtrlPlatform::signal_context(&server)?, + server.clone(), + armoury_registry, ) { Ok(ctrl) => { let sig_ctx = CtrlPlatform::signal_context(&server)?; diff --git a/rog-control-center/ui/pages/system.slint b/rog-control-center/ui/pages/system.slint index df913430..328c2735 100644 --- a/rog-control-center/ui/pages/system.slint +++ b/rog-control-center/ui/pages/system.slint @@ -302,7 +302,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_pl1_spl.current != -1 || SystemPageData.ppt_pl2_sppt.current != -1 || SystemPageData.ppt_pl3_fppt.current != -1 || SystemPageData.ppt_fppt.current != -1 || SystemPageData.ppt_apu_sppt.current != -1 || SystemPageData.nv_temp_target.current != -1 || SystemPageData.nv_dynamic_boost.current != -1: HorizontalLayout { + if (SystemPageData.ppt_pl1_spl.max > 0 && SystemPageData.ppt_pl1_spl.current != -1) || (SystemPageData.ppt_pl2_sppt.max > 0 && SystemPageData.ppt_pl2_sppt.current != -1) || (SystemPageData.ppt_pl3_fppt.max > 0 && SystemPageData.ppt_pl3_fppt.current != -1) || (SystemPageData.ppt_fppt.max > 0 && SystemPageData.ppt_fppt.current != -1) || (SystemPageData.ppt_apu_sppt.max > 0 && SystemPageData.ppt_apu_sppt.current != -1) || (SystemPageData.nv_temp_target.max > 0 && SystemPageData.nv_temp_target.current != -1) || (SystemPageData.nv_dynamic_boost.max > 0 && SystemPageData.nv_dynamic_boost.current != -1): HorizontalLayout { padding-right: 10px; padding-left: 10px; alignment: LayoutAlignment.space-between; @@ -331,7 +331,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_pl1_spl.current != -1: SystemSlider { + if SystemPageData.ppt_pl1_spl.max > 0 && SystemPageData.ppt_pl1_spl.current != -1: SystemSlider { text: @tr("ppt_pl1_spl" => "CPU Sustained Power Limit"); title: @tr("ppt_pl1_spl" => "CPU Sustained Power Limit"); help_text: @tr("ppt_pl1_spl_help" => "Long-term CPU power limit that affects sustained workload performance. Higher values may increase heat and power consumption."); @@ -349,7 +349,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_pl2_sppt.current != -1: SystemSlider { + if SystemPageData.ppt_pl2_sppt.max > 0 && SystemPageData.ppt_pl2_sppt.current != -1: SystemSlider { text: @tr("ppt_pl2_sppt" => "CPU Turbo Power Limit"); title: @tr("ppt_pl2_sppt" => "CPU Turbo Power Limit"); help_text: @tr("ppt_pl2_sppt_help" => "Short-term CPU power limit for boost periods. Controls maximum power during brief high-performance bursts."); @@ -367,7 +367,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_pl3_fppt.current != -1: SystemSlider { + if SystemPageData.ppt_pl3_fppt.max > 0 && SystemPageData.ppt_pl3_fppt.current != -1: SystemSlider { text: @tr("ppt_pl3_fppt" => "CPU Fast Burst Power Limit"); title: @tr("ppt_pl3_fppt" => "CPU Fast Burst Power Limit"); help_text: @tr("ppt_pl3_fppt_help" => "Ultra-short duration power limit for instantaneous CPU bursts. Affects responsiveness during sudden workload spikes."); @@ -384,7 +384,7 @@ export component PageSystem inherits Rectangle { SystemPageData.cb_ppt_pl3_fppt(Math.round(value)); } } - if SystemPageData.ppt_fppt.current != -1: SystemSlider { + if SystemPageData.ppt_fppt.max > 0 && SystemPageData.ppt_fppt.current != -1: SystemSlider { text: @tr("ppt_fppt" => "Fast Package Power Limit"); title: @tr("ppt_fppt" => "Fast Package Power Limit"); help_text: @tr("ppt_fppt_help" => "Ultra-short duration power limit for system package. Controls maximum power during millisecond-scale load spikes."); @@ -402,7 +402,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_apu_sppt.current != -1: SystemSlider { + if SystemPageData.ppt_apu_sppt.max > 0 && SystemPageData.ppt_apu_sppt.current != -1: SystemSlider { text: @tr("ppt_apu_sppt" => "APU Sustained Power Limit"); title: @tr("ppt_apu_sppt" => "APU Sustained Power Limit"); help_text: @tr("ppt_apu_sppt_help" => "Long-term power limit for integrated graphics and CPU combined. Affects sustained performance of APU-based workloads."); @@ -420,7 +420,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.ppt_platform_sppt.current != -1: SystemSlider { + if SystemPageData.ppt_platform_sppt.max > 0 && SystemPageData.ppt_platform_sppt.current != -1: SystemSlider { text: @tr("ppt_platform_sppt" => "Platform Sustained Power Limit"); title: @tr("ppt_platform_sppt" => "Platform Sustained Power Limit"); help_text: @tr("ppt_platform_sppt_help" => "Overall system power limit for sustained operations. Controls total platform power consumption over extended periods."); @@ -438,7 +438,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.nv_dynamic_boost.current != -1: SystemSlider { + if SystemPageData.nv_dynamic_boost.max > 0 && SystemPageData.nv_dynamic_boost.current != -1: SystemSlider { text: @tr("nv_dynamic_boost" => "GPU Power Boost"); title: @tr("nv_dynamic_boost" => "GPU Power Boost"); help_text: @tr("nv_dynamic_boost_help" => "Additional power allocation for GPU dynamic boost. Higher values increase GPU performance but generate more heat."); @@ -456,7 +456,7 @@ export component PageSystem inherits Rectangle { } } - if SystemPageData.nv_temp_target.current != -1: SystemSlider { + if SystemPageData.nv_temp_target.max > 0 && SystemPageData.nv_temp_target.current != -1: SystemSlider { text: @tr("nv_temp_target" => "GPU Temperature Limit"); title: @tr("nv_temp_target" => "GPU Temperature Limit"); help_text: @tr("nv_temp_target_help" => "Maximum GPU temperature threshold in Celsius. GPU will throttle to maintain temperature below this limit."); diff --git a/rog-platform/src/asus_armoury.rs b/rog-platform/src/asus_armoury.rs index 455f3158..b0dd2834 100644 --- a/rog-platform/src/asus_armoury.rs +++ b/rog-platform/src/asus_armoury.rs @@ -124,6 +124,22 @@ impl Attribute { &self.scalar_increment } + fn read_attr_i32(&self, name: &str) -> Option { + read_i32(&self.base_path.join(name)).ok() + } + + pub fn refresh_min_value(&self) -> Option { + self.read_attr_i32("min_value") + } + + pub fn refresh_max_value(&self) -> Option { + self.read_attr_i32("max_value") + } + + pub fn refresh_scalar_increment(&self) -> Option { + self.read_attr_i32("scalar_increment") + } + /// Read all the immutable values to struct data. These should *never* /// change, if they do then it is possibly a driver issue - although this is /// subject to `firmware_attributes` class changes in kernel.