diff --git a/src/execute_command.rs b/src/execute_command.rs new file mode 100644 index 0000000..d34e14f --- /dev/null +++ b/src/execute_command.rs @@ -0,0 +1,178 @@ +use std::sync::{RwLock, RwLockWriteGuard}; + +use log::{debug, error, info, warn}; +use servicepoint2::{ + ByteGrid, Command, Origin, PIXEL_COUNT, PIXEL_WIDTH, PixelGrid, TILE_SIZE, +}; + +use crate::font::BitmapFont; + +pub(crate) fn execute_command( + command: Command, + font: &BitmapFont, + display_ref: &RwLock, + luma_ref: &RwLock, +) -> bool { + debug!("received {command:?}"); + match command { + Command::Clear => { + info!("clearing display"); + display_ref.write().unwrap().fill(false); + } + Command::HardReset => { + warn!("display shutting down"); + return false; + } + Command::BitmapLinearWin(Origin(x, y), pixels) => { + let mut display = display_ref.write().unwrap(); + print_pixel_grid(x as usize, y as usize, &pixels, &mut display); + } + Command::Cp437Data(origin, grid) => { + let mut display = display_ref.write().unwrap(); + print_cp437_data(origin, &grid, font, &mut display); + } + #[allow(deprecated)] + Command::BitmapLegacy => { + warn!("ignoring deprecated command {:?}", command); + } + // TODO: how to deduplicate this code in a rusty way? + Command::BitmapLinear(offset, vec, _) => { + if !check_bitmap_valid(offset, vec.len()) { + return true; + } + let mut display = display_ref.write().unwrap(); + for bitmap_index in 0..vec.len() { + let (x, y) = + get_coordinates_for_index(offset as usize, bitmap_index); + display.set(x, y, vec.get(bitmap_index)); + } + } + Command::BitmapLinearAnd(offset, vec, _) => { + if !check_bitmap_valid(offset, vec.len()) { + return true; + } + let mut display = display_ref.write().unwrap(); + for bitmap_index in 0..vec.len() { + let (x, y) = + get_coordinates_for_index(offset as usize, bitmap_index); + let old_value = display.get(x, y); + display.set(x, y, old_value && vec.get(bitmap_index)); + } + } + Command::BitmapLinearOr(offset, vec, _) => { + if !check_bitmap_valid(offset, vec.len()) { + return true; + } + let mut display = display_ref.write().unwrap(); + for bitmap_index in 0..vec.len() { + let (x, y) = + get_coordinates_for_index(offset as usize, bitmap_index); + let old_value = display.get(x, y); + display.set(x, y, old_value || vec.get(bitmap_index)); + } + } + Command::BitmapLinearXor(offset, vec, _) => { + if !check_bitmap_valid(offset, vec.len()) { + return true; + } + let mut display = display_ref.write().unwrap(); + for bitmap_index in 0..vec.len() { + let (x, y) = + get_coordinates_for_index(offset as usize, bitmap_index); + let old_value = display.get(x, y); + display.set(x, y, old_value ^ vec.get(bitmap_index)); + } + } + Command::CharBrightness(origin, grid) => { + let Origin(offset_x, offset_y) = origin; + let offset_x = offset_x as usize; + let offset_y = offset_y as usize; + + let mut luma = luma_ref.write().unwrap(); + for inner_y in 0..grid.height { + for inner_x in 0..grid.width { + let brightness = grid.get(inner_x, inner_y); + luma.set( + offset_x + inner_x, + offset_y + inner_y, + brightness, + ); + } + } + } + Command::Brightness(brightness) => { + luma_ref.write().unwrap().fill(brightness); + } + Command::FadeOut => { + error!("command not implemented: {command:?}") + } + }; + + true +} + +fn check_bitmap_valid(offset: u16, payload_len: usize) -> bool { + if offset as usize + payload_len > PIXEL_COUNT { + error!( + "bitmap with offset {offset} is too big ({} bytes)", + payload_len + ); + return false; + } + + true +} + +fn print_cp437_data( + origin: Origin, + grid: &ByteGrid, + font: &BitmapFont, + display: &mut RwLockWriteGuard, +) { + let Origin(x, y) = origin; + let x = x as usize; + let y = y as usize; + + for char_y in 0usize..grid.height { + for char_x in 0usize..grid.width { + let char_code = grid.get(char_x, char_y); + + let tile_x = char_x + x; + let tile_y = char_y + y; + + let bitmap = font.get_bitmap(char_code); + print_pixel_grid( + tile_x * TILE_SIZE as usize, + tile_y * TILE_SIZE as usize, + bitmap, + display, + ); + } + } +} + +fn print_pixel_grid( + offset_x: usize, + offset_y: usize, + pixels: &PixelGrid, + display: &mut RwLockWriteGuard, +) { + debug!( + "printing {}x{} grid at {offset_x} {offset_y}", + pixels.width, pixels.height + ); + for inner_y in 0..pixels.height { + for inner_x in 0..pixels.width { + let is_set = pixels.get(inner_x, inner_y); + display.set(offset_x + inner_x, offset_y + inner_y, is_set); + } + } +} + +fn get_coordinates_for_index(offset: usize, index: usize) -> (usize, usize) { + let pixel_index = offset + index; + ( + pixel_index % PIXEL_WIDTH as usize, + pixel_index / PIXEL_WIDTH as usize, + ) +} diff --git a/src/font.rs b/src/font.rs index 953bce5..3a0c9b9 100644 --- a/src/font.rs +++ b/src/font.rs @@ -50,7 +50,7 @@ impl BitmapFont { } } - return BitmapFont { bitmaps }; + BitmapFont { bitmaps } } pub fn get_bitmap(&self, char_code: u8) -> &PixelGrid { diff --git a/src/main.rs b/src/main.rs index 274d60f..9442fc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,20 +2,22 @@ use std::io::ErrorKind; use std::net::UdpSocket; -use std::sync::{mpsc, RwLock, RwLockWriteGuard}; +use std::sync::{mpsc, RwLock}; use std::time::Duration; use clap::Parser; -use log::{debug, error, info, warn}; +use log::{info, warn}; use servicepoint2::{ - ByteGrid, Command, Origin, Packet, PIXEL_COUNT, PIXEL_HEIGHT, PIXEL_WIDTH, - PixelGrid, TILE_HEIGHT, TILE_SIZE, TILE_WIDTH, + ByteGrid, Command, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid, TILE_HEIGHT, + TILE_WIDTH, }; use winit::event_loop::{ControlFlow, EventLoop}; +use crate::execute_command::execute_command; use crate::font::BitmapFont; use crate::gui::{App, AppEvents}; +mod execute_command; mod font; mod gui; @@ -86,7 +88,15 @@ fn main() { let vec = buf[..amount].to_vec(); let package = servicepoint2::Packet::from(vec); - if !handle_package(package, &font, display_ref, luma_ref) { + let command = match Command::try_from(package) { + Err(err) => { + warn!("could not read command for packet: {:?}", err); + continue; + } + Ok(val) => val, + }; + + if !execute_command(command, &font, display_ref, luma_ref) { // hard reset event_proxy .send_event(AppEvents::UdpThreadClosed) @@ -107,181 +117,3 @@ fn main() { udp_thread.join().expect("could not join udp thread"); }); } - -fn handle_package( - received: Packet, - font: &BitmapFont, - display_ref: &RwLock, - luma_ref: &RwLock, -) -> bool { - let command = match Command::try_from(received) { - Err(err) => { - warn!("could not read command for packet: {:?}", err); - return true; - } - Ok(val) => val, - }; - - debug!("received {command:?}"); - match command { - Command::Clear => { - info!("clearing display"); - display_ref.write().unwrap().fill(false); - } - Command::HardReset => { - warn!("display shutting down"); - return false; - } - Command::BitmapLinearWin(Origin(x, y), pixels) => { - let mut display = display_ref.write().unwrap(); - print_pixel_grid(x as usize, y as usize, &pixels, &mut display); - } - Command::Cp437Data(origin, grid) => { - let mut display = display_ref.write().unwrap(); - print_cp437_data(origin, &grid, font, &mut display); - } - #[allow(deprecated)] - Command::BitmapLegacy => { - warn!("ignoring deprecated command {:?}", command); - } - // TODO: how to deduplicate this code in a rusty way? - Command::BitmapLinear(offset, vec, _) => { - if !check_bitmap_valid(offset, vec.len()) { - return true; - } - let mut display = display_ref.write().unwrap(); - for bitmap_index in 0..vec.len() { - let (x, y) = - get_coordinates_for_index(offset as usize, bitmap_index); - display.set(x, y, vec.get(bitmap_index)); - } - } - Command::BitmapLinearAnd(offset, vec, _) => { - if !check_bitmap_valid(offset, vec.len()) { - return true; - } - let mut display = display_ref.write().unwrap(); - for bitmap_index in 0..vec.len() { - let (x, y) = - get_coordinates_for_index(offset as usize, bitmap_index); - let old_value = display.get(x, y); - display.set(x, y, old_value && vec.get(bitmap_index)); - } - } - Command::BitmapLinearOr(offset, vec, _) => { - if !check_bitmap_valid(offset, vec.len()) { - return true; - } - let mut display = display_ref.write().unwrap(); - for bitmap_index in 0..vec.len() { - let (x, y) = - get_coordinates_for_index(offset as usize, bitmap_index); - let old_value = display.get(x, y); - display.set(x, y, old_value || vec.get(bitmap_index)); - } - } - Command::BitmapLinearXor(offset, vec, _) => { - if !check_bitmap_valid(offset, vec.len()) { - return true; - } - let mut display = display_ref.write().unwrap(); - for bitmap_index in 0..vec.len() { - let (x, y) = - get_coordinates_for_index(offset as usize, bitmap_index); - let old_value = display.get(x, y); - display.set(x, y, old_value ^ vec.get(bitmap_index)); - } - } - Command::CharBrightness(origin, grid) => { - let Origin(offset_x, offset_y) = origin; - let offset_x = offset_x as usize; - let offset_y = offset_y as usize; - - let mut luma = luma_ref.write().unwrap(); - for inner_y in 0..grid.height { - for inner_x in 0..grid.width { - let brightness = grid.get(inner_x, inner_y); - luma.set( - offset_x + inner_x, - offset_y + inner_y, - brightness, - ); - } - } - } - Command::Brightness(brightness) => { - luma_ref.write().unwrap().fill(brightness); - } - Command::FadeOut => { - error!("command not implemented: {command:?}") - } - }; - - true -} - -fn check_bitmap_valid(offset: u16, payload_len: usize) -> bool { - if offset as usize + payload_len > PIXEL_COUNT { - error!( - "bitmap with offset {offset} is too big ({} bytes)", - payload_len - ); - return false; - } - - true -} - -fn print_cp437_data( - origin: Origin, - grid: &ByteGrid, - font: &BitmapFont, - display: &mut RwLockWriteGuard, -) { - let Origin(x, y) = origin; - let x = x as usize; - let y = y as usize; - - for char_y in 0usize..grid.height { - for char_x in 0usize..grid.width { - let char_code = grid.get(char_x, char_y); - - let tile_x = char_x + x; - let tile_y = char_y + y; - - let bitmap = font.get_bitmap(char_code); - print_pixel_grid( - tile_x * TILE_SIZE as usize, - tile_y * TILE_SIZE as usize, - bitmap, - display, - ); - } - } -} - -fn print_pixel_grid( - offset_x: usize, - offset_y: usize, - pixels: &PixelGrid, - display: &mut RwLockWriteGuard, -) { - debug!( - "printing {}x{} grid at {offset_x} {offset_y}", - pixels.width, pixels.height - ); - for inner_y in 0..pixels.height { - for inner_x in 0..pixels.width { - let is_set = pixels.get(inner_x, inner_y); - display.set(offset_x + inner_x, offset_y + inner_y, is_set); - } - } -} - -fn get_coordinates_for_index(offset: usize, index: usize) -> (usize, usize) { - let pixel_index = offset + index; - ( - pixel_index % PIXEL_WIDTH as usize, - pixel_index / PIXEL_WIDTH as usize, - ) -}