move command execution code to own file
This commit is contained in:
		
							parent
							
								
									9f5d256963
								
							
						
					
					
						commit
						69502ac3fb
					
				
					 3 changed files with 194 additions and 184 deletions
				
			
		
							
								
								
									
										178
									
								
								src/execute_command.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/execute_command.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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<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;
 | 
			
		||||
        }
 | 
			
		||||
        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<PixelGrid>,
 | 
			
		||||
) {
 | 
			
		||||
    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<PixelGrid>,
 | 
			
		||||
) {
 | 
			
		||||
    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,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ impl BitmapFont {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return BitmapFont { bitmaps };
 | 
			
		||||
        BitmapFont { bitmaps }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_bitmap(&self, char_code: u8) -> &PixelGrid {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										198
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										198
									
								
								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<PixelGrid>,
 | 
			
		||||
    luma_ref: &RwLock<ByteGrid>,
 | 
			
		||||
) -> 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<PixelGrid>,
 | 
			
		||||
) {
 | 
			
		||||
    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<PixelGrid>,
 | 
			
		||||
) {
 | 
			
		||||
    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,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue