mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Refactor: Make all Aura type devices use "device_manager"
Open the door to adding many other types of "aura" devices later.
This commit is contained in:
343
asusd/src/aura_laptop/trait_impls.rs
Normal file
343
asusd/src/aura_laptop/trait_impls.rs
Normal file
@@ -0,0 +1,343 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use config_traits::StdConfig;
|
||||
use log::{debug, error, info, warn};
|
||||
use rog_aura::keyboard::{AuraLaptopUsbPackets, LaptopAuraPower};
|
||||
use rog_aura::{AuraDeviceType, AuraEffect, AuraModeNum, AuraZone, LedBrightness, PowerZones};
|
||||
use zbus::fdo::Error as ZbErr;
|
||||
use zbus::object_server::SignalEmitter;
|
||||
use zbus::zvariant::OwnedObjectPath;
|
||||
use zbus::{interface, Connection};
|
||||
|
||||
use super::Aura;
|
||||
use crate::error::RogError;
|
||||
use crate::{CtrlTask, Reloadable};
|
||||
|
||||
pub const AURA_ZBUS_NAME: &str = "Aura";
|
||||
pub const AURA_ZBUS_PATH: &str = "/org/asuslinux";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuraZbus(Aura);
|
||||
|
||||
impl AuraZbus {
|
||||
pub fn new(aura: Aura) -> Self {
|
||||
Self(aura)
|
||||
}
|
||||
|
||||
pub async fn start_tasks(
|
||||
mut self,
|
||||
connection: &Connection,
|
||||
// _signal_ctx: SignalEmitter<'static>,
|
||||
path: OwnedObjectPath,
|
||||
) -> Result<(), RogError> {
|
||||
// let task = zbus.clone();
|
||||
// let signal_ctx = signal_ctx.clone();
|
||||
self.reload()
|
||||
.await
|
||||
.unwrap_or_else(|err| warn!("Controller error: {}", err));
|
||||
connection
|
||||
.object_server()
|
||||
.at(path.clone(), self)
|
||||
.await
|
||||
.map_err(|e| error!("Couldn't add server at path: {path}, {e:?}"))
|
||||
.ok();
|
||||
// TODO: skip this until we keep handles to tasks so they can be killed
|
||||
// task.create_tasks(signal_ctx).await
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The main interface for changing, reading, or notfying
|
||||
///
|
||||
/// LED commands are split between Brightness, Modes, Per-Key
|
||||
#[interface(name = "org.asuslinux.Aura")]
|
||||
impl AuraZbus {
|
||||
/// Return the device type for this Aura keyboard
|
||||
#[zbus(property)]
|
||||
async fn device_type(&self) -> AuraDeviceType {
|
||||
self.0.config.lock().await.led_type
|
||||
}
|
||||
|
||||
/// Return the current LED brightness
|
||||
#[zbus(property)]
|
||||
async fn brightness(&self) -> Result<LedBrightness, ZbErr> {
|
||||
if let Some(bl) = self.0.backlight.as_ref() {
|
||||
return Ok(bl.lock().await.get_brightness().map(|n| n.into())?);
|
||||
}
|
||||
Err(ZbErr::Failed("No sysfs brightness control".to_string()))
|
||||
}
|
||||
|
||||
/// Set the keyboard brightness level (0-3)
|
||||
#[zbus(property)]
|
||||
async fn set_brightness(&mut self, brightness: LedBrightness) -> Result<(), ZbErr> {
|
||||
if let Some(bl) = self.0.backlight.as_ref() {
|
||||
return Ok(bl.lock().await.set_brightness(brightness.into())?);
|
||||
}
|
||||
Err(ZbErr::Failed("No sysfs brightness control".to_string()))
|
||||
}
|
||||
|
||||
/// Total levels of brightness available
|
||||
#[zbus(property)]
|
||||
async fn supported_brightness(&self) -> Vec<LedBrightness> {
|
||||
vec![
|
||||
LedBrightness::Off,
|
||||
LedBrightness::Low,
|
||||
LedBrightness::Med,
|
||||
LedBrightness::High,
|
||||
]
|
||||
}
|
||||
|
||||
/// The total available modes
|
||||
#[zbus(property)]
|
||||
async fn supported_basic_modes(&self) -> Result<Vec<AuraModeNum>, ZbErr> {
|
||||
let config = self.0.config.lock().await;
|
||||
Ok(config.builtins.keys().cloned().collect())
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn supported_basic_zones(&self) -> Result<Vec<AuraZone>, ZbErr> {
|
||||
let config = self.0.config.lock().await;
|
||||
Ok(config.support_data.basic_zones.clone())
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn supported_power_zones(&self) -> Result<Vec<PowerZones>, ZbErr> {
|
||||
let config = self.0.config.lock().await;
|
||||
Ok(config.support_data.power_zones.clone())
|
||||
}
|
||||
|
||||
/// The current mode data
|
||||
#[zbus(property)]
|
||||
async fn led_mode(&self) -> Result<AuraModeNum, ZbErr> {
|
||||
// entirely possible to deadlock here, so use try instead of lock()
|
||||
// let ctrl = self.0.lock().await;
|
||||
// Ok(config.current_mode)
|
||||
if let Ok(config) = self.0.config.try_lock() {
|
||||
Ok(config.current_mode)
|
||||
} else {
|
||||
Err(ZbErr::Failed("Aura control couldn't lock self".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an Aura effect if the effect mode or zone is supported.
|
||||
///
|
||||
/// On success the aura config file is read to refresh cached values, then
|
||||
/// the effect is stored and config written to disk.
|
||||
#[zbus(property)]
|
||||
async fn set_led_mode(&mut self, num: AuraModeNum) -> Result<(), ZbErr> {
|
||||
let mut config = self.0.config.lock().await;
|
||||
config.current_mode = num;
|
||||
self.0.write_current_config_mode(&mut config).await?;
|
||||
if config.brightness == LedBrightness::Off {
|
||||
config.brightness = LedBrightness::Med;
|
||||
}
|
||||
self.0.set_brightness(config.brightness.into()).await?;
|
||||
config.write();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The current mode data
|
||||
#[zbus(property)]
|
||||
async fn led_mode_data(&self) -> Result<AuraEffect, ZbErr> {
|
||||
// entirely possible to deadlock here, so use try instead of lock()
|
||||
if let Ok(config) = self.0.config.try_lock() {
|
||||
let mode = config.current_mode;
|
||||
match config.builtins.get(&mode) {
|
||||
Some(effect) => Ok(effect.clone()),
|
||||
None => Err(ZbErr::Failed("Could not get the current effect".into())),
|
||||
}
|
||||
} else {
|
||||
Err(ZbErr::Failed("Aura control couldn't lock self".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an Aura effect if the effect mode or zone is supported.
|
||||
///
|
||||
/// On success the aura config file is read to refresh cached values, then
|
||||
/// the effect is stored and config written to disk.
|
||||
#[zbus(property)]
|
||||
async fn set_led_mode_data(&mut self, effect: AuraEffect) -> Result<(), ZbErr> {
|
||||
let mut config = self.0.config.lock().await;
|
||||
if !config.support_data.basic_modes.contains(&effect.mode)
|
||||
|| effect.zone != AuraZone::None
|
||||
&& !config.support_data.basic_zones.contains(&effect.zone)
|
||||
{
|
||||
return Err(ZbErr::NotSupported(format!(
|
||||
"The Aura effect is not supported: {effect:?}"
|
||||
)));
|
||||
}
|
||||
|
||||
self.0
|
||||
.write_effect_and_apply(config.led_type, &effect)
|
||||
.await?;
|
||||
if config.brightness == LedBrightness::Off {
|
||||
config.brightness = LedBrightness::Med;
|
||||
}
|
||||
self.0.set_brightness(config.brightness.into()).await?;
|
||||
config.set_builtin(effect);
|
||||
config.write();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the data set for every mode available
|
||||
async fn all_mode_data(&self) -> BTreeMap<AuraModeNum, AuraEffect> {
|
||||
let config = self.0.config.lock().await;
|
||||
config.builtins.clone()
|
||||
}
|
||||
|
||||
// As property doesn't work for AuraPowerDev (complexity of serialization?)
|
||||
#[zbus(property)]
|
||||
async fn led_power(&self) -> LaptopAuraPower {
|
||||
let config = self.0.config.lock().await;
|
||||
config.enabled.clone()
|
||||
}
|
||||
|
||||
/// Set a variety of states, input is array of enum.
|
||||
/// `enabled` sets if the sent array should be disabled or enabled
|
||||
///
|
||||
/// For Modern ROG devices the "enabled" flag is ignored.
|
||||
#[zbus(property)]
|
||||
async fn set_led_power(&mut self, options: LaptopAuraPower) -> Result<(), ZbErr> {
|
||||
let mut config = self.0.config.lock().await;
|
||||
for opt in options.states {
|
||||
let zone = opt.zone;
|
||||
for config in config.enabled.states.iter_mut() {
|
||||
if config.zone == zone {
|
||||
*config = opt;
|
||||
}
|
||||
}
|
||||
}
|
||||
config.write();
|
||||
Ok(self.0.set_power_states(&config).await.map_err(|e| {
|
||||
warn!("{}", e);
|
||||
e
|
||||
})?)
|
||||
}
|
||||
|
||||
/// On machine that have some form of either per-key keyboard or per-zone
|
||||
/// this can be used to write custom effects over dbus. The input is a
|
||||
/// nested `Vec<Vec<8>>` where `Vec<u8>` is a raw USB packet
|
||||
async fn direct_addressing_raw(&self, data: AuraLaptopUsbPackets) -> Result<(), ZbErr> {
|
||||
let mut config = self.0.config.lock().await;
|
||||
self.0.write_effect_block(&mut config, &data).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlTask for AuraZbus {
|
||||
fn zbus_path() -> &'static str {
|
||||
"/org/asuslinux"
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, _: SignalEmitter<'static>) -> Result<(), RogError> {
|
||||
let inner1 = self.0.clone();
|
||||
let inner3 = self.0.clone();
|
||||
self.create_sys_event_tasks(
|
||||
move |sleeping| {
|
||||
let inner1 = inner1.clone();
|
||||
// unwrap as we want to bomb out of the task
|
||||
async move {
|
||||
if !sleeping {
|
||||
info!("CtrlKbdLedTask reloading brightness and modes");
|
||||
if let Some(backlight) = &inner1.backlight {
|
||||
backlight
|
||||
.lock()
|
||||
.await
|
||||
.set_brightness(inner1.config.lock().await.brightness.into())
|
||||
.map_err(|e| {
|
||||
error!("CtrlKbdLedTask: {e}");
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
let mut config = inner1.config.lock().await;
|
||||
inner1
|
||||
.write_current_config_mode(&mut config)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("CtrlKbdLedTask: {e}");
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
} else if sleeping {
|
||||
inner1
|
||||
.update_config()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("CtrlKbdLedTask: {e}");
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
move |_shutting_down| {
|
||||
let inner3 = inner3.clone();
|
||||
async move {
|
||||
info!("CtrlKbdLedTask reloading brightness and modes");
|
||||
if let Some(backlight) = &inner3.backlight {
|
||||
// unwrap as we want to bomb out of the task
|
||||
backlight
|
||||
.lock()
|
||||
.await
|
||||
.set_brightness(inner3.config.lock().await.brightness.into())
|
||||
.map_err(|e| {
|
||||
error!("CtrlKbdLedTask: {e}");
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
move |_lid_closed| {
|
||||
// on lid change
|
||||
async move {}
|
||||
},
|
||||
move |_power_plugged| {
|
||||
// power change
|
||||
async move {}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
// let ctrl2 = self.0.clone();
|
||||
// let ctrl = self.0.lock().await;
|
||||
// if ctrl.led_node.has_brightness_control() {
|
||||
// let watch = ctrl.led_node.monitor_brightness()?;
|
||||
// tokio::spawn(async move {
|
||||
// let mut buffer = [0; 32];
|
||||
// watch
|
||||
// .into_event_stream(&mut buffer)
|
||||
// .unwrap()
|
||||
// .for_each(|_| async {
|
||||
// if let Some(lock) = ctrl2.try_lock() {
|
||||
// load_save(true, lock).unwrap(); // unwrap as we want
|
||||
// // to
|
||||
// // bomb out of the
|
||||
// // task
|
||||
// }
|
||||
// })
|
||||
// .await;
|
||||
// });
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Reloadable for AuraZbus {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
self.0.fix_ally_power().await?;
|
||||
debug!("reloading keyboard mode");
|
||||
let mut config = self.0.lock_config().await;
|
||||
self.0.write_current_config_mode(&mut config).await?;
|
||||
debug!("reloading power states");
|
||||
self.0
|
||||
.set_power_states(&config)
|
||||
.await
|
||||
.map_err(|err| warn!("{err}"))
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user