diff --git a/asusd/src/asus_armoury/attr_enum_int.rs b/asusd/src/asus_armoury/attr_enum_int.rs new file mode 100644 index 00000000..29051b34 --- /dev/null +++ b/asusd/src/asus_armoury/attr_enum_int.rs @@ -0,0 +1,90 @@ +use crate::{error::RogError, ASUS_ZBUS_PATH}; +use log::error; +use rog_platform::firmware_attributes::{AttrValue, Attribute}; +use serde::{Deserialize, Serialize}; +use zbus::{ + fdo, interface, + zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Type, Value}, + Connection, +}; + +const MOD_NAME: &str = "asus_armoury"; + +#[derive(Debug, Default, Clone, Deserialize, Serialize, Type, Value, OwnedValue)] +pub struct PossibleValues { + strings: Vec, + nums: Vec, +} + +fn dbus_path_for_attr(attr_name: &str) -> OwnedObjectPath { + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{attr_name}")).into() +} + +pub struct AsusArmouryAttribute(Attribute); + +impl AsusArmouryAttribute { + pub fn new(attr: Attribute) -> Self { + Self(attr) + } + + pub async fn start_tasks(self, connection: &Connection) -> Result<(), RogError> { + // self.reload() + // .await + // .unwrap_or_else(|err| warn!("Controller error: {}", err)); + let path = dbus_path_for_attr(self.0.name()); + connection + .object_server() + .at(path.clone(), self) + .await + .map_err(|e| error!("Couldn't add server at path: {path}, {e:?}")) + .ok(); + Ok(()) + } +} + +#[interface(name = "org.asuslinux.AsusArmoury")] +impl AsusArmouryAttribute { + #[zbus(property)] + async fn name(&self) -> String { + self.0.name().to_string() + } + + #[zbus(property)] + async fn default_value(&self) -> i32 { + match self.0.default_value() { + AttrValue::Integer(i) => *i, + _ => -1, + } + } + + #[zbus(property)] + async fn possible_values(&self) -> Vec { + match self.0.possible_values() { + AttrValue::EnumInt(i) => i.clone(), + _ => Vec::default(), + } + } + + #[zbus(property)] + async fn current_value(&self) -> fdo::Result { + if let Ok(v) = self.0.current_value() { + if let AttrValue::Integer(i) = v { + return Ok(i); + } + } + Err(fdo::Error::Failed( + "Could not read current value".to_string(), + )) + } + + #[zbus(property)] + async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> { + Ok(self + .0 + .set_current_value(AttrValue::Integer(value)) + .map_err(|e| { + error!("Could not set value: {e:?}"); + e + })?) + } +} diff --git a/asusd/src/asus_armoury/attr_enum_str.rs b/asusd/src/asus_armoury/attr_enum_str.rs new file mode 100644 index 00000000..1aed3577 --- /dev/null +++ b/asusd/src/asus_armoury/attr_enum_str.rs @@ -0,0 +1,95 @@ +use crate::{error::RogError, ASUS_ZBUS_PATH}; +use log::error; +use rog_platform::firmware_attributes::{AttrType, AttrValue, Attribute}; +use serde::{Deserialize, Serialize}; +use zbus::{ + fdo, interface, + zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Type, Value}, + Connection, +}; + +const MOD_NAME: &str = "asus_armoury"; + +#[derive(Debug, Default, Clone, Deserialize, Serialize, Type, Value, OwnedValue)] +pub struct PossibleValues { + strings: Vec, + nums: Vec, +} + +fn dbus_path_for_attr(attr_name: &str) -> OwnedObjectPath { + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{attr_name}")).into() +} + +pub struct AsusArmouryAttribute(Attribute); + +impl AsusArmouryAttribute { + pub fn new(attr: Attribute) -> Self { + Self(attr) + } + + pub async fn start_tasks(self, connection: &Connection) -> Result<(), RogError> { + // self.reload() + // .await + // .unwrap_or_else(|err| warn!("Controller error: {}", err)); + let path = dbus_path_for_attr(self.0.name()); + connection + .object_server() + .at(path.clone(), self) + .await + .map_err(|e| error!("Couldn't add server at path: {path}, {e:?}")) + .ok(); + Ok(()) + } +} + +#[interface(name = "org.asuslinux.AsusArmoury")] +impl AsusArmouryAttribute { + #[zbus(property)] + async fn name(&self) -> String { + self.0.name().to_string() + } + + #[zbus(property)] + fn attribute_type(&self) -> AttrType { + self.0.attribute_type() + } + + #[zbus(property)] + async fn default_value(&self) -> i32 { + match self.0.default_value() { + AttrValue::Integer(i) => *i, + _ => -1, + } + } + + #[zbus(property)] + async fn possible_values(&self) -> Vec { + match self.0.possible_values() { + AttrValue::EnumStr(s) => s.clone(), + _ => Vec::default(), + } + } + + #[zbus(property)] + async fn current_value(&self) -> fdo::Result { + if let Ok(v) = self.0.current_value() { + if let AttrValue::String(s) = v { + return Ok(s); + } + } + Err(fdo::Error::Failed( + "Could not read current value".to_string(), + )) + } + + #[zbus(property)] + async fn set_current_value(&mut self, value: String) -> fdo::Result<()> { + Ok(self + .0 + .set_current_value(AttrValue::String(value)) + .map_err(|e| { + error!("Could not set value: {e:?}"); + e + })?) + } +} diff --git a/asusd/src/asus_armoury/attr_int.rs b/asusd/src/asus_armoury/attr_int.rs new file mode 100644 index 00000000..84221771 --- /dev/null +++ b/asusd/src/asus_armoury/attr_int.rs @@ -0,0 +1,105 @@ +use crate::{error::RogError, ASUS_ZBUS_PATH}; +use log::error; +use rog_platform::firmware_attributes::{AttrValue, Attribute}; +use serde::{Deserialize, Serialize}; +use zbus::{ + fdo, interface, + zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Type, Value}, + Connection, +}; + +const MOD_NAME: &str = "asus_armoury"; + +#[derive(Debug, Default, Clone, Deserialize, Serialize, Type, Value, OwnedValue)] +pub struct PossibleValues { + strings: Vec, + nums: Vec, +} + +fn dbus_path_for_attr(attr_name: &str) -> OwnedObjectPath { + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{attr_name}")).into() +} + +pub struct AsusArmouryAttribute(Attribute); + +impl AsusArmouryAttribute { + pub fn new(attr: Attribute) -> Self { + Self(attr) + } + + pub async fn start_tasks(self, connection: &Connection) -> Result<(), RogError> { + // self.reload() + // .await + // .unwrap_or_else(|err| warn!("Controller error: {}", err)); + let path = dbus_path_for_attr(self.0.name()); + connection + .object_server() + .at(path.clone(), self) + .await + .map_err(|e| error!("Couldn't add server at path: {path}, {e:?}")) + .ok(); + Ok(()) + } +} + +/// If return is `-1` on a property then there is avilable value for that property +#[interface(name = "org.asuslinux.AsusArmoury")] +impl AsusArmouryAttribute { + #[zbus(property)] + async fn name(&self) -> String { + self.0.name().to_string() + } + + /// If return is `-1` then there is no default value + #[zbus(property)] + async fn default_value(&self) -> i32 { + match self.0.default_value() { + AttrValue::Integer(i) => *i, + _ => -1, + } + } + + #[zbus(property)] + async fn min_value(&self) -> i32 { + match self.0.min_value() { + AttrValue::Integer(i) => *i, + _ => -1, + } + } + + #[zbus(property)] + async fn max_value(&self) -> i32 { + match self.0.max_value() { + AttrValue::Integer(i) => *i, + _ => -1, + } + } + + #[zbus(property)] + async fn scalar_increment(&self) -> i32 { + self.0.scalar_increment().unwrap_or(1) + } + + #[zbus(property)] + async fn current_value(&self) -> fdo::Result { + if let Ok(v) = self.0.current_value() { + if let AttrValue::Integer(i) = v { + return Ok(i); + } + } + Err(fdo::Error::Failed( + "Could not read current value".to_string(), + )) + } + + #[zbus(property)] + async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> { + Ok(self + .0 + .set_current_value(AttrValue::Integer(value)) + .map_err(|e| { + error!("Could not set value: {e:?}"); + e + })?) + } +} diff --git a/asusd/src/asus_armoury/mod.rs b/asusd/src/asus_armoury/mod.rs new file mode 100644 index 00000000..f55cee01 --- /dev/null +++ b/asusd/src/asus_armoury/mod.rs @@ -0,0 +1,33 @@ +use rog_platform::firmware_attributes::{AttrType, FirmwareAttributes}; +use zbus::Connection; + +use crate::error::RogError; + +pub mod attr_enum_int; +pub mod attr_enum_str; +pub mod attr_int; + +pub async fn start_attributes_zbus(server: &Connection) -> Result<(), RogError> { + for attr in FirmwareAttributes::new().attributes() { + match attr.attribute_type() { + AttrType::MinMax => { + attr_int::AsusArmouryAttribute::new(attr.clone()) + .start_tasks(server) + .await?; + } + AttrType::EnumInt => { + attr_enum_int::AsusArmouryAttribute::new(attr.clone()) + .start_tasks(server) + .await?; + } + AttrType::EnumStr => { + attr_enum_str::AsusArmouryAttribute::new(attr.clone()) + .start_tasks(server) + .await?; + } + + AttrType::Unbounded => {} + } + } + Ok(()) +} diff --git a/asusd/src/aura_manager.rs b/asusd/src/aura_manager.rs index ddd0b013..5fc70038 100644 --- a/asusd/src/aura_manager.rs +++ b/asusd/src/aura_manager.rs @@ -23,8 +23,9 @@ use crate::aura_scsi::trait_impls::ScsiZbus; use crate::aura_slash::trait_impls::SlashZbus; use crate::aura_types::DeviceHandle; use crate::error::RogError; +use crate::ASUS_ZBUS_PATH; -pub const ASUS_ZBUS_PATH: &str = "/org/asuslinux"; +const MOD_NAME: &str = "aura"; /// Returns only the Device details concatenated in a form usable for /// adding/appending to a filename @@ -54,26 +55,27 @@ pub fn filename_partial(parent: &Device) -> Option { fn dbus_path_for_dev(parent: &Device) -> Option { if let Some(filename) = filename_partial(parent) { return Some( - ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{filename}")).into(), + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{filename}")) + .into(), ); } None } fn dbus_path_for_tuf() -> OwnedObjectPath { - ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/tuf")).into() + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/tuf")).into() } fn dbus_path_for_slash() -> OwnedObjectPath { - ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/slash")).into() + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/slash")).into() } fn dbus_path_for_anime() -> OwnedObjectPath { - ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/anime")).into() + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/anime")).into() } fn dbus_path_for_scsi(prod_id: &str) -> OwnedObjectPath { - ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{prod_id}_scsi")).into() + ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{MOD_NAME}/{prod_id}_scsi")).into() } fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool { @@ -83,15 +85,6 @@ fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool { false } -// TODO: -// - make this the HID manager (and universal) -// - *really* need to make most of this actual kernel drivers -// - LED class -// - RGB modes (how, attribute?) -// - power features (how, attribute?) -// - what about per-key stuff? -// - how would the AniMe be exposed? Just a series of LEDs? - /// A device. /// /// Each controller within should track its dbus path so it can be removed if diff --git a/asusd/src/daemon.rs b/asusd/src/daemon.rs index edc0191a..ff5d658f 100644 --- a/asusd/src/daemon.rs +++ b/asusd/src/daemon.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use ::zbus::export::futures_util::lock::Mutex; use ::zbus::Connection; +use asusd::asus_armoury::start_attributes_zbus; use asusd::aura_manager::DeviceManager; use asusd::config::Config; use asusd::ctrl_fancurves::CtrlFanCurveZbus; @@ -56,23 +57,20 @@ async fn start_daemon() -> Result<(), Box> { // println!("{:?}", supported.supported_functions()); // Start zbus server - let mut connection = Connection::system().await?; - connection - .object_server() - .at("/", ObjectManager) - .await - .unwrap(); + let mut server = Connection::system().await?; + server.object_server().at("/", ObjectManager).await.unwrap(); let config = Config::new().load(); let cfg_path = config.file_path(); let config = Arc::new(Mutex::new(config)); // supported.add_to_server(&mut connection).await; + start_attributes_zbus(&server).await?; match CtrlFanCurveZbus::new() { Ok(ctrl) => { - let sig_ctx = CtrlFanCurveZbus::signal_context(&connection)?; - start_tasks(ctrl, &mut connection, sig_ctx).await?; + let sig_ctx = CtrlFanCurveZbus::signal_context(&server)?; + start_tasks(ctrl, &mut server, sig_ctx).await?; } Err(err) => { error!("FanCurves: {}", err); @@ -82,24 +80,24 @@ async fn start_daemon() -> Result<(), Box> { match CtrlPlatform::new( config.clone(), &cfg_path, - CtrlPlatform::signal_context(&connection)?, + CtrlPlatform::signal_context(&server)?, ) { Ok(ctrl) => { - let sig_ctx = CtrlPlatform::signal_context(&connection)?; - start_tasks(ctrl, &mut connection, sig_ctx).await?; + let sig_ctx = CtrlPlatform::signal_context(&server)?; + start_tasks(ctrl, &mut server, sig_ctx).await?; } Err(err) => { error!("CtrlPlatform: {}", err); } } - let _ = DeviceManager::new(connection.clone()).await?; + let _ = DeviceManager::new(server.clone()).await?; // Request dbus name after finishing initalizing all functions - connection.request_name(DBUS_NAME).await?; + server.request_name(DBUS_NAME).await?; loop { // This is just a blocker to idle and ensure the reator reacts - connection.executor().tick().await; + server.executor().tick().await; } } diff --git a/asusd/src/lib.rs b/asusd/src/lib.rs index 8a21eb3e..2d5853a8 100644 --- a/asusd/src/lib.rs +++ b/asusd/src/lib.rs @@ -6,6 +6,7 @@ pub mod ctrl_fancurves; /// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode pub mod ctrl_platform; +pub mod asus_armoury; pub mod aura_anime; pub mod aura_laptop; pub mod aura_manager; @@ -30,6 +31,8 @@ use zbus::Connection; use crate::error::RogError; const CONFIG_PATH_BASE: &str = "/etc/asusd/"; +pub const ASUS_ZBUS_PATH: &str = "/org/asuslinux"; + pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; diff --git a/rog-control-center/translations/en/rog-control-center.po b/rog-control-center/translations/en/rog-control-center.po index 40c4660f..b42706c5 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-12-24 22:29+0000\n" +"POT-Creation-Date: 2024-12-25 06:28+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 b90220fd..c081b011 100644 --- a/rog-platform/src/firmware_attributes.rs +++ b/rog-platform/src/firmware_attributes.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use typeshare::typeshare; -use zbus::zvariant::Type; +use zbus::zvariant::{OwnedValue, Type, Value}; use crate::error::PlatformError; @@ -31,7 +31,15 @@ fn read_string(path: &Path) -> Result { Ok(buf.trim().to_string()) } -#[derive(Debug, Default, PartialEq, PartialOrd)] +#[derive(Debug, Clone, Deserialize, Serialize, Type, Value, OwnedValue)] +pub enum AttrType { + MinMax = 0, + EnumInt = 1, + EnumStr = 2, + Unbounded = 3, +} + +#[derive(Debug, Default, Clone, PartialEq, PartialOrd)] pub enum AttrValue { Integer(i32), String(String), @@ -41,7 +49,7 @@ pub enum AttrValue { None, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Attribute { name: String, help: String, @@ -62,6 +70,20 @@ impl Attribute { &self.help } + pub fn attribute_type(&self) -> AttrType { + let mut attr_type = AttrType::Unbounded; + match self.max_value { + AttrValue::Integer(_) => attr_type = AttrType::MinMax, + _ => {} + } + match self.possible_values { + AttrValue::EnumInt(_) => attr_type = AttrType::EnumInt, + AttrValue::EnumStr(_) => attr_type = AttrType::EnumStr, + _ => {} + } + attr_type + } + /// Read the `current_value` directly from the attribute path pub fn current_value(&self) -> Result { match read_string(&self.base_path.join("current_value")) {