Initial groundwork of animatrix

This commit is contained in:
Luke
2020-05-31 12:21:04 +12:00
parent ca5d625cec
commit d9fc7de5cb
14 changed files with 490 additions and 162 deletions

View File

@@ -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

View File

@@ -0,0 +1,13 @@
use rog_aura::AnimatrixDbusWriter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
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));
}
}

View File

@@ -23,7 +23,5 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
writer.write_colour_block(&key_colours)?;
//std::thread::sleep(std::time::Duration::from_millis(250));
}
}

View File

@@ -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<Connection>,
block_time: u64,
stop: Arc<AtomicBool>,
}
impl AnimatrixDbusWriter {
#[inline]
pub fn new() -> Result<Self, Box<dyn Error>> {
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 .. <led brightness>
/// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
pub fn write_image(&mut self, image: &[Vec<u8>; 2]) -> Result<(), Box<dyn Error>> {
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(())
}
}

View File

@@ -59,7 +59,7 @@ impl AuraDbusWriter {
&mut self,
key_colour_array: &KeyColourArray,
) -> Result<(), Box<dyn Error>> {
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")?

View File

@@ -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::*;

View File

@@ -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<Vec<u8>>),
//ReloadLast,
}
pub struct AnimatrixWriter {
handle: DeviceHandle<rusb::GlobalContext>,
initialised: bool,
}
impl AnimatrixWriter {
#[inline]
pub fn new() -> Result<AnimatrixWriter, Box<dyn Error>> {
// 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 .. <led brightness>
/// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
async fn write_image(&mut self, image: Vec<Vec<u8>>) -> 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<DeviceHandle<rusb::GlobalContext>, 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(())
}
}

View File

@@ -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<Mutex<Option<u8>>>;
type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
pub(super) type FanModeType = Arc<Mutex<Option<u8>>>;
pub(super) type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
pub(super) type NestedVecType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
@@ -68,6 +66,13 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
.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<dyn Error>> {
let (aura_command_send, aura_command_recv) = mpsc::sync_channel::<AuraCommand>(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<dyn Error>> {
}
}
// 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<dyn Error>> {
key_read_handle.await?;
Ok(())
}
fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method<MTSync, ()> {
let factory = Factory::new_sync::<()>();
factory
// method for ledmessage
.method("LedWriteBytes", (), {
move |m| {
let bytes: Vec<u8> = 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::<Vec<u8>, _>("bytearray")
}
fn dbus_create_ledmultizone_method(effect: EffectType) -> Method<MTSync, ()> {
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<u8>> =
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::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
fn dbus_create_ledeffect_method(effect: EffectType) -> Method<MTSync, ()> {
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<u8>> = 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::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
fn dbus_create_fan_mode_method(fan_mode: FanModeType) -> Method<MTSync, ()> {
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::<u8, _>("byte")
}
fn dbus_create_tree() -> (
Tree<MTSync, ()>,
LedMsgType,
EffectType,
FanModeType,
Arc<Signal<()>>,
) {
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)
}

View File

@@ -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<BuiltInModeByte>,
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(

View File

@@ -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(())
}

View File

@@ -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;

View File

@@ -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 {

179
rog-core/src/rog_dbus.rs Normal file
View File

@@ -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<MTSync, ()> {
let factory = Factory::new_sync::<()>();
factory
// method for ledmessage
.method("LedWriteBytes", (), {
move |m| {
let bytes: Vec<u8> = 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::<Vec<u8>, _>("bytearray")
}
pub(super) fn dbus_create_ledmultizone_method(effect: NestedVecType) -> Method<MTSync, ()> {
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<u8>> =
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::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
pub(super) fn dbus_create_ledeffect_method(effect: NestedVecType) -> Method<MTSync, ()> {
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<u8>> = 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::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
pub(super) fn dbus_create_animatrix_method(effect: NestedVecType) -> Method<MTSync, ()> {
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<u8>> = vec![iter.read()?, iter.read()?];
*lock = Some(byte_array);
Ok(vec![])
} else {
Err(MethodErr::failed("Could not lock daemon for access"))
}
}
})
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
pub(super) fn dbus_create_fan_mode_method(fan_mode: FanModeType) -> Method<MTSync, ()> {
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::<u8, _>("byte")
}
pub(super) fn dbus_create_tree() -> (
Tree<MTSync, ()>,
LedMsgType,
NestedVecType,
NestedVecType,
FanModeType,
Arc<Signal<()>>,
) {
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,
)
}

View File

@@ -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;