diff --git a/firmware/rust/src/assets.rs b/firmware/rust/src/assets.rs new file mode 100644 index 0000000..9892e41 --- /dev/null +++ b/firmware/rust/src/assets.rs @@ -0,0 +1,258 @@ +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +pub const SACRED_CHAO: [[u8; 40]; 5] = [ + [ + 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFC, + 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + ], + [ + 0x80, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x03, 0xC3, + 0xE3, 0x73, 0x37, 0x17, 0x07, 0x0F, 0x1E, 0x3C, 0xF0, 0x80, + ], + [ + 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0x30, 0x00, 0x00, 0xFF, + ], + [ + 0x01, 0x0F, 0x3F, 0x4F, 0x9F, 0x3F, 0x3E, 0x3C, 0x7C, 0x7C, 0x7C, 0x7C, 0x3E, 0x3E, 0x3E, + 0x1F, 0x1F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x81, 0x40, 0x30, 0x0E, 0x01, + ], + [ + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, + 0x10, 0x08, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + ], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +pub const ONDERS_ORG: [[u8; 48]; 2] = [ + [ + 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xF8, 0x00, 0x00, + 0xE0, 0xA0, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0xA0, 0xA0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, + 0xE0, 0x60, 0xE0, + ], + [ + 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, + 0x03, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x0A, 0x0F, + ], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_0: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x0C, 0xFC, 0xF8], + &[0x1F, 0x3F, 0x30, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_1: [&[u8]; 2] = [ + &[0x30, 0x30, 0xFC, 0xFC, 0x00], + &[0x30, 0x30, 0x3F, 0x3F, 0x30], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_2: [&[u8]; 2] = [ + &[0x18, 0x1C, 0x8C, 0xFC, 0xF8], + &[0x38, 0x3E, 0x3F, 0x33, 0x30], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_3: [&[u8]; 2] = [ + &[0x18, 0x9C, 0x8C, 0xFC, 0x78], + &[0x18, 0x39, 0x31, 0x3F, 0x1E], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_4: [&[u8]; 2] = [ + &[0x80, 0xE0, 0x78, 0xFC, 0xFC], + &[0x07, 0x07, 0x06, 0x3F, 0x3F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_5: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x8C, 0x8C, 0x0C], + &[0x1C, 0x3D, 0x31, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_6: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x8C, 0xBC, 0x38], + &[0x1F, 0x3F, 0x31, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_7: [&[u8]; 2] = [ + &[0x0C, 0x0C, 0xEC, 0xFC, 0x1C], + &[0x00, 0x3E, 0x3F, 0x01, 0x00], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_8: [&[u8]; 2] = [ + &[0x78, 0xFC, 0x8C, 0xFC, 0x78], + &[0x1E, 0x3F, 0x31, 0x3F, 0x1E], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_9: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x8C, 0xFC, 0xF8], + &[0x1C, 0x3D, 0x31, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_COLON: [&[u8]; 2] = [&[0x30, 0x30], &[0x0C, 0x0C]]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_A: [&[u8]; 2] = [ + &[0xC0, 0xF0, 0x3C, 0x3C, 0xF0, 0xC0], + &[0x3F, 0x3F, 0x06, 0x06, 0x3F, 0x3F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_B: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0x78], + &[0x3F, 0x3F, 0x31, 0x31, 0x3F, 0x1E], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_C: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x0C, 0x1C, 0x18], + &[0x1F, 0x3F, 0x30, 0x38, 0x18], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_E: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x8C, 0x8C, 0x0C, 0x0C], + &[0x3F, 0x3F, 0x31, 0x31, 0x30, 0x30], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_G: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x0C, 0x0C, 0x3C, 0x38], + &[0x1F, 0x3F, 0x30, 0x33, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_H: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x80, 0x80, 0xFC, 0xFC], + &[0x3F, 0x3F, 0x01, 0x01, 0x3F, 0x3F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_I: [&[u8]; 2] = [&[0x0C, 0xFC, 0xFC, 0x0C], &[0x30, 0x3F, 0x3F, 0x30]]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_K: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0xC0, 0xF0, 0x7C, 0x1C], + &[0x3F, 0x3F, 0x03, 0x0F, 0x3E, 0x38], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_L: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x00, 0x00, 0x00], + &[0x3F, 0x3F, 0x30, 0x30, 0x30], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_N: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0xF0, 0xC0, 0x00, 0xFC, 0xFC], + &[0x3F, 0x3F, 0x00, 0x03, 0x0F, 0x3F, 0x3F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_O: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x0C, 0x0C, 0xFC, 0xF8], + &[0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_P: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8], + &[0x3F, 0x3F, 0x01, 0x01, 0x01, 0x00], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_R: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8], + &[0x3F, 0x3F, 0x01, 0x03, 0x3F, 0x3E], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_S: [&[u8]; 2] = [ + &[0xF8, 0xFC, 0x8C, 0x8C, 0x9C, 0x18], + &[0x18, 0x39, 0x31, 0x31, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_T: [&[u8]; 2] = [ + &[0x0C, 0x0C, 0xFC, 0xFC, 0x0C, 0x0C], + &[0x00, 0x00, 0x3F, 0x3F, 0x00, 0x00], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_U: [&[u8]; 2] = [ + &[0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC], + &[0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_INVALID: [&[u8]; 2] = [ + &[0x80, 0xE0, 0x98, 0xCC, 0x4C, 0x18, 0xE0, 0x80], + &[0x01, 0x07, 0x1F, 0x24, 0x25, 0x1F, 0x07, 0x01], +]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +pub const SYMBOL_TABLE: [&[&[u8]; 2]; 48] = [ + &SYM_0, // '0' + &SYM_1, // '1' + &SYM_2, // '2' + &SYM_3, // '3' + &SYM_4, // '4' + &SYM_5, // '5' + &SYM_6, // '6' + &SYM_7, // '7' + &SYM_8, // '8' + &SYM_9, // '9' + &SYM_COLON, // ':' + &SYM_INVALID, // ';' + &SYM_INVALID, // '<' + &SYM_INVALID, // '=' + &SYM_INVALID, // '>' + &SYM_INVALID, // '?' + &SYM_INVALID, // '@' + &SYM_A, // 'A' + &SYM_B, // 'B' + &SYM_C, // 'C' + &SYM_INVALID, // 'D' + &SYM_E, // 'E' + &SYM_INVALID, // 'F' + &SYM_G, // 'G' + &SYM_H, // 'H' + &SYM_I, // 'I' + &SYM_INVALID, // 'J' + &SYM_K, // 'K' + &SYM_L, // 'L' + &SYM_INVALID, // 'M' + &SYM_N, // 'N' + &SYM_O, // 'O' + &SYM_P, // 'P' + &SYM_INVALID, // 'Q' + &SYM_R, // 'R' + &SYM_S, // 'S' + &SYM_T, // 'T' + &SYM_U, // 'U' + &SYM_INVALID, // 'V' + &SYM_INVALID, // 'W' + &SYM_INVALID, // 'X' + &SYM_INVALID, // 'Y' + &SYM_INVALID, // 'Z' + &SYM_INVALID, // '[' + &SYM_INVALID, // '\' + &SYM_INVALID, // ']' + &SYM_INVALID, // '^' + &SYM_INVALID, // '_' +]; diff --git a/firmware/rust/src/lcd.rs b/firmware/rust/src/lcd.rs new file mode 100644 index 0000000..9ac6564 --- /dev/null +++ b/firmware/rust/src/lcd.rs @@ -0,0 +1,181 @@ +use atmega_hal::{ + clock::MHz8, + delay::Delay, + port::{mode::Output, Pin, PB0, PB1}, + Spi, +}; +use avr_device::interrupt; +use embedded_hal::{blocking::delay::DelayMs, spi::FullDuplex}; +use nb::block; + +use crate::{ + assets::SYMBOL_TABLE, + screen::{Screen, Screens}, +}; + +// TODO: Make `cd` and `rst` pins generic pins +pub struct Lcd { + pub spi: Spi, + pub cd: Pin, + rst: Pin, +} + +impl Lcd { + pub fn new(spi: Spi, cd: Pin, rst: Pin) -> Self { + Self { spi, cd, rst } + } + + pub fn init(&mut self, contrast: u8) { + let mut delay = Delay::::new(); + + // TODO: Test if delay is really needed + delay.delay_ms(1_u8); + self.rst.set_high(); + // TODO: Try to reduce delay to a minimum + delay.delay_ms(1_u8); + + block!(self.spi.send(0x40)).unwrap(); // (6) Set Scroll Line: Display start line 0 + block!(self.spi.send(0xA1)).unwrap(); // (13) Set SEG direction: SEG reverse + block!(self.spi.send(0xC0)).unwrap(); // (14) Set COM direction: Normal COM0 - COM63 + // block!(spi.send(0xA4)).unwrap(); // (10) Set All Pixel On: Disable -> Set All Pixel to ON */ + block!(self.spi.send(0xA6)).unwrap(); // (11) Set Inverse Display: Display inverse off + block!(self.spi.send(0xA2)).unwrap(); // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65) + block!(self.spi.send(0x2F)).unwrap(); // (5) Set Power Control: Booster, Regulator and Follower on + block!(self.spi.send(0x27)).unwrap(); // (8) Set VLCD Resistor Ratio: Set Contrast + // block!(spi.send(0xEE)).unwrap(); // (18) Reset Cursor Update Mode + block!(self.spi.send(0x81)).unwrap(); // (9) Set Electronic Volume: Set Contrast + block!(self.spi.send(contrast)).unwrap(); // (9) Set Electronic Volume: Set Contrast + // block!(spi.send(0xFA)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C + // block!(spi.send(0x90)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C + block!(self.spi.send(0xAF)).unwrap(); // (12) Set Display Enable: Display on + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + } + + pub fn move_cursor(&mut self, segment: u8, page: u8) { + assert!(segment < 102); + assert!(page < 8); + + block!(self.spi.send(0x0F & segment)).unwrap(); + block!(self.spi.send(0x10 + (segment >> 4))).unwrap(); + block!(self.spi.send(0xB0 + page)).unwrap(); + } + + fn clear(&mut self) { + let mut delay = Delay::::new(); + + for page in 0..8 { + self.move_cursor(0, page as u8); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_high(); + + for _ in 0..102 { + block!(self.spi.send(0x00)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } + } + + fn fill(&mut self, segment: u8, page: u8, width: u8, data: u8) { + assert!(segment + width <= 102); + let mut delay = Delay::::new(); + + self.move_cursor(segment, page); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_high(); + + for _ in 0..width { + block!(self.spi.send(data)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } + + pub fn fill_area(&mut self, segment: u8, page: u8, width: u8, height: u8, data: u8) { + assert!(page + height <= 8); + + for i in 0..height { + self.fill(segment, page + i, width, data); + } + } + + pub fn print(&mut self, segment: u8, page: u8, string: &str) { + let mut delay = Delay::::new(); + + for i in 0..2 { + self.move_cursor(segment, page + i); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_high(); + + block!(self.spi.send(0x00)).unwrap(); + block!(self.spi.send(0x00)).unwrap(); + for c in string.chars() { + for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { + block!(self.spi.send(*segment)).unwrap(); + } + block!(self.spi.send(0x00)).unwrap(); + } + block!(self.spi.send(0x00)).unwrap(); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } + } + + pub fn print_inverted(&mut self, segment: u8, page: u8, string: &str) { + let mut delay = Delay::::new(); + + for i in 0..2 { + self.move_cursor(segment, page + i); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_high(); + + block!(self.spi.send(0xFF)).unwrap(); + block!(self.spi.send(0xFF)).unwrap(); + for c in string.chars() { + for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { + block!(self.spi.send(!*segment)).unwrap(); + } + block!(self.spi.send(0xFF)).unwrap(); + } + block!(self.spi.send(0xFF)).unwrap(); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } + } + + pub fn draw(&mut self, screen: &Screens) { + interrupt::free(|_cs| { + self.clear(); + + match screen { + Screens::Splash(splash) => { + splash.draw(self); + } + Screens::Home(home) => { + home.draw(self); + } + Screens::Setup(setup) => { + setup.draw(self); + } + } + }); + } +} diff --git a/firmware/rust/src/main.rs b/firmware/rust/src/main.rs index dcbae03..cffdd0f 100644 --- a/firmware/rust/src/main.rs +++ b/firmware/rust/src/main.rs @@ -6,7 +6,6 @@ use atmega_hal::{ clock::MHz8, delay::Delay, pins, - port::{mode::Output, Pin, PB0, PB1}, spi::{DataOrder, SerialClockRate, Settings, Spi}, Peripherals, }; @@ -15,662 +14,31 @@ use avr_eeprom::{eeprom, Eeprom}; use core::sync::atomic::{AtomicBool, Ordering}; use embedded_hal::{ blocking::delay::DelayMs, - spi::{FullDuplex, Mode, Phase, Polarity}, + spi::{Mode, Phase, Polarity}, }; -use nb::block; use panic_halt as _; +mod assets; +mod lcd; mod rotary; +mod screen; + +use lcd::Lcd; use rotary::{Direction, Rotary}; +use screen::Screens; eeprom! { static eeprom CONTRAST: u8 = 8; static eeprom BACKLIGHT: u8 = 1; } -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SACRED_CHAO: [[u8; 40]; 5] = [ - [ - 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFC, - 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x80, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x03, 0xC3, - 0xE3, 0x73, 0x37, 0x17, 0x07, 0x0F, 0x1E, 0x3C, 0xF0, 0x80, - ], - [ - 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0x30, 0x00, 0x00, 0xFF, - ], - [ - 0x01, 0x0F, 0x3F, 0x4F, 0x9F, 0x3F, 0x3E, 0x3C, 0x7C, 0x7C, 0x7C, 0x7C, 0x3E, 0x3E, 0x3E, - 0x1F, 0x1F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x81, 0x40, 0x30, 0x0E, 0x01, - ], - [ - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, - 0x10, 0x08, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, - ], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const ONDERS_ORG: [[u8; 48]; 2] = [ - [ - 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xF8, 0x00, 0x00, - 0xE0, 0xA0, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0xA0, 0xA0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, 0xE0, 0x60, 0xE0, 0x00, 0x00, - 0xE0, 0x60, 0xE0, - ], - [ - 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, - 0x03, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x0B, 0x0A, 0x0F, - ], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_0: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x0C, 0xFC, 0xF8], - &[0x1F, 0x3F, 0x30, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_1: [&[u8]; 2] = [ - &[0x30, 0x30, 0xFC, 0xFC, 0x00], - &[0x30, 0x30, 0x3F, 0x3F, 0x30], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_2: [&[u8]; 2] = [ - &[0x18, 0x1C, 0x8C, 0xFC, 0xF8], - &[0x38, 0x3E, 0x3F, 0x33, 0x30], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_3: [&[u8]; 2] = [ - &[0x18, 0x9C, 0x8C, 0xFC, 0x78], - &[0x18, 0x39, 0x31, 0x3F, 0x1E], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_4: [&[u8]; 2] = [ - &[0x80, 0xE0, 0x78, 0xFC, 0xFC], - &[0x07, 0x07, 0x06, 0x3F, 0x3F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_5: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x8C, 0x8C, 0x0C], - &[0x1C, 0x3D, 0x31, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_6: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x8C, 0xBC, 0x38], - &[0x1F, 0x3F, 0x31, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_7: [&[u8]; 2] = [ - &[0x0C, 0x0C, 0xEC, 0xFC, 0x1C], - &[0x00, 0x3E, 0x3F, 0x01, 0x00], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_8: [&[u8]; 2] = [ - &[0x78, 0xFC, 0x8C, 0xFC, 0x78], - &[0x1E, 0x3F, 0x31, 0x3F, 0x1E], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_9: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x8C, 0xFC, 0xF8], - &[0x1C, 0x3D, 0x31, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_COLON: [&[u8]; 2] = [&[0x30, 0x30], &[0x0C, 0x0C]]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_A: [&[u8]; 2] = [ - &[0xC0, 0xF0, 0x3C, 0x3C, 0xF0, 0xC0], - &[0x3F, 0x3F, 0x06, 0x06, 0x3F, 0x3F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_B: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0x78], - &[0x3F, 0x3F, 0x31, 0x31, 0x3F, 0x1E], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_C: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x0C, 0x1C, 0x18], - &[0x1F, 0x3F, 0x30, 0x38, 0x18], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_E: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x8C, 0x8C, 0x0C, 0x0C], - &[0x3F, 0x3F, 0x31, 0x31, 0x30, 0x30], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_G: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x0C, 0x0C, 0x3C, 0x38], - &[0x1F, 0x3F, 0x30, 0x33, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_H: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x80, 0x80, 0xFC, 0xFC], - &[0x3F, 0x3F, 0x01, 0x01, 0x3F, 0x3F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_I: [&[u8]; 2] = [&[0x0C, 0xFC, 0xFC, 0x0C], &[0x30, 0x3F, 0x3F, 0x30]]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_K: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0xC0, 0xF0, 0x7C, 0x1C], - &[0x3F, 0x3F, 0x03, 0x0F, 0x3E, 0x38], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_L: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x00, 0x00, 0x00], - &[0x3F, 0x3F, 0x30, 0x30, 0x30], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_N: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0xF0, 0xC0, 0x00, 0xFC, 0xFC], - &[0x3F, 0x3F, 0x00, 0x03, 0x0F, 0x3F, 0x3F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_O: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x0C, 0x0C, 0xFC, 0xF8], - &[0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_P: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8], - &[0x3F, 0x3F, 0x01, 0x01, 0x01, 0x00], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_R: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x8C, 0x8C, 0xFC, 0xF8], - &[0x3F, 0x3F, 0x01, 0x03, 0x3F, 0x3E], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_S: [&[u8]; 2] = [ - &[0xF8, 0xFC, 0x8C, 0x8C, 0x9C, 0x18], - &[0x18, 0x39, 0x31, 0x31, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_T: [&[u8]; 2] = [ - &[0x0C, 0x0C, 0xFC, 0xFC, 0x0C, 0x0C], - &[0x00, 0x00, 0x3F, 0x3F, 0x00, 0x00], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_U: [&[u8]; 2] = [ - &[0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC], - &[0x1F, 0x3F, 0x30, 0x30, 0x3F, 0x1F], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYM_INVALID: [&[u8]; 2] = [ - &[0x80, 0xE0, 0x98, 0xCC, 0x4C, 0x18, 0xE0, 0x80], - &[0x01, 0x07, 0x1F, 0x24, 0x25, 0x1F, 0x07, 0x01], -]; - -// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -const SYMBOL_TABLE: [&[&[u8]; 2]; 48] = [ - &SYM_0, // '0' - &SYM_1, // '1' - &SYM_2, // '2' - &SYM_3, // '3' - &SYM_4, // '4' - &SYM_5, // '5' - &SYM_6, // '6' - &SYM_7, // '7' - &SYM_8, // '8' - &SYM_9, // '9' - &SYM_COLON, // ':' - &SYM_INVALID, // ';' - &SYM_INVALID, // '<' - &SYM_INVALID, // '=' - &SYM_INVALID, // '>' - &SYM_INVALID, // '?' - &SYM_INVALID, // '@' - &SYM_A, // 'A' - &SYM_B, // 'B' - &SYM_C, // 'C' - &SYM_INVALID, // 'D' - &SYM_E, // 'E' - &SYM_INVALID, // 'F' - &SYM_G, // 'G' - &SYM_H, // 'H' - &SYM_I, // 'I' - &SYM_INVALID, // 'J' - &SYM_K, // 'K' - &SYM_L, // 'L' - &SYM_INVALID, // 'M' - &SYM_N, // 'N' - &SYM_O, // 'O' - &SYM_P, // 'P' - &SYM_INVALID, // 'Q' - &SYM_R, // 'R' - &SYM_S, // 'S' - &SYM_T, // 'T' - &SYM_U, // 'U' - &SYM_INVALID, // 'V' - &SYM_INVALID, // 'W' - &SYM_INVALID, // 'X' - &SYM_INVALID, // 'Y' - &SYM_INVALID, // 'Z' - &SYM_INVALID, // '[' - &SYM_INVALID, // '\' - &SYM_INVALID, // ']' - &SYM_INVALID, // '^' - &SYM_INVALID, // '_' -]; - -pub struct Lcd { - spi: Spi, - cd: Pin, - rst: Pin, -} - -impl Lcd { - fn init(&mut self, contrast: u8) { - let mut delay = Delay::::new(); - - // TODO: Test if delay is really needed - delay.delay_ms(1_u8); - self.rst.set_high(); - // TODO: Try to reduce delay to a minimum - delay.delay_ms(1_u8); - - block!(self.spi.send(0x40)).unwrap(); // (6) Set Scroll Line: Display start line 0 - block!(self.spi.send(0xA1)).unwrap(); // (13) Set SEG direction: SEG reverse - block!(self.spi.send(0xC0)).unwrap(); // (14) Set COM direction: Normal COM0 - COM63 - // block!(spi.send(0xA4)).unwrap(); // (10) Set All Pixel On: Disable -> Set All Pixel to ON */ - block!(self.spi.send(0xA6)).unwrap(); // (11) Set Inverse Display: Display inverse off - block!(self.spi.send(0xA2)).unwrap(); // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65) - block!(self.spi.send(0x2F)).unwrap(); // (5) Set Power Control: Booster, Regulator and Follower on - block!(self.spi.send(0x27)).unwrap(); // (8) Set VLCD Resistor Ratio: Set Contrast - // block!(spi.send(0xEE)).unwrap(); // (18) Reset Cursor Update Mode - block!(self.spi.send(0x81)).unwrap(); // (9) Set Electronic Volume: Set Contrast - block!(self.spi.send(contrast)).unwrap(); // (9) Set Electronic Volume: Set Contrast - // block!(spi.send(0xFA)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C - // block!(spi.send(0x90)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C - block!(self.spi.send(0xAF)).unwrap(); // (12) Set Display Enable: Display on - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - } - - fn move_cursor(&mut self, segment: u8, page: u8) { - assert!(segment < 102); - assert!(page < 8); - - block!(self.spi.send(0x0F & segment)).unwrap(); - block!(self.spi.send(0x10 + (segment >> 4))).unwrap(); - block!(self.spi.send(0xB0 + page)).unwrap(); - } - - fn clear(&mut self) { - let mut delay = Delay::::new(); - - for page in 0..8 { - self.move_cursor(0, page as u8); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_high(); - - for _ in 0..102 { - block!(self.spi.send(0x00)).unwrap(); - } - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_low(); - } - } - - fn fill(&mut self, segment: u8, page: u8, width: u8, data: u8) { - assert!(segment + width <= 102); - let mut delay = Delay::::new(); - - self.move_cursor(segment, page); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_high(); - - for _ in 0..width { - block!(self.spi.send(data)).unwrap(); - } - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_low(); - } - - fn fill_area(&mut self, segment: u8, page: u8, width: u8, height: u8, data: u8) { - assert!(page + height <= 8); - - for i in 0..height { - self.fill(segment, page + i, width, data); - } - } - - fn print(&mut self, segment: u8, page: u8, string: &str) { - let mut delay = Delay::::new(); - - for i in 0..2 { - self.move_cursor(segment, page + i); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_high(); - - block!(self.spi.send(0x00)).unwrap(); - block!(self.spi.send(0x00)).unwrap(); - for c in string.chars() { - for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { - block!(self.spi.send(*segment)).unwrap(); - } - block!(self.spi.send(0x00)).unwrap(); - } - block!(self.spi.send(0x00)).unwrap(); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_low(); - } - } - - fn print_inverted(&mut self, segment: u8, page: u8, string: &str) { - let mut delay = Delay::::new(); - - for i in 0..2 { - self.move_cursor(segment, page + i); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_high(); - - block!(self.spi.send(0xFF)).unwrap(); - block!(self.spi.send(0xFF)).unwrap(); - for c in string.chars() { - for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { - block!(self.spi.send(!*segment)).unwrap(); - } - block!(self.spi.send(0xFF)).unwrap(); - } - block!(self.spi.send(0xFF)).unwrap(); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - self.cd.set_low(); - } - } - - fn draw(&mut self, screen: &Screens) { - interrupt::free(|_cs| { - self.clear(); - - match screen { - Screens::Splash(splash) => { - splash.draw(self); - } - Screens::Home(home) => { - home.draw(self); - } - Screens::Setup(setup) => { - setup.draw(self); - } - } - }); - } -} - -enum Input { +pub enum Input { Next, Previous, Select, Back, } -pub trait Draw { - fn draw(&self, lcd: &mut Lcd); -} - -struct SplashScreen; - -impl Draw for SplashScreen { - fn draw(&self, lcd: &mut Lcd) { - let mut delay = Delay::::new(); - - for (i, page) in SACRED_CHAO.iter().enumerate() { - lcd.move_cursor(31, 1 + i as u8); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - lcd.cd.set_high(); - - for segment in page { - block!(lcd.spi.send(*segment)).unwrap(); - } - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - lcd.cd.set_low(); - } - - for (i, page) in ONDERS_ORG.iter().enumerate() { - lcd.move_cursor(27, 6 + i as u8); - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - lcd.cd.set_high(); - - for segment in page { - block!(lcd.spi.send(*segment)).unwrap(); - } - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - lcd.cd.set_low(); - } - } -} - -enum HomeSelection { - Ch1, - Ch2, - Ch3, - Setup, -} - -struct HomeScreen { - active: HomeSelection, -} - -impl HomeScreen { - fn new() -> Self { - Self { - active: HomeSelection::Ch1, - } - } - - fn input(&self, input: &Input) -> Screens { - Screens::Home(Self { - active: match self.active { - HomeSelection::Ch1 => match input { - Input::Next => HomeSelection::Ch2, - Input::Previous => HomeSelection::Setup, - Input::Select => return Screens::Splash(SplashScreen), - Input::Back => HomeSelection::Ch1, - }, - HomeSelection::Ch2 => match input { - Input::Next => HomeSelection::Ch3, - Input::Previous => HomeSelection::Ch1, - Input::Select => return Screens::Splash(SplashScreen), - Input::Back => HomeSelection::Ch2, - }, - HomeSelection::Ch3 => match input { - Input::Next => HomeSelection::Setup, - Input::Previous => HomeSelection::Ch2, - Input::Select => return Screens::Splash(SplashScreen), - Input::Back => HomeSelection::Ch3, - }, - HomeSelection::Setup => match input { - Input::Next => HomeSelection::Ch1, - Input::Previous => HomeSelection::Ch3, - Input::Select => return Screens::Setup(SetupScreen::new()), - Input::Back => HomeSelection::Setup, - }, - }, - }) - } -} - -impl Draw for HomeScreen { - fn draw(&self, lcd: &mut Lcd) { - match &self.active { - HomeSelection::Ch1 => { - lcd.print_inverted(0, 0, "CH1"); - lcd.print(0, 2, "CH2"); - lcd.print(0, 4, "CH3"); - lcd.print(33, 6, "SETUP"); - } - HomeSelection::Ch2 => { - lcd.print(0, 0, "CH1"); - lcd.print_inverted(0, 2, "CH2"); - lcd.print(0, 4, "CH3"); - lcd.print(33, 6, "SETUP"); - } - HomeSelection::Ch3 => { - lcd.print(0, 0, "CH1"); - lcd.print(0, 2, "CH2"); - lcd.print_inverted(0, 4, "CH3"); - lcd.print(33, 6, "SETUP"); - } - HomeSelection::Setup => { - lcd.print(0, 0, "CH1"); - lcd.print(0, 2, "CH2"); - lcd.print(0, 4, "CH3"); - lcd.print_inverted(33, 6, "SETUP"); - } - } - } -} - -enum SetupSelection { - Contrast, - Backlight, - Back, -} - -struct SetupScreen { - active: SetupSelection, -} - -impl SetupScreen { - fn new() -> Self { - Self { - active: SetupSelection::Contrast, - } - } - - fn input(&self, input: &Input) -> Screens { - Screens::Setup(Self { - active: match self.active { - SetupSelection::Contrast => match input { - Input::Next => SetupSelection::Backlight, - Input::Previous => SetupSelection::Back, - Input::Select => return Screens::Splash(SplashScreen), - Input::Back => return Screens::Home(HomeScreen::new()), - }, - SetupSelection::Backlight => match input { - Input::Next => SetupSelection::Back, - Input::Previous => SetupSelection::Contrast, - Input::Select => return Screens::Splash(SplashScreen), - Input::Back => return Screens::Home(HomeScreen::new()), - }, - SetupSelection::Back => match input { - Input::Next => SetupSelection::Contrast, - Input::Previous => SetupSelection::Backlight, - Input::Select => return Screens::Home(HomeScreen::new()), - Input::Back => return Screens::Home(HomeScreen::new()), - }, - }, - }) - } -} - -impl Draw for SetupScreen { - fn draw(&self, lcd: &mut Lcd) { - match &self.active { - SetupSelection::Contrast => { - lcd.fill_area(0, 0, 33, 2, 0xFF); - lcd.print_inverted(33, 0, "SETUP"); - lcd.fill_area(69, 0, 33, 2, 0xFF); - lcd.print_inverted(0, 2, "CONTRAST:"); - lcd.print(0, 4, "BACKLIGHT:"); - lcd.print(36, 6, "BACK"); - } - SetupSelection::Backlight => { - lcd.fill_area(0, 0, 33, 2, 0xFF); - lcd.print_inverted(33, 0, "SETUP"); - lcd.fill_area(69, 0, 33, 2, 0xFF); - lcd.print(0, 2, "CONTRAST:"); - lcd.print_inverted(0, 4, "BACKLIGHT:"); - lcd.print(36, 6, "BACK"); - } - SetupSelection::Back => { - lcd.fill_area(0, 0, 33, 2, 0xFF); - lcd.print_inverted(33, 0, "SETUP"); - lcd.fill_area(69, 0, 33, 2, 0xFF); - lcd.print(0, 2, "CONTRAST:"); - lcd.print(0, 4, "BACKLIGHT:"); - lcd.print_inverted(36, 6, "BACK"); - } - } - } -} - -enum Screens { - Splash(SplashScreen), - Home(HomeScreen), - Setup(SetupScreen), -} - -impl Screens { - fn input(&mut self, input: &Input) { - match self { - Screens::Splash(_) => {} - Screens::Home(home) => *self = home.input(input), - Screens::Setup(setup) => *self = setup.input(input), - } - } -} - static UPDATE_ENCODER: AtomicBool = AtomicBool::new(false); static UPDATE_BUTTON: AtomicBool = AtomicBool::new(false); static UPDATE_TIMER: AtomicBool = AtomicBool::new(false); @@ -745,11 +113,7 @@ fn main() -> ! { ); // Init LCD - let mut lcd = Lcd { - spi, - cd: pins.pb0.into_output(), - rst: pins.pb1.into_output(), - }; + let mut lcd = Lcd::new(spi, pins.pb0.into_output(), pins.pb1.into_output()); lcd.init(contrast); // Init encoder @@ -770,7 +134,7 @@ fn main() -> ! { tc1.timsk1.write(|w| w.ocie1a().set_bit()); // Create screen - let mut screen = Screens::Splash(SplashScreen); + let mut screen = Screens::Splash(screen::Splash); // Draw splash screen lcd.draw(&screen); @@ -779,7 +143,7 @@ fn main() -> ! { delay.delay_ms(2000_u16); // Set home screen - screen = Screens::Home(HomeScreen::new()); + screen = Screens::Home(screen::Home::new()); // Draw screen lcd.draw(&screen); diff --git a/firmware/rust/src/screen/home.rs b/firmware/rust/src/screen/home.rs new file mode 100644 index 0000000..749d42f --- /dev/null +++ b/firmware/rust/src/screen/home.rs @@ -0,0 +1,83 @@ +use super::{Screen, Screens, Setup, Splash}; +use crate::{lcd::Lcd, Input}; + +enum Selection { + Ch1, + Ch2, + Ch3, + Setup, +} + +pub struct Home { + active: Selection, +} + +impl Home { + pub fn new() -> Self { + Self { + active: Selection::Ch1, + } + } + + pub fn input(&self, input: &Input) -> Screens { + Screens::Home(Self { + active: match self.active { + Selection::Ch1 => match input { + Input::Next => Selection::Ch2, + Input::Previous => Selection::Setup, + Input::Select => return Screens::Splash(Splash), + Input::Back => Selection::Ch1, + }, + Selection::Ch2 => match input { + Input::Next => Selection::Ch3, + Input::Previous => Selection::Ch1, + Input::Select => return Screens::Splash(Splash), + Input::Back => Selection::Ch2, + }, + Selection::Ch3 => match input { + Input::Next => Selection::Setup, + Input::Previous => Selection::Ch2, + Input::Select => return Screens::Splash(Splash), + Input::Back => Selection::Ch3, + }, + Selection::Setup => match input { + Input::Next => Selection::Ch1, + Input::Previous => Selection::Ch3, + Input::Select => return Screens::Setup(Setup::new()), + Input::Back => Selection::Setup, + }, + }, + }) + } +} + +impl Screen for Home { + fn draw(&self, lcd: &mut Lcd) { + match &self.active { + Selection::Ch1 => { + lcd.print_inverted(0, 0, "CH1"); + lcd.print(0, 2, "CH2"); + lcd.print(0, 4, "CH3"); + lcd.print(33, 6, "SETUP"); + } + Selection::Ch2 => { + lcd.print(0, 0, "CH1"); + lcd.print_inverted(0, 2, "CH2"); + lcd.print(0, 4, "CH3"); + lcd.print(33, 6, "SETUP"); + } + Selection::Ch3 => { + lcd.print(0, 0, "CH1"); + lcd.print(0, 2, "CH2"); + lcd.print_inverted(0, 4, "CH3"); + lcd.print(33, 6, "SETUP"); + } + Selection::Setup => { + lcd.print(0, 0, "CH1"); + lcd.print(0, 2, "CH2"); + lcd.print(0, 4, "CH3"); + lcd.print_inverted(33, 6, "SETUP"); + } + } + } +} diff --git a/firmware/rust/src/screen/mod.rs b/firmware/rust/src/screen/mod.rs new file mode 100644 index 0000000..09d46be --- /dev/null +++ b/firmware/rust/src/screen/mod.rs @@ -0,0 +1,30 @@ +mod home; +mod setup; +mod splash; + +use crate::{lcd::Lcd, Input}; +pub use home::Home; +pub use setup::Setup; +pub use splash::Splash; + +// TODO: Only update changes instead of whole screen + +pub trait Screen { + fn draw(&self, lcd: &mut Lcd); +} + +pub enum Screens { + Splash(Splash), + Home(Home), + Setup(Setup), +} + +impl Screens { + pub fn input(&mut self, input: &Input) { + match self { + Screens::Splash(_) => {} + Screens::Home(home) => *self = home.input(input), + Screens::Setup(setup) => *self = setup.input(input), + } + } +} diff --git a/firmware/rust/src/screen/setup.rs b/firmware/rust/src/screen/setup.rs new file mode 100644 index 0000000..5f3358d --- /dev/null +++ b/firmware/rust/src/screen/setup.rs @@ -0,0 +1,82 @@ +use super::{Home, Screen, Screens, Splash}; +use crate::{lcd::Lcd, Input}; + +enum Selection { + Contrast, + Backlight, + Back, +} + +pub struct Setup { + active: Selection, +} + +impl Setup { + pub fn new() -> Self { + Self { + active: Selection::Contrast, + } + } + + pub fn input(&self, input: &Input) -> Screens { + Screens::Setup(Self { + active: match self.active { + Selection::Contrast => match input { + Input::Next => Selection::Backlight, + Input::Previous => Selection::Back, + Input::Select => return Screens::Splash(Splash), + Input::Back => return Screens::Home(Home::new()), + }, + Selection::Backlight => match input { + Input::Next => Selection::Back, + Input::Previous => Selection::Contrast, + Input::Select => return Screens::Splash(Splash), + Input::Back => return Screens::Home(Home::new()), + }, + Selection::Back => match input { + Input::Next => Selection::Contrast, + Input::Previous => Selection::Backlight, + Input::Select => return Screens::Home(Home::new()), + Input::Back => return Screens::Home(Home::new()), + }, + }, + }) + } +} + +impl Screen for Setup { + fn draw(&self, lcd: &mut Lcd) { + match &self.active { + Selection::Contrast => { + lcd.fill_area(0, 0, 33, 2, 0xFF); + lcd.print_inverted(33, 0, "SETUP"); + lcd.fill_area(69, 0, 33, 2, 0xFF); + lcd.print_inverted(0, 2, "CONTRAST:"); + lcd.print(89, 2, "00"); + lcd.print(0, 4, "BACKLIGHT:"); + lcd.print(83, 4, "000"); + lcd.print(36, 6, "BACK"); + } + Selection::Backlight => { + lcd.fill_area(0, 0, 33, 2, 0xFF); + lcd.print_inverted(33, 0, "SETUP"); + lcd.fill_area(69, 0, 33, 2, 0xFF); + lcd.print(0, 2, "CONTRAST:"); + lcd.print(89, 2, "00"); + lcd.print_inverted(0, 4, "BACKLIGHT:"); + lcd.print(83, 4, "000"); + lcd.print(36, 6, "BACK"); + } + Selection::Back => { + lcd.fill_area(0, 0, 33, 2, 0xFF); + lcd.print_inverted(33, 0, "SETUP"); + lcd.fill_area(69, 0, 33, 2, 0xFF); + lcd.print(0, 2, "CONTRAST:"); + lcd.print(89, 2, "00"); + lcd.print(0, 4, "BACKLIGHT:"); + lcd.print(83, 4, "000"); + lcd.print_inverted(36, 6, "BACK"); + } + } + } +} diff --git a/firmware/rust/src/screen/splash.rs b/firmware/rust/src/screen/splash.rs new file mode 100644 index 0000000..219f314 --- /dev/null +++ b/firmware/rust/src/screen/splash.rs @@ -0,0 +1,48 @@ +use super::Screen; +use crate::{ + assets::{ONDERS_ORG, SACRED_CHAO}, + lcd::Lcd, +}; +use atmega_hal::{clock::MHz8, delay::Delay}; +use embedded_hal::{blocking::delay::DelayMs, spi::FullDuplex}; +use nb::block; + +pub struct Splash; + +impl Screen for Splash { + fn draw(&self, lcd: &mut Lcd) { + let mut delay = Delay::::new(); + + for (i, page) in SACRED_CHAO.iter().enumerate() { + lcd.move_cursor(31, 1 + i as u8); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_high(); + + for segment in page { + block!(lcd.spi.send(*segment)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_low(); + } + + for (i, page) in ONDERS_ORG.iter().enumerate() { + lcd.move_cursor(27, 6 + i as u8); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_high(); + + for segment in page { + block!(lcd.spi.send(*segment)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_low(); + } + } +}