mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
profiles: add dbus methods to change active profile
Closes #81, #73, #68
This commit is contained in:
@@ -7,7 +7,10 @@ use crate::{
|
||||
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||
};
|
||||
use log::{error, info, warn};
|
||||
use rog_aura::{AuraEffect, LED_MSG_LEN, LedBrightness, usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON}};
|
||||
use rog_aura::{
|
||||
usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON},
|
||||
AuraEffect, LedBrightness, LED_MSG_LEN,
|
||||
};
|
||||
use rog_types::supported::LedSupportedFunctions;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Read, Write};
|
||||
@@ -312,11 +315,7 @@ impl CtrlKbdLed {
|
||||
|
||||
/// Set the keyboard LED to active if laptop is awake
|
||||
fn set_awake_enable(&self, enabled: bool) -> Result<(), RogError> {
|
||||
let bytes = if enabled {
|
||||
LED_AWAKE_ON
|
||||
} else {
|
||||
LED_AWAKE_OFF
|
||||
};
|
||||
let bytes = if enabled { LED_AWAKE_ON } else { LED_AWAKE_OFF };
|
||||
self.write_bytes(&bytes)?;
|
||||
self.write_bytes(&LED_SET)?;
|
||||
// Changes won't persist unless apply is set
|
||||
@@ -326,11 +325,7 @@ impl CtrlKbdLed {
|
||||
|
||||
/// Set the keyboard suspend animation to on if plugged in
|
||||
fn set_sleep_anim_enable(&self, enabled: bool) -> Result<(), RogError> {
|
||||
let bytes = if enabled {
|
||||
LED_SLEEP_ON
|
||||
} else {
|
||||
LED_SLEEP_OFF
|
||||
};
|
||||
let bytes = if enabled { LED_SLEEP_ON } else { LED_SLEEP_OFF };
|
||||
self.write_bytes(&bytes)?;
|
||||
self.write_bytes(&LED_SET)?;
|
||||
// Changes won't persist unless apply is set
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod zbus;
|
||||
|
||||
use crate::error::RogError;
|
||||
use crate::{config::Config, GetSupported};
|
||||
use log::{info, warn};
|
||||
@@ -10,8 +12,6 @@ use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::{dbus_interface, fdo::Error};
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
||||
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
||||
@@ -34,160 +34,6 @@ impl GetSupported for CtrlFanAndCpu {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FanAndCpuZbus {
|
||||
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
||||
}
|
||||
|
||||
impl FanAndCpuZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl FanAndCpuZbus {
|
||||
/// Set profile details
|
||||
fn set_profile(&self, profile: String) {
|
||||
if let Ok(event) = serde_json::from_str(&profile) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
cfg.read();
|
||||
ctrl.handle_profile_event(&event, &mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string(profile) {
|
||||
self.notify_profile(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn next_profile(&mut self) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
cfg.read();
|
||||
ctrl.do_next_profile(&mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string(profile) {
|
||||
self.notify_profile(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
return Ok(cfg.active_profile.clone());
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile name".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: Profile can't implement Type because of Curve
|
||||
/// Fetch the active profile details
|
||||
fn profile(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Fetch all profile data
|
||||
fn profiles(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get all profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
||||
return Ok(profile_names);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to get all profile names".to_string()))
|
||||
}
|
||||
|
||||
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
|
||||
if !cfg.power_profiles.contains_key(profile) {
|
||||
return Err(Error::Failed("Invalid profile specified".to_string()));
|
||||
}
|
||||
|
||||
if cfg.power_profiles.keys().len() == 1 {
|
||||
return Err(Error::Failed("Cannot delete the last profile".to_string()));
|
||||
}
|
||||
|
||||
if cfg.active_profile == *profile {
|
||||
return Err(Error::Failed(
|
||||
"Cannot delete the active profile".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
cfg.power_profiles.remove(profile);
|
||||
cfg.write();
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to lock configuration".to_string()))
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
|
||||
}
|
||||
|
||||
impl crate::ZbusAdd for FanAndCpuZbus {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("DbusFanAndCpu: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Reloadable for CtrlFanAndCpu {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||
255
daemon/src/ctrl_profiles/zbus.rs
Normal file
255
daemon/src/ctrl_profiles/zbus.rs
Normal file
@@ -0,0 +1,255 @@
|
||||
use log::warn;
|
||||
use rog_fan_curve::Curve;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use zbus::{dbus_interface, fdo::Error};
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use super::CtrlFanAndCpu;
|
||||
|
||||
pub struct FanAndCpuZbus {
|
||||
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
||||
}
|
||||
|
||||
impl FanAndCpuZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl FanAndCpuZbus {
|
||||
/// Set profile details
|
||||
fn set_profile(&self, profile: String) {
|
||||
if let Ok(event) = serde_json::from_str(&profile) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
cfg.read();
|
||||
ctrl.handle_profile_event(&event, &mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string(profile) {
|
||||
self.notify_profile(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modify the active profile
|
||||
fn set_turbo(&self, enable: bool) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
// Update the profile then set it
|
||||
cfg.read();
|
||||
let profile = cfg.active_profile.clone();
|
||||
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||
profile.turbo = enable;
|
||||
}
|
||||
ctrl.set(&profile, &mut cfg)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify the active profile
|
||||
fn set_min_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
// Update the profile then set it
|
||||
cfg.read();
|
||||
let profile = cfg.active_profile.clone();
|
||||
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||
profile.min_percentage = percentage;
|
||||
}
|
||||
ctrl.set(&profile, &mut cfg)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify the active profile
|
||||
fn set_max_frequency(&self, percentage: u8) -> zbus::fdo::Result<()> {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
// Update the profile then set it
|
||||
cfg.read();
|
||||
let profile = cfg.active_profile.clone();
|
||||
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||
profile.max_percentage = percentage;
|
||||
}
|
||||
ctrl.set(&profile, &mut cfg)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify the active profile
|
||||
fn set_fan_preset(&self, preset: u8) -> zbus::fdo::Result<()> {
|
||||
if preset > 2 {
|
||||
return Err(zbus::fdo::Error::InvalidArgs(
|
||||
"Fan preset must be 0, 1, or 2".to_string(),
|
||||
));
|
||||
}
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
// Update the profile then set it
|
||||
cfg.read();
|
||||
let profile = cfg.active_profile.clone();
|
||||
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||
profile.fan_preset = preset;
|
||||
}
|
||||
ctrl.set(&profile, &mut cfg)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify the active profile
|
||||
fn set_fan_curve(&self, curve: String) -> zbus::fdo::Result<()> {
|
||||
let curve = Curve::from_config_str(&curve)
|
||||
.map_err(|err| zbus::fdo::Error::InvalidArgs(format!("Fan curve error: {}", err)))?;
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
// Update the profile then set it
|
||||
cfg.read();
|
||||
let profile = cfg.active_profile.clone();
|
||||
if let Some(profile) = cfg.power_profiles.get_mut(&profile) {
|
||||
profile.fan_curve = Some(curve);
|
||||
}
|
||||
ctrl.set(&profile, &mut cfg)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn next_profile(&mut self) {
|
||||
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||
cfg.read();
|
||||
ctrl.do_next_profile(&mut cfg)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string(profile) {
|
||||
self.notify_profile(&json)
|
||||
.unwrap_or_else(|err| warn!("{}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the active profile name
|
||||
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
return Ok(cfg.active_profile.clone());
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile name".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: Profile can't implement Type because of Curve
|
||||
/// Fetch the active profile details
|
||||
fn profile(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get active profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Fetch all profile data
|
||||
fn profiles(&mut self) -> zbus::fdo::Result<String> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
||||
return Ok(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::Failed(
|
||||
"Failed to get all profile details".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
||||
return Ok(profile_names);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to get all profile names".to_string()))
|
||||
}
|
||||
|
||||
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
||||
if let Ok(ctrl) = self.inner.try_lock() {
|
||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||
cfg.read();
|
||||
|
||||
if !cfg.power_profiles.contains_key(profile) {
|
||||
return Err(Error::Failed("Invalid profile specified".to_string()));
|
||||
}
|
||||
|
||||
if cfg.power_profiles.keys().len() == 1 {
|
||||
return Err(Error::Failed("Cannot delete the last profile".to_string()));
|
||||
}
|
||||
|
||||
if cfg.active_profile == *profile {
|
||||
return Err(Error::Failed(
|
||||
"Cannot delete the active profile".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
cfg.power_profiles.remove(profile);
|
||||
cfg.write();
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Failed("Failed to lock configuration".to_string()))
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
|
||||
}
|
||||
|
||||
impl crate::ZbusAdd for FanAndCpuZbus {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Profile"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("DbusFanAndCpu: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::{
|
||||
ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
|
||||
ctrl_leds::CtrlKbdLed, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
||||
ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed,
|
||||
ctrl_profiles::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
||||
};
|
||||
|
||||
use rog_types::supported::{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use daemon::ctrl_leds::{CtrlKbdLed, CtrlKbdLedTask, CtrlKbdLedZbus, CtrlKbdLedReloader};
|
||||
use daemon::ctrl_leds::{CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus};
|
||||
use daemon::{
|
||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||
};
|
||||
use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
||||
use daemon::{ctrl_anime::*, ctrl_gfx::gfx::CtrlGraphics};
|
||||
use daemon::{
|
||||
ctrl_fan_cpu::{CtrlFanAndCpu, FanAndCpuZbus},
|
||||
ctrl_profiles::{zbus::FanAndCpuZbus, CtrlFanAndCpu},
|
||||
laptops::LaptopLedData,
|
||||
};
|
||||
|
||||
|
||||
@@ -96,3 +96,10 @@ impl From<std::io::Error> for RogError {
|
||||
RogError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RogError> for zbus::fdo::Error {
|
||||
#[inline]
|
||||
fn from(err: RogError) -> Self {
|
||||
zbus::fdo::Error::Failed(format!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ pub(crate) mod config_old;
|
||||
pub mod ctrl_anime;
|
||||
/// Control of battery charge level
|
||||
pub mod ctrl_charge;
|
||||
/// GPU switching and power
|
||||
pub mod ctrl_gfx;
|
||||
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||
pub mod ctrl_leds;
|
||||
/// Control CPU min/max freq and turbo, fan mode, fan curves
|
||||
///
|
||||
/// Intel machines can control:
|
||||
@@ -19,11 +23,7 @@ pub mod ctrl_charge;
|
||||
/// - CPU turbo enable/disable
|
||||
/// - Fan mode (normal, boost, silent)
|
||||
/// - Fan min/max RPM curve
|
||||
pub mod ctrl_fan_cpu;
|
||||
/// GPU switching and power
|
||||
pub mod ctrl_gfx;
|
||||
/// Keyboard LED brightness control, RGB, and LED display modes
|
||||
pub mod ctrl_leds;
|
||||
pub mod ctrl_profiles;
|
||||
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
|
||||
pub mod ctrl_rog_bios;
|
||||
/// Laptop matching to determine capabilities
|
||||
|
||||
Reference in New Issue
Block a user