Compare commits

..

No commits in common. "master" and "keypad" have entirely different histories.

14 changed files with 277 additions and 762 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"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.77",
@ -359,7 +359,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.77",
@ -393,7 +393,6 @@ dependencies = [
"bit_field",
"embedded-graphics-core",
"embedded-hal 1.0.0",
"log",
]
[[package]]
@ -586,6 +585,12 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
@ -665,6 +670,19 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "maze"
version = "0.1.0"
@ -833,6 +851,17 @@ dependencies = [
"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]]
name = "quote"
version = "1.0.37"
@ -884,6 +913,7 @@ dependencies = [
"rand",
"shared",
"strum",
"weact-studio-epd",
]
[[package]]
@ -922,6 +952,18 @@ dependencies = [
"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]]
name = "serde"
version = "1.0.210"
@ -992,7 +1034,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
@ -1074,6 +1116,15 @@ dependencies = [
"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]]
name = "unicode-ident"
version = "1.0.13"
@ -1116,6 +1167,20 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "winapi-util"
version = "0.1.9"

View File

@ -8,13 +8,14 @@ display-interface-spi = "0.5.0"
embedded-graphics = "0.8.1"
embedded-hal-bus = "0.2.0"
esp-backtrace = { version = "0.13.0", features = ["esp32c6", "exception-handler", "panic-handler", "println"] }
esp-hal = { version = "0.20.1", features = ["esp32c6", "embedded-hal"] }
esp-hal = { version = "0.20", features = ["esp32c6", "embedded-hal"] }
esp-println = { version = "0.10.0", default-features = false, features = ["esp32c6", "log", "auto"] }
heapless = "0.8.0"
log = { version = "0.4.21" }
nutype = { version = "0.5.0", default-features = false }
profont = "0.7.0"
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'] }
maze = { path = "./maze" }

View File

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

View File

@ -289,7 +289,7 @@ where
}
fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
let _ = self.interface.wait_until_idle(delay, IS_BUSY_LOW);
self.interface.wait_until_idle(delay, IS_BUSY_LOW);
Ok(())
}
}

View File

@ -15,7 +15,6 @@ pub(crate) const LUT_1GRAY_GC: [u8; 105] = [
// This LUT updates only the pixels that have changed.
pub(crate) const LUT_1GRAY_DU: [u8; 105] = [
/*
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //1
0x01, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //2
0x0A, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //3
@ -26,18 +25,5 @@ pub(crate) const LUT_1GRAY_DU: [u8; 105] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //9
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //10
0x22, 0x22, 0x22, 0x22, 0x22,*/
//
//
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //1
0x01, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2
0x0A, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //3
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //5
0x00, 0x00, 0x05, 0x05, 0x00, 0x05, 0x03, 0x05, 0x05, 0x00, // 6
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //9
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //10
0x22, 0x22, 0x22, 0x22, 0x22,
];

View File

@ -29,7 +29,6 @@ pub const HEIGHT: u32 = 480;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
const IS_BUSY_LOW: bool = false;
const IS_BUSY_HIGH: bool = true;
const SINGLE_BYTE_WRITE: bool = true;
@ -61,51 +60,32 @@ where
DELAY: DelayNs,
{
fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
log::info!("self.interface.reset(delay, 30, 10)");
// reset the device
self.interface.reset(delay, 30, 10);
log::info!("self.interface.cmd(spi, Command::SwReset)?");
self.interface.cmd(spi, Command::SwReset)?;
log::info!("delay.delay_us(300000u32)");
delay.delay_us(300000u32);
log::info!(".cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?");
self.interface
.cmd_with_data(spi, Command::AutoWriteRedRamRegularPattern, &[0xF7])?;
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.wait_until_idle(delay, IS_BUSY_LOW);
self.interface
.cmd_with_data(spi, Command::AutoWriteBwRamRegularPattern, &[0xF7])?;
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}");
}
self.interface.wait_until_idle(delay, IS_BUSY_LOW);
log::info!(".cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?");
self.interface
.cmd_with_data(spi, Command::GateSetting, &[0xDF, 0x01, 0x00])?;
log::info!(".cmd_with_data(spi, Command::GateVoltage, &[0x00])?");
self.interface
.cmd_with_data(spi, Command::GateVoltage, &[0x00])?;
log::info!(".cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?");
self.interface
.cmd_with_data(spi, Command::GateVoltageSource, &[0x41, 0xA8, 0x32])?;
log::info!(".cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?");
self.interface
.cmd_with_data(spi, Command::DataEntrySequence, &[0x03])?;
log::info!(".cmd_with_data(spi, Command::BorderWaveformControl, &[0x03])?");
self.interface
.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(
spi,
Command::BoosterSoftStartControl,
@ -143,72 +123,6 @@ where
}
}
#[allow(dead_code)]
impl<SPI, BUSY, DC, RST, DELAY> EPD3in7<SPI, BUSY, DC, RST, DELAY>
where
SPI: SpiDevice,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
DELAY: DelayNs,
{
pub(crate) fn set_ram_area(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
start_x: u32,
start_y: u32,
end_x: u32,
end_y: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle(spi, delay)?;
assert!(start_x < end_x);
assert!(start_y < end_y);
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.cmd_with_data(
spi,
Command::SetRamXAddressStartEndPosition,
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
)?;
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
self.interface.cmd_with_data(
spi,
Command::SetRamYAddressStartEndPosition,
&[
start_y as u8,
(start_y >> 8) as u8,
end_y as u8,
(end_y >> 8) as u8,
],
)?;
Ok(())
}
pub(crate) fn set_ram_counter(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
x: u32,
y: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle(spi, delay)?;
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface
.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
// 2 Databytes: A[7:0] & 0..A[8]
self.interface.cmd_with_data(
spi,
Command::SetRamYAddressCounter,
&[y as u8, (y >> 8) as u8],
)?;
Ok(())
}
}
impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
for EPD3in7<SPI, BUSY, DC, RST, DELAY>
where
@ -228,13 +142,11 @@ where
delay: &mut DELAY,
delay_us: Option<u32>,
) -> Result<Self, SPI::Error> {
log::info!("DisplayInterface::new(busy, dc, rst, delay_us)");
let mut epd = EPD3in7 {
interface: DisplayInterface::new(busy, dc, rst, delay_us),
background_color: DEFAULT_BACKGROUND_COLOR,
};
log::info!("init");
epd.init(spi, delay)?;
Ok(epd)
}
@ -285,56 +197,25 @@ where
Ok(())
}
/**
void EPD_3IN7_1Gray_Display_Part(const UBYTE *Image, UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
{
UWORD i, Width;
Width = (Xend-Xstart)%8 == 0 ? (Xend-Xstart)/8 : (Xend-Xstart)/8+1;
UWORD IMAGE_COUNTER = Width * (Yend-Ystart);
EPD_3IN7_SendCommand(0x44);
EPD_3IN7_SendData(Xstart & 0xff);
EPD_3IN7_SendData((Xstart>>8) & 0x03);
EPD_3IN7_SendData(Xend & 0xff);
EPD_3IN7_SendData((Xend>>8) & 0x03);
EPD_3IN7_SendCommand(0x45);
EPD_3IN7_SendData(Ystart & 0xff);
EPD_3IN7_SendData((Ystart>>8) & 0x03);
EPD_3IN7_SendData(Yend & 0xff);
EPD_3IN7_SendData((Yend>>8) & 0x03);
EPD_3IN7_SendCommand(0x24);
for (i = 0; i < IMAGE_COUNTER; i++)
{
EPD_3IN7_SendData(Image[i]);
}
EPD_3IN7_Load_LUT(2);
EPD_3IN7_SendCommand(0x20);
EPD_3IN7_ReadBusy_HIGH();
}
*/
#[allow(unused)]
fn update_partial_frame(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
buffer: &[u8],
start_x: u32,
start_y: u32,
x: u32,
y: u32,
width: u32,
height: u32,
) -> Result<(), SPI::Error> {
// broken beyond repart
Ok(())
todo!()
}
fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
//self.interface
// .cmd_with_data(spi, Command::WRITE_LUT_REGISTER, &LUT_1GRAY_GC)?;
self.interface.cmd(spi, Command::DisplayUpdateSequence)?;
let _ = self.interface.wait_until_idle(delay, IS_BUSY_LOW);
self.interface.wait_until_idle(delay, IS_BUSY_LOW);
Ok(())
}
@ -379,7 +260,7 @@ where
}
fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
self.interface.wait_until_idle(delay, IS_BUSY_LOW).unwrap();
self.interface.wait_until_idle(delay, IS_BUSY_LOW);
Ok(())
}
}

View File

@ -35,9 +35,7 @@ where
/// 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 {
// default delay of 10ms
log::info!("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 {
_spi: PhantomData,
_delay: PhantomData,
@ -136,20 +134,8 @@ where
/// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?)
///
/// 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,
) -> Result<(), &'static str> {
let mut times = 0;
pub(crate) fn wait_until_idle(&mut self, delay: &mut DELAY, is_busy_low: bool) {
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 :
// - it is faster to not have it
// - it is complicated to pass the delay everywhere all the time
@ -160,7 +146,6 @@ where
delay.delay_us(self.delay_us);
}
}
Ok(())
}
/// Same as `wait_until_idle` for device needing a command to probe Busy pin

View File

@ -409,7 +409,7 @@ impl<const X: usize, const Y: usize, const SIZE: usize> AsciiBroad<X, Y, SIZE> {
// const LINE_SIZE: usize = X * Self::CELL_SIZE + 1;
// const BUFFER_SIZE: usize = Y + Self::CELL_SIZE * Self::LINE_SIZE;
pub fn format(&self, grid: &Grid<X, Y, SIZE>, output: &mut impl Write) {
fn format(&self, grid: &Grid<X, Y, SIZE>, output: &mut impl Write) {
write!(output, "#").unwrap();
(0..X).into_iter().for_each(|_| {
write!(output, "##").unwrap();
@ -426,16 +426,16 @@ impl<const X: usize, const Y: usize, const SIZE: usize> AsciiBroad<X, Y, SIZE> {
write!(bottom_line, "#").unwrap();
for x in 0..X {
write!(top_line, ".").unwrap();
write!(top_line, " ").unwrap();
let east_boundary = if grid.is_carved((x, y), Cell::EAST) {
"."
" "
} else {
"#"
};
write!(top_line, "{east_boundary}").unwrap();
let south_boundary = if grid.is_carved((x, y), Cell::SOUTH) {
"."
" "
} else {
"#"
};
@ -456,12 +456,10 @@ impl<'s> BufWriter<'s> {
pub fn new(b: &'s mut [MazePart]) -> Self {
Self(b, 0)
}
pub fn push(&mut self, part: MazePart) {
self.0[self.1] = part;
self.1 += 1;
}
pub fn copy(&mut self, src: &[MazePart]) {
src.iter()
.take_while(|p| **p != MazePart::Noop)
@ -577,8 +575,10 @@ impl<const X: usize, const Y: usize, const SIZE: usize> BinaryMapVisitor<X, Y, S
let mut bw = BufWriter::new(buffer);
bw.push(MazePart::Wall);
bw.copy(&[MazePart::Wall; X]);
bw.copy(&[MazePart::Wall; X]);
(0..X).into_iter().for_each(|_| {
bw.push(MazePart::Wall);
bw.push(MazePart::Wall);
});
let mut top_line = [MazePart::Noop; SIZE];
let mut bottom_line = [MazePart::Noop; SIZE];
@ -605,33 +605,12 @@ impl<const X: usize, const Y: usize, const SIZE: usize> BinaryMapVisitor<X, Y, S
} else {
MazePart::Wall
});
bl.push(MazePart::Wall);
}
bw.copy(&top_line);
bw.copy(&bottom_line);
}
}
}
pub fn binary_to_ascii_broad<const X: usize, const Y: usize>(b: &[MazePart], f: &mut impl Write) {
use MazePart::Passage as P;
use MazePart::Wall as W;
use MazePart::*;
write!(f, "\n").unwrap();
for y in 0..Y {
for x in 0..X {
let c = match b[y * X + x] {
P => '.',
W => '#',
Noop => '?',
Player => 'O',
};
write!(f, "{c}").unwrap();
}
write!(f, "\n").unwrap();
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MazePart {
@ -699,90 +678,6 @@ mod print_tests {
let mut map = BinaryMap::<122, 122, 14884>::new();
BinaryMapVisitor.format(&mut grid, &mut map.0);
}
#[test]
fn binary_map() {
let mut g = Grid::<5, 5, 25>::new();
g.cells[0] = Cell::EAST | Cell::SOUTH;
g.cells[1] = Cell::EAST | Cell::SOUTH;
g.cells[2] = Cell::WEST | Cell::SOUTH;
g.cells[3] = Cell::EAST | Cell::SOUTH;
g.cells[4] = Cell::WEST | Cell::SOUTH;
g.cells[5] = Cell::WEST | Cell::SOUTH;
g.cells[6] = Cell::WEST | Cell::SOUTH;
g.cells[7] = Cell::WEST | Cell::NORTH;
g.cells[8] = Cell::WEST | Cell::SOUTH;
g.cells[9] = Cell::WEST | Cell::SOUTH;
g.cells[10] = Cell::WEST | Cell::SOUTH;
g.cells[11] = Cell::EAST | Cell::NORTH;
g.cells[12] = Cell::EAST | Cell::SOUTH;
g.cells[13] = Cell::WEST | Cell::NORTH;
g.cells[14] = Cell::WEST | Cell::SOUTH;
g.cells[15] = Cell::EAST | Cell::SOUTH;
g.cells[16] = Cell::WEST | Cell::NORTH;
g.cells[17] = Cell::EAST | Cell::NORTH;
g.cells[18] = Cell::WEST | Cell::SOUTH;
g.cells[19] = Cell::WEST | Cell::SOUTH;
g.cells[20] = Cell::EAST | Cell::NORTH;
g.cells[21] = Cell::EAST | Cell::NORTH;
g.cells[22] = Cell::EAST | Cell::NORTH;
g.cells[23] = Cell::WEST | Cell::NORTH;
g.cells[24] = Cell::WEST | Cell::NORTH;
let mut map = BinaryMap::<11, 11, 121>::new();
BinaryMapVisitor.format(&g, &mut map.0);
let mut s = heapless::String::<144>::new();
AsciiBroad.format(&g, &mut s);
println!("{s}");
use MazePart::Passage as P;
use MazePart::Wall as W;
use MazePart::*;
#[derive(PartialEq)]
struct MB([MazePart; 121]);
impl std::fmt::Debug for MB {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\n");
for y in 0..11 {
for x in 0..11 {
let c = match self.0[y * 11 + x] {
P => '.',
W => '#',
Noop => '?',
Player => 'O',
};
write!(f, "{c}");
}
write!(f, "\n");
}
Ok(())
}
}
assert_eq!(
MB(map.0),
MB([
W, W, W, W, W, W, W, W, W, W, W, //
W, P, P, P, P, P, W, P, P, P, W, //
W, P, W, P, W, P, W, P, W, P, W, //
W, P, W, P, W, P, W, P, W, P, W, //
W, P, W, P, W, W, W, P, W, P, W, //
W, P, W, P, P, P, P, P, W, P, W, //
W, P, W, W, W, P, W, W, W, P, W, //
W, P, P, P, W, P, P, P, W, P, W, //
W, P, W, W, W, W, W, P, W, P, W, //
W, P, P, P, P, P, P, P, W, P, W, //
W, W, W, W, W, W, W, W, W, W, W,
])
);
}
}
#[cfg(test)]

View File

@ -1 +0,0 @@

View File

@ -1,179 +1,91 @@
use epd_waveshare::color::Color;
use maze::{binary_to_ascii_broad, BinaryMapVisitor, Direction, MazePart};
use maze::{BinaryMapVisitor, Direction};
use crate::Button;
use super::*;
pub const MAZE_WIDTH: usize = 25;
pub const MAZE_HEIGHT: usize = 25;
pub struct MazeGame {
map: maze::BinaryMap<MAZE_WIDTH, MAZE_HEIGHT, 625>,
player: Point,
old_player: Option<Point>,
map: maze::BinaryMap<122, 122, 14884>,
player: (u16, u16),
}
impl MazeGame {
pub fn new() -> Self {
Self {
map: maze::BinaryMap::new(),
player: Point { x: 0, y: 1 },
old_player: None,
player: (0, 1),
}
}
}
impl MazeGame {
const X_OFFSET: i32 = 4;
const Y_OFFSET: i32 = 4;
const CELL_SIZE: i32 = 10;
fn player_pos(&self) -> (u16, u16) {
(self.player.x as u16, self.player.y as u16)
}
fn draw_walls(&self, ctx: &mut Context) {
let wall_style = PrimitiveStyleBuilder::new()
.fill_color(Color::Black)
.build();
let passage_style = PrimitiveStyleBuilder::new()
.fill_color(Color::White)
.build();
for y in 0..MAZE_HEIGHT {
for x in 0..MAZE_WIDTH {
let style = match self.map.at(x as u16, y as u16) {
maze::MazePart::Wall => &wall_style,
_ => &passage_style,
};
Rectangle::new(
Point::new(
(x as i32 * Self::CELL_SIZE) + Self::X_OFFSET,
(y as i32 * Self::CELL_SIZE) + Self::Y_OFFSET,
),
Size::new(Self::CELL_SIZE as u32, Self::CELL_SIZE as u32),
)
.draw_styled(style, &mut ctx.epaper.display)
.unwrap();
}
}
}
fn draw_player(&self, ctx: &mut Context) {
let player_style = PrimitiveStyleBuilder::new()
.stroke_color(Color::Black)
.stroke_width(1)
.fill_color(Color::Black)
.build();
Rectangle::new(
Point::new(
(self.player.x * Self::CELL_SIZE) + Self::X_OFFSET + 1,
(self.player.y * Self::CELL_SIZE) + Self::Y_OFFSET + 1,
),
Size::new((Self::CELL_SIZE - 2) as u32, (Self::CELL_SIZE - 2) as u32),
)
.draw_styled(&player_style, &mut ctx.epaper.display)
.unwrap();
}
fn generate_map(&mut self, trng: &mut Trng) {
let mut grid = maze::Grid::<12, 12, 144>::new();
maze::RecursiveDivision.generate(&mut grid, trng);
BinaryMapVisitor.format(&mut grid, &mut self.map.0);
for x in 0..MAZE_WIDTH {
let part = &mut self.map.0[(MAZE_WIDTH + x) as usize];
if *part != MazePart::Wall {
break;
}
*part = MazePart::Passage;
}
for x in (0..MAZE_WIDTH).into_iter().rev() {
let part = &mut self.map.0[((MAZE_WIDTH * (MAZE_HEIGHT - 2)) + x) as usize];
if *part != MazePart::Wall {
break;
}
*part = MazePart::Passage;
}
let mut result = heapless::String::<4_000>::new();
// AsciiBroad.format(&grid, &mut result);
binary_to_ascii_broad::<MAZE_WIDTH, MAZE_HEIGHT>(&self.map.0, &mut result);
println!("{result}");
}
}
impl App for MazeGame {
fn start(&mut self, trng: &mut Trng) {
self.generate_map(trng);
let mut grid = maze::Grid::<60, 60, 3600>::new();
maze::RecursiveDivision.generate(&mut grid, trng);
BinaryMapVisitor.format(&mut grid, &mut self.map.0);
}
fn draw(&self, ctx: &mut Context) {
/*
self.draw_walls(ctx);
self.draw_player(ctx);*/
// FIXME: Partial update
let Some(_old) = &self.old_player else {
self.draw_walls(ctx);
self.draw_player(ctx);
return;
};
let wall_style = PrimitiveStyleBuilder::new()
.stroke_color(TriColor::Black)
.stroke_width(3)
.fill_color(TriColor::Black)
.build();
let player_style = PrimitiveStyleBuilder::new()
.stroke_color(TriColor::Red)
.stroke_width(3)
.fill_color(TriColor::Red)
.build();
ctx.epaper.fast_update();
ctx.epaper.clear_frame();
self.draw_walls(ctx);
self.draw_player(ctx);
ctx.epaper.full_update();
// ctx.epaper.partial_update(
// *old,
// Size {
// width: 1,
// height: 1,
// },
// &[Color::White as u8],
// );
// ctx.epaper.partial_update(
// self.player,
// Size {
// width: 1,
// height: 1,
// },
// &[Color::Black as u8],
// );
const X_OFFSET: i32 = 2;
const Y_OFFSET: i32 = 2;
for x in 0..122 {
for y in 0..122 {
match self.map.at(x, y) {
maze::MazePart::Wall => {
let p = Rectangle::new(
Point::new(x as i32 + X_OFFSET, y as i32 + Y_OFFSET),
Size::new(1, 1),
);
p.draw_styled(&wall_style, display).unwrap();
}
_ => {}
}
}
let p = Rectangle::new(
Point::new(
self.player.0 as i32 + X_OFFSET,
self.player.1 as i32 + Y_OFFSET,
),
Size::new(1, 1),
);
p.draw_styled(&player_style, ctx.display).unwrap();
}
*/
}
fn update(&mut self, ctx: &mut Context) -> Option<Action> {
let Some(button) = ctx.button_pressed else {
return None;
};
let player_old = self.player;
match button {
Button::Up if self.map.can_move(self.player_pos(), Direction::North) => {
self.player.y -= 1;
self.old_player = Some(player_old);
Some(Action::PartialRender)
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_pos(), Direction::South) => {
self.player.y += 1;
self.old_player = Some(player_old);
Some(Action::PartialRender)
Button::Down if self.map.can_move(self.player, Direction::South) => {
self.player.1 += 1;
}
Button::Left if self.map.can_move(self.player_pos(), Direction::West) => {
self.player.x -= 1;
self.old_player = Some(player_old);
Some(Action::PartialRender)
Button::Left if self.map.can_move(self.player, Direction::West) => {
self.player.0 -= 1;
}
Button::Right if self.map.can_move(self.player_pos(), Direction::East) => {
self.player.x += 1;
self.old_player = Some(player_old);
Some(Action::PartialRender)
Button::Right if self.map.can_move(self.player, Direction::East) => {
self.player.0 += 1;
}
Button::Back => Some(Action::GoToMenu),
_ => None,
}
Button::Back => {}
_ => {}
});
None
}
}

View File

@ -1,7 +1,6 @@
use crate::Button;
use super::*;
use epd_waveshare::color::Color;
use profont::PROFONT_18_POINT;
use strum::IntoEnumIterator;
@ -49,30 +48,31 @@ impl App for Menu {
};
match button {
Button::Up => match self.selected {
MenuEntry::Labirynth => None,
MenuEntry::Labirynth => return None,
MenuEntry::Pairs => {
self.selected = MenuEntry::Labirynth;
Some(Action::Render)
None
}
},
Button::Down => match self.selected {
MenuEntry::Labirynth => {
self.selected = MenuEntry::Pairs;
Some(Action::Render)
None
}
MenuEntry::Pairs => None,
},
Button::Circle => match self.selected {
MenuEntry::Labirynth => Some(Action::StartMaze),
MenuEntry::Pairs => Some(Action::StartPairs),
MenuEntry::Labirynth => return Some(Action::StartMaze),
MenuEntry::Pairs => return Some(Action::StartPairs),
},
_ => None,
}
}
fn draw(&self, ctx: &mut Context) {
let style = MonoTextStyle::new(&PROFONT_18_POINT, Color::Black);
let selected_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, TriColor::Red);
MenuEntry::iter().for_each(|entry| {
if entry == self.selected {
@ -82,7 +82,7 @@ impl App for Menu {
selected_style,
TextStyle::default(),
)
.draw(&mut ctx.epaper.display)
.draw(display)
.unwrap();
};
@ -96,8 +96,9 @@ impl App for Menu {
},
TextStyle::default(),
)
.draw(&mut ctx.epaper.display)
.draw(display)
.unwrap();
});
*/
}
}

View File

@ -6,9 +6,9 @@ use embedded_graphics::{
Drawable,
};
use esp_hal::rng::Trng;
use esp_println::println;
use maze_game::MazeGame;
use menu::Menu;
use weact_studio_epd::{graphics::Display290TriColor, TriColor};
use crate::Context;
@ -16,13 +16,10 @@ pub mod guess_game;
pub mod maze_game;
pub mod menu;
#[derive(Debug, Clone, Copy)]
pub enum Action {
GoToMenu,
StartMaze,
StartPairs,
Render,
PartialRender,
}
pub enum Application {
@ -30,72 +27,47 @@ pub enum Application {
Maze(maze_game::MazeGame),
}
impl Default for Application {
fn default() -> Self {
Self::Menu(Menu::new())
}
}
impl Application {
pub fn draw(&self, ctx: &mut Context, full: bool) {
if full {
ctx.epaper.slow_update();
ctx.epaper.full_erase();
}
match self {
Self::Menu(menu) => menu.draw(ctx),
Self::Maze(maze) => maze.draw(ctx),
};
if full {
ctx.epaper.full_update();
}
}
pub fn update_and_draw(&mut self, ctx: &mut Context, trng: &mut Trng) {
pub fn update(&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),
Self::Menu(menu) => menu.update(ctx),
Self::Maze(maze) => maze.update(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);
self.draw(ctx, true);
}
Action::GoToMenu => {
let mut menu = Menu::new();
menu.start(trng);
*self = Application::Menu(menu);
self.draw(ctx, true);
}
Action::StartPairs => {}
Action::Render => {
self.draw(ctx, true);
}
Action::PartialRender => {
self.draw(ctx, false);
}
};
}
}
pub fn draw(&self, ctx: &mut Context) {
match self {
Self::Menu(menu) => menu.draw(ctx),
Self::Maze(maze) => maze.draw(ctx),
}
}
}
pub trait App {
fn start(&mut self, trng: &mut Trng);
fn draw(&self, ctx: &mut Context);
fn draw(&self, display: &mut Context);
fn update(&mut self, ctx: &mut Context) -> Option<Action>;
fn update_and_draw(&mut self, ctx: &mut Context) -> Option<Action> {
fn draw_and_update(&mut self, ctx: &mut Context) -> Option<Action> {
let action = self.update(ctx);
if action.is_none() {
self.draw(ctx);
}
self.draw(ctx);
action
}
}

View File

@ -1,208 +0,0 @@
use embedded_graphics::{
geometry::{Point, Size},
mono_font::MonoTextStyleBuilder,
primitives::{Primitive, PrimitiveStyleBuilder, Rectangle},
text::{Baseline, Text, TextStyleBuilder},
Drawable,
};
use embedded_hal::delay::DelayNs;
use embedded_hal_bus::spi::ExclusiveDevice;
use epd_waveshare::epd3in7::*;
use epd_waveshare::prelude::*;
use esp_hal::{
clock::Clocks,
delay::Delay,
gpio::{Gpio18, Gpio19, Gpio20, Gpio21, Gpio22, Gpio23, Input, Level, Output, NO_PIN},
prelude::*,
spi::{master::Spi, FullDuplexMode, SpiMode},
};
pub type CS<'b> = Output<'b, Gpio20>;
pub type BUS<'b> = Input<'b, Gpio23>;
pub type RST<'b> = Output<'b, Gpio22>;
pub type DC<'b> = Output<'b, Gpio21>;
pub type SpiBus<'b> = Spi<'b, esp_hal::peripherals::SPI2, FullDuplexMode>;
pub type SPI<'b> = ExclusiveDevice<SpiBus<'b>, CS<'b>, Delay>;
pub type Driver<'b> = EPD3in7<SPI<'b>, BUS<'b>, DC<'b>, RST<'b>, Delay>;
pub struct Epaper<'d> {
pub display: Display3in7,
pub driver: Driver<'d>,
pub spi: SPI<'d>,
pub delay: Delay,
}
/**
* Board mapping:
*
*
* _________
* __| |__
* | |
* 3.3v O |
* | |
* | |
* | |
* | |
* | O 23 - BUSY
* | O 22 - RESET (RST)
* | O 21 - DC
* | O 20 - CS
* | O 19 - CLK / SCLK
* | O 18 - DIM
* | |
* | |
* | |
* |__ ___ __|
* | | | |
* CH343 ESP32C6
*
* Cannonical wiring
* * BUSY - purple - Gpio23
* * RST - white - Gpio22
* * DC - green - Gpio21
* * CS - orange - Gpio20
* * CLK - yellow - Gpio19
* * DIM - blue - Gpio18
* * GND - brown - ANY GND
* * VCC - gray - 3.3v
*
*/
// let mut epaper = epaper::Epaper::new(mosi, sclk, cs, dc, rst, busy, peripherals.SPI2, &clocks);
impl<'d> Epaper<'d> {
pub fn new(
din: Gpio18,
sclk: Gpio19,
cs: Gpio20,
dc: Gpio21,
rst: Gpio22,
busy: Gpio23,
spi: esp_hal::peripherals::SPI2,
clocks: &'d Clocks,
) -> Self {
let mut delay = Delay::new(clocks);
let spi_bus: SpiBus = Spi::new(spi, 4_000.kHz(), SpiMode::Mode0, clocks).with_pins(
Some(sclk),
Some(din),
NO_PIN,
NO_PIN, // cs is handled by the exclusive device
);
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::High);
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");
log::info!("SPI ExclusiveDevice done");
let mut driver =
EPD3in7::new(&mut spi, busy, dc, rst, &mut delay, None).expect("eink initalize error");
log::info!("Driver DONE");
let mut display = Display3in7::default();
log::info!("Display DONE");
display.set_rotation(DisplayRotation::Rotate90);
log::info!("Display ratation DONE");
driver.set_background_color(Color::White);
driver.clear_frame(&mut spi, &mut delay).unwrap();
Self {
display,
driver,
spi,
delay,
}
}
pub fn full_update(&mut self) {
// self.driver
// .clear_frame(&mut self.spi, &mut self.delay)
// .unwrap();
self.driver
.update_and_display_frame(&mut self.spi, self.display.buffer(), &mut self.delay)
.expect("display frame new graphics");
}
pub fn full_erase(&mut self) {
self.driver
.clear_frame(&mut self.spi, &mut self.delay)
.unwrap();
log::info!("Clearing display");
let _ = Rectangle::new(Point::new(0, 0), Size::new(480, 280))
.into_styled(
PrimitiveStyleBuilder::new()
.fill_color(Color::White)
.build(),
)
.draw(&mut self.display);
log::info!("Clearing display DONE");
}
pub fn fast_update(&mut self) {
self.driver
.set_lut(&mut self.spi, &mut self.delay, Some(RefreshLut::Quick))
.unwrap();
}
pub fn slow_update(&mut self) {
self.driver
.set_lut(&mut self.spi, &mut self.delay, Some(RefreshLut::Full))
.unwrap();
}
pub fn print_welcome(&mut self) {
// draw white on black background
let style = MonoTextStyleBuilder::new()
.font(&embedded_graphics::mono_font::ascii::FONT_9X15_BOLD)
.text_color(Color::Black)
.background_color(Color::White)
.build();
let text_style = TextStyleBuilder::new().baseline(Baseline::Top).build();
let _ = Text::with_text_style("Booting...", Point::new(90, 10), style, text_style)
.draw(&mut self.display);
self.driver
.update_and_display_frame(&mut self.spi, self.display.buffer(), &mut self.delay)
.expect("display frame new graphics");
self.delay.delay_ms(500);
}
pub fn wake_up(&mut self) {
self.driver.wake_up(&mut self.spi, &mut self.delay).unwrap();
}
pub fn sleep(&mut self) {
let _ = self.driver.sleep(&mut self.spi, &mut self.delay);
}
pub fn clear_frame(&mut self) {
self.driver
.clear_frame(&mut self.spi, &mut self.delay)
.unwrap();
}
pub fn partial_update(&mut self, pos: Point, size: Size, buffer: &[u8]) {
let _ = self.driver.update_partial_frame(
&mut self.spi,
&mut self.delay,
buffer,
pos.x as u32,
pos.y as u32,
size.width,
size.height,
);
}
pub fn partial_update_buffer(&mut self, pos: Point, size: Size) {
let _ = self.driver.update_partial_frame(
&mut self.spi,
&mut self.delay,
self.display.buffer(),
pos.x as u32,
pos.y as u32,
size.width,
size.height,
);
}
}

View File

@ -1,12 +1,16 @@
#![no_std]
#![no_main]
mod epaper;
use apps::Application;
use embedded_graphics::Drawable;
use apps::{menu::Menu, Application};
use display_interface_spi::SPIInterface;
use embedded_graphics::{
geometry::Point,
mono_font::{MonoTextStyle, MonoTextStyleBuilder},
text::{Baseline, Text, TextStyle, TextStyleBuilder},
Drawable,
};
use embedded_hal::delay::DelayNs;
use embedded_hal_bus::spi::ExclusiveDevice;
use epaper::Epaper;
use epd_waveshare::epd3in7::*;
use epd_waveshare::prelude::*;
use esp_backtrace as _;
@ -14,13 +18,13 @@ use esp_hal::{
clock::ClockControl,
delay::Delay,
gpio::{
Gpio0, Gpio1, Gpio10, Gpio20, Gpio21, Gpio22, Gpio23, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8,
Input, Io, Level, Output, OutputOpenDrain, Pull,
Gpio10, Gpio2, Gpio20, Gpio21, Gpio22, Gpio23, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7, Gpio8,
Input, Io, Level, Output, OutputOpenDrain, Pull, NO_PIN,
},
peripherals::Peripherals,
prelude::*,
rng::Trng,
spi::{master::Spi, FullDuplexMode},
spi::{master::Spi, FullDuplexMode, SpiMode},
system::SystemControl,
};
use esp_println::println;
@ -42,7 +46,7 @@ fn main() -> ! {
let system = SystemControl::new(peripherals.SYSTEM);
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let clocks = ClockControl::max(system.clock_control).freeze();
let delay = Delay::new(&clocks);
let mut delay = Delay::new(&clocks);
esp_println::logger::init_logger(LevelFilter::Trace);
// esp_println::logger::init_logger_from_env();
@ -53,7 +57,7 @@ fn main() -> ! {
// Configure SPI
// Settings are taken from
// Pins for e-paper
// Pins for WeAct
let mosi /* sda */ = io.pins.gpio18; // D10 / GPIO18
let sclk = io.pins.gpio19; // D8 / GPIO19
let cs = io.pins.gpio20; // D9 / GPIO20
@ -61,45 +65,106 @@ fn main() -> ! {
let rst = io.pins.gpio22; // D4 / GPIO22
let busy = io.pins.gpio23; // D5 / GPIO23
let mut epaper = epaper::Epaper::new(mosi, sclk, cs, dc, rst, busy, peripherals.SPI2, &clocks);
let spi_bus: SpiBus = Spi::new(peripherals.SPI2, 4_000.kHz(), SpiMode::Mode0, &clocks)
.with_pins(
Some(sclk),
Some(mosi),
NO_PIN,
NO_PIN, // cs is handled by the exclusive device
);
epaper.full_erase();
epaper.print_welcome();
// Convert pins into InputPins and OutputPins
/*
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 {
i1: Input::new(io.pins.gpio4, Pull::Up),
i2: Input::new(io.pins.gpio5, Pull::Up),
i3: Input::new(io.pins.gpio6, Pull::Up),
i4: Input::new(io.pins.gpio7, Pull::Up),
i1: Input::new(io.pins.gpio2, Pull::Up),
i2: Input::new(io.pins.gpio3, Pull::Up),
i3: Input::new(io.pins.gpio4, Pull::Up),
i4: Input::new(io.pins.gpio5, Pull::Up),
//---------------------------
o1: OutputOpenDrain::new(io.pins.gpio0, Level::Low, Pull::Up),
o2: OutputOpenDrain::new(io.pins.gpio1, Level::Low, Pull::Up),
o1: OutputOpenDrain::new(io.pins.gpio6, Level::Low, Pull::Up),
o2: OutputOpenDrain::new(io.pins.gpio7, Level::Low, Pull::Up),
o3: OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up),
o4: OutputOpenDrain::new(io.pins.gpio10, Level::Low, Pull::Up),
};
let mut ctx = Context {
button_pressed: None,
epaper,
driver,
display,
spi,
delay,
};
let mut app = Application::default();
let mut app = Application::Menu(Menu::new());
let mut trng = Trng::new(peripherals.RNG, peripherals.ADC1);
app.draw(&mut ctx, true);
app.update_and_draw(&mut ctx, &mut trng);
// ctx.epaper.sleep();
//app.draw(&mut display);
//driver.full_update(&display).unwrap();
//driver.sleep().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);
loop {
ctx.button_pressed = kbd.pressed();
if ctx.button_pressed.is_some() {
// ctx.epaper.clear_frame();
if !ctx.button_pressed.is_none() {
log::info!("Wake up!");
app.update_and_draw(&mut ctx, &mut trng);
ctx.driver.wake_up(&mut ctx.spi, &mut delay).unwrap();
//display.clear(TriColor::White);
//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);
}
delay.delay(100.millis());
log::info!("Sleeping for 100ms...");
//driver.sleep().unwrap();
delay.delay(300.millis());
}
}
@ -135,80 +200,42 @@ pub enum Button {
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::M1,
13 => Button::M2,
14 => Button::M3,
15 => Button::Back,
_ => return None,
})
}
}
pub struct Context<'d> {
pub button_pressed: Option<Button>,
pub epaper: Epaper<'d>,
pub display: Display3in7,
pub driver: Driver<'d>,
pub spi: SPI<'d>,
pub delay: Delay,
}
struct Keypad<'d> {
// COLS
o1: OutputOpenDrain<'d, Gpio0>, //
o2: OutputOpenDrain<'d, Gpio1>, //
o1: OutputOpenDrain<'d, Gpio6>, //
o2: OutputOpenDrain<'d, Gpio7>, //
o3: OutputOpenDrain<'d, Gpio8>, //
o4: OutputOpenDrain<'d, Gpio10>, //
// --------------------------------------
// ROWS
i1: Input<'d, Gpio4>, //
i2: Input<'d, Gpio5>, //
i3: Input<'d, Gpio6>, //
i4: Input<'d, Gpio7>, //
i1: Input<'d, Gpio2>, //
i2: Input<'d, Gpio3>, //
i3: Input<'d, Gpio4>, //
i4: Input<'d, Gpio5>, //
}
impl<'d> Keypad<'d> {
pub fn pressed(&mut self) -> Option<Button> {
let res: [[bool; 4]; 4] = core::array::from_fn(|x| {
core::array::from_fn(|y| {
self.set_low(x as u8);
let v = self.is_low(y as u8);
self.set_high(x as u8);
let v = self.is_low(y as u8);
self.set_low(x as u8);
v
})
});
if res.iter().any(|a| a.iter().any(|b| *b)) {
if res.iter().any(|a| a.iter().any(|b| !b)) {
println!("***************************************");
for a in res {
println!("col {a:?}");
}
}
let c = res
.into_iter()
.flat_map(|v| v.into_iter())
.enumerate()
.find(|(_idx, b)| *b)
.and_then(|(idx, _)| Button::from_idx(idx));
if c.is_some() {
println!("Button: {c:?}");
}
c
None
}
fn set_high(&mut self, o: u8) {