diff --git a/asusctl/src/aura_cli.rs b/asusctl/src/aura_cli.rs index 88a5c219..a0449c8b 100644 --- a/asusctl/src/aura_cli.rs +++ b/asusctl/src/aura_cli.rs @@ -50,6 +50,12 @@ pub struct SingleSpeed { help: bool, #[options(no_long, meta = "WORD", help = "set the speed: low, med, high")] pub speed: Speed, + #[options( + no_long, + meta = "", + help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left" + )] + pub zone: AuraZone, } #[derive(Debug, Clone, Options, Default)] pub struct SingleSpeedDirection { @@ -59,6 +65,12 @@ pub struct SingleSpeedDirection { pub direction: Direction, #[options(no_long, meta = "", help = "set the speed: low, med, high")] pub speed: Speed, + #[options( + no_long, + meta = "", + help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left" + )] + pub zone: AuraZone, } #[derive(Debug, Clone, Default, Options)] @@ -67,6 +79,12 @@ pub struct SingleColour { help: bool, #[options(no_long, meta = "", help = "set the RGB value e.g, ff00ff")] pub colour: Colour, + #[options( + no_long, + meta = "", + help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left" + )] + pub zone: AuraZone, } #[derive(Debug, Clone, Default, Options)] @@ -77,6 +95,12 @@ pub struct SingleColourSpeed { pub colour: Colour, #[options(no_long, meta = "", help = "set the speed: low, med, high")] pub speed: Speed, + #[options( + no_long, + meta = "", + help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left" + )] + pub zone: AuraZone, } #[derive(Debug, Clone, Options, Default)] @@ -89,10 +113,16 @@ pub struct TwoColourSpeed { pub colour2: Colour, #[options(no_long, meta = "", help = "set the speed: low, med, high")] pub speed: Speed, + #[options( + no_long, + meta = "", + help = "set the zone for this effect e.g, 0, 1, one, logo, lightbar-left" + )] + pub zone: AuraZone, } #[derive(Debug, Clone, Default, Options)] -pub struct MultiColour { +pub struct MultiZone { #[options(help = "print help message")] help: bool, #[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")] @@ -152,10 +182,6 @@ pub enum SetAuraBuiltin { Comet(SingleColour), #[options(help = "set a wide vertical line zooming from left")] Flash(SingleColour), - #[options(help = "4-zone multi-colour")] - MultiStatic(MultiColour), - #[options(help = "4-zone multi-colour breathing")] - MultiBreathe(MultiColourSpeed), } impl Default for SetAuraBuiltin { @@ -168,6 +194,7 @@ impl From<&SingleColour> for AuraEffect { fn from(aura: &SingleColour) -> Self { Self { colour1: aura.colour, + zone: aura.zone, ..Default::default() } } @@ -177,6 +204,7 @@ impl From<&SingleSpeed> for AuraEffect { fn from(aura: &SingleSpeed) -> Self { Self { speed: aura.speed, + zone: aura.zone, ..Default::default() } } @@ -187,6 +215,7 @@ impl From<&SingleColourSpeed> for AuraEffect { Self { colour1: aura.colour, speed: aura.speed, + zone: aura.zone, ..Default::default() } } @@ -197,6 +226,7 @@ impl From<&TwoColourSpeed> for AuraEffect { Self { colour1: aura.colour, colour2: aura.colour2, + zone: aura.zone, ..Default::default() } } @@ -207,6 +237,7 @@ impl From<&SingleSpeedDirection> for AuraEffect { Self { speed: aura.speed, direction: aura.direction, + zone: aura.zone, ..Default::default() } } @@ -279,51 +310,3 @@ impl From<&SetAuraBuiltin> for AuraEffect { } } } - -impl From<&SetAuraBuiltin> for Vec { - fn from(aura: &SetAuraBuiltin) -> Vec { - let mut zones = vec![AuraEffect::default(); 4]; - match aura { - SetAuraBuiltin::MultiStatic(data) => { - zones[0].mode = AuraModeNum::Static; - zones[0].zone = AuraZone::KeyOne; - zones[0].colour1 = data.colour1; - - zones[1].mode = AuraModeNum::Static; - zones[1].zone = AuraZone::KeyTwo; - zones[1].colour1 = data.colour2; - - zones[2].mode = AuraModeNum::Static; - zones[2].zone = AuraZone::KeyThree; - zones[2].colour1 = data.colour3; - - zones[3].mode = AuraModeNum::Static; - zones[3].zone = AuraZone::KeyFour; - zones[3].colour1 = data.colour4; - } - SetAuraBuiltin::MultiBreathe(data) => { - zones[0].mode = AuraModeNum::Breathe; - zones[0].zone = AuraZone::KeyOne; - zones[0].colour1 = data.colour1; - zones[0].speed = data.speed; - - zones[1].mode = AuraModeNum::Breathe; - zones[1].zone = AuraZone::KeyTwo; - zones[1].colour1 = data.colour2; - zones[1].speed = data.speed; - - zones[2].mode = AuraModeNum::Breathe; - zones[2].zone = AuraZone::KeyThree; - zones[2].colour1 = data.colour3; - zones[2].speed = data.speed; - - zones[3].mode = AuraModeNum::Breathe; - zones[3].zone = AuraZone::KeyFour; - zones[3].colour1 = data.colour4; - zones[3].speed = data.speed; - } - _ => {} - } - zones - } -} diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index fe0313c5..adf39e07 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -16,7 +16,7 @@ use rog_supported::{ RogBiosSupportedFunctions, }; -use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; +use crate::aura_cli::LedBrightness; use crate::cli_opts::*; mod anime_cli; @@ -365,7 +365,7 @@ fn handle_led_mode( return true; } } - if supported.multizone_led_mode && command.trim().starts_with("multi") { + if !supported.multizone_led_mode.is_empty() && command.trim().starts_with("multi") { return true; } false @@ -391,18 +391,9 @@ fn handle_led_mode( println!("{}", mode.self_usage()); return Ok(()); } - match mode { - SetAuraBuiltin::MultiStatic(_) | SetAuraBuiltin::MultiBreathe(_) => { - let zones = >::from(mode); - for eff in zones { - dbus.proxies().led().set_led_mode(&eff)? - } - } - _ => dbus - .proxies() - .led() - .set_led_mode(&::from(mode))?, - } + dbus.proxies() + .led() + .set_led_mode(&::from(mode))?; } if let Some(enable) = mode.boot_enable { diff --git a/daemon/src/laptops.rs b/daemon/src/laptops.rs index 3f20a720..0c195a7f 100644 --- a/daemon/src/laptops.rs +++ b/daemon/src/laptops.rs @@ -1,5 +1,5 @@ use log::{info, warn}; -use rog_aura::AuraModeNum; +use rog_aura::{AuraModeNum, AuraZone}; use serde_derive::{Deserialize, Serialize}; use std::fs::OpenOptions; use std::io::Read; @@ -37,12 +37,13 @@ struct LedSupportFile { led_data: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +#[serde(default)] pub struct LaptopLedData { pub prod_family: String, pub board_names: Vec, pub standard: Vec, - pub multizone: bool, + pub multizone: Vec, pub per_key: bool, } @@ -62,7 +63,7 @@ impl LaptopLedData { prod_family, board_names: vec![board_name], standard: vec![], - multizone: false, + multizone: vec![], per_key: false, } } @@ -101,3 +102,35 @@ impl LedSupportFile { None } } + +#[cfg(test)] +mod tests { + use std::{fs::OpenOptions, io::Read, path::PathBuf}; + + use super::LaptopLedData; + use rog_aura::{AuraModeNum, AuraZone}; + + #[test] + fn check_data_parse() { + let led = LaptopLedData { + prod_family: "Test".to_owned(), + board_names: vec!["Test".to_owned()], + standard: vec![AuraModeNum::Static], + multizone: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft], + per_key: false, + }; + + let toml = toml::to_string_pretty(&led).unwrap(); + println!("{toml}"); + + let mut data = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + data.push("../data/asusd-ledmodes.toml"); + + let mut file = OpenOptions::new().read(true).open(&data).unwrap(); + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + + let x = toml::to_string_pretty(&buf).unwrap(); + println!("{x}"); + } +} diff --git a/data/asusd-ledmodes.toml b/data/asusd-ledmodes.toml index 58a0f5b6..e0c9e896 100644 --- a/data/asusd-ledmodes.toml +++ b/data/asusd-ledmodes.toml @@ -2,105 +2,112 @@ prod_family = "Zephyrus S" board_names = ["GX502", "GX701", "G531", "GL531", "G532"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "Zephyrus M" board_names = ["GU502GV"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "Zephyrus M" board_names = ["GM501GS"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] per_key = false [[led_data]] prod_family = "ROG Zephyrus M15" board_names = ["GU502LW", "GU502LV"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "ROG Zephyrus M15" board_names = ["GU502LU"] standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "Zephyrus" board_names = ["GM501GM", "GX531"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] per_key = false [[led_data]] prod_family = "ROG Strix" board_names = ["G531GW", "G533QR", "G533QS", "G733QS", "G733QR", "G513QR", "G713QR", "G513QM"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "ROG Strix" board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] per_key = false [[led_data]] prod_family = "ROG Strix" board_names = ["G512LI", "G712LI", "G531GD"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "Strix" board_names = ["G731GV", "G731GW", "G531GV"] standard = ["Static", "Breathe", "Strobe", "Rainbow"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] +per_key = false + +[[led_data]] +prod_family = "Strix" +board_names = ["GL504G"] +standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] +multizone = ["Key1", "Key2", "Key3", "Key4", "Logo", "BarLeft", "BarRight"] per_key = false [[led_data]] prod_family = "Strix" board_names = ["G731GT", "G731GU", "G531GT", "G531GU"] standard = ["Static", "Breathe", "Strobe", "Rainbow"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "Strix Scar" board_names = ["G531", "G731"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] per_key = true [[led_data]] prod_family = "ROG" board_names = ["GL553VE"] standard = ["Static", "Breathe", "Strobe"] -multizone = true +multizone = ["Key1", "Key2", "Key3", "Key4"] per_key = false [[led_data]] prod_family = "ROG Zephyrus G14" board_names = ["GA401Q"] standard = ["Static", "Breathe", "Pulse"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "ROG Zephyrus G14" board_names = ["GA402R"] standard = ["Static", "Breathe", "Pulse", "Rainbow"] -multizone = false +multizone = [] per_key = false # GA503QE at higher priority (first match) than GA503Q @@ -108,40 +115,40 @@ per_key = false prod_family = "ROG Zephyrus G15" board_names = ["GA503QE"] standard = ["Static", "Breathe", "Pulse"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "ROG Zephyrus G15" board_names = ["GA503Q", "GA503R"] standard = ["Static", "Breathe", "Pulse", "Rainbow", "Strobe"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "ROG Zephyrus" board_names = ["GX550L"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "ROG Zephyrus Duo 15 SE" board_names = ["GX551Q"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = false +multizone = [] per_key = true [[led_data]] prod_family = "ROG Flow X13" board_names = ["GV301QH", "GV301QE"] standard = ["Static", "Breathe", "Pulse"] -multizone = false +multizone = [] per_key = false [[led_data]] prod_family = "ROG Strix" board_names = ["G513IC"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = false +multizone = [] per_key = false diff --git a/rog-aura/src/builtin_modes.rs b/rog-aura/src/builtin_modes.rs index 55422236..c4550dfa 100644 --- a/rog-aura/src/builtin_modes.rs +++ b/rog-aura/src/builtin_modes.rs @@ -148,6 +148,26 @@ pub enum AuraModeNum { Flash = 12, } +impl From for String { + fn from(mode: AuraModeNum) -> Self { + match mode { + AuraModeNum::Static => "Static", + AuraModeNum::Breathe => "Breathe", + AuraModeNum::Strobe => "Strobe", + AuraModeNum::Rainbow => "Rainbow", + AuraModeNum::Star => "Stars", + AuraModeNum::Rain => "Rain", + AuraModeNum::Highlight => "Highlight", + AuraModeNum::Laser => "Laser", + AuraModeNum::Ripple => "Ripple", + AuraModeNum::Pulse => "Pulse", + AuraModeNum::Comet => "Comet", + AuraModeNum::Flash => "Flash", + } + .to_string() + } +} + impl From<&AuraModeNum> for &str { fn from(mode: &AuraModeNum) -> Self { match mode { @@ -210,14 +230,55 @@ impl From for AuraModeNum { #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)] pub enum AuraZone { + /// Used if keyboard has no zones, or if setting all None, - KeyOne, - KeyTwo, - KeyThree, - KeyFour, + /// Leftmost zone + Key1, + /// Zone after leftmost + Key2, + /// Zone second from right + Key3, + /// Rightmost zone + Key4, + /// Logo on the lid (or elsewhere?) Logo, - LightbarLeft, - LightbarRight, + /// The left part of a lightbar (typically on the front of laptop) + BarLeft, + /// The right part of a lightbar + BarRight, +} + +impl Default for AuraZone { + fn default() -> Self { + AuraZone::None + } +} + +impl FromStr for AuraZone { + type Err = Error; + + fn from_str(s: &str) -> Result { + let s = s.to_lowercase(); + match s.to_ascii_lowercase().as_str() { + "0" => Ok(AuraZone::None), + "none" => Ok(AuraZone::None), + "1" => Ok(AuraZone::Key1), + "one" => Ok(AuraZone::Key1), + "2" => Ok(AuraZone::Key2), + "two" => Ok(AuraZone::Key2), + "3" => Ok(AuraZone::Key3), + "three" => Ok(AuraZone::Key3), + "4" => Ok(AuraZone::Key4), + "four" => Ok(AuraZone::Key4), + "5" => Ok(AuraZone::Logo), + "logo" => Ok(AuraZone::Logo), + "6" => Ok(AuraZone::BarLeft), + "lightbar-left" => Ok(AuraZone::BarLeft), + "7" => Ok(AuraZone::BarRight), + "lightbar-right" => Ok(AuraZone::BarRight), + _ => Err(Error::ParseSpeed), + } + } } /// Default factory modes structure. This easily converts to an USB HID packet with: @@ -305,3 +366,100 @@ impl From<&AuraEffect> for [u8; LED_MSG_LEN] { msg } } + +#[cfg(test)] +mod tests { + use crate::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed, LED_MSG_LEN}; + + #[test] + fn check_led_static_packet() { + let st = AuraEffect { + mode: AuraModeNum::Static, + zone: AuraZone::None, + colour1: Colour(0xff, 0x11, 0xdd), + colour2: Colour::default(), + speed: Speed::Med, + direction: Direction::Right, + }; + let ar = <[u8; LED_MSG_LEN]>::from(&st); + + println!("{:02x?}", ar); + let check = [ + 0x5d, 0xb3, 0x0, 0x0, 0xff, 0x11, 0xdd, 0xeb, 0x0, 0x0, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, + ]; + assert_eq!(ar, check); + } + + #[test] + fn check_led_static_zone_packet() { + let mut st = AuraEffect { + mode: AuraModeNum::Static, + zone: AuraZone::Key1, + colour1: Colour(0xff, 0, 0), + colour2: Colour(0, 0, 0), + speed: Speed::Low, + direction: Direction::Left, + }; + let capture = [ + 0x5d, 0xb3, 0x01, 0x00, 0xff, 0x00, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::Key2; + st.colour1 = Colour(0xff, 0xff, 0); + let capture = [ + 0x5d, 0xb3, 0x02, 0x00, 0xff, 0xff, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::Key3; + st.colour1 = Colour(0, 0xff, 0xff); + let capture = [ + 0x5d, 0xb3, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::Key4; + st.colour1 = Colour(0xff, 0x00, 0xff); + let capture = [ + 0x5d, 0xb3, 0x04, 0x00, 0xff, 0x00, 0xff, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::Logo; + st.colour1 = Colour(0x2c, 0xff, 0x00); + let capture = [ + 0x5d, 0xb3, 0x05, 0x00, 0x2c, 0xff, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::BarLeft; + st.colour1 = Colour(0xff, 0x00, 0x00); + let capture = [ + 0x5d, 0xb3, 0x06, 0x00, 0xff, 0x00, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.zone = AuraZone::BarRight; + st.colour1 = Colour(0xff, 0x00, 0xcd); + let capture = [ + 0x5d, 0xb3, 0x07, 0x00, 0xff, 0x00, 0xcd, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + + st.mode = AuraModeNum::Rainbow; + let capture = [ + 0x5d, 0xb3, 0x07, 0x03, 0xff, 0x00, 0xcd, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + ]; + assert_eq!(<[u8; LED_MSG_LEN]>::from(&st)[..9], capture[..9]); + } +} diff --git a/rog-supported/src/lib.rs b/rog-supported/src/lib.rs index 203b0390..de2f61b2 100644 --- a/rog-supported/src/lib.rs +++ b/rog-supported/src/lib.rs @@ -1,6 +1,6 @@ pub static VERSION: &str = env!("CARGO_PKG_VERSION"); -use rog_aura::AuraModeNum; +use rog_aura::{AuraModeNum, AuraZone}; use serde_derive::{Deserialize, Serialize}; use std::fmt; use zvariant_derive::Type; @@ -32,7 +32,7 @@ pub struct PlatformProfileFunctions { pub struct LedSupportedFunctions { pub brightness_set: bool, pub stock_led_modes: Vec, - pub multizone_led_mode: bool, + pub multizone_led_mode: Vec, pub per_key_led_mode: bool, } @@ -80,7 +80,7 @@ impl fmt::Display for LedSupportedFunctions { writeln!(f, "LED:")?; writeln!(f, "\tBrightness control: {}", self.brightness_set)?; writeln!(f, "\tStock LED modes: {:?}", self.stock_led_modes)?; - writeln!(f, "\tMultizone LED mode: {}", self.multizone_led_mode)?; + writeln!(f, "\tMultizone LED mode: {:?}", self.multizone_led_mode)?; writeln!(f, "\tPer key LED mode: {}", self.per_key_led_mode) } }