anime: initial system config work

This commit is contained in:
Luke D Jones
2021-04-12 12:51:34 +12:00
parent 64d99a3e05
commit 8a6d364304
32 changed files with 624 additions and 226 deletions

131
daemon/src/config_anime.rs Normal file
View File

@@ -0,0 +1,131 @@
use log::{error, warn};
use rog_anime::{error::AnimeError, ActionData, AnimTime, AnimeAction, Vec2};
use serde_derive::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::time::Duration;
pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf";
pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf";
#[derive(Deserialize, Serialize, Default)]
pub struct AnimeConfigCached {
pub system: Option<ActionData>,
pub boot: Option<ActionData>,
pub suspend: Option<ActionData>,
pub shutdown: Option<ActionData>,
}
impl AnimeConfigCached {
pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> {
if let Some(ref sys) = config.system {
self.system = Some(ActionData::from_anime_action(sys)?)
}
if let Some(ref boot) = config.boot {
self.boot = Some(ActionData::from_anime_action(boot)?)
}
if let Some(ref suspend) = config.boot {
self.suspend = Some(ActionData::from_anime_action(suspend)?)
}
if let Some(ref shutdown) = config.boot {
self.shutdown = Some(ActionData::from_anime_action(shutdown)?)
}
Ok(())
}
}
/// Config for base system actions for the anime display
#[derive(Deserialize, Serialize)]
pub struct AnimeConfig {
pub system: Option<AnimeAction>,
pub boot: Option<AnimeAction>,
pub suspend: Option<AnimeAction>,
pub shutdown: Option<AnimeAction>,
}
impl Default for AnimeConfig {
fn default() -> Self {
AnimeConfig {
system: None,
boot: None,
suspend: None,
shutdown: None,
}
}
}
impl AnimeConfig {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load() -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&ANIME_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
ANIME_CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return AnimeConfig::create_default(&mut file);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
}
warn!("Could not deserialise {}", ANIME_CONFIG_PATH);
panic!("Please remove {} then restart asusd", ANIME_CONFIG_PATH);
}
}
AnimeConfig::create_default(&mut file)
}
fn create_default(file: &mut File) -> Self {
// create a default config here
let config = AnimeConfig {
system: None,
boot: Some(AnimeAction::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 0.5,
time: AnimTime::Time(Duration::from_secs(5)),
}),
suspend: None,
shutdown: None,
};
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string(&config).unwrap();
file.write_all(json.as_bytes())
.unwrap_or_else(|_| panic!("Could not write {}", ANIME_CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&ANIME_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("File is empty {}", ANIME_CONFIG_PATH);
} else {
let x: AnimeConfig = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", ANIME_CONFIG_PATH));
*self = x;
}
}
}
pub fn write(&self) {
let mut file = File::create(ANIME_CONFIG_PATH).expect("Couldn't overwrite config");
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
}

View File

@@ -147,7 +147,6 @@ impl AuraConfig {
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraMultiZone {
static_: [AuraEffect; 4],
@@ -233,4 +232,4 @@ impl Default for AuraMultiZone {
],
}
}
}
}

View File

@@ -1,4 +1,3 @@
use rog_aura::AuraEffect;
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
@@ -66,7 +65,6 @@ impl ConfigV324 {
}
}
#[derive(Deserialize, Serialize)]
pub struct ConfigV341 {
pub gfx_mode: GfxVendors,
@@ -94,4 +92,4 @@ impl ConfigV341 {
power_profiles: self.power_profiles,
}
}
}
}

View File

@@ -4,66 +4,49 @@ use rog_anime::{
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
VENDOR_ID,
},
AnimeDataBuffer, AnimePacketType,
ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN,
};
use rog_types::supported::AnimeSupportedFunctions;
use rusb::{Device, DeviceHandle};
use std::error::Error;
use std::time::Duration;
use std::{
error::Error,
sync::{Arc, Mutex},
thread::sleep,
time::Instant,
};
use std::{sync::atomic::AtomicBool, time::Duration};
use zbus::dbus_interface;
use zvariant::ObjectPath;
use crate::GetSupported;
use crate::{
config_anime::{AnimeConfig, AnimeConfigCached},
error::RogError,
GetSupported,
};
impl GetSupported for CtrlAnimeDisplay {
impl GetSupported for CtrlAnime {
type A = AnimeSupportedFunctions;
fn get_supported() -> Self::A {
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(VENDOR_ID, PROD_ID).is_ok())
AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok())
}
}
pub struct CtrlAnimeDisplay {
pub struct CtrlAnime {
handle: DeviceHandle<rusb::GlobalContext>,
cache: AnimeConfigCached,
_config: AnimeConfig,
// set to force thread to exit
thread_exit: AtomicBool,
// Set to false when the thread exits
thread_running: AtomicBool,
}
impl crate::ZbusAdd for CtrlAnimeDisplay {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlAnimeDisplay {
/// Writes a data stream of length
fn write(&self, input: AnimeDataBuffer) {
self.write_data_buffer(input);
}
fn set_on_off(&self, status: bool) {
self.write_bytes(&pkt_for_set_on(status));
}
fn set_boot_on_off(&self, on: bool) {
self.write_bytes(&pkt_for_set_boot(on));
self.write_bytes(&pkt_for_apply());
}
}
impl CtrlAnimeDisplay {
impl CtrlAnime {
#[inline]
pub fn new() -> Result<CtrlAnimeDisplay, Box<dyn Error>> {
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, Box<dyn Error>> {
// We don't expect this ID to ever change
let device = CtrlAnimeDisplay::get_device(0x0b05, 0x193b)?;
let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
let mut device = device.open()?;
device.reset()?;
@@ -79,7 +62,16 @@ impl CtrlAnimeDisplay {
})?;
info!("Device has an AniMe Matrix display");
let ctrl = CtrlAnimeDisplay { handle: device };
let mut cache = AnimeConfigCached::default();
cache.init_from_config(&config)?;
let ctrl = CtrlAnime {
handle: device,
cache,
_config: config,
thread_exit: AtomicBool::new(false),
thread_running: AtomicBool::new(false),
};
ctrl.do_initialization();
Ok(ctrl)
@@ -95,6 +87,108 @@ impl CtrlAnimeDisplay {
Err(rusb::Error::NoDevice)
}
// DOUBLE THREAD NEST!
fn run_thread(inner: Arc<Mutex<CtrlAnime>>, action: Option<ActionData>, mut once: bool) {
std::thread::Builder::new()
.name("AniMe system thread start".into())
.spawn(move || {
// Make the loop exit first
loop {
if let Ok(lock) = inner.try_lock() {
lock.thread_exit
.store(true, std::sync::atomic::Ordering::SeqCst);
break;
}
}
loop {
if let Ok(lock) = inner.try_lock() {
if !lock
.thread_running
.load(std::sync::atomic::Ordering::SeqCst)
{
lock.thread_exit
.store(false, std::sync::atomic::Ordering::SeqCst);
info!("AniMe system thread exited");
break;
}
}
}
std::thread::Builder::new()
.name("AniMe system actions".into())
.spawn(move || {
info!("AniMe system thread started");
'main: loop {
if let Ok(lock) = inner.try_lock() {
if !once
&& lock.thread_exit.load(std::sync::atomic::Ordering::SeqCst)
{
break 'main;
}
if let Some(ref action) = action {
match action {
ActionData::Animation(frames) => {
let mut count = 0;
let start = Instant::now();
'animation: loop {
for frame in frames.frames() {
lock.write_data_buffer(frame.frame().clone());
if let AnimTime::Time(time) = frames.duration()
{
if Instant::now().duration_since(start)
> time
{
break 'animation;
}
}
sleep(frame.delay());
}
if let AnimTime::Cycles(times) = frames.duration() {
count += 1;
if count >= times {
break 'animation;
}
}
}
}
ActionData::Image(image) => {
once = false;
lock.write_data_buffer(image.as_ref().clone())
}
ActionData::Pause(_) => {}
ActionData::AudioEq => {}
ActionData::SystemInfo => {}
ActionData::TimeDate => {}
ActionData::Matrix => {}
}
} else {
break 'main;
}
if once {
let data =
AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec());
lock.write_data_buffer(data);
break 'main;
}
}
}
'exit: loop {
if let Ok(lock) = inner.try_lock() {
lock.thread_exit
.store(false, std::sync::atomic::Ordering::SeqCst);
lock.thread_running
.store(false, std::sync::atomic::Ordering::SeqCst);
break 'exit;
}
}
})
.map(|err| info!("AniMe system thread: {:?}", err))
.ok();
})
.map(|err| info!("AniMe system thread: {:?}", err))
.ok();
}
fn write_bytes(&self, message: &[u8]) {
match self.handle.write_control(
0x21, // request_type
@@ -126,3 +220,89 @@ impl CtrlAnimeDisplay {
self.write_bytes(&pkts[1]);
}
}
pub struct CtrlAnimeTask(pub Arc<Mutex<CtrlAnime>>);
impl crate::CtrlTask for CtrlAnimeTask {
fn do_task(&self) -> Result<(), RogError> {
Ok(())
}
}
pub struct CtrlAnimeReloader(pub Arc<Mutex<CtrlAnime>>);
impl crate::Reloadable for CtrlAnimeReloader {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(lock) = self.0.try_lock() {
let action = lock.cache.boot.clone();
CtrlAnime::run_thread(self.0.clone(), action, true);
}
Ok(())
}
}
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
/// The struct with the main dbus methods requires this trait
impl crate::ZbusAdd for CtrlAnimeZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
// None of these calls can be guarnateed to succeed unless we loop until okay
// If the try_lock *does* succeed then any other thread trying to lock will not grab it
// until we finish.
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlAnimeZbus {
/// Writes a data stream of length. Will force system thread to exit until it is restarted
fn write(&self, input: AnimeDataBuffer) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.thread_exit
.store(true, std::sync::atomic::Ordering::SeqCst);
lock.write_data_buffer(input);
break 'outer;
}
}
}
fn set_on_off(&self, status: bool) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_on(status));
break 'outer;
}
}
}
fn set_boot_on_off(&self, on: bool) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.write_bytes(&pkt_for_set_boot(on));
lock.write_bytes(&pkt_for_apply());
break 'outer;
}
}
}
fn run_main_loop(&self, on: bool) {
'outer: loop {
if let Ok(lock) = self.0.try_lock() {
lock.thread_exit
.store(on, std::sync::atomic::Ordering::SeqCst);
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false);
break 'outer;
}
}
}
}

View File

@@ -1,7 +1,10 @@
use crate::error::RogError;
use crate::{config::Config, GetSupported};
use log::{info, warn};
use rog_types::{profile::{FanLevel, Profile, ProfileEvent}, supported::FanCpuSupportedFunctions};
use rog_types::{
profile::{FanLevel, Profile, ProfileEvent},
supported::FanCpuSupportedFunctions,
};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
@@ -31,18 +34,18 @@ impl GetSupported for CtrlFanAndCpu {
}
}
pub struct DbusFanAndCpu {
pub struct FanAndCpuZbus {
inner: Arc<Mutex<CtrlFanAndCpu>>,
}
impl DbusFanAndCpu {
impl FanAndCpuZbus {
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
Self { inner }
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusFanAndCpu {
impl FanAndCpuZbus {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
@@ -170,7 +173,7 @@ impl DbusFanAndCpu {
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for DbusFanAndCpu {
impl crate::ZbusAdd for FanAndCpuZbus {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(

View File

@@ -7,7 +7,10 @@ use crate::{
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
};
use log::{error, info, warn};
use rog_aura::{AuraEffect, AuraModeNum, LED_MSG_LEN, LedBrightness, usb::{LED_APPLY, LED_SET}};
use rog_aura::{
usb::{LED_APPLY, LED_SET},
AuraEffect, LedBrightness, LED_MSG_LEN,
};
use rog_types::supported::LedSupportedFunctions;
use std::fs::OpenOptions;
use std::io::{Read, Write};
@@ -50,6 +53,37 @@ pub struct CtrlKbdBacklight {
config: AuraConfig,
}
pub struct CtrlKbdBacklightTask(pub Arc<Mutex<CtrlKbdBacklight>>);
impl crate::CtrlTask for CtrlKbdBacklightTask {
fn do_task(&self) -> Result<(), RogError> {
if let Ok(mut lock) = self.0.try_lock() {
let mut file = OpenOptions::new()
.read(true)
.open(&lock.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&lock.bright_node).into(), err)
}
_ => RogError::Path((&lock.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if lock.config.brightness != num.into() {
lock.config.read();
lock.config.brightness = num.into();
lock.config.write();
}
return Ok(());
}
return Err(RogError::ParseLed);
}
Ok(())
}
}
pub struct DbusKbdBacklight {
inner: Arc<Mutex<CtrlKbdBacklight>>,
}
@@ -166,73 +200,6 @@ impl DbusKbdBacklight {
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
impl crate::Reloadable for CtrlKbdBacklight {
fn reload(&mut self) -> Result<(), RogError> {
// set current mode (if any)
if self.supported_modes.standard.len() > 1 {
let current_mode = self.config.current_mode;
if self.supported_modes.standard.contains(&(current_mode)) {
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
} else {
warn!(
"An unsupported mode was set: {}, reset to first mode available",
<&str>::from(&self.config.current_mode)
);
self.config.builtins.remove(&current_mode);
self.config.current_mode = AuraModeNum::Static;
// TODO: do a recursive call with a boxed dyn future later
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
}
// Reload brightness
let bright = self.config.brightness;
self.set_brightness(bright)?;
info!("Reloaded last used brightness");
Ok(())
}
}
impl crate::CtrlTask for CtrlKbdBacklight {
fn do_task(&mut self) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if self.config.brightness != num.into() {
self.config.read();
self.config.brightness = num.into();
self.config.write();
}
return Ok(());
}
Err(RogError::ParseLed)
}
}
impl CtrlKbdBacklight {
#[inline]
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {

View File

@@ -4,7 +4,7 @@ use zbus::dbus_interface;
use zvariant::ObjectPath;
use crate::{
ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_fan_cpu::CtrlFanAndCpu,
ctrl_leds::CtrlKbdBacklight, ctrl_rog_bios::CtrlRogBios, GetSupported,
};
@@ -50,7 +50,7 @@ impl GetSupported for SupportedFunctions {
fn get_supported() -> Self::A {
SupportedFunctions {
keyboard_led: CtrlKbdBacklight::get_supported(),
anime_ctrl: CtrlAnimeDisplay::get_supported(),
anime_ctrl: CtrlAnime::get_supported(),
charge_ctrl: CtrlCharge::get_supported(),
fan_cpu_ctrl: CtrlFanAndCpu::get_supported(),
rog_bios_ctrl: CtrlRogBios::get_supported(),

View File

@@ -1,11 +1,11 @@
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::ctrl_leds::{CtrlKbdBacklight, CtrlKbdBacklightTask, DbusKbdBacklight};
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
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, DbusFanAndCpu},
ctrl_fan_cpu::{CtrlFanAndCpu, FanAndCpuZbus},
laptops::LaptopLedData,
};
@@ -41,27 +41,24 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
// - read interrupt must timeout, minimum of 1ms
// - for a single usb packet, 2ms total.
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
/// The actual main loop for the daemon
fn start_daemon() -> Result<(), Box<dyn Error>> {
let supported = SupportedFunctions::get_supported();
print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let config = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
// Collect tasks for task thread
let mut tasks: Vec<Box<dyn CtrlTask + Send>> = Vec::new();
// Start zbus server
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 = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
supported.add_to_server(&mut object_server);
match CtrlRogBios::new(config.clone()) {
@@ -90,15 +87,52 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
match CtrlAnimeDisplay::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));
FanAndCpuZbus::new(tmp).add_to_server(&mut object_server);
}
Err(err) => {
error!("Profile control: {}", err);
}
}
match CtrlAnime::new(AnimeConfig::load()) {
Ok(ctrl) => {
ctrl.add_to_server(&mut object_server);
let inner = Arc::new(Mutex::new(ctrl));
let mut reload = CtrlAnimeReloader(inner.clone());
reload
.reload()
.unwrap_or_else(|err| warn!("AniMe: {}", err));
let zbus = CtrlAnimeZbus(inner.clone());
zbus.add_to_server(&mut object_server);
tasks.push(Box::new(CtrlAnimeTask(inner)));
}
Err(err) => {
error!("AniMe control: {}", err);
}
}
let laptop = LaptopLedData::get_data();
let aura_config = AuraConfig::load(&laptop);
match CtrlKbdBacklight::new(laptop, aura_config) {
Ok(ctrl) => {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
let task = CtrlKbdBacklightTask(tmp);
tasks.push(Box::new(task));
}
Err(err) => {
error!("Keyboard control: {}", err);
}
}
// Graphics switching requires some checks on boot specifically for g-sync capable laptops
if enable_gfx_switching {
match CtrlGraphics::new(config.clone()) {
Ok(mut ctrl) => {
@@ -141,48 +175,24 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
// Collect tasks for task thread
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
if let Ok(mut ctrl) = CtrlFanAndCpu::new(config).map_err(|err| {
error!("Profile control: {}", err);
}) {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
let laptop = LaptopLedData::get_data();
let aura_config = AuraConfig::load(&laptop);
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
error!("Keyboard control: {}", err);
err
}) {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
// TODO: implement messaging between threads to check fails
// These tasks generally read a sys path or file to check for a
// change
// Run tasks
let handle = std::thread::Builder::new()
.name("asusd watch".to_string())
.spawn(move || loop {
std::thread::sleep(std::time::Duration::from_millis(100));
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
ctrl.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
});
// Run zbus server
object_server
.with(
&ObjectPath::from_str_unchecked("/org/asuslinux/Charge"),
@@ -196,6 +206,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
})
.ok();
// Loop to check errors and iterate zbus server
loop {
if let Err(err) = &handle {
error!("{}", err);

View File

@@ -1,6 +1,7 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub mod config_anime;
pub mod config_aura;
pub(crate) mod config_old;
/// Control of AniMe matrix display
@@ -48,7 +49,7 @@ pub trait ZbusAdd {
}
pub trait CtrlTask {
fn do_task(&mut self) -> Result<(), RogError>;
fn do_task(&self) -> Result<(), RogError>;
}
pub trait CtrlTaskComplex {