diff --git a/CHANGELOG.md b/CHANGELOG.md index 05dc6056..82d1d861 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 from vfio/integrated/compute. - Add asusd config option to not save compute/vfio mode switch. - Enable basic multiple user anime configs (asusd-user must still be restarted) +- Keyboard LED control now includes: + + Enable/disable LED's while laptop is awake + + Enable/disable LED animation while laptop is suspended and AC plugged in # [3.4.1] - 2021-04-11 ### Changed diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 7761779a..545e5d94 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -5,7 +5,7 @@ use crate::aura_cli::{LedBrightness, SetAuraBuiltin}; use anime_cli::{AnimeActions, AnimeCommand}; use gumdrop::{Opt, Options}; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; -use rog_aura::{self, AuraEffect, AuraModeNum}; +use rog_aura::{self, AuraEffect}; use rog_dbus::AuraDbusClient; use rog_types::{ gfx_vendors::GfxVendors, @@ -62,6 +62,16 @@ struct LedModeCommand { next_mode: bool, #[options(help = "switch to previous aura mode")] prev_mode: bool, + #[options( + meta = "", + help = "set the keyboard LED to enabled while the device is awake" + )] + awake_enable: Option, + #[options( + meta = "", + help = "set the keyboard LED suspend animation to enabled while the device is suspended" + )] + sleep_enable: Option, #[options(command)] command: Option, } @@ -335,7 +345,12 @@ fn handle_led_mode( supported: &LedSupportedFunctions, mode: &LedModeCommand, ) -> Result<(), Box> { - if mode.command.is_none() && !mode.prev_mode && !mode.next_mode { + if mode.command.is_none() + && !mode.prev_mode + && !mode.next_mode + && mode.sleep_enable.is_none() + && mode.awake_enable.is_none() + { if !mode.help { println!("Missing arg or command\n"); } @@ -347,9 +362,13 @@ fn handle_led_mode( .lines() .map(|s| s.to_string()) .collect(); - for command in commands.iter().filter(|mode| { + for command in commands.iter().filter(|command| { if let Some(modes) = supported.stock_led_modes.as_ref() { - return modes.contains(&::from(mode.as_str())); + for mode in modes { + if command.contains(&(<&str>::from(mode)).to_lowercase()) { + return true; + } + } } if supported.multizone_led_mode { return true; @@ -389,6 +408,15 @@ fn handle_led_mode( .set_led_mode(&::from(mode))?, } } + + if let Some(enable) = mode.awake_enable { + dbus.proxies().led().set_awake_enabled(enable)?; + } + + if let Some(enable) = mode.sleep_enable { + dbus.proxies().led().set_sleep_enabled(enable)?; + } + Ok(()) } diff --git a/daemon/src/ctrl_leds.rs b/daemon/src/ctrl_leds.rs index 80d2c128..918edc2a 100644 --- a/daemon/src/ctrl_leds.rs +++ b/daemon/src/ctrl_leds.rs @@ -7,10 +7,7 @@ use crate::{ laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, }; use log::{error, info, warn}; -use rog_aura::{ - usb::{LED_APPLY, LED_SET}, - AuraEffect, LedBrightness, LED_MSG_LEN, -}; +use rog_aura::{AuraEffect, LED_MSG_LEN, LedBrightness, usb::{LED_APPLY, LED_AWAKE_OFF, LED_AWAKE_ON, LED_SET, LED_SLEEP_OFF, LED_SLEEP_ON}}; use rog_types::supported::LedSupportedFunctions; use std::fs::OpenOptions; use std::io::{Read, Write}; @@ -124,6 +121,7 @@ impl crate::ZbusAdd for CtrlKbdLedZbus { /// LED commands are split between Brightness, Modes, Per-Key #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlKbdLedZbus { + /// Set the keyboard brightness level (0-3) fn set_brightness(&mut self, brightness: LedBrightness) { if let Ok(ctrl) = self.inner.try_lock() { ctrl.set_brightness(brightness) @@ -132,6 +130,24 @@ impl CtrlKbdLedZbus { } } + /// Set the keyboard LED to enabled while the device is awake + fn set_awake_enabled(&mut self, enabled: bool) { + if let Ok(ctrl) = self.inner.try_lock() { + ctrl.set_awake_enable(enabled) + .map_err(|err| warn!("{}", err)) + .ok(); + } + } + + /// Set the keyboard LED suspend animation to enabled while the device is suspended + fn set_sleep_enabled(&mut self, enabled: bool) { + if let Ok(ctrl) = self.inner.try_lock() { + ctrl.set_sleep_anim_enable(enabled) + .map_err(|err| warn!("{}", err)) + .ok(); + } + } + fn set_led_mode(&mut self, effect: AuraEffect) { if let Ok(mut ctrl) = self.inner.try_lock() { let mode_name = effect.mode_name(); @@ -261,7 +277,7 @@ impl CtrlKbdLed { None } - pub fn get_brightness(&self) -> Result { + fn get_brightness(&self) -> Result { let mut file = OpenOptions::new() .read(true) .open(&self.bright_node) @@ -277,7 +293,7 @@ impl CtrlKbdLed { Ok(buf[0]) } - pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> { + fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> { let path = Path::new(&self.bright_node); let mut file = OpenOptions::new() @@ -294,6 +310,34 @@ impl CtrlKbdLed { Ok(()) } + /// Set the keyboard LED to active if laptop is awake + fn set_awake_enable(&self, enabled: bool) -> Result<(), RogError> { + let bytes = if enabled { + LED_AWAKE_ON + } else { + LED_AWAKE_OFF + }; + self.write_bytes(&bytes)?; + self.write_bytes(&LED_SET)?; + // Changes won't persist unless apply is set + self.write_bytes(&LED_APPLY)?; + Ok(()) + } + + /// Set the keyboard suspend animation to on if plugged in + fn set_sleep_anim_enable(&self, enabled: bool) -> Result<(), RogError> { + let bytes = if enabled { + LED_SLEEP_ON + } else { + LED_SLEEP_OFF + }; + self.write_bytes(&bytes)?; + self.write_bytes(&LED_SET)?; + // Changes won't persist unless apply is set + self.write_bytes(&LED_APPLY)?; + Ok(()) + } + fn find_led_node(id_product: &str) -> Result { let mut enumerator = udev::Enumerator::new().map_err(|err| { warn!("{}", err); diff --git a/rog-aura/src/usb.rs b/rog-aura/src/usb.rs index f948adb3..c87fff54 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -14,3 +14,23 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { 0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] } + +/// Enable the keyboard when laptop is awake +pub const LED_AWAKE_ON: [u8; 17] = [ + 0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// Disable the keyboard when laptop is awake +pub const LED_AWAKE_OFF: [u8; 17] = [ + 0x5d, 0xbd, 0x01, 0xc3, 0x13, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// Enable animations when the laptop is suspended while plugged in +pub const LED_SLEEP_ON: [u8; 17] = [ + 0x5d, 0xbd, 0x01, 0xff, 0x1f, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// Disable animations when the laptop is suspended while plugged in +pub const LED_SLEEP_OFF: [u8; 17] = [ + 0x5d, 0xbd, 0x01, 0xcf, 0x17, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; \ No newline at end of file diff --git a/rog-dbus/src/zbus_led.rs b/rog-dbus/src/zbus_led.rs index f7c12e18..047ae2e4 100644 --- a/rog-dbus/src/zbus_led.rs +++ b/rog-dbus/src/zbus_led.rs @@ -44,7 +44,12 @@ trait Daemon { /// SetLedMode method fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; - /// NotifyLed signal + /// SetAwakeEnabled method + fn set_awake_enabled(&self, enabled: bool) -> zbus::Result<()>; + + /// SetSleepEnabled method + fn set_sleep_enabled(&self, enabled: bool) -> zbus::Result<()>; + /// NotifyLed signal #[dbus_proxy(signal)] fn notify_led(&self, data: &str) -> zbus::Result<()>; @@ -85,6 +90,20 @@ impl<'a> LedProxy<'a> { Ok(()) } + /// Set the keyboard LED to enabled while the device is awake + #[inline] + pub fn set_awake_enabled(&self, enabled: bool) -> Result<()> { + self.0.set_awake_enabled(enabled)?; + Ok(()) + } + + /// Set the keyboard LED suspend animation to enabled while the device is suspended + #[inline] + pub fn set_sleep_enabled(&self, enabled: bool) -> Result<()> { + self.0.set_sleep_enabled(enabled)?; + Ok(()) + } + #[inline] pub fn next_led_mode(&self) -> Result<()> { self.0.next_led_mode()