From 4e78a5dbdd1d24933c9c187e2a84339e0947bfa9 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 29 Apr 2020 14:08:22 +1200 Subject: [PATCH] Code cleanup --- Cargo.lock | 3 +- Cargo.toml | 41 +++++- src/core.rs | 93 +++++++------ src/daemon.rs | 9 +- src/laptops/gl753.rs | 154 ---------------------- src/laptops/gx502.rs | 182 -------------------------- src/laptops/mod.rs | 305 ++++++++++++++++++++++++++++++++++++++----- src/main.rs | 40 +++--- 8 files changed, 385 insertions(+), 442 deletions(-) delete mode 100644 src/laptops/gl753.rs delete mode 100644 src/laptops/gx502.rs diff --git a/Cargo.lock b/Cargo.lock index e61b7621..454aa95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,9 +660,8 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rog-daemon" -version = "0.6.1" +version = "0.7.0" dependencies = [ - "aho-corasick", "dbus", "dbus-tokio", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index 6f974f16..f527bba2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "rog-daemon" -version = "0.6.1" +version = "0.7.0" +license = "MPL-2.0" +readme = "README.md" authors = ["Luke "] +repository = "https://github.com/flukejones/rog-core" +homepage = "https://github.com/flukejones/rog-core" +description = "A daemon app for ASUS GX502 and similar laptops to control missing features" edition = "2018" [lib] @@ -14,25 +19,47 @@ path = "src/main.rs" [dependencies] rusb = "^0.5.5" -# cli crate + +# cli and logging gumdrop = "^0.8.0" log = "^0.4.8" env_logger = "^0.7.1" + # async dbus = { version = "^0.8.2", features = ["futures"] } dbus-tokio = "^0.5.1" tokio = { version = "0.2.4", features = ["rt-threaded", "macros"] } + # serialisation serde = "1.0" serde_derive = "1.0" toml = "0.5" -# used for backlight control mostly -# sysfs-class = "^0.1.2" + +# Device control +# sysfs-class = "^0.1.2" # used for backlight control mostly # cpu power management intel-pstate = { git = "https://github.com/flukejones/intel-pstate" } -# -aho-corasick = "^0.7.10" -thiserror = "^1.0.15" # virtualisation of HID, mainly for outputting consumer key codes uhid-virt = "^0.0.4" #keycode = "0.3" + +# +thiserror = "^1.0.15" + +[profile.release] +lto = true +debug = false +opt-level = 3 +panic = "abort" + +[profile.dev] +lto = true +debug = false +opt-level = 3 +#panic = "abort" + +[profile.bench] +lto = true +debug = false +opt-level = 3 +#panic = "abort" \ No newline at end of file diff --git a/src/core.rs b/src/core.rs index 058d2e39..5e0a4ee1 100644 --- a/src/core.rs +++ b/src/core.rs @@ -6,7 +6,6 @@ use crate::{ error::AuraError, virt_device::VirtKeys, }; -use aho_corasick::AhoCorasick; use gumdrop::Options; use log::{debug, error, info, warn}; use rusb::DeviceHandle; @@ -50,12 +49,7 @@ pub(crate) struct RogCore { } impl RogCore { - pub(crate) fn new( - vendor: u16, - product: u16, - led_endpoint: u8, - key_endpoint: u8, - ) -> Result { + pub(crate) fn new(vendor: u16, product: u16, led_endpoint: u8) -> Result { let mut dev_handle = RogCore::get_device(vendor, product)?; dev_handle.set_active_configuration(0).unwrap_or(()); @@ -65,11 +59,12 @@ impl RogCore { for iface in dev_config.interfaces() { for desc in iface.descriptors() { for endpoint in desc.endpoint_descriptors() { - if endpoint.address() == key_endpoint { - debug!("INTERVAL: {:?}", endpoint.interval()); - debug!("MAX: {:?}", endpoint.max_packet_size()); - debug!("SYNC: {:?}", endpoint.sync_type()); - debug!("TRANSFER_TYPE: {:?}", endpoint.transfer_type()); + if endpoint.address() == led_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()); interface = desc.interface_number(); break; } @@ -110,7 +105,7 @@ impl RogCore { }; let mut file = OpenOptions::new().write(true).open(path)?; - file.write(format!("{:?}\n", self.config.fan_mode).as_bytes())?; + file.write_all(format!("{:?}\n", self.config.fan_mode).as_bytes())?; self.set_pstate_for_fan_mode(FanLevel::from(self.config.fan_mode))?; info!("Reloaded last saved settings"); Ok(()) @@ -176,6 +171,26 @@ impl RogCore { Ok(()) } + /// Write an effect block + /// + /// `aura_effect_init` must be called any effect routine, and called only once. + pub async fn async_write_effect( + handle: &DeviceHandle, + endpoint: u8, + effect: Vec>, + ) -> Result<(), AuraError> { + for row in effect.iter() { + match handle.write_interrupt(endpoint, row, Duration::from_millis(1)) { + Ok(_) => {} + Err(err) => match err { + rusb::Error::Timeout => {} + _ => error!("Failed to write LED interrupt: {:?}", err), + }, + } + } + Ok(()) + } + pub(crate) fn aura_set_and_save( &mut self, supported_modes: &[BuiltInModeByte], @@ -205,9 +220,10 @@ impl RogCore { if bright < max_bright { bright += 1; self.config.brightness = bright; + let bytes = aura_brightness_bytes(bright); + self.aura_set_and_save(supported_modes, &bytes)?; + info!("Increased LED brightness to {:#?}", bright); } - let bytes = aura_brightness_bytes(bright); - self.aura_set_and_save(supported_modes, &bytes)?; Ok(()) } @@ -220,9 +236,10 @@ impl RogCore { if bright > min_bright { bright -= 1; self.config.brightness = bright; + let bytes = aura_brightness_bytes(bright); + self.aura_set_and_save(supported_modes, &bytes)?; + info!("Decreased LED brightness to {:#?}", bright); } - let bytes = aura_brightness_bytes(bright); - self.aura_set_and_save(supported_modes, &bytes)?; Ok(()) } @@ -300,7 +317,7 @@ impl RogCore { n = 0; } info!("Fan mode stepped to: {:#?}", FanLevel::from(n)); - fan_ctrl.write(format!("{:?}\n", n).as_bytes())?; + fan_ctrl.write_all(format!("{:?}\n", n).as_bytes())?; self.set_pstate_for_fan_mode(FanLevel::from(n))?; self.config.fan_mode = n; self.config.write(); @@ -384,26 +401,26 @@ impl RogCore { match Command::new("rfkill").arg("list").output() { Ok(output) => { if output.status.success() { - let patterns = &["yes"]; - let ac = AhoCorasick::new(patterns); - if ac.earliest_find(output.stdout).is_some() { - Command::new("rfkill") - .arg("unblock") - .arg("all") - .spawn() - .map_or_else( - |err| warn!("Could not unblock rf devices: {}", err), - |_| {}, - ); - } else { - let _ = Command::new("rfkill") - .arg("block") - .arg("all") - .spawn() - .map_or_else( - |err| warn!("Could not block rf devices: {}", err), - |_| {}, - ); + if let Ok(out) = String::from_utf8(output.stdout) { + if out.contains(": yes") { + Command::new("rfkill") + .arg("unblock") + .arg("all") + .spawn() + .map_or_else( + |err| warn!("Could not unblock rf devices: {}", err), + |_| {}, + ); + } else { + Command::new("rfkill") + .arg("block") + .arg("all") + .spawn() + .map_or_else( + |err| warn!("Could not block rf devices: {}", err), + |_| {}, + ); + } } } else { warn!("Could not list rf devices"); diff --git a/src/daemon.rs b/src/daemon.rs index 2796c42f..2153b37d 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -2,7 +2,10 @@ pub static DBUS_NAME: &'static str = "org.rogcore.Daemon"; pub static DBUS_PATH: &'static str = "/org/rogcore/Daemon"; pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon"; -use crate::{core::RogCore, laptops::match_laptop}; +use crate::{ + core::RogCore, + laptops::{match_laptop, Laptop}, +}; use dbus::{ nonblock::Process, tree::{Factory, MTSync, Method, MethodErr, Tree}, @@ -87,6 +90,8 @@ pub async fn start_daemon() -> Result<(), Box> { let supported = Vec::from(laptop.supported_modes()); // When any action occurs this time is reset let mut time_mark = Instant::now(); + let laptop_actions = laptop.get_runner(); + loop { connection.process_all(); @@ -110,7 +115,7 @@ pub async fn start_daemon() -> Result<(), Box> { if let Ok(mut lock) = key_buf.try_lock() { if let Some(bytes) = *lock { // this takes at least 10ms per colour block - match laptop.run(&mut rogcore, bytes) { + match laptop_actions(&mut rogcore, bytes) { Ok(_) => {} Err(err) => { error!("{:?}", err); diff --git a/src/laptops/gl753.rs b/src/laptops/gl753.rs deleted file mode 100644 index 23c31e38..00000000 --- a/src/laptops/gl753.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::aura::BuiltInModeByte; -use crate::core::RogCore; -use crate::error::AuraError; -use crate::virt_device::ConsumerKeys; -//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; -use super::Laptop; -use log::info; - -pub(super) struct LaptopGL753 { - usb_vendor: u16, - usb_product: u16, - board_name: &'static str, - prod_family: &'static str, - report_filter_bytes: [u8; 2], - min_led_bright: u8, - max_led_bright: u8, - led_endpoint: u8, - key_endpoint: u8, - supported_modes: [BuiltInModeByte; 3], - // backlight: Backlight, -} - -impl LaptopGL753 { - pub(super) fn new() -> Self { - LaptopGL753 { - usb_vendor: 0x0B05, - usb_product: 0x1854, - // from `cat /sys/class/dmi/id/board_name` - board_name: "LaptopGL753VE", - // from `cat /sys/class/dmi/id/product_family` - prod_family: "", - report_filter_bytes: [0x5a, 0x02], - min_led_bright: 0x00, - max_led_bright: 0x03, - //from `lsusb -vd 0b05:1866` - led_endpoint: 0x04, - //from `lsusb -vd 0b05:1866` - key_endpoint: 0x83, - supported_modes: [ - BuiltInModeByte::Single, - BuiltInModeByte::Breathing, - BuiltInModeByte::Cycle, - ], - // backlight: Backlight::new("intel_backlight").unwrap(), - } - } -} - -impl LaptopGL753 { - fn do_keypress_actions( - &self, - rogcore: &mut RogCore, - key_buf: [u8; 32], - ) -> Result<(), AuraError> { - match GL753Keys::from(key_buf[1]) { - GL753Keys::LedBrightUp => { - rogcore.aura_bright_inc(&self.supported_modes, self.max_led_bright)?; - } - GL753Keys::LedBrightDown => { - rogcore.aura_bright_dec(&self.supported_modes, self.min_led_bright)?; - } - GL753Keys::ScreenBrightUp => { - rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()) - } - GL753Keys::ScreenBrightDown => { - rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()) - } - GL753Keys::Sleep => rogcore.suspend_with_systemd(), - GL753Keys::AirplaneMode => rogcore.toggle_airplane_mode(), - GL753Keys::ScreenToggle => { - rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into()); - } - GL753Keys::TouchPadToggle => { - let mut key = [0u8; 32]; - key[0] = 0x01; - key[3] = 0x070; - rogcore.virt_keys().press(key); - } - GL753Keys::Rog => { - let mut key = [0u8; 32]; - key[0] = 0x01; - key[3] = 0x68; // XF86Tools? F13 - rogcore.virt_keys().press(key); - } - GL753Keys::None => { - if key_buf[0] != 0x5A { - info!("Unmapped key, attempt passthrough: {:X?}", &key_buf[1]); - rogcore.virt_keys().press(key_buf); - } - } - } - Ok(()) - } -} - -impl Laptop for LaptopGL753 { - fn run(&self, rogcore: &mut RogCore, key_buf: [u8; 32]) -> Result<(), AuraError> { - self.do_keypress_actions(rogcore, key_buf) - } - fn led_endpoint(&self) -> u8 { - self.led_endpoint - } - fn key_endpoint(&self) -> u8 { - self.key_endpoint - } - fn key_filter(&self) -> &[u8] { - &self.report_filter_bytes - } - fn usb_vendor(&self) -> u16 { - self.usb_vendor - } - fn usb_product(&self) -> u16 { - self.usb_product - } - fn supported_modes(&self) -> &[BuiltInModeByte] { - &self.supported_modes - } - fn board_name(&self) -> &str { - &self.board_name - } - fn prod_family(&self) -> &str { - &self.prod_family - } -} - -enum GL753Keys { - Rog = 0x38, - ScreenToggle = 0x35, - ScreenBrightDown = 0x10, - ScreenBrightUp = 0x20, - TouchPadToggle = 0x6b, - Sleep = 0x6C, - AirplaneMode = 0x88, - LedBrightUp = 0xC4, - LedBrightDown = 0xC5, - None, -} - -impl From for GL753Keys { - fn from(byte: u8) -> Self { - match byte { - 0x38 => GL753Keys::Rog, - 0x35 => GL753Keys::ScreenToggle, - 0x10 => GL753Keys::ScreenBrightDown, - 0x20 => GL753Keys::ScreenBrightUp, - 0x6b => GL753Keys::TouchPadToggle, - 0x6C => GL753Keys::Sleep, - 0x88 => GL753Keys::AirplaneMode, - 0xC4 => GL753Keys::LedBrightUp, - 0xC5 => GL753Keys::LedBrightDown, - _ => GL753Keys::None, - } - } -} diff --git a/src/laptops/gx502.rs b/src/laptops/gx502.rs deleted file mode 100644 index 2408ff30..00000000 --- a/src/laptops/gx502.rs +++ /dev/null @@ -1,182 +0,0 @@ -use crate::aura::BuiltInModeByte; -use crate::core::RogCore; -use crate::error::AuraError; -use crate::virt_device::ConsumerKeys; -//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; -use super::Laptop; -use log::{info, warn}; - -pub(super) struct LaptopGX502 { - usb_vendor: u16, - usb_product: u16, - board_name: &'static str, - prod_family: &'static str, - report_filter_bytes: [u8; 2], - min_led_bright: u8, - max_led_bright: u8, - led_endpoint: u8, - key_endpoint: u8, - supported_modes: [BuiltInModeByte; 12], - //backlight: Backlight, -} - -impl LaptopGX502 { - pub(super) fn new() -> Self { - // Find backlight - LaptopGX502 { - usb_vendor: 0x0B05, - usb_product: 0x1866, - // from `cat /sys/class/dmi/id/board_name` - board_name: "GX502GW", - // from `cat /sys/class/dmi/id/product_family` - prod_family: "Zephyrus S", - report_filter_bytes: [0x5a, 0x02], - min_led_bright: 0x00, - max_led_bright: 0x03, - //from `lsusb -vd 0b05:1866` - led_endpoint: 0x04, - //from `lsusb -vd 0b05:1866` - key_endpoint: 0x83, - supported_modes: [ - BuiltInModeByte::Single, - BuiltInModeByte::Breathing, - BuiltInModeByte::Cycle, - BuiltInModeByte::Rainbow, - BuiltInModeByte::Rain, - BuiltInModeByte::Random, - BuiltInModeByte::Highlight, - BuiltInModeByte::Laser, - BuiltInModeByte::Ripple, - BuiltInModeByte::Pulse, - BuiltInModeByte::ThinZoomy, - BuiltInModeByte::WideZoomy, - ], - //backlight: Backlight::new("intel_backlight").unwrap(), - } - } -} - -impl LaptopGX502 { - fn do_keypress_actions( - &self, - rogcore: &mut RogCore, - key_buf: [u8; 32], - ) -> Result<(), AuraError> { - match GX502Keys::from(key_buf[1]) { - GX502Keys::LedBrightUp => { - rogcore.aura_bright_inc(&self.supported_modes, self.max_led_bright)?; - } - GX502Keys::LedBrightDown => { - rogcore.aura_bright_dec(&self.supported_modes, self.min_led_bright)?; - } - GX502Keys::AuraNext => rogcore.aura_mode_next(&self.supported_modes)?, - GX502Keys::AuraPrevious => rogcore.aura_mode_prev(&self.supported_modes)?, - GX502Keys::ScreenBrightUp => { - rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()) - } //self.backlight.step_up(), - GX502Keys::ScreenBrightDown => { - rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()) - } //self.backlight.step_down(), - GX502Keys::Sleep => rogcore.suspend_with_systemd(), - GX502Keys::AirplaneMode => rogcore.toggle_airplane_mode(), - GX502Keys::MicToggle => {} - GX502Keys::Fan => { - rogcore.fan_mode_step().unwrap_or_else(|err| { - warn!("Couldn't toggle fan mode: {:?}", err); - }); - } - GX502Keys::ScreenToggle => { - rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into()); - } - GX502Keys::TouchPadToggle => { - let mut key = [0u8; 32]; - key[0] = 0x01; - key[3] = 0x070; - rogcore.virt_keys().press(key); - } - GX502Keys::Rog => { - //rogcore.aura_effect_init()?; - //rogcore.aura_write_effect(&self.per_key_led)?; - let mut key = [0u8; 32]; - key[0] = 0x01; - key[3] = 0x68; // XF86Tools? F13 - rogcore.virt_keys().press(key); - } - GX502Keys::None => { - if key_buf[0] != 0x5A { - info!("Unmapped key, attempt passthrough: {:X?}", &key_buf[1]); - rogcore.virt_keys().press(key_buf); - } - } - } - Ok(()) - } -} - -impl Laptop for LaptopGX502 { - fn run(&self, rogcore: &mut RogCore, key_buf: [u8; 32]) -> Result<(), AuraError> { - self.do_keypress_actions(rogcore, key_buf) - } - fn led_endpoint(&self) -> u8 { - self.led_endpoint - } - fn key_endpoint(&self) -> u8 { - self.key_endpoint - } - fn key_filter(&self) -> &[u8] { - &self.report_filter_bytes - } - fn usb_vendor(&self) -> u16 { - self.usb_vendor - } - fn usb_product(&self) -> u16 { - self.usb_product - } - fn supported_modes(&self) -> &[BuiltInModeByte] { - &self.supported_modes - } - fn board_name(&self) -> &str { - &self.board_name - } - fn prod_family(&self) -> &str { - &self.prod_family - } -} - -enum GX502Keys { - Rog = 0x38, - MicToggle = 0x7C, - Fan = 0xAE, - ScreenToggle = 0x35, - ScreenBrightDown = 0x10, - ScreenBrightUp = 0x20, - TouchPadToggle = 0x6b, - Sleep = 0x6C, - AirplaneMode = 0x88, - LedBrightUp = 0xC4, - LedBrightDown = 0xC5, - AuraPrevious = 0xB2, - AuraNext = 0xB3, - None, -} - -impl From for GX502Keys { - fn from(byte: u8) -> Self { - match byte { - 0x38 => GX502Keys::Rog, - 0x7C => GX502Keys::MicToggle, - 0xAE => GX502Keys::Fan, - 0x35 => GX502Keys::ScreenToggle, - 0x10 => GX502Keys::ScreenBrightDown, - 0x20 => GX502Keys::ScreenBrightUp, - 0x6b => GX502Keys::TouchPadToggle, - 0x6C => GX502Keys::Sleep, - 0x88 => GX502Keys::AirplaneMode, - 0xC4 => GX502Keys::LedBrightUp, - 0xC5 => GX502Keys::LedBrightDown, - 0xB2 => GX502Keys::AuraPrevious, - 0xB3 => GX502Keys::AuraNext, - _ => GX502Keys::None, - } - } -} diff --git a/src/laptops/mod.rs b/src/laptops/mod.rs index 87ee3729..390668b1 100644 --- a/src/laptops/mod.rs +++ b/src/laptops/mod.rs @@ -2,53 +2,68 @@ use crate::aura::BuiltInModeByte; use crate::core::RogCore; use crate::error::AuraError; //use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; -use log::info; +use crate::virt_device::ConsumerKeys; +use log::{info, warn}; -// GL753VE == 0x1854, 4 zone keyboard -mod gl753; -use gl753::LaptopGL753; - -// 0x1866, per-key LEDs, media-keys split from vendor specific -mod gx502; -use gx502::LaptopGX502; - -pub(crate) fn match_laptop() -> Box { +pub(crate) fn match_laptop() -> LaptopBase { for device in rusb::devices().unwrap().iter() { let device_desc = device.device_descriptor().unwrap(); if device_desc.vendor_id() == 0x0b05 { match device_desc.product_id() { 0x1869 | 0x1866 => { info!("Found GX502 or similar"); - return Box::new(LaptopGX502::new()); + return LaptopBase { + usb_vendor: 0x0B05, + usb_product: 0x1866, + report_filter_bytes: vec![0x5a, 0x02], + min_led_bright: 0x00, + max_led_bright: 0x03, + //from `lsusb -vd 0b05:1866` + led_endpoint: 0x04, + //from `lsusb -vd 0b05:1866` + key_endpoint: 0x83, + supported_modes: vec![ + BuiltInModeByte::Single, + BuiltInModeByte::Breathing, + BuiltInModeByte::Cycle, + BuiltInModeByte::Rainbow, + BuiltInModeByte::Rain, + BuiltInModeByte::Random, + BuiltInModeByte::Highlight, + BuiltInModeByte::Laser, + BuiltInModeByte::Ripple, + BuiltInModeByte::Pulse, + BuiltInModeByte::ThinZoomy, + BuiltInModeByte::WideZoomy, + ], + //backlight: Backlight::new("intel_backlight").unwrap(), + }; } 0x1854 => { info!("Found GL753 or similar"); - return Box::new(LaptopGL753::new()); + return LaptopBase { + usb_vendor: 0x0B05, + usb_product: 0x1854, + report_filter_bytes: vec![0x5a, 0x02], + min_led_bright: 0x00, + max_led_bright: 0x03, + //from `lsusb -vd 0b05:1866` + led_endpoint: 0x04, + //from `lsusb -vd 0b05:1866` + key_endpoint: 0x83, + supported_modes: vec![ + BuiltInModeByte::Single, + BuiltInModeByte::Breathing, + BuiltInModeByte::Cycle, + ], + // backlight: Backlight::new("intel_backlight").unwrap(), + }; } _ => {} } } } panic!("could not match laptop"); - - // let dmi = sysfs_class::DmiId::default(); - // let board_name = dmi.board_name().unwrap(); - // match &board_name.as_str()[..5] { - // // TODO: FX503VD - 0x1869, - // // These two models seem to have the same characteristics - // "GX502" | "GA502" | "GU502" => { - // info!("Found GX502 or GA502 series"); - // Box::new(LaptopGX502::new()) - // } - // // LED should work for this, but unsure of keys - // "GL753" => { - // info!("Found GL753 series"); - // Box::new(LaptopGL753::new()) - // } - // _ => { - // panic!("could not match laptop"); - // } - // } } /// All laptop models should implement this trait. The role of a `Laptop` is to @@ -63,13 +78,235 @@ pub(crate) fn match_laptop() -> Box { /// If using the `keycode` crate to build keyboard input, the report must be prefixed /// with the report ID (usually `0x01` for the virtual keyboard). pub(crate) trait Laptop { - fn board_name(&self) -> &str; - fn prod_family(&self) -> &str; - fn run(&self, core: &mut RogCore, key_buf: [u8; 32]) -> Result<(), AuraError>; + fn get_runner(&self) -> Box Result<(), AuraError>>; fn led_endpoint(&self) -> u8; fn key_endpoint(&self) -> u8; fn key_filter(&self) -> &[u8]; fn usb_vendor(&self) -> u16; fn usb_product(&self) -> u16; + // required for profiles which match more than one laptop + fn set_usb_product(&mut self, product: u16); fn supported_modes(&self) -> &[BuiltInModeByte]; } + +pub(crate) type LaptopRunner = dyn Fn(&mut RogCore, [u8; 32]) -> Result<(), AuraError>; + +pub(super) struct LaptopBase { + usb_vendor: u16, + usb_product: u16, + report_filter_bytes: Vec, + min_led_bright: u8, + max_led_bright: u8, + led_endpoint: u8, + key_endpoint: u8, + supported_modes: Vec, + //backlight: Backlight, +} + +impl Laptop for LaptopBase { + fn get_runner(&self) -> Box { + match self.usb_product { + 0x1869 | 0x1866 => self.gx502_runner(), + 0x1854 => self.gl753_runner(), + _ => panic!("No runner available for this device"), + } + } + + fn led_endpoint(&self) -> u8 { + self.led_endpoint + } + fn key_endpoint(&self) -> u8 { + self.key_endpoint + } + fn key_filter(&self) -> &[u8] { + &self.report_filter_bytes + } + fn usb_vendor(&self) -> u16 { + self.usb_vendor + } + fn usb_product(&self) -> u16 { + self.usb_product + } + fn set_usb_product(&mut self, product: u16) { + self.usb_product = product; + } + fn supported_modes(&self) -> &[BuiltInModeByte] { + &self.supported_modes + } +} + +impl LaptopBase { + // 0x1866, per-key LEDs, media-keys split from vendor specific + fn gx502_runner(&self) -> Box { + let max_led_bright = self.max_led_bright; + let min_led_bright = self.min_led_bright; + let supported_modes = self.supported_modes.to_owned(); + let function = move |rogcore: &mut RogCore, key_buf: [u8; 32]| { + match GX502Keys::from(key_buf[1]) { + GX502Keys::LedBrightUp => { + rogcore.aura_bright_inc(&supported_modes, max_led_bright)?; + } + GX502Keys::LedBrightDown => { + rogcore.aura_bright_dec(&supported_modes, min_led_bright)?; + } + GX502Keys::AuraNext => rogcore.aura_mode_next(&supported_modes)?, + GX502Keys::AuraPrevious => rogcore.aura_mode_prev(&supported_modes)?, + GX502Keys::ScreenBrightUp => { + rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()) + } //self.backlight.step_up(), + GX502Keys::ScreenBrightDown => { + rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()) + } //self.backlight.step_down(), + GX502Keys::Sleep => rogcore.suspend_with_systemd(), + GX502Keys::AirplaneMode => rogcore.toggle_airplane_mode(), + GX502Keys::MicToggle => {} + GX502Keys::Fan => { + rogcore.fan_mode_step().unwrap_or_else(|err| { + warn!("Couldn't toggle fan mode: {:?}", err); + }); + } + GX502Keys::ScreenToggle => { + rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into()); + } + GX502Keys::TouchPadToggle => { + let mut key = [0u8; 32]; + key[0] = 0x01; + key[3] = 0x070; + rogcore.virt_keys().press(key); + } + GX502Keys::Rog => { + //rogcore.aura_effect_init()?; + //rogcore.aura_write_effect(&self.per_key_led)?; + let mut key = [0u8; 32]; + key[0] = 0x01; + key[3] = 0x68; // XF86Tools? F13 + rogcore.virt_keys().press(key); + } + GX502Keys::None => { + if key_buf[0] != 0x5A { + info!("Unmapped key, attempt passthrough: {:X?}", &key_buf[1]); + rogcore.virt_keys().press(key_buf); + } + } + } + Ok(()) + }; + Box::new(function) + } + + // GL753VE == 0x1854, 4 zone keyboard + fn gl753_runner(&self) -> Box { + let max_led_bright = self.max_led_bright; + let min_led_bright = self.min_led_bright; + let supported_modes = self.supported_modes.to_owned(); + let function = move |rogcore: &mut RogCore, key_buf: [u8; 32]| { + match GL753Keys::from(key_buf[1]) { + GL753Keys::LedBrightUp => { + rogcore.aura_bright_inc(&supported_modes, max_led_bright)?; + } + GL753Keys::LedBrightDown => { + rogcore.aura_bright_dec(&supported_modes, min_led_bright)?; + } + GL753Keys::ScreenBrightUp => { + rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()) + } + GL753Keys::ScreenBrightDown => { + rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()) + } + GL753Keys::Sleep => rogcore.suspend_with_systemd(), + GL753Keys::AirplaneMode => rogcore.toggle_airplane_mode(), + GL753Keys::ScreenToggle => { + rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into()); + } + GL753Keys::TouchPadToggle => { + let mut key = [0u8; 32]; + key[0] = 0x01; + key[3] = 0x070; + rogcore.virt_keys().press(key); + } + GL753Keys::Rog => { + let mut key = [0u8; 32]; + key[0] = 0x01; + key[3] = 0x68; // XF86Tools? F13 + rogcore.virt_keys().press(key); + } + GL753Keys::None => { + if key_buf[0] != 0x5A { + info!("Unmapped key, attempt passthrough: {:X?}", &key_buf[1]); + rogcore.virt_keys().press(key_buf); + } + } + } + Ok(()) + }; + Box::new(function) + } +} + +pub(crate) enum GX502Keys { + Rog = 0x38, + MicToggle = 0x7C, + Fan = 0xAE, + ScreenToggle = 0x35, + ScreenBrightDown = 0x10, + ScreenBrightUp = 0x20, + TouchPadToggle = 0x6b, + Sleep = 0x6C, + AirplaneMode = 0x88, + LedBrightUp = 0xC4, + LedBrightDown = 0xC5, + AuraPrevious = 0xB2, + AuraNext = 0xB3, + None, +} + +impl From for GX502Keys { + fn from(byte: u8) -> Self { + match byte { + 0x38 => GX502Keys::Rog, + 0x7C => GX502Keys::MicToggle, + 0xAE => GX502Keys::Fan, + 0x35 => GX502Keys::ScreenToggle, + 0x10 => GX502Keys::ScreenBrightDown, + 0x20 => GX502Keys::ScreenBrightUp, + 0x6b => GX502Keys::TouchPadToggle, + 0x6C => GX502Keys::Sleep, + 0x88 => GX502Keys::AirplaneMode, + 0xC4 => GX502Keys::LedBrightUp, + 0xC5 => GX502Keys::LedBrightDown, + 0xB2 => GX502Keys::AuraPrevious, + 0xB3 => GX502Keys::AuraNext, + _ => GX502Keys::None, + } + } +} + +enum GL753Keys { + Rog = 0x38, + ScreenToggle = 0x35, + ScreenBrightDown = 0x10, + ScreenBrightUp = 0x20, + TouchPadToggle = 0x6b, + Sleep = 0x6C, + AirplaneMode = 0x88, + LedBrightUp = 0xC4, + LedBrightDown = 0xC5, + None, +} + +impl From for GL753Keys { + fn from(byte: u8) -> Self { + match byte { + 0x38 => GL753Keys::Rog, + 0x35 => GL753Keys::ScreenToggle, + 0x10 => GL753Keys::ScreenBrightDown, + 0x20 => GL753Keys::ScreenBrightUp, + 0x6b => GL753Keys::TouchPadToggle, + 0x6C => GL753Keys::Sleep, + 0x88 => GL753Keys::AirplaneMode, + 0xC4 => GL753Keys::LedBrightUp, + 0xC5 => GL753Keys::LedBrightDown, + _ => GL753Keys::None, + } + } +} diff --git a/src/main.rs b/src/main.rs index 5b059766..37dd5953 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use env_logger::{Builder, Target}; use gumdrop::Options; use log::LevelFilter; -static VERSION: &'static str = "0.6.1"; +static VERSION: &'static str = "0.7.0"; #[derive(Debug, Options)] struct CLIStart { @@ -42,7 +42,7 @@ struct LedModeCommand { #[tokio::main] pub async fn main() -> Result<(), Box> { - let mut builder = Builder::from_env("ROGCORE_LOG"); + let mut builder = Builder::new(); builder.target(Target::Stdout); builder.format_timestamp(None); builder.filter(None, LevelFilter::Info).init(); @@ -55,32 +55,26 @@ pub async fn main() -> Result<(), Box> { println!("Version: {}", VERSION); } - match parsed.command { - Some(Command::LedMode(mode)) => { - if let Some(command) = mode.command { - // Check for special modes here, eg, per-key or multi-zone - match command { - SetAuraBuiltin::MultiStatic(_) => { - let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command); - for arr in byte_arr.iter() { - dbus_led_builtin_write(arr)?; - } - } - _ => { - let mode = <[u8; LED_MSG_LEN]>::from(command); - dbus_led_builtin_write(&mode)?; + if let Some(Command::LedMode(mode)) = parsed.command { + if let Some(command) = mode.command { + // Check for special modes here, eg, per-key or multi-zone + match command { + SetAuraBuiltin::MultiStatic(_) => { + let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command); + for arr in byte_arr.iter() { + dbus_led_builtin_write(arr)?; } } + _ => { + let mode = <[u8; LED_MSG_LEN]>::from(command); + dbus_led_builtin_write(&mode)?; + } } } - None => {} } - match parsed.bright { - Some(brightness) => { - let bytes = aura_brightness_bytes(brightness.level()); - dbus_led_builtin_write(&bytes)?; - } - _ => {} + if let Some(brightness) = parsed.bright { + let bytes = aura_brightness_bytes(brightness.level()); + dbus_led_builtin_write(&bytes)?; } Ok(()) }