diff --git a/CHANGELOG.md b/CHANGELOG.md index d69be4ad..d846fa9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `rog-control-center` has now been moved in to the main workspace due to the heavy dependencies on most of the rog crates - +- Preliminary support of TUF RGB keyboards + power states ## [4.3.0] - 2022-07-21 ### Added diff --git a/asusctl/src/aura_cli.rs b/asusctl/src/aura_cli.rs index 84acddab..bad85ea7 100644 --- a/asusctl/src/aura_cli.rs +++ b/asusctl/src/aura_cli.rs @@ -56,7 +56,6 @@ pub struct AuraEnabled { // fn from_str(s: &str) -> Result { // let s = s.to_lowercase(); -// dbg!(s); // Ok(Self { // help: false, // keyboard: None, diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index efb313e3..5476ff4e 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -11,7 +11,7 @@ use profiles_cli::{FanCurveCommand, ProfileCommand}; use rog_anime::usb::get_anime_type; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; -use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevice, AuraPowerDev}; +use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClientBlocking; use rog_profiles::error::ProfileError; @@ -162,7 +162,10 @@ fn do_parsed( for command in commands.iter().filter(|command| { if !matches!( supported.keyboard_led.prod_id, - AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 + AuraDevice::X1854 + | AuraDevice::X1869 + | AuraDevice::X1866 + | AuraDevice::Tuf ) && command.trim().starts_with("led-pow-1") { return false; @@ -458,14 +461,27 @@ fn handle_led_power1( return Ok(()); } - if !matches!( + if matches!( supported.prod_id, AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 ) { - println!("These options are for keyboards of product ID 0x1866 only"); + handle_led_power_1_do_1866(dbus, power)?; return Ok(()); } + if matches!(supported.prod_id, AuraDevice::Tuf) { + handle_led_power_1_do_tuf(dbus, power)?; + return Ok(()); + } + + println!("These options are for keyboards of product ID 0x1866 or TUF only"); + return Ok(()); +} + +fn handle_led_power_1_do_1866( + dbus: &RogDbusClientBlocking, + power: &LedPowerCommand1, +) -> Result<(), Box> { let mut enabled: Vec = Vec::new(); let mut disabled: Vec = Vec::new(); @@ -488,12 +504,54 @@ fn handle_led_power1( let data = AuraPowerDev { x1866: enabled, x19b6: vec![], + tuf: vec![], }; dbus.proxies().led().set_leds_power(data, true)?; let data = AuraPowerDev { x1866: disabled, x19b6: vec![], + tuf: vec![], + }; + dbus.proxies().led().set_leds_power(data, false)?; + + Ok(()) +} + +fn handle_led_power_1_do_tuf( + dbus: &RogDbusClientBlocking, + power: &LedPowerCommand1, +) -> Result<(), Box> { + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + + let mut check = |e: Option, a: AuraDevTuf| { + if let Some(arg) = e { + if arg { + enabled.push(a); + } else { + disabled.push(a); + } + } + }; + + check(power.awake, AuraDevTuf::Awake); + check(power.boot, AuraDevTuf::Boot); + check(power.sleep, AuraDevTuf::Sleep); + check(power.keyboard, AuraDevTuf::Keyboard); + + let data = AuraPowerDev { + x1866: vec![], + x19b6: vec![], + tuf: enabled, + }; + dbg!(&data); + dbus.proxies().led().set_leds_power(data, true)?; + + let data = AuraPowerDev { + x1866: vec![], + x19b6: vec![], + tuf: disabled, }; dbus.proxies().led().set_leds_power(data, false)?; @@ -570,6 +628,7 @@ fn handle_led_power2( if !enabled.is_empty() { let data = AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: enabled, }; @@ -578,6 +637,7 @@ fn handle_led_power2( if !disabled.is_empty() { let data = AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: disabled, }; diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 6f736773..58f4bfc4 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,6 +1,6 @@ use crate::laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use log::{error, warn}; -use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraPowerDev}; +use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; @@ -16,13 +16,16 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; /// booting. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum AuraPowerConfig { + AuraDevTuf(HashSet), AuraDev1866(HashSet), AuraDev19b6(HashSet), } impl AuraPowerConfig { + /// Invalid for TUF laptops pub fn to_bytes(control: &Self) -> [u8; 3] { match control { + AuraPowerConfig::AuraDevTuf(_) => [0, 0, 0], AuraPowerConfig::AuraDev1866(c) => { let c: Vec = c.iter().map(|v| *v).collect(); AuraDev1866::to_bytes(&c) @@ -34,6 +37,39 @@ impl AuraPowerConfig { } } + pub fn to_tuf_bool_array(control: &Self) -> Option<[bool; 5]> { + if let Self::AuraDevTuf(c) = control { + return Some([ + true, + c.contains(&AuraDevTuf::Boot), + c.contains(&AuraDevTuf::Awake), + c.contains(&AuraDevTuf::Sleep), + c.contains(&AuraDevTuf::Keyboard), + ]); + } + + if let Self::AuraDev1866(c) = control { + return Some([ + true, + c.contains(&AuraDev1866::Boot), + c.contains(&AuraDev1866::Awake), + c.contains(&AuraDev1866::Sleep), + c.contains(&AuraDev1866::Keyboard), + ]); + } + + None + } + + pub fn set_tuf(&mut self, power: AuraDevTuf, on: bool) { + if let Self::AuraDevTuf(p) = self { + if on { + p.insert(power); + } else { + p.remove(&power); + } + } + } pub fn set_0x1866(&mut self, power: AuraDev1866, on: bool) { if let Self::AuraDev1866(p) = self { if on { @@ -58,11 +94,18 @@ impl AuraPowerConfig { impl From<&AuraPowerConfig> for AuraPowerDev { fn from(config: &AuraPowerConfig) -> Self { match config { + AuraPowerConfig::AuraDevTuf(d) => AuraPowerDev { + tuf: d.iter().map(|o| *o).collect(), + x1866: vec![], + x19b6: vec![], + }, AuraPowerConfig::AuraDev1866(d) => AuraPowerDev { + tuf: vec![], x1866: d.iter().map(|o| *o).collect(), x19b6: vec![], }, AuraPowerConfig::AuraDev19b6(d) => AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: d.iter().map(|o| *o).collect(), }, @@ -83,15 +126,19 @@ pub struct AuraConfig { impl Default for AuraConfig { fn default() -> Self { - let mut prod_id = String::new(); + let mut prod_id = AuraDevice::Unknown; for prod in ASUS_KEYBOARD_DEVICES.iter() { if let Ok(_) = CtrlKbdLed::find_led_node(prod) { - prod_id = prod.to_string(); + prod_id = AuraDevice::from(*prod); break; } } - let enabled = if prod_id == "19b6" { + if CtrlKbdLed::get_tuf_mode_path().is_some() { + prod_id = AuraDevice::Tuf; + } + + let enabled = if prod_id == AuraDevice::X19B6 { AuraPowerConfig::AuraDev19b6(HashSet::from([ AuraDev19b6::BootLogo, AuraDev19b6::BootKeyb, @@ -106,6 +153,13 @@ impl Default for AuraConfig { AuraDev19b6::SleepBar, AuraDev19b6::ShutdownBar, ])) + } else if prod_id == AuraDevice::Tuf { + AuraPowerConfig::AuraDevTuf(HashSet::from([ + AuraDevTuf::Awake, + AuraDevTuf::Boot, + AuraDevTuf::Sleep, + AuraDevTuf::Keyboard, + ])) } else { AuraPowerConfig::AuraDev1866(HashSet::from([ AuraDev1866::Awake, diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index 22c0219e..b6df2909 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -1,5 +1,7 @@ // Only these two packets must be 17 bytes static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness"; +static TUF_RGB_MODE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/tuf_krgb_mode"; +static TUF_RGB_STATE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/tuf_krgb_state"; use crate::{ error::RogError, @@ -40,16 +42,20 @@ impl GetSupported for CtrlKbdLed { let multizone_led_mode = laptop.multizone; let per_key_led_mode = laptop.per_key; - let mut prod_id = ""; + let mut prod_id = AuraDevice::Unknown; for prod in ASUS_KEYBOARD_DEVICES.iter() { if let Ok(_) = Self::find_led_node(prod) { - prod_id = *prod; + prod_id = AuraDevice::from(*prod); break; } } + if Self::get_tuf_mode_path().is_some() { + prod_id = AuraDevice::Tuf; + } + LedSupportedFunctions { - prod_id: AuraDevice::from(prod_id), + prod_id, brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), stock_led_modes, multizone_led_mode, @@ -58,10 +64,17 @@ impl GetSupported for CtrlKbdLed { } } +#[derive(Debug, PartialEq, PartialOrd)] +pub enum LEDNode { + Tuf, + Rog(String), + None, +} + pub struct CtrlKbdLed { // TODO: config stores the keyboard type as an AuraPower, use or update this pub led_prod: Option, - pub led_node: Option, + pub led_node: LEDNode, pub bright_node: String, pub supported_modes: LaptopLedData, pub flip_effect_write: bool, @@ -194,7 +207,6 @@ impl CtrlKbdLedZbus { impl CtrlKbdLed { pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result { - // TODO: return error if *all* nodes are None let mut led_prod = None; let mut led_node = None; for prod in ASUS_KEYBOARD_DEVICES.iter() { @@ -210,11 +222,28 @@ impl CtrlKbdLed { } let bright_node = Self::get_kbd_bright_path(); + let tuf_node = Self::get_tuf_mode_path().is_some() || Self::get_tuf_state_path().is_some(); - if led_node.is_none() && bright_node.is_none() { + if led_node.is_none() && tuf_node && bright_node.is_none() { + let dmi = sysfs_class::DmiId::default(); + if let Ok(prod_family) = dmi.product_family() { + if prod_family.contains("TUF") { + warn!("A kernel patch is in progress for TUF RGB support"); + } + } return Err(RogError::NoAuraKeyboard); } + let led_node = if let Some(rog) = led_node { + info!("Found ROG USB keyboard"); + LEDNode::Rog(rog) + } else if tuf_node { + info!("Found TUF keyboard"); + LEDNode::Tuf + } else { + LEDNode::None + }; + let ctrl = CtrlKbdLed { led_prod, led_node, @@ -233,6 +262,20 @@ impl CtrlKbdLed { None } + pub fn get_tuf_mode_path() -> Option { + if Path::new(TUF_RGB_MODE_PATH).exists() { + return Some(TUF_RGB_MODE_PATH.to_string()); + } + None + } + + fn get_tuf_state_path() -> Option { + if Path::new(TUF_RGB_STATE_PATH).exists() { + return Some(TUF_RGB_STATE_PATH.to_string()); + } + None + } + pub(super) fn get_brightness(&self) -> Result { let mut file = OpenOptions::new() .read(true) @@ -290,13 +333,26 @@ impl CtrlKbdLed { /// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active pub(super) fn set_power_states(&self, config: &AuraConfig) -> Result<(), RogError> { - let bytes = AuraPowerConfig::to_bytes(&config.enabled); - let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2]]; + if LEDNode::Tuf == self.led_node { + if let Some(path) = Self::get_tuf_state_path() { + let mut file = OpenOptions::new().write(true).open(path)?; + if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&config.enabled) { + let buf = format!( + "1 {} {} {} {}", + pwr[1] as u8, pwr[2] as u8, pwr[3] as u8, pwr[4] as u8, + ); + file.write_all(buf.as_bytes())?; + } + } + } else { + let bytes = AuraPowerConfig::to_bytes(&config.enabled); + let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2]]; - self.write_bytes(&message)?; - self.write_bytes(&LED_SET)?; - // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; + self.write_bytes(&message)?; + self.write_bytes(&LED_SET)?; + // Changes won't persist unless apply is set + self.write_bytes(&LED_APPLY)?; + } Ok(()) } @@ -360,7 +416,7 @@ impl CtrlKbdLed { /// Should only be used if the bytes you are writing are verified correct fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> { - if let Some(led_node) = &self.led_node { + if let LEDNode::Rog(led_node) = &self.led_node { if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) { // println!("write: {:02x?}", &message); return file @@ -422,11 +478,20 @@ impl CtrlKbdLed { } fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> { - let bytes: [u8; LED_MSG_LEN] = mode.into(); - self.write_bytes(&bytes)?; - self.write_bytes(&LED_SET)?; - // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; + if LEDNode::Tuf == self.led_node { + let mut file = OpenOptions::new().write(true).open(TUF_RGB_MODE_PATH)?; + let buf = format!( + "1 {} {} {} {} {}", + mode.mode as u8, mode.colour1.0, mode.colour1.1, mode.colour1.2, mode.speed as u8, + ); + file.write_all(buf.as_bytes())?; + } else { + let bytes: [u8; LED_MSG_LEN] = mode.into(); + self.write_bytes(&bytes)?; + self.write_bytes(&LED_SET)?; + // Changes won't persist unless apply is set + self.write_bytes(&LED_APPLY)?; + } Ok(()) } @@ -498,7 +563,10 @@ impl CtrlKbdLed { mod tests { use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; - use crate::{ctrl_aura::config::AuraConfig, laptops::LaptopLedData}; + use crate::{ + ctrl_aura::{config::AuraConfig, controller::LEDNode}, + laptops::LaptopLedData, + }; use super::CtrlKbdLed; @@ -516,7 +584,7 @@ mod tests { }; let mut controller = CtrlKbdLed { led_prod: None, - led_node: None, + led_node: LEDNode::None, bright_node: String::new(), supported_modes, flip_effect_write: false, @@ -578,7 +646,7 @@ mod tests { }; let mut controller = CtrlKbdLed { led_prod: None, - led_node: None, + led_node: LEDNode::None, bright_node: String::new(), supported_modes, flip_effect_write: false, @@ -615,7 +683,7 @@ mod tests { }; let mut controller = CtrlKbdLed { led_prod: None, - led_node: None, + led_node: LEDNode::None, bright_node: String::new(), supported_modes, flip_effect_write: false, diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 30ad18c6..c679c40c 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -66,6 +66,9 @@ impl CtrlKbdLedZbus { ) -> zbus::fdo::Result<()> { let mut states = None; if let Ok(mut ctrl) = self.0.try_lock() { + for p in options.tuf { + ctrl.config.enabled.set_tuf(p, enabled); + } for p in options.x1866 { ctrl.config.enabled.set_0x1866(p, enabled); } diff --git a/data/asusd-ledmodes.toml b/data/asusd-ledmodes.toml index 50edda44..020f8464 100644 --- a/data/asusd-ledmodes.toml +++ b/data/asusd-ledmodes.toml @@ -1,3 +1,17 @@ +[[led_data]] +prod_family = "TUF" +board_names = ["FA507"] +standard = ["Static", "Breathe", "Strobe", "Pulse"] +multizone = [] +per_key = false + +[[led_data]] +prod_family = "TUF Gaming" +board_names = ["FX505D"] +standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] +multizone = [] +per_key = false + [[led_data]] prod_family = "Zephyrus S" board_names = ["GX502", "GX701", "G531", "GL531", "G532"] @@ -162,7 +176,7 @@ multizone = [] per_key = false [[led_data]] -prod_family = "ROG Strix" +prod_family = "ROG Strix" board_names = ["G513IC"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] multizone = [] diff --git a/rog-aura/src/builtin_modes.rs b/rog-aura/src/builtin_modes.rs index fc65a748..bd296f41 100644 --- a/rog-aura/src/builtin_modes.rs +++ b/rog-aura/src/builtin_modes.rs @@ -150,8 +150,11 @@ impl FromStr for Direction { /// Enum of modes that convert to the actual number required by a USB HID packet #[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize)] +#[derive( + Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize, +)] pub enum AuraModeNum { + #[default] Static = 0, Breathe = 1, Strobe = 2, diff --git a/rog-aura/src/usb.rs b/rog-aura/src/usb.rs index b7948d7d..9c0389f3 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -23,6 +23,7 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize, Default)] pub enum AuraDevice { + Tuf, X1854, X1869, X1866, @@ -34,6 +35,7 @@ pub enum AuraDevice { impl From<&str> for AuraDevice { fn from(s: &str) -> Self { match s.to_lowercase().as_str() { + "tuf" => AuraDevice::Tuf, "1866" => AuraDevice::X1866, "1869" => AuraDevice::X1869, "1854" => AuraDevice::X1854, @@ -49,12 +51,29 @@ impl From<&str> for AuraDevice { /// This struct is intended as a helper to pass args to generic dbus interface #[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct AuraPowerDev { + pub tuf: Vec, pub x1866: Vec, pub x19b6: Vec, } +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum AuraDevTuf { + Boot, + Awake, + Sleep, + Keyboard, +} + +impl AuraDevTuf { + pub const fn dev_id() -> &'static str { + "tuf" + } +} + /// # Bits for older 0x1866 keyboard model /// /// Keybord and Lightbar require Awake, Boot and Sleep apply to both diff --git a/rog-control-center/src/app.rs b/rog-control-center/src/app.rs index d75c349a..96d14c09 100644 --- a/rog-control-center/src/app.rs +++ b/rog-control-center/src/app.rs @@ -28,7 +28,9 @@ pub struct RogApp<'a> { pub config: Config, pub asus_dbus: RogDbusClientBlocking<'a>, /// Oscillator in percentage - pub oscillator: Arc, + pub oscillator1: Arc, + pub oscillator2: Arc, + pub oscillator3: Arc, /// Frequency of oscillation pub oscillator_freq: Arc, /// A toggle that toggles true/false when the oscillator reaches 0 @@ -49,8 +51,14 @@ impl<'a> RogApp<'a> { // Set up an oscillator to run on a thread. // Helpful for visual effects like colour pulse. - let oscillator = Arc::new(AtomicU8::new(0)); - let oscillator1 = oscillator.clone(); + let oscillator1 = Arc::new(AtomicU8::new(0)); + let oscillator2 = Arc::new(AtomicU8::new(0)); + let oscillator3 = Arc::new(AtomicU8::new(0)); + + let oscillator1_1 = oscillator1.clone(); + let oscillator1_2 = oscillator2.clone(); + let oscillator1_3 = oscillator3.clone(); + let oscillator_freq = Arc::new(AtomicU8::new(5)); let oscillator_freq1 = oscillator_freq.clone(); let oscillator_toggle = Arc::new(AtomicBool::new(false)); @@ -62,19 +70,27 @@ impl<'a> RogApp<'a> { let time = started.elapsed(); // 32 = slow, 16 = med, 8 = fast let scale = oscillator_freq1.load(Ordering::SeqCst) as f64; - let elapsed = time.as_millis() as f64 / 10000.0; - let tmp = ((scale * elapsed * PI).cos()).abs(); - if tmp <= 0.1 && !toggled { + let elapsed1 = (time.as_millis() as f64 + 333.0) / 10000.0; + let elapsed2 = (time.as_millis() as f64 + 666.0) / 10000.0; + let elapsed3 = (time.as_millis() as f64 + 999.0) / 10000.0; + let tmp1 = ((scale * elapsed1 * PI).cos()).abs(); + let tmp2 = ((scale * 0.85 * elapsed2 * PI).cos()).abs(); + let tmp3 = ((scale * 0.7 * elapsed3 * PI).cos()).abs(); + if tmp1 <= 0.1 && !toggled { let s = oscillator_toggle1.load(Ordering::SeqCst); oscillator_toggle1.store(!s, Ordering::SeqCst); toggled = true; - } else if tmp > 0.9 { + } else if tmp1 > 0.9 { toggled = false; } - let tmp = (255.0 * tmp * 100.0 / 255.0) as u8; + let tmp1 = (255.0 * tmp1 * 100.0 / 255.0) as u8; + let tmp2 = (255.0 * tmp2 * 100.0 / 255.0) as u8; + let tmp3 = (255.0 * tmp3 * 100.0 / 255.0) as u8; - oscillator1.store(tmp, Ordering::SeqCst); + oscillator1_1.store(tmp1, Ordering::SeqCst); + oscillator1_2.store(tmp2, Ordering::SeqCst); + oscillator1_3.store(tmp3, Ordering::SeqCst); std::thread::sleep(Duration::from_millis(33)); } }); @@ -87,7 +103,9 @@ impl<'a> RogApp<'a> { running_in_bg: start_closed, config, asus_dbus: dbus, - oscillator, + oscillator1, + oscillator2, + oscillator3, oscillator_toggle, oscillator_freq, }) @@ -168,8 +186,9 @@ impl<'a> eframe::App for RogApp<'a> { self.system_page(ctx); } else if page == Page::AuraEffects { self.aura_page(ctx); - } else if page == Page::AnimeMatrix { - self.anime_page(ctx); + // TODO: Anime page is not complete + // } else if page == Page::AnimeMatrix { + // self.anime_page(ctx); } else if page == Page::FanCurves { self.fan_curve_page(ctx); } diff --git a/rog-control-center/src/mocking.rs b/rog-control-center/src/mocking.rs index 21ebc752..642406eb 100644 --- a/rog-control-center/src/mocking.rs +++ b/rog-control-center/src/mocking.rs @@ -147,6 +147,7 @@ impl Led { } pub fn leds_enabled(&self) -> Result { Ok(AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: vec![ AuraDev19b6::BootKeyb, diff --git a/rog-control-center/src/page_states.rs b/rog-control-center/src/page_states.rs index 20166450..c17e48df 100644 --- a/rog-control-center/src/page_states.rs +++ b/rog-control-center/src/page_states.rs @@ -173,19 +173,19 @@ impl AuraState { Ok(Self { was_notified, current_mode: if !supported.keyboard_led.stock_led_modes.is_empty() { - dbus.proxies().led().led_mode()? + dbus.proxies().led().led_mode().unwrap_or_default() } else { AuraModeNum::Static }, modes: if !supported.keyboard_led.stock_led_modes.is_empty() { - dbus.proxies().led().led_modes()? + dbus.proxies().led().led_modes().unwrap_or_default() } else { BTreeMap::new() }, - enabled: dbus.proxies().led().leds_enabled()?, + enabled: dbus.proxies().led().leds_enabled().unwrap_or_default(), bright: if !supported.keyboard_led.brightness_set { - dbus.proxies().led().led_brightness()? + dbus.proxies().led().led_brightness().unwrap_or_default() } else { 2 }, @@ -196,7 +196,7 @@ impl AuraState { } /// Bump value in to the wave and surf all along. - pub fn nudge_wave(&mut self, value: u8) { + pub fn nudge_wave(&mut self, r: u8, g: u8, b: u8) { for i in (0..self.wave_red.len()).rev() { if i > 0 { self.wave_red[i] = self.wave_red[i - 1]; @@ -204,18 +204,9 @@ impl AuraState { self.wave_blue[i] = self.wave_blue[i - 1]; } } - let mut g = value + 33; - if g > 100 { - g -= 100; - } - let mut b = value + 66; - if b > 100 { - b -= 100; - } - self.wave_red[0] = value; + self.wave_red[0] = r; self.wave_green[0] = g; self.wave_blue[0] = b; - dbg!(self.wave_blue); } } @@ -356,6 +347,7 @@ impl Default for PageDataStates { current_mode: AuraModeNum::Static, modes: Default::default(), enabled: AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: vec![], }, diff --git a/rog-control-center/src/pages/aura_page.rs b/rog-control-center/src/pages/aura_page.rs index c56b2141..c736d5d6 100644 --- a/rog-control-center/src/pages/aura_page.rs +++ b/rog-control-center/src/pages/aura_page.rs @@ -14,12 +14,17 @@ impl<'a> RogApp<'a> { supported, states, asus_dbus: dbus, - oscillator, + oscillator1, + oscillator2, + oscillator3, + oscillator_freq, .. } = self; - let osc = oscillator.load(Ordering::SeqCst) as u32; - states.aura.nudge_wave(osc as u8); + let red = oscillator1.load(Ordering::SeqCst) as u32; + let green = oscillator2.load(Ordering::SeqCst) as u32; + let blue = oscillator3.load(Ordering::SeqCst) as u32; + states.aura.nudge_wave(red as u8, green as u8, blue as u8); // let osc = c.0 * 255 / osc; // dbg!(osc); let c1 = states @@ -39,29 +44,35 @@ impl<'a> RogApp<'a> { let mut colour = Color32::from_rgb(c1.0, c1.1, c1.2); if states.aura.current_mode == AuraModeNum::Pulse { colour = Color32::from_rgb( - (osc * c1.0 as u32 / 100) as u8, - (osc * c1.1 as u32 / 100) as u8, - (osc * c1.2 as u32 / 100) as u8, + (red * c1.0 as u32 / 100) as u8, + (red * c1.1 as u32 / 100) as u8, + (red * c1.2 as u32 / 100) as u8, ); } else if states.aura.current_mode == AuraModeNum::Breathe { if self.oscillator_toggle.load(Ordering::SeqCst) { colour = Color32::from_rgb( - (osc * c2.0 as u32 / 100) as u8, - (osc * c2.1 as u32 / 100) as u8, - (osc * c2.2 as u32 / 100) as u8, + (red * c2.0 as u32 / 100) as u8, + (red * c2.1 as u32 / 100) as u8, + (red * c2.2 as u32 / 100) as u8, ); } else { colour = Color32::from_rgb( - (osc * c1.0 as u32 / 100) as u8, - (osc * c1.1 as u32 / 100) as u8, - (osc * c1.2 as u32 / 100) as u8, + (red * c1.0 as u32 / 100) as u8, + (red * c1.1 as u32 / 100) as u8, + (red * c1.2 as u32 / 100) as u8, ); } + } else if states.aura.current_mode == AuraModeNum::Strobe { + colour = Color32::from_rgb( + (red * 255 / 100) as u8, + (green * 255 / 100) as u8, + (blue * 255 / 100) as u8, + ); } // TODO: animation of colour changes/periods/blending egui::CentralPanel::default().show(ctx, |ui| { - aura_modes_group(supported, states, dbus, ui); + aura_modes_group(supported, states, oscillator_freq, dbus, ui); keyboard(ui, &states.keyboard_layout, &mut states.aura, colour); }); diff --git a/rog-control-center/src/widgets/aura_modes.rs b/rog-control-center/src/widgets/aura_modes.rs index 0ff1cf13..e4f589fa 100644 --- a/rog-control-center/src/widgets/aura_modes.rs +++ b/rog-control-center/src/widgets/aura_modes.rs @@ -1,3 +1,8 @@ +use std::sync::{ + atomic::{AtomicU8, Ordering}, + Arc, +}; + use egui::{RichText, Ui}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed}; use rog_supported::SupportedFunctions; @@ -10,6 +15,7 @@ use crate::{ pub fn aura_modes_group( supported: &SupportedFunctions, states: &mut PageDataStates, + freq: &mut Arc, dbus: &mut RogDbusClientBlocking, ui: &mut Ui, ) { @@ -55,7 +61,17 @@ pub fn aura_modes_group( ui.selectable_value(&mut effect.zone, a, format!("{:?}", a)); }; let mut speed_button = |a: Speed, ui: &mut Ui| { - ui.selectable_value(&mut effect.speed, a, format!("{:?}", a)); + if ui + .selectable_value(&mut effect.speed, a, format!("{:?}", a)) + .clicked() + { + let val = match effect.speed { + Speed::Low => 6, + Speed::Med => 8, + Speed::High => 10, + }; + freq.store(val, Ordering::SeqCst); + } }; let mut dir_button = |a: rog_aura::Direction, ui: &mut Ui| { ui.selectable_value(&mut effect.direction, a, format!("{:?}", a)); @@ -69,72 +85,82 @@ pub fn aura_modes_group( ui.vertical(|ui| { let h = 16.0; ui.set_row_height(22.0); - if has_keyzones || has_lightbar || has_logo { + ui.add_enabled_ui(allowed.zone, |ui| { + if has_keyzones || has_lightbar || has_logo { + ui.horizontal_wrapped(|ui| { + ui.label(RichText::new("Zone").size(h)); + }); + } + }); + ui.add_enabled_ui(allowed.colour1, |ui| { ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.zone); - ui.label(RichText::new("Zone").size(h)); + ui.label(RichText::new("Colour 1").size(h)); }); - } - ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.colour1); - ui.label(RichText::new("Colour 1").size(h)); }); - - ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.colour2); - ui.label(RichText::new("Colour 2").size(h)); + ui.add_enabled_ui(allowed.colour2, |ui| { + ui.horizontal_wrapped(|ui| { + ui.label(RichText::new("Colour 2").size(h)); + }); }); - - ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.speed); - ui.label(RichText::new("Speed").size(h)); + ui.add_enabled_ui(allowed.speed, |ui| { + ui.horizontal_wrapped(|ui| { + ui.set_enabled(allowed.speed); + ui.label(RichText::new("Speed").size(h)); + }); }); - ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.direction); - ui.label(RichText::new("Direction").size(h)); + ui.add_enabled_ui(allowed.direction, |ui| { + ui.horizontal_wrapped(|ui| { + ui.set_enabled(allowed.direction); + ui.label(RichText::new("Direction").size(h)); + }); }); ui.set_enabled(true); }); ui.vertical(|ui| { ui.set_row_height(22.0); - if has_keyzones || has_lightbar || has_logo { - ui.horizontal_wrapped(|ui| { - ui.set_enabled(allowed.zone); - zone_button(AuraZone::None, ui); - if has_keyzones { - zone_button(AuraZone::Key1, ui); - zone_button(AuraZone::Key2, ui); - zone_button(AuraZone::Key3, ui); - zone_button(AuraZone::Key4, ui); - } - if has_logo { - zone_button(AuraZone::Logo, ui); - } - if has_lightbar { - zone_button(AuraZone::BarLeft, ui); - zone_button(AuraZone::BarRight, ui); - } - }); - } - - ui.set_enabled(allowed.colour1); - egui::color_picker::color_edit_button_srgb(ui, &mut c1); - ui.set_enabled(allowed.colour2); - egui::color_picker::color_edit_button_srgb(ui, &mut c2); - - ui.set_enabled(allowed.speed); - ui.horizontal_wrapped(|ui| { - speed_button(Speed::Low, ui); - speed_button(Speed::Med, ui); - speed_button(Speed::High, ui); + ui.add_enabled_ui(allowed.zone, |ui| { + if has_keyzones || has_lightbar || has_logo { + ui.horizontal_wrapped(|ui| { + zone_button(AuraZone::None, ui); + if has_keyzones { + zone_button(AuraZone::Key1, ui); + zone_button(AuraZone::Key2, ui); + zone_button(AuraZone::Key3, ui); + zone_button(AuraZone::Key4, ui); + } + if has_logo { + zone_button(AuraZone::Logo, ui); + } + if has_lightbar { + zone_button(AuraZone::BarLeft, ui); + zone_button(AuraZone::BarRight, ui); + } + }); + } }); - ui.set_enabled(allowed.direction); - ui.horizontal_wrapped(|ui| { - dir_button(rog_aura::Direction::Left, ui); - dir_button(rog_aura::Direction::Down, ui); - dir_button(rog_aura::Direction::Right, ui); - dir_button(rog_aura::Direction::Up, ui); + ui.add_enabled_ui(allowed.colour1, |ui| { + egui::color_picker::color_edit_button_srgb(ui, &mut c1) + }); + ui.add_enabled_ui(allowed.colour2, |ui| { + egui::color_picker::color_edit_button_srgb(ui, &mut c2) + }); + + ui.add_enabled_ui(allowed.speed, |ui| { + ui.horizontal_wrapped(|ui| { + speed_button(Speed::Low, ui); + speed_button(Speed::Med, ui); + speed_button(Speed::High, ui); + }); + }); + + ui.add_enabled_ui(allowed.direction, |ui| { + ui.horizontal_wrapped(|ui| { + dir_button(rog_aura::Direction::Left, ui); + dir_button(rog_aura::Direction::Down, ui); + dir_button(rog_aura::Direction::Right, ui); + dir_button(rog_aura::Direction::Up, ui); + }); }); }); }); diff --git a/rog-control-center/src/widgets/aura_power.rs b/rog-control-center/src/widgets/aura_power.rs index 2c8a41fe..24855730 100644 --- a/rog-control-center/src/widgets/aura_power.rs +++ b/rog-control-center/src/widgets/aura_power.rs @@ -1,6 +1,6 @@ use egui::{RichText, Ui}; use rog_aura::{ - usb::{AuraDev1866, AuraDev19b6, AuraDevice, AuraPowerDev}, + usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}, AuraZone, }; use rog_supported::SupportedFunctions; @@ -20,6 +20,7 @@ pub fn aura_power_group( aura_power1(supported, states, dbus, ui) } AuraDevice::X19B6 => aura_power2(supported, states, dbus, ui), + AuraDevice::Tuf => aura_power1(supported, states, dbus, ui), AuraDevice::Unknown => {} } } @@ -31,10 +32,15 @@ fn aura_power1( ui: &mut Ui, ) { let enabled_states = &mut states.aura.enabled; - let boot = &mut enabled_states.x1866.contains(&AuraDev1866::Boot); - let sleep = &mut enabled_states.x1866.contains(&AuraDev1866::Sleep); - let keyboard = &mut enabled_states.x1866.contains(&AuraDev1866::Keyboard); - let lightbar = &mut enabled_states.x1866.contains(&AuraDev1866::Lightbar); + let mut boot = enabled_states.x1866.contains(&AuraDev1866::Boot); + let mut sleep = enabled_states.x1866.contains(&AuraDev1866::Sleep); + let mut keyboard = enabled_states.x1866.contains(&AuraDev1866::Keyboard); + let mut lightbar = enabled_states.x1866.contains(&AuraDev1866::Lightbar); + if supported.keyboard_led.prod_id == AuraDevice::Tuf { + boot = enabled_states.tuf.contains(&AuraDevTuf::Boot); + sleep = enabled_states.tuf.contains(&AuraDevTuf::Sleep); + keyboard = enabled_states.tuf.contains(&AuraDevTuf::Awake); + } let mut changed = false; ui.horizontal_wrapped(|ui| { @@ -59,22 +65,22 @@ fn aura_power1( ui.vertical(|ui| { ui.set_row_height(22.0); ui.horizontal_wrapped(|ui| { - if ui.checkbox(boot, "Enable").changed() { + if ui.checkbox(&mut boot, "Enable").changed() { changed = true; } }); ui.horizontal_wrapped(|ui| { - if ui.toggle_value(keyboard, "Keyboard").changed() { + if ui.toggle_value(&mut keyboard, "Keyboard").changed() { changed = true; } if !supported.keyboard_led.multizone_led_mode.is_empty() { - if ui.toggle_value(lightbar, "Lightbar").changed() { + if ui.toggle_value(&mut lightbar, "Lightbar").changed() { changed = true; } } }); ui.horizontal_wrapped(|ui| { - if ui.checkbox(sleep, "Enable").changed() { + if ui.checkbox(&mut sleep, "Enable").changed() { changed = true; } }); @@ -102,53 +108,102 @@ fn aura_power1( }); if changed { - let mut enabled = Vec::new(); - let mut disabled = Vec::new(); + if supported.keyboard_led.prod_id == AuraDevice::Tuf { + let mut enabled = Vec::new(); + let mut disabled = Vec::new(); - let mut modify = |b: bool, a: AuraDev1866| { - if b { - enabled.push(a); - if !enabled_states.x1866.contains(&a) { - enabled_states.x1866.push(a); - } - } else { - disabled.push(a); - // This would be so much better as a hashset - if enabled_states.x1866.contains(&a) { - let mut idx = 0; - for (i, n) in enabled_states.x1866.iter().enumerate() { - if *n == a { - idx = i; - break; - } + let mut modify_tuf = |b: bool, a: AuraDevTuf| { + if b { + enabled.push(a); + if !enabled_states.tuf.contains(&a) { + enabled_states.tuf.push(a); + } + } else { + disabled.push(a); + // This would be so much better as a hashset + if enabled_states.tuf.contains(&a) { + let mut idx = 0; + for (i, n) in enabled_states.tuf.iter().enumerate() { + if *n == a { + idx = i; + break; + } + } + enabled_states.tuf.remove(idx); } - enabled_states.x1866.remove(idx); } - } - }; - modify(*boot, AuraDev1866::Boot); - modify(*sleep, AuraDev1866::Sleep); - modify(*keyboard, AuraDev1866::Keyboard); - if !supported.keyboard_led.multizone_led_mode.is_empty() { - modify(*lightbar, AuraDev1866::Lightbar); - } - - let mut send = |enable: bool, data: Vec| { - let options = AuraPowerDev { - x1866: data, - x19b6: vec![], }; - // build data to send - dbus.proxies() - .led() - .set_leds_power(options, enable) - .map_err(|err| { - states.error = Some(err.to_string()); - }) - .ok(); - }; - send(true, enabled); - send(false, disabled); + modify_tuf(boot, AuraDevTuf::Boot); + modify_tuf(sleep, AuraDevTuf::Sleep); + modify_tuf(keyboard, AuraDevTuf::Awake); + + let mut send = |enable: bool, data: Vec| { + let options = AuraPowerDev { + tuf: data, + x1866: vec![], + x19b6: vec![], + }; + // build data to send + dbus.proxies() + .led() + .set_leds_power(options, enable) + .map_err(|err| { + states.error = Some(err.to_string()); + }) + .ok(); + }; + send(true, enabled); + send(false, disabled); + } else { + let mut enabled = Vec::new(); + let mut disabled = Vec::new(); + + let mut modify_x1866 = |b: bool, a: AuraDev1866| { + if b { + enabled.push(a); + if !enabled_states.x1866.contains(&a) { + enabled_states.x1866.push(a); + } + } else { + disabled.push(a); + // This would be so much better as a hashset + if enabled_states.x1866.contains(&a) { + let mut idx = 0; + for (i, n) in enabled_states.x1866.iter().enumerate() { + if *n == a { + idx = i; + break; + } + } + enabled_states.x1866.remove(idx); + } + } + }; + modify_x1866(boot, AuraDev1866::Boot); + modify_x1866(sleep, AuraDev1866::Sleep); + modify_x1866(keyboard, AuraDev1866::Keyboard); + if !supported.keyboard_led.multizone_led_mode.is_empty() { + modify_x1866(lightbar, AuraDev1866::Lightbar); + } + + let mut send = |enable: bool, data: Vec| { + let options = AuraPowerDev { + tuf: vec![], + x1866: data, + x19b6: vec![], + }; + // build data to send + dbus.proxies() + .led() + .set_leds_power(options, enable) + .map_err(|err| { + states.error = Some(err.to_string()); + }) + .ok(); + }; + send(true, enabled); + send(false, disabled); + } } } @@ -271,6 +326,7 @@ fn aura_power2( let mut send = |enable: bool, data: Vec| { let options = AuraPowerDev { + tuf: vec![], x1866: vec![], x19b6: data, }; diff --git a/rog-control-center/src/widgets/keyboard_layout.rs b/rog-control-center/src/widgets/keyboard_layout.rs index ef335ccd..bcb376eb 100644 --- a/rog-control-center/src/widgets/keyboard_layout.rs +++ b/rog-control-center/src/widgets/keyboard_layout.rs @@ -3,7 +3,12 @@ use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum}; use crate::page_states::AuraState; -pub fn keyboard(ui: &mut egui::Ui, keyboard_layout: &KeyLayout, states: &mut AuraState, mut colour: Color32) { +pub fn keyboard( + ui: &mut egui::Ui, + keyboard_layout: &KeyLayout, + states: &mut AuraState, + mut colour: Color32, +) { ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0); let mut arrows_done = false; let mut rog_done = false; @@ -13,8 +18,8 @@ pub fn keyboard(ui: &mut egui::Ui, keyboard_layout: &KeyLayout, states: &mut Aur if states.current_mode == AuraModeNum::Rainbow { colour = Color32::from_rgb( (states.wave_red[i] as u32 * 255 / 100) as u8, - (states.wave_green[i]as u32 * 255 / 100) as u8, - (states.wave_blue[i]as u32 * 255 / 100) as u8, + (states.wave_green[i] as u32 * 255 / 100) as u8, + (states.wave_blue[i] as u32 * 255 / 100) as u8, ); } // your boat diff --git a/rog-control-center/src/widgets/side_panel.rs b/rog-control-center/src/widgets/side_panel.rs index c7db63ce..8a3562fb 100644 --- a/rog-control-center/src/widgets/side_panel.rs +++ b/rog-control-center/src/widgets/side_panel.rs @@ -38,15 +38,16 @@ impl<'a> RogApp<'a> { } } - if self.supported.anime_ctrl.0 { - ui.separator(); - if ui - .selectable_value(page, Page::AnimeMatrix, "AniMe Matrix") - .clicked() - { - *page = Page::AnimeMatrix; - } - } + // TODO: Anime page is not complete + // if self.supported.anime_ctrl.0 { + // ui.separator(); + // if ui + // .selectable_value(page, Page::AnimeMatrix, "AniMe Matrix") + // .clicked() + // { + // *page = Page::AnimeMatrix; + // } + // } ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| { ui.horizontal(|ui| {