diff --git a/asusctl/src/aura_cli.rs b/asusctl/src/aura_cli.rs index 7d319392..37e98415 100644 --- a/asusctl/src/aura_cli.rs +++ b/asusctl/src/aura_cli.rs @@ -2,6 +2,53 @@ use gumdrop::Options; use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed}; use std::str::FromStr; +#[derive(Options)] +pub struct LedPowerCommand { + #[options(help = "print help message")] + pub help: bool, + #[options(command)] + pub command: Option, +} + +#[derive(Options)] +pub enum SetAuraEnabled { + #[options(help = "set to enabled while the device is booting")] + Boot(AuraEnabled), + #[options(help = "set to animate while the device is suspended")] + Sleep(AuraEnabled), + #[options(help = "set to enabled while device is awake")] + Awake(AuraEnabled), + #[options(help = "set to animate while the device is shutdown")] + Shutdown(AuraEnabled), +} + +#[derive(Debug, Clone, Default, Options)] +pub struct AuraEnabled { + #[options(help = "print help message")] + pub help: bool, + #[options(meta = "", help = "")] + pub keyboard: Option, + #[options(meta = "", help = "")] + pub logo: Option, + #[options(meta = "", help = "")] + pub lightbar: Option, +} + +// impl FromStr for AuraEnabled { +// type Err = Error; + +// fn from_str(s: &str) -> Result { +// let s = s.to_lowercase(); +// dbg!(s); +// Ok(Self { +// help: false, +// keyboard: None, +// logo: None, +// lightbar: None, +// }) +// } +// } + #[derive(Options)] pub struct LedBrightness { level: Option, @@ -50,7 +97,14 @@ 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 { #[options(help = "print help message")] @@ -59,6 +113,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 +127,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 +143,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 +161,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 +230,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 +242,7 @@ impl From<&SingleColour> for AuraEffect { fn from(aura: &SingleColour) -> Self { Self { colour1: aura.colour, + zone: aura.zone, ..Default::default() } } @@ -177,6 +252,7 @@ impl From<&SingleSpeed> for AuraEffect { fn from(aura: &SingleSpeed) -> Self { Self { speed: aura.speed, + zone: aura.zone, ..Default::default() } } @@ -187,6 +263,7 @@ impl From<&SingleColourSpeed> for AuraEffect { Self { colour1: aura.colour, speed: aura.speed, + zone: aura.zone, ..Default::default() } } @@ -197,6 +274,7 @@ impl From<&TwoColourSpeed> for AuraEffect { Self { colour1: aura.colour, colour2: aura.colour2, + zone: aura.zone, ..Default::default() } } @@ -207,6 +285,7 @@ impl From<&SingleSpeedDirection> for AuraEffect { Self { speed: aura.speed, direction: aura.direction, + zone: aura.zone, ..Default::default() } } @@ -275,55 +354,6 @@ impl From<&SetAuraBuiltin> for AuraEffect { data.mode = AuraModeNum::Flash; data } - _ => AuraEffect::default(), } } } - -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::One; - zones[0].colour1 = data.colour1; - - zones[1].mode = AuraModeNum::Static; - zones[1].zone = AuraZone::Two; - zones[1].colour1 = data.colour2; - - zones[2].mode = AuraModeNum::Static; - zones[2].zone = AuraZone::Three; - zones[2].colour1 = data.colour3; - - zones[3].mode = AuraModeNum::Static; - zones[3].zone = AuraZone::Four; - zones[3].colour1 = data.colour4; - } - SetAuraBuiltin::MultiBreathe(data) => { - zones[0].mode = AuraModeNum::Breathe; - zones[0].zone = AuraZone::One; - zones[0].colour1 = data.colour1; - zones[0].speed = data.speed; - - zones[1].mode = AuraModeNum::Breathe; - zones[1].zone = AuraZone::Two; - zones[1].colour1 = data.colour2; - zones[1].speed = data.speed; - - zones[2].mode = AuraModeNum::Breathe; - zones[2].zone = AuraZone::Three; - zones[2].colour1 = data.colour3; - zones[2].speed = data.speed; - - zones[3].mode = AuraModeNum::Breathe; - zones[3].zone = AuraZone::Four; - zones[3].colour1 = data.colour4; - zones[3].speed = data.speed; - } - _ => {} - } - zones - } -} diff --git a/asusctl/src/cli_opts.rs b/asusctl/src/cli_opts.rs index 13585ff6..21a31194 100644 --- a/asusctl/src/cli_opts.rs +++ b/asusctl/src/cli_opts.rs @@ -1,6 +1,6 @@ use crate::{ anime_cli::AnimeCommand, - aura_cli::{LedBrightness, SetAuraBuiltin}, + aura_cli::{LedBrightness, LedPowerCommand, SetAuraBuiltin}, profiles_cli::{FanCurveCommand, ProfileCommand}, }; use gumdrop::Options; @@ -29,6 +29,8 @@ pub struct CliStart { pub enum CliCommand { #[options(help = "Set the keyboard lighting from built-in modes")] LedMode(LedModeCommand), + #[options(help = "Set the keyboard lighting from built-in modes")] + LedPower(LedPowerCommand), #[options(help = "Set or select platform_profile")] Profile(ProfileCommand), #[options(help = "Set, select, or modify fan curves if supported")] @@ -49,25 +51,6 @@ pub struct LedModeCommand { pub next_mode: bool, #[options(help = "switch to previous aura mode")] pub prev_mode: bool, - #[options( - meta = "", - help = "set the keyboard LED to enabled while the device is awake" - )] - pub boot_enable: Option, - #[options( - meta = "", - help = "set the keyboard LED suspend animation to enabled while the device is suspended" - )] - pub sleep_enable: Option, - #[options( - meta = "", - help = "set the full keyboard LEDs (keys and side) to enabled" - )] - pub all_leds_enable: Option, - #[options(meta = "", help = "set the keyboard keys LEDs to enabled")] - pub keys_leds_enable: Option, - #[options(meta = "", help = "set the keyboard side LEDs to enabled")] - pub side_leds_enable: Option, #[options(command)] pub command: Option, } diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 9df13c7b..8e158bc7 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -2,11 +2,13 @@ use std::process::Command; use std::thread::sleep; use std::{env::args, path::Path}; +use aura_cli::LedPowerCommand; use gumdrop::{Opt, Options}; use anime_cli::{AnimeActions, AnimeCommand}; use profiles_cli::{FanCurveCommand, ProfileCommand}; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; +use rog_aura::usb::AuraControl; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClientBlocking; use rog_profiles::error::ProfileError; @@ -16,7 +18,7 @@ use rog_supported::{ RogBiosSupportedFunctions, }; -use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; +use crate::aura_cli::LedBrightness; use crate::cli_opts::*; mod anime_cli; @@ -143,6 +145,7 @@ fn do_parsed( ) -> Result<(), Box> { match &parsed.command { Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?, + Some(CliCommand::LedPower(pow)) => handle_led_power(dbus, &supported.keyboard_led, pow)?, Some(CliCommand::Profile(cmd)) => handle_profile(dbus, &supported.platform_profile, cmd)?, Some(CliCommand::FanCurve(cmd)) => { handle_fan_curve(dbus, &supported.platform_profile, cmd)? @@ -339,15 +342,7 @@ fn handle_led_mode( supported: &LedSupportedFunctions, mode: &LedModeCommand, ) -> Result<(), Box> { - if mode.command.is_none() - && !mode.prev_mode - && !mode.next_mode - && mode.boot_enable.is_none() - && mode.sleep_enable.is_none() - && mode.all_leds_enable.is_none() - && mode.keys_leds_enable.is_none() - && mode.side_leds_enable.is_none() - { + if mode.command.is_none() && !mode.prev_mode && !mode.next_mode { if !mode.help { println!("Missing arg or command\n"); } @@ -365,7 +360,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,38 +386,172 @@ 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))?; + } + + Ok(()) +} + +fn handle_led_power( + dbus: &RogDbusClientBlocking, + _supported: &LedSupportedFunctions, + power: &LedPowerCommand, +) -> Result<(), Box> { + if power.command().is_none() { + if !power.help { + println!("Missing arg or command\n"); + } + println!("{}\n", power.self_usage()); + println!("Commands available"); + + if let Some(cmdlist) = LedPowerCommand::command_list() { + let commands: Vec = cmdlist.lines().map(|s| s.to_string()).collect(); + for command in commands.iter() { + println!("{}", command); + } + } + + println!("\nHelp can also be requested on commands, e.g: boot --help"); + return Ok(()); + } + + if let Some(pow) = power.command.as_ref() { + if pow.help_requested() { + println!("{}", pow.self_usage()); + return Ok(()); + } + + match pow { + // TODO: make this a macro or something + aura_cli::SetAuraEnabled::Boot(arg) => { + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + arg.keyboard.map(|v| { + if v { + enabled.push(AuraControl::BootKeyb) + } else { + disabled.push(AuraControl::BootKeyb) + } + }); + arg.logo.map(|v| { + if v { + enabled.push(AuraControl::BootLogo) + } else { + disabled.push(AuraControl::BootLogo) + } + }); + arg.lightbar.map(|v| { + if v { + enabled.push(AuraControl::BootBar) + } else { + disabled.push(AuraControl::BootBar) + } + }); + if !enabled.is_empty() { + dbus.proxies().led().set_leds_enabled(enabled)?; + } + if !disabled.is_empty() { + dbus.proxies().led().set_leds_disabled(disabled)?; + } + } + aura_cli::SetAuraEnabled::Sleep(arg) => { + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + arg.keyboard.map(|v| { + if v { + enabled.push(AuraControl::SleepKeyb) + } else { + disabled.push(AuraControl::SleepKeyb) + } + }); + arg.logo.map(|v| { + if v { + enabled.push(AuraControl::SleepLogo) + } else { + disabled.push(AuraControl::SleepLogo) + } + }); + arg.lightbar.map(|v| { + if v { + enabled.push(AuraControl::SleepBar) + } else { + disabled.push(AuraControl::SleepBar) + } + }); + if !enabled.is_empty() { + dbus.proxies().led().set_leds_enabled(enabled)?; + } + if !disabled.is_empty() { + dbus.proxies().led().set_leds_disabled(disabled)?; + } + } + aura_cli::SetAuraEnabled::Awake(arg) => { + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + arg.keyboard.map(|v| { + if v { + enabled.push(AuraControl::AwakeKeyb) + } else { + disabled.push(AuraControl::AwakeKeyb) + } + }); + arg.logo.map(|v| { + if v { + enabled.push(AuraControl::AwakeLogo) + } else { + disabled.push(AuraControl::AwakeLogo) + } + }); + arg.lightbar.map(|v| { + if v { + enabled.push(AuraControl::AwakeBar) + } else { + disabled.push(AuraControl::AwakeBar) + } + }); + if !enabled.is_empty() { + dbus.proxies().led().set_leds_enabled(enabled)?; + } + if !disabled.is_empty() { + dbus.proxies().led().set_leds_disabled(disabled)?; + } + } + aura_cli::SetAuraEnabled::Shutdown(arg) => { + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + arg.keyboard.map(|v| { + if v { + enabled.push(AuraControl::ShutdownKeyb) + } else { + disabled.push(AuraControl::ShutdownKeyb) + } + }); + arg.logo.map(|v| { + if v { + enabled.push(AuraControl::ShutdownLogo) + } else { + disabled.push(AuraControl::ShutdownLogo) + } + }); + arg.lightbar.map(|v| { + if v { + enabled.push(AuraControl::ShutdownBar) + } else { + disabled.push(AuraControl::ShutdownBar) + } + }); + if !enabled.is_empty() { + dbus.proxies().led().set_leds_enabled(enabled)?; + } + if !disabled.is_empty() { + dbus.proxies().led().set_leds_disabled(disabled)?; } } - _ => dbus - .proxies() - .led() - .set_led_mode(&::from(mode))?, } } - if let Some(enable) = mode.boot_enable { - dbus.proxies().led().set_boot_enabled(enable)?; - } - - if let Some(enable) = mode.sleep_enable { - dbus.proxies().led().set_sleep_enabled(enable)?; - } - - if let Some(enable) = mode.all_leds_enable { - dbus.proxies().led().set_all_leds_enabled(enable)?; - } - if let Some(enable) = mode.keys_leds_enable { - dbus.proxies().led().set_keys_leds_enabled(enable)?; - } - if let Some(enable) = mode.side_leds_enable { - dbus.proxies().led().set_side_leds_enabled(enable)?; - } - Ok(()) } diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index d78e20df..bfde0275 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,6 +1,7 @@ use crate::laptops::LaptopLedData; -use log::{error, info, warn}; -use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness, LedPowerStates}; +use log::{error, warn}; +use rog_aura::usb::AuraControl; +use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness}; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::fs::{File, OpenOptions}; @@ -9,83 +10,36 @@ use std::io::{Read, Write}; pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; #[derive(Deserialize, Serialize)] -pub struct AuraConfigV407 { - pub brightness: LedBrightness, - pub current_mode: AuraModeNum, - pub builtins: BTreeMap, - pub multizone: Option, - pub awake_enabled: bool, - pub sleep_anim_enabled: bool, - pub side_leds_enabled: bool, -} - -impl AuraConfigV407 { - pub(crate) fn into_current(self) -> AuraConfig { - AuraConfig { - brightness: self.brightness, - last_brightness: LedBrightness::Med, - current_mode: self.current_mode, - builtins: self.builtins, - multizone: self.multizone, - power_states: LedPowerStates { - boot_anim: true, - sleep_anim: self.sleep_anim_enabled, - all_leds: self.awake_enabled, - keys_leds: self.awake_enabled, - side_leds: self.side_leds_enabled, - }, - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct AuraConfigV411 { - pub brightness: LedBrightness, - pub current_mode: AuraModeNum, - pub builtins: BTreeMap, - pub multizone: Option, - pub power_states: LedPowerStates, -} - -impl AuraConfigV411 { - pub(crate) fn into_current(self) -> AuraConfig { - AuraConfig { - brightness: self.brightness, - last_brightness: LedBrightness::Med, - current_mode: self.current_mode, - builtins: self.builtins, - multizone: self.multizone, - power_states: self.power_states, - } - } -} - -#[derive(Deserialize, Serialize)] +#[serde(default)] pub struct AuraConfig { pub brightness: LedBrightness, - /// Used to re-set brightness on wake from sleep/hibernation - pub last_brightness: LedBrightness, pub current_mode: AuraModeNum, pub builtins: BTreeMap, - pub multizone: Option, - pub power_states: LedPowerStates, + pub multizone: Option>>, + pub enabled: Vec, } impl Default for AuraConfig { fn default() -> Self { AuraConfig { brightness: LedBrightness::Med, - last_brightness: LedBrightness::Med, current_mode: AuraModeNum::Static, builtins: BTreeMap::new(), multizone: None, - power_states: LedPowerStates { - boot_anim: true, - sleep_anim: true, - all_leds: true, - keys_leds: true, - side_leds: true, - }, + enabled: vec![ + AuraControl::BootLogo, + AuraControl::BootKeyb, + AuraControl::SleepLogo, + AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + AuraControl::AwakeBar, + AuraControl::BootBar, + AuraControl::SleepBar, + AuraControl::ShutdownBar, + ], } } } @@ -111,16 +65,6 @@ impl AuraConfig { } else { if let Ok(data) = serde_json::from_str(&buf) { return data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated AuraConfig version"); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated AuraConfig version"); - return config; } warn!( "Could not deserialise {}.\nWill rename to {}-old and recreate config", @@ -187,107 +131,27 @@ impl AuraConfig { } _ => { if let Some(multi) = self.multizone.as_mut() { - multi.set(effect) + if let Some(fx) = multi.get_mut(effect.mode()) { + for fx in fx.iter_mut() { + if fx.mode == effect.mode { + *fx = effect; + break; + } + } + } else { + let mut tmp = BTreeMap::new(); + tmp.insert(*effect.mode(), vec![effect]); + self.multizone = Some(tmp); + } } } } } - pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> { + pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect]> { if let Some(multi) = &self.multizone { - if aura_type == AuraModeNum::Static { - return Some(multi.static_()); - } else if aura_type == AuraModeNum::Breathe { - return Some(multi.breathe()); - } + return multi.get(&aura_type).map(|v| v.as_slice()); } None } } - -#[derive(Deserialize, Serialize)] -pub struct AuraMultiZone { - static_: [AuraEffect; 4], - breathe: [AuraEffect; 4], -} - -impl AuraMultiZone { - pub fn set(&mut self, effect: AuraEffect) { - if effect.mode == AuraModeNum::Static { - match effect.zone { - AuraZone::None => {} - AuraZone::One => self.static_[0] = effect, - AuraZone::Two => self.static_[1] = effect, - AuraZone::Three => self.static_[2] = effect, - AuraZone::Four => self.static_[3] = effect, - } - } else if effect.mode == AuraModeNum::Breathe { - match effect.zone { - AuraZone::None => {} - AuraZone::One => self.breathe[0] = effect, - AuraZone::Two => self.breathe[1] = effect, - AuraZone::Three => self.breathe[2] = effect, - AuraZone::Four => self.breathe[3] = effect, - } - } - } - - pub fn static_(&self) -> &[AuraEffect; 4] { - &self.static_ - } - - pub fn breathe(&self) -> &[AuraEffect; 4] { - &self.breathe - } -} - -impl Default for AuraMultiZone { - fn default() -> Self { - Self { - static_: [ - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::One, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Two, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Three, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Static, - zone: AuraZone::Four, - ..Default::default() - }, - ], - breathe: [ - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::One, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Two, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Three, - ..Default::default() - }, - AuraEffect { - mode: AuraModeNum::Breathe, - zone: AuraZone::Four, - ..Default::default() - }, - ], - } - } -} diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index 9ad66b3c..6665db8d 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -9,7 +9,7 @@ use crate::{ use async_trait::async_trait; use log::{error, info, warn}; use logind_zbus::manager::ManagerProxy; -use rog_aura::usb::leds_message; +use rog_aura::usb::AuraControl; use rog_aura::{ usb::{LED_APPLY, LED_SET}, AuraEffect, LedBrightness, LED_MSG_LEN, @@ -103,7 +103,7 @@ impl CtrlTask for CtrlKbdLedTask { // If waking up if !start { info!("CtrlKbdLedTask reloading brightness and modes"); - lock.set_brightness(lock.config.last_brightness) + lock.set_brightness(lock.config.brightness) .map_err(|e| error!("CtrlKbdLedTask: {e}")) .ok(); if let Some(mode) = lock.config.builtins.get(&lock.config.current_mode) { @@ -113,7 +113,9 @@ impl CtrlTask for CtrlKbdLedTask { } } else if start { info!("CtrlKbdLedTask saving last brightness"); - lock.config.last_brightness = lock.config.brightness; + Self::update_config(&mut lock) + .map_err(|e| error!("CtrlKbdLedTask: {e}")) + .ok(); } }; @@ -153,14 +155,14 @@ impl CtrlTask for CtrlKbdLedTask { }) .detach(); - let inner = self.inner.clone(); - self.repeating_task(500, executor, move || loop { - if let Ok(ref mut lock) = inner.try_lock() { - Self::update_config(lock).unwrap(); - break; - } - }) - .await; + // let inner = self.inner.clone(); + // self.repeating_task(500, executor, move || loop { + // if let Ok(ref mut lock) = inner.try_lock() { + // Self::update_config(lock).unwrap(); + // break; + // } + // }) + // .await; Ok(()) } } @@ -296,17 +298,11 @@ 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 = leds_message( - config.power_states.boot_anim, - config.power_states.sleep_anim, - config.power_states.all_leds, - config.power_states.keys_leds, - config.power_states.side_leds, - ); + let bytes = AuraControl::to_bytes(&config.enabled); // Quite ugly, must be a more idiomatic way to do let message = [ - 0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x5d, 0xbd, 0x01, bytes[0], bytes[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; self.write_bytes(&message)?; diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index c4847340..28fee02e 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use log::warn; -use rog_aura::{AuraEffect, LedBrightness, LedPowerStates}; +use rog_aura::{usb::AuraControl, AuraEffect, LedBrightness}; use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlKbdLedZbus; @@ -26,22 +26,26 @@ impl CtrlKbdLedZbus { } } - /// Set the keyboard LED to enabled while the device is awake - async fn set_boot_enabled( + /// Set a variety of states + async fn set_leds_enabled( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: bool, + enabled: Vec, ) { let mut states = None; if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.config.power_states.boot_anim = enabled; + for s in enabled { + if !ctrl.config.enabled.contains(&s) { + ctrl.config.enabled.push(s); + } + } ctrl.config.write(); ctrl.set_power_states(&ctrl.config) .map_err(|err| warn!("{}", err)) .ok(); - states = Some(ctrl.config.power_states); + states = Some(ctrl.config.enabled.clone()); } // Need to pull state out like this due to MutexGuard if let Some(states) = states { @@ -51,98 +55,27 @@ impl CtrlKbdLedZbus { } } - /// Set the keyboard LED suspend animation to enabled while the device is suspended - async fn set_sleep_enabled( + async fn set_leds_disabled( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: bool, + disabled: Vec, ) { let mut states = None; if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.config.power_states.sleep_anim = enabled; + for s in disabled { + if ctrl.config.enabled.contains(&s) { + if let Ok(idx) = ctrl.config.enabled.binary_search(&s) { + ctrl.config.enabled.remove(idx); + } + } + } ctrl.config.write(); ctrl.set_power_states(&ctrl.config) .map_err(|err| warn!("{}", err)) .ok(); - states = Some(ctrl.config.power_states); - } - if let Some(states) = states { - Self::notify_power_states(&ctxt, &states) - .await - .unwrap_or_else(|err| warn!("{}", err)); - } - } - - /// Set all the keyboard LEDs (keys and side) to enabled - async fn set_all_leds_enabled( - &mut self, - #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: bool, - ) { - let mut states = None; - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.config.power_states.all_leds = enabled; - ctrl.config.power_states.keys_leds = enabled; - ctrl.config.power_states.side_leds = enabled; - ctrl.config.write(); - - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{}", err)) - .ok(); - - states = Some(ctrl.config.power_states); - } - // Need to pull state out like this due to MutexGuard - if let Some(states) = states { - Self::notify_power_states(&ctxt, &states) - .await - .unwrap_or_else(|err| warn!("{}", err)); - } - } - - /// Set the keyboard keys LEDs to enabled - async fn set_keys_leds_enabled( - &mut self, - #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: bool, - ) { - let mut states = None; - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.config.power_states.keys_leds = enabled; - ctrl.config.write(); - - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{}", err)) - .ok(); - - states = Some(ctrl.config.power_states); - } - // Need to pull state out like this due to MutexGuard - if let Some(states) = states { - Self::notify_power_states(&ctxt, &states) - .await - .unwrap_or_else(|err| warn!("{}", err)); - } - } - - /// Set the keyboard side LEDs to enabled - async fn set_side_leds_enabled( - &mut self, - #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: bool, - ) { - let mut states = None; - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.config.power_states.side_leds = enabled; - ctrl.config.write(); - - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{}", err)) - .ok(); - - states = Some(ctrl.config.power_states); + states = Some(ctrl.config.enabled.clone()); } // Need to pull state out like this due to MutexGuard if let Some(states) = states { @@ -226,43 +159,11 @@ impl CtrlKbdLedZbus { } #[dbus_interface(property)] - async fn boot_enabled(&self) -> bool { + async fn leds_enabled(&self) -> Vec { if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.power_states.boot_anim; + return AuraControl::to_bytes(&ctrl.config.enabled).to_vec(); } - true - } - - #[dbus_interface(property)] - async fn sleep_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.power_states.sleep_anim; - } - true - } - - #[dbus_interface(property)] - async fn all_leds_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.power_states.all_leds; - } - true - } - - #[dbus_interface(property)] - async fn keys_leds_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.power_states.keys_leds; - } - true - } - - #[dbus_interface(property)] - fn side_leds_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.power_states.side_leds; - } - true + vec![0, 0] } /// Return the current mode data @@ -307,6 +208,6 @@ impl CtrlKbdLedZbus { #[dbus_interface(signal)] async fn notify_power_states( signal_ctxt: &SignalContext<'_>, - data: &LedPowerStates, + data: &[AuraControl], ) -> zbus::Result<()>; } 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 133768de..2a54bc49 100644 --- a/rog-aura/src/builtin_modes.rs +++ b/rog-aura/src/builtin_modes.rs @@ -11,16 +11,6 @@ use zvariant::Type; use crate::{error::Error, LED_MSG_LEN}; -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] -pub struct LedPowerStates { - pub boot_anim: bool, - pub sleep_anim: bool, - pub all_leds: bool, - pub keys_leds: bool, - pub side_leds: bool, -} - #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)] pub enum LedBrightness { @@ -148,6 +138,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,11 +220,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, - One, - Two, - Three, - Four, + /// Leftmost zone + Key1, + /// Zone after leftmost + Key2, + /// Zone second from right + Key3, + /// Rightmost zone + Key4, + /// Logo on the lid (or elsewhere?) + Logo, + /// 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: @@ -302,3 +356,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-aura/src/usb.rs b/rog-aura/src/usb.rs index 10de6c37..72719e02 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -1,6 +1,7 @@ -use crate::usb::LedCfgState::{Off, On}; -use std::convert::TryFrom; +use serde::{Deserialize, Serialize}; use std::ops::{BitAnd, BitOr}; +#[cfg(feature = "dbus")] +use zvariant::Type; pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9]; pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d @@ -12,13 +13,6 @@ pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; pub const LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -pub const BOOT_MASK: i32 = 0xc31309; -pub const SLEEP_MASK: i32 = 0x300904; -pub const ALL_LEDS_MASK: i32 = 0x000002; -pub const KBD_LEDS_MASK: i32 = 0x080000; -pub const SIDE_LEDS_MASK: i32 = 0x040500; -pub const LEDS_STATE_MASK: i32 = ALL_LEDS_MASK | KBD_LEDS_MASK | SIDE_LEDS_MASK; - /// Writes out the correct byte string for brightness pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { [ @@ -26,113 +20,152 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { ] } -#[derive(Clone, Copy)] -pub enum LedCfgState { - On = 0xffffff, - Off = 0x0, +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] +#[repr(u16)] +pub enum AuraControl { + BootLogo = 1, + BootKeyb = 1 << 1, + AwakeLogo = 1 << 2, + AwakeKeyb = 1 << 3, + SleepLogo = 1 << 4, + SleepKeyb = 1 << 5, + ShutdownLogo = 1 << 6, + ShutdownKeyb = 1 << 7, + AwakeBar = 1 << 7 + 2, + BootBar = 1 << 7 + 3, + SleepBar = 1 << 7 + 4, + ShutdownBar = 1 << 7 + 5, } -impl From for LedCfgState { - fn from(state: i32) -> Self { - match state { - 0xffffff => On, - 0x0 => Off, - _ => Off, - } +impl From for u16 { + fn from(a: AuraControl) -> Self { + a as u16 } } -impl From for LedCfgState { - fn from(state: bool) -> Self { - match state { - true => On, - false => Off, - } +impl AuraControl { + pub fn to_bytes(control: &[Self]) -> [u8; 2] { + let mut a: u16 = 0; + control.iter().for_each(|n| { + a |= *n as u16; + }); + [(a & 0xff) as u8, ((a & 0xff00) >> 8) as u8] } } -impl TryFrom<[u8; 3]> for LedCfgState { - type Error = &'static str; +impl BitOr for AuraControl { + type Output = u16; - fn try_from(value: [u8; 3]) -> Result { - match value { - [0xff, 0xff, 0xff] => Ok(On), - [0, 0, 0] => Ok(Off), - _ => Err("Unconvertible value"), - } + fn bitor(self, rhs: AuraControl) -> Self::Output { + return self as u16 | rhs as u16; } } -impl BitAnd for i32 { - type Output = i32; +impl BitAnd for AuraControl { + type Output = u16; - fn bitand(self, rhs: LedCfgState) -> i32 { - return self & rhs as i32; - } -} -impl BitOr for i32 { - type Output = i32; - - fn bitor(self, rhs: LedCfgState) -> Self::Output { - return self | rhs as i32; + fn bitand(self, rhs: AuraControl) -> Self::Output { + return self as u16 & rhs as u16; } } -impl BitOr for LedCfgState { - type Output = i32; +#[cfg(test)] +mod tests { + use crate::usb::AuraControl; - fn bitor(self, rhs: LedCfgState) -> i32 { - return self as i32 | rhs as i32; + #[test] + fn check_led_control_bytes() { + // All on + let byte1 = [ + AuraControl::BootLogo, + AuraControl::BootKeyb, + AuraControl::SleepLogo, + AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + ]; + let bytes = AuraControl::to_bytes(&byte1); + println!("{:08b}", bytes[0]); + assert_eq!(bytes[0], 0xff); + + // + let byte1 = [ + // AuraControl::BootLogo, + AuraControl::BootKeyb, + AuraControl::SleepLogo, + AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + ]; + let bytes = AuraControl::to_bytes(&byte1); + println!("{:08b}", bytes[0]); + assert_eq!(bytes[0], 0xfe); + + let byte1 = [ + AuraControl::BootLogo, + // AuraControl::BootKeyb, + AuraControl::SleepLogo, + AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + ]; + let bytes = AuraControl::to_bytes(&byte1); + println!("{:08b}", bytes[0]); + assert_eq!(bytes[0], 0xfd); + + let byte1 = [ + AuraControl::BootLogo, + AuraControl::BootKeyb, + // AuraControl::SleepLogo, + AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + ]; + let bytes = AuraControl::to_bytes(&byte1); + println!("{:08b}", bytes[0]); + assert_eq!(bytes[0], 0xef); + + let byte1 = [ + AuraControl::BootLogo, + AuraControl::BootKeyb, + AuraControl::SleepLogo, + // AuraControl::SleepKeyb, + AuraControl::AwakeLogo, + AuraControl::AwakeKeyb, + AuraControl::ShutdownLogo, + AuraControl::ShutdownKeyb, + ]; + let bytes = AuraControl::to_bytes(&byte1); + println!("{:08b}", bytes[0]); + assert_eq!(bytes[0], 0xdf); + + let byte2 = [ + AuraControl::AwakeBar, + AuraControl::BootBar, + AuraControl::SleepBar, + AuraControl::ShutdownBar, + ]; + let bytes = AuraControl::to_bytes(&byte2); + println!("{:08b}", bytes[1]); + assert_eq!(bytes[1], 0x1e); + + let byte2 = [ + AuraControl::AwakeBar, + AuraControl::BootBar, + // AuraControl::SleepBar, + AuraControl::ShutdownBar, + ]; + let bytes = AuraControl::to_bytes(&byte2); + println!("{:08b}", bytes[1]); + assert_eq!(bytes[1], 0x16); } } - -impl BitAnd for LedCfgState { - type Output = LedCfgState; - - fn bitand(self, rhs: LedCfgState) -> LedCfgState { - return (self as i32 & rhs as i32).into(); - } -} - -pub fn leds_message( - boot_state: bool, - sleep_state: bool, - all_leds_state: bool, - kbd_leds_state: bool, - side_leds_state: bool, -) -> [u8; 3] { - let raw_message = _leds_message( - boot_state.into(), - sleep_state.into(), - all_leds_state.into(), - kbd_leds_state.into(), - side_leds_state.into(), - ); - - let [_, lows @ ..] = i32::to_be_bytes(raw_message); - return lows; -} - -fn _leds_message( - boot_state: LedCfgState, - sleep_state: LedCfgState, - all_leds_state: LedCfgState, - kbd_leds_state: LedCfgState, - side_leds_state: LedCfgState, -) -> i32 { - let full_leds_state = match all_leds_state { - On => { - (ALL_LEDS_MASK & all_leds_state) - | (KBD_LEDS_MASK & kbd_leds_state) - | (SIDE_LEDS_MASK & side_leds_state) - } - Off => 0x0100 & side_leds_state, - }; - - let boot_xor_sleep = (BOOT_MASK & boot_state) ^ (SLEEP_MASK & sleep_state); - - return match (all_leds_state | kbd_leds_state | side_leds_state).into() { - On => boot_xor_sleep ^ ((boot_xor_sleep ^ full_leds_state) & LEDS_STATE_MASK), - _ => boot_xor_sleep, - }; -} diff --git a/rog-dbus/src/zbus_led.rs b/rog-dbus/src/zbus_led.rs index 3d120582..d72a900d 100644 --- a/rog-dbus/src/zbus_led.rs +++ b/rog-dbus/src/zbus_led.rs @@ -22,7 +22,7 @@ use zbus::{blocking::Connection, Result}; use zbus_macros::dbus_proxy; -use rog_aura::{AuraEffect, KeyColourArray, LedBrightness, LedPowerStates}; +use rog_aura::{usb::AuraControl, AuraEffect, KeyColourArray, LedBrightness}; const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS @@ -49,27 +49,16 @@ trait Led { /// SetLedMode method fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; - /// SetAwakeEnabled method - fn set_boot_enabled(&self, enabled: bool) -> zbus::Result<()>; + fn set_leds_enabled(&self, enabled: Vec) -> zbus::Result<()>; - /// SetSleepEnabled method - fn set_sleep_enabled(&self, enabled: bool) -> zbus::Result<()>; - - /// SetSideLedsEnabled method - fn set_all_leds_enabled(&self, enabled: bool) -> Result<()>; - - /// SetSideLedsEnabled method - fn set_keys_leds_enabled(&self, enabled: bool) -> Result<()>; - - /// SetSideLedsEnabled method - fn set_side_leds_enabled(&self, enabled: bool) -> Result<()>; + fn set_leds_disabled(&self, disabled: Vec) -> zbus::Result<()>; /// NotifyLed signal #[dbus_proxy(signal)] fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; #[dbus_proxy(signal)] - fn notify_power_states(&self, data: LedPowerStates) -> zbus::Result<()>; + fn notify_power_states(&self, data: Vec) -> zbus::Result<()>; /// LedBrightness property #[dbus_proxy(property)] @@ -84,13 +73,7 @@ trait Led { fn led_modes(&self) -> zbus::Result; #[dbus_proxy(property)] - fn awake_enabled(&self) -> zbus::Result; - - #[dbus_proxy(property)] - fn sleep_enabled(&self) -> zbus::Result; - - #[dbus_proxy(property)] - fn side_leds_enabled(&self) -> zbus::Result; + fn leds_enabled(&self) -> zbus::Result>; } pub struct LedProxyPerkey<'a>(LedProxyBlocking<'a>); 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) } }