fw-rust: Add symbols and screens
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

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.
This commit is contained in:
finga 2022-03-12 23:53:13 +01:00
parent de8f789e63
commit 1688bb868e
2 changed files with 319 additions and 13 deletions

View file

@ -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",

View file

@ -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<Output, PB0>,
@ -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::<MHz8>::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::<MHz8>::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<RefCell<Screens>> = 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::<MHz8>::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)]