diff --git a/examples/per-key-effect-2.rs b/examples/per-key-effect-2.rs index c73a9d38..c5e3f4fc 100644 --- a/examples/per-key-effect-2.rs +++ b/examples/per-key-effect-2.rs @@ -1,23 +1,7 @@ -use daemon::aura::{Key, KeyColourArray}; -use daemon::daemon::{DBUS_IFACE, DBUS_NAME, DBUS_PATH}; -use dbus::Error as DbusError; -use dbus::{ffidisp::Connection, Message}; -use std::{thread, time}; - -pub fn dbus_led_builtin_write(bytes: &[u8]) -> Result<(), Box> { - let bus = Connection::new_system()?; - let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")? - .append1(bytes.to_vec()); - let r = bus.send_with_reply_and_block(msg, 5000)?; - if let Some(reply) = r.get1::<&str>() { - println!("Success: {:x?}", reply); - return Ok(()); - } - Err(Box::new(DbusError::new_custom("name", "message"))) -} +use daemon::aura::{AuraDbusWriter, Key, KeyColourArray}; fn main() -> Result<(), Box> { - let bus = Connection::new_system()?; + let writer = AuraDbusWriter::new()?; let mut per_key_led = Vec::new(); let mut key_colours = KeyColourArray::new(); @@ -43,37 +27,13 @@ fn main() -> Result<(), Box> { per_key_led.push(key_colours.clone()); } - // It takes each interrupt at least 1ms. 10ms to write complete block. - let time = time::Duration::from_millis(10); // aim for 100 per second - - let row = KeyColourArray::get_init_msg(); - let msg = - Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")?.append1(row); - bus.send(msg).unwrap(); - + writer.init_effect()?; loop { let now = std::time::Instant::now(); - thread::sleep(time); - for group in &per_key_led { - let group = group.get(); - let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledeffect")? - .append1(&group[0].to_vec()) - .append1(&group[1].to_vec()) - .append1(&group[2].to_vec()) - .append1(&group[3].to_vec()) - .append1(&group[4].to_vec()) - .append1(&group[5].to_vec()) - .append1(&group[6].to_vec()) - .append1(&group[7].to_vec()) - .append1(&group[8].to_vec()) - .append1(&group[9].to_vec()); - bus.send(msg).unwrap(); - thread::sleep(time); + writer.write_colour_block(group)?; } - let after = std::time::Instant::now(); - let diff = after.duration_since(now); - dbg!(diff.as_millis()); + dbg!(std::time::Instant::now().duration_since(now).as_millis()); //return Ok(()); } } diff --git a/src/aura.rs b/src/aura.rs index 60844819..cf61d301 100644 --- a/src/aura.rs +++ b/src/aura.rs @@ -1,5 +1,9 @@ +pub static DBUS_NAME: &'static str = "org.rogcore.Daemon"; +pub static DBUS_PATH: &'static str = "/org/rogcore/Daemon"; +pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon"; +pub const LED_MSG_LEN: usize = 17; + use crate::cli_options::*; -use crate::core::LED_MSG_LEN; use serde_derive::{Deserialize, Serialize}; /// Writes aout the correct byte string for brightness @@ -111,8 +115,8 @@ pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { /// ``` /// /// This descriptor is also used for the per-key LED settings -impl From for [u8; LED_MSG_LEN] { - fn from(mode: SetAuraBuiltin) -> Self { +impl From<&SetAuraBuiltin> for [u8; LED_MSG_LEN] { + fn from(mode: &SetAuraBuiltin) -> Self { let mut msg = [0u8; LED_MSG_LEN]; msg[0] = 0x5d; msg[1] = 0xb3; @@ -178,6 +182,12 @@ impl From for [u8; LED_MSG_LEN] { } } +impl From for [u8; LED_MSG_LEN] { + fn from(mode: SetAuraBuiltin) -> Self { + <[u8; LED_MSG_LEN]>::from(&mode) + } +} + impl From for [[u8; LED_MSG_LEN]; 4] { fn from(mode: SetAuraBuiltin) -> Self { let mut msg = [[0u8; LED_MSG_LEN]; 4]; @@ -627,3 +637,78 @@ pub enum Key { Right, RFn, } + +use dbus::{ffidisp::Connection, Message}; +use std::error::Error; +use std::{thread, time::Duration}; + +/// Simplified way to write a effect block +pub struct AuraDbusWriter { + connection: Connection, + block_time: u64, +} + +impl AuraDbusWriter { + pub fn new() -> Result> { + Ok(AuraDbusWriter { + connection: Connection::new_system()?, + block_time: 10, + }) + } + + /// This method must always be called before the very first write to initialise + /// the keyboard LED EC in the correct mode + pub fn init_effect(&self) -> Result<(), Box> { + let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")? + .append1(KeyColourArray::get_init_msg()); + self.connection.send(msg).unwrap(); + Ok(()) + } + + /// Write a single colour block. + /// + /// Intentionally blocks for 10ms after sending to allow the block to + /// be written to the keyboard EC. This should not be async. + pub fn write_colour_block( + &self, + key_colour_array: &KeyColourArray, + ) -> Result<(), Box> { + let group = key_colour_array.get(); + let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledeffect")? + .append1(&group[0].to_vec()) + .append1(&group[1].to_vec()) + .append1(&group[2].to_vec()) + .append1(&group[3].to_vec()) + .append1(&group[4].to_vec()) + .append1(&group[5].to_vec()) + .append1(&group[6].to_vec()) + .append1(&group[7].to_vec()) + .append1(&group[8].to_vec()) + .append1(&group[9].to_vec()); + self.connection.send(msg).unwrap(); + thread::sleep(Duration::from_millis(self.block_time)); + Ok(()) + } + + pub fn write_bytes(&self, bytes: &[u8]) -> Result> { + let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")? + .append1(bytes.to_vec()); + let r = self.connection.send_with_reply_and_block(msg, 5000)?; + if let Some(reply) = r.get1::<&str>() { + return Ok(reply.to_owned()); + } + Err(Box::new(dbus::Error::new_custom("name", "message"))) + } + + pub fn write_builtin_mode( + &self, + mode: &SetAuraBuiltin, + ) -> Result> { + let bytes = <[u8; LED_MSG_LEN]>::from(mode); + self.write_bytes(&bytes) + } + + pub fn write_brightness(&self, level: u8) -> Result> { + self.write_bytes(&aura_brightness_bytes(level)) + } +} diff --git a/src/cli_options.rs b/src/cli_options.rs index 5f6b712e..3aadbbf7 100644 --- a/src/cli_options.rs +++ b/src/cli_options.rs @@ -24,7 +24,7 @@ impl FromStr for Colour { } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum Speed { Low = 0xe1, Med = 0xeb, @@ -52,7 +52,7 @@ impl FromStr for Speed { /// Used for Rainbow mode. /// /// Enum corresponds to the required integer value -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum Direction { Right, Left, diff --git a/src/core.rs b/src/core.rs index c8706eb9..522c6b42 100644 --- a/src/core.rs +++ b/src/core.rs @@ -19,7 +19,6 @@ use std::ptr::NonNull; use std::str::FromStr; use std::time::Duration; -pub const LED_MSG_LEN: usize = 17; static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; @@ -314,6 +313,7 @@ where /// UNSAFE unsafe impl<'d, C> Send for LedWriter<'d, C> where C: rusb::UsbContext {} +unsafe impl<'d, C> Sync for LedWriter<'d, C> where C: rusb::UsbContext {} impl<'d, C> LedWriter<'d, C> where @@ -524,6 +524,7 @@ impl FromStr for LedBrightness { } } } + #[derive(Debug)] enum FanLevel { Normal, diff --git a/src/daemon.rs b/src/daemon.rs index 76dedef1..0489a9b1 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,8 +1,4 @@ -pub static DBUS_NAME: &'static str = "org.rogcore.Daemon"; -pub static DBUS_PATH: &'static str = "/org/rogcore/Daemon"; -pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon"; - -use crate::{config::Config, core::*, laptops::match_laptop}; +use crate::{aura::*, config::Config, core::*, laptops::match_laptop}; use dbus::{ nonblock::Process, tree::{Factory, MTSync, Method, MethodErr, Tree}, @@ -83,7 +79,7 @@ pub async fn start_daemon() -> Result<(), Box> { let led_writer1 = led_writer.clone(); let config1 = config.clone(); // start the keyboard reader and laptop-action loop - tokio::task::spawn(async move { + let key_read_handle = tokio::spawn(async move { loop { let data = keyboard_reader.poll_keyboard().await; if let Some(bytes) = data { @@ -97,48 +93,54 @@ pub async fn start_daemon() -> Result<(), Box> { }); // start the LED writer loop - let mut time_mark = Instant::now(); - loop { - connection.process_all(); + let led_write_handle = tokio::spawn(async move { + let mut time_mark = Instant::now(); + loop { + connection.process_all(); - let led_writer = led_writer.clone(); - if let Ok(mut lock) = input.try_lock() { - if let Some(bytes) = lock.take() { - let mut led_writer = led_writer.lock().await; - let mut config = config.lock().await; - led_writer - .aura_set_and_save(&supported, &bytes, &mut config) - .await - .map_err(|err| warn!("{:?}", err)) - .unwrap(); - time_mark = Instant::now(); + let led_writer = led_writer.clone(); + if let Ok(mut lock) = input.try_lock() { + if let Some(bytes) = lock.take() { + let mut led_writer = led_writer.lock().await; + let mut config = config.lock().await; + led_writer + .aura_set_and_save(&supported, &bytes, &mut config) + .await + .map_err(|err| warn!("{:?}", err)) + .unwrap(); + time_mark = Instant::now(); + } + } + + // Write a colour block + let led_writer = led_writer.clone(); + if let Ok(mut lock) = effect.try_lock() { + // Spawn a writer + if let Some(stuff) = lock.take() { + let led_writer = led_writer.lock().await; + led_writer + .async_write_effect(led_endpoint, stuff) + .await + .map_err(|err| warn!("{:?}", err)) + .unwrap(); + time_mark = Instant::now(); + } + } + + let now = Instant::now(); + // Cool-down steps + // This block is to prevent the loop spooling as fast as possible and saturating the CPU + if now.duration_since(time_mark).as_millis() > 500 { + std::thread::sleep(Duration::from_millis(200)); + } else if now.duration_since(time_mark).as_millis() > 100 { + std::thread::sleep(Duration::from_millis(50)); } } + }); - // Write a colour block - let led_writer = led_writer.clone(); - if let Ok(mut lock) = effect.try_lock() { - // Spawn a writer - if let Some(stuff) = lock.take() { - let led_writer = led_writer.lock().await; - led_writer - .async_write_effect(led_endpoint, stuff) - .await - .map_err(|err| warn!("{:?}", err)) - .unwrap(); - time_mark = Instant::now(); - } - } - - let now = Instant::now(); - // Cool-down steps - // This block is to prevent the loop spooling as fast as possible and saturating the CPU - if now.duration_since(time_mark).as_millis() > 500 { - std::thread::sleep(Duration::from_millis(200)); - } else if now.duration_since(time_mark).as_millis() > 100 { - std::thread::sleep(Duration::from_millis(50)); - } - } + led_write_handle.await?; + key_read_handle.await?; + Ok(()) } fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method { diff --git a/src/main.rs b/src/main.rs index fad4e319..8ae2600a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,9 @@ use daemon::{ - aura::aura_brightness_bytes, + aura::{AuraDbusWriter, LED_MSG_LEN}, cli_options::SetAuraBuiltin, - core::{LedBrightness, LED_MSG_LEN}, - daemon::{start_daemon, DBUS_IFACE, DBUS_NAME, DBUS_PATH}, + core::LedBrightness, + daemon::start_daemon, }; -use dbus::Error as DbusError; -use dbus::{ffidisp::Connection, Message}; use env_logger::{Builder, Target}; use gumdrop::Options; use log::LevelFilter; @@ -55,6 +53,8 @@ pub async fn main() -> Result<(), Box> { println!("Version: {}", VERSION); } + let writer = AuraDbusWriter::new()?; + if let Some(Command::LedMode(mode)) = parsed.command { if let Some(command) = mode.command { // Check for special modes here, eg, per-key or multi-zone @@ -62,32 +62,17 @@ pub async fn main() -> Result<(), Box> { SetAuraBuiltin::MultiStatic(_) => { let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command); for arr in byte_arr.iter() { - dbus_led_builtin_write(arr)?; + writer.write_bytes(arr)?; } } _ => { - let mode = <[u8; LED_MSG_LEN]>::from(command); - dbus_led_builtin_write(&mode)?; + writer.write_builtin_mode(&command)?; } } } } if let Some(brightness) = parsed.bright { - let bytes = aura_brightness_bytes(brightness.level()); - dbus_led_builtin_write(&bytes)?; + writer.write_brightness(brightness.level())?; } Ok(()) } - -pub fn dbus_led_builtin_write(bytes: &[u8]) -> Result<(), Box> { - let bus = Connection::new_system()?; - //let proxy = bus.with_proxy(DBUS_IFACE, "/", Duration::from_millis(5000)); - let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")? - .append1(bytes.to_vec()); - let r = bus.send_with_reply_and_block(msg, 5000)?; - if let Some(reply) = r.get1::<&str>() { - println!("Success: {:x?}", reply); - return Ok(()); - } - Err(Box::new(DbusError::new_custom("name", "message"))) -}