mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Initial groundwork of animatrix
This commit is contained in:
@@ -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
|
||||
13
aura/examples/animatrix.rs
Normal file
13
aura/examples/animatrix.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
55
aura/src/animatrix_dbus.rs
Normal file
55
aura/src/animatrix_dbus.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -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")?
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
|
||||
196
rog-core/src/animatrix_control.rs
Normal file
196
rog-core/src/animatrix_control.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
179
rog-core/src/rog_dbus.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user