diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index c2ff13b7..b7d2c084 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -268,7 +268,7 @@ fn handle_anime( std::process::exit(1); } - let matrix = AnimeDiagonal::from_png(Path::new(&image.path), None, image.bright)?; + let matrix = AnimeDiagonal::from_png(Path::new(&image.path), None, image.bright, anime_type)?; dbus.proxies() .anime() diff --git a/daemon/src/ctrl_anime/config.rs b/daemon/src/ctrl_anime/config.rs index 12a04e45..d45624c5 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -80,8 +80,7 @@ pub struct AnimeConfigCached { } impl AnimeConfigCached { - pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> { - let anime_type = AnimeType::GA401; // TODO: detect + pub fn init_from_config(&mut self, config: &AnimeConfig, anime_type: AnimeType) -> Result<(), AnimeError> { let mut sys = Vec::with_capacity(config.system.len()); for ani in config.system.iter() { sys.push(ActionData::from_anime_action(anime_type, ani)?); diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 0c5ca9b9..f52c632f 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -11,8 +11,7 @@ use rog_anime::{ find_node, get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID, VENDOR_ID, }, - ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, ANIME_GA401_DATA_LEN, - ANIME_GA402_DATA_LEN, + ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, }; use rog_supported::AnimeSupportedFunctions; use rusb::{Device, DeviceHandle}; @@ -61,7 +60,7 @@ impl CtrlAnime { info!("Device has an AniMe Matrix display"); let mut cache = AnimeConfigCached::default(); - cache.init_from_config(&config)?; + cache.init_from_config(&config, anime_type)?; let ctrl = CtrlAnime { _node: node, @@ -202,16 +201,10 @@ impl CtrlAnime { } // Clear the display on exit if let Ok(lock) = inner.try_lock() { - let data = match anime_type { - AnimeType::GA401 => AnimeDataBuffer::from_vec( - anime_type, - [0u8; ANIME_GA401_DATA_LEN].to_vec(), - ), - AnimeType::GA402 => AnimeDataBuffer::from_vec( - anime_type, - [0u8; ANIME_GA402_DATA_LEN].to_vec(), - ), - }; + let data = AnimeDataBuffer::from_vec( + anime_type, + vec![0u8; anime_type.data_length()], + ); lock.write_data_buffer(data); } // Loop ended, set the atmonics diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index 727e3f0d..9fd26212 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -16,9 +16,6 @@ const BLOCK_START: usize = 7; const BLOCK_END: usize = 634; /// Individual usable data length of each USB packet const PANE_LEN: usize = BLOCK_END - BLOCK_START; -/// The length of usable data -pub const ANIME_GA401_DATA_LEN: usize = PANE_LEN * 2; -pub const ANIME_GA402_DATA_LEN: usize = PANE_LEN * 3; /// First packet is for GA401 + GA402 const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02]; @@ -42,6 +39,32 @@ pub enum AnimeType { GA402, } +impl AnimeType { + /// The width of diagonal images + pub fn width(&self) -> usize { + match self { + AnimeType::GA401 => 74, + AnimeType::GA402 => 74, + } + } + + /// The height of diagonal images + pub fn height(&self) -> usize { + match self { + AnimeType::GA401 => 32, + AnimeType::GA402 => 39, + } + } + + /// The length of usable data for this type + pub fn data_length(&self) -> usize { + match self { + AnimeType::GA401 => PANE_LEN * 2, + AnimeType::GA402 => PANE_LEN * 3, + } + } +} + /// The minimal serializable data that can be transferred over wire types. /// Other data structures in `rog_anime` will convert to this. #[cfg_attr(feature = "dbus", derive(Type))] @@ -54,10 +77,7 @@ pub struct AnimeDataBuffer { impl AnimeDataBuffer { #[inline] pub fn new(anime: AnimeType) -> Self { - let len = match anime { - AnimeType::GA401 => ANIME_GA401_DATA_LEN, - AnimeType::GA402 => ANIME_GA402_DATA_LEN, - }; + let len = anime.data_length(); AnimeDataBuffer { data: vec![0u8; len], @@ -83,10 +103,8 @@ impl AnimeDataBuffer { /// Will panic if the vector length is not `ANIME_DATA_LEN` #[inline] pub fn from_vec(anime: AnimeType, data: Vec) -> Self { - match anime { - AnimeType::GA401 => assert_eq!(data.len(), ANIME_GA401_DATA_LEN), - AnimeType::GA402 => assert_eq!(data.len(), ANIME_GA402_DATA_LEN), - } + assert_eq!(data.len(), anime.data_length()); + Self { data, anime } } } @@ -97,15 +115,11 @@ pub type AnimePacketType = Vec<[u8; 640]>; impl From for AnimePacketType { #[inline] fn from(anime: AnimeDataBuffer) -> Self { + assert_eq!(anime.data.len(), anime.anime.data_length()); + let mut buffers = match anime.anime { - AnimeType::GA401 => { - assert!(anime.data.len() == ANIME_GA401_DATA_LEN); - vec![[0; 640]; 2] - } - AnimeType::GA402 => { - assert!(anime.data.len() == ANIME_GA402_DATA_LEN); - vec![[0; 640]; 3] - } + AnimeType::GA401 => vec![[0; 640]; 2], + AnimeType::GA402 => vec![[0; 640]; 3], }; for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() { diff --git a/rog-anime/src/diagonal.rs b/rog-anime/src/diagonal.rs index 68b1a48e..fd457b9d 100644 --- a/rog-anime/src/diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -1,42 +1,31 @@ use std::{path::Path, time::Duration}; -use crate::{ - data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN}, - error::AnimeError, - AnimeType, ANIME_GA402_DATA_LEN, -}; - -const WIDTH: usize = 74; -// TODO: Change for GA402 -const HEIGHT: usize = 36; +use crate::{data::AnimeDataBuffer, error::AnimeError, AnimeType}; /// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images) #[derive(Debug, Clone)] -pub struct AnimeDiagonal([[u8; WIDTH]; HEIGHT], Option); - -impl Default for AnimeDiagonal { - #[inline] - fn default() -> Self { - Self::new(None) - } -} +pub struct AnimeDiagonal(AnimeType, Vec>, Option); impl AnimeDiagonal { #[inline] - pub fn new(duration: Option) -> Self { - Self([[0u8; WIDTH]; HEIGHT], duration) + pub fn new(anime_type: AnimeType, duration: Option) -> Self { + Self( + anime_type, + vec![vec![0; anime_type.width()]; anime_type.height()], + duration, + ) } #[inline] - pub fn get_mut(&mut self) -> &mut [[u8; WIDTH]; HEIGHT] { - &mut self.0 + pub fn get_mut(&mut self) -> &mut Vec> { + &mut self.1 } /// Get a full diagonal row where `x` `y` is the starting point and `len` is the length of data. fn get_row(&self, x: usize, y: usize, len: usize) -> Vec { let mut buf = Vec::with_capacity(len); for i in 0..len { - let val = self.0[HEIGHT - y - i - 1][x + i]; + let val = self.1[self.0.height() - y - i - 1][x + i]; buf.push(val); } buf @@ -49,13 +38,14 @@ impl AnimeDiagonal { path: &Path, duration: Option, bright: f32, + anime_type: AnimeType, ) -> Result { let data = std::fs::read(path)?; let data = std::io::Cursor::new(data); let decoder = png_pong::Decoder::new(data)?.into_steps(); let png_pong::Step { raster, delay: _ } = decoder.last().ok_or(AnimeError::NoFrames)??; - let mut matrix = AnimeDiagonal::new(duration); + let mut matrix = AnimeDiagonal::new(anime_type, duration); match raster { png_pong::PngRaster::Gray8(ras) => { @@ -102,7 +92,7 @@ impl AnimeDiagonal { + (::from(px.two()) / 3) as f32 + (::from(px.three()) / 3) as f32 }; - matrix.0[y][x] = (v * bright) as u8; + matrix.1[y][x] = (v * bright) as u8; } } } @@ -125,7 +115,7 @@ impl AnimeDiagonal { + ((::from(px.two()) / 3) >> 8) as f32 + ((::from(px.three()) / 3) >> 8) as f32 }; - matrix.0[y][x] = (v * bright) as u8; + matrix.1[y][x] = (v * bright) as u8; } } } @@ -142,7 +132,7 @@ impl AnimeDiagonal { /// Do conversion from the nested Vec in AnimeMatrix to the two required /// packets suitable for sending over USB fn into_ga401_packets(&self) -> AnimeDataBuffer { - let mut buf = vec![0u8; ANIME_GA401_DATA_LEN]; + let mut buf = vec![0u8; AnimeType::GA401.data_length()]; buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32)); buf[34..=66].copy_from_slice(&self.get_row(0, 2, 33)); @@ -204,7 +194,7 @@ impl AnimeDiagonal { } fn into_ga402_packets(&self) -> AnimeDataBuffer { - let mut buf = vec![0u8; ANIME_GA402_DATA_LEN]; + let mut buf = vec![0u8; AnimeType::GA402.data_length()]; let mut start_index: usize = 0; fn copy_slice( @@ -291,7 +281,7 @@ impl AnimeDiagonal { mod tests { use std::path::PathBuf; - use crate::{AnimeDiagonal, AnimePacketType}; + use crate::{AnimeDiagonal, AnimePacketType, AnimeType}; #[test] fn ga401_diagonal_packet_check() { @@ -380,7 +370,7 @@ mod tests { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("test/ga401-diagonal.png"); - let matrix = AnimeDiagonal::from_png(&path, None, 255.0).unwrap(); + let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA401).unwrap(); let data = matrix.into_data_buffer(crate::AnimeType::GA401); let pkt = AnimePacketType::from(data); diff --git a/rog-anime/src/gif.rs b/rog-anime/src/gif.rs index d796c053..5e33ba55 100644 --- a/rog-anime/src/gif.rs +++ b/rog-anime/src/gif.rs @@ -90,12 +90,11 @@ impl AnimeGif { #[inline] pub fn from_diagonal_gif( file_name: &Path, - duration: AnimTime, brightness: f32, anime_type: AnimeType, ) -> Result { - let mut matrix = AnimeDiagonal::new(None); + let mut matrix = AnimeDiagonal::new(anime_type, None); let mut decoder = gif::DecodeOptions::new(); // Configure the decoder such that it will expand the image to RGBA. @@ -138,7 +137,7 @@ impl AnimeGif { duration: AnimTime, brightness: f32, ) -> Result { - let image = AnimeDiagonal::from_png(file_name, None, brightness)?; + let image = AnimeDiagonal::from_png(file_name, None, brightness, anime_type)?; let mut total = Duration::from_millis(1000); if let AnimTime::Fade(fade) = duration { diff --git a/rog-anime/src/grid.rs b/rog-anime/src/grid.rs index eb3e3910..f80e84e2 100644 --- a/rog-anime/src/grid.rs +++ b/rog-anime/src/grid.rs @@ -1,5 +1,5 @@ -use crate::data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN}; -use crate::{AnimeImage, AnimeType, ANIME_GA402_DATA_LEN}; +use crate::data::AnimeDataBuffer; +use crate::{AnimeImage, AnimeType}; // TODO: Adjust these sizes as WIDTH_GA401 WIDTH_GA402 const WIDTH: usize = 33; @@ -92,10 +92,7 @@ impl From for AnimeDataBuffer { /// packets suitable for sending over USB #[inline] fn from(anime: AnimeGrid) -> Self { - let mut buf = match anime.anime_type { - AnimeType::GA401 => vec![0u8; ANIME_GA401_DATA_LEN], - AnimeType::GA402 => vec![0u8; ANIME_GA402_DATA_LEN], - }; + let mut buf = vec![0u8; anime.anime_type.data_length()]; for (idx, pos) in AnimeImage::generate_image_positioning(anime.anime_type) .iter() diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 570de37b..8d2640de 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -3,11 +3,7 @@ use std::path::Path; pub use glam::Vec2; use glam::{Mat3, Vec3}; -use crate::{ - data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN}, - error::AnimeError, - AnimeType, -}; +use crate::{data::AnimeDataBuffer, error::AnimeError, AnimeType}; /// A single greyscale + alpha pixel in the image #[derive(Copy, Clone, Debug)] @@ -392,7 +388,7 @@ impl From<&AnimeImage> for AnimeDataBuffer { .iter() .map(|l| if let Some(l) = l { l.bright() } else { 0 }) .collect(); - let mut v = Vec::with_capacity(ANIME_GA401_DATA_LEN); + let mut v = Vec::with_capacity(leds.anime_type.data_length()); v.push(0); v.append(&mut l); v.append(&mut vec![0u8; 9]); diff --git a/rog-anime/src/sequencer.rs b/rog-anime/src/sequencer.rs index a71099a2..fa30b3ae 100644 --- a/rog-anime/src/sequencer.rs +++ b/rog-anime/src/sequencer.rs @@ -86,7 +86,7 @@ impl ActionData { brightness, } => match time { AnimTime::Infinite => { - let image = AnimeDiagonal::from_png(file, None, *brightness)?; + let image = AnimeDiagonal::from_png(file, None, *brightness, anime_type)?; let data = image.into_data_buffer(anime_type); ActionData::Image(Box::new(data)) } diff --git a/rog-anime/src/usb.rs b/rog-anime/src/usb.rs index c8fa60ec..c6507ec2 100644 --- a/rog-anime/src/usb.rs +++ b/rog-anime/src/usb.rs @@ -28,7 +28,7 @@ pub fn get_anime_type() -> Result { if board_name.contains("GA401Q") { return Ok(AnimeType::GA401); - } else if board_name.contains("GA401R") { + } else if board_name.contains("GA402R") { return Ok(AnimeType::GA402); } Err(AnimeError::UnsupportedDevice)