From ff76c356c5f1acafe3cb1fbc5e6266b18698d31d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 9 Jul 2022 15:01:07 +1200 Subject: [PATCH 1/8] First pass of Anime update for new matrix display Co-authored with @I-Al-Istannen Part of #189 --- CHANGELOG.md | 3 + Cargo.lock | 2 + asusctl/examples/anime-outline.rs | 224 ++--- asusctl/src/main.rs | 7 +- daemon-user/src/daemon.rs | 4 +- daemon-user/src/user_config.rs | 6 +- daemon/src/ctrl_anime/config.rs | 11 +- daemon/src/ctrl_anime/mod.rs | 55 +- rog-anime/Cargo.toml | 6 +- rog-anime/src/data.rs | 77 +- rog-anime/src/diagonal.rs | 317 ++++-- rog-anime/src/error.rs | 6 + rog-anime/src/gif.rs | 16 +- rog-anime/src/grid.rs | 50 +- rog-anime/src/image.rs | 1485 +++-------------------------- rog-anime/src/sequencer.rs | 49 +- rog-anime/src/usb.rs | 43 + rog-anime/test/ga401-diagonal.gif | Bin 0 -> 981 bytes rog-anime/test/ga401-diagonal.png | Bin 0 -> 6168 bytes rog-anime/test/ga402-diagonal.gif | Bin 0 -> 189 bytes rog-anime/test/ga402-diagonal.png | Bin 0 -> 670 bytes 21 files changed, 734 insertions(+), 1627 deletions(-) create mode 100644 rog-anime/test/ga401-diagonal.gif create mode 100644 rog-anime/test/ga401-diagonal.png create mode 100644 rog-anime/test/ga402-diagonal.gif create mode 100644 rog-anime/test/ga402-diagonal.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 540a17db..053051c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased ] +### Changed +- Data for anime-matrix now requires passing the laptop model as enum + ### Added - Support for GA503R LED modes ### Changed diff --git a/Cargo.lock b/Cargo.lock index 05eddef7..2d39f79a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,6 +1027,8 @@ dependencies = [ "png_pong", "serde", "serde_derive", + "sysfs-class", + "udev", "zvariant", ] diff --git a/asusctl/examples/anime-outline.rs b/asusctl/examples/anime-outline.rs index 88602872..35829eb9 100644 --- a/asusctl/examples/anime-outline.rs +++ b/asusctl/examples/anime-outline.rs @@ -7,122 +7,122 @@ use rog_dbus::RogDbusClientBlocking; fn main() { let (client, _) = RogDbusClientBlocking::new().unwrap(); let mut matrix = AnimeDataBuffer::new(); - matrix.get_mut()[1] = 100; // start = 1 - for n in matrix.get_mut()[2..32].iter_mut() { + matrix.data_mut()[1] = 100; // start = 1 + for n in matrix.data_mut()[2..32].iter_mut() { *n = 250; } - matrix.get_mut()[32] = 100; // end - matrix.get_mut()[34] = 100; // start x = 0 - matrix.get_mut()[66] = 100; // end - matrix.get_mut()[69] = 100; // start x = 1 - matrix.get_mut()[101] = 100; // end - matrix.get_mut()[102] = 100; // start - matrix.get_mut()[134] = 100; // end - matrix.get_mut()[137] = 100; // start - matrix.get_mut()[169] = 100; // end - matrix.get_mut()[170] = 100; // start - matrix.get_mut()[202] = 100; // end - matrix.get_mut()[204] = 100; // start - matrix.get_mut()[236] = 100; // end - matrix.get_mut()[237] = 100; // start - matrix.get_mut()[268] = 100; // end - matrix.get_mut()[270] = 100; // start - matrix.get_mut()[301] = 100; // end - matrix.get_mut()[302] = 100; // start - matrix.get_mut()[332] = 100; // end - matrix.get_mut()[334] = 100; // start - matrix.get_mut()[364] = 100; // end - matrix.get_mut()[365] = 100; // start - matrix.get_mut()[394] = 100; // end - matrix.get_mut()[396] = 100; // start - matrix.get_mut()[425] = 100; // end - matrix.get_mut()[426] = 100; // start - matrix.get_mut()[454] = 100; // end - matrix.get_mut()[456] = 100; // start - matrix.get_mut()[484] = 100; // end - matrix.get_mut()[485] = 100; // start - matrix.get_mut()[512] = 100; // end - matrix.get_mut()[514] = 100; // start - matrix.get_mut()[541] = 100; // end - matrix.get_mut()[542] = 100; // start - matrix.get_mut()[568] = 100; // end - matrix.get_mut()[570] = 100; // start - matrix.get_mut()[596] = 100; // end - matrix.get_mut()[597] = 100; // start - matrix.get_mut()[622] = 100; // end - matrix.get_mut()[624] = 100; // start - matrix.get_mut()[649] = 100; // end - matrix.get_mut()[650] = 100; // start - matrix.get_mut()[674] = 100; // end - matrix.get_mut()[676] = 100; // start - matrix.get_mut()[700] = 100; // end - matrix.get_mut()[701] = 100; // start - matrix.get_mut()[724] = 100; // end - matrix.get_mut()[726] = 100; // start - matrix.get_mut()[749] = 100; // end - matrix.get_mut()[750] = 100; // start - matrix.get_mut()[772] = 100; // end - matrix.get_mut()[774] = 100; // start - matrix.get_mut()[796] = 100; // end - matrix.get_mut()[797] = 100; // start - matrix.get_mut()[818] = 100; // end - matrix.get_mut()[820] = 100; // start - matrix.get_mut()[841] = 100; // end - matrix.get_mut()[842] = 100; // start - matrix.get_mut()[862] = 100; // end - matrix.get_mut()[864] = 100; // start - matrix.get_mut()[884] = 100; // end - matrix.get_mut()[885] = 100; // start - matrix.get_mut()[904] = 100; // end - matrix.get_mut()[906] = 100; // start - matrix.get_mut()[925] = 100; // end - matrix.get_mut()[926] = 100; // start - matrix.get_mut()[944] = 100; // end - matrix.get_mut()[946] = 100; // start - matrix.get_mut()[964] = 100; // end - matrix.get_mut()[965] = 100; // start - matrix.get_mut()[982] = 100; // end - matrix.get_mut()[984] = 100; // start - matrix.get_mut()[1001] = 100; // end - matrix.get_mut()[1002] = 100; // start - matrix.get_mut()[1018] = 100; // end - matrix.get_mut()[1020] = 100; // start - matrix.get_mut()[1036] = 100; // end - matrix.get_mut()[1037] = 100; // start - matrix.get_mut()[1052] = 100; // end - matrix.get_mut()[1054] = 100; // start - matrix.get_mut()[1069] = 100; // end - matrix.get_mut()[1070] = 100; // start - matrix.get_mut()[1084] = 100; // end - matrix.get_mut()[1086] = 100; // start - matrix.get_mut()[1100] = 100; // end - matrix.get_mut()[1101] = 100; // start - matrix.get_mut()[1114] = 100; // end - matrix.get_mut()[1116] = 100; // start - matrix.get_mut()[1129] = 100; // end - matrix.get_mut()[1130] = 100; // start - matrix.get_mut()[1142] = 100; // end - matrix.get_mut()[1144] = 100; // start - matrix.get_mut()[1156] = 100; // end - matrix.get_mut()[1157] = 100; // start - matrix.get_mut()[1168] = 100; // end - matrix.get_mut()[1170] = 100; // start - matrix.get_mut()[1181] = 100; // end - matrix.get_mut()[1182] = 100; // start - matrix.get_mut()[1192] = 100; // end - matrix.get_mut()[1194] = 100; // start - matrix.get_mut()[1204] = 100; // end - matrix.get_mut()[1205] = 100; // start - matrix.get_mut()[1214] = 100; // end - matrix.get_mut()[1216] = 100; // start - matrix.get_mut()[1225] = 100; // end - matrix.get_mut()[1226] = 100; // start - matrix.get_mut()[1234] = 100; // end - matrix.get_mut()[1236] = 100; // start - for n in matrix.get_mut()[1237..1244].iter_mut() { + matrix.data_mut()[32] = 100; // end + matrix.data_mut()[34] = 100; // start x = 0 + matrix.data_mut()[66] = 100; // end + matrix.data_mut()[69] = 100; // start x = 1 + matrix.data_mut()[101] = 100; // end + matrix.data_mut()[102] = 100; // start + matrix.data_mut()[134] = 100; // end + matrix.data_mut()[137] = 100; // start + matrix.data_mut()[169] = 100; // end + matrix.data_mut()[170] = 100; // start + matrix.data_mut()[202] = 100; // end + matrix.data_mut()[204] = 100; // start + matrix.data_mut()[236] = 100; // end + matrix.data_mut()[237] = 100; // start + matrix.data_mut()[268] = 100; // end + matrix.data_mut()[270] = 100; // start + matrix.data_mut()[301] = 100; // end + matrix.data_mut()[302] = 100; // start + matrix.data_mut()[332] = 100; // end + matrix.data_mut()[334] = 100; // start + matrix.data_mut()[364] = 100; // end + matrix.data_mut()[365] = 100; // start + matrix.data_mut()[394] = 100; // end + matrix.data_mut()[396] = 100; // start + matrix.data_mut()[425] = 100; // end + matrix.data_mut()[426] = 100; // start + matrix.data_mut()[454] = 100; // end + matrix.data_mut()[456] = 100; // start + matrix.data_mut()[484] = 100; // end + matrix.data_mut()[485] = 100; // start + matrix.data_mut()[512] = 100; // end + matrix.data_mut()[514] = 100; // start + matrix.data_mut()[541] = 100; // end + matrix.data_mut()[542] = 100; // start + matrix.data_mut()[568] = 100; // end + matrix.data_mut()[570] = 100; // start + matrix.data_mut()[596] = 100; // end + matrix.data_mut()[597] = 100; // start + matrix.data_mut()[622] = 100; // end + matrix.data_mut()[624] = 100; // start + matrix.data_mut()[649] = 100; // end + matrix.data_mut()[650] = 100; // start + matrix.data_mut()[674] = 100; // end + matrix.data_mut()[676] = 100; // start + matrix.data_mut()[700] = 100; // end + matrix.data_mut()[701] = 100; // start + matrix.data_mut()[724] = 100; // end + matrix.data_mut()[726] = 100; // start + matrix.data_mut()[749] = 100; // end + matrix.data_mut()[750] = 100; // start + matrix.data_mut()[772] = 100; // end + matrix.data_mut()[774] = 100; // start + matrix.data_mut()[796] = 100; // end + matrix.data_mut()[797] = 100; // start + matrix.data_mut()[818] = 100; // end + matrix.data_mut()[820] = 100; // start + matrix.data_mut()[841] = 100; // end + matrix.data_mut()[842] = 100; // start + matrix.data_mut()[862] = 100; // end + matrix.data_mut()[864] = 100; // start + matrix.data_mut()[884] = 100; // end + matrix.data_mut()[885] = 100; // start + matrix.data_mut()[904] = 100; // end + matrix.data_mut()[906] = 100; // start + matrix.data_mut()[925] = 100; // end + matrix.data_mut()[926] = 100; // start + matrix.data_mut()[944] = 100; // end + matrix.data_mut()[946] = 100; // start + matrix.data_mut()[964] = 100; // end + matrix.data_mut()[965] = 100; // start + matrix.data_mut()[982] = 100; // end + matrix.data_mut()[984] = 100; // start + matrix.data_mut()[1001] = 100; // end + matrix.data_mut()[1002] = 100; // start + matrix.data_mut()[1018] = 100; // end + matrix.data_mut()[1020] = 100; // start + matrix.data_mut()[1036] = 100; // end + matrix.data_mut()[1037] = 100; // start + matrix.data_mut()[1052] = 100; // end + matrix.data_mut()[1054] = 100; // start + matrix.data_mut()[1069] = 100; // end + matrix.data_mut()[1070] = 100; // start + matrix.data_mut()[1084] = 100; // end + matrix.data_mut()[1086] = 100; // start + matrix.data_mut()[1100] = 100; // end + matrix.data_mut()[1101] = 100; // start + matrix.data_mut()[1114] = 100; // end + matrix.data_mut()[1116] = 100; // start + matrix.data_mut()[1129] = 100; // end + matrix.data_mut()[1130] = 100; // start + matrix.data_mut()[1142] = 100; // end + matrix.data_mut()[1144] = 100; // start + matrix.data_mut()[1156] = 100; // end + matrix.data_mut()[1157] = 100; // start + matrix.data_mut()[1168] = 100; // end + matrix.data_mut()[1170] = 100; // start + matrix.data_mut()[1181] = 100; // end + matrix.data_mut()[1182] = 100; // start + matrix.data_mut()[1192] = 100; // end + matrix.data_mut()[1194] = 100; // start + matrix.data_mut()[1204] = 100; // end + matrix.data_mut()[1205] = 100; // start + matrix.data_mut()[1214] = 100; // end + matrix.data_mut()[1216] = 100; // start + matrix.data_mut()[1225] = 100; // end + matrix.data_mut()[1226] = 100; // start + matrix.data_mut()[1234] = 100; // end + matrix.data_mut()[1236] = 100; // start + for n in matrix.data_mut()[1237..1244].iter_mut() { *n = 250; } - matrix.get_mut()[1244] = 100; // end + matrix.data_mut()[1244] = 100; // end println!("{:?}", &matrix); client.proxies().anime().write(matrix).unwrap(); diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 8702ce7f..c2ff13b7 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -7,6 +7,7 @@ use gumdrop::{Opt, Options}; use anime_cli::{AnimeActions, AnimeCommand}; use profiles_cli::{FanCurveCommand, ProfileCommand}; +use rog_anime::usb::get_anime_type; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; use rog_aura::usb::AuraControl; use rog_aura::{self, AuraEffect}; @@ -234,6 +235,7 @@ fn handle_anime( dbus.proxies().anime().set_brightness(bright as f32)? } if let Some(action) = cmd.command.as_ref() { + let anime_type = get_anime_type()?; match action { AnimeActions::Image(image) => { if image.help_requested() || image.path.is_empty() { @@ -250,6 +252,7 @@ fn handle_anime( image.angle, Vec2::new(image.x_pos, image.y_pos), image.bright, + anime_type, )?; dbus.proxies() @@ -269,7 +272,7 @@ fn handle_anime( dbus.proxies() .anime() - .write(::from(&matrix))?; + .write(matrix.into_data_buffer(anime_type))?; } AnimeActions::Gif(gif) => { if gif.help_requested() || gif.path.is_empty() { @@ -287,6 +290,7 @@ fn handle_anime( Vec2::new(gif.x_pos, gif.y_pos), AnimTime::Count(1), gif.bright, + anime_type, )?; let mut loops = gif.loops as i32; @@ -316,6 +320,7 @@ fn handle_anime( Path::new(&gif.path), AnimTime::Count(1), gif.bright, + anime_type, )?; let mut loops = gif.loops as i32; diff --git a/daemon-user/src/daemon.rs b/daemon-user/src/daemon.rs index 67294c99..39c8c99f 100644 --- a/daemon-user/src/daemon.rs +++ b/daemon-user/src/daemon.rs @@ -1,3 +1,4 @@ +use rog_anime::usb::get_anime_type; use rog_dbus::RogDbusClientBlocking; use rog_user::{ ctrl_anime::{CtrlAnime, CtrlAnimeInner}, @@ -28,8 +29,9 @@ fn main() -> Result<(), Box> { let early_return = Arc::new(AtomicBool::new(false)); // Set up the anime data and run loop/thread if supported.anime_ctrl.0 { + let anime_type = get_anime_type()?; let anime_config = UserAnimeConfig::load_config(config.active_anime)?; - let anime = anime_config.create_anime()?; + let anime = anime_config.create_anime(anime_type)?; let anime_config = Arc::new(Mutex::new(anime_config)); executor diff --git a/daemon-user/src/user_config.rs b/daemon-user/src/user_config.rs index c0762604..5f424096 100644 --- a/daemon-user/src/user_config.rs +++ b/daemon-user/src/user_config.rs @@ -4,7 +4,7 @@ use std::{ time::Duration, }; -use rog_anime::{ActionLoader, AnimTime, Fade, Sequences, Vec2}; +use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2}; use serde_derive::{Deserialize, Serialize}; use crate::error::Error; @@ -16,8 +16,8 @@ pub struct UserAnimeConfig { } impl UserAnimeConfig { - pub fn create_anime(&self) -> Result { - let mut seq = Sequences::new(); + pub fn create_anime(&self, anime_type: AnimeType) -> Result { + let mut seq = Sequences::new(anime_type); for (idx, action) in self.anime.iter().enumerate() { seq.insert(idx, action)?; diff --git a/daemon/src/ctrl_anime/config.rs b/daemon/src/ctrl_anime/config.rs index c18c4220..12a04e45 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -1,7 +1,7 @@ use crate::VERSION; use log::{error, info, warn}; -use rog_anime::Fade; use rog_anime::{error::AnimeError, ActionData, ActionLoader, AnimTime, Vec2}; +use rog_anime::{AnimeType, Fade}; use serde_derive::{Deserialize, Serialize}; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; @@ -81,27 +81,28 @@ pub struct AnimeConfigCached { impl AnimeConfigCached { pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> { + let anime_type = AnimeType::GA401; // TODO: detect let mut sys = Vec::with_capacity(config.system.len()); for ani in config.system.iter() { - sys.push(ActionData::from_anime_action(ani)?); + sys.push(ActionData::from_anime_action(anime_type, ani)?); } self.system = sys; let mut boot = Vec::with_capacity(config.boot.len()); for ani in config.boot.iter() { - boot.push(ActionData::from_anime_action(ani)?); + boot.push(ActionData::from_anime_action(anime_type, ani)?); } self.boot = boot; let mut wake = Vec::with_capacity(config.wake.len()); for ani in config.wake.iter() { - wake.push(ActionData::from_anime_action(ani)?); + wake.push(ActionData::from_anime_action(anime_type, ani)?); } self.wake = wake; let mut shutdown = Vec::with_capacity(config.shutdown.len()); for ani in config.shutdown.iter() { - shutdown.push(ActionData::from_anime_action(ani)?); + shutdown.push(ActionData::from_anime_action(anime_type, ani)?); } self.shutdown = shutdown; Ok(()) diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index fef33c46..0c5ca9b9 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -8,10 +8,11 @@ use logind_zbus::manager::ManagerProxy; use rog_anime::{ error::AnimeError, usb::{ - pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID, - VENDOR_ID, + 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, ANIME_DATA_LEN, + ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, ANIME_GA401_DATA_LEN, + ANIME_GA402_DATA_LEN, }; use rog_supported::AnimeSupportedFunctions; use rusb::{Device, DeviceHandle}; @@ -41,6 +42,7 @@ impl GetSupported for CtrlAnime { pub struct CtrlAnime { _node: String, + anime_type: AnimeType, handle: RefCell>, cache: AnimeConfigCached, config: AnimeConfig, @@ -53,7 +55,8 @@ pub struct CtrlAnime { impl CtrlAnime { #[inline] pub fn new(config: AnimeConfig) -> Result> { - let node = Self::find_node("193b")?; + let node = find_node("193b")?; + let anime_type = get_anime_type()?; let device = Self::get_dev_handle()?; info!("Device has an AniMe Matrix display"); @@ -62,6 +65,7 @@ impl CtrlAnime { let ctrl = CtrlAnime { _node: node, + anime_type, handle: RefCell::new(device), cache, config, @@ -73,34 +77,6 @@ impl CtrlAnime { Ok(ctrl) } - fn find_node(id_product: &str) -> Result { - let mut enumerator = udev::Enumerator::new().map_err(|err| { - warn!("{}", err); - RogError::Udev("enumerator failed".into(), err) - })?; - enumerator.match_subsystem("usb").map_err(|err| { - warn!("{}", err); - RogError::Udev("match_subsystem failed".into(), err) - })?; - - for device in enumerator.scan_devices().map_err(|err| { - warn!("{}", err); - RogError::Udev("scan_devices failed".into(), err) - })? { - if let Some(attr) = device.attribute_value("idProduct") { - if attr == id_product { - if let Some(dev_node) = device.devnode() { - info!("Using device at: {:?} for AniMe control", dev_node); - return Ok(dev_node.to_string_lossy().to_string()); - } - } - } - } - Err(RogError::MissingFunction( - "ASUS AniMe device node not found".into(), - )) - } - fn get_dev_handle() -> Result, Box> { // We don't expect this ID to ever change let device = CtrlAnime::get_device(0x0b05, 0x193b)?; @@ -156,10 +132,12 @@ impl CtrlAnime { // we don't block other threads/main let thread_exit; let thread_running; + let anime_type; loop { if let Ok(lock) = inner.try_lock() { thread_exit = lock.thread_exit.clone(); thread_running = lock.thread_running.clone(); + anime_type = lock.anime_type; break; } } @@ -224,7 +202,16 @@ impl CtrlAnime { } // Clear the display on exit if let Ok(lock) = inner.try_lock() { - let data = AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec()); + 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(), + ), + }; lock.write_data_buffer(data); } // Loop ended, set the atmonics @@ -277,7 +264,7 @@ impl CtrlAnime { /// Write only a data packet. This will modify the leds brightness using the /// global brightness set in config. fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) { - for led in buffer.get_mut()[7..].iter_mut() { + for led in buffer.data_mut()[7..].iter_mut() { let mut bright = *led as f32 * self.config.brightness; if bright > 254.0 { bright = 254.0; diff --git a/rog-anime/Cargo.toml b/rog-anime/Cargo.toml index 2d410ee6..34f14643 100644 --- a/rog-anime/Cargo.toml +++ b/rog-anime/Cargo.toml @@ -13,8 +13,9 @@ edition = "2018" exclude = ["data"] [features] -default = ["dbus"] +default = ["dbus", "detect"] dbus = ["zvariant"] +detect = ["udev", "sysfs-class"] [dependencies] png_pong = "^0.8.0" @@ -28,3 +29,6 @@ serde_derive = "^1.0" glam = { version = "0.20.5", features = ["serde"] } zvariant = { version = "^3.0", optional = true } + +udev = { version = "^0.6", optional = true } +sysfs-class = { version = "^0.1", optional = true } \ No newline at end of file diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index 9029afd7..727e3f0d 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -17,10 +17,15 @@ 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_DATA_LEN: usize = PANE_LEN * 2; +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]; +/// Second packet is for GA401 + GA402 const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02]; +/// Third packet is for GA402 matrix +const USB_PREFIX3: [u8; 7] = [0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02]; #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] @@ -30,34 +35,46 @@ pub struct AnimePowerStates { pub boot_anim_enabled: bool, } +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Debug, Copy, Clone, Deserialize, Serialize)] +pub enum AnimeType { + GA401, + GA402, +} + /// 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))] #[derive(Debug, Clone, Deserialize, Serialize)] -pub struct AnimeDataBuffer(Vec); - -impl Default for AnimeDataBuffer { - fn default() -> Self { - Self::new() - } +pub struct AnimeDataBuffer { + data: Vec, + anime: AnimeType, } impl AnimeDataBuffer { #[inline] - pub fn new() -> Self { - AnimeDataBuffer(vec![0u8; ANIME_DATA_LEN]) + pub fn new(anime: AnimeType) -> Self { + let len = match anime { + AnimeType::GA401 => ANIME_GA401_DATA_LEN, + AnimeType::GA402 => ANIME_GA402_DATA_LEN, + }; + + AnimeDataBuffer { + data: vec![0u8; len], + anime, + } } /// Get the inner data buffer #[inline] - pub fn get(&self) -> &[u8] { - &self.0 + pub fn data(&self) -> &[u8] { + &self.data } /// Get a mutable slice of the inner buffer #[inline] - pub fn get_mut(&mut self) -> &mut [u8] { - &mut self.0 + pub fn data_mut(&mut self) -> &mut [u8] { + &mut self.data } /// Create from a vector of bytes @@ -65,25 +82,41 @@ impl AnimeDataBuffer { /// # Panics /// Will panic if the vector length is not `ANIME_DATA_LEN` #[inline] - pub fn from_vec(input: Vec) -> Self { - assert_eq!(input.len(), ANIME_DATA_LEN); - Self(input) + 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), + } + Self { data, anime } } } /// The two packets to be written to USB -pub type AnimePacketType = [[u8; 640]; 2]; +pub type AnimePacketType = Vec<[u8; 640]>; impl From for AnimePacketType { #[inline] fn from(anime: AnimeDataBuffer) -> Self { - assert!(anime.0.len() == ANIME_DATA_LEN); - let mut buffers = [[0; 640]; 2]; - for (idx, chunk) in anime.0.as_slice().chunks(PANE_LEN).enumerate() { + 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] + } + }; + + for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() { buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk); } buffers[0][..7].copy_from_slice(&USB_PREFIX1); buffers[1][..7].copy_from_slice(&USB_PREFIX2); + + if matches!(anime.anime, AnimeType::GA402) { + buffers[2][..7].copy_from_slice(&USB_PREFIX3); + } buffers } } @@ -142,7 +175,7 @@ pub fn run_animation( if let AnimTime::Fade(_) = frames.duration() { if frame_start <= start + fade_in { - for pixel in output.get_mut() { + for pixel in output.data_mut() { *pixel = (*pixel as f32 * fade_in_accum) as u8; } fade_in_accum = fade_in_step * (frame_start - start).as_secs_f32(); @@ -153,7 +186,7 @@ pub fn run_animation( } else { fade_out_accum = 0.0; } - for pixel in output.get_mut() { + for pixel in output.data_mut() { *pixel = (*pixel as f32 * fade_out_accum) as u8; } } diff --git a/rog-anime/src/diagonal.rs b/rog-anime/src/diagonal.rs index ba770baa..68b1a48e 100644 --- a/rog-anime/src/diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -1,11 +1,13 @@ use std::{path::Path, time::Duration}; use crate::{ - data::{AnimeDataBuffer, ANIME_DATA_LEN}, + 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; /// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images) @@ -127,71 +129,262 @@ impl AnimeDiagonal { } } } -} -impl From<&AnimeDiagonal> for AnimeDataBuffer { + /// Convert to a data buffer that can be sent over dbus + #[inline] + pub fn into_data_buffer(&self, anime_type: AnimeType) -> AnimeDataBuffer { + match anime_type { + AnimeType::GA401 => self.into_ga401_packets(), + AnimeType::GA402 => self.into_ga402_packets(), + } + } + /// Do conversion from the nested Vec in AnimeMatrix to the two required /// packets suitable for sending over USB - #[inline] - fn from(anime: &AnimeDiagonal) -> Self { - let mut buf = vec![0u8; ANIME_DATA_LEN]; + fn into_ga401_packets(&self) -> AnimeDataBuffer { + let mut buf = vec![0u8; ANIME_GA401_DATA_LEN]; - buf[1..=32].copy_from_slice(&anime.get_row(0, 3, 32)); - buf[34..=66].copy_from_slice(&anime.get_row(0, 2, 33)); - buf[69..=101].copy_from_slice(&anime.get_row(1, 2, 33)); // ?! - buf[102..=134].copy_from_slice(&anime.get_row(1, 1, 33)); - buf[137..=169].copy_from_slice(&anime.get_row(2, 1, 33)); - buf[170..=202].copy_from_slice(&anime.get_row(2, 0, 33)); - buf[204..=236].copy_from_slice(&anime.get_row(3, 0, 33)); - buf[237..=268].copy_from_slice(&anime.get_row(4, 0, 32)); - buf[270..=301].copy_from_slice(&anime.get_row(5, 0, 32)); - buf[302..=332].copy_from_slice(&anime.get_row(6, 0, 31)); - buf[334..=364].copy_from_slice(&anime.get_row(7, 0, 31)); - buf[365..=394].copy_from_slice(&anime.get_row(8, 0, 30)); - buf[396..=425].copy_from_slice(&anime.get_row(9, 0, 30)); - buf[426..=454].copy_from_slice(&anime.get_row(10, 0, 29)); - buf[456..=484].copy_from_slice(&anime.get_row(11, 0, 29)); - buf[485..=512].copy_from_slice(&anime.get_row(12, 0, 28)); - buf[514..=541].copy_from_slice(&anime.get_row(13, 0, 28)); - buf[542..=568].copy_from_slice(&anime.get_row(14, 0, 27)); - buf[570..=596].copy_from_slice(&anime.get_row(15, 0, 27)); - buf[597..=622].copy_from_slice(&anime.get_row(16, 0, 26)); - buf[624..=649].copy_from_slice(&anime.get_row(17, 0, 26)); - buf[650..=674].copy_from_slice(&anime.get_row(18, 0, 25)); - buf[676..=700].copy_from_slice(&anime.get_row(19, 0, 25)); - buf[701..=724].copy_from_slice(&anime.get_row(20, 0, 24)); - buf[726..=749].copy_from_slice(&anime.get_row(21, 0, 24)); - buf[750..=772].copy_from_slice(&anime.get_row(22, 0, 23)); - buf[774..=796].copy_from_slice(&anime.get_row(23, 0, 23)); - buf[797..=818].copy_from_slice(&anime.get_row(24, 0, 22)); - buf[820..=841].copy_from_slice(&anime.get_row(25, 0, 22)); - buf[842..=862].copy_from_slice(&anime.get_row(26, 0, 21)); - buf[864..=884].copy_from_slice(&anime.get_row(27, 0, 21)); - buf[885..=904].copy_from_slice(&anime.get_row(28, 0, 20)); - buf[906..=925].copy_from_slice(&anime.get_row(29, 0, 20)); - buf[926..=944].copy_from_slice(&anime.get_row(30, 0, 19)); - buf[946..=964].copy_from_slice(&anime.get_row(31, 0, 19)); - buf[965..=982].copy_from_slice(&anime.get_row(32, 0, 18)); - buf[984..=1001].copy_from_slice(&anime.get_row(33, 0, 18)); - buf[1002..=1018].copy_from_slice(&anime.get_row(34, 0, 17)); - buf[1020..=1036].copy_from_slice(&anime.get_row(35, 0, 17)); - buf[1037..=1052].copy_from_slice(&anime.get_row(36, 0, 16)); - buf[1054..=1069].copy_from_slice(&anime.get_row(37, 0, 16)); - buf[1070..=1084].copy_from_slice(&anime.get_row(38, 0, 15)); - buf[1086..=1100].copy_from_slice(&anime.get_row(39, 0, 15)); - buf[1101..=1114].copy_from_slice(&anime.get_row(40, 0, 14)); - buf[1116..=1129].copy_from_slice(&anime.get_row(41, 0, 14)); - buf[1130..=1142].copy_from_slice(&anime.get_row(42, 0, 13)); - buf[1144..=1156].copy_from_slice(&anime.get_row(43, 0, 13)); - buf[1157..=1168].copy_from_slice(&anime.get_row(44, 0, 12)); - buf[1170..=1181].copy_from_slice(&anime.get_row(45, 0, 12)); - buf[1182..=1192].copy_from_slice(&anime.get_row(46, 0, 11)); - buf[1194..=1204].copy_from_slice(&anime.get_row(47, 0, 11)); - buf[1205..=1214].copy_from_slice(&anime.get_row(48, 0, 10)); - buf[1216..=1225].copy_from_slice(&anime.get_row(49, 0, 10)); - buf[1226..=1234].copy_from_slice(&anime.get_row(50, 0, 9)); - buf[1236..=1244].copy_from_slice(&anime.get_row(51, 0, 9)); + buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32)); + buf[34..=66].copy_from_slice(&self.get_row(0, 2, 33)); + buf[69..=101].copy_from_slice(&self.get_row(1, 2, 33)); // ?! + buf[102..=134].copy_from_slice(&self.get_row(1, 1, 33)); + buf[137..=169].copy_from_slice(&self.get_row(2, 1, 33)); + buf[170..=202].copy_from_slice(&self.get_row(2, 0, 33)); + buf[204..=236].copy_from_slice(&self.get_row(3, 0, 33)); + buf[237..=268].copy_from_slice(&self.get_row(4, 0, 32)); + buf[270..=301].copy_from_slice(&self.get_row(5, 0, 32)); + buf[302..=332].copy_from_slice(&self.get_row(6, 0, 31)); + buf[334..=364].copy_from_slice(&self.get_row(7, 0, 31)); + buf[365..=394].copy_from_slice(&self.get_row(8, 0, 30)); + buf[396..=425].copy_from_slice(&self.get_row(9, 0, 30)); + buf[426..=454].copy_from_slice(&self.get_row(10, 0, 29)); + buf[456..=484].copy_from_slice(&self.get_row(11, 0, 29)); + buf[485..=512].copy_from_slice(&self.get_row(12, 0, 28)); + buf[514..=541].copy_from_slice(&self.get_row(13, 0, 28)); + buf[542..=568].copy_from_slice(&self.get_row(14, 0, 27)); + buf[570..=596].copy_from_slice(&self.get_row(15, 0, 27)); + buf[597..=622].copy_from_slice(&self.get_row(16, 0, 26)); + buf[624..=649].copy_from_slice(&self.get_row(17, 0, 26)); + buf[650..=674].copy_from_slice(&self.get_row(18, 0, 25)); + buf[676..=700].copy_from_slice(&self.get_row(19, 0, 25)); + buf[701..=724].copy_from_slice(&self.get_row(20, 0, 24)); + buf[726..=749].copy_from_slice(&self.get_row(21, 0, 24)); + buf[750..=772].copy_from_slice(&self.get_row(22, 0, 23)); + buf[774..=796].copy_from_slice(&self.get_row(23, 0, 23)); + buf[797..=818].copy_from_slice(&self.get_row(24, 0, 22)); + buf[820..=841].copy_from_slice(&self.get_row(25, 0, 22)); + buf[842..=862].copy_from_slice(&self.get_row(26, 0, 21)); + buf[864..=884].copy_from_slice(&self.get_row(27, 0, 21)); + buf[885..=904].copy_from_slice(&self.get_row(28, 0, 20)); + buf[906..=925].copy_from_slice(&self.get_row(29, 0, 20)); + buf[926..=944].copy_from_slice(&self.get_row(30, 0, 19)); + buf[946..=964].copy_from_slice(&self.get_row(31, 0, 19)); + buf[965..=982].copy_from_slice(&self.get_row(32, 0, 18)); + buf[984..=1001].copy_from_slice(&self.get_row(33, 0, 18)); + buf[1002..=1018].copy_from_slice(&self.get_row(34, 0, 17)); + buf[1020..=1036].copy_from_slice(&self.get_row(35, 0, 17)); + buf[1037..=1052].copy_from_slice(&self.get_row(36, 0, 16)); + buf[1054..=1069].copy_from_slice(&self.get_row(37, 0, 16)); + buf[1070..=1084].copy_from_slice(&self.get_row(38, 0, 15)); + buf[1086..=1100].copy_from_slice(&self.get_row(39, 0, 15)); + buf[1101..=1114].copy_from_slice(&self.get_row(40, 0, 14)); + buf[1116..=1129].copy_from_slice(&self.get_row(41, 0, 14)); + buf[1130..=1142].copy_from_slice(&self.get_row(42, 0, 13)); + buf[1144..=1156].copy_from_slice(&self.get_row(43, 0, 13)); + buf[1157..=1168].copy_from_slice(&self.get_row(44, 0, 12)); + buf[1170..=1181].copy_from_slice(&self.get_row(45, 0, 12)); + buf[1182..=1192].copy_from_slice(&self.get_row(46, 0, 11)); + buf[1194..=1204].copy_from_slice(&self.get_row(47, 0, 11)); + buf[1205..=1214].copy_from_slice(&self.get_row(48, 0, 10)); + buf[1216..=1225].copy_from_slice(&self.get_row(49, 0, 10)); + buf[1226..=1234].copy_from_slice(&self.get_row(50, 0, 9)); + buf[1236..=1244].copy_from_slice(&self.get_row(51, 0, 9)); - AnimeDataBuffer::from_vec(buf) + AnimeDataBuffer::from_vec(crate::AnimeType::GA401, buf) + } + + fn into_ga402_packets(&self) -> AnimeDataBuffer { + let mut buf = vec![0u8; ANIME_GA402_DATA_LEN]; + let mut start_index: usize = 0; + + fn copy_slice( + buf: &mut Vec, + anime: &AnimeDiagonal, + x: usize, + y: usize, + start_index: &mut usize, + len: usize, + ) { + buf[*start_index..*start_index + len].copy_from_slice(&anime.get_row(x, y, len)); + *start_index += len; + } + + let b = &mut buf; + let a = &self; + copy_slice(b, a, 0, 5, &mut start_index, 34); + copy_slice(b, a, 1, 5, &mut start_index, 34); + copy_slice(b, a, 1, 4, &mut start_index, 34); + copy_slice(b, a, 2, 4, &mut start_index, 34); + copy_slice(b, a, 2, 3, &mut start_index, 34); + copy_slice(b, a, 3, 3, &mut start_index, 34); + copy_slice(b, a, 3, 2, &mut start_index, 34); + copy_slice(b, a, 4, 2, &mut start_index, 34); + copy_slice(b, a, 4, 1, &mut start_index, 34); + copy_slice(b, a, 5, 1, &mut start_index, 34); + copy_slice(b, a, 5, 0, &mut start_index, 34); + copy_slice(b, a, 6, 0, &mut start_index, 34); + copy_slice(b, a, 7, 0, &mut start_index, 33); + copy_slice(b, a, 8, 0, &mut start_index, 33); + copy_slice(b, a, 9, 0, &mut start_index, 32); + copy_slice(b, a, 10, 0, &mut start_index, 32); + copy_slice(b, a, 11, 0, &mut start_index, 31); + copy_slice(b, a, 12, 0, &mut start_index, 31); + copy_slice(b, a, 13, 0, &mut start_index, 30); + copy_slice(b, a, 14, 0, &mut start_index, 30); + copy_slice(b, a, 15, 0, &mut start_index, 29); + copy_slice(b, a, 16, 0, &mut start_index, 29); + copy_slice(b, a, 17, 0, &mut start_index, 28); + copy_slice(b, a, 18, 0, &mut start_index, 28); + copy_slice(b, a, 19, 0, &mut start_index, 27); + copy_slice(b, a, 20, 0, &mut start_index, 27); + copy_slice(b, a, 21, 0, &mut start_index, 26); + copy_slice(b, a, 22, 0, &mut start_index, 26); + copy_slice(b, a, 23, 0, &mut start_index, 25); + copy_slice(b, a, 24, 0, &mut start_index, 25); + copy_slice(b, a, 25, 0, &mut start_index, 24); + copy_slice(b, a, 26, 0, &mut start_index, 24); + copy_slice(b, a, 27, 0, &mut start_index, 23); + copy_slice(b, a, 28, 0, &mut start_index, 23); + copy_slice(b, a, 29, 0, &mut start_index, 22); + copy_slice(b, a, 30, 0, &mut start_index, 22); + copy_slice(b, a, 31, 0, &mut start_index, 21); + copy_slice(b, a, 32, 0, &mut start_index, 21); + copy_slice(b, a, 33, 0, &mut start_index, 20); + copy_slice(b, a, 34, 0, &mut start_index, 20); + copy_slice(b, a, 35, 0, &mut start_index, 19); + copy_slice(b, a, 36, 0, &mut start_index, 19); + copy_slice(b, a, 37, 0, &mut start_index, 18); + copy_slice(b, a, 38, 0, &mut start_index, 18); + copy_slice(b, a, 39, 0, &mut start_index, 17); + copy_slice(b, a, 40, 0, &mut start_index, 17); + copy_slice(b, a, 41, 0, &mut start_index, 16); + copy_slice(b, a, 42, 0, &mut start_index, 16); + copy_slice(b, a, 43, 0, &mut start_index, 15); + copy_slice(b, a, 44, 0, &mut start_index, 15); + copy_slice(b, a, 45, 0, &mut start_index, 14); + copy_slice(b, a, 46, 0, &mut start_index, 14); + copy_slice(b, a, 47, 0, &mut start_index, 13); + copy_slice(b, a, 48, 0, &mut start_index, 13); + copy_slice(b, a, 49, 0, &mut start_index, 12); + copy_slice(b, a, 50, 0, &mut start_index, 12); + copy_slice(b, a, 51, 0, &mut start_index, 11); + copy_slice(b, a, 52, 0, &mut start_index, 11); + copy_slice(b, a, 53, 0, &mut start_index, 10); + copy_slice(b, a, 54, 0, &mut start_index, 10); + copy_slice(b, a, 55, 0, &mut start_index, 9); + + AnimeDataBuffer::from_vec(crate::AnimeType::GA402, buf) + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::{AnimeDiagonal, AnimePacketType}; + + #[test] + fn ga401_diagonal_packet_check() { + let pkt0_check = [ + 0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, + ]; + let pkt1_check = [ + 0x5e, 0xc0, 0x2, 0x74, 0x2, 0x73, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + 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 data = matrix.into_data_buffer(crate::AnimeType::GA401); + let pkt = AnimePacketType::from(data); + + assert_eq!(pkt[0], pkt0_check); + assert_eq!(pkt[1], pkt1_check); } } diff --git a/rog-anime/src/error.rs b/rog-anime/src/error.rs index ee12a440..9a97859a 100644 --- a/rog-anime/src/error.rs +++ b/rog-anime/src/error.rs @@ -13,6 +13,9 @@ pub enum AnimeError { /// The input was incorrect size, expected size is `IncorrectSize(width, height)` IncorrectSize(u32, u32), Dbus(String), + Udev(String, std::io::Error), + NoDevice, + UnsupportedDevice, } impl fmt::Display for AnimeError { @@ -30,6 +33,9 @@ impl fmt::Display for AnimeError { width, height ), AnimeError::Dbus(detail) => write!(f, "{}", detail), + AnimeError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error), + AnimeError::NoDevice => write!(f, "No AniMe Matrix device found"), + AnimeError::UnsupportedDevice => write!(f, "Unsupported AniMe Matrix device found"), } } } diff --git a/rog-anime/src/gif.rs b/rog-anime/src/gif.rs index ef89ad4b..d796c053 100644 --- a/rog-anime/src/gif.rs +++ b/rog-anime/src/gif.rs @@ -2,7 +2,7 @@ use glam::Vec2; use serde_derive::{Deserialize, Serialize}; use std::{fs::File, path::Path, time::Duration}; -use crate::{error::AnimeError, AnimeDataBuffer, AnimeDiagonal, AnimeImage, Pixel}; +use crate::{error::AnimeError, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel}; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct AnimeFrame { @@ -90,8 +90,10 @@ 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); @@ -121,7 +123,7 @@ impl AnimeGif { } frames.push(AnimeFrame { - data: ::from(&matrix), + data: matrix.into_data_buffer(anime_type), delay: Duration::from_millis(wait as u64), }); } @@ -132,6 +134,7 @@ impl AnimeGif { #[inline] pub fn from_diagonal_png( file_name: &Path, + anime_type: AnimeType, duration: AnimTime, brightness: f32, ) -> Result { @@ -148,7 +151,7 @@ impl AnimeGif { let frame_count = total.as_millis() / 30; let single = AnimeFrame { - data: ::from(&image), + data: image.into_data_buffer(anime_type), delay: Duration::from_millis(30), }; let frames = vec![single; frame_count as usize]; @@ -166,6 +169,7 @@ impl AnimeGif { translation: Vec2, duration: AnimTime, brightness: f32, + anime_type: AnimeType, ) -> Result { let mut frames = Vec::new(); @@ -187,6 +191,7 @@ impl AnimeGif { brightness, pixels, decoder.width() as u32, + anime_type, ); while let Some(frame) = decoder.read_next_frame()? { @@ -201,6 +206,7 @@ impl AnimeGif { brightness, pixels, width as u32, + anime_type, ); } for (y, row) in frame.buffer.chunks(frame.width as usize * 4).enumerate() { @@ -238,8 +244,10 @@ impl AnimeGif { translation: Vec2, duration: AnimTime, brightness: f32, + anime_type: AnimeType, ) -> Result { - let image = AnimeImage::from_png(file_name, scale, angle, translation, brightness)?; + let image = + AnimeImage::from_png(file_name, scale, angle, translation, 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 c53ab0dd..eb3e3910 100644 --- a/rog-anime/src/grid.rs +++ b/rog-anime/src/grid.rs @@ -1,8 +1,7 @@ -use std::time::Duration; - -use crate::data::{AnimeDataBuffer, ANIME_DATA_LEN}; -use crate::image::LED_IMAGE_POSITIONS; +use crate::data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN}; +use crate::{AnimeImage, AnimeType, ANIME_GA402_DATA_LEN}; +// TODO: Adjust these sizes as WIDTH_GA401 WIDTH_GA402 const WIDTH: usize = 33; const HEIGHT: usize = 55; @@ -14,41 +13,40 @@ const HEIGHT: usize = 55; /// /// **Note:** the columns in each odd row are offset by half a pixel left #[derive(Debug, Clone)] -pub struct AnimeGrid([[u8; WIDTH]; HEIGHT], Option); - -impl Default for AnimeGrid { - #[inline] - fn default() -> Self { - Self::new(None) - } +pub struct AnimeGrid { + anime_type: AnimeType, + data: [[u8; WIDTH]; HEIGHT], } impl AnimeGrid { #[inline] - pub fn new(duration: Option) -> Self { - AnimeGrid([[0u8; WIDTH]; HEIGHT], duration) + pub fn new(anime_type: AnimeType) -> Self { + Self { + anime_type, + data: [[0u8; WIDTH]; HEIGHT], + } } /// Set a position in the grid with a brightness value #[inline] pub fn set(&mut self, x: usize, y: usize, b: u8) { - self.0[y][x] = b; + self.data[y][x] = b; } #[inline] pub fn get(&self) -> &[[u8; WIDTH]; HEIGHT] { - &self.0 + &self.data } #[inline] pub fn get_mut(&mut self) -> &mut [[u8; WIDTH]; HEIGHT] { - &mut self.0 + &mut self.data } /// Fill the grid with a value #[inline] pub fn fill_with(&mut self, fill: u8) { - for row in self.0.iter_mut() { + for row in self.data.iter_mut() { for x in row.iter_mut() { *x = fill; } @@ -94,16 +92,22 @@ impl From for AnimeDataBuffer { /// packets suitable for sending over USB #[inline] fn from(anime: AnimeGrid) -> Self { - let mut buf = vec![0u8; ANIME_DATA_LEN]; + let mut buf = match anime.anime_type { + AnimeType::GA401 => vec![0u8; ANIME_GA401_DATA_LEN], + AnimeType::GA402 => vec![0u8; ANIME_GA402_DATA_LEN], + }; - for (idx, pos) in LED_IMAGE_POSITIONS.iter().enumerate() { + for (idx, pos) in AnimeImage::generate_image_positioning(anime.anime_type) + .iter() + .enumerate() + { if let Some(pos) = pos { let x = pos.x().ceil() as usize; let y = pos.y().ceil() as usize; - buf[idx + 1] = anime.0[y][x]; + buf[idx + 1] = anime.data[y][x]; } } - AnimeDataBuffer::from_vec(buf) + AnimeDataBuffer::from_vec(anime.anime_type, buf) } } @@ -113,7 +117,7 @@ mod tests { #[test] fn check_data_alignment() { - let mut matrix = AnimeGrid::new(None); + let mut matrix = AnimeGrid::new(AnimeType::GA401); { let tmp = matrix.get_mut(); for row in tmp.iter_mut() { @@ -171,6 +175,6 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - assert_eq!(matrix.get(), &data_cmp); + assert_eq!(matrix.data(), &data_cmp); } } diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index e69ec96c..570de37b 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -4,12 +4,11 @@ pub use glam::Vec2; use glam::{Mat3, Vec3}; use crate::{ - data::{AnimeDataBuffer, ANIME_DATA_LEN}, + data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN}, error::AnimeError, + AnimeType, }; -const LED_PIXEL_LEN: usize = 1244; - /// A single greyscale + alpha pixel in the image #[derive(Copy, Clone, Debug)] pub(crate) struct Pixel { @@ -69,81 +68,116 @@ pub struct AnimeImage { /// Brightness of final image, `0.0` = off, `1.0` = full pub bright: f32, /// Positions of all the LEDs - led_pos: [Option; LED_PIXEL_LEN], + led_pos: Vec>, /// THe image data for sampling img_pixels: Vec, /// width of the image width: u32, + /// The type of the display. The GA401 and GA402 use the same controller and therefore same ID, + /// so the identifier must be by laptop model in `AnimeType`. + anime_type: AnimeType, } impl AnimeImage { - pub(crate) const fn new( + pub(crate) fn new( scale: Vec2, angle: f32, translation: Vec2, bright: f32, pixels: Vec, width: u32, + anime_type: AnimeType, ) -> Self { Self { scale, angle, translation, bright, - led_pos: LED_IMAGE_POSITIONS, + led_pos: Self::generate_image_positioning(anime_type), img_pixels: pixels, width, + anime_type, + } + } + + // TODO: Convert functions back to const after todo completed + + /// Scale ratio in CM + fn scale_x(anime_type: AnimeType) -> f32 { + match anime_type { + AnimeType::GA401 => 0.8, + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } } /// Scale ratio in CM - const fn scale_x() -> f32 { - 0.8 - } - - /// Scale ratio in CM - const fn scale_y() -> f32 { - 0.3 + fn scale_y(anime_type: AnimeType) -> f32 { + match anime_type { + AnimeType::GA401 => 0.3, + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + } } /// Get the starting X position for the data we actually require when writing /// it out to LEDs - const fn first_x(y: u32) -> u32 { - if y < 5 { - return 0; + fn first_x(anime_type: AnimeType, y: u32) -> u32 { + match anime_type { + AnimeType::GA401 => { + if y < 5 { + return 0; + } + (y + 1) / 2 - 3 + } + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } - (y + 1) / 2 - 3 } /// Width in LED count - const fn width(y: u32) -> u32 { - if y < 5 { - return 33; + fn width(anime_type: AnimeType, y: u32) -> u32 { + match anime_type { + AnimeType::GA401 => { + if y < 5 { + return 33; + } + 36 - (y + 1) / 2 + } + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } - 36 - (y + 1) / 2 } /// Physical display width - fn phys_width() -> f32 { - (32.0 - -0.5 + 1.0) * Self::scale_x() + fn phys_width(anime_type: AnimeType) -> f32 { + match anime_type { + AnimeType::GA401 => (32.0 - -0.5 + 1.0) * Self::scale_x(anime_type), + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + } } /// Height in LED count - const fn height() -> u32 { - 55 + fn height(anime_type: AnimeType) -> u32 { + match anime_type { + AnimeType::GA401 => 55, + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + } } /// Physical display height - fn phys_height() -> f32 { - (54.0 + 1.0) * Self::scale_y() + fn phys_height(anime_type: AnimeType) -> f32 { + match anime_type { + AnimeType::GA401 => (54.0 + 1.0) * Self::scale_y(anime_type), + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + } } /// Find the actual width of the data including the dead pixels - const fn pitch(y: u32) -> u32 { - match y { - 0 | 2 | 4 => 33, - 1 | 3 => 35, - _ => 36 - y / 2, + fn pitch(anime_type: AnimeType, y: u32) -> u32 { + match anime_type { + AnimeType::GA401 => match y { + 0 | 2 | 4 => 33, + 1 | 3 => 35, + _ => 36 - y / 2, + }, + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } } @@ -151,21 +185,24 @@ impl AnimeImage { &mut self.img_pixels } - /// Really only used to generate the output for including as a full const in `LED_IMAGE_POSITIONS` + /// Generate the data used to #[inline] - pub fn generate() -> Vec> { - (0..AnimeImage::height()) - .flat_map(|y| { - (0..AnimeImage::pitch(y)).map(move |l| { - if l < AnimeImage::width(y) { - let x = AnimeImage::first_x(y) + l; - Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) - } else { - None - } + pub fn generate_image_positioning(anime_type: AnimeType) -> Vec> { + match anime_type { + AnimeType::GA401 => (0..AnimeImage::height(anime_type)) + .flat_map(|y| { + (0..AnimeImage::pitch(anime_type, y)).map(move |l| { + if l < AnimeImage::width(anime_type, y) { + let x = AnimeImage::first_x(anime_type, y) + l; + Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) + } else { + None + } + }) }) - }) - .collect() + .collect(), + AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + } } /// Called after setting new angle, position, or scale to refresh the image @@ -216,8 +253,8 @@ impl AnimeImage { // Center of image let center = Mat3::from_translation(Vec2::new(-0.5 * bmp_w, -0.5 * bmp_h)); // Find the scale required for cleanly showing the image - let h = AnimeImage::phys_height() / bmp_h; - let mut base_scale = AnimeImage::phys_width() / bmp_w; + let h = AnimeImage::phys_height(self.anime_type) / bmp_h; + let mut base_scale = AnimeImage::phys_width(self.anime_type) / bmp_w; if base_scale > h { base_scale = h; } @@ -225,8 +262,8 @@ impl AnimeImage { let cm_from_px = Mat3::from_scale(Vec2::new(base_scale, base_scale)); let led_from_cm = Mat3::from_scale(Vec2::new( - 1.0 / AnimeImage::scale_x(), - 1.0 / AnimeImage::scale_y(), + 1.0 / AnimeImage::scale_x(self.anime_type), + 1.0 / AnimeImage::scale_y(self.anime_type), )); let transform = @@ -248,6 +285,7 @@ impl AnimeImage { angle: f32, translation: Vec2, bright: f32, + anime_type: AnimeType, ) -> Result { let data = std::fs::read(path)?; let data = std::io::Cursor::new(data); @@ -298,6 +336,7 @@ impl AnimeImage { bright, pixels, width, + anime_type, ); matrix.update(); @@ -353,1272 +392,21 @@ 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_DATA_LEN); + let mut v = Vec::with_capacity(ANIME_GA401_DATA_LEN); v.push(0); v.append(&mut l); v.append(&mut vec![0u8; 9]); - AnimeDataBuffer::from_vec(v) + AnimeDataBuffer::from_vec(leds.anime_type, v) } } -/// Data starts at first index which means that when mapping this data to the final -/// USB packet it must start from index 8, not 7. -/// -/// Verbatim copy of `generate()`. `LED_IMAGE_POSITIONS` is `const` so prefer this. -pub const LED_IMAGE_POSITIONS: [Option; LED_PIXEL_LEN] = [ - Some(Led(0.0, 0.0, 0)), - Some(Led(1.0, 0.0, 0)), - Some(Led(2.0, 0.0, 0)), - Some(Led(3.0, 0.0, 0)), - Some(Led(4.0, 0.0, 0)), - Some(Led(5.0, 0.0, 0)), - Some(Led(6.0, 0.0, 0)), - Some(Led(7.0, 0.0, 0)), - Some(Led(8.0, 0.0, 0)), - Some(Led(9.0, 0.0, 0)), - Some(Led(10.0, 0.0, 0)), - Some(Led(11.0, 0.0, 0)), - Some(Led(12.0, 0.0, 0)), - Some(Led(13.0, 0.0, 0)), - Some(Led(14.0, 0.0, 0)), - Some(Led(15.0, 0.0, 0)), - Some(Led(16.0, 0.0, 0)), - Some(Led(17.0, 0.0, 0)), - Some(Led(18.0, 0.0, 0)), - Some(Led(19.0, 0.0, 0)), - Some(Led(20.0, 0.0, 0)), - Some(Led(21.0, 0.0, 0)), - Some(Led(22.0, 0.0, 0)), - Some(Led(23.0, 0.0, 0)), - Some(Led(24.0, 0.0, 0)), - Some(Led(25.0, 0.0, 0)), - Some(Led(26.0, 0.0, 0)), - Some(Led(27.0, 0.0, 0)), - Some(Led(28.0, 0.0, 0)), - Some(Led(29.0, 0.0, 0)), - Some(Led(30.0, 0.0, 0)), - Some(Led(31.0, 0.0, 0)), - Some(Led(32.0, 0.0, 0)), - Some(Led(-0.5, 1.0, 0)), - Some(Led(0.5, 1.0, 0)), - Some(Led(1.5, 1.0, 0)), - Some(Led(2.5, 1.0, 0)), - Some(Led(3.5, 1.0, 0)), - Some(Led(4.5, 1.0, 0)), - Some(Led(5.5, 1.0, 0)), - Some(Led(6.5, 1.0, 0)), - Some(Led(7.5, 1.0, 0)), - Some(Led(8.5, 1.0, 0)), - Some(Led(9.5, 1.0, 0)), - Some(Led(10.5, 1.0, 0)), - Some(Led(11.5, 1.0, 0)), - Some(Led(12.5, 1.0, 0)), - Some(Led(13.5, 1.0, 0)), - Some(Led(14.5, 1.0, 0)), - Some(Led(15.5, 1.0, 0)), - Some(Led(16.5, 1.0, 0)), - Some(Led(17.5, 1.0, 0)), - Some(Led(18.5, 1.0, 0)), - Some(Led(19.5, 1.0, 0)), - Some(Led(20.5, 1.0, 0)), - Some(Led(21.5, 1.0, 0)), - Some(Led(22.5, 1.0, 0)), - Some(Led(23.5, 1.0, 0)), - Some(Led(24.5, 1.0, 0)), - Some(Led(25.5, 1.0, 0)), - Some(Led(26.5, 1.0, 0)), - Some(Led(27.5, 1.0, 0)), - Some(Led(28.5, 1.0, 0)), - Some(Led(29.5, 1.0, 0)), - Some(Led(30.5, 1.0, 0)), - Some(Led(31.5, 1.0, 0)), - None, - None, - Some(Led(0.0, 2.0, 0)), - Some(Led(1.0, 2.0, 0)), - Some(Led(2.0, 2.0, 0)), - Some(Led(3.0, 2.0, 0)), - Some(Led(4.0, 2.0, 0)), - Some(Led(5.0, 2.0, 0)), - Some(Led(6.0, 2.0, 0)), - Some(Led(7.0, 2.0, 0)), - Some(Led(8.0, 2.0, 0)), - Some(Led(9.0, 2.0, 0)), - Some(Led(10.0, 2.0, 0)), - Some(Led(11.0, 2.0, 0)), - Some(Led(12.0, 2.0, 0)), - Some(Led(13.0, 2.0, 0)), - Some(Led(14.0, 2.0, 0)), - Some(Led(15.0, 2.0, 0)), - Some(Led(16.0, 2.0, 0)), - Some(Led(17.0, 2.0, 0)), - Some(Led(18.0, 2.0, 0)), - Some(Led(19.0, 2.0, 0)), - Some(Led(20.0, 2.0, 0)), - Some(Led(21.0, 2.0, 0)), - Some(Led(22.0, 2.0, 0)), - Some(Led(23.0, 2.0, 0)), - Some(Led(24.0, 2.0, 0)), - Some(Led(25.0, 2.0, 0)), - Some(Led(26.0, 2.0, 0)), - Some(Led(27.0, 2.0, 0)), - Some(Led(28.0, 2.0, 0)), - Some(Led(29.0, 2.0, 0)), - Some(Led(30.0, 2.0, 0)), - Some(Led(31.0, 2.0, 0)), - Some(Led(32.0, 2.0, 0)), - Some(Led(-0.5, 3.0, 0)), - Some(Led(0.5, 3.0, 0)), - Some(Led(1.5, 3.0, 0)), - Some(Led(2.5, 3.0, 0)), - Some(Led(3.5, 3.0, 0)), - Some(Led(4.5, 3.0, 0)), - Some(Led(5.5, 3.0, 0)), - Some(Led(6.5, 3.0, 0)), - Some(Led(7.5, 3.0, 0)), - Some(Led(8.5, 3.0, 0)), - Some(Led(9.5, 3.0, 0)), - Some(Led(10.5, 3.0, 0)), - Some(Led(11.5, 3.0, 0)), - Some(Led(12.5, 3.0, 0)), - Some(Led(13.5, 3.0, 0)), - Some(Led(14.5, 3.0, 0)), - Some(Led(15.5, 3.0, 0)), - Some(Led(16.5, 3.0, 0)), - Some(Led(17.5, 3.0, 0)), - Some(Led(18.5, 3.0, 0)), - Some(Led(19.5, 3.0, 0)), - Some(Led(20.5, 3.0, 0)), - Some(Led(21.5, 3.0, 0)), - Some(Led(22.5, 3.0, 0)), - Some(Led(23.5, 3.0, 0)), - Some(Led(24.5, 3.0, 0)), - Some(Led(25.5, 3.0, 0)), - Some(Led(26.5, 3.0, 0)), - Some(Led(27.5, 3.0, 0)), - Some(Led(28.5, 3.0, 0)), - Some(Led(29.5, 3.0, 0)), - Some(Led(30.5, 3.0, 0)), - Some(Led(31.5, 3.0, 0)), - None, - None, - Some(Led(0.0, 4.0, 0)), - Some(Led(1.0, 4.0, 0)), - Some(Led(2.0, 4.0, 0)), - Some(Led(3.0, 4.0, 0)), - Some(Led(4.0, 4.0, 0)), - Some(Led(5.0, 4.0, 0)), - Some(Led(6.0, 4.0, 0)), - Some(Led(7.0, 4.0, 0)), - Some(Led(8.0, 4.0, 0)), - Some(Led(9.0, 4.0, 0)), - Some(Led(10.0, 4.0, 0)), - Some(Led(11.0, 4.0, 0)), - Some(Led(12.0, 4.0, 0)), - Some(Led(13.0, 4.0, 0)), - Some(Led(14.0, 4.0, 0)), - Some(Led(15.0, 4.0, 0)), - Some(Led(16.0, 4.0, 0)), - Some(Led(17.0, 4.0, 0)), - Some(Led(18.0, 4.0, 0)), - Some(Led(19.0, 4.0, 0)), - Some(Led(20.0, 4.0, 0)), - Some(Led(21.0, 4.0, 0)), - Some(Led(22.0, 4.0, 0)), - Some(Led(23.0, 4.0, 0)), - Some(Led(24.0, 4.0, 0)), - Some(Led(25.0, 4.0, 0)), - Some(Led(26.0, 4.0, 0)), - Some(Led(27.0, 4.0, 0)), - Some(Led(28.0, 4.0, 0)), - Some(Led(29.0, 4.0, 0)), - Some(Led(30.0, 4.0, 0)), - Some(Led(31.0, 4.0, 0)), - Some(Led(32.0, 4.0, 0)), - Some(Led(-0.5, 5.0, 0)), - Some(Led(0.5, 5.0, 0)), - Some(Led(1.5, 5.0, 0)), - Some(Led(2.5, 5.0, 0)), - Some(Led(3.5, 5.0, 0)), - Some(Led(4.5, 5.0, 0)), - Some(Led(5.5, 5.0, 0)), - Some(Led(6.5, 5.0, 0)), - Some(Led(7.5, 5.0, 0)), - Some(Led(8.5, 5.0, 0)), - Some(Led(9.5, 5.0, 0)), - Some(Led(10.5, 5.0, 0)), - Some(Led(11.5, 5.0, 0)), - Some(Led(12.5, 5.0, 0)), - Some(Led(13.5, 5.0, 0)), - Some(Led(14.5, 5.0, 0)), - Some(Led(15.5, 5.0, 0)), - Some(Led(16.5, 5.0, 0)), - Some(Led(17.5, 5.0, 0)), - Some(Led(18.5, 5.0, 0)), - Some(Led(19.5, 5.0, 0)), - Some(Led(20.5, 5.0, 0)), - Some(Led(21.5, 5.0, 0)), - Some(Led(22.5, 5.0, 0)), - Some(Led(23.5, 5.0, 0)), - Some(Led(24.5, 5.0, 0)), - Some(Led(25.5, 5.0, 0)), - Some(Led(26.5, 5.0, 0)), - Some(Led(27.5, 5.0, 0)), - Some(Led(28.5, 5.0, 0)), - Some(Led(29.5, 5.0, 0)), - Some(Led(30.5, 5.0, 0)), - Some(Led(31.5, 5.0, 0)), - None, - Some(Led(0.0, 6.0, 0)), - Some(Led(1.0, 6.0, 0)), - Some(Led(2.0, 6.0, 0)), - Some(Led(3.0, 6.0, 0)), - Some(Led(4.0, 6.0, 0)), - Some(Led(5.0, 6.0, 0)), - Some(Led(6.0, 6.0, 0)), - Some(Led(7.0, 6.0, 0)), - Some(Led(8.0, 6.0, 0)), - Some(Led(9.0, 6.0, 0)), - Some(Led(10.0, 6.0, 0)), - Some(Led(11.0, 6.0, 0)), - Some(Led(12.0, 6.0, 0)), - Some(Led(13.0, 6.0, 0)), - Some(Led(14.0, 6.0, 0)), - Some(Led(15.0, 6.0, 0)), - Some(Led(16.0, 6.0, 0)), - Some(Led(17.0, 6.0, 0)), - Some(Led(18.0, 6.0, 0)), - Some(Led(19.0, 6.0, 0)), - Some(Led(20.0, 6.0, 0)), - Some(Led(21.0, 6.0, 0)), - Some(Led(22.0, 6.0, 0)), - Some(Led(23.0, 6.0, 0)), - Some(Led(24.0, 6.0, 0)), - Some(Led(25.0, 6.0, 0)), - Some(Led(26.0, 6.0, 0)), - Some(Led(27.0, 6.0, 0)), - Some(Led(28.0, 6.0, 0)), - Some(Led(29.0, 6.0, 0)), - Some(Led(30.0, 6.0, 0)), - Some(Led(31.0, 6.0, 0)), - Some(Led(32.0, 6.0, 0)), - Some(Led(0.5, 7.0, 0)), - Some(Led(1.5, 7.0, 0)), - Some(Led(2.5, 7.0, 0)), - Some(Led(3.5, 7.0, 0)), - Some(Led(4.5, 7.0, 0)), - Some(Led(5.5, 7.0, 0)), - Some(Led(6.5, 7.0, 0)), - Some(Led(7.5, 7.0, 0)), - Some(Led(8.5, 7.0, 0)), - Some(Led(9.5, 7.0, 0)), - Some(Led(10.5, 7.0, 0)), - Some(Led(11.5, 7.0, 0)), - Some(Led(12.5, 7.0, 0)), - Some(Led(13.5, 7.0, 0)), - Some(Led(14.5, 7.0, 0)), - Some(Led(15.5, 7.0, 0)), - Some(Led(16.5, 7.0, 0)), - Some(Led(17.5, 7.0, 0)), - Some(Led(18.5, 7.0, 0)), - Some(Led(19.5, 7.0, 0)), - Some(Led(20.5, 7.0, 0)), - Some(Led(21.5, 7.0, 0)), - Some(Led(22.5, 7.0, 0)), - Some(Led(23.5, 7.0, 0)), - Some(Led(24.5, 7.0, 0)), - Some(Led(25.5, 7.0, 0)), - Some(Led(26.5, 7.0, 0)), - Some(Led(27.5, 7.0, 0)), - Some(Led(28.5, 7.0, 0)), - Some(Led(29.5, 7.0, 0)), - Some(Led(30.5, 7.0, 0)), - Some(Led(31.5, 7.0, 0)), - None, - Some(Led(1.0, 8.0, 0)), - Some(Led(2.0, 8.0, 0)), - Some(Led(3.0, 8.0, 0)), - Some(Led(4.0, 8.0, 0)), - Some(Led(5.0, 8.0, 0)), - Some(Led(6.0, 8.0, 0)), - Some(Led(7.0, 8.0, 0)), - Some(Led(8.0, 8.0, 0)), - Some(Led(9.0, 8.0, 0)), - Some(Led(10.0, 8.0, 0)), - Some(Led(11.0, 8.0, 0)), - Some(Led(12.0, 8.0, 0)), - Some(Led(13.0, 8.0, 0)), - Some(Led(14.0, 8.0, 0)), - Some(Led(15.0, 8.0, 0)), - Some(Led(16.0, 8.0, 0)), - Some(Led(17.0, 8.0, 0)), - Some(Led(18.0, 8.0, 0)), - Some(Led(19.0, 8.0, 0)), - Some(Led(20.0, 8.0, 0)), - Some(Led(21.0, 8.0, 0)), - Some(Led(22.0, 8.0, 0)), - Some(Led(23.0, 8.0, 0)), - Some(Led(24.0, 8.0, 0)), - Some(Led(25.0, 8.0, 0)), - Some(Led(26.0, 8.0, 0)), - Some(Led(27.0, 8.0, 0)), - Some(Led(28.0, 8.0, 0)), - Some(Led(29.0, 8.0, 0)), - Some(Led(30.0, 8.0, 0)), - Some(Led(31.0, 8.0, 0)), - Some(Led(32.0, 8.0, 0)), - Some(Led(1.5, 9.0, 0)), - Some(Led(2.5, 9.0, 0)), - Some(Led(3.5, 9.0, 0)), - Some(Led(4.5, 9.0, 0)), - Some(Led(5.5, 9.0, 0)), - Some(Led(6.5, 9.0, 0)), - Some(Led(7.5, 9.0, 0)), - Some(Led(8.5, 9.0, 0)), - Some(Led(9.5, 9.0, 0)), - Some(Led(10.5, 9.0, 0)), - Some(Led(11.5, 9.0, 0)), - Some(Led(12.5, 9.0, 0)), - Some(Led(13.5, 9.0, 0)), - Some(Led(14.5, 9.0, 0)), - Some(Led(15.5, 9.0, 0)), - Some(Led(16.5, 9.0, 0)), - Some(Led(17.5, 9.0, 0)), - Some(Led(18.5, 9.0, 0)), - Some(Led(19.5, 9.0, 0)), - Some(Led(20.5, 9.0, 0)), - Some(Led(21.5, 9.0, 0)), - Some(Led(22.5, 9.0, 0)), - Some(Led(23.5, 9.0, 0)), - Some(Led(24.5, 9.0, 0)), - Some(Led(25.5, 9.0, 0)), - Some(Led(26.5, 9.0, 0)), - Some(Led(27.5, 9.0, 0)), - Some(Led(28.5, 9.0, 0)), - Some(Led(29.5, 9.0, 0)), - Some(Led(30.5, 9.0, 0)), - Some(Led(31.5, 9.0, 0)), - None, - Some(Led(2.0, 10.0, 0)), - Some(Led(3.0, 10.0, 0)), - Some(Led(4.0, 10.0, 0)), - Some(Led(5.0, 10.0, 0)), - Some(Led(6.0, 10.0, 0)), - Some(Led(7.0, 10.0, 0)), - Some(Led(8.0, 10.0, 0)), - Some(Led(9.0, 10.0, 0)), - Some(Led(10.0, 10.0, 0)), - Some(Led(11.0, 10.0, 0)), - Some(Led(12.0, 10.0, 0)), - Some(Led(13.0, 10.0, 0)), - Some(Led(14.0, 10.0, 0)), - Some(Led(15.0, 10.0, 0)), - Some(Led(16.0, 10.0, 0)), - Some(Led(17.0, 10.0, 0)), - Some(Led(18.0, 10.0, 0)), - Some(Led(19.0, 10.0, 0)), - Some(Led(20.0, 10.0, 0)), - Some(Led(21.0, 10.0, 0)), - Some(Led(22.0, 10.0, 0)), - Some(Led(23.0, 10.0, 0)), - Some(Led(24.0, 10.0, 0)), - Some(Led(25.0, 10.0, 0)), - Some(Led(26.0, 10.0, 0)), - Some(Led(27.0, 10.0, 0)), - Some(Led(28.0, 10.0, 0)), - Some(Led(29.0, 10.0, 0)), - Some(Led(30.0, 10.0, 0)), - Some(Led(31.0, 10.0, 0)), - Some(Led(32.0, 10.0, 0)), - Some(Led(2.5, 11.0, 0)), - Some(Led(3.5, 11.0, 0)), - Some(Led(4.5, 11.0, 0)), - Some(Led(5.5, 11.0, 0)), - Some(Led(6.5, 11.0, 0)), - Some(Led(7.5, 11.0, 0)), - Some(Led(8.5, 11.0, 0)), - Some(Led(9.5, 11.0, 0)), - Some(Led(10.5, 11.0, 0)), - Some(Led(11.5, 11.0, 0)), - Some(Led(12.5, 11.0, 0)), - Some(Led(13.5, 11.0, 0)), - Some(Led(14.5, 11.0, 0)), - Some(Led(15.5, 11.0, 0)), - Some(Led(16.5, 11.0, 0)), - Some(Led(17.5, 11.0, 0)), - Some(Led(18.5, 11.0, 0)), - Some(Led(19.5, 11.0, 0)), - Some(Led(20.5, 11.0, 0)), - Some(Led(21.5, 11.0, 0)), - Some(Led(22.5, 11.0, 0)), - Some(Led(23.5, 11.0, 0)), - Some(Led(24.5, 11.0, 0)), - Some(Led(25.5, 11.0, 0)), - Some(Led(26.5, 11.0, 0)), - Some(Led(27.5, 11.0, 0)), - Some(Led(28.5, 11.0, 0)), - Some(Led(29.5, 11.0, 0)), - Some(Led(30.5, 11.0, 0)), - Some(Led(31.5, 11.0, 0)), - None, - Some(Led(3.0, 12.0, 0)), - Some(Led(4.0, 12.0, 0)), - Some(Led(5.0, 12.0, 0)), - Some(Led(6.0, 12.0, 0)), - Some(Led(7.0, 12.0, 0)), - Some(Led(8.0, 12.0, 0)), - Some(Led(9.0, 12.0, 0)), - Some(Led(10.0, 12.0, 0)), - Some(Led(11.0, 12.0, 0)), - Some(Led(12.0, 12.0, 0)), - Some(Led(13.0, 12.0, 0)), - Some(Led(14.0, 12.0, 0)), - Some(Led(15.0, 12.0, 0)), - Some(Led(16.0, 12.0, 0)), - Some(Led(17.0, 12.0, 0)), - Some(Led(18.0, 12.0, 0)), - Some(Led(19.0, 12.0, 0)), - Some(Led(20.0, 12.0, 0)), - Some(Led(21.0, 12.0, 0)), - Some(Led(22.0, 12.0, 0)), - Some(Led(23.0, 12.0, 0)), - Some(Led(24.0, 12.0, 0)), - Some(Led(25.0, 12.0, 0)), - Some(Led(26.0, 12.0, 0)), - Some(Led(27.0, 12.0, 0)), - Some(Led(28.0, 12.0, 0)), - Some(Led(29.0, 12.0, 0)), - Some(Led(30.0, 12.0, 0)), - Some(Led(31.0, 12.0, 0)), - Some(Led(32.0, 12.0, 0)), - Some(Led(3.5, 13.0, 0)), - Some(Led(4.5, 13.0, 0)), - Some(Led(5.5, 13.0, 0)), - Some(Led(6.5, 13.0, 0)), - Some(Led(7.5, 13.0, 0)), - Some(Led(8.5, 13.0, 0)), - Some(Led(9.5, 13.0, 0)), - Some(Led(10.5, 13.0, 0)), - Some(Led(11.5, 13.0, 0)), - Some(Led(12.5, 13.0, 0)), - Some(Led(13.5, 13.0, 0)), - Some(Led(14.5, 13.0, 0)), - Some(Led(15.5, 13.0, 0)), - Some(Led(16.5, 13.0, 0)), - Some(Led(17.5, 13.0, 0)), - Some(Led(18.5, 13.0, 0)), - Some(Led(19.5, 13.0, 0)), - Some(Led(20.5, 13.0, 0)), - Some(Led(21.5, 13.0, 0)), - Some(Led(22.5, 13.0, 0)), - Some(Led(23.5, 13.0, 0)), - Some(Led(24.5, 13.0, 0)), - Some(Led(25.5, 13.0, 0)), - Some(Led(26.5, 13.0, 0)), - Some(Led(27.5, 13.0, 0)), - Some(Led(28.5, 13.0, 0)), - Some(Led(29.5, 13.0, 0)), - Some(Led(30.5, 13.0, 0)), - Some(Led(31.5, 13.0, 0)), - None, - Some(Led(4.0, 14.0, 0)), - Some(Led(5.0, 14.0, 0)), - Some(Led(6.0, 14.0, 0)), - Some(Led(7.0, 14.0, 0)), - Some(Led(8.0, 14.0, 0)), - Some(Led(9.0, 14.0, 0)), - Some(Led(10.0, 14.0, 0)), - Some(Led(11.0, 14.0, 0)), - Some(Led(12.0, 14.0, 0)), - Some(Led(13.0, 14.0, 0)), - Some(Led(14.0, 14.0, 0)), - Some(Led(15.0, 14.0, 0)), - Some(Led(16.0, 14.0, 0)), - Some(Led(17.0, 14.0, 0)), - Some(Led(18.0, 14.0, 0)), - Some(Led(19.0, 14.0, 0)), - Some(Led(20.0, 14.0, 0)), - Some(Led(21.0, 14.0, 0)), - Some(Led(22.0, 14.0, 0)), - Some(Led(23.0, 14.0, 0)), - Some(Led(24.0, 14.0, 0)), - Some(Led(25.0, 14.0, 0)), - Some(Led(26.0, 14.0, 0)), - Some(Led(27.0, 14.0, 0)), - Some(Led(28.0, 14.0, 0)), - Some(Led(29.0, 14.0, 0)), - Some(Led(30.0, 14.0, 0)), - Some(Led(31.0, 14.0, 0)), - Some(Led(32.0, 14.0, 0)), - Some(Led(4.5, 15.0, 0)), - Some(Led(5.5, 15.0, 0)), - Some(Led(6.5, 15.0, 0)), - Some(Led(7.5, 15.0, 0)), - Some(Led(8.5, 15.0, 0)), - Some(Led(9.5, 15.0, 0)), - Some(Led(10.5, 15.0, 0)), - Some(Led(11.5, 15.0, 0)), - Some(Led(12.5, 15.0, 0)), - Some(Led(13.5, 15.0, 0)), - Some(Led(14.5, 15.0, 0)), - Some(Led(15.5, 15.0, 0)), - Some(Led(16.5, 15.0, 0)), - Some(Led(17.5, 15.0, 0)), - Some(Led(18.5, 15.0, 0)), - Some(Led(19.5, 15.0, 0)), - Some(Led(20.5, 15.0, 0)), - Some(Led(21.5, 15.0, 0)), - Some(Led(22.5, 15.0, 0)), - Some(Led(23.5, 15.0, 0)), - Some(Led(24.5, 15.0, 0)), - Some(Led(25.5, 15.0, 0)), - Some(Led(26.5, 15.0, 0)), - Some(Led(27.5, 15.0, 0)), - Some(Led(28.5, 15.0, 0)), - Some(Led(29.5, 15.0, 0)), - Some(Led(30.5, 15.0, 0)), - Some(Led(31.5, 15.0, 0)), - None, - Some(Led(5.0, 16.0, 0)), - Some(Led(6.0, 16.0, 0)), - Some(Led(7.0, 16.0, 0)), - Some(Led(8.0, 16.0, 0)), - Some(Led(9.0, 16.0, 0)), - Some(Led(10.0, 16.0, 0)), - Some(Led(11.0, 16.0, 0)), - Some(Led(12.0, 16.0, 0)), - Some(Led(13.0, 16.0, 0)), - Some(Led(14.0, 16.0, 0)), - Some(Led(15.0, 16.0, 0)), - Some(Led(16.0, 16.0, 0)), - Some(Led(17.0, 16.0, 0)), - Some(Led(18.0, 16.0, 0)), - Some(Led(19.0, 16.0, 0)), - Some(Led(20.0, 16.0, 0)), - Some(Led(21.0, 16.0, 0)), - Some(Led(22.0, 16.0, 0)), - Some(Led(23.0, 16.0, 0)), - Some(Led(24.0, 16.0, 0)), - Some(Led(25.0, 16.0, 0)), - Some(Led(26.0, 16.0, 0)), - Some(Led(27.0, 16.0, 0)), - Some(Led(28.0, 16.0, 0)), - Some(Led(29.0, 16.0, 0)), - Some(Led(30.0, 16.0, 0)), - Some(Led(31.0, 16.0, 0)), - Some(Led(32.0, 16.0, 0)), - Some(Led(5.5, 17.0, 0)), - Some(Led(6.5, 17.0, 0)), - Some(Led(7.5, 17.0, 0)), - Some(Led(8.5, 17.0, 0)), - Some(Led(9.5, 17.0, 0)), - Some(Led(10.5, 17.0, 0)), - Some(Led(11.5, 17.0, 0)), - Some(Led(12.5, 17.0, 0)), - Some(Led(13.5, 17.0, 0)), - Some(Led(14.5, 17.0, 0)), - Some(Led(15.5, 17.0, 0)), - Some(Led(16.5, 17.0, 0)), - Some(Led(17.5, 17.0, 0)), - Some(Led(18.5, 17.0, 0)), - Some(Led(19.5, 17.0, 0)), - Some(Led(20.5, 17.0, 0)), - Some(Led(21.5, 17.0, 0)), - Some(Led(22.5, 17.0, 0)), - Some(Led(23.5, 17.0, 0)), - Some(Led(24.5, 17.0, 0)), - Some(Led(25.5, 17.0, 0)), - Some(Led(26.5, 17.0, 0)), - Some(Led(27.5, 17.0, 0)), - Some(Led(28.5, 17.0, 0)), - Some(Led(29.5, 17.0, 0)), - Some(Led(30.5, 17.0, 0)), - Some(Led(31.5, 17.0, 0)), - None, - Some(Led(6.0, 18.0, 0)), - Some(Led(7.0, 18.0, 0)), - Some(Led(8.0, 18.0, 0)), - Some(Led(9.0, 18.0, 0)), - Some(Led(10.0, 18.0, 0)), - Some(Led(11.0, 18.0, 0)), - Some(Led(12.0, 18.0, 0)), - Some(Led(13.0, 18.0, 0)), - Some(Led(14.0, 18.0, 0)), - Some(Led(15.0, 18.0, 0)), - Some(Led(16.0, 18.0, 0)), - Some(Led(17.0, 18.0, 0)), - Some(Led(18.0, 18.0, 0)), - Some(Led(19.0, 18.0, 0)), - Some(Led(20.0, 18.0, 0)), - Some(Led(21.0, 18.0, 0)), - Some(Led(22.0, 18.0, 0)), - Some(Led(23.0, 18.0, 0)), - Some(Led(24.0, 18.0, 0)), - Some(Led(25.0, 18.0, 0)), - Some(Led(26.0, 18.0, 0)), - Some(Led(27.0, 18.0, 0)), - Some(Led(28.0, 18.0, 0)), - Some(Led(29.0, 18.0, 0)), - Some(Led(30.0, 18.0, 0)), - Some(Led(31.0, 18.0, 0)), - Some(Led(32.0, 18.0, 0)), - Some(Led(6.5, 19.0, 0)), - Some(Led(7.5, 19.0, 0)), - Some(Led(8.5, 19.0, 0)), - Some(Led(9.5, 19.0, 0)), - Some(Led(10.5, 19.0, 0)), - Some(Led(11.5, 19.0, 0)), - Some(Led(12.5, 19.0, 0)), - Some(Led(13.5, 19.0, 0)), - Some(Led(14.5, 19.0, 0)), - Some(Led(15.5, 19.0, 0)), - Some(Led(16.5, 19.0, 0)), - Some(Led(17.5, 19.0, 0)), - Some(Led(18.5, 19.0, 0)), - Some(Led(19.5, 19.0, 0)), - Some(Led(20.5, 19.0, 0)), - Some(Led(21.5, 19.0, 0)), - Some(Led(22.5, 19.0, 0)), - Some(Led(23.5, 19.0, 0)), - Some(Led(24.5, 19.0, 0)), - Some(Led(25.5, 19.0, 0)), - Some(Led(26.5, 19.0, 0)), - Some(Led(27.5, 19.0, 0)), - Some(Led(28.5, 19.0, 0)), - Some(Led(29.5, 19.0, 0)), - Some(Led(30.5, 19.0, 0)), - Some(Led(31.5, 19.0, 0)), - None, - Some(Led(7.0, 20.0, 0)), - Some(Led(8.0, 20.0, 0)), - Some(Led(9.0, 20.0, 0)), - Some(Led(10.0, 20.0, 0)), - Some(Led(11.0, 20.0, 0)), - Some(Led(12.0, 20.0, 0)), - Some(Led(13.0, 20.0, 0)), - Some(Led(14.0, 20.0, 0)), - Some(Led(15.0, 20.0, 0)), - Some(Led(16.0, 20.0, 0)), - Some(Led(17.0, 20.0, 0)), - Some(Led(18.0, 20.0, 0)), - Some(Led(19.0, 20.0, 0)), - Some(Led(20.0, 20.0, 0)), - Some(Led(21.0, 20.0, 0)), - Some(Led(22.0, 20.0, 0)), - Some(Led(23.0, 20.0, 0)), - Some(Led(24.0, 20.0, 0)), - Some(Led(25.0, 20.0, 0)), - Some(Led(26.0, 20.0, 0)), - Some(Led(27.0, 20.0, 0)), - Some(Led(28.0, 20.0, 0)), - Some(Led(29.0, 20.0, 0)), - Some(Led(30.0, 20.0, 0)), - Some(Led(31.0, 20.0, 0)), - Some(Led(32.0, 20.0, 0)), - Some(Led(7.5, 21.0, 0)), - Some(Led(8.5, 21.0, 0)), - Some(Led(9.5, 21.0, 0)), - Some(Led(10.5, 21.0, 0)), - Some(Led(11.5, 21.0, 0)), - Some(Led(12.5, 21.0, 0)), - Some(Led(13.5, 21.0, 0)), - Some(Led(14.5, 21.0, 0)), - Some(Led(15.5, 21.0, 0)), - Some(Led(16.5, 21.0, 0)), - Some(Led(17.5, 21.0, 0)), - Some(Led(18.5, 21.0, 0)), - Some(Led(19.5, 21.0, 0)), - Some(Led(20.5, 21.0, 0)), - Some(Led(21.5, 21.0, 0)), - Some(Led(22.5, 21.0, 0)), - Some(Led(23.5, 21.0, 0)), - Some(Led(24.5, 21.0, 0)), - Some(Led(25.5, 21.0, 0)), - Some(Led(26.5, 21.0, 0)), - Some(Led(27.5, 21.0, 0)), - Some(Led(28.5, 21.0, 0)), - Some(Led(29.5, 21.0, 0)), - Some(Led(30.5, 21.0, 0)), - Some(Led(31.5, 21.0, 0)), - None, - Some(Led(8.0, 22.0, 0)), - Some(Led(9.0, 22.0, 0)), - Some(Led(10.0, 22.0, 0)), - Some(Led(11.0, 22.0, 0)), - Some(Led(12.0, 22.0, 0)), - Some(Led(13.0, 22.0, 0)), - Some(Led(14.0, 22.0, 0)), - Some(Led(15.0, 22.0, 0)), - Some(Led(16.0, 22.0, 0)), - Some(Led(17.0, 22.0, 0)), - Some(Led(18.0, 22.0, 0)), - Some(Led(19.0, 22.0, 0)), - Some(Led(20.0, 22.0, 0)), - Some(Led(21.0, 22.0, 0)), - Some(Led(22.0, 22.0, 0)), - Some(Led(23.0, 22.0, 0)), - Some(Led(24.0, 22.0, 0)), - Some(Led(25.0, 22.0, 0)), - Some(Led(26.0, 22.0, 0)), - Some(Led(27.0, 22.0, 0)), - Some(Led(28.0, 22.0, 0)), - Some(Led(29.0, 22.0, 0)), - Some(Led(30.0, 22.0, 0)), - Some(Led(31.0, 22.0, 0)), - Some(Led(32.0, 22.0, 0)), - Some(Led(8.5, 23.0, 0)), - Some(Led(9.5, 23.0, 0)), - Some(Led(10.5, 23.0, 0)), - Some(Led(11.5, 23.0, 0)), - Some(Led(12.5, 23.0, 0)), - Some(Led(13.5, 23.0, 0)), - Some(Led(14.5, 23.0, 0)), - Some(Led(15.5, 23.0, 0)), - Some(Led(16.5, 23.0, 0)), - Some(Led(17.5, 23.0, 0)), - Some(Led(18.5, 23.0, 0)), - Some(Led(19.5, 23.0, 0)), - Some(Led(20.5, 23.0, 0)), - Some(Led(21.5, 23.0, 0)), - Some(Led(22.5, 23.0, 0)), - Some(Led(23.5, 23.0, 0)), - Some(Led(24.5, 23.0, 0)), - Some(Led(25.5, 23.0, 0)), - Some(Led(26.5, 23.0, 0)), - Some(Led(27.5, 23.0, 0)), - Some(Led(28.5, 23.0, 0)), - Some(Led(29.5, 23.0, 0)), - Some(Led(30.5, 23.0, 0)), - Some(Led(31.5, 23.0, 0)), - None, - Some(Led(9.0, 24.0, 0)), - Some(Led(10.0, 24.0, 0)), - Some(Led(11.0, 24.0, 0)), - Some(Led(12.0, 24.0, 0)), - Some(Led(13.0, 24.0, 0)), - Some(Led(14.0, 24.0, 0)), - Some(Led(15.0, 24.0, 0)), - Some(Led(16.0, 24.0, 0)), - Some(Led(17.0, 24.0, 0)), - Some(Led(18.0, 24.0, 0)), - Some(Led(19.0, 24.0, 0)), - Some(Led(20.0, 24.0, 0)), - Some(Led(21.0, 24.0, 0)), - Some(Led(22.0, 24.0, 0)), - Some(Led(23.0, 24.0, 0)), - Some(Led(24.0, 24.0, 0)), - Some(Led(25.0, 24.0, 0)), - Some(Led(26.0, 24.0, 0)), - Some(Led(27.0, 24.0, 0)), - Some(Led(28.0, 24.0, 0)), - Some(Led(29.0, 24.0, 0)), - Some(Led(30.0, 24.0, 0)), - Some(Led(31.0, 24.0, 0)), - Some(Led(32.0, 24.0, 0)), - Some(Led(9.5, 25.0, 0)), - Some(Led(10.5, 25.0, 0)), - Some(Led(11.5, 25.0, 0)), - Some(Led(12.5, 25.0, 0)), - Some(Led(13.5, 25.0, 0)), - Some(Led(14.5, 25.0, 0)), - Some(Led(15.5, 25.0, 0)), - Some(Led(16.5, 25.0, 0)), - Some(Led(17.5, 25.0, 0)), - Some(Led(18.5, 25.0, 0)), - Some(Led(19.5, 25.0, 0)), - Some(Led(20.5, 25.0, 0)), - Some(Led(21.5, 25.0, 0)), - Some(Led(22.5, 25.0, 0)), - Some(Led(23.5, 25.0, 0)), - Some(Led(24.5, 25.0, 0)), - Some(Led(25.5, 25.0, 0)), - Some(Led(26.5, 25.0, 0)), - Some(Led(27.5, 25.0, 0)), - Some(Led(28.5, 25.0, 0)), - Some(Led(29.5, 25.0, 0)), - Some(Led(30.5, 25.0, 0)), - Some(Led(31.5, 25.0, 0)), - None, - Some(Led(10.0, 26.0, 0)), - Some(Led(11.0, 26.0, 0)), - Some(Led(12.0, 26.0, 0)), - Some(Led(13.0, 26.0, 0)), - Some(Led(14.0, 26.0, 0)), - Some(Led(15.0, 26.0, 0)), - Some(Led(16.0, 26.0, 0)), - Some(Led(17.0, 26.0, 0)), - Some(Led(18.0, 26.0, 0)), - Some(Led(19.0, 26.0, 0)), - Some(Led(20.0, 26.0, 0)), - Some(Led(21.0, 26.0, 0)), - Some(Led(22.0, 26.0, 0)), - Some(Led(23.0, 26.0, 0)), - Some(Led(24.0, 26.0, 0)), - Some(Led(25.0, 26.0, 0)), - Some(Led(26.0, 26.0, 0)), - Some(Led(27.0, 26.0, 0)), - Some(Led(28.0, 26.0, 0)), - Some(Led(29.0, 26.0, 0)), - Some(Led(30.0, 26.0, 0)), - Some(Led(31.0, 26.0, 0)), - Some(Led(32.0, 26.0, 0)), - Some(Led(10.5, 27.0, 0)), - Some(Led(11.5, 27.0, 0)), - Some(Led(12.5, 27.0, 0)), - Some(Led(13.5, 27.0, 0)), - Some(Led(14.5, 27.0, 0)), - Some(Led(15.5, 27.0, 0)), - Some(Led(16.5, 27.0, 0)), - Some(Led(17.5, 27.0, 0)), - Some(Led(18.5, 27.0, 0)), - Some(Led(19.5, 27.0, 0)), - Some(Led(20.5, 27.0, 0)), - Some(Led(21.5, 27.0, 0)), - Some(Led(22.5, 27.0, 0)), - Some(Led(23.5, 27.0, 0)), - Some(Led(24.5, 27.0, 0)), - Some(Led(25.5, 27.0, 0)), - Some(Led(26.5, 27.0, 0)), - Some(Led(27.5, 27.0, 0)), - Some(Led(28.5, 27.0, 0)), - Some(Led(29.5, 27.0, 0)), - Some(Led(30.5, 27.0, 0)), - Some(Led(31.5, 27.0, 0)), - None, - Some(Led(11.0, 28.0, 0)), - Some(Led(12.0, 28.0, 0)), - Some(Led(13.0, 28.0, 0)), - Some(Led(14.0, 28.0, 0)), - Some(Led(15.0, 28.0, 0)), - Some(Led(16.0, 28.0, 0)), - Some(Led(17.0, 28.0, 0)), - Some(Led(18.0, 28.0, 0)), - Some(Led(19.0, 28.0, 0)), - Some(Led(20.0, 28.0, 0)), - Some(Led(21.0, 28.0, 0)), - Some(Led(22.0, 28.0, 0)), - Some(Led(23.0, 28.0, 0)), - Some(Led(24.0, 28.0, 0)), - Some(Led(25.0, 28.0, 0)), - Some(Led(26.0, 28.0, 0)), - Some(Led(27.0, 28.0, 0)), - Some(Led(28.0, 28.0, 0)), - Some(Led(29.0, 28.0, 0)), - Some(Led(30.0, 28.0, 0)), - Some(Led(31.0, 28.0, 0)), - Some(Led(32.0, 28.0, 0)), - Some(Led(11.5, 29.0, 0)), - Some(Led(12.5, 29.0, 0)), - Some(Led(13.5, 29.0, 0)), - Some(Led(14.5, 29.0, 0)), - Some(Led(15.5, 29.0, 0)), - Some(Led(16.5, 29.0, 0)), - Some(Led(17.5, 29.0, 0)), - Some(Led(18.5, 29.0, 0)), - Some(Led(19.5, 29.0, 0)), - Some(Led(20.5, 29.0, 0)), - Some(Led(21.5, 29.0, 0)), - Some(Led(22.5, 29.0, 0)), - Some(Led(23.5, 29.0, 0)), - Some(Led(24.5, 29.0, 0)), - Some(Led(25.5, 29.0, 0)), - Some(Led(26.5, 29.0, 0)), - Some(Led(27.5, 29.0, 0)), - Some(Led(28.5, 29.0, 0)), - Some(Led(29.5, 29.0, 0)), - Some(Led(30.5, 29.0, 0)), - Some(Led(31.5, 29.0, 0)), - None, - Some(Led(12.0, 30.0, 0)), - Some(Led(13.0, 30.0, 0)), - Some(Led(14.0, 30.0, 0)), - Some(Led(15.0, 30.0, 0)), - Some(Led(16.0, 30.0, 0)), - Some(Led(17.0, 30.0, 0)), - Some(Led(18.0, 30.0, 0)), - Some(Led(19.0, 30.0, 0)), - Some(Led(20.0, 30.0, 0)), - Some(Led(21.0, 30.0, 0)), - Some(Led(22.0, 30.0, 0)), - Some(Led(23.0, 30.0, 0)), - Some(Led(24.0, 30.0, 0)), - Some(Led(25.0, 30.0, 0)), - Some(Led(26.0, 30.0, 0)), - Some(Led(27.0, 30.0, 0)), - Some(Led(28.0, 30.0, 0)), - Some(Led(29.0, 30.0, 0)), - Some(Led(30.0, 30.0, 0)), - Some(Led(31.0, 30.0, 0)), - Some(Led(32.0, 30.0, 0)), - Some(Led(12.5, 31.0, 0)), - Some(Led(13.5, 31.0, 0)), - Some(Led(14.5, 31.0, 0)), - Some(Led(15.5, 31.0, 0)), - Some(Led(16.5, 31.0, 0)), - Some(Led(17.5, 31.0, 0)), - Some(Led(18.5, 31.0, 0)), - Some(Led(19.5, 31.0, 0)), - Some(Led(20.5, 31.0, 0)), - Some(Led(21.5, 31.0, 0)), - Some(Led(22.5, 31.0, 0)), - Some(Led(23.5, 31.0, 0)), - Some(Led(24.5, 31.0, 0)), - Some(Led(25.5, 31.0, 0)), - Some(Led(26.5, 31.0, 0)), - Some(Led(27.5, 31.0, 0)), - Some(Led(28.5, 31.0, 0)), - Some(Led(29.5, 31.0, 0)), - Some(Led(30.5, 31.0, 0)), - Some(Led(31.5, 31.0, 0)), - None, - Some(Led(13.0, 32.0, 0)), - Some(Led(14.0, 32.0, 0)), - Some(Led(15.0, 32.0, 0)), - Some(Led(16.0, 32.0, 0)), - Some(Led(17.0, 32.0, 0)), - Some(Led(18.0, 32.0, 0)), - Some(Led(19.0, 32.0, 0)), - Some(Led(20.0, 32.0, 0)), - Some(Led(21.0, 32.0, 0)), - Some(Led(22.0, 32.0, 0)), - Some(Led(23.0, 32.0, 0)), - Some(Led(24.0, 32.0, 0)), - Some(Led(25.0, 32.0, 0)), - Some(Led(26.0, 32.0, 0)), - Some(Led(27.0, 32.0, 0)), - Some(Led(28.0, 32.0, 0)), - Some(Led(29.0, 32.0, 0)), - Some(Led(30.0, 32.0, 0)), - Some(Led(31.0, 32.0, 0)), - Some(Led(32.0, 32.0, 0)), - Some(Led(13.5, 33.0, 0)), - Some(Led(14.5, 33.0, 0)), - Some(Led(15.5, 33.0, 0)), - Some(Led(16.5, 33.0, 0)), - Some(Led(17.5, 33.0, 0)), - Some(Led(18.5, 33.0, 0)), - Some(Led(19.5, 33.0, 0)), - Some(Led(20.5, 33.0, 0)), - Some(Led(21.5, 33.0, 0)), - Some(Led(22.5, 33.0, 0)), - Some(Led(23.5, 33.0, 0)), - Some(Led(24.5, 33.0, 0)), - Some(Led(25.5, 33.0, 0)), - Some(Led(26.5, 33.0, 0)), - Some(Led(27.5, 33.0, 0)), - Some(Led(28.5, 33.0, 0)), - Some(Led(29.5, 33.0, 0)), - Some(Led(30.5, 33.0, 0)), - Some(Led(31.5, 33.0, 0)), - None, - Some(Led(14.0, 34.0, 0)), - Some(Led(15.0, 34.0, 0)), - Some(Led(16.0, 34.0, 0)), - Some(Led(17.0, 34.0, 0)), - Some(Led(18.0, 34.0, 0)), - Some(Led(19.0, 34.0, 0)), - Some(Led(20.0, 34.0, 0)), - Some(Led(21.0, 34.0, 0)), - Some(Led(22.0, 34.0, 0)), - Some(Led(23.0, 34.0, 0)), - Some(Led(24.0, 34.0, 0)), - Some(Led(25.0, 34.0, 0)), - Some(Led(26.0, 34.0, 0)), - Some(Led(27.0, 34.0, 0)), - Some(Led(28.0, 34.0, 0)), - Some(Led(29.0, 34.0, 0)), - Some(Led(30.0, 34.0, 0)), - Some(Led(31.0, 34.0, 0)), - Some(Led(32.0, 34.0, 0)), - Some(Led(14.5, 35.0, 0)), - Some(Led(15.5, 35.0, 0)), - Some(Led(16.5, 35.0, 0)), - Some(Led(17.5, 35.0, 0)), - Some(Led(18.5, 35.0, 0)), - Some(Led(19.5, 35.0, 0)), - Some(Led(20.5, 35.0, 0)), - Some(Led(21.5, 35.0, 0)), - Some(Led(22.5, 35.0, 0)), - Some(Led(23.5, 35.0, 0)), - Some(Led(24.5, 35.0, 0)), - Some(Led(25.5, 35.0, 0)), - Some(Led(26.5, 35.0, 0)), - Some(Led(27.5, 35.0, 0)), - Some(Led(28.5, 35.0, 0)), - Some(Led(29.5, 35.0, 0)), - Some(Led(30.5, 35.0, 0)), - Some(Led(31.5, 35.0, 0)), - None, - Some(Led(15.0, 36.0, 0)), - Some(Led(16.0, 36.0, 0)), - Some(Led(17.0, 36.0, 0)), - Some(Led(18.0, 36.0, 0)), - Some(Led(19.0, 36.0, 0)), - Some(Led(20.0, 36.0, 0)), - Some(Led(21.0, 36.0, 0)), - Some(Led(22.0, 36.0, 0)), - Some(Led(23.0, 36.0, 0)), - Some(Led(24.0, 36.0, 0)), - Some(Led(25.0, 36.0, 0)), - Some(Led(26.0, 36.0, 0)), - Some(Led(27.0, 36.0, 0)), - Some(Led(28.0, 36.0, 0)), - Some(Led(29.0, 36.0, 0)), - Some(Led(30.0, 36.0, 0)), - Some(Led(31.0, 36.0, 0)), - Some(Led(32.0, 36.0, 0)), - Some(Led(15.5, 37.0, 0)), - Some(Led(16.5, 37.0, 0)), - Some(Led(17.5, 37.0, 0)), - Some(Led(18.5, 37.0, 0)), - Some(Led(19.5, 37.0, 0)), - Some(Led(20.5, 37.0, 0)), - Some(Led(21.5, 37.0, 0)), - Some(Led(22.5, 37.0, 0)), - Some(Led(23.5, 37.0, 0)), - Some(Led(24.5, 37.0, 0)), - Some(Led(25.5, 37.0, 0)), - Some(Led(26.5, 37.0, 0)), - Some(Led(27.5, 37.0, 0)), - Some(Led(28.5, 37.0, 0)), - Some(Led(29.5, 37.0, 0)), - Some(Led(30.5, 37.0, 0)), - Some(Led(31.5, 37.0, 0)), - None, - Some(Led(16.0, 38.0, 0)), - Some(Led(17.0, 38.0, 0)), - Some(Led(18.0, 38.0, 0)), - Some(Led(19.0, 38.0, 0)), - Some(Led(20.0, 38.0, 0)), - Some(Led(21.0, 38.0, 0)), - Some(Led(22.0, 38.0, 0)), - Some(Led(23.0, 38.0, 0)), - Some(Led(24.0, 38.0, 0)), - Some(Led(25.0, 38.0, 0)), - Some(Led(26.0, 38.0, 0)), - Some(Led(27.0, 38.0, 0)), - Some(Led(28.0, 38.0, 0)), - Some(Led(29.0, 38.0, 0)), - Some(Led(30.0, 38.0, 0)), - Some(Led(31.0, 38.0, 0)), - Some(Led(32.0, 38.0, 0)), - Some(Led(16.5, 39.0, 0)), - Some(Led(17.5, 39.0, 0)), - Some(Led(18.5, 39.0, 0)), - Some(Led(19.5, 39.0, 0)), - Some(Led(20.5, 39.0, 0)), - Some(Led(21.5, 39.0, 0)), - Some(Led(22.5, 39.0, 0)), - Some(Led(23.5, 39.0, 0)), - Some(Led(24.5, 39.0, 0)), - Some(Led(25.5, 39.0, 0)), - Some(Led(26.5, 39.0, 0)), - Some(Led(27.5, 39.0, 0)), - Some(Led(28.5, 39.0, 0)), - Some(Led(29.5, 39.0, 0)), - Some(Led(30.5, 39.0, 0)), - Some(Led(31.5, 39.0, 0)), - None, - Some(Led(17.0, 40.0, 0)), - Some(Led(18.0, 40.0, 0)), - Some(Led(19.0, 40.0, 0)), - Some(Led(20.0, 40.0, 0)), - Some(Led(21.0, 40.0, 0)), - Some(Led(22.0, 40.0, 0)), - Some(Led(23.0, 40.0, 0)), - Some(Led(24.0, 40.0, 0)), - Some(Led(25.0, 40.0, 0)), - Some(Led(26.0, 40.0, 0)), - Some(Led(27.0, 40.0, 0)), - Some(Led(28.0, 40.0, 0)), - Some(Led(29.0, 40.0, 0)), - Some(Led(30.0, 40.0, 0)), - Some(Led(31.0, 40.0, 0)), - Some(Led(32.0, 40.0, 0)), - Some(Led(17.5, 41.0, 0)), - Some(Led(18.5, 41.0, 0)), - Some(Led(19.5, 41.0, 0)), - Some(Led(20.5, 41.0, 0)), - Some(Led(21.5, 41.0, 0)), - Some(Led(22.5, 41.0, 0)), - Some(Led(23.5, 41.0, 0)), - Some(Led(24.5, 41.0, 0)), - Some(Led(25.5, 41.0, 0)), - Some(Led(26.5, 41.0, 0)), - Some(Led(27.5, 41.0, 0)), - Some(Led(28.5, 41.0, 0)), - Some(Led(29.5, 41.0, 0)), - Some(Led(30.5, 41.0, 0)), - Some(Led(31.5, 41.0, 0)), - None, - Some(Led(18.0, 42.0, 0)), - Some(Led(19.0, 42.0, 0)), - Some(Led(20.0, 42.0, 0)), - Some(Led(21.0, 42.0, 0)), - Some(Led(22.0, 42.0, 0)), - Some(Led(23.0, 42.0, 0)), - Some(Led(24.0, 42.0, 0)), - Some(Led(25.0, 42.0, 0)), - Some(Led(26.0, 42.0, 0)), - Some(Led(27.0, 42.0, 0)), - Some(Led(28.0, 42.0, 0)), - Some(Led(29.0, 42.0, 0)), - Some(Led(30.0, 42.0, 0)), - Some(Led(31.0, 42.0, 0)), - Some(Led(32.0, 42.0, 0)), - Some(Led(18.5, 43.0, 0)), - Some(Led(19.5, 43.0, 0)), - Some(Led(20.5, 43.0, 0)), - Some(Led(21.5, 43.0, 0)), - Some(Led(22.5, 43.0, 0)), - Some(Led(23.5, 43.0, 0)), - Some(Led(24.5, 43.0, 0)), - Some(Led(25.5, 43.0, 0)), - Some(Led(26.5, 43.0, 0)), - Some(Led(27.5, 43.0, 0)), - Some(Led(28.5, 43.0, 0)), - Some(Led(29.5, 43.0, 0)), - Some(Led(30.5, 43.0, 0)), - Some(Led(31.5, 43.0, 0)), - None, - Some(Led(19.0, 44.0, 0)), - Some(Led(20.0, 44.0, 0)), - Some(Led(21.0, 44.0, 0)), - Some(Led(22.0, 44.0, 0)), - Some(Led(23.0, 44.0, 0)), - Some(Led(24.0, 44.0, 0)), - Some(Led(25.0, 44.0, 0)), - Some(Led(26.0, 44.0, 0)), - Some(Led(27.0, 44.0, 0)), - Some(Led(28.0, 44.0, 0)), - Some(Led(29.0, 44.0, 0)), - Some(Led(30.0, 44.0, 0)), - Some(Led(31.0, 44.0, 0)), - Some(Led(32.0, 44.0, 0)), - Some(Led(19.5, 45.0, 0)), - Some(Led(20.5, 45.0, 0)), - Some(Led(21.5, 45.0, 0)), - Some(Led(22.5, 45.0, 0)), - Some(Led(23.5, 45.0, 0)), - Some(Led(24.5, 45.0, 0)), - Some(Led(25.5, 45.0, 0)), - Some(Led(26.5, 45.0, 0)), - Some(Led(27.5, 45.0, 0)), - Some(Led(28.5, 45.0, 0)), - Some(Led(29.5, 45.0, 0)), - Some(Led(30.5, 45.0, 0)), - Some(Led(31.5, 45.0, 0)), - None, - Some(Led(20.0, 46.0, 0)), - Some(Led(21.0, 46.0, 0)), - Some(Led(22.0, 46.0, 0)), - Some(Led(23.0, 46.0, 0)), - Some(Led(24.0, 46.0, 0)), - Some(Led(25.0, 46.0, 0)), - Some(Led(26.0, 46.0, 0)), - Some(Led(27.0, 46.0, 0)), - Some(Led(28.0, 46.0, 0)), - Some(Led(29.0, 46.0, 0)), - Some(Led(30.0, 46.0, 0)), - Some(Led(31.0, 46.0, 0)), - Some(Led(32.0, 46.0, 0)), - Some(Led(20.5, 47.0, 0)), - Some(Led(21.5, 47.0, 0)), - Some(Led(22.5, 47.0, 0)), - Some(Led(23.5, 47.0, 0)), - Some(Led(24.5, 47.0, 0)), - Some(Led(25.5, 47.0, 0)), - Some(Led(26.5, 47.0, 0)), - Some(Led(27.5, 47.0, 0)), - Some(Led(28.5, 47.0, 0)), - Some(Led(29.5, 47.0, 0)), - Some(Led(30.5, 47.0, 0)), - Some(Led(31.5, 47.0, 0)), - None, - Some(Led(21.0, 48.0, 0)), - Some(Led(22.0, 48.0, 0)), - Some(Led(23.0, 48.0, 0)), - Some(Led(24.0, 48.0, 0)), - Some(Led(25.0, 48.0, 0)), - Some(Led(26.0, 48.0, 0)), - Some(Led(27.0, 48.0, 0)), - Some(Led(28.0, 48.0, 0)), - Some(Led(29.0, 48.0, 0)), - Some(Led(30.0, 48.0, 0)), - Some(Led(31.0, 48.0, 0)), - Some(Led(32.0, 48.0, 0)), - Some(Led(21.5, 49.0, 0)), - Some(Led(22.5, 49.0, 0)), - Some(Led(23.5, 49.0, 0)), - Some(Led(24.5, 49.0, 0)), - Some(Led(25.5, 49.0, 0)), - Some(Led(26.5, 49.0, 0)), - Some(Led(27.5, 49.0, 0)), - Some(Led(28.5, 49.0, 0)), - Some(Led(29.5, 49.0, 0)), - Some(Led(30.5, 49.0, 0)), - Some(Led(31.5, 49.0, 0)), - None, - Some(Led(22.0, 50.0, 0)), - Some(Led(23.0, 50.0, 0)), - Some(Led(24.0, 50.0, 0)), - Some(Led(25.0, 50.0, 0)), - Some(Led(26.0, 50.0, 0)), - Some(Led(27.0, 50.0, 0)), - Some(Led(28.0, 50.0, 0)), - Some(Led(29.0, 50.0, 0)), - Some(Led(30.0, 50.0, 0)), - Some(Led(31.0, 50.0, 0)), - Some(Led(32.0, 50.0, 0)), - Some(Led(22.5, 51.0, 0)), - Some(Led(23.5, 51.0, 0)), - Some(Led(24.5, 51.0, 0)), - Some(Led(25.5, 51.0, 0)), - Some(Led(26.5, 51.0, 0)), - Some(Led(27.5, 51.0, 0)), - Some(Led(28.5, 51.0, 0)), - Some(Led(29.5, 51.0, 0)), - Some(Led(30.5, 51.0, 0)), - Some(Led(31.5, 51.0, 0)), - None, - Some(Led(23.0, 52.0, 0)), - Some(Led(24.0, 52.0, 0)), - Some(Led(25.0, 52.0, 0)), - Some(Led(26.0, 52.0, 0)), - Some(Led(27.0, 52.0, 0)), - Some(Led(28.0, 52.0, 0)), - Some(Led(29.0, 52.0, 0)), - Some(Led(30.0, 52.0, 0)), - Some(Led(31.0, 52.0, 0)), - Some(Led(32.0, 52.0, 0)), - Some(Led(23.5, 53.0, 0)), - Some(Led(24.5, 53.0, 0)), - Some(Led(25.5, 53.0, 0)), - Some(Led(26.5, 53.0, 0)), - Some(Led(27.5, 53.0, 0)), - Some(Led(28.5, 53.0, 0)), - Some(Led(29.5, 53.0, 0)), - Some(Led(30.5, 53.0, 0)), - Some(Led(31.5, 53.0, 0)), - None, - Some(Led(24.0, 54.0, 0)), - Some(Led(25.0, 54.0, 0)), - Some(Led(26.0, 54.0, 0)), - Some(Led(27.0, 54.0, 0)), - Some(Led(28.0, 54.0, 0)), - Some(Led(29.0, 54.0, 0)), - Some(Led(30.0, 54.0, 0)), - Some(Led(31.0, 54.0, 0)), - Some(Led(32.0, 54.0, 0)), -]; - #[cfg(test)] mod tests { use crate::image::*; #[test] fn led_positions() { - let leds = AnimeImage::generate(); + let leds = AnimeImage::generate_image_positioning(AnimeType::GA401); assert_eq!(leds[0], Some(Led(0.0, 0.0, 0))); assert_eq!(leds[1], Some(Led(1.0, 0.0, 0))); assert_eq!(leds[2], Some(Led(2.0, 0.0, 0))); @@ -1645,60 +433,63 @@ mod tests { assert_eq!(leds[673], Some(Led(31.5, 21.0, 0))); // end } - #[test] - fn led_positions_const() { - let leds = AnimeImage::generate(); - assert_eq!(leds[1], LED_IMAGE_POSITIONS[1]); - assert_eq!(leds[34], LED_IMAGE_POSITIONS[34]); - assert_eq!(leds[69], LED_IMAGE_POSITIONS[69]); - assert_eq!(leds[137], LED_IMAGE_POSITIONS[137]); - assert_eq!(leds[169], LED_IMAGE_POSITIONS[169]); - assert_eq!(leds[170], LED_IMAGE_POSITIONS[170]); - assert_eq!(leds[236], LED_IMAGE_POSITIONS[236]); - assert_eq!(leds[649], LED_IMAGE_POSITIONS[649]); - assert_eq!(leds[674], LED_IMAGE_POSITIONS[674]); - } + // #[test] + // fn led_positions_const() { + // let leds = AnimeImage::generate(); + // assert_eq!(leds[1], LED_IMAGE_POSITIONS[1]); + // assert_eq!(leds[34], LED_IMAGE_POSITIONS[34]); + // assert_eq!(leds[69], LED_IMAGE_POSITIONS[69]); + // assert_eq!(leds[137], LED_IMAGE_POSITIONS[137]); + // assert_eq!(leds[169], LED_IMAGE_POSITIONS[169]); + // assert_eq!(leds[170], LED_IMAGE_POSITIONS[170]); + // assert_eq!(leds[236], LED_IMAGE_POSITIONS[236]); + // assert_eq!(leds[649], LED_IMAGE_POSITIONS[649]); + // assert_eq!(leds[674], LED_IMAGE_POSITIONS[674]); + // } #[test] fn row_starts() { - assert_eq!(AnimeImage::first_x(5), 0); - assert_eq!(AnimeImage::first_x(6), 0); - assert_eq!(AnimeImage::first_x(7), 1); - assert_eq!(AnimeImage::first_x(8), 1); - assert_eq!(AnimeImage::first_x(9), 2); - assert_eq!(AnimeImage::first_x(10), 2); - assert_eq!(AnimeImage::first_x(11), 3); + let a = AnimeType::GA401; + assert_eq!(AnimeImage::first_x(a, 5), 0); + assert_eq!(AnimeImage::first_x(a, 6), 0); + assert_eq!(AnimeImage::first_x(a, 7), 1); + assert_eq!(AnimeImage::first_x(a, 8), 1); + assert_eq!(AnimeImage::first_x(a, 9), 2); + assert_eq!(AnimeImage::first_x(a, 10), 2); + assert_eq!(AnimeImage::first_x(a, 11), 3); } #[test] fn row_widths() { - assert_eq!(AnimeImage::width(5), 33); - assert_eq!(AnimeImage::width(6), 33); - assert_eq!(AnimeImage::width(7), 32); - assert_eq!(AnimeImage::width(8), 32); - assert_eq!(AnimeImage::width(9), 31); - assert_eq!(AnimeImage::width(10), 31); - assert_eq!(AnimeImage::width(11), 30); - assert_eq!(AnimeImage::width(12), 30); - assert_eq!(AnimeImage::width(13), 29); - assert_eq!(AnimeImage::width(14), 29); - assert_eq!(AnimeImage::width(15), 28); - assert_eq!(AnimeImage::width(16), 28); - assert_eq!(AnimeImage::width(17), 27); - assert_eq!(AnimeImage::width(18), 27); + let a = AnimeType::GA401; + assert_eq!(AnimeImage::width(a, 5), 33); + assert_eq!(AnimeImage::width(a, 6), 33); + assert_eq!(AnimeImage::width(a, 7), 32); + assert_eq!(AnimeImage::width(a, 8), 32); + assert_eq!(AnimeImage::width(a, 9), 31); + assert_eq!(AnimeImage::width(a, 10), 31); + assert_eq!(AnimeImage::width(a, 11), 30); + assert_eq!(AnimeImage::width(a, 12), 30); + assert_eq!(AnimeImage::width(a, 13), 29); + assert_eq!(AnimeImage::width(a, 14), 29); + assert_eq!(AnimeImage::width(a, 15), 28); + assert_eq!(AnimeImage::width(a, 16), 28); + assert_eq!(AnimeImage::width(a, 17), 27); + assert_eq!(AnimeImage::width(a, 18), 27); } #[test] fn row_pitch() { - assert_eq!(AnimeImage::pitch(5), 34); - assert_eq!(AnimeImage::pitch(6), 33); - assert_eq!(AnimeImage::pitch(7), 33); - assert_eq!(AnimeImage::pitch(8), 32); - assert_eq!(AnimeImage::pitch(9), 32); - assert_eq!(AnimeImage::pitch(10), 31); - assert_eq!(AnimeImage::pitch(11), 31); - assert_eq!(AnimeImage::pitch(12), 30); - assert_eq!(AnimeImage::pitch(13), 30); - assert_eq!(AnimeImage::pitch(14), 29); + let a = AnimeType::GA401; + assert_eq!(AnimeImage::pitch(a, 5), 34); + assert_eq!(AnimeImage::pitch(a, 6), 33); + assert_eq!(AnimeImage::pitch(a, 7), 33); + assert_eq!(AnimeImage::pitch(a, 8), 32); + assert_eq!(AnimeImage::pitch(a, 9), 32); + assert_eq!(AnimeImage::pitch(a, 10), 31); + assert_eq!(AnimeImage::pitch(a, 11), 31); + assert_eq!(AnimeImage::pitch(a, 12), 30); + assert_eq!(AnimeImage::pitch(a, 13), 30); + assert_eq!(AnimeImage::pitch(a, 14), 29); } } diff --git a/rog-anime/src/sequencer.rs b/rog-anime/src/sequencer.rs index 5db29882..a71099a2 100644 --- a/rog-anime/src/sequencer.rs +++ b/rog-anime/src/sequencer.rs @@ -3,7 +3,9 @@ use std::{path::PathBuf, time::Duration}; use glam::Vec2; use serde_derive::{Deserialize, Serialize}; -use crate::{error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage}; +use crate::{ + error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, +}; /// All the possible AniMe actions that can be used. This enum is intended to be /// a helper for loading up `ActionData`. @@ -63,13 +65,21 @@ pub enum ActionData { } impl ActionData { - pub fn from_anime_action(action: &ActionLoader) -> Result { + pub fn from_anime_action( + anime_type: AnimeType, + action: &ActionLoader, + ) -> Result { let a = match action { ActionLoader::AsusAnimation { file, time, brightness, - } => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?), + } => ActionData::Animation(AnimeGif::from_diagonal_gif( + file, + *time, + *brightness, + anime_type, + )?), ActionLoader::AsusImage { file, time, @@ -77,10 +87,15 @@ impl ActionData { } => match time { AnimTime::Infinite => { let image = AnimeDiagonal::from_png(file, None, *brightness)?; - let data = ::from(&image); + let data = image.into_data_buffer(anime_type); ActionData::Image(Box::new(data)) } - _ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?), + _ => ActionData::Animation(AnimeGif::from_diagonal_png( + file, + anime_type, + *time, + *brightness, + )?), }, ActionLoader::ImageAnimation { file, @@ -99,6 +114,7 @@ impl ActionData { *translation, *time, *brightness, + anime_type, )?)); } } @@ -109,6 +125,7 @@ impl ActionData { *translation, *time, *brightness, + anime_type, )?) } ActionLoader::Image { @@ -122,8 +139,14 @@ impl ActionData { match time { AnimTime::Infinite => { // If no time then create a plain static image - let image = - AnimeImage::from_png(file, *scale, *angle, *translation, *brightness)?; + let image = AnimeImage::from_png( + file, + *scale, + *angle, + *translation, + *brightness, + anime_type, + )?; let data = ::from(&image); ActionData::Image(Box::new(data)) } @@ -134,6 +157,7 @@ impl ActionData { *translation, *time, *brightness, + anime_type, )?), } } @@ -144,20 +168,21 @@ impl ActionData { } /// An optimised precomputed set of actions that the user can cycle through -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct Sequences(Vec); +#[derive(Debug, Deserialize, Serialize)] +pub struct Sequences(Vec, AnimeType); impl Sequences { #[inline] - pub fn new() -> Self { - Self(Vec::new()) + pub fn new(anime_type: AnimeType) -> Self { + Self(Vec::new(), anime_type) } /// Use a base `AnimeAction` to generate the precomputed data and insert in to /// the run buffer #[inline] pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<(), AnimeError> { - self.0.insert(index, ActionData::from_anime_action(action)?); + self.0 + .insert(index, ActionData::from_anime_action(self.1, action)?); Ok(()) } diff --git a/rog-anime/src/usb.rs b/rog-anime/src/usb.rs index 622b160a..c8fa60ec 100644 --- a/rog-anime/src/usb.rs +++ b/rog-anime/src/usb.rs @@ -7,6 +7,8 @@ //! //! Step 1 need to applied only on fresh system boot. +use crate::{error::AnimeError, 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'.', ]; @@ -15,6 +17,47 @@ const DEV_PAGE: u8 = 0x5e; pub const VENDOR_ID: u16 = 0x0b05; pub const PROD_ID: u16 = 0x193b; +/// `get_anime_type` is very broad, matching on part of the laptop board name only. For this +/// reason `find_node()` must be used also to verify if the USB device is available. +/// +/// The currently known USB device is `19b6`. +#[inline] +pub fn get_anime_type() -> Result { + let dmi = sysfs_class::DmiId::default(); + let board_name = dmi.board_name()?; + + if board_name.contains("GA401Q") { + return Ok(AnimeType::GA401); + } else if board_name.contains("GA401R") { + return Ok(AnimeType::GA402); + } + Err(AnimeError::UnsupportedDevice) +} + +/// Find the USB device node - known devices so far: `19b6` +#[inline] +pub fn find_node(id_product: &str) -> Result { + let mut enumerator = + udev::Enumerator::new().map_err(|err| AnimeError::Udev("enumerator failed".into(), err))?; + enumerator + .match_subsystem("usb") + .map_err(|err| AnimeError::Udev("match_subsystem failed".into(), err))?; + + for device in enumerator + .scan_devices() + .map_err(|err| AnimeError::Udev("scan_devices failed".into(), err))? + { + if let Some(attr) = device.attribute_value("idProduct") { + if attr == id_product { + if let Some(dev_node) = device.devnode() { + return Ok(dev_node.to_string_lossy().to_string()); + } + } + } + } + Err(AnimeError::NoDevice) +} + /// Get the two device initialization packets. These are required for device start /// after the laptop boots. #[inline] diff --git a/rog-anime/test/ga401-diagonal.gif b/rog-anime/test/ga401-diagonal.gif new file mode 100644 index 0000000000000000000000000000000000000000..79091dc7366e37924018261e5353792f74c89377 GIT binary patch literal 981 zcmV;`11kJSNk%w1VL$*R0Ou+I000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IP59EC2ui06+jF000QG009UbNU)&6g9sBUT*$B?!G91PN}MS1 zpTLL|Gin@Ykz>b=ARB)47_wx-kq=RtEU7Z(%9Sk(VtlzVroovsC)zxSGbh8H2z&Yr zS`(;GqY8x%y=YSD(U(r4=8Vd6DAk%v0bHes6y#QiT|<6d7?x$(n^}XN<(T&5+O<&2 z!lgNO?o^|8kM7KCH6~xHMB8TcD|m3=!W9oA7U^~|vgTSe5>s*vyz*8_SyS8dw+ZHbCSDC z9O!FdW^G0w5G;g#Ucvac2mY})HNvkOj9-i+5R6wPgoJ5=p*WIKrNE>yC`l8qL`kSt ziV+CfhNn4mR9#M%KQ=EOwa;kbiu=m4H*w&F{40L-VS7iOdW|mdDKQm#TzT>DDB-Yc zHNA{C=DD{j>}7ceervGE9mYGma%9cZIZu4|K1_U)>sF$Cr_8^%eO*tJt=$=dhGgRy>leMdOn2d#z){GW|#0WG_wGM1JdWP7dpJ2)+| z*Uqit>yZb>v_(I)td@X3tuLQk!1^X@{o$|DdhK_t9C;(dz{2>|N*`HwMAG>n|PPkbiXHe-GF4^1hLhFYE9cwjj{on(J+ z!PIo})~KzoXz4@8RF>L*8(4TT_+@SccN`L0n&0|8<6(%{JAP%};V0qeaw%JfkKZ4# zl##J6-DAe2`2paVnx=;bz74-yL^3)zKj&|)^9zT{9~}YqI73+ za_Y8=)9gumr0jL8t0E1r{TLb*C4Lqyu2PNlSP51n(ZejlJ(vZn_ej*iJX=e@;YsAV z+5Q)djF(f(j|q2VmH+GXG#l&h^B#zb)>VnBG7uAo)#YJo8#C{fMU@8bfr~+_HMEAY z@EZCpqmgCh4c5_R`|_-|%?R8;ujREJF?UJ0U&+3e&{jR%&19U_`eGuh>bAg?D!FKS z;p=KU>yw+1V4c)oYqU)3_rX>XcYX34JNhDRm4 z3r?F{-MqCpSGxaT>zt^L;s)Et+3&`btP(J9X0@a~E4F^dV+WW9I;JvH=4;bTot}jm z5`fwJE}54(IG@=p^OVdSOLVk|4mEN%F^(No$Dmf&9dtf_9(d>z=>A}0^UR;Z4$Yg~ zJ@Y_h$*9Dk_jlDFHREp2J^o0r^yTz7XNMoAI8>L^UkG8%^j79%^Rc<0I7;MnV}Try zxok@HTw8DE8dKzO^gE(D_<9l6QtjUP;F4jcdki6~DXp~0D0Y0t=tAQesMhiu*R}6k zJtvItQKrVcgPd7mc;_Oi%!5PsbGED?$a za7Anl!C|nb-uV0F?Y>UZ!t*oxFNuk}J%n9di;d6s9#6kMMTbfu^^Er4oZsv$uIuTE zNLpV@$$CCj*p_`huAp#~X{3qN_;`+Ic#;xZ8%oL>SD0}Gu_I{`cPts>&#MVJYVN>) zTNgjXKjBqT*D#&Ku7rVZsD+Iyj`lpbnO!?YT(^(1CGMBPS^3R1Kdz5hnmBJoXK%*c zox7Ls95>?rkmPF7q?GH|m&7lri?Ha9OkO&CXm4@ch4K^j-?AnYXSPn_Prc-~ti`;p za#niYt}<2NsIay(Q)OL23*W8aym!n5!k$u=6$*Ago%7W;_cH6Tqbe56fAQd{6g(F_8?z)mU< zh=l^dhfNvZiu1Ot-RplsY?WFQve#P^Y<0>uCAuIzXKu+uW$Meki@ZEy490@M)-cX>s+RC4^~+Y=Y=WHlvj6Ri;K ze_#ydbn~AtKi&23H1tJL^pVYN?_H-&pPO2DaI$&VR>SCdPcD}Hu_x_iW70CGM9aqM zo4s2cJLH)@sh4);PrTB8=E@(KL#<1#XkKN?1?sQb`qi6gwgp?AFJ0vxhk_mjTPlNu zPNJ39a;3#BJ|XAN-S=QvK4e+MH^%<_YvwxFiJdfJTwy08epBzeh_{@b?6NiSHddZZ z;o{2Euy)zYw(6;VIYb-CJHDA$VXqqmLo!9n+LLgY$O7Sx+OccO_6*3nH zQAki1txSoZaRh>^yH*Lo(Wr(bK_jJdKKc3K8Zt?W@X527B2c6hpixr41Qj|XAut3^ zh=#cc+1<^|Rm;NxWT*xrX=O2THBZYY>v4Jby-rLalk_T@Xg)biBqj+IDwM=;^JK5=q?IXB!$Z5aw#B%r<^q0_h+`lPh8yt70aAIa_R~a&REEybKsq+5EGC;yqtmz`i^B#P z+)qlOs7j4jq7IV^y3qRw(WQll2ZIv}>FN{*&|BcK@B}Ip(kN6R3PlW`taFK^v-~(M z!rKXfG>{jhL2*!!M&p5O9>@)$QgI4+OwgH%O9tpG5GfY_zqEDDLvrm)xt~;xuOF`$ z^>x$?bYb79Zx|!hw-Sk@Zwej+_l2N_7NLmVPaLan3XX#0ktn`<^q1=gx%5v;0poBv zFbhKfCYL4w7;KgV;L@2Wz~ay_80AnQ41@=xs}-0g4pO0>kvNYyS9p2qxgt5~6E$hD zc3c#y%K}KF0w4nbSs_$9&K8eJ>nDuz_lF1~EDngF5Wr+2x)Me3x~Ec^01KuwIT99v z(NNA{r~iTw89e%jn)nAo#1MQhfME>aq99whC!hcXGr0gAMnF8T2#qU|{3RjM035%+ z>_Hxl^Uq}wW6`OYM8X1?bdU}(I2fKqIs@Oh*mN!zVxfqH*4O_Z+u;Aq;=m9GbasCh zT`9W5?L%w2QvR!X`xFM8hIoPZ$?#JaKeQd^ktFH;`a+( zU+DTQ20lyqOLcvr>$4d6EaflN^_S6Q_UV5=D#w4W$Kn6#^BOJy_!9v`$uwUt0-#x{twBr(7*A9HJ45yoa<7F&#suSxh&|!bMd=FVB#$6Q^znhn*l< z8ecBXd^<1aJIQQ+NzCo;V>S^6JLT8QG}RSP^WRL&`{6V@I?^Y>!(G11;g`+@hP>Sl zw|{dczHWa@)OH*uzV28|)OJoGzV3WX)OPJ8zV3=9dbK+fPqudvy*l<0Pj;w@UY&H} z$66g(Bn~;E0MPa;7e|Ht|b0Qd{S9x94cj^U;77q7W9s9W%y=a(PQVp`F*1 zYN}nS0^j!7OooThFPUnVVn5@}0MK@&IdN-!a<^;Oq`bnf1^B^-2Po*3cPKQMMX153 rSQZwEhUchac}Z8OxiQA583#&uH;UzFx+Lhp+UoiW8!HRTQ2+otuJ}~- literal 0 HcmV?d00001 diff --git a/rog-anime/test/ga402-diagonal.png b/rog-anime/test/ga402-diagonal.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa5b62e2de5cf8940d8d1215eb0120f7367414e GIT binary patch literal 670 zcmV;P0%84$P)EX>4Tx04R}tkv&MmKpe$iQ>8^J4i*$~$WWauh>AFB6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0HIM~n$AQI0q!?cMvh^IGg zgY!Odl$B(a_?&pmqze*1a$WKGjdRgufoDd|OnRO;N-P#TSm|I^GBx5U;+U%GlrLmG zRyl8R)+#mDx+i~OB(JY5bDicel32tNB#2N@Lm3s=h|{W*Vj)fY2_OHE>zBx-kgE(v zjs;YqL3aJ%fAG6ot1vm?B}EcI_lx6vi~ylspjmgE?_%tF%H5o z425Aw*b-v~xK9>#FWmnsK$`^Hf1|2tEcuh0Co)cOTD#K3)@0Zst+ ziwS>y1`ePeZwFVwv&+C0@IH43m%-Iz;1a0&YlF8g4CUWp-~y;&0x#1=F#eH&+n}Z! za&QaGH*VnOQ5kgM&Z9Hv5>{haQ_tylhP8%$zQZ~yA6ak>Byk{k0{{R307*qoM6N<$ Ef_B6ig8%>k literal 0 HcmV?d00001 From f3f6fadfe22372d08d8c2581400cbafe44284762 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 10 Jul 2022 15:05:46 +1200 Subject: [PATCH 2/8] Fix anime exampels --- asusctl/examples/anime-diag-png.rs | 6 ++++-- asusctl/examples/anime-diag.rs | 10 +++++++--- asusctl/examples/anime-gif.rs | 5 +++-- asusctl/examples/anime-grid.rs | 5 +++-- asusctl/examples/anime-outline.rs | 5 +++-- asusctl/examples/anime-png.rs | 3 +++ asusctl/examples/anime-spinning.rs | 3 +++ asusctl/examples/aura-rgb-ball.rs | 6 ++---- 8 files changed, 28 insertions(+), 15 deletions(-) diff --git a/asusctl/examples/anime-diag-png.rs b/asusctl/examples/anime-diag-png.rs index 2fe4303d..cdc0962e 100644 --- a/asusctl/examples/anime-diag-png.rs +++ b/asusctl/examples/anime-diag-png.rs @@ -1,6 +1,6 @@ use std::{env, error::Error, path::Path, process::exit}; -use rog_anime::{AnimeDataBuffer, AnimeDiagonal}; +use rog_anime::{usb::get_anime_type, AnimeDiagonal}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { @@ -16,10 +16,12 @@ fn main() -> Result<(), Box> { let matrix = AnimeDiagonal::from_png(Path::new(&args[1]), None, args[2].parse::().unwrap())?; + let anime_type = get_anime_type()?; + client .proxies() .anime() - .write(::from(&matrix)) + .write(matrix.into_data_buffer(anime_type)) .unwrap(); Ok(()) diff --git a/asusctl/examples/anime-diag.rs b/asusctl/examples/anime-diag.rs index 0a9a97b4..c3817447 100644 --- a/asusctl/examples/anime-diag.rs +++ b/asusctl/examples/anime-diag.rs @@ -1,6 +1,6 @@ use std::{thread::sleep, time::Duration}; -use rog_anime::{AnimeDataBuffer, AnimeDiagonal}; +use rog_anime::{usb::get_anime_type, AnimeDiagonal}; use rog_dbus::RogDbusClientBlocking; // In usable data: @@ -25,8 +25,12 @@ fn main() { } } - let m = ::from(&matrix); - client.proxies().anime().write(m).unwrap(); + let anime_type = get_anime_type().unwrap(); + client + .proxies() + .anime() + .write(matrix.into_data_buffer(anime_type)) + .unwrap(); sleep(Duration::from_millis(300)); } } diff --git a/asusctl/examples/anime-gif.rs b/asusctl/examples/anime-gif.rs index 045b1592..79deecf0 100644 --- a/asusctl/examples/anime-gif.rs +++ b/asusctl/examples/anime-gif.rs @@ -1,6 +1,6 @@ use std::{env, path::Path, thread::sleep}; -use rog_anime::{ActionData, ActionLoader, Sequences}; +use rog_anime::{usb::get_anime_type, ActionData, ActionLoader, Sequences}; use rog_dbus::RogDbusClientBlocking; fn main() { @@ -14,7 +14,8 @@ fn main() { let path = Path::new(&args[1]); let brightness = args[2].parse::().unwrap(); - let mut seq = Sequences::new(); + let anime_type = get_anime_type().unwrap(); + let mut seq = Sequences::new(anime_type); seq.insert( 0, &ActionLoader::AsusAnimation { diff --git a/asusctl/examples/anime-grid.rs b/asusctl/examples/anime-grid.rs index a862edb6..ea532899 100644 --- a/asusctl/examples/anime-grid.rs +++ b/asusctl/examples/anime-grid.rs @@ -1,4 +1,4 @@ -use rog_anime::{AnimeDataBuffer, AnimeGrid}; +use rog_anime::{usb::get_anime_type, AnimeDataBuffer, AnimeGrid}; use rog_dbus::RogDbusClientBlocking; // In usable data: @@ -8,7 +8,8 @@ use rog_dbus::RogDbusClientBlocking; fn main() { let (client, _) = RogDbusClientBlocking::new().unwrap(); - let mut matrix = AnimeGrid::new(None); + let anime_type = get_anime_type().unwrap(); + let mut matrix = AnimeGrid::new(anime_type); let tmp = matrix.get_mut(); let mut i = 0; diff --git a/asusctl/examples/anime-outline.rs b/asusctl/examples/anime-outline.rs index 35829eb9..f7a0fba9 100644 --- a/asusctl/examples/anime-outline.rs +++ b/asusctl/examples/anime-outline.rs @@ -1,4 +1,4 @@ -use rog_anime::AnimeDataBuffer; +use rog_anime::{usb::get_anime_type, AnimeDataBuffer}; use rog_dbus::RogDbusClientBlocking; // In usable data: @@ -6,7 +6,8 @@ use rog_dbus::RogDbusClientBlocking; fn main() { let (client, _) = RogDbusClientBlocking::new().unwrap(); - let mut matrix = AnimeDataBuffer::new(); + let anime_type = get_anime_type().unwrap(); + let mut matrix = AnimeDataBuffer::new(anime_type); matrix.data_mut()[1] = 100; // start = 1 for n in matrix.data_mut()[2..32].iter_mut() { *n = 250; diff --git a/asusctl/examples/anime-png.rs b/asusctl/examples/anime-png.rs index 69cd8b9e..99c24656 100644 --- a/asusctl/examples/anime-png.rs +++ b/asusctl/examples/anime-png.rs @@ -1,6 +1,7 @@ use std::{env, error::Error, path::Path, process::exit}; use rog_anime::{ + usb::get_anime_type, AnimeDataBuffer, {AnimeImage, Vec2}, }; use rog_dbus::RogDbusClientBlocking; @@ -15,6 +16,7 @@ fn main() -> Result<(), Box> { exit(-1); } + let anime_type = get_anime_type()?; let matrix = AnimeImage::from_png( Path::new(&args[1]), args[2].parse::().unwrap(), @@ -24,6 +26,7 @@ fn main() -> Result<(), Box> { args[5].parse::().unwrap(), ), args[6].parse::().unwrap(), + anime_type, )?; client diff --git a/asusctl/examples/anime-spinning.rs b/asusctl/examples/anime-spinning.rs index 6f1d4db0..0beb53ca 100644 --- a/asusctl/examples/anime-spinning.rs +++ b/asusctl/examples/anime-spinning.rs @@ -3,6 +3,7 @@ use std::{ }; use rog_anime::{ + usb::get_anime_type, AnimeDataBuffer, {AnimeImage, Vec2}, }; use rog_dbus::RogDbusClientBlocking; @@ -17,6 +18,7 @@ fn main() -> Result<(), Box> { exit(-1); } + let anime_type = get_anime_type()?; let mut matrix = AnimeImage::from_png( Path::new(&args[1]), args[2].parse::().unwrap(), @@ -26,6 +28,7 @@ fn main() -> Result<(), Box> { args[5].parse::().unwrap(), ), args[6].parse::().unwrap(), + anime_type, )?; loop { diff --git a/asusctl/examples/aura-rgb-ball.rs b/asusctl/examples/aura-rgb-ball.rs index d7c21235..883c3ee7 100644 --- a/asusctl/examples/aura-rgb-ball.rs +++ b/asusctl/examples/aura-rgb-ball.rs @@ -1,5 +1,5 @@ use rog_aura::{GX502Layout, Key, KeyColourArray, KeyLayout}; -use rog_dbus::RogDbusClient; +use rog_dbus::RogDbusClientBlocking; use std::collections::LinkedList; #[derive(Debug, Clone)] @@ -52,7 +52,7 @@ impl Ball { } fn main() -> Result<(), Box> { - let (dbus, _) = RogDbusClient::new()?; + let (dbus, _) = RogDbusClientBlocking::new()?; let mut colours = KeyColourArray::new(); @@ -60,8 +60,6 @@ fn main() -> Result<(), Box> { let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)]; - dbus.proxies().led().init_effect()?; - let rows = layout.get_rows(); loop { for (n, ball) in balls.iter_mut().enumerate() { From a2c8a226a4d50e16b658bef4cb87970e7b64f7f5 Mon Sep 17 00:00:00 2001 From: I-Al-Istannen Date: Sun, 10 Jul 2022 13:23:21 +0200 Subject: [PATCH 3/8] Complete anime diagonal gif support for GA402 --- asusctl/src/main.rs | 2 +- daemon/src/ctrl_anime/config.rs | 3 +- daemon/src/ctrl_anime/mod.rs | 19 ++++-------- rog-anime/src/data.rs | 52 +++++++++++++++++++++------------ rog-anime/src/diagonal.rs | 48 ++++++++++++------------------ rog-anime/src/gif.rs | 5 ++-- rog-anime/src/grid.rs | 9 ++---- rog-anime/src/image.rs | 8 ++--- rog-anime/src/sequencer.rs | 2 +- rog-anime/src/usb.rs | 2 +- 10 files changed, 69 insertions(+), 81 deletions(-) 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) From e66847c26365626dd92d33897d2a8e82dded1d62 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 13 Jul 2022 21:17:10 +1200 Subject: [PATCH 4/8] Add commenting to AnimeImage to help with GA402 --- asusctl/src/main.rs | 7 ++++++- daemon/src/ctrl_anime/config.rs | 6 +++++- daemon/src/ctrl_anime/mod.rs | 6 ++---- rog-anime/src/image.rs | 33 ++++++++++++++++++++++++++++----- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index b7d2c084..331980fc 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -268,7 +268,12 @@ fn handle_anime( std::process::exit(1); } - let matrix = AnimeDiagonal::from_png(Path::new(&image.path), None, image.bright, anime_type)?; + 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 d45624c5..7d6a2a98 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -80,7 +80,11 @@ pub struct AnimeConfigCached { } impl AnimeConfigCached { - pub fn init_from_config(&mut self, config: &AnimeConfig, anime_type: AnimeType) -> Result<(), AnimeError> { + 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 f52c632f..fed5a296 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -201,10 +201,8 @@ impl CtrlAnime { } // Clear the display on exit if let Ok(lock) = inner.try_lock() { - let data = AnimeDataBuffer::from_vec( - anime_type, - vec![0u8; anime_type.data_length()], - ); + 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/image.rs b/rog-anime/src/image.rs index 8d2640de..3a14a421 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -99,6 +99,11 @@ impl AnimeImage { // TODO: Convert functions back to const after todo completed /// Scale ratio in CM + /// + /// This is worked out by measuring the pyhsical width of the display, then dividing by + /// ` + 0.5`, where the LED count is first/longest row. + /// + /// For GA401 this is `26.8 / (33 + 0.5) = 0.8` fn scale_x(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.8, @@ -107,6 +112,11 @@ impl AnimeImage { } /// Scale ratio in CM + /// + /// This is worked out by measuring the pyhsical height of the display, then dividing by + /// ` + 1.0`, where the LED count is first/longest row. + /// + /// For GA401 this is `16.5 / (54.0 + 1.0) = 0.3` fn scale_y(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.3, @@ -115,24 +125,33 @@ impl AnimeImage { } /// Get the starting X position for the data we actually require when writing - /// it out to LEDs + /// it out to LEDs. + /// + /// In relation to the display itself you should think of it as a full square grid, so `first_x` + /// is the x position on that grid where the LED is actually positioned in relation to the Y. fn first_x(anime_type: AnimeType, y: u32) -> u32 { match anime_type { AnimeType::GA401 => { if y < 5 { + // first 5 rows for GA401 are always at X = 0 return 0; } (y + 1) / 2 - 3 } + // The GA402 has different number of rows with consistent length and + // row lengths and may need new offset formula AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } } /// Width in LED count + /// + /// This is how many LED's are physically in a row fn width(anime_type: AnimeType, y: u32) -> u32 { match anime_type { AnimeType::GA401 => { if y < 5 { + // First 5 rows for GA401 are always 33 physical LEDs long return 33; } 36 - (y + 1) / 2 @@ -144,12 +163,13 @@ impl AnimeImage { /// Physical display width fn phys_width(anime_type: AnimeType) -> f32 { match anime_type { - AnimeType::GA401 => (32.0 - -0.5 + 1.0) * Self::scale_x(anime_type), + // 33.0 = Longest row LED count (physical) plus half-pixel offset + AnimeType::GA401 => (33.0 + 0.5) * Self::scale_x(anime_type), AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), } } - /// Height in LED count + /// Height in LED count of longest column (physical) fn height(anime_type: AnimeType) -> u32 { match anime_type { AnimeType::GA401 => 55, @@ -160,7 +180,9 @@ impl AnimeImage { /// Physical display height fn phys_height(anime_type: AnimeType) -> f32 { match anime_type { + // 54.0 = End column LED count (physical) plus one dead pixel 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 => todo!("GA402R series AnimeImage positions not completed"), } } @@ -170,7 +192,7 @@ impl AnimeImage { match anime_type { AnimeType::GA401 => match y { 0 | 2 | 4 => 33, - 1 | 3 => 35, + 1 | 3 => 35, // Some rows are padded _ => 36 - y / 2, }, AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), @@ -187,12 +209,13 @@ impl AnimeImage { match anime_type { AnimeType::GA401 => (0..AnimeImage::height(anime_type)) .flat_map(|y| { + // For each row (Y) get actual length (0..AnimeImage::pitch(anime_type, y)).map(move |l| { if l < AnimeImage::width(anime_type, y) { let x = AnimeImage::first_x(anime_type, y) + l; Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) } else { - None + None // dead pixels to the left } }) }) From 37d586c5de451bc7d9501ab95a4d137ddb14fd51 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 15 Jul 2022 11:13:38 +1200 Subject: [PATCH 5/8] Additional comments in animeimage --- rog-anime/src/image.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 3a14a421..10fd2983 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -203,7 +203,8 @@ impl AnimeImage { &mut self.img_pixels } - /// Generate the data used to + /// Generate a list of LED positions. These are then used to sample the Image data, + /// and will contain their resulting brightness. #[inline] pub fn generate_image_positioning(anime_type: AnimeType) -> Vec> { match anime_type { @@ -215,7 +216,7 @@ impl AnimeImage { let x = AnimeImage::first_x(anime_type, y) + l; Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) } else { - None // dead pixels to the left + None // dead/non-existant pixels to the left } }) }) @@ -226,7 +227,10 @@ impl AnimeImage { /// Called after setting new angle, position, or scale to refresh the image /// samples, the result can then been transformed to the appropriate data - /// for displaying + /// for displaying. + /// + /// The internal for loop iterates over the LED positions, skipping the blank/dead + /// pixels if any. #[inline] pub fn update(&mut self) { let width = self.width as i32; From 16c4ee609e470792d0bf2e14e56c9eaf85548713 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 15 Jul 2022 12:52:08 +1200 Subject: [PATCH 6/8] Add GA402 anime-matrix packet unit test --- asusctl/examples/anime-diag-png.rs | 10 +- asusctl/examples/anime-diag.rs | 4 +- rog-anime/src/data.rs | 2 +- rog-anime/src/diagonal.rs | 290 ++++++++++++++++++- rog-anime/src/image.rs | 257 ++++++++++++++-- rog-anime/test/ga402-diagonal-fullbright.png | Bin 0 -> 7755 bytes rog-anime/test/ga402-diagonal.png | Bin 670 -> 7678 bytes 7 files changed, 526 insertions(+), 37 deletions(-) create mode 100644 rog-anime/test/ga402-diagonal-fullbright.png diff --git a/asusctl/examples/anime-diag-png.rs b/asusctl/examples/anime-diag-png.rs index cdc0962e..25c617a7 100644 --- a/asusctl/examples/anime-diag-png.rs +++ b/asusctl/examples/anime-diag-png.rs @@ -1,6 +1,6 @@ use std::{env, error::Error, path::Path, process::exit}; -use rog_anime::{usb::get_anime_type, AnimeDiagonal}; +use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { @@ -13,8 +13,12 @@ fn main() -> Result<(), Box> { exit(-1); } - let matrix = - AnimeDiagonal::from_png(Path::new(&args[1]), None, args[2].parse::().unwrap())?; + let matrix = AnimeDiagonal::from_png( + Path::new(&args[1]), + None, + args[2].parse::().unwrap(), + AnimeType::GA401, + )?; let anime_type = get_anime_type()?; diff --git a/asusctl/examples/anime-diag.rs b/asusctl/examples/anime-diag.rs index c3817447..9874b1bc 100644 --- a/asusctl/examples/anime-diag.rs +++ b/asusctl/examples/anime-diag.rs @@ -1,6 +1,6 @@ use std::{thread::sleep, time::Duration}; -use rog_anime::{usb::get_anime_type, AnimeDiagonal}; +use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType}; use rog_dbus::RogDbusClientBlocking; // In usable data: @@ -12,7 +12,7 @@ fn main() { let (client, _) = RogDbusClientBlocking::new().unwrap(); for step in (2..50).rev() { - let mut matrix = AnimeDiagonal::new(None); + let mut matrix = AnimeDiagonal::new(AnimeType::GA401, None); for c in (0..60).into_iter().step_by(step) { for i in matrix.get_mut().iter_mut() { i[c] = 50; diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index 9fd26212..acda75b9 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -33,7 +33,7 @@ pub struct AnimePowerStates { } #[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Copy, Clone, Deserialize, Serialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] pub enum AnimeType { GA401, GA402, diff --git a/rog-anime/src/diagonal.rs b/rog-anime/src/diagonal.rs index fd457b9d..e89aeb40 100644 --- a/rog-anime/src/diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -25,7 +25,8 @@ impl AnimeDiagonal { 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.1[self.0.height() - y - i - 1][x + i]; + let y = self.0.height() - y - i - 1; + let val = self.1[y][x + i]; buf.push(val); } buf @@ -92,7 +93,9 @@ impl AnimeDiagonal { + (::from(px.two()) / 3) as f32 + (::from(px.three()) / 3) as f32 }; - matrix.1[y][x] = (v * bright) as u8; + if y < matrix.1.len() && x < matrix.1[y].len() { + matrix.1[y][x] = (v * bright) as u8; + } } } } @@ -140,7 +143,7 @@ impl AnimeDiagonal { buf[102..=134].copy_from_slice(&self.get_row(1, 1, 33)); buf[137..=169].copy_from_slice(&self.get_row(2, 1, 33)); buf[170..=202].copy_from_slice(&self.get_row(2, 0, 33)); - buf[204..=236].copy_from_slice(&self.get_row(3, 0, 33)); + buf[204..=236].copy_from_slice(&self.get_row(3, 0, 33)); // This and above cause overflow? buf[237..=268].copy_from_slice(&self.get_row(4, 0, 32)); buf[270..=301].copy_from_slice(&self.get_row(5, 0, 32)); buf[302..=332].copy_from_slice(&self.get_row(6, 0, 31)); @@ -377,4 +380,285 @@ mod tests { assert_eq!(pkt[0], pkt0_check); assert_eq!(pkt[1], pkt1_check); } + + #[test] + fn ga402_diagonal_packet_check() { + let pkt0_check = [ + 0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, + ]; + let pkt1_check = [ + 0x5e, 0xc0, 0x2, 0x74, 0x2, 0x73, 0x2, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + let pkt2_check = [ + 0x5e, 0xc0, 0x2, 0xe7, 0x4, 0x73, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("test/ga402-diagonal.png"); + + let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA402).unwrap(); + let data = matrix.into_data_buffer(crate::AnimeType::GA402); + let pkt = AnimePacketType::from(data); + + assert_eq!(pkt[0], pkt0_check); + assert_eq!(pkt[1], pkt1_check); + assert_eq!(pkt[2], pkt2_check); + } + + #[test] + #[ignore = "Needs the packets verified with capture"] + fn ga402_diagonal_fullbright_packet_check() { + let pkt0_check = [ + 0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x67, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + let pkt1_check = [ + 0x5e, 0xc0, 0x2, 0x74, 0x2, 0x73, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + let pkt2_check = [ + 0x5e, 0xc0, 0x2, 0xe7, 0x4, 0x73, 0x2, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("test/ga402-diagonal-fullbright.png"); + + let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA402).unwrap(); + let data = matrix.into_data_buffer(crate::AnimeType::GA402); + let pkt = AnimePacketType::from(data); + + assert_eq!(pkt[0], pkt0_check); + assert_eq!(pkt[1], pkt1_check); + assert_eq!(pkt[2], pkt2_check); + } } diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 10fd2983..3aa8fa31 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -104,10 +104,11 @@ impl AnimeImage { /// ` + 0.5`, where the LED count is first/longest row. /// /// For GA401 this is `26.8 / (33 + 0.5) = 0.8` + /// For GA402 this is `27.3 / (35 + 0.5) = 0.77` fn scale_x(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.8, - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => 0.77, } } @@ -117,10 +118,11 @@ impl AnimeImage { /// ` + 1.0`, where the LED count is first/longest row. /// /// For GA401 this is `16.5 / (54.0 + 1.0) = 0.3` + /// For GA402 this is `17.0 / (61.0 + 1.0) = 0.274` fn scale_y(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.3, - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => 0.274, } } @@ -140,7 +142,12 @@ impl AnimeImage { } // The GA402 has different number of rows with consistent length and // row lengths and may need new offset formula - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => { + if y <= 11 { + return 0; + } + (y + 1) / 2 - 5 + } } } @@ -156,24 +163,29 @@ impl AnimeImage { } 36 - (y + 1) / 2 } - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => { + if y <= 11 { + return 34; + } + 39 - y / 2 + } } } - /// Physical display width + /// Physical display width by count of LED fn phys_width(anime_type: AnimeType) -> f32 { match anime_type { // 33.0 = Longest row LED count (physical) plus half-pixel offset AnimeType::GA401 => (33.0 + 0.5) * Self::scale_x(anime_type), - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => (35.0 + 0.5) * Self::scale_x(anime_type), } } - /// Height in LED count of longest column (physical) + /// Height in LED count of longest column (physical count) fn height(anime_type: AnimeType) -> u32 { match anime_type { AnimeType::GA401 => 55, - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => 61, } } @@ -183,7 +195,7 @@ impl AnimeImage { // 54.0 = End column LED count (physical) plus one dead pixel 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 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => (61.0 + 1.0) * Self::scale_y(anime_type), } } @@ -195,7 +207,12 @@ impl AnimeImage { 1 | 3 => 35, // Some rows are padded _ => 36 - y / 2, }, - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), + AnimeType::GA402 => match y { + 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 => 34, // CONFIRMED CORRECT + // 0|1 | 2 | 4 | 6 | 8 | 10 => 34, // These are the top rows of consistent length + //1|3|5|7|9|11 => 35, // Padding.. may be needed for odd rows, but unsure + _ => 39 - y / 2, // This may not be correct (37 is a guess based on photo) + }, } } @@ -207,22 +224,19 @@ impl AnimeImage { /// and will contain their resulting brightness. #[inline] pub fn generate_image_positioning(anime_type: AnimeType) -> Vec> { - match anime_type { - AnimeType::GA401 => (0..AnimeImage::height(anime_type)) - .flat_map(|y| { - // For each row (Y) get actual length - (0..AnimeImage::pitch(anime_type, y)).map(move |l| { - if l < AnimeImage::width(anime_type, y) { - let x = AnimeImage::first_x(anime_type, y) + l; - Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) - } else { - None // dead/non-existant pixels to the left - } - }) + (0..AnimeImage::height(anime_type)) + .flat_map(|y| { + // For each row (Y) get actual length + (0..AnimeImage::pitch(anime_type, y)).map(move |l| { + if l < AnimeImage::width(anime_type, y) { + let x = AnimeImage::first_x(anime_type, y) + l; + Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) + } else { + None // dead/non-existant pixels to the left + } }) - .collect(), - AnimeType::GA402 => todo!("GA402R series AnimeImage positions not completed"), - } + }) + .collect() } /// Called after setting new angle, position, or scale to refresh the image @@ -269,6 +283,48 @@ impl AnimeImage { sum /= count as f32; led.set_bright((sum * self.bright * alpha) as u8); } + + // TODO: remove when sorted out + // if self.anime_type == AnimeType::GA402 { + self.edge_outline(); + // } + } + + fn edge_outline(&mut self) { + // Janky shit here just to try help align images + let mut last_x = 0.0; + let mut last_y = 0.0; + let mut last_was_led = false; + let mut ends = Vec::new(); + for (idx, led) in self.led_pos.iter_mut().enumerate() { + if let Some(led) = led { + // Capture the starting LED + if led.x() - last_x != 1.0 { + led.set_bright(255); + last_x = led.x(); + } else { + // top and bottom + if led.y() == 0.0 || led.y() >= AnimeImage::height(self.anime_type) as f32 - 1.0 + { + led.set_bright(255); + } + last_x += 1.0; + } + if led.y() - last_y == 1.0 { + ends.push(idx); + last_y = led.y(); + } + last_was_led = true; + } else if last_was_led { + //ends.push(idx); + last_was_led = false; + } + } + for end in ends { + if let Some(led) = self.led_pos[end - 1].as_mut() { + led.set_bright(255); + } + } } /// Put the render window in place on the image @@ -416,16 +472,18 @@ impl From<&AnimeImage> for AnimeDataBuffer { .map(|l| if let Some(l) = l { l.bright() } else { 0 }) .collect(); let mut v = Vec::with_capacity(leds.anime_type.data_length()); - v.push(0); + if leds.anime_type == AnimeType::GA401 { + v.push(0); + } v.append(&mut l); - v.append(&mut vec![0u8; 9]); + v.append(&mut vec![0u8; leds.anime_type.data_length() - v.len()]); AnimeDataBuffer::from_vec(leds.anime_type, v) } } #[cfg(test)] mod tests { - use crate::image::*; + use crate::{image::*, AnimePacketType}; #[test] fn led_positions() { @@ -515,4 +573,147 @@ mod tests { assert_eq!(AnimeImage::pitch(a, 13), 30); assert_eq!(AnimeImage::pitch(a, 14), 29); } + + #[test] + #[ignore = "Needs the packets verified with capture"] + fn ga402_image_edge_packet_check() { + let pkt0_check = [ + 0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, + ]; + let pkt1_check = [ + 0x5e, 0xc0, 0x2, 0x74, 0x2, 0x73, 0x2, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + let pkt2_check = [ + 0x5e, 0xc0, 0x2, 0xe7, 0x4, 0x73, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + let mut matrix = AnimeImage::new( + Vec2::new(1.0, 1.0), + 0.0, + Vec2::default(), + 0.0, + vec![Pixel::default(); 1000], + 100, + AnimeType::GA402, + ); + matrix.edge_outline(); + let data = AnimeDataBuffer::from(&matrix); + let pkt = AnimePacketType::from(data); + + assert_eq!(pkt[0], pkt0_check); + assert_eq!(pkt[1], pkt1_check); + assert_eq!(pkt[2], pkt2_check); + } } diff --git a/rog-anime/test/ga402-diagonal-fullbright.png b/rog-anime/test/ga402-diagonal-fullbright.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3c0af852f359609f9bfea8b8b2cb96e1c72aaf GIT binary patch literal 7755 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 z

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 fc<1AuMj|;#mjlz~@5GL&ikDvV?ow=H~ delta 630 zcmV-+0*U?pJDvrQ7=Ho-0002h)HY@S00D$)LqkwWLqi~Na&Km7Y-IodD3N`UJxIeq z9K~N#r9~1q~8j=(jN5Qq=;KyRs!Nplu2UkH5 z`~Y!ua#D1W691PJTEuv8+>dwn9(V5mp;2L))in-ix^1SD34bx0TNOjE2qBCC#4sQ; z%b1g-6nw|mJpz2ai}Ni1bAOIrHE%H>AQI0q!?cMvh^IGggY!Odl$B(a_?&pmqze*1 za$WKGjdRgufoDd|OnRO;N-P#TSm|I^GBx5U;+U%GlrLmGRyl8R)+#mDx+i~OB(JY5 zbDicel32tNB!7rdP(v9N*of1rlVTxF`w1Wakn5MorI4!(Mvetkp+R>2;D7MDTdOcR z;Uz^9K=+H|e2f60U7%TaobO}DX`TSVXW&Y2`>PFL=9Bb#TZ{haQ_tylhP8%$zQZ~yA6ak>Byk{k Q0{{R307*qoM6N<$g0w0YxBvhE From eabe78af713025bfba4c7aac862ab803ea6df4bd Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 15 Jul 2022 22:41:15 +1200 Subject: [PATCH 7/8] tmp --- rog-anime/src/data.rs | 2 +- rog-anime/src/image.rs | 16 ++++++++++++++-- .../aura-rgb-ball.rs | 0 .../aura-rgb-comet.rs | 0 .../aura-rgb-iterate-keys.rs | 0 .../aura-rgb-per-key-effect-2.rs | 0 .../aura-rgb-pulser.rs | 0 7 files changed, 15 insertions(+), 3 deletions(-) rename {asusctl/examples => tmp-aura-examples}/aura-rgb-ball.rs (100%) rename {asusctl/examples => tmp-aura-examples}/aura-rgb-comet.rs (100%) rename {asusctl/examples => tmp-aura-examples}/aura-rgb-iterate-keys.rs (100%) rename {asusctl/examples => tmp-aura-examples}/aura-rgb-per-key-effect-2.rs (100%) rename {asusctl/examples => tmp-aura-examples}/aura-rgb-pulser.rs (100%) diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index acda75b9..af72ae03 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -51,7 +51,7 @@ impl AnimeType { /// The height of diagonal images pub fn height(&self) -> usize { match self { - AnimeType::GA401 => 32, + AnimeType::GA401 => 36, AnimeType::GA402 => 39, } } diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 3aa8fa31..9ea6eb1d 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -483,7 +483,9 @@ impl From<&AnimeImage> for AnimeDataBuffer { #[cfg(test)] mod tests { - use crate::{image::*, AnimePacketType}; + use std::path::PathBuf; + + use crate::{image::*, AnimePacketType, AnimeGif, AnimTime}; #[test] fn led_positions() { @@ -575,7 +577,6 @@ mod tests { } #[test] - #[ignore = "Needs the packets verified with capture"] fn ga402_image_edge_packet_check() { let pkt0_check = [ 0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -716,4 +717,15 @@ mod tests { assert_eq!(pkt[1], pkt1_check); assert_eq!(pkt[2], pkt2_check); } + + #[test] + #[ignore = "Just to inspect image packet"] + fn ga402_image_packet_check() { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("data/anime/custom/sonic-run.gif"); + + let matrix = AnimeGif::from_gif(&path, 1.0, 0.0, Vec2::default(), AnimTime::Infinite, 1.0, AnimeType::GA402).unwrap(); + matrix.frames()[0].frame(); + let _pkt = AnimePacketType::from(matrix.frames()[0].frame().clone()); + } } diff --git a/asusctl/examples/aura-rgb-ball.rs b/tmp-aura-examples/aura-rgb-ball.rs similarity index 100% rename from asusctl/examples/aura-rgb-ball.rs rename to tmp-aura-examples/aura-rgb-ball.rs diff --git a/asusctl/examples/aura-rgb-comet.rs b/tmp-aura-examples/aura-rgb-comet.rs similarity index 100% rename from asusctl/examples/aura-rgb-comet.rs rename to tmp-aura-examples/aura-rgb-comet.rs diff --git a/asusctl/examples/aura-rgb-iterate-keys.rs b/tmp-aura-examples/aura-rgb-iterate-keys.rs similarity index 100% rename from asusctl/examples/aura-rgb-iterate-keys.rs rename to tmp-aura-examples/aura-rgb-iterate-keys.rs diff --git a/asusctl/examples/aura-rgb-per-key-effect-2.rs b/tmp-aura-examples/aura-rgb-per-key-effect-2.rs similarity index 100% rename from asusctl/examples/aura-rgb-per-key-effect-2.rs rename to tmp-aura-examples/aura-rgb-per-key-effect-2.rs diff --git a/asusctl/examples/aura-rgb-pulser.rs b/tmp-aura-examples/aura-rgb-pulser.rs similarity index 100% rename from asusctl/examples/aura-rgb-pulser.rs rename to tmp-aura-examples/aura-rgb-pulser.rs From 2512cea19d6e1e83f61a7bdf25f6839c7db710c7 Mon Sep 17 00:00:00 2001 From: I-Al-Istannen Date: Fri, 15 Jul 2022 13:11:24 +0200 Subject: [PATCH 8/8] Slightly adjust G402 scaling, add some more documentation --- rog-anime/src/image.rs | 62 +++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 9ea6eb1d..de1441a2 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -100,11 +100,12 @@ impl AnimeImage { /// Scale ratio in CM /// - /// This is worked out by measuring the pyhsical width of the display, then dividing by - /// ` + 0.5`, where the LED count is first/longest row. + /// This is worked out by measuring the physical width of the display from pixel center to + /// center, then dividing by ` + 0.5`, where the LED count is + /// first/longest row. /// /// For GA401 this is `26.8 / (33 + 0.5) = 0.8` - /// For GA402 this is `27.3 / (35 + 0.5) = 0.77` + /// For GA402 this is `27.4 / (35 + 0.5) = 0.77` fn scale_x(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.8, @@ -114,15 +115,16 @@ impl AnimeImage { /// Scale ratio in CM /// - /// This is worked out by measuring the pyhsical height of the display, then dividing by - /// ` + 1.0`, where the LED count is first/longest row. + /// This is worked out by measuring the physical height of the display from pixel center to + /// pixel center, then dividing by ` + 1.0`, where the LED count is + /// first/longest row. /// /// For GA401 this is `16.5 / (54.0 + 1.0) = 0.3` - /// For GA402 this is `17.0 / (61.0 + 1.0) = 0.274` + /// For GA402 this is `17.3 / (61.0) = 0.283` fn scale_y(anime_type: AnimeType) -> f32 { match anime_type { AnimeType::GA401 => 0.3, - AnimeType::GA402 => 0.274, + AnimeType::GA402 => 0.283, } } @@ -131,6 +133,19 @@ impl AnimeImage { /// /// In relation to the display itself you should think of it as a full square grid, so `first_x` /// is the x position on that grid where the LED is actually positioned in relation to the Y. + /// ```text + /// +------------+ + /// | | + /// | | + /// \ | + /// \ | + /// \ | + /// \ | + /// \ | + /// |----|\ | + /// ^ ------+ + /// first_x + /// ``` fn first_x(anime_type: AnimeType, y: u32) -> u32 { match anime_type { AnimeType::GA401 => { @@ -140,12 +155,12 @@ impl AnimeImage { } (y + 1) / 2 - 3 } - // The GA402 has different number of rows with consistent length and - // row lengths and may need new offset formula AnimeType::GA402 => { + // first 11 rows start at zero if y <= 11 { return 0; } + // and then their offset grows by one every two rows (y + 1) / 2 - 5 } } @@ -154,6 +169,18 @@ impl AnimeImage { /// Width in LED count /// /// This is how many LED's are physically in a row + /// ```text + /// +------------+ + /// | | + /// | | + /// \ | + /// \ width | + /// \ v | + /// \|------|| + /// \ | + /// \ | + /// ------+ + /// ``` fn width(anime_type: AnimeType, y: u32) -> u32 { match anime_type { AnimeType::GA401 => { @@ -195,7 +222,7 @@ impl AnimeImage { // 54.0 = End column LED count (physical) plus one dead pixel 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 + 1.0) * Self::scale_y(anime_type), + AnimeType::GA402 => 61.0 * Self::scale_y(anime_type), } } @@ -207,12 +234,8 @@ impl AnimeImage { 1 | 3 => 35, // Some rows are padded _ => 36 - y / 2, }, - AnimeType::GA402 => match y { - 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 => 34, // CONFIRMED CORRECT - // 0|1 | 2 | 4 | 6 | 8 | 10 => 34, // These are the top rows of consistent length - //1|3|5|7|9|11 => 35, // Padding.. may be needed for odd rows, but unsure - _ => 39 - y / 2, // This may not be correct (37 is a guess based on photo) - }, + // GA402 does not have padding, equivalent to width + AnimeType::GA402 => AnimeImage::width(anime_type, y), } } @@ -232,7 +255,7 @@ impl AnimeImage { let x = AnimeImage::first_x(anime_type, y) + l; Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32)) } else { - None // dead/non-existant pixels to the left + None // dead/non-existent pixels to the left } }) }) @@ -283,11 +306,6 @@ impl AnimeImage { sum /= count as f32; led.set_bright((sum * self.bright * alpha) as u8); } - - // TODO: remove when sorted out - // if self.anime_type == AnimeType::GA402 { - self.edge_outline(); - // } } fn edge_outline(&mut self) {