From 9406eb3faa6efcb6d8ea9ecfcc629a47cf4d2a5f Mon Sep 17 00:00:00 2001 From: Annika Hannig Date: Mon, 26 Sep 2022 17:15:17 +0200 Subject: [PATCH] initial framebuffer --- airportdisplay/src/graphics.rs | 46 ++++++++++++++++++++++++++++++++-- airportdisplay/src/protocol.rs | 25 ++++++++++++------ 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/airportdisplay/src/graphics.rs b/airportdisplay/src/graphics.rs index 800c13a..b11daca 100644 --- a/airportdisplay/src/graphics.rs +++ b/airportdisplay/src/graphics.rs @@ -1,9 +1,51 @@ +use super::geometry::{COLUMNS, ROWS}; + +const FB_WIDTH: usize = COLUMNS * 8; +const FB_HEIGHT: usize = ROWS * 8; + pub enum Graphics { /// Raw is a series - Raw, + Raw(Raw), } /// Raw: Offset + Raw pixel content. /// Pixels content: series of byte-sized 8 pixel -/// horizontal blocks. highest bit is the top left pixel +/// horizontal blocks. highest bit is the top left pixel. pub struct Raw(pub u16, pub Vec); + +/// A framebuffer holds 8bit pixel data. +/// The value of each pixel encodes the luminance, +/// unfortunatley this can only be set per block - so the average +/// across 8 pixels is used. +/// +/// There are 56 segments and 20 rows, with 8x8 pixels per segment. +pub struct Framebuffer { + data: Vec, +} + +impl Framebuffer { + pub fn new() -> Self { + Self { + data: Vec::with_capacity(FB_WIDTH * FB_HEIGHT), + } + } + + /// Convert to pixel data. (Not convinced this is correct...) + pub fn into_bitmap(&self) -> Vec { + let mut bitmap = Vec::with_capacity(COLUMNS * ROWS); + for (i, v) in self.data.iter().enumerate() { + let offset = i / 8; + let pixel = i % 8; + let shift = 7 - pixel; + if *v > 0 { + bitmap[offset] |= 1 << shift + } else { + bitmap[offset] &= !(1 << shift) + } + } + bitmap + } + + // Convert to luminance map + // ... TODO +} diff --git a/airportdisplay/src/protocol.rs b/airportdisplay/src/protocol.rs index d187633..9f1d0fa 100644 --- a/airportdisplay/src/protocol.rs +++ b/airportdisplay/src/protocol.rs @@ -5,14 +5,14 @@ use codepage_437::{ToCp437, CP437_WINGDINGS}; use super::{ commands::Command, geometry::{Origin, Size, Window, COLUMNS, ROWS}, - graphics::Raw as GraphicsRaw, + graphics::{Graphics, Raw as GraphicsRaw}, luminance::Luminance, text::{Buffer as TextBuffer, Raw as TextRaw, Text}, }; -const CMD_RAW_TEXT: &'static [u8] = &[0x00, 0x03]; -const CMD_RAW_LUM: &'static [u8] = &[0x00, 0x05]; -const CMD_RAW_GFX: &'static [u8] = &[0x00, 0x12]; +const CMD_TEXT_RAW: &'static [u8] = &[0x00, 0x03]; +const CMD_LUM_RAW: &'static [u8] = &[0x00, 0x05]; +const CMD_GFX_RAW: &'static [u8] = &[0x00, 0x12]; /// A frame holds a single encoded display command, /// like set text at pos x, y. @@ -51,7 +51,7 @@ impl From for Data { fn from(raw: GraphicsRaw) -> Self { let GraphicsRaw(offset, data) = raw; vec![[ - CMD_RAW_GFX.into(), + CMD_GFX_RAW.into(), encode_u16(offset), encode_u16(data.len() as u16), encode_u16(0), @@ -68,7 +68,7 @@ impl From for Data { let mut bytes = bytes.clone(); bytes.truncate(COLUMNS); let size = Size(bytes.len() as u16, 1); - vec![[CMD_RAW_TEXT.into(), origin.into(), size.into(), bytes].concat()] + vec![[CMD_TEXT_RAW.into(), origin.into(), size.into(), bytes].concat()] } } @@ -76,7 +76,7 @@ impl From for Data { impl From for Data { fn from(luminance: Luminance) -> Data { let Luminance(window, value) = luminance; - vec![[CMD_RAW_LUM.into(), Vec::from(window), encode_u16(value)].concat()] + vec![[CMD_LUM_RAW.into(), Vec::from(window), encode_u16(value)].concat()] } } @@ -98,7 +98,7 @@ impl From for Data { let size = Size(len, 1); data.push( [ - Frame::from(CMD_RAW_TEXT), + Frame::from(CMD_TEXT_RAW), pos.into(), size.into(), bytes.into(), @@ -121,6 +121,14 @@ impl From for Data { } } +impl From for Data { + fn from(gfx: Graphics) -> Data { + match gfx { + Graphics::Raw(raw) => raw.into(), + } + } +} + /// Encode command impl From for Data { fn from(cmd: Command) -> Self { @@ -131,6 +139,7 @@ impl From for Data { Command::Fadeout => vec![vec![0x00, 0x0d]], Command::Text(text) => text.into(), Command::Luminance(lum) => lum.into(), + Command::Graphics(gfx) => gfx.into(), } } }