Merge branch 'devel'

This commit is contained in:
Denis Benato
2025-10-14 01:50:20 +02:00
9 changed files with 279 additions and 72 deletions

View File

@@ -55,6 +55,25 @@ impl AsusArmouryAttribute {
String::from(self.attr.name()) String::from(self.attr.name())
} }
fn resolve_i32_value(refreshed: Option<i32>, cached: &AttrValue) -> i32 {
refreshed
.or(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> { pub async fn move_to_zbus(self, connection: &Connection) -> Result<(), RogError> {
let path = dbus_path_for_attr(self.attr.name()); let path = dbus_path_for_attr(self.attr.name());
connection connection
@@ -117,6 +136,35 @@ impl AsusArmouryAttribute {
} }
} }
#[derive(Clone, Default)]
pub struct ArmouryAttributeRegistry {
attrs: Vec<AsusArmouryAttribute>,
}
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<RogError> = 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 { impl crate::Reloadable for AsusArmouryAttribute {
async fn reload(&mut self) -> Result<(), RogError> { async fn reload(&mut self) -> Result<(), RogError> {
info!("Reloading {}", self.attr.name()); info!("Reloading {}", self.attr.name());
@@ -131,25 +179,31 @@ impl crate::Reloadable for AsusArmouryAttribute {
error!("Could not get power status: {e:?}"); error!("Could not get power status: {e:?}");
e e
}) })
.unwrap_or_default(); .unwrap_or_default()
let config = if power_plugged == 1 { == 1;
&self.config.lock().await.ac_profile_tunings
} else { let apply_value = {
&self.config.lock().await.dc_profile_tunings let config = self.config.lock().await;
config
.select_tunings_ref(power_plugged, profile)
.and_then(|tuning| {
if tuning.enabled {
tuning.group.get(&self.name()).copied()
} else {
None
}
})
}; };
if let Some(tuning) = config.get(&profile) {
if tuning.enabled { if let Some(tune) = apply_value {
if let Some(tune) = tuning.group.get(&self.name()) { self.attr
self.attr .set_current_value(&AttrValue::Integer(tune))
.set_current_value(&AttrValue::Integer(*tune)) .map_err(|e| {
.map_err(|e| { error!("Could not set {} value: {e:?}", self.attr.name());
error!("Could not set {} value: {e:?}", self.attr.name()); self.attr.base_path_exists();
self.attr.base_path_exists(); e
e })?;
})?; info!("Set {} to {:?}", self.attr.name(), tune);
info!("Set {} to {:?}", self.attr.name(), tune);
}
}
} }
} else { } else {
// Handle non-PPT attributes (boolean and other settings) // Handle non-PPT attributes (boolean and other settings)
@@ -256,26 +310,20 @@ impl AsusArmouryAttribute {
#[zbus(property)] #[zbus(property)]
async fn min_value(&self) -> i32 { async fn min_value(&self) -> i32 {
match self.attr.min_value() { Self::resolve_i32_value(self.attr.refresh_min_value(), self.attr.min_value())
AttrValue::Integer(i) => *i,
_ => -1,
}
} }
#[zbus(property)] #[zbus(property)]
async fn max_value(&self) -> i32 { async fn max_value(&self) -> i32 {
match self.attr.max_value() { Self::resolve_i32_value(self.attr.refresh_max_value(), self.attr.max_value())
AttrValue::Integer(i) => *i,
_ => -1,
}
} }
#[zbus(property)] #[zbus(property)]
async fn scalar_increment(&self) -> i32 { async fn scalar_increment(&self) -> i32 {
match self.attr.scalar_increment() { Self::resolve_i32_value(
AttrValue::Integer(i) => *i, self.attr.refresh_scalar_increment(),
_ => -1, self.attr.scalar_increment(),
} )
} }
#[zbus(property)] #[zbus(property)]
@@ -297,12 +345,15 @@ impl AsusArmouryAttribute {
error!("Could not get power status: {e:?}"); error!("Could not get power status: {e:?}");
e e
}) })
.unwrap_or_default(); .unwrap_or_default()
let mut config = self.config.lock().await; == 1;
let tuning = config.select_tunings(power_plugged == 1, profile); let config = self.config.lock().await;
if let Some(tune) = tuning.group.get(&self.name()) { if let Some(tuning) = config.select_tunings_ref(power_plugged, profile) {
return Ok(*tune); if let Some(tune) = tuning.group.get(&self.name()) {
} else if let AttrValue::Integer(i) = self.attr.default_value() { return Ok(*tune);
}
}
if let AttrValue::Integer(i) = self.attr.default_value() {
return Ok(*i); return Ok(*i);
} }
return Err(fdo::Error::Failed( return Err(fdo::Error::Failed(
@@ -318,6 +369,83 @@ impl AsusArmouryAttribute {
)) ))
} }
async fn stored_value_for_power(&self, on_ac: bool) -> fdo::Result<i32> {
if !self.name().is_ppt() {
return Err(fdo::Error::NotSupported(
"Stored values are only available for PPT attributes".to_string(),
));
}
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let config = self.config.lock().await;
if let Some(tuning) = config.select_tunings_ref(on_ac, profile) {
if let Some(tune) = tuning.group.get(&self.name()) {
return Ok(*tune);
}
}
if let AttrValue::Integer(i) = self.attr.default_value() {
return Ok(*i);
}
Err(fdo::Error::Failed(
"Could not read stored value".to_string(),
))
}
async fn set_value_for_power(&mut self, on_ac: bool, value: i32) -> fdo::Result<()> {
if !self.name().is_ppt() {
return Err(fdo::Error::NotSupported(
"Setting stored values is only supported for PPT attributes".to_string(),
));
}
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let apply_now;
{
let mut config = self.config.lock().await;
let tuning = config.select_tunings(on_ac, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!(
"Store {} value for {} power = {}",
self.attr.name(),
if on_ac { "AC" } else { "DC" },
value
);
}
apply_now = tuning.enabled;
config.write();
}
if apply_now {
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
!= 0;
if power_plugged == on_ac {
self.attr
.set_current_value(&AttrValue::Integer(value))
.map_err(|e| {
error!("Could not set value: {e:?}");
e
})?;
}
}
Ok(())
}
#[zbus(property)] #[zbus(property)]
async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> { async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> {
if self.name().is_ppt() { if self.name().is_ppt() {
@@ -393,7 +521,8 @@ pub async fn start_attributes_zbus(
power: AsusPower, power: AsusPower,
attributes: FirmwareAttributes, attributes: FirmwareAttributes,
config: Arc<Mutex<Config>>, config: Arc<Mutex<Config>>,
) -> Result<(), RogError> { ) -> Result<ArmouryAttributeRegistry, RogError> {
let mut registry = ArmouryAttributeRegistry::default();
for attr in attributes.attributes() { for attr in attributes.attributes() {
let mut attr = AsusArmouryAttribute::new( let mut attr = AsusArmouryAttribute::new(
attr.clone(), attr.clone(),
@@ -402,6 +531,8 @@ pub async fn start_attributes_zbus(
config.clone(), config.clone(),
); );
let registry_attr = attr.clone();
if let Err(e) = attr.reload().await { if let Err(e) = attr.reload().await {
error!( error!(
"Skipping attribute '{}' due to reload error: {e:?}", "Skipping attribute '{}' due to reload error: {e:?}",
@@ -430,9 +561,12 @@ pub async fn start_attributes_zbus(
if let Err(e) = attr.move_to_zbus(conn).await { if let Err(e) = attr.move_to_zbus(conn).await {
error!("Failed to register attribute '{attr_name}' on zbus: {e:?}"); 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( pub async fn set_config_or_default(

View File

@@ -67,6 +67,19 @@ impl Config {
}; };
config.entry(profile).or_insert_with(Tuning::default) config.entry(profile).or_insert_with(Tuning::default)
} }
pub fn select_tunings_ref(
&self,
power_plugged: bool,
profile: PlatformProfile,
) -> Option<&Tuning> {
let config = if power_plugged {
&self.ac_profile_tunings
} else {
&self.dc_profile_tunings
};
config.get(&profile)
}
} }
impl Default for Config { impl Default for Config {
@@ -146,7 +159,7 @@ pub struct Config611 {
impl From<Config611> for Config { impl From<Config611> for Config {
fn from(c: Config611) -> Self { fn from(c: Config611) -> Self {
Self { let mut config = Self {
// Restore the base charge limit // Restore the base charge limit
charge_control_end_threshold: c.charge_control_end_threshold, charge_control_end_threshold: c.charge_control_end_threshold,
base_charge_control_end_threshold: c.charge_control_end_threshold, base_charge_control_end_threshold: c.charge_control_end_threshold,
@@ -168,7 +181,12 @@ impl From<Config611> for Config {
armoury_settings: HashMap::default(), armoury_settings: HashMap::default(),
screenpad_gamma: None, screenpad_gamma: None,
screenpad_sync_primary: Default::default(), screenpad_sync_primary: Default::default(),
} };
config.ac_profile_tunings = c.ac_profile_tunings;
config.dc_profile_tunings = c.dc_profile_tunings;
config.armoury_settings = c.armoury_settings;
config
} }
} }

View File

@@ -13,7 +13,7 @@ use zbus::fdo::Error as FdoErr;
use zbus::object_server::SignalEmitter; use zbus::object_server::SignalEmitter;
use zbus::{interface, Connection}; 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::config::Config;
use crate::error::RogError; use crate::error::RogError;
use crate::{task_watch_item, CtrlTask, ReloadAndNotify}; use crate::{task_watch_item, CtrlTask, ReloadAndNotify};
@@ -46,6 +46,8 @@ pub struct CtrlPlatform {
attributes: FirmwareAttributes, attributes: FirmwareAttributes,
cpu_control: Option<CPUControl>, cpu_control: Option<CPUControl>,
config: Arc<Mutex<Config>>, config: Arc<Mutex<Config>>,
connection: Connection,
armoury_registry: ArmouryAttributeRegistry,
} }
impl CtrlPlatform { impl CtrlPlatform {
@@ -56,6 +58,8 @@ impl CtrlPlatform {
config: Arc<Mutex<Config>>, config: Arc<Mutex<Config>>,
config_path: &Path, config_path: &Path,
signal_context: SignalEmitter<'static>, signal_context: SignalEmitter<'static>,
connection: Connection,
armoury_registry: ArmouryAttributeRegistry,
) -> Result<Self, RogError> { ) -> Result<Self, RogError> {
let config1 = config.clone(); let config1 = config.clone();
let config_path = config_path.to_owned(); let config_path = config_path.to_owned();
@@ -68,6 +72,8 @@ impl CtrlPlatform {
cpu_control: CPUControl::new() cpu_control: CPUControl::new()
.map_err(|e| error!("Couldn't get CPU control sysfs: {e}")) .map_err(|e| error!("Couldn't get CPU control sysfs: {e}"))
.ok(), .ok(),
connection,
armoury_registry,
}; };
let mut inotify_self = ret_self.clone(); let mut inotify_self = ret_self.clone();
@@ -729,6 +735,31 @@ impl CtrlTask for CtrlPlatform {
} }
if !sleeping { if !sleeping {
platform1.run_ac_or_bat_cmd(power_plugged > 0).await; 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; 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 // TODO: manage this better, shouldn't need to create every time
let attrs = FirmwareAttributes::new(); let attrs = FirmwareAttributes::new();
set_config_or_default( {
&attrs, let mut cfg = platform3.config.lock().await;
&mut *platform3.config.lock().await, set_config_or_default(&attrs, &mut cfg, power_plugged, profile).await;
power_plugged, }
profile, if let Err(e) = platform3
) .armoury_registry
.await; .emit_limits(&platform3.connection)
.await
{
error!("Failed to emit armoury updates after AC/DC toggle: {e:?}");
}
platform3 platform3
.enable_ppt_group_changed(&signal_ctxt_copy) .enable_ppt_group_changed(&signal_ctxt_copy)
.await .await
@@ -852,6 +887,9 @@ impl CtrlTask for CtrlPlatform {
profile, profile,
) )
.await; .await;
if let Err(e) = ctrl.armoury_registry.emit_limits(&ctrl.connection).await {
error!("Failed to emit armoury updates after profile change: {e:?}");
}
} }
} }
} }

View File

@@ -3,7 +3,7 @@ use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
use ::zbus::Connection; 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::aura_manager::DeviceManager;
use asusd::config::Config; use asusd::config::Config;
use asusd::ctrl_backlight::CtrlBacklight; use asusd::ctrl_backlight::CtrlBacklight;
@@ -74,7 +74,7 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
let platform = RogPlatform::new()?; // TODO: maybe needs async mutex? let platform = RogPlatform::new()?; // TODO: maybe needs async mutex?
let power = AsusPower::new()?; // TODO: maybe needs async mutex? let power = AsusPower::new()?; // TODO: maybe needs async mutex?
let attributes = FirmwareAttributes::new(); let attributes = FirmwareAttributes::new();
if let Err(e) = start_attributes_zbus( let armoury_registry = match start_attributes_zbus(
&server, &server,
platform.clone(), platform.clone(),
power.clone(), power.clone(),
@@ -83,8 +83,12 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
) )
.await .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() { match CtrlFanCurveZbus::new() {
Ok(ctrl) => { Ok(ctrl) => {
@@ -113,6 +117,8 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
config.clone(), config.clone(),
&cfg_path, &cfg_path,
CtrlPlatform::signal_context(&server)?, CtrlPlatform::signal_context(&server)?,
server.clone(),
armoury_registry,
) { ) {
Ok(ctrl) => { Ok(ctrl) => {
let sig_ctx = CtrlPlatform::signal_context(&server)?; let sig_ctx = CtrlPlatform::signal_context(&server)?;

View File

@@ -169,7 +169,7 @@ impl AnimeImage {
// first 5 rows for GA401 are always at X = 0 // first 5 rows for GA401 are always at X = 0
return 0; return 0;
} }
(y + 1) / 2 - 3 y.div_ceil(2) - 3
} }
AnimeType::GU604 => { AnimeType::GU604 => {
// first 9 rows start at zero // first 9 rows start at zero
@@ -185,7 +185,7 @@ impl AnimeImage {
return 0; return 0;
} }
// and then their offset grows by one every two rows // and then their offset grows by one every two rows
(y + 1) / 2 - 5 y.div_ceil(2) - 5
} }
} }
} }
@@ -213,7 +213,7 @@ impl AnimeImage {
// First 5 rows for GA401 are always 33 physical LEDs long // First 5 rows for GA401 are always 33 physical LEDs long
return 33; return 33;
} }
36 - (y + 1) / 2 36 - y.div_ceil(2)
} }
AnimeType::GU604 => { AnimeType::GU604 => {
if y <= 9 { if y <= 9 {

View File

@@ -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-right: 10px;
padding-left: 10px; padding-left: 10px;
alignment: LayoutAlignment.space-between; 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"); text: @tr("ppt_pl1_spl" => "CPU Sustained Power Limit");
title: @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."); 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"); text: @tr("ppt_pl2_sppt" => "CPU Turbo Power Limit");
title: @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."); 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"); text: @tr("ppt_pl3_fppt" => "CPU Fast Burst Power Limit");
title: @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."); 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)); 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"); text: @tr("ppt_fppt" => "Fast Package Power Limit");
title: @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."); 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"); text: @tr("ppt_apu_sppt" => "APU Sustained Power Limit");
title: @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."); 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"); text: @tr("ppt_platform_sppt" => "Platform Sustained Power Limit");
title: @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."); 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"); text: @tr("nv_dynamic_boost" => "GPU Power Boost");
title: @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."); 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"); text: @tr("nv_temp_target" => "GPU Temperature Limit");
title: @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."); help_text: @tr("nv_temp_target_help" => "Maximum GPU temperature threshold in Celsius. GPU will throttle to maintain temperature below this limit.");

View File

@@ -124,6 +124,22 @@ impl Attribute {
&self.scalar_increment &self.scalar_increment
} }
fn read_attr_i32(&self, name: &str) -> Option<i32> {
read_i32(&self.base_path.join(name)).ok()
}
pub fn refresh_min_value(&self) -> Option<i32> {
self.read_attr_i32("min_value")
}
pub fn refresh_max_value(&self) -> Option<i32> {
self.read_attr_i32("max_value")
}
pub fn refresh_scalar_increment(&self) -> Option<i32> {
self.read_attr_i32("scalar_increment")
}
/// Read all the immutable values to struct data. These should *never* /// 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 /// change, if they do then it is possibly a driver issue - although this is
/// subject to `firmware_attributes` class changes in kernel. /// subject to `firmware_attributes` class changes in kernel.

View File

@@ -37,8 +37,9 @@ pub fn find_fan_curve_node() -> Result<Device, ProfileError> {
derive(Type, Value, OwnedValue), derive(Type, Value, OwnedValue),
zvariant(signature = "s") zvariant(signature = "s")
)] )]
#[derive(Deserialize, Serialize, Debug, Hash, PartialEq, Eq, Clone, Copy)] #[derive(Default, Deserialize, Serialize, Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum FanCurvePU { pub enum FanCurvePU {
#[default]
CPU = 0, CPU = 0,
GPU = 1, GPU = 1,
MID = 2, MID = 2,
@@ -100,12 +101,6 @@ impl std::str::FromStr for FanCurvePU {
} }
} }
impl Default for FanCurvePU {
fn default() -> Self {
Self::CPU
}
}
/// Main purpose of `FanCurves` is to enable restoring state on system boot /// Main purpose of `FanCurves` is to enable restoring state on system boot
#[cfg_attr(feature = "dbus", derive(Type))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Deserialize, Serialize, Debug, Default)] #[derive(Deserialize, Serialize, Debug, Default)]

View File

@@ -158,7 +158,7 @@ fn main() -> Result<(), Box<dyn Error>> {
canvas.set_draw_color(Color::RGB(*b, *b, *b)); canvas.set_draw_color(Color::RGB(*b, *b, *b));
let x: i32 = w + x_count as i32 * w let x: i32 = w + x_count as i32 * w
- if (y_count + y_offset as usize) % 2 != 0 { - if !(y_count + y_offset as usize).is_multiple_of(2) {
0 0
} else { } else {
w / 2 w / 2