Many updates

This commit is contained in:
Luke D. Jones
2024-08-26 17:52:42 +12:00
parent abd2ca8601
commit b661f67084
5 changed files with 253 additions and 251 deletions

View File

@@ -5,6 +5,7 @@ use std::sync::Arc;
use config_traits::StdConfig; use config_traits::StdConfig;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP}; use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP};
// use rog_platform::firmware_attributes::FirmwareAttributes;
use rog_platform::platform::{GpuMode, Properties, RogPlatform, ThrottlePolicy}; use rog_platform::platform::{GpuMode, Properties, RogPlatform, ThrottlePolicy};
use rog_platform::power::AsusPower; use rog_platform::power::AsusPower;
use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::lock::Mutex;
@@ -94,6 +95,7 @@ impl CtrlPlatform {
config_path: &Path, config_path: &Path,
signal_context: SignalContext<'static>, signal_context: SignalContext<'static>,
) -> Result<Self, RogError> { ) -> Result<Self, RogError> {
// let attrs = FirmwareAttributes::new();
let platform = RogPlatform::new()?; let platform = RogPlatform::new()?;
let power = AsusPower::new()?; let power = AsusPower::new()?;

View File

@@ -903,7 +903,7 @@
device_name: "RC71L", device_name: "RC71L",
product_id: "", product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse, RainbowCycle],
basic_zones: [], basic_zones: [],
advanced_type: None, advanced_type: None,
power_zones: [Keyboard], power_zones: [Keyboard],
@@ -912,7 +912,7 @@
device_name: "RC72L", device_name: "RC72L",
product_id: "", product_id: "",
layout_name: "ga401q", layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse], basic_modes: [Static, Breathe, Pulse, RainbowCycle],
basic_zones: [], basic_zones: [],
advanced_type: None, advanced_type: None,
power_zones: [Keyboard], power_zones: [Keyboard],

View File

@@ -2,7 +2,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"

View File

@@ -1,289 +1,288 @@
// Firmware attribute interfaces use std::fs::{read_dir, File};
// - current_value use std::io::Read;
// - default_value use std::path::Path;
// - 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 crate::error::PlatformError; 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<i32, PlatformError> { fn read_i32(path: &Path) -> Result<i32, PlatformError> {
if let Ok(mut f) = File::open(path) { if let Ok(mut f) = File::open(path) {
let mut buf = String::new(); let mut buf = String::new();
f.read_to_string(&mut buf)?; f.read_to_string(&mut buf)?;
buf = buf.trim_end().to_string(); buf.trim()
if let Ok(int) = buf.parse::<i32>() { .parse::<i32>()
return Ok(int); .map_err(|_| PlatformError::ParseNum)
} } else {
Err(PlatformError::ParseNum)
} }
Err(PlatformError::ParseNum)
} }
fn read_string(path: &Path) -> Result<String, PlatformError> { fn read_string(path: &Path) -> Result<String, PlatformError> {
if let Ok(mut f) = File::open(path) { let mut f = File::open(path)?;
let mut buf = String::new(); let mut buf = String::new();
f.read_to_string(&mut buf)?; f.read_to_string(&mut buf)?;
buf = buf.trim_end().to_string(); Ok(buf.trim().to_string())
return Ok(buf);
}
Err(PlatformError::ParseNum)
} }
fn attr_path_if_exists(mut base_path: PathBuf, attr: &str) -> Option<PathBuf> { #[derive(Debug, Default, PartialEq, PartialOrd)]
base_path.push(attr); pub enum AttrValue {
if base_path.exists() { Integer(i32),
return Some(base_path.clone()); String(String),
} EnumInt(Vec<i32>),
None EnumStr(Vec<String>),
}
#[derive(Debug, Default)]
pub struct AttrInteger {
current: PathBuf,
default: Option<PathBuf>,
min: Option<PathBuf>,
max: Option<PathBuf>,
scalar_inc: Option<PathBuf>,
}
impl AttrInteger {
pub fn current_value(&self) -> Result<i32, PlatformError> {
read_i32(&self.current)
}
fn read_i32(path: Option<&PathBuf>) -> Result<Option<i32>, PlatformError> {
if let Some(path) = path {
let int = read_i32(path)?;
return Ok(Some(int));
}
Ok(None)
}
pub fn default_value(&self) -> Result<Option<i32>, PlatformError> {
Self::read_i32(self.default.as_ref())
}
pub fn min_value(&self) -> Result<Option<i32>, PlatformError> {
Self::read_i32(self.min.as_ref())
}
pub fn max_value(&self) -> Result<Option<i32>, PlatformError> {
Self::read_i32(self.max.as_ref())
}
pub fn scalar_increment(&self) -> Result<Option<i32>, PlatformError> {
Self::read_i32(self.scalar_inc.as_ref())
}
}
#[derive(Debug, Default)]
pub struct AttEnumInteger {
current: PathBuf,
default: Option<PathBuf>,
possible: Option<PathBuf>,
}
impl AttEnumInteger {
pub fn current_value(&self) -> Result<i32, PlatformError> {
read_i32(&self.current)
}
pub fn default_value(&self) -> Result<Option<i32>, 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<i32> {
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::<i32>() {
Ok(n) => output.push(n),
Err(e) => error!("Couldn't parse num: {e:?}"),
}
}
}
}
output
}
}
#[derive(Debug, Default)]
pub struct AttEnumString {
current: PathBuf,
default: Option<PathBuf>,
possible: Option<PathBuf>,
}
impl AttEnumString {
pub fn current_value(&self) -> Result<String, PlatformError> {
read_string(&self.current)
}
pub fn default_value(&self) -> Result<Option<String>, 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<String> {
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),
#[default] #[default]
Unknown, None,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Attribute { pub struct Attribute {
name: String, name: String,
help: String, help: String,
_base_path: PathBuf, current_value: AttrValue,
attr_type: AttrType, default_value: AttrValue,
possible_values: AttrValue,
min_value: AttrValue,
max_value: AttrValue,
scalar_increment: Option<i32>,
} }
impl Attribute { impl Attribute {
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
self.name.as_str() &self.name
} }
pub fn help(&self) -> &str { 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<i32> {
self.scalar_increment
}
fn read_values(
base_path: &Path,
) -> (
AttrValue,
AttrValue,
AttrValue,
AttrValue,
AttrValue,
Option<i32>,
) {
let current_value = match read_string(&base_path.join("current_value")) {
Ok(val) => {
if let Ok(int) = val.parse::<i32>() {
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::<i32>() {
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::<i32>() {
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<Attribute> { pub struct FirmwareAttributes {
let mut attrs = Vec::new(); attrs: Vec<Attribute>,
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(&current) {
let mut buf = String::new();
f.read_to_string(&mut buf).unwrap();
buf = buf.trim_end().to_string();
if buf.parse::<i32>().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
} }
#[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<Attribute> {
&self.attrs
}
pub fn attributes_mut(&mut self) -> &mut Vec<Attribute> {
&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)] #[cfg(test)]
mod tests { mod tests {
use super::get_attributes; use super::*;
#[test] #[test]
fn find_attributes() { fn find_attributes() {
let attrs = get_attributes(); let attrs = FirmwareAttributes::new();
for a in attrs { for attr in attrs.attributes() {
dbg!(&a); 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
}
} }

View File

@@ -3,6 +3,7 @@
pub mod cpu; pub mod cpu;
pub mod error; pub mod error;
pub mod firmware_attributes;
pub mod hid_raw; pub mod hid_raw;
pub mod keyboard_led; pub mod keyboard_led;
pub(crate) mod macros; pub(crate) mod macros;