From 732295f8b7553f9973ae65dcf6e261e6368201b6 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 15 Apr 2020 17:01:57 +1200 Subject: [PATCH] CLI up --- Cargo.lock | 56 +++++++ Cargo.toml | 3 +- src/aura.rs | 409 ++++++++++++++++++++++++++++++---------------------- src/core.rs | 143 ++++++++++++++++++ src/main.rs | 55 ++++++- 5 files changed, 490 insertions(+), 176 deletions(-) create mode 100644 src/core.rs diff --git a/Cargo.lock b/Cargo.lock index d1bda3d6..064c8ff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "gumdrop" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde" +dependencies = [ + "gumdrop_derive", +] + +[[package]] +name = "gumdrop_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "libc" version = "0.2.68" @@ -92,6 +112,24 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + [[package]] name = "redox_syscall" version = "0.1.56" @@ -108,6 +146,7 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" name = "rog-core" version = "0.1.0" dependencies = [ + "gumdrop", "rusb", ] @@ -122,6 +161,17 @@ dependencies = [ "libusb1-sys", ] +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -140,6 +190,12 @@ dependencies = [ "xattr", ] +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + [[package]] name = "vcpkg" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index c228b010..80f2b2e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors = ["Luke "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] rusb = "0.5" +gumdrop = "0.7" diff --git a/src/aura.rs b/src/aura.rs index afae2c2d..85f248df 100644 --- a/src/aura.rs +++ b/src/aura.rs @@ -1,174 +1,245 @@ -use rusb::{DeviceHandle, Error}; -use std::time::Duration; +use crate::core::LED_MSG_LEN; +use gumdrop::Options; +use std::error::Error; +use std::fmt; +use std::fmt::{Debug, Display}; +use std::str::FromStr; -static LED_MSG_LEN: usize = 17; -pub static LED_SPEED_BYTES: [u8; 3] = [0xe1, 0xeb, 0xf5]; // maps to 1, 2, 3 -static LED_BRIGHT_BYTES: [u8; 5] = [0x5a, 0xba, 0xc5, 0xc4, 0]; // Index 4 = set brightness -static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; -static LED_INIT2: &'static str = "]ASUS Tech.Inc."; // ] == 0x5d -static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; -static LED_INIT4: &'static str = "^ASUS Tech.Inc."; // ^ == 0x5e -static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; - -// `LED_BUILTIN[7]` sets speed from `LED_SPEED_BYTES` -// `LED_BUILTIN[4,5,6]` colours RGB -// `LED_BUILTIN[3]` sets type: -// - 00 = static -// - 01 = breathe (can set two colours) -// - 02 = cycle (through all colours) -// - 03 = rainbow -// - 04 = rain -// - 05 = random keys, red, white, turquoise -// - 06 = pressed keys light up and fade -// - 07 = pressed key emits laser -// - 08 = pressed key emits water ripple -// - 09 = off -// - 0a fast pulse (no speed setting) -// - 0b vertical line racing to right (no speed setting) -// - 0c wider vertical line racing to right (no speed setting) -// `LED_BUILTIN[9]` sets rainbow direction: -// - 0x00 = rightwards -// - 0x01 = leftwards -// - 0x02 = upwards -// - 0x03 = downwards -// `LED_BUILTIN[10,11,12]` 2nd colours RGB -static LED_BUILTIN: [u8; 13] = [ - 0x5d, 0xb3, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, -]; - -// 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]; - -// bytes 0,1 set mode -// bytes 3,4,5 set to on, -// byte 6 increments (starts at 0x00, continues 0x10 to 0xA0) 0-10 << 4 -// byte 7 resets (stays on 10 until byte6 == 0xA0 then flips to 08 in same packet as 0xA0) -// bytes 8-57 are bitfield for keys -static LED_SPECIAL: [u8; 64] = [ - 0x5d, 0xbc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -/// ROG device controller -/// -/// For the GX502GW the LED setup sequence looks like: -/// -/// -` LED_INIT1` -/// - `LED_INIT3` -/// - `LED_INIT4` -/// - `LED_INIT2` -/// - `LED_INIT4` -pub struct RogCore { - handle: DeviceHandle, - initialised: bool, - led_interface_num: u8, - keys_interface_num: u8, +#[derive(PartialEq)] +pub enum AuraError { + ParseMode, + ParseColour, + ParseSpeed, + ParseDirection, } -impl RogCore { - pub fn new() -> Result { - let mut handle = RogCore::get_device(0x0B05, 0x1866)?; - handle.set_active_configuration(0).unwrap_or(()); - - let config = handle.device().config_descriptor(0).unwrap(); - // Interface with outputs - let mut keys_interface_num = 0; - let mut led_interface_num = 0; - for iface in config.interfaces() { - for desc in iface.descriptors() { - for endpoint in desc.endpoint_descriptors() { - if endpoint.address() == 0x83 { - keys_interface_num = desc.interface_number(); - } else if endpoint.address() == 0x81 { - led_interface_num = desc.interface_number(); - } - } - } - } - - handle.set_auto_detach_kernel_driver(true).unwrap(); - handle.set_auto_detach_kernel_driver(true).unwrap(); - - // let iface_out = config - // .interfaces() - // .nth(keys_interface_num as usize) - // .unwrap(); - // let iface_led = config.interfaces().nth(led_interface_num as usize).unwrap(); - - //handle.claim_interface(iface_out.number()).unwrap(); - //handle.claim_interface(iface_led.number()).unwrap(); - - Ok(RogCore { - handle, - initialised: false, - led_interface_num, - keys_interface_num, - }) - } - - fn get_device(vendor: u16, product: u16) -> Result, Error> { - for device in rusb::devices().unwrap().iter() { - let device_desc = device.device_descriptor().unwrap(); - if device_desc.vendor_id() == vendor && device_desc.product_id() == product { - return device.open(); - } - } - Err(Error::NoDevice) - } - - fn aura_write_messages(&mut self, messages: &[Vec]) -> Result<(), Error> { - self.handle.claim_interface(self.led_interface_num)?; - // Declared as a zoomy so that it is hidden - let write = |message: &[u8]| { - self.handle - .write_control(0x21, 0x09, 0x035D, 0, message, Duration::new(0, 5)) - }; - - if !self.initialised { - write(&LED_INIT1)?; - write(LED_INIT2.as_bytes())?; - write(&LED_INIT3)?; - write(LED_INIT4.as_bytes())?; - write(&LED_INIT5)?; - } - - for message in messages { - println!("{:x?}", &message); - write(message)?; - write(&LED_SET)?; - //write(&LED_APPLY)?; - } - - self.handle.release_interface(self.led_interface_num)?; - - Ok(()) - } - - pub fn aura_set_brightness(&mut self, brightness: u8) -> Result<(), Error> { - let mut bright = LED_BRIGHT_BYTES.to_vec(); - bright[4] = brightness; - let messages = [bright]; - self.aura_write_messages(&messages) - } - - pub fn aura_set_colour(&mut self, rgb: (u8, u8, u8)) -> Result<(), Error> { - let mut colour = LED_BUILTIN.to_vec(); - colour[3] = 0; // static - colour[4] = rgb.0; - colour[5] = rgb.1; - colour[6] = rgb.2; - let messages = [colour]; - self.aura_write_messages(&messages) - } - - pub fn aura_set_rainbow(&mut self, speed: u8) -> Result<(), Error> { - let mut rainbow = LED_BUILTIN.to_vec(); - rainbow[3] = 3; - rainbow[7] = speed; - let messages = [rainbow]; - self.aura_write_messages(&messages) +impl Debug for AuraError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.description(), f) + } +} + +impl Display for AuraError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.description(), f) + } +} + +impl Error for AuraError { + fn description(&self) -> &str { + match self { + AuraError::ParseMode => "incorrect mode specified", + AuraError::ParseColour => "could not parse colour", + AuraError::ParseSpeed => "could not parse speed", + AuraError::ParseDirection => "could not parse direction", + } + } +} + +#[derive(Default, Debug, PartialEq)] +pub struct Colour(u8, u8, u8); + +impl FromStr for Colour { + type Err = AuraError; + + fn from_str(s: &str) -> Result { + if s.len() < 6 { + return Err(AuraError::ParseColour); + } + let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?; + let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?; + let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?; + Ok(Colour(r, g, b)) + } +} + +#[derive(Debug, PartialEq)] +pub enum Speed { + Slow = 0xe1, + Medium = 0xeb, + Fast = 0xf5, +} +impl Default for Speed { + fn default() -> Self { + Speed::Slow + } +} +impl FromStr for Speed { + type Err = AuraError; + + fn from_str(s: &str) -> Result { + let s = s.to_lowercase(); + match s.as_str() { + "slow" => Ok(Speed::Slow), + "medium" => Ok(Speed::Medium), + "fast" => Ok(Speed::Fast), + _ => Err(AuraError::ParseSpeed), + } + } +} + +/// Used for Rainbow mode. +/// +/// Enum corresponds to the required integer value +#[derive(Debug, PartialEq)] +pub enum Direction { + Right, + Left, + Up, + Down, +} +impl Default for Direction { + fn default() -> Self { + Direction::Right + } +} +impl FromStr for Direction { + type Err = AuraError; + + fn from_str(s: &str) -> Result { + let s = s.to_lowercase(); + match s.as_str() { + "right" => Ok(Direction::Right), + "up" => Ok(Direction::Up), + "down" => Ok(Direction::Down), + "left" => Ok(Direction::Left), + _ => Err(AuraError::ParseDirection), + } + } +} + +/// Byte value for setting the built-in mode. +/// +/// Enum corresponds to the required integer value +#[derive(Debug, PartialEq)] +pub enum ModeByte { + Stable, // colour1 + Breathe, // colour1, colour2, speed + Cycle, // speed + Rainbow, // speed, direction + Rain, // colour1, speed + Random, // speed + Highlight, // colour1, speed + Laser, // colour1, speed + Ripple, // colour1, speed + Off, // none + Pulse, // colour1 + LineRace, // colour1 + WideLineRace, // colour1 +} +impl Default for ModeByte { + fn default() -> Self { + ModeByte::Stable + } +} +impl FromStr for ModeByte { + type Err = AuraError; + + fn from_str(s: &str) -> Result { + match s { + "stable" => Ok(ModeByte::Stable), + "breathe" => Ok(ModeByte::Breathe), + "cycle" => Ok(ModeByte::Cycle), + "rainbow" => Ok(ModeByte::Rainbow), + "rain" => Ok(ModeByte::Rain), + "random" => Ok(ModeByte::Random), + "highlight" => Ok(ModeByte::Highlight), + "laser" => Ok(ModeByte::Laser), + "ripple" => Ok(ModeByte::Ripple), + "off" => Ok(ModeByte::Off), + "pulse" => Ok(ModeByte::Pulse), + "linerace" => Ok(ModeByte::LineRace), + "widelinerace" => Ok(ModeByte::WideLineRace), + _ => Err(AuraError::ParseMode), + } + } +} + +#[derive(Debug, PartialEq, Options)] +pub struct BuiltInMode { + #[options(help = "selects from the built-in keyboard modes")] + mode: ModeByte, + #[options(help = "set the first colour if a mode uses it, must be in hex: ffffff")] + colour1: Colour, + #[options(help = "set the second colour if a mode uses it, must be in hex: ffffff")] + colour2: Colour, + #[options(help = "set the speed of an effect if a mode uses it")] + speed: Speed, + #[options(help = "set the direction of an effect if a mode uses it")] + direction: Direction, +} + +impl Default for BuiltInMode { + fn default() -> BuiltInMode { + BuiltInMode { + mode: ModeByte::Stable, + colour1: Colour(0xff, 0x00, 0x00), + colour2: Colour(0x00, 0x00, 0x00), + speed: Speed::Slow, + direction: Direction::Right, + } + } +} + +/// Packet Data: +/// +/// ``` +/// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| +/// |---|---|---|---|---|---|---|---|---|---|---|---|---| +/// |5d |b3 |03 |00 |ff |00 |00 |00 |00 |00 |00 |ff |00 | +/// ``` +/// +/// Bytes 1 and 2 should always be 5d, b3 +/// +/// Byte 3 sets the mode type: +/// - 00 = static +/// - 01 = breathe (can set two colours) +/// - 02 = cycle (through all colours) +/// - 03 = rainbow +/// - 04 = rain +/// - 05 = random keys, red, white, turquoise +/// - 06 = pressed keys light up and fade +/// - 07 = pressed key emits laser +/// - 08 = pressed key emits water ripple +/// - 09 = off +/// - 0a fast pulse (no speed setting) +/// - 0b vertical line racing to right (no speed setting) +/// - 0c wider vertical line racing to right (no speed setting) +/// +/// Bytes 4, 5, 6 are Red, Green, Blue +/// +/// Byte 7 sets speed from +/// - 0x00 = Off +/// - 0xe1 = Slow +/// - 0xeb = Medium +/// - 0xf5 = Fast +/// +/// Byte 8 sets rainbow direction: +/// - 0x00 = rightwards +/// - 0x01 = leftwards +/// - 0x02 = upwards +/// - 0x03 = downwards +/// +/// Bytes 10, 11, 12 are Red, Green, Blue for second colour if mode supports it +pub struct ModeMessage(pub [u8; LED_MSG_LEN]); + +impl From for ModeMessage { + fn from(mode: BuiltInMode) -> Self { + let mut msg = [0u8; LED_MSG_LEN]; + msg[0] = 0x5d; + msg[1] = 0xb3; + msg[3] = mode.mode as u8; + msg[4] = mode.colour1.0; + msg[5] = mode.colour1.1; + msg[6] = mode.colour1.2; + msg[7] = mode.speed as u8; + msg[8] = mode.direction as u8; + msg[10] = mode.colour2.0; + msg[11] = mode.colour2.1; + msg[12] = mode.colour2.2; + + ModeMessage(msg) } } diff --git a/src/core.rs b/src/core.rs new file mode 100644 index 00000000..477db6f6 --- /dev/null +++ b/src/core.rs @@ -0,0 +1,143 @@ +use crate::aura::ModeMessage; +use rusb::{DeviceHandle, Error}; +use std::time::Duration; + +pub const LED_MSG_LEN: usize = 17; +pub static LED_SPEED_BYTES: [u8; 3] = [0xe1, 0xeb, 0xf5]; // maps to 1, 2, 3 +static LED_BRIGHT_BYTES: [u8; 5] = [0x5a, 0xba, 0xc5, 0xc4, 0]; // Index 4 = set brightness +static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; +static LED_INIT2: &'static str = "]ASUS Tech.Inc."; // ] == 0x5d +static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; +static LED_INIT4: &'static str = "^ASUS Tech.Inc."; // ^ == 0x5e +static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; + +static LED_BUILTIN: [u8; 13] = [ + 0x5d, 0xb3, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, +]; + +// 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]; + +// bytes 0,1 set mode +// bytes 3,4,5 set to on, +// byte 6 increments (starts at 0x00, continues 0x10 to 0xA0) 0-10 << 4 +// byte 7 resets (stays on 10 until byte6 == 0xA0 then flips to 08 in same packet as 0xA0) +// bytes 8-57 are bitfield for keys +static LED_SPECIAL: [u8; 64] = [ + 0x5d, 0xbc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; + +/// ROG device controller +/// +/// For the GX502GW the LED setup sequence looks like: +/// +/// -` LED_INIT1` +/// - `LED_INIT3` +/// - `LED_INIT4` +/// - `LED_INIT2` +/// - `LED_INIT4` +pub struct RogCore { + handle: DeviceHandle, + initialised: bool, + led_interface_num: u8, + keys_interface_num: u8, +} + +impl RogCore { + pub fn new() -> Result { + let mut handle = RogCore::get_device(0x0B05, 0x1866)?; + handle.set_active_configuration(0).unwrap_or(()); + + let config = handle.device().config_descriptor(0).unwrap(); + // Interface with outputs + let mut keys_interface_num = 0; + let mut led_interface_num = 0; + for iface in config.interfaces() { + for desc in iface.descriptors() { + for endpoint in desc.endpoint_descriptors() { + if endpoint.address() == 0x83 { + keys_interface_num = desc.interface_number(); + } else if endpoint.address() == 0x81 { + led_interface_num = desc.interface_number(); + } + } + } + } + + handle.set_auto_detach_kernel_driver(true).unwrap(); + handle.set_auto_detach_kernel_driver(true).unwrap(); + + // let iface_out = config + // .interfaces() + // .nth(keys_interface_num as usize) + // .unwrap(); + // let iface_led = config.interfaces().nth(led_interface_num as usize).unwrap(); + + //handle.claim_interface(iface_out.number()).unwrap(); + //handle.claim_interface(iface_led.number()).unwrap(); + + Ok(RogCore { + handle, + initialised: false, + led_interface_num, + keys_interface_num, + }) + } + + fn get_device(vendor: u16, product: u16) -> Result, Error> { + for device in rusb::devices().unwrap().iter() { + let device_desc = device.device_descriptor().unwrap(); + if device_desc.vendor_id() == vendor && device_desc.product_id() == product { + return device.open(); + } + } + Err(Error::NoDevice) + } + + fn aura_write_messages(&mut self, messages: &[[u8; LED_MSG_LEN]]) -> Result<(), Error> { + self.handle.claim_interface(self.led_interface_num)?; + // Declared as a zoomy so that it is hidden + let write = |message: &[u8]| { + self.handle + .write_control(0x21, 0x09, 0x035D, 0, message, Duration::new(0, 5)) + }; + + if !self.initialised { + write(&LED_INIT1)?; + write(LED_INIT2.as_bytes())?; + write(&LED_INIT3)?; + write(LED_INIT4.as_bytes())?; + write(&LED_INIT5)?; + } + + for message in messages { + println!("{:x?}", &message); + write(message)?; + write(&LED_SET)?; + //write(&LED_APPLY)?; + } + + self.handle.release_interface(self.led_interface_num)?; + Ok(()) + } + + pub fn aura_set_brightness(&mut self, brightness: u8) -> Result<(), Error> { + let mut bright = [0u8; LED_MSG_LEN]; + bright[0] = 0x5a; + bright[1] = 0xba; + bright[2] = 0xc5; + bright[3] = 0xc4; + bright[4] = brightness; + let messages = [bright]; + self.aura_write_messages(&messages) + } + + pub fn aura_set_mode(&mut self, mode: ModeMessage) -> Result<(), Error> { + let messages = [mode.0]; + self.aura_write_messages(&messages) + } +} diff --git a/src/main.rs b/src/main.rs index b249c804..90917dea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,57 @@ -extern crate rusb; mod aura; +mod core; -use aura::RogCore; +use crate::aura::{BuiltInMode, ModeMessage}; +use crate::core::RogCore; +use gumdrop::{Options, ParsingStyle}; +use std::env; + +#[derive(Debug, Options)] +struct CLIStart { + #[options(command, required)] + command: Option, +} + +#[derive(Debug, Options)] +enum Command { + #[options(help = "show help for a command (eg: help aura)")] + Help(FreeOptions), + #[options(help = "Set the keyboard lighting from built-in modes")] + LedMode(BuiltInMode), +} + +#[derive(Debug, Options)] +struct FreeOptions { + #[options(free)] + free: Vec, +} fn main() -> Result<(), Box> { - let mut core = RogCore::new()?; - core.aura_set_brightness(3)?; - core.aura_set_colour((0xff, 0x00, 0x00))?; + let args: Vec = env::args().collect(); + match CLIStart::parse_args(&args[1..], ParsingStyle::AllOptions) { + Ok(okk) => { + dbg!(&okk); + match okk.command { + Some(Command::Help(help)) => { + if help.free.contains(&"aura".to_string()) { + println!("\n{}", BuiltInMode::usage()) + } + } + Some(Command::LedMode(aura)) => { + let mut core = RogCore::new()?; + let mode = ModeMessage::from(aura); + core.aura_set_mode(mode)?; + } + None => {} + } + } + Err(err) => { + println!("\n{}", err); + println!("\nUsage:\n{}", Command::usage()); + } + } + + //core.aura_set_brightness(3)?; // core.test_builtins(aura::LED_SPEED_BYTES[2])?;