diff --git a/aura/examples/animatrix.rs b/aura/examples/animatrix.rs index d242cb68..155b43dc 100644 --- a/aura/examples/animatrix.rs +++ b/aura/examples/animatrix.rs @@ -1,12 +1,42 @@ -use rog_aura::AniMeDbusWriter; +use rog_aura::{AniMeDbusWriter, AniMeMatrix, AniMePacketType}; fn main() { let mut writer = AniMeDbusWriter::new().unwrap(); loop { - for brightness in 0..0xFF { - let mut buffers = [[brightness; 640], [brightness; 640]]; - writer.write_image(&mut buffers).unwrap(); + for brightness in 0x01..0xFF { + let mut matrix = AniMeMatrix::new(); + matrix.fill_with(brightness); + + let mut matrix: AniMePacketType = AniMePacketType::from(matrix); + // println!("{:?}", matrix[0].to_vec()); + // println!("{:?}", matrix[1].to_vec()); + + writer.write_image(&mut matrix).unwrap(); + } + break; + } + + // Try an outline, top and right + let mut matrix = AniMeMatrix::new(); + { + let mut tmp = matrix.get_mut(); + let mut first_row_done = false; + for row in tmp.iter_mut() { + if !first_row_done { + for c in row.iter_mut() { + *c = 0xff; + } + first_row_done = true; + } else { + row[row.len() - 1] = 0xff; + } } } + + let mut matrix: AniMePacketType = AniMePacketType::from(matrix); + println!("{:?}", matrix[0].to_vec()); + println!("{:?}", matrix[1].to_vec()); + + writer.write_image(&mut matrix).unwrap(); } diff --git a/aura/examples/ball.rs b/aura/examples/ball.rs index 5a359b14..e0ede3cb 100644 --- a/aura/examples/ball.rs +++ b/aura/examples/ball.rs @@ -56,7 +56,7 @@ fn main() -> Result<(), Box> { let layout = GX502Layout::default(); - let mut balls = [Ball::new(2, 1, 8), Ball::new(4, 6, 6), Ball::new(12, 3, 4)]; + let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)]; writer.init_effect()?; diff --git a/aura/src/animatrix_dbus.rs b/aura/src/animatrix_dbus.rs index 897a250c..7a7b4ad5 100644 --- a/aura/src/animatrix_dbus.rs +++ b/aura/src/animatrix_dbus.rs @@ -11,7 +11,49 @@ use std::{thread, time::Duration}; pub const ANIME_PANE1_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02]; pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02]; -/// Simplified way to write a effect block +/// Interface for the AniMe dot-matrix display +/// +/// The resolution is 34x56 (1904) but only 1,215 LEDs in the top-left are used. +/// The display is available only on select GA401 models. +/// +/// Amory crate assumes first row is 33 pixels/bytes, this means the actual structure +/// likely follows this format with every second line offset physically by half. +/// Even rows (mod 1) are aligned right, odd are offset left by half (`..=` is inclusive) +/// +/// - 0..=32, row 0, 33 pixels // len starts at 37 if using formula +/// - 33..=66, row 1, 33 pixels +/// - 68..=101, row 2, 33 pixels +/// - 101..=134, row 3, 33 pixels +/// - 135..=168, row 4, 33 pixels +/// - 169..=202, row 5, 33 pixels // Should be last offset line? +/// - 203..=236, row 6, 33 pixels +/// - 237..=268, row 7, 31 pixels -2 px from last +/// - 269..=301, row 8, 32 pixels +1 px from last +/// - 302..=332, row 9, 30 pixels -2 +/// - 333..=364, row 10, 31 pixels +1 +/// - 365..=394, row 11, 29 pixels -2 +/// - 395..=425, row 12, 30 pixels +1 +/// - 426..=454, row 13, 28 pixels -2 +/// - 455..=484, row 14, 29 pixels +1 +/// - 485..=512, row 15, 27 pixels -2 +/// - 513..=541, row 16, 28 pixels +1 +/// - 542..=568, row 17, 26 pixels -2 +/// - 569..=596, row 18, 27 pixels +1 +/// - 597..=622, row 19, 25 pixels -2 +/// - BEGIN NEXT BLOCK AT IDX627 (when writing out the one dimensional array) +/// - 623..=649, row 20, 26 pixels +1 +/// - .. 57 rows (from 0) +/// +/// Image is 33x56, and +/// +/// The formula below starts at row 7 +/// ``` +/// if current_row_idx != 0 && current_row_idx.mod(1) == 0 +/// then current_row_len = last_row_len + 1 +/// else current_row_len = last_row_len - 2, // offset left by half +/// ``` +/// +/// Data structure should be nested array of [[u8; 33]; 56] pub struct AniMeDbusWriter { connection: Box, block_time: u64, @@ -29,7 +71,7 @@ impl AniMeDbusWriter { }) } - pub fn write_image_to_buf(_buf: &mut [[u8; 640]; 2], _image_data: &[u8]) { + pub fn write_image_to_buf(_buf: &mut AniMePacketType, _image_data: &[u8]) { unimplemented!("Image format is in progress of being worked out") } @@ -44,12 +86,12 @@ impl AniMeDbusWriter { /// # Note: /// The vectors are expected to contain the full sequence of bytes as follows /// - /// - Write pane 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. - /// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. + /// - Write packet 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. + /// - Write packet 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. /// /// Where led brightness is 0..255, low to high #[inline] - pub fn write_image(&mut self, image: &mut [[u8; 640]; 2]) -> Result<(), Box> { + pub fn write_image(&mut self, image: &mut AniMePacketType) -> Result<(), Box> { if image[0][0] != ANIME_PANE1_PREFIX[0] && image[0][6] != ANIME_PANE1_PREFIX[6] { image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX); } diff --git a/aura/src/anime_matrix.rs b/aura/src/anime_matrix.rs new file mode 100644 index 00000000..6446d4c5 --- /dev/null +++ b/aura/src/anime_matrix.rs @@ -0,0 +1,86 @@ +pub const WIDTH: usize = 34; +pub const HEIGHT: usize = 56; +pub type AniMeBufferType = [[u8; WIDTH]; HEIGHT]; +pub type AniMePacketType = [[u8; 640]; 2]; +const BLOCK_START: usize = 7; +const BLOCK_END: usize = 634; + +pub struct AniMeMatrix(AniMeBufferType); + +impl AniMeMatrix { + pub fn new() -> Self { + AniMeMatrix([[0u8; WIDTH]; HEIGHT]) + } + + pub fn get(&self) -> &AniMeBufferType { + &self.0 + } + + pub fn get_mut(&mut self) -> &mut AniMeBufferType { + &mut self.0 + } + + pub fn fill_with(&mut self, fill: u8) { + for row in self.0.iter_mut() { + for x in row.iter_mut() { + *x = fill; + } + } + } +} + +impl From for AniMePacketType { + /// Do conversion from the nested Vec in AniMeMatrix to the two required + /// packets suitable for sending over USB + #[inline] + fn from(anime: AniMeMatrix) -> Self { + let mut buffers = [[0; 640]; 2]; + + let mut write_index = BLOCK_START; + let mut write_block = &mut buffers[0]; + let mut block1_done = false; + let mut phys_row_len = WIDTH - 1; // not taking in to account starting at 0 + + let mut total = 0; + for (count, row) in anime.0.iter().enumerate() { + // Write the top block of LEDs (first 7 rows) + if count <= 7 { + for x in row.iter() { + write_block[write_index] = *x; + write_index += 1; + total += 1; + } + println!("{:X?}", row.to_vec()); + } else { + if count == 7 { + phys_row_len -= 1; + } + // Switch to next block (looks like ) + if count % 2 != 0 { + phys_row_len -= 2; + } else { + phys_row_len += 1; + } + + let index = row.len() - phys_row_len; + for n in index..row.len() - 1 { + // Require a special case to catch the correct end-of-packet which is + // 6 bytes from the end + if write_index == BLOCK_END && !block1_done { + block1_done = true; + write_block = &mut buffers[1]; + write_index = BLOCK_START; + } + total += 1; + + //println!("{:?}", write_block.to_vec()); + write_block[write_index] = row[n]; + write_index += 1; + } + println!("{:X?}", row[index..].to_vec()); + } + } + dbg!(total); + buffers + } +} diff --git a/aura/src/lib.rs b/aura/src/lib.rs index 487b89cb..a74ce684 100644 --- a/aura/src/lib.rs +++ b/aura/src/lib.rs @@ -18,6 +18,9 @@ pub use fancy::*; mod animatrix_dbus; pub use animatrix_dbus::*; +mod anime_matrix; +pub use anime_matrix::*; + pub mod error; use crate::cli_options::*;