From d9fc7de5cbd47ab4f4f84275df9fe869ab592fb8 Mon Sep 17 00:00:00 2001 From: Luke Date: Sun, 31 May 2020 12:21:04 +1200 Subject: [PATCH] Initial groundwork of animatrix --- README.md | 5 + aura/examples/animatrix.rs | 13 ++ aura/examples/comet.rs | 2 - aura/src/animatrix_dbus.rs | 55 +++++++++ aura/src/aura_dbus.rs | 2 +- aura/src/lib.rs | 3 + rog-core/src/animatrix_control.rs | 196 ++++++++++++++++++++++++++++++ rog-core/src/daemon.rs | 177 ++++----------------------- rog-core/src/laptops.rs | 7 ++ rog-core/src/led_control.rs | 5 - rog-core/src/lib.rs | 4 + rog-core/src/main.rs | 2 +- rog-core/src/rog_dbus.rs | 179 +++++++++++++++++++++++++++ rog-core/src/rogcore.rs | 2 +- 14 files changed, 490 insertions(+), 162 deletions(-) create mode 100644 aura/examples/animatrix.rs create mode 100644 aura/src/animatrix_dbus.rs create mode 100644 rog-core/src/animatrix_control.rs create mode 100644 rog-core/src/rog_dbus.rs diff --git a/README.md b/README.md index 951f74af..0b681c15 100644 --- a/README.md +++ b/README.md @@ -212,5 +212,10 @@ Mozilla Public License 2 (MPL-2.0) - [flukejones](https://github.com/flukejones/), project maintainer. - [tuxuser](https://github.com/tuxuser/) +<<<<<<< HEAD - [aspann](https://github.com/aspann) +======= +- ZappeL, `TODO: link, any details` +- dragonn, `TODO: link, any details` +>>>>>>> Initial groundwork of animatrix - Anyone missed? Please contact me \ No newline at end of file diff --git a/aura/examples/animatrix.rs b/aura/examples/animatrix.rs new file mode 100644 index 00000000..f8fbcac9 --- /dev/null +++ b/aura/examples/animatrix.rs @@ -0,0 +1,13 @@ +use rog_aura::AnimatrixDbusWriter; + +fn main() -> Result<(), Box> { + let mut writer = AnimatrixDbusWriter::new()?; + + let mut send_buffer = [vec![0; 640], vec![0; 640]]; + + loop { + writer.write_image(&send_buffer)?; + + //std::thread::sleep(std::time::Duration::from_millis(60)); + } +} diff --git a/aura/examples/comet.rs b/aura/examples/comet.rs index 98024d0a..55542436 100644 --- a/aura/examples/comet.rs +++ b/aura/examples/comet.rs @@ -23,7 +23,5 @@ fn main() -> Result<(), Box> { } writer.write_colour_block(&key_colours)?; - - //std::thread::sleep(std::time::Duration::from_millis(250)); } } diff --git a/aura/src/animatrix_dbus.rs b/aura/src/animatrix_dbus.rs new file mode 100644 index 00000000..c8ab8f67 --- /dev/null +++ b/aura/src/animatrix_dbus.rs @@ -0,0 +1,55 @@ +use super::*; +use dbus::channel::Sender; +use dbus::{blocking::Connection, Message}; +use std::error::Error; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use std::{thread, time::Duration}; + +/// Simplified way to write a effect block +pub struct AnimatrixDbusWriter { + connection: Box, + block_time: u64, + stop: Arc, +} + +impl AnimatrixDbusWriter { + #[inline] + pub fn new() -> Result> { + let connection = Connection::new_system()?; + Ok(AnimatrixDbusWriter { + connection: Box::new(connection), + block_time: 100, + stop: Arc::new(AtomicBool::new(false)), + }) + } + + /// Write an Animatrix image + /// + /// The expected input here is *two* Vectors, 640 bytes in length. The two vectors + /// are each one half of the full image write. + /// + /// After each write a flush is written, it is assumed that this tells the device to + /// go ahead and display the written bytes + /// + /// # Note: + /// The vectors are expected to contain the full sequence of bytes as follows + /// + /// - Write pane 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. + /// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. + /// + /// Where led brightness is 0..255, low to high + #[inline] + pub fn write_image(&mut self, image: &[Vec; 2]) -> Result<(), Box> { + let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "AnimatrixWrite")? + .append2(image[0].to_vec(), image[1].to_vec()); + self.connection.send(msg).unwrap(); + thread::sleep(Duration::from_millis(self.block_time)); + if self.stop.load(Ordering::Relaxed) { + panic!("Got signal to stop!"); + } + Ok(()) + } +} diff --git a/aura/src/aura_dbus.rs b/aura/src/aura_dbus.rs index 890feef0..a5cd3ac9 100644 --- a/aura/src/aura_dbus.rs +++ b/aura/src/aura_dbus.rs @@ -59,7 +59,7 @@ impl AuraDbusWriter { &mut self, key_colour_array: &KeyColourArray, ) -> Result<(), Box> { - self.connection.process(Duration::from_micros(300))?; + // self.connection.process(Duration::from_micros(300))?; let group = key_colour_array.get(); let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")? diff --git a/aura/src/lib.rs b/aura/src/lib.rs index 49ba60da..487b89cb 100644 --- a/aura/src/lib.rs +++ b/aura/src/lib.rs @@ -15,6 +15,9 @@ pub use aura_dbus::*; pub use fancy::*; +mod animatrix_dbus; +pub use animatrix_dbus::*; + pub mod error; use crate::cli_options::*; diff --git a/rog-core/src/animatrix_control.rs b/rog-core/src/animatrix_control.rs new file mode 100644 index 00000000..70bc27df --- /dev/null +++ b/rog-core/src/animatrix_control.rs @@ -0,0 +1,196 @@ +const INIT_STR: &str = "ASUS Tech.Inc."; +const PACKET_SIZE: usize = 640; + +// Only these two packets must be 17 bytes +const DEV_PAGE: u8 = 0x5e; +// These bytes are in [1] position of the array +const WRITE: u8 = 0xc0; +const INIT: u8 = 0xc2; +const APPLY: u8 = 0xc3; +const SET: u8 = 0xc4; + +use log::error; +use rog_aura::error::AuraError; +use rusb::DeviceHandle; +use std::error::Error; +use std::time::Duration; + +#[derive(Debug)] +pub enum AnimatrixCommand { + Apply, + Set, + WriteImage(Vec>), + //ReloadLast, +} + +pub struct AnimatrixWriter { + handle: DeviceHandle, + initialised: bool, +} + +impl AnimatrixWriter { + #[inline] + pub fn new() -> Result> { + // We don't expect this ID to ever change + let mut dev_handle = AnimatrixWriter::get_device(0x0b05, 0x193b).map_err(|err| { + error!("Could not get device handle: {:?}", err); + err + })?; + // This config seems to be the required device config for writing + dev_handle.set_active_configuration(1).unwrap_or(()); + + // For the animatrix device there is only one interface and one endpoint + let interface = 0; + + dev_handle + .set_auto_detach_kernel_driver(true) + .map_err(|err| { + error!("Auto-detach kernel driver failed: {:?}", err); + err + })?; + dev_handle.claim_interface(interface).map_err(|err| { + error!("Could not claim device interface: {:?}", err); + err + })?; + + Ok(AnimatrixWriter { + handle: dev_handle, + initialised: false, + }) + } + + pub async fn do_command(&mut self, command: AnimatrixCommand) -> Result<(), AuraError> { + if !self.initialised { + self.do_initialization().await? + } + + match command { + AnimatrixCommand::WriteImage(effect) => self.write_image(effect).await?, + AnimatrixCommand::Set => self.do_set().await?, + AnimatrixCommand::Apply => self.do_apply().await?, + //AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?, + } + Ok(()) + } + + /// Should only be used if the bytes you are writing are verified correct + #[inline] + async fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> { + let prev = std::time::Instant::now(); + match self.handle.write_control( + 0x21, // request_type + 0x09, // request + 0x35e, // value + 0x00, // index + message, + Duration::from_millis(200), + ) { + Ok(_) => { + println!( + "{:?}", + std::time::Instant::now().duration_since(prev).as_micros() + ); + } + Err(err) => match err { + rusb::Error::Timeout => {} + _ => error!("Failed to write to led interrupt: {:?}", err), + }, + } + Ok(()) + } + + /// Write an Animatrix image + /// + /// The expected input here is *two* Vectors, 640 bytes in length. The two vectors + /// are each one half of the full image write. + /// + /// After each write a flush is written, it is assumed that this tells the device to + /// go ahead and display the written bytes + /// + /// # Note: + /// The vectors are expected to contain the full sequence of bytes as follows + /// + /// - Write pane 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. + /// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. + /// + /// Where led brightness is 0..255, low to high + #[inline] + async fn write_image(&mut self, image: Vec>) -> Result<(), AuraError> { + for row in image.iter() { + self.write_bytes(row).await?; + } + self.do_flush().await?; + Ok(()) + } + + // TODO: save/reload last frame + #[inline] + fn get_device( + vendor: u16, + product: u16, + ) -> Result, rusb::Error> { + for device in rusb::devices()?.iter() { + let device_desc = device.device_descriptor()?; + if device_desc.vendor_id() == vendor && device_desc.product_id() == product { + return device.open(); + } + } + Err(rusb::Error::NoDevice) + } + + #[inline] + async fn do_initialization(&mut self) -> Result<(), AuraError> { + let mut init = [0; PACKET_SIZE]; + init[0] = DEV_PAGE; // This is the USB page we're using throughout + for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() { + init[idx + 1] = *byte + } + self.write_bytes(&init).await?; + // clear the init array and write other init message + for idx in 0..INIT_STR.len() { + match idx { + 0 => init[idx] = DEV_PAGE, // write it to be sure? + 1 => init[idx] = INIT, + _ => init[idx] = 0, + } + } + self.write_bytes(&init).await?; + self.initialised = true; + Ok(()) + } + + #[inline] + async fn do_flush(&mut self) -> Result<(), AuraError> { + let mut flush = [0; PACKET_SIZE]; + flush[0] = DEV_PAGE; + flush[1] = WRITE; + flush[2] = 0x03; + + self.write_bytes(&flush).await?; + Ok(()) + } + + #[inline] + async fn do_set(&mut self) -> Result<(), AuraError> { + let mut flush = [0; PACKET_SIZE]; + flush[0] = DEV_PAGE; + flush[1] = SET; + flush[2] = 0x01; + flush[3] = 0x80; + + self.write_bytes(&flush).await?; + Ok(()) + } + + #[inline] + async fn do_apply(&mut self) -> Result<(), AuraError> { + let mut flush = [0; PACKET_SIZE]; + flush[0] = DEV_PAGE; + flush[1] = APPLY; + flush[2] = 0x01; + flush[3] = 0x80; + + self.write_bytes(&flush).await?; + Ok(()) + } +} diff --git a/rog-core/src/daemon.rs b/rog-core/src/daemon.rs index 84c63378..cee20330 100644 --- a/rog-core/src/daemon.rs +++ b/rog-core/src/daemon.rs @@ -1,15 +1,13 @@ use crate::{ + animatrix_control::{AnimatrixCommand, AnimatrixWriter}, config::Config, laptops::match_laptop, led_control::{AuraCommand, LedWriter}, + rog_dbus::dbus_create_tree, rogcore::*, }; -use dbus::{ - channel::Sender, - nonblock::Process, - tree::{Factory, MTSync, Method, MethodErr, Signal, Tree}, -}; +use dbus::{channel::Sender, nonblock::Process}; use dbus_tokio::connection; use log::{error, info, warn}; @@ -19,9 +17,9 @@ use std::sync::{mpsc, Arc}; use std::time::{Duration, Instant}; use tokio::sync::Mutex; -type FanModeType = Arc>>; -type LedMsgType = Arc>>>; -type EffectType = Arc>>>>; +pub(super) type FanModeType = Arc>>; +pub(super) type LedMsgType = Arc>>>; +pub(super) type NestedVecType = Arc>>>>; // Timing is such that: // - interrupt write is minimum 1ms (sometimes lower) @@ -68,6 +66,13 @@ pub async fn start_daemon() -> Result<(), Box> { .do_command(AuraCommand::ReloadLast, &mut config) .await?; + // Possible Animatrix + let mut animatrix_writer = None; + if laptop.support_animatrix() { + animatrix_writer = Some(AnimatrixWriter::new()?); + info!("Device has an AniMatrix display"); + } + // Set up the mutexes let config = Arc::new(Mutex::new(config)); let (resource, connection) = connection::new_system_sync()?; @@ -82,7 +87,7 @@ pub async fn start_daemon() -> Result<(), Box> { let (aura_command_send, aura_command_recv) = mpsc::sync_channel::(1); - let (tree, input, effect, fan_mode, effect_cancel_signal) = dbus_create_tree(); + let (tree, input, effect, animatrix_img, fan_mode, effect_cancel_signal) = dbus_create_tree(); // We add the tree to the connection so that incoming method calls will be handled. tree.start_receive_send(&*connection); @@ -185,6 +190,17 @@ pub async fn start_daemon() -> Result<(), Box> { } } + // If animatrix is supported, try doing a write + if let Some(writer) = animatrix_writer.as_mut() { + let mut image_lock = animatrix_img.lock().await; + if let Some(image) = image_lock.take() { + writer + .do_command(AnimatrixCommand::WriteImage(image)) + .await + .unwrap_or_else(|err| warn!("{:?}", err)); + } + } + let now = Instant::now(); // Cool-down steps // This block is to prevent the loop spooling as fast as possible and saturating the CPU @@ -202,146 +218,3 @@ pub async fn start_daemon() -> Result<(), Box> { key_read_handle.await?; Ok(()) } - -fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method { - let factory = Factory::new_sync::<()>(); - factory - // method for ledmessage - .method("LedWriteBytes", (), { - 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)); - Ok(vec![mret]) - } else { - Err(MethodErr::failed("Could not lock daemon for access")) - } - } - }) - .outarg::<&str, _>("reply") - .inarg::, _>("bytearray") -} - -fn dbus_create_ledmultizone_method(effect: EffectType) -> Method { - let factory = Factory::new_sync::<()>(); - factory - // method for ledmessage - .method("LedWriteMultizone", (), { - 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()?]; - *lock = Some(byte_array); - let mret = m - .msg - .method_return() - .append1(&"Got effect part".to_string()); - Ok(vec![mret]) - } else { - Err(MethodErr::failed("Could not lock daemon for access")) - } - } - }) - .outarg::<&str, _>("reply") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") -} - -fn dbus_create_ledeffect_method(effect: EffectType) -> Method { - let factory = Factory::new_sync::<()>(); - factory - // method for ledmessage - .method("LedWriteEffect", (), { - 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()?, - iter.read()?, - ]; - *lock = Some(byte_array); - Ok(vec![]) - } else { - Err(MethodErr::failed("Could not lock daemon for access")) - } - } - }) - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") - .inarg::, _>("bytearray") -} - -fn dbus_create_fan_mode_method(fan_mode: FanModeType) -> Method { - let factory = Factory::new_sync::<()>(); - factory - // method for ledmessage - .method("FanMode", (), { - move |m| { - if let Ok(mut lock) = fan_mode.try_lock() { - let mut iter = m.msg.iter_init(); - let byte: u8 = iter.read()?; - *lock = Some(byte); - let mret = m - .msg - .method_return() - .append1(format!("Fan level set to {:?}", FanLevel::from(byte))); - Ok(vec![mret]) - } else { - Err(MethodErr::failed("Could not lock daemon for access")) - } - } - }) - .outarg::<&str, _>("reply") - .inarg::("byte") -} - -fn dbus_create_tree() -> ( - Tree, - LedMsgType, - EffectType, - FanModeType, - Arc>, -) { - let input_bytes: LedMsgType = Arc::new(Mutex::new(None)); - let input_effect: EffectType = Arc::new(Mutex::new(None)); - let fan_mode: FanModeType = Arc::new(Mutex::new(None)); - - let factory = Factory::new_sync::<()>(); - let effect_cancel_sig = Arc::new(factory.signal("LedCancelEffect", ())); - let tree = factory.tree(()).add( - factory.object_path(DBUS_PATH, ()).add( - factory - .interface(DBUS_IFACE, ()) - .add_m(dbus_create_ledmsg_method(input_bytes.clone())) - .add_m(dbus_create_ledmultizone_method(input_effect.clone())) - .add_m(dbus_create_ledeffect_method(input_effect.clone())) - .add_m(dbus_create_fan_mode_method(fan_mode.clone())) - .add_s(effect_cancel_sig.clone()), - ), - ); - (tree, input_bytes, input_effect, fan_mode, effect_cancel_sig) -} diff --git a/rog-core/src/laptops.rs b/rog-core/src/laptops.rs index 5c95e6c9..ea884534 100644 --- a/rog-core/src/laptops.rs +++ b/rog-core/src/laptops.rs @@ -27,6 +27,7 @@ pub(crate) fn match_laptop() -> LaptopBase { BuiltInModeByte::Breathing, BuiltInModeByte::Cycle, ], + support_animatrix: false, // backlight: Backlight::new("intel_backlight").unwrap(), }; } @@ -51,6 +52,7 @@ fn choose_1866_device(prod: u16) -> LaptopBase { //from `lsusb -vd 0b05:1866` key_endpoint: 0x83, supported_modes: vec![], + support_animatrix: false, //backlight: Backlight::new("intel_backlight").unwrap(), }; match &board_name.as_str()[..5] { @@ -83,6 +85,7 @@ fn choose_1866_device(prod: u16) -> LaptopBase { "GA401" => { // Has no RGB control info!("Found GA401 series"); + laptop.support_animatrix = true; } _ => panic!("Unsupported laptop: {}, please request support at\nhttps://github.com/flukejones/rog-core", board_name), } @@ -98,6 +101,7 @@ pub(super) struct LaptopBase { led_endpoint: u8, key_endpoint: u8, supported_modes: Vec, + support_animatrix: bool, //backlight: Backlight, } @@ -150,6 +154,9 @@ impl LaptopBase { pub(super) fn supported_modes(&self) -> &[BuiltInModeByte] { &self.supported_modes } + pub(super) fn support_animatrix(&self) -> bool { + self.support_animatrix + } // 0x1866, per-key LEDs, media-keys split from vendor specific async fn gx502_runner( diff --git a/rog-core/src/led_control.rs b/rog-core/src/led_control.rs index ba71b243..550ea8d0 100644 --- a/rog-core/src/led_control.rs +++ b/rog-core/src/led_control.rs @@ -147,7 +147,6 @@ where /// Should only be used if the bytes you are writing are verified correct #[inline] async fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> { - let prev_time = std::time::Instant::now(); match unsafe { self.handle.as_ref() }.write_interrupt( self.led_endpoint, message, @@ -159,10 +158,6 @@ where _ => error!("Failed to write to led interrupt: {:?}", err), }, } - println!( - "Took: {:?}", - std::time::Instant::now().duration_since(prev_time) - ); Ok(()) } diff --git a/rog-core/src/lib.rs b/rog-core/src/lib.rs index 04ee4018..82a385d3 100644 --- a/rog-core/src/lib.rs +++ b/rog-core/src/lib.rs @@ -1,4 +1,6 @@ #![deny(unused_must_use)] +/// +mod animatrix_control; /// Configuration loading, saving mod config; /// Start the daemon loop @@ -7,6 +9,8 @@ pub mod daemon; mod laptops; /// mod led_control; +/// +mod rog_dbus; /// The core module which allows writing to LEDs or polling the /// laptop keyboard attached devices pub mod rogcore; diff --git a/rog-core/src/main.rs b/rog-core/src/main.rs index 72ce500e..4b03192b 100644 --- a/rog-core/src/main.rs +++ b/rog-core/src/main.rs @@ -8,7 +8,7 @@ use rog_aura::{ AuraDbusWriter, LED_MSG_LEN, }; -static VERSION: &'static str = "0.9.9"; +static VERSION: &str = "0.9.9"; #[derive(Debug, Options)] struct CLIStart { diff --git a/rog-core/src/rog_dbus.rs b/rog-core/src/rog_dbus.rs new file mode 100644 index 00000000..ca0299e1 --- /dev/null +++ b/rog-core/src/rog_dbus.rs @@ -0,0 +1,179 @@ +use crate::daemon::{FanModeType, LedMsgType, NestedVecType}; +use crate::rogcore::FanLevel; +use dbus::tree::{Factory, MTSync, Method, MethodErr, Signal, Tree}; +use rog_aura::{DBUS_IFACE, DBUS_PATH}; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub(super) fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("LedWriteBytes", (), { + 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)); + Ok(vec![mret]) + } else { + Err(MethodErr::failed("Could not lock daemon for access")) + } + } + }) + .outarg::<&str, _>("reply") + .inarg::, _>("bytearray") +} + +pub(super) fn dbus_create_ledmultizone_method(effect: NestedVecType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("LedWriteMultizone", (), { + 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()?]; + *lock = Some(byte_array); + let mret = m + .msg + .method_return() + .append1(&"Got effect part".to_string()); + Ok(vec![mret]) + } else { + Err(MethodErr::failed("Could not lock daemon for access")) + } + } + }) + .outarg::<&str, _>("reply") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") +} + +pub(super) fn dbus_create_ledeffect_method(effect: NestedVecType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("LedWriteEffect", (), { + 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()?, + iter.read()?, + ]; + *lock = Some(byte_array); + Ok(vec![]) + } else { + Err(MethodErr::failed("Could not lock daemon for access")) + } + } + }) + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") +} + +pub(super) fn dbus_create_animatrix_method(effect: NestedVecType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("AnimatrixWrite", (), { + 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()?]; + *lock = Some(byte_array); + Ok(vec![]) + } else { + Err(MethodErr::failed("Could not lock daemon for access")) + } + } + }) + .inarg::, _>("bytearray") + .inarg::, _>("bytearray") +} + +pub(super) fn dbus_create_fan_mode_method(fan_mode: FanModeType) -> Method { + let factory = Factory::new_sync::<()>(); + factory + // method for ledmessage + .method("FanMode", (), { + move |m| { + if let Ok(mut lock) = fan_mode.try_lock() { + let mut iter = m.msg.iter_init(); + let byte: u8 = iter.read()?; + *lock = Some(byte); + let mret = m + .msg + .method_return() + .append1(format!("Fan level set to {:?}", FanLevel::from(byte))); + Ok(vec![mret]) + } else { + Err(MethodErr::failed("Could not lock daemon for access")) + } + } + }) + .outarg::<&str, _>("reply") + .inarg::("byte") +} + +pub(super) fn dbus_create_tree() -> ( + Tree, + LedMsgType, + NestedVecType, + NestedVecType, + FanModeType, + Arc>, +) { + let input_bytes: LedMsgType = Arc::new(Mutex::new(None)); + let input_effect: NestedVecType = Arc::new(Mutex::new(None)); + let animatrix_img: NestedVecType = Arc::new(Mutex::new(None)); + let fan_mode: FanModeType = Arc::new(Mutex::new(None)); + + let factory = Factory::new_sync::<()>(); + let effect_cancel_sig = Arc::new(factory.signal("LedCancelEffect", ())); + let tree = factory.tree(()).add( + factory.object_path(DBUS_PATH, ()).add( + factory + .interface(DBUS_IFACE, ()) + .add_m(dbus_create_ledmsg_method(input_bytes.clone())) + .add_m(dbus_create_ledmultizone_method(input_effect.clone())) + .add_m(dbus_create_ledeffect_method(input_effect.clone())) + .add_m(dbus_create_animatrix_method(animatrix_img.clone())) + .add_m(dbus_create_fan_mode_method(fan_mode.clone())) + .add_s(effect_cancel_sig.clone()), + ), + ); + ( + tree, + input_bytes, + input_effect, + animatrix_img, + fan_mode, + effect_cancel_sig, + ) +} diff --git a/rog-core/src/rogcore.rs b/rog-core/src/rogcore.rs index b425cf65..e3e7f713 100644 --- a/rog-core/src/rogcore.rs +++ b/rog-core/src/rogcore.rs @@ -5,7 +5,7 @@ use log::{error, info, warn}; use rusb::DeviceHandle; use std::error::Error; use std::fs::OpenOptions; -use std::io::{Read, Write}; +use std::io::Write; use std::marker::{PhantomData, PhantomPinned}; use std::path::Path; use std::process::Command;