fw-rust: Add symbols and screens
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
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:
parent
de8f789e63
commit
1688bb868e
2 changed files with 319 additions and 13 deletions
2
firmware/rust/Cargo.lock
generated
2
firmware/rust/Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in a new issue