Working buttons & menu

This commit is contained in:
Adrian Woźniak 2024-09-30 16:09:01 +02:00
parent 97ca331f34
commit a6ccd36ab5
9 changed files with 224 additions and 217 deletions

73
Cargo.lock generated
View File

@ -160,7 +160,7 @@ version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [ dependencies = [
"heck 0.5.0", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.77",
@ -359,7 +359,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
dependencies = [ dependencies = [
"heck 0.5.0", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.77",
@ -393,6 +393,7 @@ dependencies = [
"bit_field", "bit_field",
"embedded-graphics-core", "embedded-graphics-core",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"log",
] ]
[[package]] [[package]]
@ -585,12 +586,6 @@ dependencies = [
"stable_deref_trait", "stable_deref_trait",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -670,19 +665,6 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "maybe-async-cfg"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e083394889336bc66a4eaf1011ffbfa74893e910f902a9f271fa624c61e1b2"
dependencies = [
"proc-macro-error",
"proc-macro2",
"pulldown-cmark",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "maze" name = "maze"
version = "0.1.0" version = "0.1.0"
@ -851,17 +833,6 @@ dependencies = [
"embedded-graphics", "embedded-graphics",
] ]
[[package]]
name = "pulldown-cmark"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
dependencies = [
"bitflags",
"memchr",
"unicase",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.37" version = "1.0.37"
@ -913,7 +884,6 @@ dependencies = [
"rand", "rand",
"shared", "shared",
"strum", "strum",
"weact-studio-epd",
] ]
[[package]] [[package]]
@ -952,18 +922,6 @@ dependencies = [
"twox-hash", "twox-hash",
] ]
[[package]]
name = "sealed"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"syn 2.0.77",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.210" version = "1.0.210"
@ -1034,7 +992,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [ dependencies = [
"heck 0.5.0", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
@ -1116,15 +1074,6 @@ dependencies = [
"static_assertions", "static_assertions",
] ]
[[package]]
name = "unicase"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.13" version = "1.0.13"
@ -1167,20 +1116,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "weact-studio-epd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e531b21e70dfc6294be2429e4f616f634c8ca1a328325dceefc4f92c12d6e9b"
dependencies = [
"display-interface",
"embedded-graphics",
"embedded-hal 1.0.0",
"embedded-hal-async",
"maybe-async-cfg",
"sealed",
]
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.9" version = "0.1.9"

View File

@ -8,14 +8,13 @@ display-interface-spi = "0.5.0"
embedded-graphics = "0.8.1" embedded-graphics = "0.8.1"
embedded-hal-bus = "0.2.0" embedded-hal-bus = "0.2.0"
esp-backtrace = { version = "0.13.0", features = ["esp32c6", "exception-handler", "panic-handler", "println"] } esp-backtrace = { version = "0.13.0", features = ["esp32c6", "exception-handler", "panic-handler", "println"] }
esp-hal = { version = "0.20", features = ["esp32c6", "embedded-hal"] } esp-hal = { version = "0.20.1", features = ["esp32c6", "embedded-hal"] }
esp-println = { version = "0.10.0", default-features = false, features = ["esp32c6", "log", "auto"] } esp-println = { version = "0.10.0", default-features = false, features = ["esp32c6", "log", "auto"] }
heapless = "0.8.0" heapless = "0.8.0"
log = { version = "0.4.21" } log = { version = "0.4.21" }
nutype = { version = "0.5.0", default-features = false } nutype = { version = "0.5.0", default-features = false }
profont = "0.7.0" profont = "0.7.0"
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
weact-studio-epd = { version = "0.1.2", features = ["blocking"] }
shared = { path = "./shared", features = ['trng'] } shared = { path = "./shared", features = ['trng'] }
maze = { path = "./maze" } maze = { path = "./maze" }

View File

@ -19,6 +19,7 @@ edition = "2021"
embedded-graphics-core = { version = "0.4", optional = true } embedded-graphics-core = { version = "0.4", optional = true }
embedded-hal = "1.0.0" embedded-hal = "1.0.0"
bit_field = "0.10.1" bit_field = "0.10.1"
log = { version = "0.4.21" }
[dev-dependencies] [dev-dependencies]
embedded-graphics = "0.8" embedded-graphics = "0.8"

View File

@ -60,32 +60,51 @@ where
DELAY: DelayNs, DELAY: DelayNs,
{ {
fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
log::info!("self.interface.reset(delay, 30, 10)");
// reset the device // reset the device
self.interface.reset(delay, 30, 10); self.interface.reset(delay, 30, 10);
log::info!("self.interface.cmd(spi, Command::SwReset)?");
self.interface.cmd(spi, Command::SwReset)?; self.interface.cmd(spi, Command::SwReset)?;
log::info!("delay.delay_us(300000u32)");
delay.delay_us(300000u32); delay.delay_us(300000u32);
log::info!(".cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?");
self.interface self.interface
.cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?; .cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?;
self.interface.wait_until_idle(delay, IS_BUSY_LOW); log::info!("1 .wait_until_idle(delay, IS_BUSY_LOW)");
if let Err(e) = self.interface.wait_until_idle(delay, IS_BUSY_LOW) {
log::error!("{e}");
panic!("{e}");
};
log::info!(".cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7])?");
self.interface self.interface
.cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7])?; .cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7])?;
self.interface.wait_until_idle(delay, IS_BUSY_LOW); log::info!("2 .wait_until_idle(delay, IS_BUSY_LOW)");
if let Err(e) = self.interface.wait_until_idle(delay, IS_BUSY_LOW) {
log::error!("{e}");
panic!("{e}");
}
log::info!(".cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?");
self.interface self.interface
.cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?; .cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?;
log::info!(".cmd_with_data(spi, Command::GateVoltage, &[0x00])?");
self.interface self.interface
.cmd_with_data(spi, Command::GateVoltage, &[0x00])?; .cmd_with_data(spi, Command::GateVoltage, &[0x00])?;
log::info!(".cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?");
self.interface self.interface
.cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?; .cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?;
log::info!(".cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?");
self.interface self.interface
.cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?; .cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?;
log::info!(".cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?");
self.interface self.interface
.cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?; .cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?;
log::info!(".cmd_with_data( spi, Command::BoosterSoftStartControl, &[0xAE, 0xC7, 0xC3, 0xC0, 0xC0],)?");
self.interface.cmd_with_data( self.interface.cmd_with_data(
spi, spi,
Command::BoosterSoftStartControl, Command::BoosterSoftStartControl,
@ -142,11 +161,13 @@ where
delay: &mut DELAY, delay: &mut DELAY,
delay_us: Option<u32>, delay_us: Option<u32>,
) -> Result<Self, SPI::Error> { ) -> Result<Self, SPI::Error> {
log::info!("DisplayInterface::new(busy, dc, rst, delay_us)");
let mut epd = EPD3in7 { let mut epd = EPD3in7 {
interface: DisplayInterface::new(busy, dc, rst, delay_us), interface: DisplayInterface::new(busy, dc, rst, delay_us),
background_color: DEFAULT_BACKGROUND_COLOR, background_color: DEFAULT_BACKGROUND_COLOR,
}; };
log::info!("init");
epd.init(spi, delay)?; epd.init(spi, delay)?;
Ok(epd) Ok(epd)
} }

View File

@ -35,7 +35,9 @@ where
/// If no delay is given, a default delay of 10ms is used. /// If no delay is given, a default delay of 10ms is used.
pub fn new(busy: BUSY, dc: DC, rst: RST, delay_us: Option<u32>) -> Self { pub fn new(busy: BUSY, dc: DC, rst: RST, delay_us: Option<u32>) -> Self {
// default delay of 10ms // default delay of 10ms
log::info!("delay_us.unwrap_or(10_000)");
let delay_us = delay_us.unwrap_or(10_000); let delay_us = delay_us.unwrap_or(10_000);
log::info!("delay_us.unwrap_or(10_000) done");
DisplayInterface { DisplayInterface {
_spi: PhantomData, _spi: PhantomData,
_delay: PhantomData, _delay: PhantomData,
@ -134,8 +136,20 @@ where
/// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?) /// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?)
/// ///
/// Most likely there was a mistake with the 2in9 busy connection /// Most likely there was a mistake with the 2in9 busy connection
pub(crate) fn wait_until_idle(&mut self, delay: &mut DELAY, is_busy_low: bool) { pub(crate) fn wait_until_idle(
&mut self,
delay: &mut DELAY,
is_busy_low: bool,
) -> Result<(), &'static str> {
let mut times = 0;
while self.is_busy(is_busy_low) { while self.is_busy(is_busy_low) {
times += 1;
if times % 10 == 0 {
log::warn!("wait_until_idle {times}");
}
if times == 1_000 {
return Err("Failed to wait 1 000 times despite idle");
}
// This has been removed and added many time : // This has been removed and added many time :
// - it is faster to not have it // - it is faster to not have it
// - it is complicated to pass the delay everywhere all the time // - it is complicated to pass the delay everywhere all the time
@ -146,6 +160,7 @@ where
delay.delay_us(self.delay_us); delay.delay_us(self.delay_us);
} }
} }
Ok(())
} }
/// Same as `wait_until_idle` for device needing a command to probe Busy pin /// Same as `wait_until_idle` for device needing a command to probe Busy pin

View File

@ -1,3 +1,4 @@
use epd_waveshare::{color::Color, prelude::WaveshareDisplay};
use maze::{BinaryMapVisitor, Direction}; use maze::{BinaryMapVisitor, Direction};
use crate::Button; use crate::Button;
@ -6,18 +7,24 @@ use super::*;
pub struct MazeGame { pub struct MazeGame {
map: maze::BinaryMap<122, 122, 14884>, map: maze::BinaryMap<122, 122, 14884>,
player: (u16, u16), player: Point,
} }
impl MazeGame { impl MazeGame {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
map: maze::BinaryMap::new(), map: maze::BinaryMap::new(),
player: (0, 1), player: Point { x: 0, y: 1 },
} }
} }
} }
impl MazeGame {
fn player_pos(&self) -> (u16, u16) {
(self.player.x as u16, self.player.y as u16)
}
}
impl App for MazeGame { impl App for MazeGame {
fn start(&mut self, trng: &mut Trng) { fn start(&mut self, trng: &mut Trng) {
let mut grid = maze::Grid::<60, 60, 3600>::new(); let mut grid = maze::Grid::<60, 60, 3600>::new();
@ -25,17 +32,46 @@ impl App for MazeGame {
BinaryMapVisitor.format(&mut grid, &mut self.map.0); BinaryMapVisitor.format(&mut grid, &mut self.map.0);
} }
fn draw(&self, ctx: &mut Context) { fn update_and_draw(&mut self, ctx: &mut Context) -> Option<Action> {
/* let Some(button) = ctx.button_pressed else {
return None;
};
let player_old = self.player.clone();
Some(match button {
Button::Up if self.map.can_move(self.player_pos(), Direction::North) => {
self.player.y -= 1;
}
Button::Down if self.map.can_move(self.player_pos(), Direction::South) => {
self.player.y += 1;
}
Button::Left if self.map.can_move(self.player_pos(), Direction::West) => {
self.player.x -= 1;
}
Button::Right if self.map.can_move(self.player_pos(), Direction::East) => {
self.player.x += 1;
}
Button::Back => {}
_ => {}
});
ctx.epaper.partial_update(
player_old,
Size {
width: 0,
height: 0,
},
&[Color::White as u8],
);
let wall_style = PrimitiveStyleBuilder::new() let wall_style = PrimitiveStyleBuilder::new()
.stroke_color(TriColor::Black) .stroke_color(Color::Black)
.stroke_width(3) .stroke_width(3)
.fill_color(TriColor::Black) .fill_color(Color::Black)
.build(); .build();
let player_style = PrimitiveStyleBuilder::new() let player_style = PrimitiveStyleBuilder::new()
.stroke_color(TriColor::Red) .stroke_color(Color::Black)
.stroke_width(3) .stroke_width(1)
.fill_color(TriColor::Red) .fill_color(Color::Black)
.build(); .build();
const X_OFFSET: i32 = 2; const X_OFFSET: i32 = 2;
@ -49,43 +85,27 @@ impl App for MazeGame {
Point::new(x as i32 + X_OFFSET, y as i32 + Y_OFFSET), Point::new(x as i32 + X_OFFSET, y as i32 + Y_OFFSET),
Size::new(1, 1), Size::new(1, 1),
); );
p.draw_styled(&wall_style, display).unwrap(); p.draw_styled(&wall_style, &mut ctx.epaper.display).unwrap();
} }
_ => {} _ => {}
} }
} }
let p = Rectangle::new( let p = Rectangle::new(
Point::new( Point::new(
self.player.0 as i32 + X_OFFSET, self.player.x as i32 + X_OFFSET,
self.player.1 as i32 + Y_OFFSET, self.player.y as i32 + Y_OFFSET,
), ),
Size::new(1, 1), Size::new(1, 1),
); );
p.draw_styled(&player_style, ctx.display).unwrap(); p.draw_styled(&player_style, &mut ctx.epaper.display)
.unwrap();
} }
*/ None
} }
fn update(&mut self, ctx: &mut Context) -> Option<Action> { fn draw(&self, _ctx: &mut Context) {}
let Some(button) = ctx.button_pressed else {
return None; fn update(&mut self, _ctx: &mut Context) -> Option<Action> {
};
Some(match button {
Button::Up if self.map.can_move(self.player, Direction::North) => {
self.player.1 -= 1;
}
Button::Down if self.map.can_move(self.player, Direction::South) => {
self.player.1 += 1;
}
Button::Left if self.map.can_move(self.player, Direction::West) => {
self.player.0 -= 1;
}
Button::Right if self.map.can_move(self.player, Direction::East) => {
self.player.0 += 1;
}
Button::Back => {}
_ => {}
});
None None
} }
} }

View File

@ -1,6 +1,7 @@
use crate::Button; use crate::Button;
use super::*; use super::*;
use epd_waveshare::color::Color;
use profont::PROFONT_18_POINT; use profont::PROFONT_18_POINT;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -70,9 +71,8 @@ impl App for Menu {
} }
fn draw(&self, ctx: &mut Context) { fn draw(&self, ctx: &mut Context) {
/* let style = MonoTextStyle::new(&PROFONT_18_POINT, Color::Black);
let style = MonoTextStyle::new(&PROFONT_18_POINT, TriColor::Black); let selected_style = MonoTextStyle::new(&PROFONT_18_POINT, Color::Black);
let selected_style = MonoTextStyle::new(&PROFONT_18_POINT, TriColor::Red);
MenuEntry::iter().for_each(|entry| { MenuEntry::iter().for_each(|entry| {
if entry == self.selected { if entry == self.selected {
@ -82,7 +82,7 @@ impl App for Menu {
selected_style, selected_style,
TextStyle::default(), TextStyle::default(),
) )
.draw(display) .draw(&mut ctx.epaper.display)
.unwrap(); .unwrap();
}; };
@ -96,9 +96,8 @@ impl App for Menu {
}, },
TextStyle::default(), TextStyle::default(),
) )
.draw(display) .draw(&mut ctx.epaper.display)
.unwrap(); .unwrap();
}); });
*/
} }
} }

View File

@ -6,9 +6,9 @@ use embedded_graphics::{
Drawable, Drawable,
}; };
use esp_hal::rng::Trng; use esp_hal::rng::Trng;
use esp_println::println;
use maze_game::MazeGame; use maze_game::MazeGame;
use menu::Menu; use menu::Menu;
use weact_studio_epd::{graphics::Display290TriColor, TriColor};
use crate::Context; use crate::Context;
@ -16,6 +16,7 @@ pub mod guess_game;
pub mod maze_game; pub mod maze_game;
pub mod menu; pub mod menu;
#[derive(Debug, Clone, Copy)]
pub enum Action { pub enum Action {
GoToMenu, GoToMenu,
StartMaze, StartMaze,
@ -27,6 +28,12 @@ pub enum Application {
Maze(maze_game::MazeGame), Maze(maze_game::MazeGame),
} }
impl Default for Application {
fn default() -> Self {
Self::Menu(Menu::new())
}
}
impl Application { impl Application {
pub fn update(&mut self, ctx: &mut Context, trng: &mut Trng) { pub fn update(&mut self, ctx: &mut Context, trng: &mut Trng) {
let Some(action) = (match self { let Some(action) = (match self {
@ -51,23 +58,52 @@ impl Application {
} }
pub fn draw(&self, ctx: &mut Context) { pub fn draw(&self, ctx: &mut Context) {
ctx.epaper.full_erase();
match self { match self {
Self::Menu(menu) => menu.draw(ctx), Self::Menu(menu) => menu.draw(ctx),
Self::Maze(maze) => maze.draw(ctx), Self::Maze(maze) => maze.draw(ctx),
};
ctx.epaper.full_update();
} }
pub fn update_and_draw(&mut self, ctx: &mut Context, trng: &mut Trng) {
let Some(action) = (match self {
Self::Menu(menu) => menu.update_and_draw(ctx),
Self::Maze(maze) => maze.update_and_draw(ctx),
}) else {
println!("No action");
return;
};
println!("Action: {action:?}");
match action {
Action::StartMaze => {
let mut maze = MazeGame::new();
maze.start(trng);
*self = Application::Maze(maze);
}
Action::GoToMenu => {
let mut menu = Menu::new();
menu.start(trng);
*self = Application::Menu(menu);
}
Action::StartPairs => {}
};
self.draw(ctx);
} }
} }
pub trait App { pub trait App {
fn start(&mut self, trng: &mut Trng); fn start(&mut self, trng: &mut Trng);
fn draw(&self, display: &mut Context); fn draw(&self, ctx: &mut Context);
fn update(&mut self, ctx: &mut Context) -> Option<Action>; fn update(&mut self, ctx: &mut Context) -> Option<Action>;
fn draw_and_update(&mut self, ctx: &mut Context) -> Option<Action> { fn update_and_draw(&mut self, ctx: &mut Context) -> Option<Action> {
let action = self.update(ctx); let action = self.update(ctx);
if action.is_none() {
self.draw(ctx); self.draw(ctx);
}
action action
} }
} }

View File

@ -1,16 +1,19 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
mod epaper;
use apps::{menu::Menu, Application}; use apps::{menu::Menu, Application};
use display_interface_spi::SPIInterface;
use embedded_graphics::{ use embedded_graphics::{
geometry::Point, geometry::{Point, Size},
mono_font::{MonoTextStyle, MonoTextStyleBuilder}, mono_font::MonoTextStyleBuilder,
text::{Baseline, Text, TextStyle, TextStyleBuilder}, primitives::{Primitive, PrimitiveStyleBuilder, Rectangle, StyledDrawable},
text::{Baseline, Text, TextStyleBuilder},
Drawable, Drawable,
}; };
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use epaper::Epaper;
use epd_waveshare::epd3in7::*; use epd_waveshare::epd3in7::*;
use epd_waveshare::prelude::*; use epd_waveshare::prelude::*;
use esp_backtrace as _; use esp_backtrace as _;
@ -18,8 +21,8 @@ use esp_hal::{
clock::ClockControl, clock::ClockControl,
delay::Delay, delay::Delay,
gpio::{ gpio::{
Gpio10, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8, Gpio0, Gpio1, Gpio10, Gpio11, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio3, Gpio4, Gpio5,
Input, Io, Level, Output, OutputOpenDrain, Pull, NO_PIN, Gpio6, Gpio7, Gpio8, Input, Io, Level, Output, OutputOpenDrain, Pull, NO_PIN,
}, },
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
@ -46,7 +49,7 @@ fn main() -> ! {
let system = SystemControl::new(peripherals.SYSTEM); let system = SystemControl::new(peripherals.SYSTEM);
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let clocks = ClockControl::max(system.clock_control).freeze(); let clocks = ClockControl::max(system.clock_control).freeze();
let mut delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
esp_println::logger::init_logger(LevelFilter::Trace); esp_println::logger::init_logger(LevelFilter::Trace);
// esp_println::logger::init_logger_from_env(); // esp_println::logger::init_logger_from_env();
@ -57,7 +60,7 @@ fn main() -> ! {
// Configure SPI // Configure SPI
// Settings are taken from // Settings are taken from
// Pins for WeAct // Pins for e-paper
let mosi /* sda */ = io.pins.gpio18; // D10 / GPIO18 let mosi /* sda */ = io.pins.gpio18; // D10 / GPIO18
let sclk = io.pins.gpio19; // D8 / GPIO19 let sclk = io.pins.gpio19; // D8 / GPIO19
let cs = io.pins.gpio20; // D9 / GPIO20 let cs = io.pins.gpio20; // D9 / GPIO20
@ -65,104 +68,45 @@ fn main() -> ! {
let rst = io.pins.gpio22; // D4 / GPIO22 let rst = io.pins.gpio22; // D4 / GPIO22
let busy = io.pins.gpio23; // D5 / GPIO23 let busy = io.pins.gpio23; // D5 / GPIO23
let spi_bus: SpiBus = Spi::new(peripherals.SPI2, 4_000.kHz(), SpiMode::Mode0, &clocks) let mut epaper = epaper::Epaper::new(mosi, sclk, cs, dc, rst, busy, peripherals.SPI2, &clocks);
.with_pins(
Some(sclk),
Some(mosi),
NO_PIN,
NO_PIN, // cs is handled by the exclusive device
);
// Convert pins into InputPins and OutputPins epaper.full_erase();
/* epaper.print_welcome();
CS: OutputPin,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
*/
let cs: CS = Output::new(cs, Level::High);
let busy: BUS = Input::new(busy, esp_hal::gpio::Pull::Up);
let dc: DC = Output::new(dc, Level::Low);
let rst = Output::new(rst, Level::High);
log::info!("Intializing SPI Device...");
let mut spi: SPI =
ExclusiveDevice::new(spi_bus, cs, delay).expect("SPI device initialize error");
// let spi_interface = SPIInterface::new(spi_device, dc);
let mut driver =
EPD3in7::new(&mut spi, busy, dc, rst, &mut delay, None).expect("eink initalize error");
let mut display = Display3in7::default();
display.set_rotation(DisplayRotation::Rotate90);
// draw white on black background
let style = MonoTextStyleBuilder::new()
.font(&embedded_graphics::mono_font::ascii::FONT_6X10)
.text_color(Color::White)
.background_color(Color::Black)
.build();
let text_style = TextStyleBuilder::new().baseline(Baseline::Top).build();
let _ =
Text::with_text_style("Witamy!", Point::new(90, 10), style, text_style).draw(&mut display);
driver
.update_and_display_frame(&mut spi, display.buffer(), &mut delay)
.expect("display frame new graphics");
delay.delay_ms(500);
// epd2in13
// .set_refresh(&mut spi, &mut delay, RefreshLut::Quick)
// .unwrap();
driver.clear_frame(&mut spi, &mut delay).unwrap();
let mut kbd = Keypad { let mut kbd = Keypad {
i1: Input::new(io.pins.gpio2, Pull::Up), i1: Input::new(io.pins.gpio4, Pull::Up),
i2: Input::new(io.pins.gpio3, Pull::Up), i2: Input::new(io.pins.gpio5, Pull::Up),
i3: Input::new(io.pins.gpio4, Pull::Up), i3: Input::new(io.pins.gpio6, Pull::Up),
i4: Input::new(io.pins.gpio5, Pull::Up), i4: Input::new(io.pins.gpio7, Pull::Up),
//--------------------------- //---------------------------
o1: OutputOpenDrain::new(io.pins.gpio6, Level::Low, Pull::Up), o1: OutputOpenDrain::new(io.pins.gpio0, Level::Low, Pull::Up),
o2: OutputOpenDrain::new(io.pins.gpio7, Level::Low, Pull::Up), o2: OutputOpenDrain::new(io.pins.gpio1, Level::Low, Pull::Up),
o3: OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up), o3: OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up),
o4: OutputOpenDrain::new(io.pins.gpio10, Level::Low, Pull::Up), o4: OutputOpenDrain::new(io.pins.gpio10, Level::Low, Pull::Up),
}; };
let mut ctx = Context { let mut ctx = Context {
button_pressed: None, button_pressed: None,
driver, epaper,
display,
spi,
delay, delay,
}; };
let mut app = Application::Menu(Menu::new()); let mut app = Application::default();
let mut trng = Trng::new(peripherals.RNG, peripherals.ADC1); let mut trng = Trng::new(peripherals.RNG, peripherals.ADC1);
//app.draw(&mut display); app.draw(&mut ctx);
//driver.full_update(&display).unwrap(); app.update_and_draw(&mut ctx, &mut trng);
//driver.sleep().unwrap();
ctx.driver.clear_frame(&mut ctx.spi, &mut delay).unwrap(); // ctx.epaper.sleep();
ctx.driver
.update_and_display_frame(&mut ctx.spi, ctx.display.buffer(), &mut delay)
.expect("display frame new graphics");
let _ = ctx.driver.sleep(&mut ctx.spi, &mut delay);
loop { loop {
ctx.button_pressed = kbd.pressed(); ctx.button_pressed = kbd.pressed();
if !ctx.button_pressed.is_none() { if !ctx.button_pressed.is_none() {
log::info!("Wake up!"); log::info!("Wake up!");
ctx.driver.wake_up(&mut ctx.spi, &mut delay).unwrap(); // ctx.epaper.wake_up();
//display.clear(TriColor::White); app.update_and_draw(&mut ctx, &mut trng);
//app.update(&ctx, &mut trng);
// app.draw(&mut display);
//driver.full_update(&display).unwrap();
ctx.driver.clear_frame(&mut ctx.spi, &mut delay).unwrap();
ctx.driver
.update_and_display_frame(&mut ctx.spi, ctx.display.buffer(), &mut delay)
.expect("display frame new graphics");
let _ = ctx.driver.sleep(&mut ctx.spi, &mut delay);
} }
log::info!("Sleeping for 100ms..."); // log::info!("Sleeping for 100ms...");
//driver.sleep().unwrap(); //driver.sleep().unwrap();
delay.delay(300.millis()); delay.delay(300.millis());
} }
@ -200,42 +144,79 @@ pub enum Button {
Back, Back,
} }
impl Button {
pub fn from_idx(idx: usize) -> Option<Button> {
Some(match idx {
0 => Button::A,
1 => Button::Up,
2 => Button::B,
3 => Button::X,
//
4 => Button::Left,
5 => Button::Circle,
6 => Button::Right,
7 => Button::Y,
//
8 => Button::C,
9 => Button::Down,
10 => Button::D,
11 => Button::Z,
//
12 => Button::A,
13 => Button::A,
14 => Button::A,
15 => Button::A,
_ => return None,
})
}
}
pub struct Context<'d> { pub struct Context<'d> {
pub button_pressed: Option<Button>, pub button_pressed: Option<Button>,
pub display: Display3in7, pub epaper: Epaper<'d>,
pub driver: Driver<'d>,
pub spi: SPI<'d>,
pub delay: Delay, pub delay: Delay,
} }
struct Keypad<'d> { struct Keypad<'d> {
o1: OutputOpenDrain<'d, Gpio6>, // // COLS
o2: OutputOpenDrain<'d, Gpio7>, // o1: OutputOpenDrain<'d, Gpio0>, //
o2: OutputOpenDrain<'d, Gpio1>, //
o3: OutputOpenDrain<'d, Gpio8>, // o3: OutputOpenDrain<'d, Gpio8>, //
o4: OutputOpenDrain<'d, Gpio10>, // o4: OutputOpenDrain<'d, Gpio10>, //
// -------------------------------------- // --------------------------------------
i1: Input<'d, Gpio2>, // // ROWS
i2: Input<'d, Gpio3>, // i1: Input<'d, Gpio4>, //
i3: Input<'d, Gpio4>, // i2: Input<'d, Gpio5>, //
i4: Input<'d, Gpio5>, // i3: Input<'d, Gpio6>, //
i4: Input<'d, Gpio7>, //
} }
impl<'d> Keypad<'d> { impl<'d> Keypad<'d> {
pub fn pressed(&mut self) -> Option<Button> { pub fn pressed(&mut self) -> Option<Button> {
let res: [[bool; 4]; 4] = core::array::from_fn(|x| { let res: [[bool; 4]; 4] = core::array::from_fn(|x| {
core::array::from_fn(|y| { core::array::from_fn(|y| {
self.set_high(x as u8);
let v = self.is_low(y as u8);
self.set_low(x as u8); self.set_low(x as u8);
let v = self.is_low(y as u8);
self.set_high(x as u8);
v v
}) })
}); });
if res.iter().any(|a| a.iter().any(|b| !b)) { if res.iter().any(|a| a.iter().any(|b| *b)) {
println!("***************************************"); println!("***************************************");
for a in res { for a in res {
println!("col {a:?}"); println!("col {a:?}");
} }
} }
None let c = res
.into_iter()
.map(|v| v.into_iter())
.flatten()
.enumerate()
.find(|(_idx, b)| *b)
.and_then(|(idx, _)| Button::from_idx(idx));
println!("Button: {c:?}");
c
} }
fn set_high(&mut self, o: u8) { fn set_high(&mut self, o: u8) {