servicepoint-simulator/src/execute_command.rs

180 lines
5.6 KiB
Rust
Raw Normal View History

use std::sync::{RwLock, RwLockWriteGuard};
use log::{debug, error, info, warn};
use servicepoint2::{
2024-05-17 21:28:51 +02:00
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<PixelGrid>,
luma_ref: &RwLock<ByteGrid>,
) -> 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;
}
2024-05-16 23:26:57 +02:00
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();
2024-05-17 21:28:51 +02:00
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<PixelGrid>,
) {
let Origin(x, y) = origin;
let x = x as usize;
let y = y as usize;
2024-05-17 21:28:51 +02:00
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<PixelGrid>,
) {
debug!(
"printing {}x{} grid at {offset_x} {offset_y}",
2024-05-17 21:28:51 +02:00
pixels.width(),
pixels.height()
);
2024-05-17 21:28:51 +02:00
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,
)
}