From b661f67084113aa3188a25d250e80e593f488868 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Mon, 26 Aug 2024 17:52:42 +1200 Subject: [PATCH] Many updates --- asusd/src/ctrl_platform.rs | 2 + rog-aura/data/aura_support.ron | 4 +- .../translations/en/rog-control-center.po | 2 +- rog-platform/src/firmware_attributes.rs | 495 +++++++++--------- rog-platform/src/lib.rs | 1 + 5 files changed, 253 insertions(+), 251 deletions(-) diff --git a/asusd/src/ctrl_platform.rs b/asusd/src/ctrl_platform.rs index 5a14af25..c34daf96 100644 --- a/asusd/src/ctrl_platform.rs +++ b/asusd/src/ctrl_platform.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use config_traits::StdConfig; use log::{debug, error, info, warn}; use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP}; +// use rog_platform::firmware_attributes::FirmwareAttributes; use rog_platform::platform::{GpuMode, Properties, RogPlatform, ThrottlePolicy}; use rog_platform::power::AsusPower; use zbus::export::futures_util::lock::Mutex; @@ -94,6 +95,7 @@ impl CtrlPlatform { config_path: &Path, signal_context: SignalContext<'static>, ) -> Result { + // let attrs = FirmwareAttributes::new(); let platform = RogPlatform::new()?; let power = AsusPower::new()?; diff --git a/rog-aura/data/aura_support.ron b/rog-aura/data/aura_support.ron index 9e03fcc4..7457db69 100644 --- a/rog-aura/data/aura_support.ron +++ b/rog-aura/data/aura_support.ron @@ -903,7 +903,7 @@ device_name: "RC71L", product_id: "", layout_name: "ga401q", - basic_modes: [Static, Breathe, Pulse], + basic_modes: [Static, Breathe, Pulse, RainbowCycle], basic_zones: [], advanced_type: None, power_zones: [Keyboard], @@ -912,7 +912,7 @@ device_name: "RC72L", product_id: "", layout_name: "ga401q", - basic_modes: [Static, Breathe, Pulse], + basic_modes: [Static, Breathe, Pulse, RainbowCycle], basic_zones: [], advanced_type: None, power_zones: [Keyboard], diff --git a/rog-control-center/translations/en/rog-control-center.po b/rog-control-center/translations/en/rog-control-center.po index edca9985..2c20845c 100644 --- a/rog-control-center/translations/en/rog-control-center.po +++ b/rog-control-center/translations/en/rog-control-center.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2024-07-25 10:03+0000\n" +"POT-Creation-Date: 2024-08-26 05:52+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/rog-platform/src/firmware_attributes.rs b/rog-platform/src/firmware_attributes.rs index 5da5bcaf..9cebfbf0 100644 --- a/rog-platform/src/firmware_attributes.rs +++ b/rog-platform/src/firmware_attributes.rs @@ -1,289 +1,288 @@ -// Firmware attribute interfaces -// - current_value -// - default_value -// - display_name -// - default_value -// - possible_values -// - max_value -// - min_value -// - scalar_increment -// - type - -use std::{ - fs::{read_dir, File}, - io::Read, - path::{Path, PathBuf}, -}; - -use log::error; +use std::fs::{read_dir, File}; +use std::io::Read; +use std::path::Path; use crate::error::PlatformError; -const BASE_DIR: &str = "/sys/class/firmware-attributes/asus-bioscfg/attributes/"; +const BASE_DIR: &str = "/sys/class/firmware-attributes/asus-armoury/attributes/"; fn read_i32(path: &Path) -> Result { if let Ok(mut f) = File::open(path) { let mut buf = String::new(); f.read_to_string(&mut buf)?; - buf = buf.trim_end().to_string(); - if let Ok(int) = buf.parse::() { - return Ok(int); - } + buf.trim() + .parse::() + .map_err(|_| PlatformError::ParseNum) + } else { + Err(PlatformError::ParseNum) } - Err(PlatformError::ParseNum) } fn read_string(path: &Path) -> Result { - if let Ok(mut f) = File::open(path) { - let mut buf = String::new(); - f.read_to_string(&mut buf)?; - buf = buf.trim_end().to_string(); - return Ok(buf); - } - Err(PlatformError::ParseNum) + let mut f = File::open(path)?; + let mut buf = String::new(); + f.read_to_string(&mut buf)?; + Ok(buf.trim().to_string()) } -fn attr_path_if_exists(mut base_path: PathBuf, attr: &str) -> Option { - base_path.push(attr); - if base_path.exists() { - return Some(base_path.clone()); - } - None -} - -#[derive(Debug, Default)] -pub struct AttrInteger { - current: PathBuf, - default: Option, - min: Option, - max: Option, - scalar_inc: Option, -} - -impl AttrInteger { - pub fn current_value(&self) -> Result { - read_i32(&self.current) - } - - fn read_i32(path: Option<&PathBuf>) -> Result, PlatformError> { - if let Some(path) = path { - let int = read_i32(path)?; - return Ok(Some(int)); - } - Ok(None) - } - - pub fn default_value(&self) -> Result, PlatformError> { - Self::read_i32(self.default.as_ref()) - } - - pub fn min_value(&self) -> Result, PlatformError> { - Self::read_i32(self.min.as_ref()) - } - - pub fn max_value(&self) -> Result, PlatformError> { - Self::read_i32(self.max.as_ref()) - } - - pub fn scalar_increment(&self) -> Result, PlatformError> { - Self::read_i32(self.scalar_inc.as_ref()) - } -} - -#[derive(Debug, Default)] -pub struct AttEnumInteger { - current: PathBuf, - default: Option, - possible: Option, -} - -impl AttEnumInteger { - pub fn current_value(&self) -> Result { - read_i32(&self.current) - } - - pub fn default_value(&self) -> Result, PlatformError> { - if let Some(path) = self.default.as_ref() { - let int = read_i32(path)?; - return Ok(Some(int)); - } - Ok(None) - } - - pub fn possible_values(&self) -> Vec { - let mut output = Vec::new(); - if let Some(path) = self.possible.as_ref() { - if let Ok(string) = read_string(path) { - for n in string.split(';') { - match n.parse::() { - Ok(n) => output.push(n), - Err(e) => error!("Couldn't parse num: {e:?}"), - } - } - } - } - - output - } -} - -#[derive(Debug, Default)] -pub struct AttEnumString { - current: PathBuf, - default: Option, - possible: Option, -} - -impl AttEnumString { - pub fn current_value(&self) -> Result { - read_string(&self.current) - } - - pub fn default_value(&self) -> Result, PlatformError> { - if let Some(path) = self.default.as_ref() { - let string = read_string(path)?; - return Ok(Some(string)); - } - Ok(None) - } - - pub fn possible_values(&self) -> Vec { - let mut output = Vec::new(); - if let Some(path) = self.possible.as_ref() { - if let Ok(string) = read_string(path) { - for n in string.split(';') { - if !n.is_empty() { - output.push(n.to_owned()); - } - } - } - } - - output - } -} - -#[derive(Debug, Default)] -pub enum AttrType { - Integer(AttrInteger), - EnumInt(AttEnumInteger), - EnumStr(AttEnumString), +#[derive(Debug, Default, PartialEq, PartialOrd)] +pub enum AttrValue { + Integer(i32), + String(String), + EnumInt(Vec), + EnumStr(Vec), #[default] - Unknown, + None, } #[derive(Debug, Default)] pub struct Attribute { name: String, help: String, - _base_path: PathBuf, - attr_type: AttrType, + current_value: AttrValue, + default_value: AttrValue, + possible_values: AttrValue, + min_value: AttrValue, + max_value: AttrValue, + scalar_increment: Option, } impl Attribute { pub fn name(&self) -> &str { - self.name.as_str() + &self.name } pub fn help(&self) -> &str { - self.help.as_str() + &self.help + } + + pub fn current_value(&self) -> &AttrValue { + &self.current_value + } + + pub fn default_value(&self) -> &AttrValue { + &self.default_value + } + + pub fn possible_values(&self) -> &AttrValue { + &self.possible_values + } + + pub fn min_value(&self) -> &AttrValue { + &self.min_value + } + + pub fn max_value(&self) -> &AttrValue { + &self.max_value + } + + pub fn scalar_increment(&self) -> Option { + self.scalar_increment + } + + fn read_values( + base_path: &Path, + ) -> ( + AttrValue, + AttrValue, + AttrValue, + AttrValue, + AttrValue, + Option, + ) { + let current_value = match read_string(&base_path.join("current_value")) { + Ok(val) => { + if let Ok(int) = val.parse::() { + AttrValue::Integer(int) + } else { + AttrValue::String(val) + } + } + Err(_) => AttrValue::None, + }; + + let default_value = match read_string(&base_path.join("default_value")) { + Ok(val) => { + if let Ok(int) = val.parse::() { + AttrValue::Integer(int) + } else { + AttrValue::String(val) + } + } + Err(_) => AttrValue::None, + }; + + let possible_values = match read_string(&base_path.join("possible_values")) { + Ok(val) => { + if let Ok(int) = val.parse::() { + AttrValue::Integer(int) + } else if val.contains(';') { + AttrValue::EnumInt(val.split(';').filter_map(|s| s.parse().ok()).collect()) + } else { + AttrValue::EnumStr(val.split(';').map(|s| s.to_string()).collect()) + } + } + Err(_) => AttrValue::None, + }; + + let min_value = read_i32(&base_path.join("min_value")) + .ok() + .map(AttrValue::Integer) + .unwrap_or_default(); + let max_value = read_i32(&base_path.join("max_value")) + .ok() + .map(AttrValue::Integer) + .unwrap_or_default(); + let scalar_increment = read_i32(&base_path.join("scalar_increment")).ok(); + + ( + current_value, + default_value, + possible_values, + min_value, + max_value, + scalar_increment, + ) } } -pub fn get_attributes() -> Vec { - let mut attrs = Vec::new(); - - let dir = read_dir(BASE_DIR).unwrap(); - dir.for_each(|d| { - if let Ok(base_dir) = d { - let mut attr_path = base_dir.path(); - let mut attr = Attribute { - _base_path: base_dir.path(), - attr_type: AttrType::Unknown, - ..Default::default() - }; - - // TYPE - attr_path.push("type"); - let mut buf = String::new(); - if let Ok(mut f) = File::open(&attr_path) { - f.read_to_string(&mut buf).unwrap(); - buf = buf.trim_end().to_string(); - - attr_path.pop(); - let mut current = attr_path.clone(); - current.push("current_value"); - - match buf.to_lowercase().as_str() { - "integer" => { - attr.attr_type = AttrType::Integer(AttrInteger { - current, - default: attr_path_if_exists(attr_path.clone(), "default_value"), - min: attr_path_if_exists(attr_path.clone(), "min_value"), - max: attr_path_if_exists(attr_path.clone(), "max_value"), - scalar_inc: attr_path_if_exists(attr_path.clone(), "scalar_increment"), - }) - } - _ => { - // Check what the current_value type is - if let Ok(mut f) = File::open(¤t) { - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - buf = buf.trim_end().to_string(); - if buf.parse::().is_ok() { - attr.attr_type = AttrType::EnumInt(AttEnumInteger { - current, - default: attr_path_if_exists( - attr_path.clone(), - "default_value", - ), - possible: attr_path_if_exists( - attr_path.clone(), - "possible_values", - ), - }); - } else { - attr.attr_type = AttrType::EnumStr(AttEnumString { - current, - default: attr_path_if_exists( - attr_path.clone(), - "default_value", - ), - possible: attr_path_if_exists( - attr_path.clone(), - "possible_values", - ), - }); - } - } - } - } - } - // DISPLAY_NAME - attr_path.push("display_name"); - if let Ok(res) = read_string(&attr_path) { - attr.help = res; - } - // DISPLAY_NAME - attr_path.pop(); - attr.name = attr_path.file_name().unwrap().to_string_lossy().to_string(); - - attrs.push(attr); - } - }); - - attrs +pub struct FirmwareAttributes { + attrs: Vec, } +#[allow(clippy::new_without_default)] +impl FirmwareAttributes { + pub fn new() -> Self { + let mut attrs = Vec::new(); + if let Ok(dir) = read_dir(BASE_DIR) { + for entry in dir.flatten() { + let base_path = entry.path(); + let name = base_path.file_name().unwrap().to_string_lossy().to_string(); + let help = read_string(&base_path.join("display_name")).unwrap_or_default(); + + let ( + current_value, + default_value, + possible_values, + min_value, + max_value, + scalar_increment, + ) = Attribute::read_values(&base_path); + + attrs.push(Attribute { + name, + help, + current_value, + default_value, + possible_values, + min_value, + max_value, + scalar_increment, + }); + } + } + Self { attrs } + } + + pub fn attributes(&self) -> &Vec { + &self.attrs + } + + pub fn attributes_mut(&mut self) -> &mut Vec { + &mut self.attrs + } +} + +macro_rules! define_attribute_getters { + ($($attr:ident),*) => { + impl FirmwareAttributes { + $( + pub fn $attr(&self) -> Option<&Attribute> { + self.attrs.iter().find(|a| a.name() == stringify!($attr)) + } + + concat_idents::concat_idents!(attr_mut = $attr, _mut { + pub fn attr_mut(&mut self) -> Option<&mut Attribute> { + self.attrs.iter_mut().find(|a| a.name() == stringify!($attr)) + } + }); + )* + } + } +} + +define_attribute_getters!( + apu_mem, + cores_performance, + cores_efficiency, + ppt_pl1_spl, + ppt_pl2_sppt, + ppt_apu_sppt, + ppt_platform_sppt, + ppt_fppt, + nv_dynamic_boost, + nv_temp_target, + dgpu_base_tgp, + dgpu_tgp, + charge_mode, + boot_sound, + mcu_powersave, + panel_od, + panel_hd_mode, + egpu_connected, + egpu_enable, + dgpu_disable, + gpu_mux_mode, + mini_led_mode +); + #[cfg(test)] mod tests { - use super::get_attributes; + use super::*; #[test] fn find_attributes() { - let attrs = get_attributes(); - for a in attrs { - dbg!(&a); + let attrs = FirmwareAttributes::new(); + for attr in attrs.attributes() { + dbg!(attr.name()); + match attr.name() { + "nv_dynamic_boost" => { + assert!(!attr.help().is_empty()); + assert!(matches!(attr.current_value, AttrValue::Integer(_))); + if let AttrValue::Integer(val) = attr.current_value { + assert_eq!(val, 5); + } + if let AttrValue::Integer(val) = attr.default_value { + assert_eq!(val, 25); + } + assert_eq!(attr.min_value, AttrValue::Integer(0)); + assert_eq!(attr.max_value, AttrValue::Integer(25)); + } + "boot_sound" => { + assert!(!attr.help().is_empty()); + assert!(matches!(attr.current_value, AttrValue::Integer(0))); + // dbg!(attr.current_value()); + } + _ => {} + } } } + + #[test] + fn test_boot_sound() { + let attrs = FirmwareAttributes::new(); + let attr = attrs + .attributes() + .iter() + .find(|a| a.name() == "boot_sound") + .unwrap(); + + assert_eq!(attr.name(), "boot_sound"); + assert!(!attr.help().is_empty()); + assert!(matches!(attr.current_value(), AttrValue::Integer(_))); + if let AttrValue::Integer(val) = attr.current_value() { + assert_eq!(*val, 0); // assuming value is 0 + } + // Check other members if applicable + } } diff --git a/rog-platform/src/lib.rs b/rog-platform/src/lib.rs index 094d988c..16851a85 100644 --- a/rog-platform/src/lib.rs +++ b/rog-platform/src/lib.rs @@ -3,6 +3,7 @@ pub mod cpu; pub mod error; +pub mod firmware_attributes; pub mod hid_raw; pub mod keyboard_led; pub(crate) mod macros;