From 1688bb868ebeda51d13b242ae2c50a8133f1f346 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 12 Mar 2022 23:53:13 +0100 Subject: [PATCH] fw-rust: Add symbols and screens Add several symbols and a symbol table in an ascii order. Add the `print()` and `print_inverted()` functions to be able to draw strings, "black on white" as well as "white on black" onto the display. Add a `HomeScreen` which also saves the state of which selection is active. To save the screen state and also make it accessible globally use a `RefCell` contained in a `Mutex`. Also update the build dependencies. --- firmware/rust/Cargo.lock | 2 +- firmware/rust/src/main.rs | 330 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 319 insertions(+), 13 deletions(-) diff --git a/firmware/rust/Cargo.lock b/firmware/rust/Cargo.lock index cb6f692..04ba3b3 100644 --- a/firmware/rust/Cargo.lock +++ b/firmware/rust/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "avr-eeprom" version = "0.1.0-dev" -source = "git+https://git.onders.org/finga/avr-eeprom-rs.git?branch=main#0177da7268e91fa3c0cf545150589b2e33aa2101" +source = "git+https://git.onders.org/finga/avr-eeprom-rs.git?branch=main#96397b5fbbaaa8531842db301127c1346f6e05f9" dependencies = [ "avr-device", "nb 1.0.0", diff --git a/firmware/rust/src/main.rs b/firmware/rust/src/main.rs index ef10494..159e421 100644 --- a/firmware/rust/src/main.rs +++ b/firmware/rust/src/main.rs @@ -9,8 +9,9 @@ use atmega_hal::{ spi::{DataOrder, SerialClockRate, Settings, Spi}, Peripherals, }; -use avr_device::interrupt; +use avr_device::interrupt::{self, Mutex}; use avr_eeprom::{eeprom, Eeprom}; +use core::cell::RefCell; use embedded_hal::{ blocking::delay::DelayMs, spi::{FullDuplex, Mode, Phase, Polarity}, @@ -68,6 +69,166 @@ const ONDERS_ORG: [[u8; 48]; 2] = [ ], ]; +// 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_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_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_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_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_INVALID, // ':' + &SYM_INVALID, // ';' + &SYM_INVALID, // '<' + &SYM_INVALID, // '=' + &SYM_INVALID, // '>' + &SYM_INVALID, // '?' + &SYM_INVALID, // '@' + &SYM_INVALID, // 'A' + &SYM_INVALID, // 'B' + &SYM_C, // 'C' + &SYM_INVALID, // 'D' + &SYM_E, // 'E' + &SYM_INVALID, // 'F' + &SYM_INVALID, // 'G' + &SYM_H, // 'H' + &SYM_INVALID, // 'I' + &SYM_INVALID, // 'J' + &SYM_INVALID, // 'K' + &SYM_INVALID, // 'L' + &SYM_INVALID, // 'M' + &SYM_INVALID, // 'N' + &SYM_INVALID, // 'O' + &SYM_P, // 'P' + &SYM_INVALID, // 'Q' + &SYM_INVALID, // '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, @@ -132,12 +293,69 @@ impl Lcd { } } - fn screen(&mut self, screen: &Screens) { + 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 screen(&mut self) { self.clear(); - match screen { - Screens::Splash(splash) => splash.draw(self), - } + interrupt::free(|cs| match &*SCREEN.borrow(cs).borrow() { + Screens::Splash(splash) => { + splash.draw(self); + } + Screens::Home(home) => { + home.draw(self); + } + }) } } @@ -185,17 +403,64 @@ impl Draw for SplashScreen { } } +enum HomeSelection { + Ch1, + Ch2, + Ch3, + Setup, +} + +struct HomeScreen { + active: HomeSelection, +} + +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 Screens { Splash(SplashScreen), + Home(HomeScreen), } +// TODO: Investigate if this should also be volatile +static SCREEN: Mutex> = Mutex::new(RefCell::new(Screens::Splash(SplashScreen))); + #[atmega_hal::entry] fn main() -> ! { - interrupt::free(|_cs| { - // Get peripherals, pins and eeprom + interrupt::free(|cs| { + // Get peripherals, pins, eeprom and delay let dp = Peripherals::take().unwrap(); let pins = pins!(dp); let eeprom = Eeprom::new(dp.EEPROM); + let mut delay = Delay::::new(); // Get contrast and backlight from EEPROM let contrast = eeprom.read_value(&CONTRAST); @@ -242,12 +507,53 @@ fn main() -> ! { }; lcd.init(contrast); - // Create screen - // TODO: This should use volatile and probably be somehow globally accessible - let screen = Screens::Splash(SplashScreen); - // Draw splash screen - lcd.screen(&screen); + lcd.screen(); + + // Show splash screen for a moment + delay.delay_ms(2000_u16); + + // Set home screen + let screen = SCREEN.borrow(cs); + *screen.borrow_mut() = Screens::Home(HomeScreen { + active: HomeSelection::Ch1, + }); + + // Draw screen + lcd.screen(); + + // Show splash screen for a moment + delay.delay_ms(1000_u16); + + // Demo select CH2 + *screen.borrow_mut() = Screens::Home(HomeScreen { + active: HomeSelection::Ch2, + }); + + // Draw screen + lcd.screen(); + + // Show splash screen for a moment + delay.delay_ms(1000_u16); + + // Demo select CH3 + *screen.borrow_mut() = Screens::Home(HomeScreen { + active: HomeSelection::Ch3, + }); + + // Draw screen + lcd.screen(); + + // Show splash screen for a moment + delay.delay_ms(1000_u16); + + // Demo select SETUP + *screen.borrow_mut() = Screens::Home(HomeScreen { + active: HomeSelection::Setup, + }); + + // Draw screen + lcd.screen(); }); #[allow(clippy::empty_loop)]