diff --git a/src/core.rs b/src/core.rs index 792fd70c..9b60da49 100644 --- a/src/core.rs +++ b/src/core.rs @@ -110,7 +110,7 @@ impl RogCore { let mut file = OpenOptions::new().write(true).open(path)?; file.write(format!("{:?}\n", self.config.fan_mode).as_bytes())?; - + info!("Reloaded last saved settings"); Ok(()) } @@ -325,7 +325,7 @@ impl RogCore { pub(crate) async fn poll_keyboard( handle: &DeviceHandle, endpoint: u8, - report_filter_bytes: Vec, + report_filter_bytes: &[u8], ) -> Option<[u8; 32]> { let mut buf = [0u8; 32]; match handle.read_interrupt(endpoint, &mut buf, Duration::from_millis(200)) { diff --git a/src/daemon.rs b/src/daemon.rs index f50a4502..461de199 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -5,7 +5,7 @@ pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon"; use crate::{core::RogCore, laptops::match_laptop}; use dbus::{ nonblock::Process, - tree::{Factory, MethodErr}, + tree::{Factory, MTSync, Method, MethodErr, Tree}, }; use dbus_tokio::connection; @@ -14,6 +14,18 @@ use std::error::Error; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; +type LedMsgType = Arc>>>; +type EffectType = Arc>>>>; + +// 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) +// +// DBUS processing takes 6ms if not tokiod pub async fn start_daemon() -> Result<(), Box> { let laptop = match_laptop(); let mut rogcore = RogCore::new(&*laptop).map_or_else( @@ -28,7 +40,6 @@ pub async fn start_daemon() -> Result<(), Box> { ); // Reload settings rogcore.reload().await?; - info!("Reloaded last saved settings"); let (resource, connection) = connection::new_system_sync()?; tokio::spawn(async { @@ -40,125 +51,39 @@ pub async fn start_daemon() -> Result<(), Box> { .request_name(DBUS_IFACE, false, true, false) .await?; - let factory = Factory::new_sync::<()>(); - - let input: Arc>>> = Arc::new(Mutex::new(None)); - let effect: Arc>>>> = Arc::new(Mutex::new(None)); - - let tree = factory.tree(()).add( - factory.object_path(DBUS_PATH, ()).add( - factory - .interface(DBUS_IFACE, ()) - .add_m( - factory - // method for ledmessage - .method("ledmessage", (), { - let input = input.clone(); - - move |m| { - let bytes: Vec = m.msg.read1()?; - if let Ok(mut lock) = input.try_lock() { - *lock = Some(bytes.to_vec()); - let mret = m - .msg - .method_return() - .append1(&format!("Wrote {:x?}", bytes)); - return Ok(vec![mret]); - } else { - return Err(MethodErr::failed( - "Could not lock daemon for access", - )); - } - } - }) - .outarg::<&str, _>("reply") - .inarg::, _>("bytearray"), - ) - .add_m( - factory - // method for ledmessage - .method("ledeffect", (), { - let effect = effect.clone(); - move |m| { - if let Ok(mut lock) = effect.try_lock() { - let mut iter = m.msg.iter_init(); - let byte_array: Vec> = vec![ - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - iter.read()?, - ]; - - *lock = Some(byte_array); - let mret = - m.msg.method_return().append1(&format!("Got effect part")); - return Ok(vec![mret]); - } else { - return Err(MethodErr::failed( - "Could not lock daemon for access", - )); - } - } - }) - .outarg::<&str, _>("reply") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray"), - ), - ), - ); - + let (tree, input, effect) = dbus_create_tree(); // We add the tree to the connection so that incoming method calls will be handled. tree.start_receive_send(&*connection); - let supported = Vec::from(laptop.supported_modes()); - let key_buf: Arc>> = Arc::new(Mutex::new(None)); - let handle = unsafe { &*(rogcore.get_raw_device_handle()) }; - let endpoint = laptop.key_endpoint(); - let report_filter_bytes = laptop.key_filter().to_owned(); + { + let usb_dev_handle = unsafe { &*(rogcore.get_raw_device_handle()) }; + let keyboard_endpoint = laptop.key_endpoint(); + let report_filter_bytes = laptop.key_filter().to_owned(); - let key_buf1 = key_buf.clone(); - // This is *not* safe - tokio::spawn(async move { - loop { - let data = RogCore::poll_keyboard(handle, endpoint, report_filter_bytes.clone()).await; - if let Some(stuff) = data { - if let Ok(mut lock) = key_buf1.lock() { - lock.replace(stuff); + let key_buf1 = key_buf.clone(); + // This is *not* safe + tokio::spawn(async move { + loop { + let data = + RogCore::poll_keyboard(usb_dev_handle, keyboard_endpoint, &report_filter_bytes) + .await; + if let Some(stuff) = data { + // If we have some data to show, we *must* lock + if let Ok(mut lock) = key_buf1.lock() { + lock.replace(stuff); + } } } - } - }); + }); + } + let supported = Vec::from(laptop.supported_modes()); // When any action occurs this time is reset let mut time_mark = Instant::now(); loop { - // 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) - - // DBUS processing takes 6ms.... connection.process_all(); - // 700u per write if let Ok(mut lock) = input.try_lock() { if let Some(bytes) = &*lock { // It takes up to 20 milliseconds to write a complete colour block here @@ -202,3 +127,84 @@ pub async fn start_daemon() -> Result<(), Box> { } } } + +fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("ledmessage", (), { + move |m| { + let bytes: Vec = m.msg.read1()?; + if let Ok(mut lock) = msg.try_lock() { + *lock = Some(bytes.to_vec()); + let mret = m + .msg + .method_return() + .append1(&format!("Wrote {:x?}", bytes)); + return Ok(vec![mret]); + } else { + return Err(MethodErr::failed("Could not lock daemon for access")); + } + } + }) + .outarg::<&str, _>("reply") + .inarg::, _>("bytearray") +} + +fn dbus_create_ledeffect_method(effect: EffectType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("ledeffect", (), { + move |m| { + if let Ok(mut lock) = effect.try_lock() { + let mut iter = m.msg.iter_init(); + let byte_array: Vec> = vec![ + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + iter.read()?, + ]; + + *lock = Some(byte_array); + let mret = m.msg.method_return().append1(&format!("Got effect part")); + return Ok(vec![mret]); + } else { + return Err(MethodErr::failed("Could not lock daemon for access")); + } + } + }) + .outarg::<&str, _>("reply") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") +} + +fn dbus_create_tree() -> (Tree, LedMsgType, EffectType) { + let input: LedMsgType = Arc::new(Mutex::new(None)); + let effect: EffectType = Arc::new(Mutex::new(None)); + + let factory = Factory::new_sync::<()>(); + let tree = factory.tree(()).add( + factory.object_path(DBUS_PATH, ()).add( + factory + .interface(DBUS_IFACE, ()) + .add_m(dbus_create_ledmsg_method(input.clone())) + .add_m(dbus_create_ledeffect_method(effect.clone())), + ), + ); + (tree, input, effect) +}