diff --git a/README.md b/README.md index 21e92f50..0a5df3e5 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Models GA401, GA502, GU502 support LED brightness change only (no RGB). - `libdbus-1-dev` - `llvm` - `libclang-dev` +- `libudev-dev` ## Installing diff --git a/rog-client/src/lib.rs b/rog-client/src/lib.rs index 73f570a3..6b6f8321 100644 --- a/rog-client/src/lib.rs +++ b/rog-client/src/lib.rs @@ -23,6 +23,12 @@ pub mod anime_matrix; pub mod error; +// static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; +// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d +// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; +// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e +// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; + /// Writes aout the correct byte string for brightness /// /// The HID descriptor looks like: diff --git a/rog-core/src/daemon.rs b/rog-core/src/daemon.rs index c051ab49..9bbe454b 100644 --- a/rog-core/src/daemon.rs +++ b/rog-core/src/daemon.rs @@ -34,21 +34,7 @@ pub async fn start_daemon() -> Result<(), Box> { info!("Config loaded"); - let mut rogcore = RogCore::new( - laptop.usb_vendor(), - laptop.usb_product(), - laptop.key_endpoint(), - ) - .map_or_else( - |err| { - error!("{}", err); - panic!("{}", err); - }, - |daemon| { - info!("RogCore loaded"); - daemon - }, - ); + let mut rogcore = RogCore::new(laptop.usb_vendor(), laptop.usb_product()); // Reload settings rogcore @@ -59,8 +45,7 @@ pub async fn start_daemon() -> Result<(), Box> { .unwrap_or_else(|err| warn!("Battery charge limit: {}", err)); let mut led_writer = LedWriter::new( - rogcore.get_raw_device_handle(), - laptop.led_endpoint(), + "/dev/hidraw2".to_string(), laptop.supported_modes().to_owned(), ); @@ -136,6 +121,7 @@ pub async fn start_daemon() -> Result<(), Box> { // spawning this in a function causes a segfault for reasons I haven't investigated yet tokio::spawn(async move { loop { + // TODO: MAKE SYS COMMANDS OPERATE USING CHANNEL LIKE AURA MODES // Fan mode if let Ok(mut lock) = fan_mode.try_lock() { if let Some(n) = lock.take() { @@ -154,7 +140,7 @@ pub async fn start_daemon() -> Result<(), Box> { .unwrap_or_else(|err| warn!("{:?}", err)); } } - + std::thread::sleep(std::time::Duration::from_millis(500)); } }); @@ -262,4 +248,3 @@ async fn send_boot_signals( .unwrap_or_else(|_| 0); Ok(()) } - diff --git a/rog-core/src/laptops.rs b/rog-core/src/laptops.rs index 67b0d554..4353d8a8 100644 --- a/rog-core/src/laptops.rs +++ b/rog-core/src/laptops.rs @@ -1,10 +1,8 @@ -use rog_client::{ - aura_modes::{ - AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW, - RGB, RIPPLE, SINGLE, STAR, STROBE, - }, -}; use log::{info, warn}; +use rog_client::aura_modes::{ + AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW, RGB, + RIPPLE, SINGLE, STAR, STROBE, +}; static HELP_ADDRESS: &str = "https://github.com/flukejones/rog-core"; @@ -21,8 +19,6 @@ pub(crate) fn match_laptop() -> LaptopBase { usb_product: 0x1854, //from `lsusb -vd 0b05:1866` led_endpoint: 0x04, - //from `lsusb -vd 0b05:1866` - key_endpoint: 0x83, supported_modes: vec![SINGLE, BREATHING, STROBE], support_animatrix: false, }; @@ -47,8 +43,6 @@ fn select_1866_device(prod: u16) -> LaptopBase { usb_product: prod, //from `lsusb -vd 0b05:1866` led_endpoint: 0x04, - //from `lsusb -vd 0b05:1866` - key_endpoint: 0x83, supported_modes: vec![], support_animatrix: false, }; @@ -72,12 +66,22 @@ fn select_1866_device(prod: u16) -> LaptopBase { SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET, FLASH, RGB, ]; - } else if board_name.starts_with("G531") - || board_name.starts_with("G731") - { + } else if board_name.starts_with("G531") || board_name.starts_with("G731") { laptop.supported_modes = vec![ - SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET, - FLASH, MULTISTATIC, RGB, + SINGLE, + BREATHING, + STROBE, + RAINBOW, + STAR, + RAIN, + HIGHLIGHT, + LASER, + RIPPLE, + PULSE, + COMET, + FLASH, + MULTISTATIC, + RGB, ]; // RGB, limited effects, no zones } else if board_name.starts_with("G512LI") || board_name.starts_with("G712LI") { @@ -116,7 +120,6 @@ pub(super) struct LaptopBase { usb_vendor: u16, usb_product: u16, led_endpoint: u8, - key_endpoint: u8, supported_modes: Vec, support_animatrix: bool, } @@ -125,9 +128,6 @@ impl LaptopBase { pub(super) fn led_endpoint(&self) -> u8 { self.led_endpoint } - pub(super) fn key_endpoint(&self) -> u8 { - self.key_endpoint - } pub(super) fn usb_vendor(&self) -> u16 { self.usb_vendor } diff --git a/rog-core/src/led_control.rs b/rog-core/src/led_control.rs index 5ce2c808..a53349a2 100644 --- a/rog-core/src/led_control.rs +++ b/rog-core/src/led_control.rs @@ -1,9 +1,3 @@ -static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; -static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d -static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; -static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e -static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; - // Only these two packets must be 17 bytes static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; @@ -13,104 +7,46 @@ use log::{error, info, warn}; use rog_client::{ aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN, }; -use rusb::DeviceHandle; -use std::marker::PhantomData; -use std::ptr::NonNull; -use std::time::Duration; +use std::fs::OpenOptions; +use std::io::Write; /// UNSAFE: Must live as long as RogCore /// /// Because we're holding a pointer to something that *may* go out of scope while the /// pointer is held. We're relying on access to struct to be behind a Mutex, and for behaviour /// that may cause invalididated pointer to cause the program to panic rather than continue. -pub struct LedWriter<'d, C: 'd> -where - C: rusb::UsbContext, -{ - handle: NonNull>, +pub struct LedWriter { + dev_node: String, supported_modes: Vec, - led_endpoint: u8, - initialised: bool, flip_effect_write: bool, - _phantom: PhantomData<&'d DeviceHandle>, } -/// UNSAFE -unsafe impl<'d, C> Send for LedWriter<'d, C> where C: rusb::UsbContext {} -unsafe impl<'d, C> Sync for LedWriter<'d, C> where C: rusb::UsbContext {} - -impl<'d, C> LedWriter<'d, C> -where - C: rusb::UsbContext, -{ +impl LedWriter { #[inline] - pub fn new( - device_handle: NonNull>, - led_endpoint: u8, - supported_modes: Vec, - ) -> Self { + pub fn new(dev_node: String, supported_modes: Vec) -> Self { LedWriter { - handle: device_handle, - led_endpoint, + dev_node, supported_modes, - initialised: false, flip_effect_write: false, - _phantom: PhantomData, } } - async fn initialise(&mut self) -> Result<(), RogError> { - if !self.initialised { - self.write_bytes(&LED_INIT1).await?; - self.write_bytes(LED_INIT2.as_bytes()).await?; - self.write_bytes(&LED_INIT3).await?; - self.write_bytes(LED_INIT4.as_bytes()).await?; - self.write_bytes(&LED_INIT5).await?; - self.initialised = true; - } - Ok(()) - } - pub async fn do_command( &mut self, mode: AuraModes, config: &mut Config, ) -> Result<(), RogError> { - self.initialise().await?; self.set_and_save(mode, config).await } /// Should only be used if the bytes you are writing are verified correct #[inline] async fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> { - println!("1 Wrote: {:X?}", message); - match unsafe { self.handle.as_ref() }.write_interrupt( - self.led_endpoint, - message, - Duration::from_millis(5), - ) { - Ok(_) => { - let mut buf = [0; 32]; - match unsafe { self.handle.as_ref() }.read_interrupt( - 0x83, - &mut buf, - Duration::from_millis(5), - ) { - Ok(_) => { - println!("2 Read: {:X?}", buf); - } - Err(err) => match err { - rusb::Error::Timeout => {} - _ => error!("Failed to read to led interrupt: {:?}", err), - }, - } - } - Err(err) => match err { - rusb::Error::Timeout => {} - _ => error!("Failed to write to led interrupt: {:?}", err), - }, + if let Ok(mut file) = OpenOptions::new().write(true).open(&self.dev_node) { + file.write_all(message).unwrap(); + return Ok(()); } - Ok(()) + Err(RogError::NotSupported) } /// Write an effect block @@ -150,10 +86,6 @@ where config.current_mode = mode_num; config.set_mode_data(mode); config.write(); - info!( - "Switched LED mode to {}", - <&str>::from(&::from(config.current_mode)) - ); } } Ok(()) @@ -198,7 +130,6 @@ where #[inline] pub async fn reload_last_builtin(&mut self, config: &mut Config) -> Result<(), RogError> { - self.initialise().await?; // set current mode (if any) if self.supported_modes.len() > 1 { if self.supported_modes.contains(&config.current_mode) { diff --git a/rog-core/src/rogcore.rs b/rog-core/src/rogcore.rs index 9cede77b..e7207b31 100644 --- a/rog-core/src/rogcore.rs +++ b/rog-core/src/rogcore.rs @@ -2,14 +2,11 @@ use crate::{config::Config, error::RogError}; use log::{error, info, warn}; -use rusb::{Device, DeviceHandle}; use std::error::Error; use std::fs::OpenOptions; use std::io::Write; -use std::marker::{PhantomPinned}; use std::path::Path; use std::process::Command; -use std::ptr::NonNull; use std::str::FromStr; static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; @@ -26,72 +23,11 @@ static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_ /// - `LED_INIT4` /// - `LED_INIT2` /// - `LED_INIT4` -pub struct RogCore { - handle: DeviceHandle, - _pin: PhantomPinned, -} +pub struct RogCore {} impl RogCore { - pub fn new(vendor: u16, product: u16, match_endpoint: u8) -> Result> { - let device = RogCore::get_device(vendor, product).map_err(|err| { - error!("Could not find keyboard device: {:?}", err); - err - })?; - - let dev_config = device.config_descriptor(0).map_err(|err| { - error!("Could not get keyboard device config: {:?}", err); - err - })?; - info!("ACTIVE CONFIG: {:?}", dev_config.number()); - - // Interface with outputs - let mut interface = 2; // The interface with keyboard consumer device and LED control - // is #2 on 0x1866 device at least - for iface in dev_config.interfaces() { - for desc in iface.descriptors() { - for endpoint in desc.endpoint_descriptors() { - if endpoint.address() == match_endpoint { - info!("INTERVAL: {:?}", endpoint.interval()); - info!("MAX_PKT_SIZE: {:?}", endpoint.max_packet_size()); - info!("SYNC: {:?}", endpoint.sync_type()); - info!("TRANSFER_TYPE: {:?}", endpoint.transfer_type()); - info!("ENDPOINT: {:X?}", endpoint.address()); - info!("INTERFACE: {:X?}", desc.interface_number()); - interface = desc.interface_number(); - break; - } - } - } - } - - let mut device = device.open().map_err(|err| { - error!("Could not open device: {:?}", err); - err - })?; - - if let Err(err) = device.set_auto_detach_kernel_driver(true) { - warn!("Auto-detach kernel driver failed: {:?}", err); - warn!("Trying device reset"); - device.reset()?; - std::thread::sleep(std::time::Duration::from_millis(500)); - device.set_auto_detach_kernel_driver(true)?; - } - - // std::thread::sleep(std::time::Duration::from_millis(500)); - Ok(RogCore { - handle: device, - _pin: PhantomPinned, - }) - } - - 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 Ok(device); - } - } - Err(rusb::Error::NoDevice) + pub fn new(vendor: u16, product: u16) -> Self { + RogCore {} } fn get_fan_path() -> Result<&'static str, std::io::Error> { @@ -318,7 +254,6 @@ impl RogCore { } } - #[derive(Debug)] pub enum FanLevel { Normal,