Make LED power more universal

Closes #219
This commit is contained in:
Luke D. Jones
2022-07-21 14:48:16 +12:00
parent bdbb403a0e
commit 02fb7addf4
9 changed files with 436 additions and 284 deletions

View File

@@ -3,7 +3,23 @@ use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Directio
use std::str::FromStr; use std::str::FromStr;
#[derive(Options)] #[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 <true/false>")]
pub awake: Option<bool>,
#[options(meta = "", help = "Use with awake option <true/false>")]
pub keyboard: Option<bool>,
#[options(meta = "", help = "Use with awake option <true/false>")]
pub lightbar: Option<bool>,
#[options(meta = "", help = "Control boot animations <true/false>")]
pub boot: Option<bool>,
#[options(meta = "", help = "Control suspend animations <true/false>")]
pub sleep: Option<bool>,
}
#[derive(Options)]
pub struct LedPowerCommand2 {
#[options(help = "print help message")] #[options(help = "print help message")]
pub help: bool, pub help: bool,
#[options(command)] #[options(command)]
@@ -12,12 +28,13 @@ pub struct LedPowerCommand {
#[derive(Options)] #[derive(Options)]
pub enum SetAuraEnabled { pub enum SetAuraEnabled {
/// Applies to both old and new models
#[options(help = "set <keyboard, logo, lightbar> to enabled while device is awake")]
Awake(AuraEnabled),
#[options(help = "set <keyboard, logo, lightbar> to enabled while the device is booting")] #[options(help = "set <keyboard, logo, lightbar> to enabled while the device is booting")]
Boot(AuraEnabled), Boot(AuraEnabled),
#[options(help = "set <keyboard, logo, lightbar> to animate while the device is suspended")] #[options(help = "set <keyboard, logo, lightbar> to animate while the device is suspended")]
Sleep(AuraEnabled), Sleep(AuraEnabled),
#[options(help = "set <keyboard, logo, lightbar> to enabled while device is awake")]
Awake(AuraEnabled),
#[options(help = "set <keyboard, logo, lightbar> to animate while the device is shutdown")] #[options(help = "set <keyboard, logo, lightbar> to animate while the device is shutdown")]
Shutdown(AuraEnabled), Shutdown(AuraEnabled),
} }

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
anime_cli::AnimeCommand, anime_cli::AnimeCommand,
aura_cli::{LedBrightness, LedPowerCommand, SetAuraBuiltin}, aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin},
profiles_cli::{FanCurveCommand, ProfileCommand}, profiles_cli::{FanCurveCommand, ProfileCommand},
}; };
use gumdrop::Options; use gumdrop::Options;
@@ -29,8 +29,10 @@ pub struct CliStart {
pub enum CliCommand { pub enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")] #[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand), LedMode(LedModeCommand),
#[options(help = "Set the keyboard lighting from built-in modes")] #[options(help = "Set the LED power states")]
LedPower(LedPowerCommand), LedPow1(LedPowerCommand1),
#[options(help = "Set the LED power states")]
LedPow2(LedPowerCommand2),
#[options(help = "Set or select platform_profile")] #[options(help = "Set or select platform_profile")]
Profile(ProfileCommand), Profile(ProfileCommand),
#[options(help = "Set, select, or modify fan curves if supported")] #[options(help = "Set, select, or modify fan curves if supported")]

View File

@@ -3,14 +3,14 @@ use std::process::Command;
use std::thread::sleep; use std::thread::sleep;
use std::{env::args, path::Path}; use std::{env::args, path::Path};
use aura_cli::LedPowerCommand; use aura_cli::{LedPowerCommand1, LedPowerCommand2};
use gumdrop::{Opt, Options}; use gumdrop::{Opt, Options};
use anime_cli::{AnimeActions, AnimeCommand}; use anime_cli::{AnimeActions, AnimeCommand};
use profiles_cli::{FanCurveCommand, ProfileCommand}; use profiles_cli::{FanCurveCommand, ProfileCommand};
use rog_anime::usb::get_anime_type; use rog_anime::usb::get_anime_type;
use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; 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_aura::{self, AuraEffect};
use rog_dbus::RogDbusClientBlocking; use rog_dbus::RogDbusClientBlocking;
use rog_profiles::error::ProfileError; use rog_profiles::error::ProfileError;
@@ -137,7 +137,8 @@ fn do_parsed(
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
match &parsed.command { match &parsed.command {
Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?, 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::Profile(cmd)) => handle_profile(dbus, &supported.platform_profile, cmd)?,
Some(CliCommand::FanCurve(cmd)) => { Some(CliCommand::FanCurve(cmd)) => {
handle_fan_curve(dbus, &supported.platform_profile, cmd)? handle_fan_curve(dbus, &supported.platform_profile, cmd)?
@@ -156,7 +157,22 @@ fn do_parsed(
println!("{}", CliStart::usage()); println!("{}", CliStart::usage());
println!(); println!();
if let Some(cmdlist) = CliStart::command_list() { if let Some(cmdlist) = CliStart::command_list() {
println!("{}", cmdlist); let commands: Vec<String> = 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:"); println!("\nExtra help can be requested on any command or subcommand:");
@@ -421,10 +437,67 @@ fn handle_led_mode(
Ok(()) Ok(())
} }
fn handle_led_power( fn handle_led_power1(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking,
_supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
power: &LedPowerCommand, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> {
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<AuraDev1866> = Vec::new();
let mut disabled: Vec<AuraDev1866> = Vec::new();
let mut check = |e: Option<bool>, 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<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if power.command().is_none() { if power.command().is_none() {
if !power.help { if !power.help {
@@ -433,7 +506,7 @@ fn handle_led_power(
println!("{}\n", power.self_usage()); println!("{}\n", power.self_usage());
println!("Commands available"); println!("Commands available");
if let Some(cmdlist) = LedPowerCommand::command_list() { if let Some(cmdlist) = LedPowerCommand2::command_list() {
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect();
for command in commands.iter() { for command in commands.iter() {
println!("{}", command); println!("{}", command);
@@ -450,133 +523,60 @@ fn handle_led_power(
return Ok(()); return Ok(());
} }
if supported.prod_id == "1866" {
println!("This option does not apply to keyboards with product ID 0x1866")
}
let mut enabled: Vec<AuraDev19b6> = Vec::new();
let mut disabled: Vec<AuraDev19b6> = Vec::new();
let mut check = |e: Option<bool>, a: AuraDev19b6| {
if let Some(arg) = e {
if arg {
enabled.push(a);
} else {
disabled.push(a);
}
}
};
match pow { match pow {
// TODO: make this a macro or something
aura_cli::SetAuraEnabled::Boot(arg) => { aura_cli::SetAuraEnabled::Boot(arg) => {
let mut enabled: Vec<AuraControl> = Vec::new(); check(arg.keyboard, AuraDev19b6::BootKeyb);
let mut disabled: Vec<AuraControl> = Vec::new(); check(arg.logo, AuraDev19b6::BootLogo);
arg.keyboard.map(|v| { check(arg.lightbar, AuraDev19b6::BootBar);
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) => { aura_cli::SetAuraEnabled::Sleep(arg) => {
let mut enabled: Vec<AuraControl> = Vec::new(); check(arg.keyboard, AuraDev19b6::SleepKeyb);
let mut disabled: Vec<AuraControl> = Vec::new(); check(arg.logo, AuraDev19b6::SleepLogo);
arg.keyboard.map(|v| { check(arg.lightbar, AuraDev19b6::SleepBar);
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) => { aura_cli::SetAuraEnabled::Awake(arg) => {
let mut enabled: Vec<AuraControl> = Vec::new(); check(arg.keyboard, AuraDev19b6::AwakeKeyb);
let mut disabled: Vec<AuraControl> = Vec::new(); check(arg.logo, AuraDev19b6::AwakeLogo);
arg.keyboard.map(|v| { check(arg.lightbar, AuraDev19b6::AwakeBar);
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) => { aura_cli::SetAuraEnabled::Shutdown(arg) => {
let mut enabled: Vec<AuraControl> = Vec::new(); check(arg.keyboard, AuraDev19b6::ShutdownKeyb);
let mut disabled: Vec<AuraControl> = Vec::new(); check(arg.logo, AuraDev19b6::ShutdownLogo);
arg.keyboard.map(|v| { check(arg.lightbar, AuraDev19b6::ShutdownBar);
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)?;
}
} }
} }
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(()) Ok(())

View File

@@ -1,6 +1,6 @@
use crate::laptops::LaptopLedData; use crate::laptops::LaptopLedData;
use log::{error, warn}; 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 rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
@@ -9,6 +9,65 @@ use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; 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<AuraDev1866>),
AuraDev19b6(HashSet<AuraDev19b6>),
}
impl AuraPowerConfig {
pub fn to_bytes(control: &Self) -> [u8; 3] {
match control {
AuraPowerConfig::AuraDev1866(c) => {
let c: Vec<AuraDev1866> = c.iter().map(|v| *v).collect();
AuraDev1866::to_bytes(&c)
}
AuraPowerConfig::AuraDev19b6(c) => {
let c: Vec<AuraDev19b6> = 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)] #[derive(Deserialize, Serialize)]
#[serde(default)] #[serde(default)]
pub struct AuraConfig { pub struct AuraConfig {
@@ -17,7 +76,7 @@ pub struct AuraConfig {
pub builtins: BTreeMap<AuraModeNum, AuraEffect>, pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<BTreeMap<AuraModeNum, Vec<AuraEffect>>>, pub multizone: Option<BTreeMap<AuraModeNum, Vec<AuraEffect>>>,
pub multizone_on: bool, pub multizone_on: bool,
pub enabled: HashSet<AuraControl>, pub enabled: AuraPowerConfig,
} }
impl Default for AuraConfig { impl Default for AuraConfig {
@@ -28,20 +87,7 @@ impl Default for AuraConfig {
builtins: BTreeMap::new(), builtins: BTreeMap::new(),
multizone: None, multizone: None,
multizone_on: false, multizone_on: false,
enabled: HashSet::from([ enabled: AuraPowerConfig::AuraDev1866(HashSet::new()),
AuraControl::BootLogo,
AuraControl::BootKeyb,
AuraControl::SleepLogo,
AuraControl::SleepKeyb,
AuraControl::AwakeLogo,
AuraControl::AwakeKeyb,
AuraControl::ShutdownLogo,
AuraControl::ShutdownKeyb,
AuraControl::AwakeBar,
AuraControl::BootBar,
AuraControl::SleepBar,
AuraControl::ShutdownBar,
]),
} }
} }
} }

View File

@@ -9,11 +9,11 @@ use crate::{
use async_trait::async_trait; use async_trait::async_trait;
use log::{error, info, warn}; use log::{error, info, warn};
use logind_zbus::manager::ManagerProxy; use logind_zbus::manager::ManagerProxy;
use rog_aura::{usb::AuraControl, AuraZone, Direction, Speed, GRADIENT};
use rog_aura::{ use rog_aura::{
usb::{LED_APPLY, LED_SET}, usb::{LED_APPLY, LED_SET},
AuraEffect, LedBrightness, LED_MSG_LEN, AuraEffect, LedBrightness, LED_MSG_LEN,
}; };
use rog_aura::{AuraZone, Direction, Speed, GRADIENT};
use rog_supported::LedSupportedFunctions; use rog_supported::LedSupportedFunctions;
use smol::{stream::StreamExt, Executor}; use smol::{stream::StreamExt, Executor};
use std::path::Path; use std::path::Path;
@@ -28,7 +28,7 @@ use zbus::Connection;
use crate::GetSupported; use crate::GetSupported;
use super::config::AuraConfig; use super::config::{AuraConfig, AuraPowerConfig};
impl GetSupported for CtrlKbdLed { impl GetSupported for CtrlKbdLed {
type A = LedSupportedFunctions; type A = LedSupportedFunctions;
@@ -40,7 +40,16 @@ impl GetSupported for CtrlKbdLed {
let multizone_led_mode = laptop.multizone; let multizone_led_mode = laptop.multizone;
let per_key_led_mode = laptop.per_key; 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 { LedSupportedFunctions {
prod_id,
brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(),
stock_led_modes, stock_led_modes,
multizone_led_mode, multizone_led_mode,
@@ -50,6 +59,8 @@ impl GetSupported for CtrlKbdLed {
} }
pub struct CtrlKbdLed { pub struct CtrlKbdLed {
// TODO: config stores the keyboard type as an AuraPower, use or update this
pub led_prod: Option<String>,
pub led_node: Option<String>, pub led_node: Option<String>,
pub bright_node: String, pub bright_node: String,
pub supported_modes: LaptopLedData, pub supported_modes: LaptopLedData,
@@ -184,10 +195,12 @@ impl CtrlKbdLedZbus {
impl CtrlKbdLed { impl CtrlKbdLed {
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> { pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None // TODO: return error if *all* nodes are None
let mut led_prod = None;
let mut led_node = None; let mut led_node = None;
for prod in ASUS_KEYBOARD_DEVICES.iter() { for prod in ASUS_KEYBOARD_DEVICES.iter() {
match Self::find_led_node(prod) { match Self::find_led_node(prod) {
Ok(node) => { Ok(node) => {
led_prod = Some(prod.to_string());
led_node = Some(node); led_node = Some(node);
info!("Looked for keyboard controller 0x{prod}: Found"); info!("Looked for keyboard controller 0x{prod}: Found");
break; break;
@@ -209,6 +222,7 @@ impl CtrlKbdLed {
} }
let ctrl = CtrlKbdLed { let ctrl = CtrlKbdLed {
led_prod,
led_node, led_node,
bright_node: bright_node.unwrap(), // If was none then we already returned above bright_node: bright_node.unwrap(), // If was none then we already returned above
supported_modes, supported_modes,
@@ -282,12 +296,8 @@ impl CtrlKbdLed {
/// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active /// 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> { pub(super) fn set_power_states(&self, config: &AuraConfig) -> Result<(), RogError> {
let set: Vec<AuraControl> = config.enabled.iter().map(|v| *v).collect(); let bytes = AuraPowerConfig::to_bytes(&config.enabled);
let bytes = AuraControl::to_bytes(&set); let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2]];
let message = [
0x5d, 0xbd, 0x01, bytes[0], bytes[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
self.write_bytes(&message)?; self.write_bytes(&message)?;
self.write_bytes(&LED_SET)?; self.write_bytes(&LED_SET)?;
@@ -511,6 +521,7 @@ mod tests {
per_key: false, per_key: false,
}; };
let mut controller = CtrlKbdLed { let mut controller = CtrlKbdLed {
led_prod: None,
led_node: None, led_node: None,
bright_node: String::new(), bright_node: String::new(),
supported_modes, supported_modes,
@@ -572,6 +583,7 @@ mod tests {
per_key: false, per_key: false,
}; };
let mut controller = CtrlKbdLed { let mut controller = CtrlKbdLed {
led_prod: None,
led_node: None, led_node: None,
bright_node: String::new(), bright_node: String::new(),
supported_modes, supported_modes,
@@ -608,6 +620,7 @@ mod tests {
per_key: false, per_key: false,
}; };
let mut controller = CtrlKbdLed { let mut controller = CtrlKbdLed {
led_prod: None,
led_node: None, led_node: None,
bright_node: String::new(), bright_node: String::new(),
supported_modes, supported_modes,

View File

@@ -1,6 +1,6 @@
use async_trait::async_trait; use async_trait::async_trait;
use log::warn; use log::warn;
use rog_aura::{usb::AuraControl, AuraEffect, LedBrightness}; use rog_aura::{usb::AuraPowerDev, AuraEffect, LedBrightness};
use zbus::{dbus_interface, Connection, SignalContext}; use zbus::{dbus_interface, Connection, SignalContext};
use super::controller::CtrlKbdLedZbus; use super::controller::CtrlKbdLedZbus;
@@ -42,16 +42,21 @@ impl CtrlKbdLedZbus {
/// SleepBar, /// SleepBar,
/// ShutdownBar, /// ShutdownBar,
/// } /// }
async fn set_leds_enabled( async fn set_leds_power(
&mut self, &mut self,
#[zbus(signal_context)] ctxt: SignalContext<'_>, #[zbus(signal_context)] ctxt: SignalContext<'_>,
enabled: Vec<AuraControl>, options: AuraPowerDev,
enabled: bool,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
let mut states = None; let mut states = None;
if let Ok(mut ctrl) = self.0.try_lock() { if let Ok(mut ctrl) = self.0.try_lock() {
for s in enabled { for p in options.x1866 {
ctrl.config.enabled.insert(s); ctrl.config.enabled.set_0x1866(p, enabled);
} }
for p in options.x19b6 {
ctrl.config.enabled.set_0x19b6(p, enabled);
}
ctrl.config.write(); ctrl.config.write();
ctrl.set_power_states(&ctrl.config).map_err(|e| { ctrl.set_power_states(&ctrl.config).map_err(|e| {
@@ -59,37 +64,7 @@ impl CtrlKbdLedZbus {
e e
})?; })?;
let set: Vec<AuraControl> = ctrl.config.enabled.iter().map(|v| *v).collect(); states = Some(AuraPowerDev::from(&ctrl.config.enabled));
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<AuraControl>,
) -> 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<AuraControl> = ctrl.config.enabled.iter().map(|v| *v).collect();
states = Some(set);
} }
// Need to pull state out like this due to MutexGuard // Need to pull state out like this due to MutexGuard
if let Some(states) = states { if let Some(states) = states {
@@ -189,13 +164,14 @@ impl CtrlKbdLedZbus {
Ok(()) Ok(())
} }
#[dbus_interface(property)] // As property doesn't work for AuraPowerDev (complexity of serialization?)
async fn leds_enabled(&self) -> Vec<u8> { // #[dbus_interface(property)]
if let Ok(ctrl) = self.0.try_lock() { async fn leds_power(&self) -> AuraPowerDev {
let set: Vec<AuraControl> = ctrl.config.enabled.iter().map(|v| *v).collect(); loop {
return AuraControl::to_bytes(&set).to_vec(); if let Ok(ctrl) = self.0.try_lock() {
return AuraPowerDev::from(&ctrl.config.enabled);
}
} }
vec![0, 0]
} }
/// Return the current mode data /// Return the current mode data
@@ -240,6 +216,6 @@ impl CtrlKbdLedZbus {
#[dbus_interface(signal)] #[dbus_interface(signal)]
async fn notify_power_states( async fn notify_power_states(
signal_ctxt: &SignalContext<'_>, signal_ctxt: &SignalContext<'_>,
data: &[AuraControl], data: &AuraPowerDev,
) -> zbus::Result<()>; ) -> zbus::Result<()>;
} }

View File

@@ -20,16 +20,85 @@ pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
] ]
} }
/// Enable/disable LED control in various states such as /// This struct is intended as a helper to pass args to generic dbus interface
/// when the device is awake, suspended, shutting down or #[cfg_attr(feature = "dbus", derive(Type))]
/// booting. #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuraPowerDev {
pub x1866: Vec<AuraDev1866>,
pub x19b6: Vec<AuraDev19b6>,
}
/// # 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<AuraDev1866> 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<AuraDev1866> for AuraDev1866 {
type Output = u32;
fn bitor(self, rhs: AuraDev1866) -> Self::Output {
return self as u32 | rhs as u32;
}
}
impl BitAnd<AuraDev1866> for AuraDev1866 {
type Output = u32;
fn bitand(self, rhs: AuraDev1866) -> Self::Output {
return self as u32 & rhs as u32;
}
}
/// # Bits for 0x19b6 keyboard model /// # Bits for 0x19b6 keyboard model
/// ///
/// ```text
/// byte 4 in the USB packet is for keyboard + logo power states /// byte 4 in the USB packet is for keyboard + logo power states
/// default is on, `ff` /// default is on, `ff`
/// Keyboard and logo use the full range of bits (almost) /// Keyboard and logo use the full range of bits (almost)
///
/// | n1 | n2 | hex | action | bit | /// | n1 | n2 | hex | action | bit |
/// |------|------|-----|-----------------------|-------| /// |------|------|-----|-----------------------|-------|
/// | 0000 | 0000 | 00 | all off | | /// | 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 | /// | 1000 | 0000 | 80 | keyboard shutdown off | bit 8 |
/// ///
/// byte 5 = lightbar /// byte 5 = lightbar
///
/// | 1 | 2 | hex | action | bit | /// | 1 | 2 | hex | action | bit |
/// |------|------|-----|----------------------|-------| /// |------|------|-----|----------------------|-------|
/// | 0000 | 0010 | 02 | lightbar off boot | bit 2 | /// | 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 | /// | 0000 | 1000 | 08 | lightbar off sleep | bit 4 |
/// | 0001 | 0000 | 10 | lightbar shtdn off | bit 5 | /// | 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))] #[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[repr(u16)] #[repr(u16)]
pub enum AuraControl { pub enum AuraDev19b6 {
BootLogo = 1, BootLogo = 1,
BootKeyb = 1 << 1, BootKeyb = 1 << 1,
AwakeLogo = 1 << 2, AwakeLogo = 1 << 2,
@@ -81,133 +138,174 @@ pub enum AuraControl {
ShutdownBar = 1 << 7 + 5, ShutdownBar = 1 << 7 + 5,
} }
impl From<AuraControl> for u16 { impl From<AuraDev19b6> for u16 {
fn from(a: AuraControl) -> Self { fn from(a: AuraDev19b6) -> Self {
a as u16 a as u16
} }
} }
impl AuraControl { impl AuraDev19b6 {
pub fn to_bytes(control: &[Self]) -> [u8; 2] { pub fn to_bytes(control: &[Self]) -> [u8; 3] {
let mut a: u16 = 0; let mut a: u16 = 0;
control.iter().for_each(|n| { control.iter().for_each(|n| {
a |= *n as u16; 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<AuraControl> for AuraControl { impl BitOr<AuraDev19b6> for AuraDev19b6 {
type Output = u16; type Output = u16;
fn bitor(self, rhs: AuraControl) -> Self::Output { fn bitor(self, rhs: AuraDev19b6) -> Self::Output {
return self as u16 | rhs as u16; return self as u16 | rhs as u16;
} }
} }
impl BitAnd<AuraControl> for AuraControl { impl BitAnd<AuraDev19b6> for AuraDev19b6 {
type Output = u16; type Output = u16;
fn bitand(self, rhs: AuraControl) -> Self::Output { fn bitand(self, rhs: AuraDev19b6) -> Self::Output {
return self as u16 & rhs as u16; return self as u16 & rhs as u16;
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::usb::AuraControl; use crate::usb::AuraDev19b6;
use super::AuraDev1866;
#[test] #[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 // All on
let byte1 = [ let byte1 = [
AuraControl::BootLogo, AuraDev19b6::BootLogo,
AuraControl::BootKeyb, AuraDev19b6::BootKeyb,
AuraControl::SleepLogo, AuraDev19b6::SleepLogo,
AuraControl::SleepKeyb, AuraDev19b6::SleepKeyb,
AuraControl::AwakeLogo, AuraDev19b6::AwakeLogo,
AuraControl::AwakeKeyb, AuraDev19b6::AwakeKeyb,
AuraControl::ShutdownLogo, AuraDev19b6::ShutdownLogo,
AuraControl::ShutdownKeyb, AuraDev19b6::ShutdownKeyb,
]; ];
let bytes = AuraControl::to_bytes(&byte1); let bytes = AuraDev19b6::to_bytes(&byte1);
println!("{:08b}", bytes[0]); println!("{:08b}", bytes[0]);
assert_eq!(bytes[0], 0xff); assert_eq!(bytes[0], 0xff);
// //
let byte1 = [ let byte1 = [
// AuraControl::BootLogo, // AuraControl::BootLogo,
AuraControl::BootKeyb, AuraDev19b6::BootKeyb,
AuraControl::SleepLogo, AuraDev19b6::SleepLogo,
AuraControl::SleepKeyb, AuraDev19b6::SleepKeyb,
AuraControl::AwakeLogo, AuraDev19b6::AwakeLogo,
AuraControl::AwakeKeyb, AuraDev19b6::AwakeKeyb,
AuraControl::ShutdownLogo, AuraDev19b6::ShutdownLogo,
AuraControl::ShutdownKeyb, AuraDev19b6::ShutdownKeyb,
]; ];
let bytes = AuraControl::to_bytes(&byte1); let bytes = AuraDev19b6::to_bytes(&byte1);
println!("{:08b}", bytes[0]); println!("{:08b}", bytes[0]);
assert_eq!(bytes[0], 0xfe); assert_eq!(bytes[0], 0xfe);
let byte1 = [ let byte1 = [
AuraControl::BootLogo, AuraDev19b6::BootLogo,
// AuraControl::BootKeyb, // AuraControl::BootKeyb,
AuraControl::SleepLogo, AuraDev19b6::SleepLogo,
AuraControl::SleepKeyb, AuraDev19b6::SleepKeyb,
AuraControl::AwakeLogo, AuraDev19b6::AwakeLogo,
AuraControl::AwakeKeyb, AuraDev19b6::AwakeKeyb,
AuraControl::ShutdownLogo, AuraDev19b6::ShutdownLogo,
AuraControl::ShutdownKeyb, AuraDev19b6::ShutdownKeyb,
]; ];
let bytes = AuraControl::to_bytes(&byte1); let bytes = AuraDev19b6::to_bytes(&byte1);
println!("{:08b}", bytes[0]); println!("{:08b}", bytes[0]);
assert_eq!(bytes[0], 0xfd); assert_eq!(bytes[0], 0xfd);
let byte1 = [ let byte1 = [
AuraControl::BootLogo, AuraDev19b6::BootLogo,
AuraControl::BootKeyb, AuraDev19b6::BootKeyb,
// AuraControl::SleepLogo, // AuraControl::SleepLogo,
AuraControl::SleepKeyb, AuraDev19b6::SleepKeyb,
AuraControl::AwakeLogo, AuraDev19b6::AwakeLogo,
AuraControl::AwakeKeyb, AuraDev19b6::AwakeKeyb,
AuraControl::ShutdownLogo, AuraDev19b6::ShutdownLogo,
AuraControl::ShutdownKeyb, AuraDev19b6::ShutdownKeyb,
]; ];
let bytes = AuraControl::to_bytes(&byte1); let bytes = AuraDev19b6::to_bytes(&byte1);
println!("{:08b}", bytes[0]); println!("{:08b}", bytes[0]);
assert_eq!(bytes[0], 0xef); assert_eq!(bytes[0], 0xef);
let byte1 = [ let byte1 = [
AuraControl::BootLogo, AuraDev19b6::BootLogo,
AuraControl::BootKeyb, AuraDev19b6::BootKeyb,
AuraControl::SleepLogo, AuraDev19b6::SleepLogo,
// AuraControl::SleepKeyb, // AuraControl::SleepKeyb,
AuraControl::AwakeLogo, AuraDev19b6::AwakeLogo,
AuraControl::AwakeKeyb, AuraDev19b6::AwakeKeyb,
AuraControl::ShutdownLogo, AuraDev19b6::ShutdownLogo,
AuraControl::ShutdownKeyb, AuraDev19b6::ShutdownKeyb,
]; ];
let bytes = AuraControl::to_bytes(&byte1); let bytes = AuraDev19b6::to_bytes(&byte1);
println!("{:08b}", bytes[0]); println!("{:08b}", bytes[0]);
assert_eq!(bytes[0], 0xdf); assert_eq!(bytes[0], 0xdf);
let byte2 = [ let byte2 = [
AuraControl::AwakeBar, AuraDev19b6::AwakeBar,
AuraControl::BootBar, AuraDev19b6::BootBar,
AuraControl::SleepBar, AuraDev19b6::SleepBar,
AuraControl::ShutdownBar, AuraDev19b6::ShutdownBar,
]; ];
let bytes = AuraControl::to_bytes(&byte2); let bytes = AuraDev19b6::to_bytes(&byte2);
println!("{:08b}", bytes[1]); println!("{:08b}", bytes[1]);
assert_eq!(bytes[1], 0x1e); assert_eq!(bytes[1], 0x1e);
let byte2 = [ let byte2 = [
AuraControl::AwakeBar, AuraDev19b6::AwakeBar,
AuraControl::BootBar, AuraDev19b6::BootBar,
// AuraControl::SleepBar, // AuraControl::SleepBar,
AuraControl::ShutdownBar, AuraDev19b6::ShutdownBar,
]; ];
let bytes = AuraControl::to_bytes(&byte2); let bytes = AuraDev19b6::to_bytes(&byte2);
println!("{:08b}", bytes[1]); println!("{:08b}", bytes[1]);
assert_eq!(bytes[1], 0x16); assert_eq!(bytes[1], 0x16);
} }

View File

@@ -22,7 +22,7 @@
use zbus::{blocking::Connection, Result}; use zbus::{blocking::Connection, Result};
use zbus_macros::dbus_proxy; 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 const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
@@ -49,16 +49,14 @@ trait Led {
/// SetLedMode method /// SetLedMode method
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
fn set_leds_enabled(&self, enabled: Vec<AuraControl>) -> zbus::Result<()>; fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>;
fn set_leds_disabled(&self, disabled: Vec<AuraControl>) -> zbus::Result<()>;
/// NotifyLed signal /// NotifyLed signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_power_states(&self, data: Vec<AuraControl>) -> zbus::Result<()>; fn notify_power_states(&self, data: AuraPowerDev) -> zbus::Result<()>;
/// LedBrightness property /// LedBrightness property
#[dbus_proxy(property)] #[dbus_proxy(property)]
@@ -72,8 +70,9 @@ trait Led {
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn led_modes(&self) -> zbus::Result<String>; fn led_modes(&self) -> zbus::Result<String>;
#[dbus_proxy(property)] // As property doesn't work for AuraPowerDev (complexity of serialization?)
fn leds_enabled(&self) -> zbus::Result<Vec<u8>>; // #[dbus_proxy(property)]
fn leds_enabled(&self) -> zbus::Result<AuraPowerDev>;
} }
pub struct LedProxyPerkey<'a>(LedProxyBlocking<'a>); pub struct LedProxyPerkey<'a>(LedProxyBlocking<'a>);

View File

@@ -30,6 +30,7 @@ pub struct PlatformProfileFunctions {
#[derive(Serialize, Deserialize, Type, Debug)] #[derive(Serialize, Deserialize, Type, Debug)]
pub struct LedSupportedFunctions { pub struct LedSupportedFunctions {
pub prod_id: String,
pub brightness_set: bool, pub brightness_set: bool,
pub stock_led_modes: Vec<AuraModeNum>, pub stock_led_modes: Vec<AuraModeNum>,
pub multizone_led_mode: Vec<AuraZone>, pub multizone_led_mode: Vec<AuraZone>,