diff --git a/CHANGELOG.md b/CHANGELOG.md index 63153fa4..1fcf7673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased ] +### Added +- Add panel overdrive support (autodetects if supported) +- Add detection of dgpu_disable and egpu_enable for diagnostic +### Changed +- Fixed save and restore of multizone LED settings + ## [4.2.0] - 2022-07-16 ### Added - Support for GA402 Anime Matrix display (Author: I-Al-Istannen & Luke Jones) diff --git a/Cargo.lock b/Cargo.lock index 6be3078d..1c578a21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ dependencies = [ [[package]] name = "asusctl" -version = "4.0.7" +version = "4.2.1" dependencies = [ "daemon", "gif", @@ -278,7 +278,7 @@ dependencies = [ [[package]] name = "daemon" -version = "4.2.0" +version = "4.2.1" dependencies = [ "async-trait", "env_logger", @@ -1034,7 +1034,7 @@ dependencies = [ [[package]] name = "rog_aura" -version = "1.1.1" +version = "1.1.2" dependencies = [ "serde", "serde_derive", @@ -1067,7 +1067,7 @@ dependencies = [ [[package]] name = "rog_supported" -version = "4.0.0" +version = "4.2.0" dependencies = [ "rog_aura", "serde", diff --git a/asusctl/Cargo.toml b/asusctl/Cargo.toml index 735a0cf3..1a72d092 100644 --- a/asusctl/Cargo.toml +++ b/asusctl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "asusctl" -version = "4.0.7" +version = "4.2.1" authors = ["Luke D Jones "] edition = "2018" diff --git a/asusctl/src/cli_opts.rs b/asusctl/src/cli_opts.rs index 21a31194..85b17182 100644 --- a/asusctl/src/cli_opts.rs +++ b/asusctl/src/cli_opts.rs @@ -67,18 +67,29 @@ pub struct BiosCommand { pub help: bool, #[options( meta = "", + short = "S", no_long, help = "set bios POST sound: asusctl -p " )] pub post_sound_set: Option, - #[options(no_long, help = "read bios POST sound")] + #[options(no_long, short = "s", help = "read bios POST sound")] pub post_sound_get: bool, #[options( meta = "", + short = "D", no_long, help = "activate dGPU dedicated/G-Sync: asusctl -d , reboot required" )] pub dedicated_gfx_set: Option, - #[options(no_long, help = "get GPU mode")] + #[options(no_long, short = "d", help = "get GPU mode")] pub dedicated_gfx_get: bool, + #[options( + meta = "", + short = "O", + no_long, + help = "Set device panel overdrive " + )] + pub panel_overdrive_set: Option, + #[options(no_long, short = "o", help = "get panel overdrive")] + pub panel_overdrive_get: bool, } diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index e4adad81..ed1d6c6a 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -167,6 +167,10 @@ fn do_parsed( if let Some(cmdlist) = CliStart::command_list() { println!("{}", cmdlist); } + + println!("\nExtra help can be requested on any command or subcommand:"); + println!(" asusctl led-mode --help"); + println!(" asusctl led-mode static --help"); } } } @@ -692,7 +696,9 @@ fn handle_bios_option( if (cmd.dedicated_gfx_set.is_none() && !cmd.dedicated_gfx_get && cmd.post_sound_set.is_none() - && !cmd.post_sound_get) + && !cmd.post_sound_get + && cmd.panel_overdrive_set.is_none() + && !cmd.panel_overdrive_get) || cmd.help { println!("Missing arg or command\n"); @@ -703,8 +709,9 @@ fn handle_bios_option( .collect(); for line in usage.iter().filter(|line| { - line.contains("sound") && supported.post_sound_toggle - || line.contains("GPU") && supported.dedicated_gfx_toggle + line.contains("sound") && supported.post_sound + || line.contains("GPU") && supported.dedicated_gfx + || line.contains("panel") && supported.panel_overdrive }) { println!("{}", line); } @@ -717,6 +724,7 @@ fn handle_bios_option( let res = dbus.proxies().rog_bios().post_boot_sound()? == 1; println!("Bios POST sound on: {}", res); } + if let Some(opt) = cmd.dedicated_gfx_set { println!("Rebuilding initrd to include drivers"); dbus.proxies().rog_bios().set_dedicated_graphic_mode(opt)?; @@ -733,6 +741,14 @@ fn handle_bios_option( let res = dbus.proxies().rog_bios().dedicated_graphic_mode()? == 1; println!("Bios dedicated GPU on: {}", res); } + + if let Some(opt) = cmd.panel_overdrive_set { + dbus.proxies().rog_bios().set_panel_overdrive(opt)?; + } + if cmd.panel_overdrive_get { + let res = dbus.proxies().rog_bios().panel_overdrive()? == 1; + println!("Panel overdrive on: {}", res); + } } Ok(()) } diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 296a31a9..94a14c83 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.2.0" +version = "4.2.1" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/daemon/src/config.rs b/daemon/src/config.rs index 0ebf6b1a..847326ae 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Default)] pub struct Config { /// Save charge limit for restoring on boot pub bat_charge_limit: u8, diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 7e7d9543..e86a2f0d 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -16,6 +16,7 @@ pub struct AuraConfig { pub current_mode: AuraModeNum, pub builtins: BTreeMap, pub multizone: Option>>, + pub multizone_on: bool, pub enabled: HashSet, } @@ -26,6 +27,7 @@ impl Default for AuraConfig { current_mode: AuraModeNum::Static, builtins: BTreeMap::new(), multizone: None, + multizone_on: false, enabled: HashSet::from([ AuraControl::BootLogo, AuraControl::BootKeyb, @@ -123,27 +125,35 @@ impl AuraConfig { .unwrap_or_else(|err| error!("Could not write config: {}", err)); } - /// Multipurpose, will accept AuraEffect with zones and put in the correct store + /// Set the mode data, current mode, and if multizone enabled. + /// + /// Multipurpose, will accept AuraEffect with zones and put in the correct store. pub fn set_builtin(&mut self, effect: AuraEffect) { + self.current_mode = effect.mode; match effect.zone() { AuraZone::None => { self.builtins.insert(*effect.mode(), effect); + self.multizone_on = false; } _ => { if let Some(multi) = self.multizone.as_mut() { if let Some(fx) = multi.get_mut(effect.mode()) { for fx in fx.iter_mut() { - if fx.mode == effect.mode { + if fx.zone == effect.zone { *fx = effect; - break; + return; } } + fx.push(effect); } else { - let mut tmp = BTreeMap::new(); - tmp.insert(*effect.mode(), vec![effect]); - self.multizone = Some(tmp); + multi.insert(*effect.mode(), vec![effect]); } + } else { + let mut tmp = BTreeMap::new(); + tmp.insert(*effect.mode(), vec![effect]); + self.multizone = Some(tmp); } + self.multizone_on = true; } } } @@ -155,3 +165,86 @@ impl AuraConfig { None } } + +#[cfg(test)] +mod tests { + use super::AuraConfig; + use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; + + #[test] + fn set_multizone_4key_config() { + let mut config = AuraConfig::default(); + + let mut effect = AuraEffect::default(); + effect.colour1 = Colour(0xff, 0x00, 0xff); + effect.zone = AuraZone::Key1; + config.set_builtin(effect); + + assert!(config.multizone.is_some()); + + let mut effect = AuraEffect::default(); + effect.colour1 = Colour(0x00, 0xff, 0xff); + effect.zone = AuraZone::Key2; + config.set_builtin(effect); + + let mut effect = AuraEffect::default(); + effect.colour1 = Colour(0xff, 0xff, 0x00); + effect.zone = AuraZone::Key3; + config.set_builtin(effect); + + let mut effect = AuraEffect::default(); + effect.colour1 = Colour(0x00, 0xff, 0x00); + effect.zone = AuraZone::Key4; + let effect_clone = effect.clone(); + config.set_builtin(effect); + // This should replace existing + config.set_builtin(effect_clone); + + let res = config.multizone.unwrap(); + let sta = res.get(&AuraModeNum::Static).unwrap(); + assert_eq!(sta.len(), 4); + assert_eq!(sta[0].colour1, Colour(0xff, 0x00, 0xff)); + assert_eq!(sta[1].colour1, Colour(0x00, 0xff, 0xff)); + assert_eq!(sta[2].colour1, Colour(0xff, 0xff, 0x00)); + assert_eq!(sta[3].colour1, Colour(0x00, 0xff, 0x00)); + } + + #[test] + fn set_multizone_multimode_config() { + let mut config = AuraConfig::default(); + + let mut effect = AuraEffect::default(); + effect.zone = AuraZone::Key1; + config.set_builtin(effect); + + assert!(config.multizone.is_some()); + + let mut effect = AuraEffect::default(); + effect.zone = AuraZone::Key2; + effect.mode = AuraModeNum::Breathe; + config.set_builtin(effect); + + let mut effect = AuraEffect::default(); + effect.zone = AuraZone::Key3; + effect.mode = AuraModeNum::Comet; + config.set_builtin(effect); + + let mut effect = AuraEffect::default(); + effect.zone = AuraZone::Key4; + effect.mode = AuraModeNum::Pulse; + config.set_builtin(effect); + + let res = config.multizone.unwrap(); + let sta = res.get(&AuraModeNum::Static).unwrap(); + assert_eq!(sta.len(), 1); + + let sta = res.get(&AuraModeNum::Breathe).unwrap(); + assert_eq!(sta.len(), 1); + + let sta = res.get(&AuraModeNum::Comet).unwrap(); + assert_eq!(sta.len(), 1); + + let sta = res.get(&AuraModeNum::Pulse).unwrap(); + assert_eq!(sta.len(), 1); + } +} diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index 734bbb39..0c3a1098 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::AuraControl; +use rog_aura::{usb::AuraControl, AuraZone}; use rog_aura::{ usb::{LED_APPLY, LED_SET}, AuraEffect, LedBrightness, LED_MSG_LEN, @@ -106,11 +106,9 @@ impl CtrlTask for CtrlKbdLedTask { 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) { - lock.write_mode(mode) - .map_err(|e| error!("CtrlKbdLedTask: {e}")) - .ok(); - } + lock.write_current_config_mode() + .map_err(|e| error!("CtrlKbdLedTask: {e}")) + .ok(); } else if start { info!("CtrlKbdLedTask saving last brightness"); Self::update_config(&mut lock) @@ -154,15 +152,6 @@ 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; Ok(()) } } @@ -171,12 +160,8 @@ pub struct CtrlKbdLedReloader(pub Arc>); impl crate::Reloadable for CtrlKbdLedReloader { fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut ctrl) = self.0.try_lock() { - let current = ctrl.config.current_mode; - if let Some(mode) = ctrl.config.builtins.get(¤t).cloned() { - ctrl.do_command(mode).ok(); - } - + if let Ok(ctrl) = self.0.try_lock() { + ctrl.write_current_config_mode()?; ctrl.set_power_states(&ctrl.config) .map_err(|err| warn!("{err}")) .ok(); @@ -211,11 +196,8 @@ impl CtrlKbdLed { let bright_node = Self::get_kbd_bright_path(); - if led_node.is_none() && bright_node.is_none() { - return Err(RogError::MissingFunction( - "All keyboard features missing, you may require a v5.11 series kernel or newer" - .into(), - )); + if led_node.is_none() { + return Err(RogError::NoAuraKeyboard); } if bright_node.is_none() { @@ -301,7 +283,6 @@ impl CtrlKbdLed { let set: Vec = config.enabled.iter().map(|v| *v).collect(); let bytes = AuraControl::to_bytes(&set); - // Quite ugly, must be a more idiomatic way to do let message = [ 0x5d, 0xbd, 0x01, bytes[0], bytes[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; @@ -351,8 +332,24 @@ impl CtrlKbdLed { )) } - pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> { - self.set_and_save(mode) + /// Set an Aura effect if the effect mode or zone is supported. + /// + /// On success the aura config file is read to refresh cached values, then the effect is + /// stored and config written to disk. + pub(crate) fn set_effect(&mut self, effect: AuraEffect) -> Result<(), RogError> { + if !self.supported_modes.standard.contains(&effect.mode) { + return Err(RogError::AuraEffectNotSupported); + } else if effect.zone != AuraZone::None + && !self.supported_modes.multizone.contains(&effect.zone) + { + return Err(RogError::AuraEffectNotSupported); + } + + self.write_mode(&effect)?; + self.config.read(); // refresh config if successful + self.config.set_builtin(effect); + self.config.write(); + Ok(()) } /// Should only be used if the bytes you are writing are verified correct @@ -366,10 +363,10 @@ impl CtrlKbdLed { .map_err(|err| RogError::Write("write_bytes".into(), err)); } } - Err(RogError::NotSupported) + Err(RogError::NoAuraNode) } - /// Write an effect block + /// Write an effect block. This is for per-key #[inline] fn _write_effect(&mut self, effect: &[Vec]) -> Result<(), RogError> { if self.flip_effect_write { @@ -385,19 +382,6 @@ impl CtrlKbdLed { Ok(()) } - /// Used to set a builtin mode and save the settings for it - /// - /// This needs to be universal so that settings applied by dbus stick - #[inline] - fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> { - self.config.read(); - self.write_mode(&mode)?; - self.config.current_mode = *mode.mode(); - self.config.set_builtin(mode); - self.config.write(); - Ok(()) - } - #[inline] pub(super) fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> { let current = self.config.current_mode; @@ -424,9 +408,9 @@ impl CtrlKbdLed { let next = self.supported_modes.standard[idx]; self.config.read(); - if let Some(data) = self.config.builtins.get(&next) { - self.write_mode(data)?; + if self.config.builtins.contains_key(&next) { self.config.current_mode = next; + self.write_current_config_mode()?; } self.config.write(); } @@ -436,9 +420,6 @@ impl CtrlKbdLed { #[inline] fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> { - if !self.supported_modes.standard.contains(mode.mode()) { - return Err(RogError::NotSupported); - } let bytes: [u8; LED_MSG_LEN] = mode.into(); self.write_bytes(&bytes)?; self.write_bytes(&LED_SET)?; @@ -446,4 +427,96 @@ impl CtrlKbdLed { self.write_bytes(&LED_APPLY)?; Ok(()) } + + #[inline] + fn write_current_config_mode(&self) -> Result<(), RogError> { + if self.config.multizone_on { + let mode = self.config.current_mode; + if let Some(multizones) = self.config.multizone.as_ref() { + if let Some(set) = multizones.get(&mode) { + for mode in set { + self.write_mode(mode)?; + } + } + } + } else { + let mode = self.config.current_mode; + if let Some(effect) = self.config.builtins.get(&mode) { + self.write_mode(effect)?; + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; + + use crate::{ctrl_aura::config::AuraConfig, laptops::LaptopLedData}; + + use super::CtrlKbdLed; + + #[test] + // #[ignore = "Must be manually run due to detection stage"] + fn check_set_mode_errors() { + // Checking to ensure set_mode errors when unsupported modes are tried + let config = AuraConfig::default(); + let supported_modes = LaptopLedData { + prod_family: "".into(), + board_names: vec![], + standard: vec![AuraModeNum::Static], + multizone: vec![], + per_key: false, + }; + let mut controller = CtrlKbdLed { + led_node: None, + bright_node: String::new(), + supported_modes, + flip_effect_write: false, + config, + }; + + let mut effect = AuraEffect::default(); + effect.colour1 = Colour(0xff, 0x00, 0xff); + effect.zone = AuraZone::None; + + // This error comes from write_bytes because we don't have a keyboard node stored + assert_eq!( + controller + .set_effect(effect.clone()) + .unwrap_err() + .to_string(), + "No Aura keyboard node found" + ); + + effect.mode = AuraModeNum::Laser; + assert_eq!( + controller + .set_effect(effect.clone()) + .unwrap_err() + .to_string(), + "Aura effect not supported" + ); + + effect.mode = AuraModeNum::Static; + effect.zone = AuraZone::Key2; + assert_eq!( + controller + .set_effect(effect.clone()) + .unwrap_err() + .to_string(), + "Aura effect not supported" + ); + + controller.supported_modes.multizone.push(AuraZone::Key2); + assert_eq!( + controller + .set_effect(effect.clone()) + .unwrap_err() + .to_string(), + "No Aura keyboard node found" + ); + } } diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 79f33447..893c85e5 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -46,7 +46,7 @@ impl CtrlKbdLedZbus { &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, enabled: Vec, - ) { + ) -> zbus::fdo::Result<()> { let mut states = None; if let Ok(mut ctrl) = self.0.try_lock() { for s in enabled { @@ -54,9 +54,10 @@ impl CtrlKbdLedZbus { } ctrl.config.write(); - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{}", err)) - .ok(); + 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); @@ -67,13 +68,14 @@ impl CtrlKbdLedZbus { .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 { @@ -81,9 +83,10 @@ impl CtrlKbdLedZbus { } ctrl.config.write(); - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{}", err)) - .ok(); + 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); @@ -94,24 +97,22 @@ impl CtrlKbdLedZbus { .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } async fn set_led_mode( &mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>, effect: AuraEffect, - ) { + ) -> zbus::fdo::Result<()> { let mut led = None; if let Ok(mut ctrl) = self.0.try_lock() { - match ctrl.do_command(effect) { - Ok(_) => { - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - } - Err(err) => { - warn!("{}", err); - } + ctrl.set_effect(effect).map_err(|e| { + warn!("{}", e); + e + })?; + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + led = Some(mode.clone()); } } if let Some(led) = led { @@ -119,13 +120,19 @@ impl CtrlKbdLedZbus { .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } - async fn next_led_mode(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>) { + async fn next_led_mode( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + ) -> zbus::fdo::Result<()> { let mut led = None; if let Ok(mut ctrl) = self.0.lock() { - ctrl.toggle_mode(false) - .unwrap_or_else(|err| warn!("{}", err)); + ctrl.toggle_mode(false).map_err(|e| { + warn!("{}", e); + e + })?; if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { led = Some(mode.clone()); @@ -136,13 +143,19 @@ impl CtrlKbdLedZbus { .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } - async fn prev_led_mode(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>) { + async fn prev_led_mode( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + ) -> zbus::fdo::Result<()> { let mut led = None; if let Ok(mut ctrl) = self.0.lock() { - ctrl.toggle_mode(true) - .unwrap_or_else(|err| warn!("{}", err)); + ctrl.toggle_mode(true).map_err(|e| { + warn!("{}", e); + e + })?; if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { led = Some(mode.clone()); @@ -153,20 +166,27 @@ impl CtrlKbdLedZbus { .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } - async fn next_led_brightness(&self) { + async fn next_led_brightness(&self) -> zbus::fdo::Result<()> { if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.next_brightness() - .unwrap_or_else(|err| warn!("{}", err)); + ctrl.next_brightness().map_err(|e| { + warn!("{}", e); + e + })?; } + Ok(()) } - async fn prev_led_brightness(&self) { + async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> { if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.prev_brightness() - .unwrap_or_else(|err| warn!("{}", err)); + ctrl.prev_brightness().map_err(|e| { + warn!("{}", e); + e + })?; } + Ok(()) } #[dbus_interface(property)] diff --git a/daemon/src/ctrl_rog_bios.rs b/daemon/src/ctrl_rog_bios.rs index e66d7249..dabf565e 100644 --- a/daemon/src/ctrl_rog_bios.rs +++ b/daemon/src/ctrl_rog_bios.rs @@ -19,6 +19,9 @@ static ASUS_SWITCH_GRAPHIC_MODE: &str = "/sys/firmware/efi/efivars/AsusSwitchGraphicMode-607005d5-3f75-4b2e-98f0-85ba66797a3e"; static ASUS_POST_LOGO_SOUND: &str = "/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e"; +static ASUS_PANEL_OD_PATH: &str = "/sys/devices/platform/asus-nb-wmi/panel_od"; +static ASUS_DGPU_DISABLE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/dgpu_disable"; +static ASUS_EGPU_ENABLE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/egpu_enable"; pub struct CtrlRogBios { _config: Arc>, @@ -29,8 +32,11 @@ impl GetSupported for CtrlRogBios { fn get_supported() -> Self::A { RogBiosSupportedFunctions { - post_sound_toggle: Path::new(ASUS_POST_LOGO_SOUND).exists(), - dedicated_gfx_toggle: Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists(), + post_sound: Path::new(ASUS_POST_LOGO_SOUND).exists(), + dedicated_gfx: Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists(), + panel_overdrive: Path::new(ASUS_PANEL_OD_PATH).exists(), + dgpu_disable: Path::new(ASUS_DGPU_DISABLE_PATH).exists(), + egpu_enable: Path::new(ASUS_EGPU_ENABLE_PATH).exists(), } } } @@ -94,6 +100,52 @@ impl CtrlRogBios { #[dbus_interface(signal)] async fn notify_post_boot_sound(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()> {} + + async fn set_panel_overdrive( + &mut self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + overdrive: bool, + ) { + if self + .set_panel_od(overdrive) + .map_err(|err| { + warn!("CtrlRogBios: set_panel_overdrive {}", err); + err + }) + .is_ok() + { + Self::notify_panel_overdrive(&ctxt, overdrive).await.ok(); + } + } + + fn panel_overdrive(&self) -> i8 { + let path = ASUS_PANEL_OD_PATH; + if let Ok(mut file) = OpenOptions::new().read(true).open(path).map_err(|err| { + warn!("CtrlRogBios: panel_overdrive {}", err); + err + }) { + let mut buf = Vec::new(); + file.read_to_end(&mut buf) + .map_err(|err| { + warn!("CtrlRogBios: set_panel_overdrive {}", err); + err + }) + .ok(); + + if buf.len() >= 1 { + let tmp = String::from_utf8_lossy(&buf[0..1]); + return tmp.parse::().unwrap_or(-1); + } + } + -1 + } + + #[dbus_interface(signal)] + async fn notify_panel_overdrive( + signal_ctxt: &SignalContext<'_>, + overdrive: bool, + ) -> zbus::Result<()> { + } } #[async_trait] @@ -305,4 +357,43 @@ impl CtrlRogBios { } Ok(()) } + + fn set_panel_od(&mut self, overdrive: bool) -> Result<(), RogError> { + let path = ASUS_PANEL_OD_PATH; + let mut file = OpenOptions::new().write(true).open(path).map_err(|err| { + warn!("CtrlRogBios: set_panel_overdrive {}", err); + err + })?; + + let s = if overdrive { '1' } else { '0' }; + file.write(&[s as u8]).map_err(|err| { + warn!("CtrlRogBios: set_panel_overdrive {}", err); + err + })?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::CtrlRogBios; + use crate::config::Config; + use std::sync::{Arc, Mutex}; + + #[test] + #[ignore = "Must be manually tested"] + fn set_multizone_4key_config() { + let config = Config::default(); + + let controller = CtrlRogBios { + _config: Arc::new(Mutex::new(config)), + }; + + let res = controller.panel_overdrive(); + assert_eq!(res, 1); + + // controller.set_panel_od(false).unwrap(); + // let res = controller.panel_overdrive(); + // assert_eq!(res, 0); + } } diff --git a/daemon/src/error.rs b/daemon/src/error.rs index 14f254ab..67853b50 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -23,6 +23,9 @@ pub enum RogError { Io(std::io::Error), Zbus(zbus::Error), ChargeLimit(u8), + AuraEffectNotSupported, + NoAuraKeyboard, + NoAuraNode, } impl fmt::Display for RogError { @@ -48,6 +51,9 @@ impl fmt::Display for RogError { RogError::Io(detail) => write!(f, "std::io error: {}", detail), RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail), RogError::ChargeLimit(value) => write!(f, "Invalid charging limit, not in range 20-100%: {}", value), + RogError::AuraEffectNotSupported => write!(f, "Aura effect not supported"), + RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), + RogError::NoAuraNode => write!(f, "No Aura keyboard node found"), } } } diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index ba725a5e..c12a5074 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -731,7 +731,7 @@ mod tests { vec![Pixel::default(); 1000], 100, AnimeType::GA402, - ); + ).unwrap(); matrix._edge_outline(); let data = AnimeDataBuffer::from(&matrix); let pkt = AnimePacketType::from(data); diff --git a/rog-aura/Cargo.toml b/rog-aura/Cargo.toml index 3e11fd08..d3139d22 100644 --- a/rog-aura/Cargo.toml +++ b/rog-aura/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_aura" -version = "1.1.1" +version = "1.1.2" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/rog-aura/src/usb.rs b/rog-aura/src/usb.rs index b4acc550..749db528 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -25,7 +25,7 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { /// booting. /// /// # Bits for 0x19b6 keyboard model -/// +/// /// ```text /// byte 4 in the USB packet is for keyboard + logo power states /// default is on, `ff` @@ -51,7 +51,7 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { /// | 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 | diff --git a/rog-dbus/src/zbus_rogbios.rs b/rog-dbus/src/zbus_rogbios.rs index 437a1766..ae4cbd71 100644 --- a/rog-dbus/src/zbus_rogbios.rs +++ b/rog-dbus/src/zbus_rogbios.rs @@ -38,6 +38,12 @@ trait RogBios { /// SetPostBootSound method fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>; + /// PanelOverdrive method + fn panel_overdrive(&self) -> zbus::Result; + + /// SetPanelOverdrive method + fn set_panel_overdrive(&self, overdrive: bool) -> zbus::Result<()>; + /// NotifyDedicatedGraphicMode signal #[dbus_proxy(signal)] fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()>; @@ -45,4 +51,8 @@ trait RogBios { /// NotifyPostBootSound signal #[dbus_proxy(signal)] fn notify_post_boot_sound(&self, sound: bool) -> zbus::Result<()>; + + /// NotifyPanelOverdrive signal + #[dbus_proxy(signal)] + fn notify_panel_overdrive(&self, overdrive: bool) -> zbus::Result<()>; } diff --git a/rog-supported/Cargo.toml b/rog-supported/Cargo.toml index dba59c44..d8da8eb1 100644 --- a/rog-supported/Cargo.toml +++ b/rog-supported/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_supported" -version = "4.0.0" +version = "4.2.0" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/rog-supported/src/lib.rs b/rog-supported/src/lib.rs index de2f61b2..3de399e6 100644 --- a/rog-supported/src/lib.rs +++ b/rog-supported/src/lib.rs @@ -38,8 +38,11 @@ pub struct LedSupportedFunctions { #[derive(Serialize, Deserialize, Type, Debug)] pub struct RogBiosSupportedFunctions { - pub post_sound_toggle: bool, - pub dedicated_gfx_toggle: bool, + pub post_sound: bool, + pub dedicated_gfx: bool, + pub panel_overdrive: bool, + pub dgpu_disable: bool, + pub egpu_enable: bool, } impl fmt::Display for SupportedFunctions { @@ -87,7 +90,11 @@ impl fmt::Display for LedSupportedFunctions { impl fmt::Display for RogBiosSupportedFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "ROG BIOS:")?; - writeln!(f, "\tPOST sound toggle: {}", self.post_sound_toggle)?; - writeln!(f, "\tDedicated GFX toggle: {}", self.dedicated_gfx_toggle) + writeln!(f, "\tPOST sound switch: {}", self.post_sound)?; + writeln!(f, "\tPanel Overdrive: {}", self.panel_overdrive)?; + writeln!(f, "\tdGPU disable switch: {}", self.dgpu_disable)?; + writeln!(f, "\teGPU enable switch: {}", self.egpu_enable)?; + writeln!(f, "\tDedicated GFX switch: {}", self.dedicated_gfx)?; + Ok(()) } }