mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Add the missing dirs, dumbarse
This commit is contained in:
287
asusd/src/ctrl_power.rs
Normal file
287
asusd/src/ctrl_power.rs
Normal file
@@ -0,0 +1,287 @@
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use config_traits::StdConfig;
|
||||
use log::{error, info, warn};
|
||||
use rog_platform::power::AsusPower;
|
||||
use rog_platform::supported::ChargeSupportedFunctions;
|
||||
use systemd_zbus::{ManagerProxy as SystemdProxy, Mode, UnitFileState};
|
||||
use tokio::time::sleep;
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
use zbus::{dbus_interface, Connection, SignalContext};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::RogError;
|
||||
use crate::{task_watch_item, CtrlTask, GetSupported};
|
||||
|
||||
const ZBUS_PATH: &str = "/org/asuslinux/Power";
|
||||
const NVIDIA_POWERD: &str = "nvidia-powerd.service";
|
||||
|
||||
impl GetSupported for CtrlPower {
|
||||
type A = ChargeSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
ChargeSupportedFunctions {
|
||||
charge_level_set: if let Ok(power) = AsusPower::new() {
|
||||
power.has_charge_control_end_threshold()
|
||||
} else {
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtrlPower {
|
||||
power: AsusPower,
|
||||
config: Arc<Mutex<Config>>,
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlPower {
|
||||
async fn set_charge_control_end_threshold(
|
||||
&mut self,
|
||||
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
||||
limit: u8,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
if !(20..=100).contains(&limit) {
|
||||
return Err(RogError::ChargeLimit(limit))?;
|
||||
}
|
||||
self.set(limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
Self::notify_charge_control_end_threshold(&ctxt, limit)
|
||||
.await
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn charge_control_end_threshold(&self) -> u8 {
|
||||
loop {
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
let limit = self
|
||||
.power
|
||||
.get_charge_control_end_threshold()
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: get_charge_control_end_threshold {}", err);
|
||||
err
|
||||
})
|
||||
.unwrap_or(100);
|
||||
|
||||
config.read();
|
||||
config.bat_charge_limit = limit;
|
||||
config.write();
|
||||
|
||||
return config.bat_charge_limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mains_online(&self) -> bool {
|
||||
if self.power.has_online() {
|
||||
if let Ok(v) = self.power.get_online() {
|
||||
return v == 1;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_charge_control_end_threshold(
|
||||
ctxt: &SignalContext<'_>,
|
||||
limit: u8,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_interface(signal)]
|
||||
async fn notify_mains_online(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ZbusRun for CtrlPower {
|
||||
async fn add_to_server(self, server: &mut Connection) {
|
||||
Self::add_to_server_helper(self, ZBUS_PATH, server).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Reloadable for CtrlPower {
|
||||
async fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
config.read();
|
||||
self.set(config.bat_charge_limit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlPower {
|
||||
task_watch_item!(charge_control_end_threshold power);
|
||||
|
||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||
Ok(CtrlPower {
|
||||
power: AsusPower::new()?,
|
||||
config,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn set(&self, limit: u8) -> Result<(), RogError> {
|
||||
if !(20..=100).contains(&limit) {
|
||||
return Err(RogError::ChargeLimit(limit));
|
||||
}
|
||||
|
||||
self.power.set_charge_control_end_threshold(limit)?;
|
||||
|
||||
info!("Battery charge limit: {}", limit);
|
||||
|
||||
if let Some(mut config) = self.config.try_lock() {
|
||||
config.read();
|
||||
config.bat_charge_limit = limit;
|
||||
config.write();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CtrlTask for CtrlPower {
|
||||
fn zbus_path() -> &'static str {
|
||||
ZBUS_PATH
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let conn = zbus::Connection::system().await?;
|
||||
let sysd1 = SystemdProxy::new(&conn).await?;
|
||||
let sysd2 = sysd1.clone();
|
||||
let sysd3 = sysd1.clone();
|
||||
|
||||
let power1 = self.clone();
|
||||
let power2 = self.clone();
|
||||
self.create_sys_event_tasks(
|
||||
move || async {},
|
||||
move || {
|
||||
let power = power1.clone();
|
||||
let sysd = sysd1.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
|
||||
if lock.disable_nvidia_powerd_on_battery {
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
move || async {},
|
||||
move || {
|
||||
let power = power2.clone();
|
||||
let sysd = sysd2.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
|
||||
if lock.disable_nvidia_powerd_on_battery {
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
let config = self.config.clone();
|
||||
self.watch_charge_control_end_threshold(signal_ctxt.clone())
|
||||
.await?;
|
||||
|
||||
let ctrl = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut online = 10;
|
||||
loop {
|
||||
if let Ok(value) = ctrl.power.get_online() {
|
||||
if online != value {
|
||||
online = value;
|
||||
let mut config = config.lock().await;
|
||||
config.read();
|
||||
|
||||
if config.disable_nvidia_powerd_on_battery {
|
||||
do_nvidia_powerd_action(&sysd3, value == 1).await;
|
||||
}
|
||||
|
||||
Self::notify_mains_online(&signal_ctxt, value == 1)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut prog: Vec<&str> = Vec::new();
|
||||
if value == 1 {
|
||||
// AC ONLINE
|
||||
prog = config.ac_command.split_whitespace().collect();
|
||||
} else if value == 0 {
|
||||
// BATTERY
|
||||
prog = config.bat_command.split_whitespace().collect();
|
||||
}
|
||||
|
||||
if prog.len() > 1 {
|
||||
let mut cmd = Command::new(prog[0]);
|
||||
for arg in prog.iter().skip(1) {
|
||||
cmd.arg(*arg);
|
||||
}
|
||||
if let Err(e) = cmd.spawn() {
|
||||
if value == 1 {
|
||||
error!("AC power command error: {e}");
|
||||
} else {
|
||||
error!("Battery power command error: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The inotify doesn't pick up events when the kernel changes internal value
|
||||
// so we need to watch it with a thread and sleep unfortunately
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_nvidia_powerd_action(proxy: &SystemdProxy<'_>, ac_on: bool) {
|
||||
if let Ok(res) = proxy.get_unit_file_state(NVIDIA_POWERD).await {
|
||||
if res == UnitFileState::Enabled {
|
||||
if ac_on {
|
||||
proxy
|
||||
.start_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
} else {
|
||||
proxy
|
||||
.stop_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user