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.
|
- [flukejones](https://github.com/flukejones/), project maintainer.
|
||||||
- [tuxuser](https://github.com/tuxuser/)
|
- [tuxuser](https://github.com/tuxuser/)
|
||||||
|
<<<<<<< HEAD
|
||||||
- [aspann](https://github.com/aspann)
|
- [aspann](https://github.com/aspann)
|
||||||
|
=======
|
||||||
|
- ZappeL, `TODO: link, any details`
|
||||||
|
- dragonn, `TODO: link, any details`
|
||||||
|
>>>>>>> Initial groundwork of animatrix
|
||||||
- Anyone missed? Please contact me
|
- 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)?;
|
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,
|
&mut self,
|
||||||
key_colour_array: &KeyColourArray,
|
key_colour_array: &KeyColourArray,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> 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 group = key_colour_array.get();
|
||||||
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")?
|
let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "LedWriteEffect")?
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ pub use aura_dbus::*;
|
|||||||
|
|
||||||
pub use fancy::*;
|
pub use fancy::*;
|
||||||
|
|
||||||
|
mod animatrix_dbus;
|
||||||
|
pub use animatrix_dbus::*;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
use crate::cli_options::*;
|
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::{
|
use crate::{
|
||||||
|
animatrix_control::{AnimatrixCommand, AnimatrixWriter},
|
||||||
config::Config,
|
config::Config,
|
||||||
laptops::match_laptop,
|
laptops::match_laptop,
|
||||||
led_control::{AuraCommand, LedWriter},
|
led_control::{AuraCommand, LedWriter},
|
||||||
|
rog_dbus::dbus_create_tree,
|
||||||
rogcore::*,
|
rogcore::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use dbus::{
|
use dbus::{channel::Sender, nonblock::Process};
|
||||||
channel::Sender,
|
|
||||||
nonblock::Process,
|
|
||||||
tree::{Factory, MTSync, Method, MethodErr, Signal, Tree},
|
|
||||||
};
|
|
||||||
|
|
||||||
use dbus_tokio::connection;
|
use dbus_tokio::connection;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
@@ -19,9 +17,9 @@ use std::sync::{mpsc, Arc};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
type FanModeType = Arc<Mutex<Option<u8>>>;
|
pub(super) type FanModeType = Arc<Mutex<Option<u8>>>;
|
||||||
type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
|
pub(super) type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
|
||||||
type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
|
pub(super) type NestedVecType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
|
||||||
|
|
||||||
// Timing is such that:
|
// Timing is such that:
|
||||||
// - interrupt write is minimum 1ms (sometimes lower)
|
// - 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)
|
.do_command(AuraCommand::ReloadLast, &mut config)
|
||||||
.await?;
|
.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
|
// Set up the mutexes
|
||||||
let config = Arc::new(Mutex::new(config));
|
let config = Arc::new(Mutex::new(config));
|
||||||
let (resource, connection) = connection::new_system_sync()?;
|
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 (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.
|
// We add the tree to the connection so that incoming method calls will be handled.
|
||||||
tree.start_receive_send(&*connection);
|
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();
|
let now = Instant::now();
|
||||||
// Cool-down steps
|
// Cool-down steps
|
||||||
// This block is to prevent the loop spooling as fast as possible and saturating the CPU
|
// 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?;
|
key_read_handle.await?;
|
||||||
Ok(())
|
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::Breathing,
|
||||||
BuiltInModeByte::Cycle,
|
BuiltInModeByte::Cycle,
|
||||||
],
|
],
|
||||||
|
support_animatrix: false,
|
||||||
// backlight: Backlight::new("intel_backlight").unwrap(),
|
// backlight: Backlight::new("intel_backlight").unwrap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -51,6 +52,7 @@ fn choose_1866_device(prod: u16) -> LaptopBase {
|
|||||||
//from `lsusb -vd 0b05:1866`
|
//from `lsusb -vd 0b05:1866`
|
||||||
key_endpoint: 0x83,
|
key_endpoint: 0x83,
|
||||||
supported_modes: vec![],
|
supported_modes: vec![],
|
||||||
|
support_animatrix: false,
|
||||||
//backlight: Backlight::new("intel_backlight").unwrap(),
|
//backlight: Backlight::new("intel_backlight").unwrap(),
|
||||||
};
|
};
|
||||||
match &board_name.as_str()[..5] {
|
match &board_name.as_str()[..5] {
|
||||||
@@ -83,6 +85,7 @@ fn choose_1866_device(prod: u16) -> LaptopBase {
|
|||||||
"GA401" => {
|
"GA401" => {
|
||||||
// Has no RGB control
|
// Has no RGB control
|
||||||
info!("Found GA401 series");
|
info!("Found GA401 series");
|
||||||
|
laptop.support_animatrix = true;
|
||||||
}
|
}
|
||||||
_ => panic!("Unsupported laptop: {}, please request support at\nhttps://github.com/flukejones/rog-core", board_name),
|
_ => 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,
|
led_endpoint: u8,
|
||||||
key_endpoint: u8,
|
key_endpoint: u8,
|
||||||
supported_modes: Vec<BuiltInModeByte>,
|
supported_modes: Vec<BuiltInModeByte>,
|
||||||
|
support_animatrix: bool,
|
||||||
//backlight: Backlight,
|
//backlight: Backlight,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +154,9 @@ impl LaptopBase {
|
|||||||
pub(super) fn supported_modes(&self) -> &[BuiltInModeByte] {
|
pub(super) fn supported_modes(&self) -> &[BuiltInModeByte] {
|
||||||
&self.supported_modes
|
&self.supported_modes
|
||||||
}
|
}
|
||||||
|
pub(super) fn support_animatrix(&self) -> bool {
|
||||||
|
self.support_animatrix
|
||||||
|
}
|
||||||
|
|
||||||
// 0x1866, per-key LEDs, media-keys split from vendor specific
|
// 0x1866, per-key LEDs, media-keys split from vendor specific
|
||||||
async fn gx502_runner(
|
async fn gx502_runner(
|
||||||
|
|||||||
@@ -147,7 +147,6 @@ where
|
|||||||
/// Should only be used if the bytes you are writing are verified correct
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
|
async fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
|
||||||
let prev_time = std::time::Instant::now();
|
|
||||||
match unsafe { self.handle.as_ref() }.write_interrupt(
|
match unsafe { self.handle.as_ref() }.write_interrupt(
|
||||||
self.led_endpoint,
|
self.led_endpoint,
|
||||||
message,
|
message,
|
||||||
@@ -159,10 +158,6 @@ where
|
|||||||
_ => error!("Failed to write to led interrupt: {:?}", err),
|
_ => error!("Failed to write to led interrupt: {:?}", err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
println!(
|
|
||||||
"Took: {:?}",
|
|
||||||
std::time::Instant::now().duration_since(prev_time)
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#![deny(unused_must_use)]
|
#![deny(unused_must_use)]
|
||||||
|
///
|
||||||
|
mod animatrix_control;
|
||||||
/// Configuration loading, saving
|
/// Configuration loading, saving
|
||||||
mod config;
|
mod config;
|
||||||
/// Start the daemon loop
|
/// Start the daemon loop
|
||||||
@@ -7,6 +9,8 @@ pub mod daemon;
|
|||||||
mod laptops;
|
mod laptops;
|
||||||
///
|
///
|
||||||
mod led_control;
|
mod led_control;
|
||||||
|
///
|
||||||
|
mod rog_dbus;
|
||||||
/// The core module which allows writing to LEDs or polling the
|
/// The core module which allows writing to LEDs or polling the
|
||||||
/// laptop keyboard attached devices
|
/// laptop keyboard attached devices
|
||||||
pub mod rogcore;
|
pub mod rogcore;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rog_aura::{
|
|||||||
AuraDbusWriter, LED_MSG_LEN,
|
AuraDbusWriter, LED_MSG_LEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static VERSION: &'static str = "0.9.9";
|
static VERSION: &str = "0.9.9";
|
||||||
|
|
||||||
#[derive(Debug, Options)]
|
#[derive(Debug, Options)]
|
||||||
struct CLIStart {
|
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 rusb::DeviceHandle;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::Write;
|
||||||
use std::marker::{PhantomData, PhantomPinned};
|
use std::marker::{PhantomData, PhantomPinned};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|||||||
Reference in New Issue
Block a user