Code cleanup

This commit is contained in:
Luke
2020-04-29 14:08:22 +12:00
parent f818ffa191
commit 4e78a5dbdd
8 changed files with 385 additions and 442 deletions

3
Cargo.lock generated
View File

@@ -660,9 +660,8 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
[[package]] [[package]]
name = "rog-daemon" name = "rog-daemon"
version = "0.6.1" version = "0.7.0"
dependencies = [ dependencies = [
"aho-corasick",
"dbus", "dbus",
"dbus-tokio", "dbus-tokio",
"env_logger", "env_logger",

View File

@@ -1,7 +1,12 @@
[package] [package]
name = "rog-daemon" name = "rog-daemon"
version = "0.6.1" version = "0.7.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
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" edition = "2018"
[lib] [lib]
@@ -14,25 +19,47 @@ path = "src/main.rs"
[dependencies] [dependencies]
rusb = "^0.5.5" rusb = "^0.5.5"
# cli crate
# cli and logging
gumdrop = "^0.8.0" gumdrop = "^0.8.0"
log = "^0.4.8" log = "^0.4.8"
env_logger = "^0.7.1" env_logger = "^0.7.1"
# async # async
dbus = { version = "^0.8.2", features = ["futures"] } dbus = { version = "^0.8.2", features = ["futures"] }
dbus-tokio = "^0.5.1" dbus-tokio = "^0.5.1"
tokio = { version = "0.2.4", features = ["rt-threaded", "macros"] } tokio = { version = "0.2.4", features = ["rt-threaded", "macros"] }
# serialisation # serialisation
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
toml = "0.5" 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 # cpu power management
intel-pstate = { git = "https://github.com/flukejones/intel-pstate" } 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 # virtualisation of HID, mainly for outputting consumer key codes
uhid-virt = "^0.0.4" uhid-virt = "^0.0.4"
#keycode = "0.3" #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"

View File

@@ -6,7 +6,6 @@ use crate::{
error::AuraError, error::AuraError,
virt_device::VirtKeys, virt_device::VirtKeys,
}; };
use aho_corasick::AhoCorasick;
use gumdrop::Options; use gumdrop::Options;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use rusb::DeviceHandle; use rusb::DeviceHandle;
@@ -50,12 +49,7 @@ pub(crate) struct RogCore {
} }
impl RogCore { impl RogCore {
pub(crate) fn new( pub(crate) fn new(vendor: u16, product: u16, led_endpoint: u8) -> Result<RogCore, AuraError> {
vendor: u16,
product: u16,
led_endpoint: u8,
key_endpoint: u8,
) -> Result<RogCore, AuraError> {
let mut dev_handle = RogCore::get_device(vendor, product)?; let mut dev_handle = RogCore::get_device(vendor, product)?;
dev_handle.set_active_configuration(0).unwrap_or(()); dev_handle.set_active_configuration(0).unwrap_or(());
@@ -65,11 +59,12 @@ impl RogCore {
for iface in dev_config.interfaces() { for iface in dev_config.interfaces() {
for desc in iface.descriptors() { for desc in iface.descriptors() {
for endpoint in desc.endpoint_descriptors() { for endpoint in desc.endpoint_descriptors() {
if endpoint.address() == key_endpoint { if endpoint.address() == led_endpoint {
debug!("INTERVAL: {:?}", endpoint.interval()); info!("INTERVAL: {:?}", endpoint.interval());
debug!("MAX: {:?}", endpoint.max_packet_size()); info!("MAX_PKT_SIZE: {:?}", endpoint.max_packet_size());
debug!("SYNC: {:?}", endpoint.sync_type()); info!("SYNC: {:?}", endpoint.sync_type());
debug!("TRANSFER_TYPE: {:?}", endpoint.transfer_type()); info!("TRANSFER_TYPE: {:?}", endpoint.transfer_type());
info!("ENDPOINT: {:X?}", endpoint.address());
interface = desc.interface_number(); interface = desc.interface_number();
break; break;
} }
@@ -110,7 +105,7 @@ impl RogCore {
}; };
let mut file = OpenOptions::new().write(true).open(path)?; 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))?; self.set_pstate_for_fan_mode(FanLevel::from(self.config.fan_mode))?;
info!("Reloaded last saved settings"); info!("Reloaded last saved settings");
Ok(()) Ok(())
@@ -176,6 +171,26 @@ impl RogCore {
Ok(()) 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<rusb::GlobalContext>,
endpoint: u8,
effect: Vec<Vec<u8>>,
) -> 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( pub(crate) fn aura_set_and_save(
&mut self, &mut self,
supported_modes: &[BuiltInModeByte], supported_modes: &[BuiltInModeByte],
@@ -205,9 +220,10 @@ impl RogCore {
if bright < max_bright { if bright < max_bright {
bright += 1; bright += 1;
self.config.brightness = bright; 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(()) Ok(())
} }
@@ -220,9 +236,10 @@ impl RogCore {
if bright > min_bright { if bright > min_bright {
bright -= 1; bright -= 1;
self.config.brightness = bright; 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(()) Ok(())
} }
@@ -300,7 +317,7 @@ impl RogCore {
n = 0; n = 0;
} }
info!("Fan mode stepped to: {:#?}", FanLevel::from(n)); 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.set_pstate_for_fan_mode(FanLevel::from(n))?;
self.config.fan_mode = n; self.config.fan_mode = n;
self.config.write(); self.config.write();
@@ -384,26 +401,26 @@ impl RogCore {
match Command::new("rfkill").arg("list").output() { match Command::new("rfkill").arg("list").output() {
Ok(output) => { Ok(output) => {
if output.status.success() { if output.status.success() {
let patterns = &["yes"]; if let Ok(out) = String::from_utf8(output.stdout) {
let ac = AhoCorasick::new(patterns); if out.contains(": yes") {
if ac.earliest_find(output.stdout).is_some() { Command::new("rfkill")
Command::new("rfkill") .arg("unblock")
.arg("unblock") .arg("all")
.arg("all") .spawn()
.spawn() .map_or_else(
.map_or_else( |err| warn!("Could not unblock rf devices: {}", err),
|err| warn!("Could not unblock rf devices: {}", err), |_| {},
|_| {}, );
); } else {
} else { Command::new("rfkill")
let _ = Command::new("rfkill") .arg("block")
.arg("block") .arg("all")
.arg("all") .spawn()
.spawn() .map_or_else(
.map_or_else( |err| warn!("Could not block rf devices: {}", err),
|err| warn!("Could not block rf devices: {}", err), |_| {},
|_| {}, );
); }
} }
} else { } else {
warn!("Could not list rf devices"); warn!("Could not list rf devices");

View File

@@ -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_PATH: &'static str = "/org/rogcore/Daemon";
pub static DBUS_IFACE: &'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::{ use dbus::{
nonblock::Process, nonblock::Process,
tree::{Factory, MTSync, Method, MethodErr, Tree}, tree::{Factory, MTSync, Method, MethodErr, Tree},
@@ -87,6 +90,8 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
let supported = Vec::from(laptop.supported_modes()); let supported = Vec::from(laptop.supported_modes());
// When any action occurs this time is reset // When any action occurs this time is reset
let mut time_mark = Instant::now(); let mut time_mark = Instant::now();
let laptop_actions = laptop.get_runner();
loop { loop {
connection.process_all(); connection.process_all();
@@ -110,7 +115,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
if let Ok(mut lock) = key_buf.try_lock() { if let Ok(mut lock) = key_buf.try_lock() {
if let Some(bytes) = *lock { if let Some(bytes) = *lock {
// this takes at least 10ms per colour block // this takes at least 10ms per colour block
match laptop.run(&mut rogcore, bytes) { match laptop_actions(&mut rogcore, bytes) {
Ok(_) => {} Ok(_) => {}
Err(err) => { Err(err) => {
error!("{:?}", err); error!("{:?}", err);

View File

@@ -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<u8> 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,
}
}
}

View File

@@ -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<u8> 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,
}
}
}

View File

@@ -2,53 +2,68 @@ use crate::aura::BuiltInModeByte;
use crate::core::RogCore; use crate::core::RogCore;
use crate::error::AuraError; use crate::error::AuraError;
//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; //use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState};
use log::info; use crate::virt_device::ConsumerKeys;
use log::{info, warn};
// GL753VE == 0x1854, 4 zone keyboard pub(crate) fn match_laptop() -> LaptopBase {
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<dyn Laptop> {
for device in rusb::devices().unwrap().iter() { for device in rusb::devices().unwrap().iter() {
let device_desc = device.device_descriptor().unwrap(); let device_desc = device.device_descriptor().unwrap();
if device_desc.vendor_id() == 0x0b05 { if device_desc.vendor_id() == 0x0b05 {
match device_desc.product_id() { match device_desc.product_id() {
0x1869 | 0x1866 => { 0x1869 | 0x1866 => {
info!("Found GX502 or similar"); 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 => { 0x1854 => {
info!("Found GL753 or similar"); 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"); 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 /// All laptop models should implement this trait. The role of a `Laptop` is to
@@ -63,13 +78,235 @@ pub(crate) fn match_laptop() -> Box<dyn Laptop> {
/// If using the `keycode` crate to build keyboard input, the report must be prefixed /// If using the `keycode` crate to build keyboard input, the report must be prefixed
/// with the report ID (usually `0x01` for the virtual keyboard). /// with the report ID (usually `0x01` for the virtual keyboard).
pub(crate) trait Laptop { pub(crate) trait Laptop {
fn board_name(&self) -> &str; fn get_runner(&self) -> Box<dyn Fn(&mut RogCore, [u8; 32]) -> Result<(), AuraError>>;
fn prod_family(&self) -> &str;
fn run(&self, core: &mut RogCore, key_buf: [u8; 32]) -> Result<(), AuraError>;
fn led_endpoint(&self) -> u8; fn led_endpoint(&self) -> u8;
fn key_endpoint(&self) -> u8; fn key_endpoint(&self) -> u8;
fn key_filter(&self) -> &[u8]; fn key_filter(&self) -> &[u8];
fn usb_vendor(&self) -> u16; fn usb_vendor(&self) -> u16;
fn usb_product(&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]; 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<u8>,
min_led_bright: u8,
max_led_bright: u8,
led_endpoint: u8,
key_endpoint: u8,
supported_modes: Vec<BuiltInModeByte>,
//backlight: Backlight,
}
impl Laptop for LaptopBase {
fn get_runner(&self) -> Box<LaptopRunner> {
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<LaptopRunner> {
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<LaptopRunner> {
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<u8> 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<u8> 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,
}
}
}

View File

@@ -10,7 +10,7 @@ use env_logger::{Builder, Target};
use gumdrop::Options; use gumdrop::Options;
use log::LevelFilter; use log::LevelFilter;
static VERSION: &'static str = "0.6.1"; static VERSION: &'static str = "0.7.0";
#[derive(Debug, Options)] #[derive(Debug, Options)]
struct CLIStart { struct CLIStart {
@@ -42,7 +42,7 @@ struct LedModeCommand {
#[tokio::main] #[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> { pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut builder = Builder::from_env("ROGCORE_LOG"); let mut builder = Builder::new();
builder.target(Target::Stdout); builder.target(Target::Stdout);
builder.format_timestamp(None); builder.format_timestamp(None);
builder.filter(None, LevelFilter::Info).init(); builder.filter(None, LevelFilter::Info).init();
@@ -55,32 +55,26 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Version: {}", VERSION); println!("Version: {}", VERSION);
} }
match parsed.command { if let Some(Command::LedMode(mode)) = parsed.command {
Some(Command::LedMode(mode)) => { if let Some(command) = mode.command {
if let Some(command) = mode.command { // Check for special modes here, eg, per-key or multi-zone
// Check for special modes here, eg, per-key or multi-zone match command {
match command { SetAuraBuiltin::MultiStatic(_) => {
SetAuraBuiltin::MultiStatic(_) => { let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command);
let byte_arr = <[[u8; LED_MSG_LEN]; 4]>::from(command); for arr in byte_arr.iter() {
for arr in byte_arr.iter() { dbus_led_builtin_write(arr)?;
dbus_led_builtin_write(arr)?;
}
}
_ => {
let mode = <[u8; LED_MSG_LEN]>::from(command);
dbus_led_builtin_write(&mode)?;
} }
} }
_ => {
let mode = <[u8; LED_MSG_LEN]>::from(command);
dbus_led_builtin_write(&mode)?;
}
} }
} }
None => {}
} }
match parsed.bright { if let Some(brightness) = parsed.bright {
Some(brightness) => { let bytes = aura_brightness_bytes(brightness.level());
let bytes = aura_brightness_bytes(brightness.level()); dbus_led_builtin_write(&bytes)?;
dbus_led_builtin_write(&bytes)?;
}
_ => {}
} }
Ok(()) Ok(())
} }