From 02fb7addf45e21dadda3be26cf127884d63b103e Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 21 Jul 2022 14:48:16 +1200 Subject: [PATCH] Make LED power more universal Closes #219 --- asusctl/src/aura_cli.rs | 23 ++- asusctl/src/cli_opts.rs | 8 +- asusctl/src/main.rs | 250 ++++++++++++++-------------- daemon/src/ctrl_aura/config.rs | 78 +++++++-- daemon/src/ctrl_aura/controller.rs | 29 +++- daemon/src/ctrl_aura/zbus.rs | 62 +++---- rog-aura/src/usb.rs | 256 ++++++++++++++++++++--------- rog-dbus/src/zbus_led.rs | 13 +- rog-supported/src/lib.rs | 1 + 9 files changed, 436 insertions(+), 284 deletions(-) diff --git a/asusctl/src/aura_cli.rs b/asusctl/src/aura_cli.rs index 37e98415..84acddab 100644 --- a/asusctl/src/aura_cli.rs +++ b/asusctl/src/aura_cli.rs @@ -3,7 +3,23 @@ use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Directio use std::str::FromStr; #[derive(Options)] -pub struct LedPowerCommand { +pub struct LedPowerCommand1 { + #[options(help = "print help message")] + pub help: bool, + #[options(meta = "", help = "Control if LEDs enabled while awake ")] + pub awake: Option, + #[options(meta = "", help = "Use with awake option ")] + pub keyboard: Option, + #[options(meta = "", help = "Use with awake option ")] + pub lightbar: Option, + #[options(meta = "", help = "Control boot animations ")] + pub boot: Option, + #[options(meta = "", help = "Control suspend animations ")] + pub sleep: Option, +} + +#[derive(Options)] +pub struct LedPowerCommand2 { #[options(help = "print help message")] pub help: bool, #[options(command)] @@ -12,12 +28,13 @@ pub struct LedPowerCommand { #[derive(Options)] pub enum SetAuraEnabled { + /// Applies to both old and new models + #[options(help = "set to enabled while device is awake")] + Awake(AuraEnabled), #[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), } diff --git a/asusctl/src/cli_opts.rs b/asusctl/src/cli_opts.rs index 85b17182..2d98a049 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, LedPowerCommand, SetAuraBuiltin}, + aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin}, profiles_cli::{FanCurveCommand, ProfileCommand}, }; use gumdrop::Options; @@ -29,8 +29,10 @@ 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 the LED power states")] + LedPow1(LedPowerCommand1), + #[options(help = "Set the LED power states")] + LedPow2(LedPowerCommand2), #[options(help = "Set or select platform_profile")] Profile(ProfileCommand), #[options(help = "Set, select, or modify fan curves if supported")] diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index dcccc417..f31d1100 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -3,14 +3,14 @@ use std::process::Command; use std::thread::sleep; use std::{env::args, path::Path}; -use aura_cli::LedPowerCommand; +use aura_cli::{LedPowerCommand1, LedPowerCommand2}; use gumdrop::{Opt, Options}; use anime_cli::{AnimeActions, AnimeCommand}; 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::AuraControl; +use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraPowerDev}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClientBlocking; use rog_profiles::error::ProfileError; @@ -137,7 +137,8 @@ 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::LedPow1(pow)) => handle_led_power1(dbus, &supported.keyboard_led, pow)?, + Some(CliCommand::LedPow2(pow)) => handle_led_power2(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)? @@ -156,7 +157,22 @@ fn do_parsed( println!("{}", CliStart::usage()); println!(); if let Some(cmdlist) = CliStart::command_list() { - println!("{}", cmdlist); + let commands: Vec = cmdlist.lines().map(|s| s.to_string()).collect(); + for command in commands.iter().filter(|command| { + if supported.keyboard_led.prod_id != "1866" + && command.trim().starts_with("led-pow-1") + { + return false; + } + if supported.keyboard_led.prod_id != "19b6" + && command.trim().starts_with("led-pow-2") + { + return false; + } + true + }) { + println!("{}", command); + } } println!("\nExtra help can be requested on any command or subcommand:"); @@ -421,10 +437,67 @@ fn handle_led_mode( Ok(()) } -fn handle_led_power( +fn handle_led_power1( dbus: &RogDbusClientBlocking, - _supported: &LedSupportedFunctions, - power: &LedPowerCommand, + supported: &LedSupportedFunctions, + power: &LedPowerCommand1, +) -> Result<(), Box> { + if power.awake.is_none() + && power.sleep.is_none() + && power.boot.is_none() + && power.keyboard.is_none() + && power.lightbar.is_none() + { + if !power.help { + println!("Missing arg or command\n"); + } + println!("{}\n", power.self_usage()); + return Ok(()); + } + + if supported.prod_id != "1866" { + println!("These options are for keyboards of product ID 0x1866 only"); + return Ok(()); + } + + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + + let mut check = |e: Option, a: AuraDev1866| { + if let Some(arg) = e { + if arg { + enabled.push(a); + } else { + disabled.push(a); + } + } + }; + + check(power.awake, AuraDev1866::Awake); + check(power.boot, AuraDev1866::Boot); + check(power.sleep, AuraDev1866::Sleep); + check(power.keyboard, AuraDev1866::Keyboard); + check(power.lightbar, AuraDev1866::Lightbar); + + let data = AuraPowerDev { + x1866: enabled, + x19b6: vec![], + }; + dbus.proxies().led().set_leds_power(data, true)?; + + let data = AuraPowerDev { + x1866: disabled, + x19b6: vec![], + }; + dbus.proxies().led().set_leds_power(data, false)?; + + Ok(()) +} + +fn handle_led_power2( + dbus: &RogDbusClientBlocking, + supported: &LedSupportedFunctions, + power: &LedPowerCommand2, ) -> Result<(), Box> { if power.command().is_none() { if !power.help { @@ -433,7 +506,7 @@ fn handle_led_power( println!("{}\n", power.self_usage()); println!("Commands available"); - if let Some(cmdlist) = LedPowerCommand::command_list() { + if let Some(cmdlist) = LedPowerCommand2::command_list() { let commands: Vec = cmdlist.lines().map(|s| s.to_string()).collect(); for command in commands.iter() { println!("{}", command); @@ -450,133 +523,60 @@ fn handle_led_power( return Ok(()); } + if supported.prod_id == "1866" { + println!("This option does not apply to keyboards with product ID 0x1866") + } + + let mut enabled: Vec = Vec::new(); + let mut disabled: Vec = Vec::new(); + let mut check = |e: Option, a: AuraDev19b6| { + if let Some(arg) = e { + if arg { + enabled.push(a); + } else { + disabled.push(a); + } + } + }; + 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)?; - } + check(arg.keyboard, AuraDev19b6::BootKeyb); + check(arg.logo, AuraDev19b6::BootLogo); + check(arg.lightbar, AuraDev19b6::BootBar); } 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)?; - } + check(arg.keyboard, AuraDev19b6::SleepKeyb); + check(arg.logo, AuraDev19b6::SleepLogo); + check(arg.lightbar, AuraDev19b6::SleepBar); } 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)?; - } + check(arg.keyboard, AuraDev19b6::AwakeKeyb); + check(arg.logo, AuraDev19b6::AwakeLogo); + check(arg.lightbar, AuraDev19b6::AwakeBar); } 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)?; - } + check(arg.keyboard, AuraDev19b6::ShutdownKeyb); + check(arg.logo, AuraDev19b6::ShutdownLogo); + check(arg.lightbar, AuraDev19b6::ShutdownBar); } } + + if !enabled.is_empty() { + let data = AuraPowerDev { + x1866: vec![], + x19b6: enabled, + }; + dbus.proxies().led().set_leds_power(data, true)?; + } + + if !disabled.is_empty() { + let data = AuraPowerDev { + x1866: vec![], + x19b6: disabled, + }; + dbus.proxies().led().set_leds_power(data, false)?; + } } Ok(()) diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index a4756a24..2ae6feda 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,6 +1,6 @@ use crate::laptops::LaptopLedData; use log::{error, warn}; -use rog_aura::usb::AuraControl; +use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraPowerDev}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; @@ -9,6 +9,65 @@ use std::io::{Read, Write}; pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; +/// Enable/disable LED control in various states such as +/// when the device is awake, suspended, shutting down or +/// booting. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum AuraPowerConfig { + AuraDev1866(HashSet), + AuraDev19b6(HashSet), +} + +impl AuraPowerConfig { + pub fn to_bytes(control: &Self) -> [u8; 3] { + match control { + AuraPowerConfig::AuraDev1866(c) => { + let c: Vec = c.iter().map(|v| *v).collect(); + AuraDev1866::to_bytes(&c) + } + AuraPowerConfig::AuraDev19b6(c) => { + let c: Vec = c.iter().map(|v| *v).collect(); + AuraDev19b6::to_bytes(&c) + } + } + } + + pub fn set_0x1866(&mut self, power: AuraDev1866, on: bool) { + if let Self::AuraDev1866(p) = self { + if on { + p.insert(power); + } else { + p.remove(&power); + } + } + } + + pub fn set_0x19b6(&mut self, power: AuraDev19b6, on: bool) { + if let Self::AuraDev19b6(p) = self { + if on { + p.insert(power); + } else { + p.remove(&power); + } + } + } +} + +impl From<&AuraPowerConfig> for AuraPowerDev { + fn from(config: &AuraPowerConfig) -> Self { + match config { + AuraPowerConfig::AuraDev1866(d) => AuraPowerDev { + x1866: d.iter().map(|o| *o).collect(), + x19b6: vec![], + }, + AuraPowerConfig::AuraDev19b6(d) => AuraPowerDev { + x1866: vec![], + x19b6: d.iter().map(|o| *o).collect(), + }, + } + } +} + #[derive(Deserialize, Serialize)] #[serde(default)] pub struct AuraConfig { @@ -17,7 +76,7 @@ pub struct AuraConfig { pub builtins: BTreeMap, pub multizone: Option>>, pub multizone_on: bool, - pub enabled: HashSet, + pub enabled: AuraPowerConfig, } impl Default for AuraConfig { @@ -28,20 +87,7 @@ impl Default for AuraConfig { builtins: BTreeMap::new(), multizone: None, multizone_on: false, - enabled: HashSet::from([ - AuraControl::BootLogo, - AuraControl::BootKeyb, - AuraControl::SleepLogo, - AuraControl::SleepKeyb, - AuraControl::AwakeLogo, - AuraControl::AwakeKeyb, - AuraControl::ShutdownLogo, - AuraControl::ShutdownKeyb, - AuraControl::AwakeBar, - AuraControl::BootBar, - AuraControl::SleepBar, - AuraControl::ShutdownBar, - ]), + enabled: AuraPowerConfig::AuraDev1866(HashSet::new()), } } } diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index f72d032f..e47e2f5d 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -9,11 +9,11 @@ use crate::{ use async_trait::async_trait; use log::{error, info, warn}; use logind_zbus::manager::ManagerProxy; -use rog_aura::{usb::AuraControl, AuraZone, Direction, Speed, GRADIENT}; use rog_aura::{ usb::{LED_APPLY, LED_SET}, AuraEffect, LedBrightness, LED_MSG_LEN, }; +use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; use rog_supported::LedSupportedFunctions; use smol::{stream::StreamExt, Executor}; use std::path::Path; @@ -28,7 +28,7 @@ use zbus::Connection; use crate::GetSupported; -use super::config::AuraConfig; +use super::config::{AuraConfig, AuraPowerConfig}; impl GetSupported for CtrlKbdLed { type A = LedSupportedFunctions; @@ -40,7 +40,16 @@ impl GetSupported for CtrlKbdLed { let multizone_led_mode = laptop.multizone; let per_key_led_mode = laptop.per_key; + let mut prod_id = String::new(); + for prod in ASUS_KEYBOARD_DEVICES.iter() { + if let Ok(_) = Self::find_led_node(prod) { + prod_id = prod.to_string(); + break; + } + } + LedSupportedFunctions { + prod_id, brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), stock_led_modes, multizone_led_mode, @@ -50,6 +59,8 @@ impl GetSupported for CtrlKbdLed { } 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 bright_node: String, pub supported_modes: LaptopLedData, @@ -184,10 +195,12 @@ 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() { match Self::find_led_node(prod) { Ok(node) => { + led_prod = Some(prod.to_string()); led_node = Some(node); info!("Looked for keyboard controller 0x{prod}: Found"); break; @@ -209,6 +222,7 @@ impl CtrlKbdLed { } let ctrl = CtrlKbdLed { + led_prod, led_node, bright_node: bright_node.unwrap(), // If was none then we already returned above supported_modes, @@ -282,12 +296,8 @@ 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 set: Vec = config.enabled.iter().map(|v| *v).collect(); - let bytes = AuraControl::to_bytes(&set); - - let message = [ - 0x5d, 0xbd, 0x01, bytes[0], bytes[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + 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)?; @@ -511,6 +521,7 @@ mod tests { per_key: false, }; let mut controller = CtrlKbdLed { + led_prod: None, led_node: None, bright_node: String::new(), supported_modes, @@ -572,6 +583,7 @@ mod tests { per_key: false, }; let mut controller = CtrlKbdLed { + led_prod: None, led_node: None, bright_node: String::new(), supported_modes, @@ -608,6 +620,7 @@ mod tests { per_key: false, }; let mut controller = CtrlKbdLed { + led_prod: None, led_node: None, bright_node: String::new(), supported_modes, diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 893c85e5..041913a1 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::{usb::AuraControl, AuraEffect, LedBrightness}; +use rog_aura::{usb::AuraPowerDev, AuraEffect, LedBrightness}; use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlKbdLedZbus; @@ -42,16 +42,21 @@ impl CtrlKbdLedZbus { /// SleepBar, /// ShutdownBar, /// } - async fn set_leds_enabled( + async fn set_leds_power( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, - enabled: Vec, + options: AuraPowerDev, + enabled: bool, ) -> zbus::fdo::Result<()> { let mut states = None; if let Ok(mut ctrl) = self.0.try_lock() { - for s in enabled { - ctrl.config.enabled.insert(s); + for p in options.x1866 { + ctrl.config.enabled.set_0x1866(p, enabled); } + for p in options.x19b6 { + ctrl.config.enabled.set_0x19b6(p, enabled); + } + ctrl.config.write(); ctrl.set_power_states(&ctrl.config).map_err(|e| { @@ -59,37 +64,7 @@ impl CtrlKbdLedZbus { e })?; - let set: Vec = ctrl.config.enabled.iter().map(|v| *v).collect(); - states = Some(set); - } - // 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)); - } - Ok(()) - } - - async fn set_leds_disabled( - &mut self, - #[zbus(signal_context)] ctxt: SignalContext<'_>, - disabled: Vec, - ) -> zbus::fdo::Result<()> { - let mut states = None; - if let Ok(mut ctrl) = self.0.try_lock() { - for s in disabled { - ctrl.config.enabled.remove(&s); - } - ctrl.config.write(); - - ctrl.set_power_states(&ctrl.config).map_err(|e| { - warn!("{}", e); - e - })?; - - let set: Vec = ctrl.config.enabled.iter().map(|v| *v).collect(); - states = Some(set); + states = Some(AuraPowerDev::from(&ctrl.config.enabled)); } // Need to pull state out like this due to MutexGuard if let Some(states) = states { @@ -189,13 +164,14 @@ impl CtrlKbdLedZbus { Ok(()) } - #[dbus_interface(property)] - async fn leds_enabled(&self) -> Vec { - if let Ok(ctrl) = self.0.try_lock() { - let set: Vec = ctrl.config.enabled.iter().map(|v| *v).collect(); - return AuraControl::to_bytes(&set).to_vec(); + // As property doesn't work for AuraPowerDev (complexity of serialization?) + // #[dbus_interface(property)] + async fn leds_power(&self) -> AuraPowerDev { + loop { + if let Ok(ctrl) = self.0.try_lock() { + return AuraPowerDev::from(&ctrl.config.enabled); + } } - vec![0, 0] } /// Return the current mode data @@ -240,6 +216,6 @@ impl CtrlKbdLedZbus { #[dbus_interface(signal)] async fn notify_power_states( signal_ctxt: &SignalContext<'_>, - data: &[AuraControl], + data: &AuraPowerDev, ) -> zbus::Result<()>; } diff --git a/rog-aura/src/usb.rs b/rog-aura/src/usb.rs index ea08bc03..c53be464 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -20,16 +20,85 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { ] } -/// Enable/disable LED control in various states such as -/// when the device is awake, suspended, shutting down or -/// booting. +/// 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)] +pub struct AuraPowerDev { + pub x1866: Vec, + pub x19b6: Vec, +} + +/// # Bits for older 0x1866 keyboard model /// +/// Keybord and Lightbar require Awake, Boot and Sleep apply to both +/// Keybord and Lightbar regardless of if either are enabled (or Awake is enabled) +/// +/// | Byte 1 | Byte 2 | Byte 3 | function | hex | +/// |------------|------------|------------|----------|----------| +/// | 0000, 0000 | 0000, 0000 | 0000, 0010 | Awake | 00,00,02 | +/// | 0000, 1000 | 0000, 0000 | 0000, 0000 | Keyboard | 08,00,00 | +/// | 0000, 0100 | 0000, 0101 | 0000, 0000 | Lightbar | 04,05,00 | +/// | 1100, 0011 | 0001, 0010 | 0000, 1001 | Boot/Sht | c3,12,09 | +/// | 0011, 0000 | 0000, 1000 | 0000, 0100 | Sleep | 30,08,04 | +/// | 1111, 1111 | 0001, 1111 | 0000, 1111 | all on | | +/// +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum AuraDev1866 { + Awake = 0x000002, + Keyboard = 0x080000, + Lightbar = 0x040500, + Boot = 0xc31209, + Sleep = 0x300804, +} + +impl From for u32 { + fn from(a: AuraDev1866) -> Self { + a as u32 + } +} + +impl AuraDev1866 { + pub fn to_bytes(control: &[Self]) -> [u8; 3] { + let mut a: u32 = 0; + control.iter().for_each(|n| { + a |= *n as u32; + }); + [ + ((a & 0xff0000) >> 16) as u8, + ((a & 0xff00) >> 8) as u8, + (a & 0xff) as u8, + ] + } + + pub const fn dev_id() -> &'static str { + "0x1866" + } +} + +impl BitOr for AuraDev1866 { + type Output = u32; + + fn bitor(self, rhs: AuraDev1866) -> Self::Output { + return self as u32 | rhs as u32; + } +} + +impl BitAnd for AuraDev1866 { + type Output = u32; + + fn bitand(self, rhs: AuraDev1866) -> Self::Output { + return self as u32 & rhs as u32; + } +} + /// # Bits for 0x19b6 keyboard model /// -/// ```text /// byte 4 in the USB packet is for keyboard + logo power states /// default is on, `ff` /// Keyboard and logo use the full range of bits (almost) +/// /// | n1 | n2 | hex | action | bit | /// |------|------|-----|-----------------------|-------| /// | 0000 | 0000 | 00 | all off | | @@ -43,6 +112,7 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { /// | 1000 | 0000 | 80 | keyboard shutdown off | bit 8 | /// /// byte 5 = lightbar +/// /// | 1 | 2 | hex | action | bit | /// |------|------|-----|----------------------|-------| /// | 0000 | 0010 | 02 | lightbar off boot | bit 2 | @@ -50,23 +120,10 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { /// | 0000 | 1000 | 08 | lightbar off sleep | bit 4 | /// | 0001 | 0000 | 10 | lightbar shtdn off | bit 5 | /// -/// # Bits for older 0x1866 keyboard model -/// -/// Keybord and Light zone require Awake -/// | byte 1 | byte 2 | byte 3 | | | -/// | 1 | 2 | 3 | 4 | 5 | 6 | function | hex | -/// |------|------|------|------|------|------|----------|----------| -/// | 0000 | 0000 | 0000 | 0000 | 0000 | 0010 | Awake | 00,00,02 | -/// | 1000 | 0000 | 0000 | 0000 | 0000 | 0000 | Keyboard | 80,00,00 | -/// | 0000 | 0100 | 0000 | 0101 | 0000 | 0000 | Lightbar | 04,05,00 | -/// | 0100 | 0011 | 0001 | 0010 | 0000 | 1001 | Boot/Sht | c3,12,09 | -/// | 0011 | 0000 | 0000 | 1000 | 0000 | 0100 | Sleep | 30,08,04 | -/// | 0000 | 1000 | 0000 | 0000 | 0000 | 0000 | Unsure | 08,00,00 | -/// The last row in the table seems to apply only when all are on #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] #[repr(u16)] -pub enum AuraControl { +pub enum AuraDev19b6 { BootLogo = 1, BootKeyb = 1 << 1, AwakeLogo = 1 << 2, @@ -81,133 +138,174 @@ pub enum AuraControl { ShutdownBar = 1 << 7 + 5, } -impl From for u16 { - fn from(a: AuraControl) -> Self { +impl From for u16 { + fn from(a: AuraDev19b6) -> Self { a as u16 } } -impl AuraControl { - pub fn to_bytes(control: &[Self]) -> [u8; 2] { +impl AuraDev19b6 { + pub fn to_bytes(control: &[Self]) -> [u8; 3] { let mut a: u16 = 0; control.iter().for_each(|n| { a |= *n as u16; }); - [(a & 0xff) as u8, ((a & 0xff00) >> 8) as u8] + [(a & 0xff) as u8, ((a & 0xff00) >> 8) as u8, 0x00] + } + + pub const fn dev_id() -> &'static str { + "0x196b" } } -impl BitOr for AuraControl { +impl BitOr for AuraDev19b6 { type Output = u16; - fn bitor(self, rhs: AuraControl) -> Self::Output { + fn bitor(self, rhs: AuraDev19b6) -> Self::Output { return self as u16 | rhs as u16; } } -impl BitAnd for AuraControl { +impl BitAnd for AuraDev19b6 { type Output = u16; - fn bitand(self, rhs: AuraControl) -> Self::Output { + fn bitand(self, rhs: AuraDev19b6) -> Self::Output { return self as u16 & rhs as u16; } } #[cfg(test)] mod tests { - use crate::usb::AuraControl; + use crate::usb::AuraDev19b6; + + use super::AuraDev1866; #[test] - fn check_led_control_bytes() { + fn check_0x1866_control_bytes() { + let bytes = [AuraDev1866::Keyboard, AuraDev1866::Awake]; + let bytes = AuraDev1866::to_bytes(&bytes); + println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); + assert_eq!(bytes, [0x08, 0x00, 0x02]); + + let bytes = [AuraDev1866::Lightbar, AuraDev1866::Awake]; + let bytes = AuraDev1866::to_bytes(&bytes); + println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); + assert_eq!(bytes, [0x04, 0x05, 0x02]); + + let bytes = [AuraDev1866::Sleep]; + let bytes = AuraDev1866::to_bytes(&bytes); + println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); + assert_eq!(bytes, [0x30, 0x08, 0x04]); + + let bytes = [AuraDev1866::Boot]; + let bytes = AuraDev1866::to_bytes(&bytes); + println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); + assert_eq!(bytes, [0xc3, 0x12, 0x09]); + + let bytes = [ + AuraDev1866::Keyboard, + AuraDev1866::Lightbar, + AuraDev1866::Awake, + AuraDev1866::Sleep, + AuraDev1866::Boot, + ]; + + let bytes = AuraDev1866::to_bytes(&bytes); + println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); + assert_eq!(bytes, [0xff, 0x1f, 0x000f]); + } + + #[test] + fn check_0x19b6_control_bytes() { // All on let byte1 = [ - AuraControl::BootLogo, - AuraControl::BootKeyb, - AuraControl::SleepLogo, - AuraControl::SleepKeyb, - AuraControl::AwakeLogo, - AuraControl::AwakeKeyb, - AuraControl::ShutdownLogo, - AuraControl::ShutdownKeyb, + AuraDev19b6::BootLogo, + AuraDev19b6::BootKeyb, + AuraDev19b6::SleepLogo, + AuraDev19b6::SleepKeyb, + AuraDev19b6::AwakeLogo, + AuraDev19b6::AwakeKeyb, + AuraDev19b6::ShutdownLogo, + AuraDev19b6::ShutdownKeyb, ]; - let bytes = AuraControl::to_bytes(&byte1); + let bytes = AuraDev19b6::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, + AuraDev19b6::BootKeyb, + AuraDev19b6::SleepLogo, + AuraDev19b6::SleepKeyb, + AuraDev19b6::AwakeLogo, + AuraDev19b6::AwakeKeyb, + AuraDev19b6::ShutdownLogo, + AuraDev19b6::ShutdownKeyb, ]; - let bytes = AuraControl::to_bytes(&byte1); + let bytes = AuraDev19b6::to_bytes(&byte1); println!("{:08b}", bytes[0]); assert_eq!(bytes[0], 0xfe); let byte1 = [ - AuraControl::BootLogo, + AuraDev19b6::BootLogo, // AuraControl::BootKeyb, - AuraControl::SleepLogo, - AuraControl::SleepKeyb, - AuraControl::AwakeLogo, - AuraControl::AwakeKeyb, - AuraControl::ShutdownLogo, - AuraControl::ShutdownKeyb, + AuraDev19b6::SleepLogo, + AuraDev19b6::SleepKeyb, + AuraDev19b6::AwakeLogo, + AuraDev19b6::AwakeKeyb, + AuraDev19b6::ShutdownLogo, + AuraDev19b6::ShutdownKeyb, ]; - let bytes = AuraControl::to_bytes(&byte1); + let bytes = AuraDev19b6::to_bytes(&byte1); println!("{:08b}", bytes[0]); assert_eq!(bytes[0], 0xfd); let byte1 = [ - AuraControl::BootLogo, - AuraControl::BootKeyb, + AuraDev19b6::BootLogo, + AuraDev19b6::BootKeyb, // AuraControl::SleepLogo, - AuraControl::SleepKeyb, - AuraControl::AwakeLogo, - AuraControl::AwakeKeyb, - AuraControl::ShutdownLogo, - AuraControl::ShutdownKeyb, + AuraDev19b6::SleepKeyb, + AuraDev19b6::AwakeLogo, + AuraDev19b6::AwakeKeyb, + AuraDev19b6::ShutdownLogo, + AuraDev19b6::ShutdownKeyb, ]; - let bytes = AuraControl::to_bytes(&byte1); + let bytes = AuraDev19b6::to_bytes(&byte1); println!("{:08b}", bytes[0]); assert_eq!(bytes[0], 0xef); let byte1 = [ - AuraControl::BootLogo, - AuraControl::BootKeyb, - AuraControl::SleepLogo, + AuraDev19b6::BootLogo, + AuraDev19b6::BootKeyb, + AuraDev19b6::SleepLogo, // AuraControl::SleepKeyb, - AuraControl::AwakeLogo, - AuraControl::AwakeKeyb, - AuraControl::ShutdownLogo, - AuraControl::ShutdownKeyb, + AuraDev19b6::AwakeLogo, + AuraDev19b6::AwakeKeyb, + AuraDev19b6::ShutdownLogo, + AuraDev19b6::ShutdownKeyb, ]; - let bytes = AuraControl::to_bytes(&byte1); + let bytes = AuraDev19b6::to_bytes(&byte1); println!("{:08b}", bytes[0]); assert_eq!(bytes[0], 0xdf); let byte2 = [ - AuraControl::AwakeBar, - AuraControl::BootBar, - AuraControl::SleepBar, - AuraControl::ShutdownBar, + AuraDev19b6::AwakeBar, + AuraDev19b6::BootBar, + AuraDev19b6::SleepBar, + AuraDev19b6::ShutdownBar, ]; - let bytes = AuraControl::to_bytes(&byte2); + let bytes = AuraDev19b6::to_bytes(&byte2); println!("{:08b}", bytes[1]); assert_eq!(bytes[1], 0x1e); let byte2 = [ - AuraControl::AwakeBar, - AuraControl::BootBar, + AuraDev19b6::AwakeBar, + AuraDev19b6::BootBar, // AuraControl::SleepBar, - AuraControl::ShutdownBar, + AuraDev19b6::ShutdownBar, ]; - let bytes = AuraControl::to_bytes(&byte2); + let bytes = AuraDev19b6::to_bytes(&byte2); println!("{:08b}", bytes[1]); assert_eq!(bytes[1], 0x16); } diff --git a/rog-dbus/src/zbus_led.rs b/rog-dbus/src/zbus_led.rs index d72a900d..e6db6880 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::{usb::AuraControl, AuraEffect, KeyColourArray, LedBrightness}; +use rog_aura::{usb::AuraPowerDev, AuraEffect, KeyColourArray, LedBrightness}; const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS @@ -49,16 +49,14 @@ trait Led { /// SetLedMode method fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; - fn set_leds_enabled(&self, enabled: Vec) -> zbus::Result<()>; - - fn set_leds_disabled(&self, disabled: Vec) -> zbus::Result<()>; + fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>; /// NotifyLed signal #[dbus_proxy(signal)] fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; #[dbus_proxy(signal)] - fn notify_power_states(&self, data: Vec) -> zbus::Result<()>; + fn notify_power_states(&self, data: AuraPowerDev) -> zbus::Result<()>; /// LedBrightness property #[dbus_proxy(property)] @@ -72,8 +70,9 @@ trait Led { #[dbus_proxy(property)] fn led_modes(&self) -> zbus::Result; - #[dbus_proxy(property)] - fn leds_enabled(&self) -> zbus::Result>; + // As property doesn't work for AuraPowerDev (complexity of serialization?) + // #[dbus_proxy(property)] + 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 3de399e6..eb57e7e2 100644 --- a/rog-supported/src/lib.rs +++ b/rog-supported/src/lib.rs @@ -30,6 +30,7 @@ pub struct PlatformProfileFunctions { #[derive(Serialize, Deserialize, Type, Debug)] pub struct LedSupportedFunctions { + pub prod_id: String, pub brightness_set: bool, pub stock_led_modes: Vec, pub multizone_led_mode: Vec,