GFX control, no-tokio, no-async, dbus client refactor

- Working gfx modes <iGPU only, dGPU only, or hybrid>
- Add signal for gfx vendor change and make CLI wait for signal
- Add polling for led brightness to save to config
- Move daemon to zbus crate
- dbus client refactor
- Further dbus methods and updates
- Add basic notification user daemon and systemd service
This commit is contained in:
Luke D Jones
2020-09-13 15:05:59 +12:00
parent 4cdb06959b
commit fe6231ad4e
129 changed files with 2495 additions and 363398 deletions

View File

@@ -1,27 +1,24 @@
use daemon::{
config::Config, ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge,
ctrl_fan_cpu::CtrlFanAndCPU, ctrl_leds::CtrlKbdBacklight, dbus::dbus_create_tree,
laptops::match_laptop,
};
use ctrl_gfx::ctrl_gfx::CtrlGraphics;
use daemon::config::Config;
use daemon::ctrl_anime::CtrlAnimeDisplay;
use daemon::ctrl_charge::CtrlCharge;
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::laptops::match_laptop;
use dbus::{
channel::Sender,
nonblock::{Process, SyncConnection},
tree::Signal,
};
use dbus_tokio::connection;
use asus_nb::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
use daemon::Controller;
use asus_nb::DBUS_NAME;
use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
use log::{error, info, warn};
use std::error::Error;
use std::io::Write;
use std::sync::Arc;
use tokio::sync::Mutex;
use std::sync::Mutex;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
use zbus::fdo;
use zbus::Connection;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.target(env_logger::Target::Stdout)
@@ -30,7 +27,7 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
.init();
info!("Version: {}", daemon::VERSION);
start_daemon().await?;
start_daemon()?;
Ok(())
}
@@ -43,209 +40,100 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
// as fast as 1ms per row of the matrix inside it. (10ms total time)
//
// DBUS processing takes 6ms if not tokiod
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
fn start_daemon() -> Result<(), Box<dyn Error>> {
let laptop = match_laptop();
let mut config = if let Some(laptop) = laptop.as_ref() {
let config = if let Some(laptop) = laptop.as_ref() {
Config::default().load(laptop.supported_modes())
} else {
Config::default().load(&[])
};
let mut led_control = if let Some(laptop) = laptop {
Some(CtrlKbdBacklight::new(
let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)?
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
let config = Arc::new(Mutex::new(config));
match CtrlCharge::new(config.clone()) {
Ok(mut ctrl) => {
// Do a reload of any settings
ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("charge_control: {}", err);
}
}
match CtrlAnimeDisplay::new() {
Ok(ctrl) => {
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("AniMe control: {}", err);
}
}
match CtrlGraphics::new() {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
// Collect tasks for task thread
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
match CtrlFanAndCPU::new(config.clone()) {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
DbusFanAndCpu::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
Err(err) => {
error!("Profile control: {}", err);
}
};
if let Some(laptop) = laptop {
let ctrl = CtrlKbdBacklight::new(
laptop.usb_product(),
laptop.condev_iface(),
laptop.supported_modes().to_owned(),
))
} else {
None
};
let mut charge_control = CtrlCharge::new().map_or_else(
|err| {
error!("{}", err);
None
},
Some,
);
let mut fan_control = CtrlFanAndCPU::new().map_or_else(
|err| {
error!("{}", err);
None
},
Some,
);
// Reload settings
if let Some(ctrl) = fan_control.as_mut() {
ctrl.reload_from_config(&mut config)
.await
.unwrap_or_else(|err| warn!("Fan mode: {}", err));
config,
);
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
if let Some(ctrl) = charge_control.as_mut() {
ctrl.reload_from_config(&mut config)
.await
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
}
// TODO: implement messaging between threads to check fails
// These tasks generally read a sys path or file to check for a
// change
let _handle = std::thread::Builder::new()
.name("asusd watch".to_string())
.spawn(move || loop {
std::thread::sleep(std::time::Duration::from_millis(100));
if let Some(ctrl) = led_control.as_mut() {
ctrl.reload_from_config(&mut config)
.await
.unwrap_or_else(|err| warn!("Reload settings: {}", err));
}
let (resource, connection) = connection::new_system_sync()?;
tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
});
connection
.request_name(DBUS_NAME, false, true, true)
.await?;
let config = Arc::new(Mutex::new(config));
let (
tree,
aura_command_recv,
animatrix_recv,
_fan_mode_recv,
charge_limit_recv,
profile_recv,
led_changed_signal,
fanmode_signal,
charge_limit_signal,
) = dbus_create_tree(config.clone());
// We add the tree to the connection so that incoming method calls will be handled.
tree.start_receive_send(&*connection);
// Send boot signals
send_boot_signals(
connection.clone(),
config.clone(),
fanmode_signal.clone(),
charge_limit_signal.clone(),
led_changed_signal.clone(),
)
.await?;
// For helping with processing signals
start_signal_task(
connection.clone(),
config.clone(),
fanmode_signal,
charge_limit_signal,
);
// Begin all tasks
let mut handles = Vec::new();
if let Ok(ctrl) = CtrlAnimeDisplay::new() {
handles.append(&mut ctrl.spawn_task_loop(config.clone(), animatrix_recv, None, None));
}
if let Some(ctrl) = fan_control.take() {
handles.append(&mut ctrl.spawn_task_loop(config.clone(), profile_recv, None, None));
}
if let Some(ctrl) = charge_control.take() {
handles.append(&mut ctrl.spawn_task_loop(config.clone(), charge_limit_recv, None, None));
}
if let Some(ctrl) = led_control.take() {
handles.append(&mut ctrl.spawn_task_loop(
config.clone(),
aura_command_recv,
Some(connection.clone()),
Some(led_changed_signal),
));
}
connection.process_all();
for handle in handles {
handle.await?;
}
Ok(())
}
// TODO: Move these in to the controllers tasks
fn start_signal_task(
connection: Arc<SyncConnection>,
config: Arc<Mutex<Config>>,
fanmode_signal: Arc<Signal<()>>,
charge_limit_signal: Arc<Signal<()>>,
) {
tokio::spawn(async move {
// Some small things we need to track, without passing all sorts of stuff around
let mut last_fan_mode = config.lock().await.power_profile;
let mut last_charge_limit = config.lock().await.bat_charge_limit;
loop {
// Use tokio sleep to not hold up other threads
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
let config = config.lock().await;
if config.power_profile != last_fan_mode {
last_fan_mode = config.power_profile;
connection
.send(
fanmode_signal
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
.append1(last_fan_mode),
)
.unwrap_or_else(|_| 0);
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task().unwrap();
}
}
});
if config.bat_charge_limit != last_charge_limit {
last_charge_limit = config.bat_charge_limit;
connection
.send(
charge_limit_signal
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
.append1(last_charge_limit),
)
.unwrap_or_else(|_| 0);
}
loop {
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);
}
});
}
async fn send_boot_signals(
connection: Arc<SyncConnection>,
config: Arc<Mutex<Config>>,
fanmode_signal: Arc<Signal<()>>,
charge_limit_signal: Arc<Signal<()>>,
led_changed_signal: Arc<Signal<()>>,
) -> Result<(), Box<dyn Error>> {
let config = config.lock().await;
if let Some(data) = config.get_led_mode_data(config.kbd_backlight_mode) {
connection
.send(
led_changed_signal
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
.append1(serde_json::to_string(data)?),
)
.unwrap_or_else(|_| 0);
}
connection
.send(
fanmode_signal
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
.append1(config.power_profile),
)
.unwrap_or_else(|_| 0);
connection
.send(
charge_limit_signal
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
.append1(config.bat_charge_limit),
)
.unwrap_or_else(|_| 0);
Ok(())
}