use std::sync::{RwLock, RwLockWriteGuard}; use log::{debug, error, info, warn}; use servicepoint2::{ ByteGrid, Command, Origin, PixelGrid, PIXEL_COUNT, PIXEL_WIDTH, 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, ) }