From 40e00c4739ffca61c202b700a5d1efa0f0987097 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 15 Jun 2023 23:53:24 +1200 Subject: [PATCH] Anime: fixups, GU604 support --- asusctl/src/main.rs | 9 +-- daemon-user/src/ctrl_anime.rs | 4 +- daemon/src/ctrl_anime/mod.rs | 9 ++- daemon/src/ctrl_anime/trait_impls.rs | 55 +++++++++++++++---- rog-anime/src/data.rs | 14 +++-- rog-anime/src/diagonal.rs | 1 + rog-anime/src/image.rs | 20 +++++++ rog-anime/src/usb.rs | 28 +++++++--- rog-control-center/src/system_state.rs | 2 +- rog-control-center/src/widgets/anime_power.rs | 4 +- rog-dbus/src/zbus_anime.rs | 8 +-- 11 files changed, 115 insertions(+), 39 deletions(-) diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 20d3fbc1..33d4330d 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -225,7 +225,8 @@ fn handle_anime( if (cmd.command.is_none() && cmd.enable.is_none() && cmd.boot_enable.is_none() - && cmd.brightness.is_none()) + && cmd.brightness.is_none() + && !cmd.clear) || cmd.help { println!("Missing arg or command\n\n{}", cmd.self_usage()); @@ -234,14 +235,14 @@ fn handle_anime( } } if let Some(anime_turn) = cmd.enable { - dbus.proxies().anime().set_on_off(anime_turn)?; + dbus.proxies().anime().set_awake_enabled(anime_turn)?; } if let Some(anime_boot) = cmd.boot_enable { - dbus.proxies().anime().set_boot_on_off(anime_boot)?; + dbus.proxies().anime().set_animation_enabled(anime_boot)?; } if let Some(bright) = cmd.brightness { verify_brightness(bright); - dbus.proxies().anime().set_brightness(bright)?; + dbus.proxies().anime().set_image_brightness(bright)?; } if cmd.clear { let anime_type = get_anime_type()?; diff --git a/daemon-user/src/ctrl_anime.rs b/daemon-user/src/ctrl_anime.rs index 7961dd5c..6954711b 100644 --- a/daemon-user/src/ctrl_anime.rs +++ b/daemon-user/src/ctrl_anime.rs @@ -360,13 +360,13 @@ impl CtrlAnime<'static> { pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> { // Operations here need to be in specific order if on { - self.client.proxies().anime().set_on_off(on).ok(); + self.client.proxies().anime().set_awake_enabled(on).ok(); // Let the inner loop run self.inner_early_return.store(false, Ordering::SeqCst); } else { // Must make the inner run loop return early self.inner_early_return.store(true, Ordering::SeqCst); - self.client.proxies().anime().set_on_off(on).ok(); + self.client.proxies().anime().set_awake_enabled(on).ok(); } Ok(()) } diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index f93e270a..c7973c78 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -15,6 +15,7 @@ use rog_anime::usb::{get_anime_type, pkt_for_flush, pkts_for_init}; use rog_anime::{ActionData, AnimeDataBuffer, AnimePacketType, AnimeType}; use rog_platform::hid_raw::HidRaw; use rog_platform::supported::AnimeSupportedFunctions; +use rog_platform::usb_raw::USBRaw; use self::config::{AnimeConfig, AnimeConfigCached}; use crate::error::RogError; @@ -29,7 +30,8 @@ impl GetSupported for CtrlAnime { } pub struct CtrlAnime { - node: HidRaw, + // node: HidRaw, + node: USBRaw, anime_type: AnimeType, cache: AnimeConfigCached, config: AnimeConfig, @@ -42,10 +44,11 @@ pub struct CtrlAnime { impl CtrlAnime { #[inline] pub fn new(config: AnimeConfig) -> Result> { - let node = HidRaw::new("193b")?; + // let node = HidRaw::new("193b")?; + let node = USBRaw::new(0x193b)?; let anime_type = get_anime_type().unwrap_or(AnimeType::GA401); - info!("Device has an AniMe Matrix display"); + info!("Device has an AniMe Matrix display: {anime_type:?}"); let mut cache = AnimeConfigCached::default(); cache.init_from_config(&config, anime_type)?; diff --git a/daemon/src/ctrl_anime/trait_impls.rs b/daemon/src/ctrl_anime/trait_impls.rs index c6009fb2..df9dd0f3 100644 --- a/daemon/src/ctrl_anime/trait_impls.rs +++ b/daemon/src/ctrl_anime/trait_impls.rs @@ -4,7 +4,9 @@ use std::sync::Arc; use async_trait::async_trait; use config_traits::StdConfig; use log::warn; -use rog_anime::usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}; +use rog_anime::usb::{ + pkt_for_enable_animation, pkt_for_set_awake_enabled, pkt_for_set_boot, pkt_for_set_brightness, +}; use rog_anime::{AnimeDataBuffer, AnimePowerStates}; use zbus::export::futures_util::lock::Mutex; use zbus::{dbus_interface, Connection, SignalContext}; @@ -43,7 +45,7 @@ impl CtrlAnimeZbus { } /// Set the global AniMe brightness - async fn set_brightness(&self, bright: f32) { + async fn set_image_brightness(&self, bright: f32) { let mut lock = self.0.lock().await; let mut bright = bright; if bright < 0.0 { @@ -55,11 +57,40 @@ impl CtrlAnimeZbus { lock.config.write(); } - /// Set whether the AniMe is displaying images/data - async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) { + /// Set base brightness level + // TODO: enum for brightness + async fn set_brightness(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) { let mut lock = self.0.lock().await; lock.node - .write_bytes(&pkt_for_set_on(status)) + .write_bytes(&pkt_for_set_brightness(status)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.config.awake_enabled = status; + lock.config.write(); + + Self::notify_power_states( + &ctxt, + AnimePowerStates { + brightness: lock.config.brightness.floor() as u8, + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }, + ) + .await + .ok(); + } + + /// Set whether the AniMe is displaying images/data + async fn set_awake_enabled( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + status: bool, + ) { + let mut lock = self.0.lock().await; + lock.node + .write_bytes(&pkt_for_set_awake_enabled(status)) .map_err(|err| { warn!("rog_anime::run_animation:callback {}", err); }) @@ -80,7 +111,11 @@ impl CtrlAnimeZbus { } /// Set whether the AniMe will show boot, suspend, or off animations - async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) { + async fn set_animation_enabled( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + on: bool, + ) { let mut lock = self.0.lock().await; lock.node .write_bytes(&pkt_for_set_boot(on)) @@ -89,7 +124,7 @@ impl CtrlAnimeZbus { }) .ok(); lock.node - .write_bytes(&pkt_for_apply()) + .write_bytes(&pkt_for_enable_animation()) .map_err(|err| { warn!("rog_anime::run_animation:callback {}", err); }) @@ -128,7 +163,7 @@ impl CtrlAnimeZbus { /// Get the status of if factory system-status animations are enabled #[dbus_interface(property)] - async fn boot_enabled(&self) -> bool { + async fn animation_enabled(&self) -> bool { let lock = self.0.lock().await; lock.config.boot_anim_enabled } @@ -198,11 +233,9 @@ impl crate::Reloadable for CtrlAnimeZbus { async fn reload(&mut self) -> Result<(), RogError> { if let Some(lock) = self.0.try_lock() { lock.node - .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; - lock.node.write_bytes(&pkt_for_apply())?; + .write_bytes(&pkt_for_set_brightness(lock.config.awake_enabled))?; lock.node .write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?; - lock.node.write_bytes(&pkt_for_apply())?; let action = lock.cache.boot.clone(); CtrlAnime::run_thread(self.0.clone(), action, true); diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index e6dd11fc..5d8948bf 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -38,6 +38,7 @@ pub struct AnimePowerStates { pub enum AnimeType { GA401, GA402, + GU604, Unknown, } @@ -46,6 +47,7 @@ impl AnimeType { pub fn width(&self) -> usize { match self { AnimeType::GA401 | AnimeType::GA402 => 74, + AnimeType::GU604 => 74, AnimeType::Unknown => 0, } } @@ -55,6 +57,7 @@ impl AnimeType { match self { AnimeType::GA401 => 36, AnimeType::GA402 => 39, + AnimeType::GU604 => 39, AnimeType::Unknown => 0, } } @@ -64,6 +67,7 @@ impl AnimeType { match self { AnimeType::GA401 => PANE_LEN * 2, AnimeType::GA402 => PANE_LEN * 3, + AnimeType::GU604 => PANE_LEN * 3, AnimeType::Unknown => 0, } } @@ -115,7 +119,7 @@ impl AnimeDataBuffer { } } -/// The two packets to be written to USB +/// The packets to be written to USB pub type AnimePacketType = Vec<[u8; 640]>; impl TryFrom for AnimePacketType { @@ -128,8 +132,7 @@ impl TryFrom for AnimePacketType { let mut buffers = match anime.anime { AnimeType::GA401 => vec![[0; 640]; 2], - AnimeType::GA402 => vec![[0; 640]; 3], - AnimeType::Unknown => vec![[0; 640]; 1], + AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unknown => vec![[0; 640]; 3], }; for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() { @@ -138,7 +141,10 @@ impl TryFrom for AnimePacketType { buffers[0][..7].copy_from_slice(&USB_PREFIX1); buffers[1][..7].copy_from_slice(&USB_PREFIX2); - if matches!(anime.anime, AnimeType::GA402) { + if matches!( + anime.anime, + AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unknown + ) { buffers[2][..7].copy_from_slice(&USB_PREFIX3); } Ok(buffers) diff --git a/rog-anime/src/diagonal.rs b/rog-anime/src/diagonal.rs index d6008cea..6de5c98e 100644 --- a/rog-anime/src/diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -139,6 +139,7 @@ impl AnimeDiagonal { match anime_type { AnimeType::GA401 => self.to_ga401_packets(), AnimeType::GA402 => self.to_ga402_packets(), + AnimeType::GU604 => self.to_ga402_packets(), AnimeType::Unknown => self.to_unknown_packets(), } } diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 0a2e20c7..6b72de68 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -118,6 +118,7 @@ impl AnimeImage { match anime_type { AnimeType::GA401 => 0.8, AnimeType::GA402 => 0.77, + AnimeType::GU604 => 0.77, AnimeType::Unknown => 0.0, } } @@ -134,6 +135,7 @@ impl AnimeImage { match anime_type { AnimeType::GA401 => 0.3, AnimeType::GA402 => 0.283, + AnimeType::GU604 => 0.283, AnimeType::Unknown => 0.0, } } @@ -175,6 +177,14 @@ impl AnimeImage { // and then their offset grows by one every two rows (y + 1) / 2 - 5 } + AnimeType::GU604 => { + // first 11 rows start at zero + if y <= 9 { + return 0; + } + // and then their offset grows by one every two rows + (y + 1) / 2 - 5 + } AnimeType::Unknown => 0, } } @@ -209,6 +219,12 @@ impl AnimeImage { } 39 - y / 2 } + AnimeType::GU604 => { + if y <= 9 { + return 39; + } + 44 - y / 2 + } AnimeType::Unknown => 0, } } @@ -219,6 +235,7 @@ impl AnimeImage { // 33.0 = Longest row LED count (physical) plus half-pixel offset AnimeType::GA401 => (33.0 + 0.5) * Self::scale_x(anime_type), AnimeType::GA402 => (35.0 + 0.5) * Self::scale_x(anime_type), + AnimeType::GU604 => (35.0 + 0.5) * Self::scale_x(anime_type), AnimeType::Unknown => 0.0, } } @@ -228,6 +245,7 @@ impl AnimeImage { match anime_type { AnimeType::GA401 => 55, AnimeType::GA402 => 61, + AnimeType::GU604 => 61, AnimeType::Unknown => 0, } } @@ -239,6 +257,7 @@ impl AnimeImage { AnimeType::GA401 => (54.0 + 1.0) * Self::scale_y(anime_type), // GA402 may not have dead pixels and require only the physical LED count AnimeType::GA402 => 61.0 * Self::scale_y(anime_type), + AnimeType::GU604 => 61.0 * Self::scale_y(anime_type), AnimeType::Unknown => 0.0, } } @@ -253,6 +272,7 @@ impl AnimeImage { }, // GA402 does not have padding, equivalent to width AnimeType::GA402 => AnimeImage::width(anime_type, y), + AnimeType::GU604 => AnimeImage::width(anime_type, y), AnimeType::Unknown => 0, } } diff --git a/rog-anime/src/usb.rs b/rog-anime/src/usb.rs index d5e0c43a..6d99e323 100644 --- a/rog-anime/src/usb.rs +++ b/rog-anime/src/usb.rs @@ -11,9 +11,6 @@ use crate::error::AnimeError; use crate::AnimeType; -const INIT_STR: [u8; 15] = [ - 0x5e, b'A', b'S', b'U', b'S', b' ', b'T', b'e', b'c', b'h', b'.', b'I', b'n', b'c', b'.', -]; const PACKET_SIZE: usize = 640; const DEV_PAGE: u8 = 0x5e; pub const VENDOR_ID: u16 = 0x0b05; @@ -33,6 +30,8 @@ pub fn get_anime_type() -> Result { return Ok(AnimeType::GA401); } else if board_name.contains("GA402R") { return Ok(AnimeType::GA402); + } else if board_name.contains("GU604V") { + return Ok(AnimeType::GU604); } log::warn!("AniMe Matrix device found but not yet supported"); Ok(AnimeType::Unknown) @@ -45,12 +44,14 @@ pub const fn pkts_for_init() -> [[u8; PACKET_SIZE]; 2] { let mut packets = [[0; PACKET_SIZE]; 2]; packets[0][0] = DEV_PAGE; // This is the USB page we're using throughout let mut count = 0; - while count < INIT_STR.len() { - packets[0][count] = INIT_STR[count]; + // TODO: memcpy or slice copy + let bytes = "ASUS Tech.Inc.".as_bytes(); + while count < bytes.len() { + packets[0][count + 1] = bytes[count]; count += 1; } // - packets[1][0] = DEV_PAGE; // write it to be sure? + packets[1][0] = DEV_PAGE; packets[1][1] = 0xc2; packets } @@ -80,8 +81,9 @@ pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] { /// Get the packet required for setting the device to on. Requires /// `pkt_for_apply()` to be written after. +// TODO: change the users of this method #[inline] -pub const fn pkt_for_set_on(on: bool) -> [u8; PACKET_SIZE] { +pub const fn pkt_for_set_brightness(on: bool) -> [u8; PACKET_SIZE] { let mut pkt = [0; PACKET_SIZE]; pkt[0] = DEV_PAGE; pkt[1] = 0xc0; @@ -90,9 +92,19 @@ pub const fn pkt_for_set_on(on: bool) -> [u8; PACKET_SIZE] { pkt } +#[inline] +pub const fn pkt_for_set_awake_enabled(enable: bool) -> [u8; PACKET_SIZE] { + let mut pkt = [0; PACKET_SIZE]; + pkt[0] = DEV_PAGE; + pkt[1] = 0xc3; + pkt[2] = 0x01; + pkt[3] = if enable { 0x80 } else { 0x00 }; + pkt +} + /// Packet required to apply a device setting #[inline] -pub const fn pkt_for_apply() -> [u8; PACKET_SIZE] { +pub const fn pkt_for_enable_animation() -> [u8; PACKET_SIZE] { let mut pkt = [0; PACKET_SIZE]; pkt[0] = DEV_PAGE; pkt[1] = 0xc4; diff --git a/rog-control-center/src/system_state.rs b/rog-control-center/src/system_state.rs index 3f7e465f..6ef348a8 100644 --- a/rog-control-center/src/system_state.rs +++ b/rog-control-center/src/system_state.rs @@ -204,7 +204,7 @@ impl AnimeState { pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result { Ok(Self { boot: if supported.anime_ctrl.0 { - dbus.proxies().anime().boot_enabled()? + dbus.proxies().anime().animation_enabled()? } else { false }, diff --git a/rog-control-center/src/widgets/anime_power.rs b/rog-control-center/src/widgets/anime_power.rs index 1cd50a1e..4b258f8d 100644 --- a/rog-control-center/src/widgets/anime_power.rs +++ b/rog-control-center/src/widgets/anime_power.rs @@ -42,7 +42,7 @@ pub fn anime_power_group(_supported: &SupportedFunctions, states: &mut SystemSta .asus_dbus .proxies() .anime() - .set_boot_on_off(states.anime.boot) + .set_animation_enabled(states.anime.boot) .map_err(|err| { states.error = Some(err.to_string()); }) @@ -55,7 +55,7 @@ pub fn anime_power_group(_supported: &SupportedFunctions, states: &mut SystemSta .asus_dbus .proxies() .anime() - .set_on_off(states.anime.awake) + .set_awake_enabled(states.anime.awake) .map_err(|err| { states.error = Some(err.to_string()); }) diff --git a/rog-dbus/src/zbus_anime.rs b/rog-dbus/src/zbus_anime.rs index 228a0830..b12da9d9 100644 --- a/rog-dbus/src/zbus_anime.rs +++ b/rog-dbus/src/zbus_anime.rs @@ -7,13 +7,13 @@ use zbus::dbus_proxy; )] trait Anime { /// Set whether the AniMe will show boot, suspend, or off animations - fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>; + fn set_animation_enabled(&self, status: bool) -> zbus::Result<()>; /// Set the global AniMe brightness - fn set_brightness(&self, bright: f32) -> zbus::Result<()>; + fn set_image_brightness(&self, bright: f32) -> zbus::Result<()>; /// Set whether the AniMe is displaying images/data - fn set_on_off(&self, status: bool) -> zbus::Result<()>; + fn set_awake_enabled(&self, status: bool) -> zbus::Result<()>; /// Writes a data stream of length. Will force system thread to exit until /// it is restarted @@ -25,7 +25,7 @@ trait Anime { /// Get the status of if factory system-status animations are enabled #[dbus_proxy(property)] - fn boot_enabled(&self) -> zbus::Result; + fn animation_enabled(&self) -> zbus::Result; /// Notify listeners of the status of AniMe LED power and factory /// system-status animations