From 97481cd45ef846a6c92cf8e8ef97e0e5f8d705a6 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 26 Aug 2022 18:29:17 +1200 Subject: [PATCH] rog-aura: add per-zone effects --- CHANGELOG.md | 1 + Cargo.lock | 4 +- MANUAL.md | 34 +++++-- asusctl/examples/aura-rgb-breathe.rs | 30 +++--- asusctl/examples/aura-zoned-breathe.rs | 44 +++++++++ daemon-user/src/user_config.rs | 18 ++-- daemon/Cargo.toml | 2 +- rog-aura/Cargo.toml | 2 +- rog-aura/src/builtin_modes.rs | 9 +- rog-aura/src/lib.rs | 4 + rog-aura/src/per_zone.rs | 124 +++++++++++++++++++++++++ rog-aura/src/sequencer.rs | 66 +++++++++---- 12 files changed, 281 insertions(+), 57 deletions(-) create mode 100644 asusctl/examples/aura-zoned-breathe.rs create mode 100644 rog-aura/src/per_zone.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a1fb412..e4aefb45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added (v4.4.0) - Support for per-key config has been added to `asusd-user`. At the moment it is basic with only two effects done. Please see the manual for more information. +- Support for per-zone effects on some laptops. As above. ### Changed - Create new rog-platform crate to manage all i/o in a universal way + kbd-led handling (requires kernel patches, TUF specific) diff --git a/Cargo.lock b/Cargo.lock index 3daabf7c..f33692ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,7 +552,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.4.0-rc2" +version = "4.4.0-rc3" dependencies = [ "async-trait", "env_logger", @@ -2025,7 +2025,7 @@ dependencies = [ [[package]] name = "rog_aura" -version = "1.3.1" +version = "1.3.2" dependencies = [ "serde", "serde_derive", diff --git a/MANUAL.md b/MANUAL.md index ecc887c6..b740fd9d 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -141,7 +141,9 @@ An Aura config itself is a file with contents: { [ { - "key": "F", + "led_type": { + "Key": "W" + }, "action": { "Breathe": { "colour1": [ @@ -159,18 +161,34 @@ An Aura config itself is a file with contents: } }, { - "key": "Esc", - "action": { - "Static": [ - 0, - 0, - 255 - ] + "led_type": { + "Key": "Esc" + }, + "action": { + "Static": [ + 0, + 0, + 255 + ] + } } ] } ``` +If your laptop supports multizone, `"led_type"` can also be `"PerZone": ` +- `"None"` +- `"KeyboardLeft"` +- `"KeyboardCenterLeft"` +- `"KeyboardCenterRight"` +- `"KeyboardRight"` +- `"LightbarRight"` +- `"LightbarRightCorner"` +- `"LightbarRightBottom"` +- `"LightbarLeftBottom"` +- `"LightbarLeftCorner"` +- `"LightbarLeft"` + At the moment there are only two effects available as shown in the example. More will come in the future but this may take me some time. diff --git a/asusctl/examples/aura-rgb-breathe.rs b/asusctl/examples/aura-rgb-breathe.rs index bcd9c3a4..90dd8159 100644 --- a/asusctl/examples/aura-rgb-breathe.rs +++ b/asusctl/examples/aura-rgb-breathe.rs @@ -1,6 +1,6 @@ //! Using a combination of key-colour array plus a key layout to generate outputs. -use rog_aura::{keys::Key, layouts::KeyLayout, ActionData, Colour, Sequences, Speed}; +use rog_aura::{keys::Key, layouts::KeyLayout, ActionData, Colour, LedType, Sequences, Speed}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { @@ -9,40 +9,44 @@ fn main() -> Result<(), Box> { let (client, _) = RogDbusClientBlocking::new().unwrap(); let mut seq = Sequences::new(); - let mut key = - ActionData::new_breathe(Key::W, Colour(255, 127, 0), Colour(127, 0, 255), Speed::Med); + let mut key = ActionData::new_breathe( + LedType::Key(Key::W), + Colour(255, 127, 0), + Colour(127, 0, 255), + Speed::Med, + ); seq.push(key.clone()); - key.set_key(Key::A); + key.set_led_type(LedType::Key(Key::A)); seq.push(key.clone()); - key.set_key(Key::S); + key.set_led_type(LedType::Key(Key::S)); seq.push(key.clone()); - key.set_key(Key::D); + key.set_led_type(LedType::Key(Key::D)); seq.push(key.clone()); let mut key = ActionData::new_breathe( - Key::Q, + LedType::Key(Key::Q), Colour(127, 127, 127), Colour(127, 255, 255), Speed::Low, ); seq.push(key.clone()); - key.set_key(Key::E); + key.set_led_type(LedType::Key(Key::E)); seq.push(key.clone()); let mut key = ActionData::new_breathe( - Key::N1, + LedType::Key(Key::N1), Colour(166, 127, 166), Colour(127, 155, 20), Speed::High, ); - key.set_key(Key::Tilde); + key.set_led_type(LedType::Key(Key::Tilde)); seq.push(key.clone()); - key.set_key(Key::N2); + key.set_led_type(LedType::Key(Key::N2)); seq.push(key.clone()); - key.set_key(Key::N3); + key.set_led_type(LedType::Key(Key::N3)); seq.push(key.clone()); - key.set_key(Key::N4); + key.set_led_type(LedType::Key(Key::N4)); seq.push(key.clone()); loop { diff --git a/asusctl/examples/aura-zoned-breathe.rs b/asusctl/examples/aura-zoned-breathe.rs new file mode 100644 index 00000000..7b4f4c77 --- /dev/null +++ b/asusctl/examples/aura-zoned-breathe.rs @@ -0,0 +1,44 @@ +//! Using a combination of key-colour array plus a key layout to generate outputs. + +use rog_aura::{layouts::KeyLayout, ActionData, Colour, LedType, PerZone, Sequences, Speed}; +use rog_dbus::RogDbusClientBlocking; + +fn main() -> Result<(), Box> { + let layout = KeyLayout::gx502_layout(); + + let (client, _) = RogDbusClientBlocking::new().unwrap(); + + let mut seq = Sequences::new(); + + let zone = ActionData::new_breathe( + LedType::Zone(PerZone::KeyboardLeft), + Colour(166, 127, 166), + Colour(127, 155, 20), + Speed::High, + ); + seq.push(zone); + + let zone = ActionData::new_breathe( + LedType::Zone(PerZone::KeyboardCenterLeft), + Colour(16, 127, 255), + Colour(127, 15, 20), + Speed::Low, + ); + seq.push(zone); + + let zone = ActionData::new_breathe( + LedType::Zone(PerZone::LightbarRightCorner), + Colour(0, 255, 255), + Colour(255, 0, 255), + Speed::Med, + ); + seq.push(zone); + + loop { + seq.next_state(&layout); + let packets = seq.create_packets(); + + client.proxies().led().per_key_raw(packets)?; + std::thread::sleep(std::time::Duration::from_millis(60)); + } +} diff --git a/daemon-user/src/user_config.rs b/daemon-user/src/user_config.rs index 6a756baf..a1216950 100644 --- a/daemon-user/src/user_config.rs +++ b/daemon-user/src/user_config.rs @@ -5,7 +5,7 @@ use std::{ }; use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2}; -use rog_aura::{keys::Key, Colour, Speed}; +use rog_aura::{keys::Key, Colour, LedType, Speed}; use serde::de::DeserializeOwned; use serde_derive::{Deserialize, Serialize}; @@ -198,33 +198,33 @@ impl Default for UserAuraConfig { fn default() -> Self { let mut seq = rog_aura::Sequences::new(); let mut key = rog_aura::ActionData::new_breathe( - Key::W, + LedType::Key(Key::W), Colour(255, 0, 20), Colour(20, 255, 0), Speed::Low, ); seq.push(key.clone()); - key.set_key(Key::A); + key.set_led_type(LedType::Key(Key::A)); seq.push(key.clone()); - key.set_key(Key::S); + key.set_led_type(LedType::Key(Key::S)); seq.push(key.clone()); - key.set_key(Key::D); + key.set_led_type(LedType::Key(Key::D)); seq.push(key); let key = rog_aura::ActionData::new_breathe( - Key::F, + LedType::Key(Key::F), Colour(255, 0, 0), Colour(255, 0, 0), Speed::High, ); seq.push(key); - let mut key = rog_aura::ActionData::new_static(Key::RCtrl, Colour(0, 0, 255)); + let mut key = rog_aura::ActionData::new_static(LedType::Key(Key::RCtrl), Colour(0, 0, 255)); seq.push(key.clone()); - key.set_key(Key::LCtrl); + key.set_led_type(LedType::Key(Key::LCtrl)); seq.push(key.clone()); - key.set_key(Key::Esc); + key.set_led_type(LedType::Key(Key::Esc)); seq.push(key); Self { diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index faefb557..bd662855 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.4.0-rc2" +version = "4.4.0-rc3" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/rog-aura/Cargo.toml b/rog-aura/Cargo.toml index 256b03f0..e1536b25 100644 --- a/rog-aura/Cargo.toml +++ b/rog-aura/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_aura" -version = "1.3.1" +version = "1.3.2" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/rog-aura/src/builtin_modes.rs b/rog-aura/src/builtin_modes.rs index 2fa1da61..d6e57ce7 100644 --- a/rog-aura/src/builtin_modes.rs +++ b/rog-aura/src/builtin_modes.rs @@ -251,9 +251,10 @@ impl From for AuraModeNum { /// Base effects have no zoning, while multizone is 1-4 #[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Deserialize, Serialize)] pub enum AuraZone { /// Used if keyboard has no zones, or if setting all + #[default] None, /// Leftmost zone Key1, @@ -271,12 +272,6 @@ pub enum AuraZone { BarRight, } -impl Default for AuraZone { - fn default() -> Self { - AuraZone::None - } -} - impl FromStr for AuraZone { type Err = Error; diff --git a/rog-aura/src/lib.rs b/rog-aura/src/lib.rs index de01735e..bc9e530c 100644 --- a/rog-aura/src/lib.rs +++ b/rog-aura/src/lib.rs @@ -8,6 +8,10 @@ pub use builtin_modes::*; mod per_key_rgb; pub use per_key_rgb::*; + +mod per_zone; +pub use per_zone::*; + pub mod error; pub mod key_to_str; pub mod keys; diff --git a/rog-aura/src/per_zone.rs b/rog-aura/src/per_zone.rs new file mode 100644 index 00000000..30501595 --- /dev/null +++ b/rog-aura/src/per_zone.rs @@ -0,0 +1,124 @@ +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "dbus")] +use zvariant::Type; + +/// Represents the zoned raw USB packets +pub type ZonedRaw = Vec; + +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] +pub enum PerZone { + None, + KeyboardLeft, + KeyboardCenterLeft, + KeyboardCenterRight, + KeyboardRight, + LightbarRight, + LightbarRightCorner, + LightbarRightBottom, + LightbarLeftBottom, + LightbarLeftCorner, + LightbarLeft, +} + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ZonedColourArray(ZonedRaw); + +impl Default for ZonedColourArray { + fn default() -> Self { + Self::new() + } +} + +impl ZonedColourArray { + pub fn new() -> Self { + let mut pkt = vec![0u8; 64]; + pkt[0] = 0x5d; // Report ID + pkt[1] = 0xbc; // Mode = custom??, 0xb3 is builtin + pkt[2] = 0x01; + pkt[3] = 0x01; // ?? + pkt[4] = 0x04; // ??, 4,5,6 are normally RGB for builtin mode colours + ZonedColourArray(pkt) + } + + pub fn rgb_for_zone(&mut self, zone: PerZone) -> &mut [u8] { + match zone { + PerZone::None => &mut self.0[9..=11], + PerZone::KeyboardLeft => &mut self.0[9..=11], + PerZone::KeyboardCenterLeft => &mut self.0[12..=14], + PerZone::KeyboardCenterRight => &mut self.0[15..=17], + PerZone::KeyboardRight => &mut self.0[18..=20], + // Two sections missing here? + PerZone::LightbarRight => &mut self.0[27..=29], + PerZone::LightbarRightCorner => &mut self.0[30..=32], + PerZone::LightbarRightBottom => &mut self.0[33..=35], + PerZone::LightbarLeftBottom => &mut self.0[36..=38], + PerZone::LightbarLeftCorner => &mut self.0[39..=41], + PerZone::LightbarLeft => &mut self.0[42..=44], + } + } + + #[inline] + pub fn get(&self) -> ZonedRaw { + self.0.clone() + } + + #[inline] + pub fn get_ref(&self) -> &ZonedRaw { + &self.0 + } + + #[inline] + pub fn get_mut(&mut self) -> &mut ZonedRaw { + &mut self.0 + } +} + +impl From for ZonedRaw { + fn from(k: ZonedColourArray) -> Self { + k.0 + } +} + +#[cfg(test)] +mod tests { + use crate::{PerZone, ZonedColourArray, ZonedRaw}; + + macro_rules! colour_check { + ($zone:expr, $pkt_idx_start:expr) => { + let mut zone = ZonedColourArray::new(); + let c = zone.rgb_for_zone($zone); + c[0] = 255; + c[1] = 255; + c[2] = 255; + + let pkt: ZonedRaw = zone.get(); + assert_eq!(pkt[$pkt_idx_start], 0xff); + assert_eq!(pkt[$pkt_idx_start + 1], 0xff); + assert_eq!(pkt[$pkt_idx_start + 2], 0xff); + }; + } + + #[test] + fn zone_to_packet_check() { + let zone = ZonedColourArray::new(); + let pkt: ZonedRaw = zone.into(); + assert_eq!(pkt[0], 0x5d); + assert_eq!(pkt[1], 0xbc); + assert_eq!(pkt[2], 0x01); + assert_eq!(pkt[3], 0x01); + assert_eq!(pkt[4], 0x04); + + colour_check!(PerZone::KeyboardLeft, 9); + colour_check!(PerZone::KeyboardCenterLeft, 12); + colour_check!(PerZone::KeyboardCenterRight, 15); + colour_check!(PerZone::KeyboardRight, 18); + + colour_check!(PerZone::LightbarRight, 27); + colour_check!(PerZone::LightbarRightCorner, 30); + colour_check!(PerZone::LightbarRightBottom, 33); + colour_check!(PerZone::LightbarLeftBottom, 36); + colour_check!(PerZone::LightbarLeftCorner, 39); + colour_check!(PerZone::LightbarLeft, 42); + } +} diff --git a/rog-aura/src/sequencer.rs b/rog-aura/src/sequencer.rs index e239c1b5..c203df98 100644 --- a/rog-aura/src/sequencer.rs +++ b/rog-aura/src/sequencer.rs @@ -1,6 +1,21 @@ use serde_derive::{Deserialize, Serialize}; -use crate::{keys::Key, layouts::KeyLayout, Colour, KeyColourArray, PerKeyRaw, Speed}; +use crate::{ + keys::Key, layouts::KeyLayout, Colour, KeyColourArray, PerKeyRaw, PerZone, Speed, + ZonedColourArray, +}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum LedType { + Key(Key), + Zone(PerZone), +} + +impl Default for LedType { + fn default() -> Self { + Self::Zone(PerZone::None) + } +} #[derive(Debug, Clone, Deserialize, Serialize)] pub(super) enum Action { @@ -30,7 +45,7 @@ impl Default for Action { #[derive(Debug, Default, Clone, Deserialize, Serialize)] pub struct ActionData { - key: Key, + led_type: LedType, action: Action, // TODO: time /// The end resulting colour after stepping through effect @@ -39,21 +54,21 @@ pub struct ActionData { } impl ActionData { - pub fn set_key(&mut self, key: Key) { - self.key = key + pub fn set_led_type(&mut self, led_type: LedType) { + self.led_type = led_type } - pub fn new_static(key: Key, colour: Colour) -> Self { + pub fn new_static(led_type: LedType, colour: Colour) -> Self { Self { - key, + led_type, action: Action::Static(colour), colour: Default::default(), } } - pub fn new_breathe(key: Key, colour1: Colour, colour2: Colour, speed: Speed) -> Self { + pub fn new_breathe(led_type: LedType, colour1: Colour, colour2: Colour, speed: Speed) -> Self { Self { - key, + led_type, action: Action::Breathe { colour1, colour2, @@ -153,27 +168,46 @@ impl Sequences { pub fn create_packets(&self) -> PerKeyRaw { let mut keys = KeyColourArray::new(); + let mut zones = ZonedColourArray::new(); + let mut is_per_key = false; for effect in self.0.iter() { - if let Some(rgb) = keys.rgb_for_key(effect.key) { - rgb[0] = effect.colour.0; - rgb[1] = effect.colour.1; - rgb[2] = effect.colour.2; + match effect.led_type { + LedType::Key(key) => { + is_per_key = true; + if let Some(rgb) = keys.rgb_for_key(key) { + rgb[0] = effect.colour.0; + rgb[1] = effect.colour.1; + rgb[2] = effect.colour.2; + } + } + LedType::Zone(z) => { + let rgb = zones.rgb_for_zone(z); + rgb[0] = effect.colour.0; + rgb[1] = effect.colour.1; + rgb[2] = effect.colour.2; + } } } - keys.into() + if is_per_key { + keys.into() + } else { + vec![zones.into()] + } } } #[cfg(test)] mod tests { - use crate::{keys::Key, layouts::KeyLayout, Action, ActionData, Colour, Sequences, Speed}; + use crate::{ + keys::Key, layouts::KeyLayout, Action, ActionData, Colour, LedType, Sequences, Speed, + }; #[test] fn single_key_next_state_then_create() { let layout = KeyLayout::gx502_layout(); let mut seq = Sequences::new(); seq.0.push(ActionData { - key: Key::F, + led_type: LedType::Key(Key::F), action: Action::Static(Colour(255, 127, 0)), colour: Default::default(), }); @@ -192,7 +226,7 @@ mod tests { let layout = KeyLayout::gx502_layout(); let mut seq = Sequences::new(); seq.0.push(ActionData { - key: Key::F, + led_type: LedType::Key(Key::F), action: Action::Breathe { colour1: Colour(255, 127, 0), colour2: Colour(127, 0, 255),