From 9cd595acfee23271795b0c10c1fd1d7071ff7b20 Mon Sep 17 00:00:00 2001 From: lukas Date: Sun, 2 Aug 2026 17:20:40 +0200 Subject: [PATCH] OLED driver with shared SPI bus integrated --- Cargo.lock | 11 ++++ Cargo.toml | 5 ++ src/bin/main.rs | 51 ++++++++++++---- src/display.rs | 1 + src/display/primary_lcd.rs | 66 ++++++++------------ src/display/secondary_oled.rs | 35 ++++++++++- src/display/shared_bus.rs | 109 ++++++++++++++++++++++++++++++++++ src/display/sprite.rs | 1 - src/display/tertiary_lcd.rs | 22 +++++-- src/drivers/nfc_pn532.rs | 34 ++++++----- src/navigation/navigation.rs | 15 +++-- src/navigation/state.rs | 1 - src/views/card_view.rs | 10 ++-- src/views/journal_view.rs | 13 ++-- src/views/main_menu.rs | 10 ++-- src/views/menu_item.rs | 17 +++--- src/views/scan_menu.rs | 11 ++-- src/views/settings_menu.rs | 11 ++-- src/views/view.rs | 12 ++-- 19 files changed, 312 insertions(+), 123 deletions(-) create mode 100644 src/display/shared_bus.rs diff --git a/Cargo.lock b/Cargo.lock index 004980d..c7ada03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,6 +235,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "ch1115" +version = "0.1.2" +source = "git+https://github.com/ede1998/ch1115.git?rev=2d3a3ba38050efe012e6a210afe3e125ec280c37#2d3a3ba38050efe012e6a210afe3e125ec280c37" +dependencies = [ + "display-interface", + "embedded-graphics-core", + "embedded-hal 1.0.0", +] + [[package]] name = "cobs" version = "0.3.0" @@ -309,6 +319,7 @@ name = "creaturedex" version = "0.1.0" dependencies = [ "base64 0.22.1", + "ch1115", "critical-section", "display-interface-spi", "embassy-executor", diff --git a/Cargo.toml b/Cargo.toml index 626171a..55b0e77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,11 @@ num_enum = { version = "0.7.6", default-features = false } embassy-sync = "0.8.0" embedded-hal-async = "1.0.0" i2c-character-display = "0.5.1" +ch1115 = { version = "0.1.2", features = ["graphics"] } + + +[patch.crates-io] +ch1115 = { git = "https://github.com/ede1998/ch1115.git", rev = "2d3a3ba38050efe012e6a210afe3e125ec280c37" } # For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html [profile.dev] diff --git a/src/bin/main.rs b/src/bin/main.rs index eb4c02e..3cb377b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -10,7 +10,7 @@ use alloc::boxed::Box; use creaturedex::card::decoder::split_nfc_hex; use creaturedex::card::model::Card; -use creaturedex::display::primary_lcd::{PrimaryLcdDisplay, init_primary_lcd}; +use creaturedex::display::shared_bus::{DualSecondaryDisplay, init_dual_displays}; use creaturedex::display::tertiary_lcd::{init_tertiary_lcd, write_wrapped}; use creaturedex::drivers::nfc_pn532::NfcPn532Driver; use creaturedex::navigation::inputs::Inputs; @@ -18,13 +18,19 @@ use creaturedex::navigation::navigation::{self, CARD_DATA}; use creaturedex::network::wifi::setup_wifi; use embassy_executor::Spawner; use embassy_time::Instant; +use embedded_graphics::pixelcolor::BinaryColor; +use embedded_graphics::{ + mono_font::{MonoTextStyle, ascii::FONT_6X10}, + prelude::*, + text::Text, +}; use embedded_hal_bus::i2c::AtomicDevice; use embedded_hal_bus::util::AtomicCell; use esp_hal::Blocking; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Pull}; -use esp_hal::timer::timg::TimerGroup; use esp_hal::i2c::master::{Config as I2cConfig, I2c}; +use esp_hal::timer::timg::TimerGroup; use log::error; #[panic_handler] @@ -59,19 +65,22 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); - let display: &mut PrimaryLcdDisplay = Box::leak(Box::new(init_primary_lcd( + let (display, oled) = Box::leak(Box::new(init_dual_displays( peripherals.SPI2, peripherals.GPIO36, // sck peripherals.GPIO35, // mosi peripherals.GPIO37, // miso peripherals.GPIO11, // primary cs + peripherals.GPIO13, // oled cs peripherals.GPIO10, // shared reset peripherals.GPIO12, // shared dc ))); let config = I2cConfig::default().with_frequency(esp_hal::time::Rate::from_khz(400)); let i2c = match I2c::new(peripherals.I2C0, config) { - Ok(bus) => bus.with_sda(peripherals.GPIO17).with_scl(peripherals.GPIO18), + Ok(bus) => bus + .with_sda(peripherals.GPIO17) + .with_scl(peripherals.GPIO18), Err(e) => { log::error!("Shared I2C bus initialization failed for GPIO17/GPIO18: {e:?}"); panic!("Shared I2C bus initialization failed"); @@ -82,10 +91,12 @@ async fn main(spawner: Spawner) { let mut lcd = init_tertiary_lcd(AtomicDevice::new(shared_i2c)); if let Err(_) = write_wrapped(&mut lcd, "Testing more than 16 chars what happens now?") { - log::error!("Tertiary LCD startup text write failed over shared I2C bus; check the shared bus, wiring, and device responses"); + log::error!( + "Tertiary LCD startup text write failed over shared I2C bus; check the shared bus, wiring, and device responses" + ); } - // setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await; + setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await; let mut nfc_driver = NfcPn532Driver::new(AtomicDevice::new(shared_i2c)); if nfc_driver.configure_sam().await.is_ok() { @@ -104,14 +115,17 @@ async fn main(spawner: Spawner) { ok: Input::new(peripherals.GPIO0, button_config), }; + display_shit(oled); + log::info!("Setup complete, entering main loop"); spawner.spawn(navigation::run(inputs, display).expect("run task failed")); spawner.spawn(nfc_driver_task(nfc_driver).expect("nfc driver task failed")); } - #[embassy_executor::task] -async fn nfc_driver_task(mut nfc_driver: NfcPn532Driver>>) { +async fn nfc_driver_task( + mut nfc_driver: NfcPn532Driver>>, +) { loop { while CARD_DATA.lock().await.is_none() { let start = Instant::now(); @@ -121,9 +135,16 @@ async fn nfc_driver_task(mut nfc_driver: NfcPn532Driver { log::info!("No NFC card found"); @@ -133,3 +154,13 @@ async fn nfc_driver_task(mut nfc_driver: NfcPn532Driver) { + oled.clear().unwrap(); + + let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); + Text::new("Hello OLED", Point::new(10, 20), text_style) + .draw(oled) + .unwrap(); + oled.flush().unwrap(); +} diff --git a/src/display.rs b/src/display.rs index aac8524..614d495 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,4 +1,5 @@ pub mod primary_lcd; pub mod secondary_oled; +pub mod shared_bus; pub mod sprite; pub mod tertiary_lcd; diff --git a/src/display/primary_lcd.rs b/src/display/primary_lcd.rs index 65e727d..a8a5578 100644 --- a/src/display/primary_lcd.rs +++ b/src/display/primary_lcd.rs @@ -2,55 +2,37 @@ use display_interface_spi::SPIInterface; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::RgbColor; -use embedded_hal_bus::spi::ExclusiveDevice; +use embedded_hal::digital::OutputPin as EhOutputPin; +use embedded_hal_bus::spi::AtomicDevice; +use embedded_hal_bus::util::AtomicCell; use esp_hal::delay::Delay; -use esp_hal::gpio::{Level, Output, OutputConfig}; -use esp_hal::peripherals::{GPIO10, GPIO11, GPIO12, GPIO35, GPIO36, GPIO37, SPI2}; -use esp_hal::spi::{ - Mode, - master::{Config, Spi}, -}; -use esp_hal::time::Rate; +use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin}; use ili9341::{DisplaySize240x320, Ili9341, Orientation}; -pub type PrimaryLcdDisplay<'a> = Ili9341< - SPIInterface, Output<'a>, Delay>, Output<'a>>, - Output<'a>, ->; +pub type PrimaryLcdDisplay<'a, BUS, DC, RES> = + Ili9341, Delay>, DC>, RES>; -pub fn init_primary_lcd( - spi2: SPI2<'static>, - sck: GPIO36<'static>, - mosi: GPIO35<'static>, - miso: GPIO37<'static>, - cs: GPIO11<'static>, - reset: GPIO10<'static>, - dc: GPIO12<'static>, -) -> PrimaryLcdDisplay<'static> { - let freq = Rate::from_khz(60_000); - log::info!("Display freq: {freq}"); - - let spi_bus = Spi::new( - spi2, - Config::default().with_frequency(freq).with_mode(Mode::_0), - ) - .unwrap() - .with_sck(sck) - .with_mosi(mosi) - .with_miso(miso); - - let mut delay = Delay::new(); - - let cs_main = Output::new(cs, Level::High, OutputConfig::default()); - let spi_dev = ExclusiveDevice::new(spi_bus, cs_main, delay).unwrap(); - let reset_main = Output::new(reset, Level::High, OutputConfig::default()); - let spi_dc = Output::new(dc, Level::High, OutputConfig::default()); - let iface = SPIInterface::new(spi_dev, spi_dc); +pub fn init_primary_lcd_on_bus<'a, BUS, CS, RES, DC>( + spi_bus: &'a AtomicCell, + cs: CS, + reset: RES, + dc: DC, + delay: &mut Delay, +) -> PrimaryLcdDisplay<'a, BUS, DC, RES> +where + BUS: embedded_hal::spi::SpiBus, + CS: OutputPin + 'static, + RES: EhOutputPin, + DC: EhOutputPin, +{ + let cs_pin = Output::new(cs, Level::High, OutputConfig::default()); + let spi_dev = AtomicDevice::new(spi_bus, cs_pin, *delay).unwrap(); + let iface = SPIInterface::new(spi_dev, dc); let mut display = Ili9341::new( iface, - reset_main, - &mut delay, + reset, + delay, Orientation::Portrait, DisplaySize240x320, ) diff --git a/src/display/secondary_oled.rs b/src/display/secondary_oled.rs index 668cfb6..b003bdb 100644 --- a/src/display/secondary_oled.rs +++ b/src/display/secondary_oled.rs @@ -1 +1,34 @@ -// Secondary OLED module +use ch1115::{Ch1115, Size128x64}; +use display_interface_spi::SPIInterface; +use embedded_hal::digital::OutputPin as EhOutputPin; +use embedded_hal_bus::spi::AtomicDevice; +use embedded_hal_bus::util::AtomicCell; +use esp_hal::delay::Delay; +use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin}; + +pub type SecondaryOledDisplay<'a, BUS, RST, DC> = + Ch1115, Delay>, DC>, RST, Size128x64>; + +pub fn init_secondary_oled_on_bus<'a, BUS, CS, RES, DC>( + spi_bus: &'a AtomicCell, + cs: CS, + res: RES, + dc: DC, + delay: &mut Delay, +) -> SecondaryOledDisplay<'a, BUS, RES, DC> +where + BUS: embedded_hal::spi::SpiBus, + CS: OutputPin + 'static, + RES: EhOutputPin, + DC: EhOutputPin, +{ + let cs_pin = Output::new(cs, Level::High, OutputConfig::default()); + let spi_dev = AtomicDevice::new(spi_bus, cs_pin, *delay).unwrap(); + let interface = SPIInterface::new(spi_dev, dc); + + let mut display = Ch1115::new(interface, res, Size128x64); + + display.init(&mut Delay::new()).unwrap(); + + display +} diff --git a/src/display/shared_bus.rs b/src/display/shared_bus.rs new file mode 100644 index 0000000..375ab4c --- /dev/null +++ b/src/display/shared_bus.rs @@ -0,0 +1,109 @@ +use crate::display::primary_lcd::{PrimaryLcdDisplay, init_primary_lcd_on_bus}; +use alloc::boxed::Box; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embedded_hal::digital::ErrorType; +use embedded_hal::digital::OutputPin as EhOutputPin; +use embedded_hal_bus::util::AtomicCell; +use esp_hal::delay::Delay; +use esp_hal::gpio::interconnect::{PeripheralInput, PeripheralOutput}; +use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin}; +use esp_hal::spi::Mode; +use esp_hal::spi::master::{Config as SpiConfig, Spi}; +use esp_hal::time::Rate; + +use crate::display::secondary_oled::{SecondaryOledDisplay, init_secondary_oled_on_bus}; + +use core::cell::RefCell; +use embassy_sync::blocking_mutex::Mutex as BlockingMutex; + +#[derive(Clone)] +pub struct SharedPin<'a, P> { + mutex: &'a BlockingMutex>, +} + +impl<'a, P> SharedPin<'a, P> { + pub fn new(mutex: &'a BlockingMutex>) -> Self { + Self { mutex } + } + + pub fn pre_wrap(pin: P) -> &'static BlockingMutex> { + let mutexed = BlockingMutex::new(RefCell::new(pin)); + Box::leak(Box::new(mutexed)) + } +} + +impl<'a, P: EhOutputPin> ErrorType for SharedPin<'a, P> { + type Error = P::Error; +} + +impl<'a, P: EhOutputPin> EhOutputPin for SharedPin<'a, P> { + fn set_low(&mut self) -> Result<(), Self::Error> { + self.mutex.lock(|p| p.borrow_mut().set_low()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + self.mutex.lock(|p| p.borrow_mut().set_high()) + } +} + +pub type DisplaySpiBus = Spi<'static, esp_hal::Blocking>; +pub type DualPrimaryDisplay<'a> = + PrimaryLcdDisplay<'a, DisplaySpiBus, SharedPin<'a, Output<'a>>, SharedPin<'a, Output<'a>>>; +pub type DualSecondaryDisplay<'a> = + SecondaryOledDisplay<'a, DisplaySpiBus, SharedPin<'a, Output<'a>>, SharedPin<'a, Output<'a>>>; + +pub fn init_dual_displays( + spi_peripheral: SPI, + sck: SCK, + mosi: MOSI, + miso: MISO, + cs_primary: CS1, + cs_secondary: CS2, + reset_pin: RES, + dc_pin: DC, +) -> (DualPrimaryDisplay<'static>, DualSecondaryDisplay<'static>) +where + SPI: esp_hal::spi::master::Instance + 'static, + SCK: PeripheralOutput<'static>, + MOSI: PeripheralOutput<'static>, + MISO: PeripheralInput<'static>, + CS1: OutputPin + 'static, + CS2: OutputPin + 'static, + RES: OutputPin + 'static, + DC: OutputPin + 'static, +{ + let spi = Spi::new( + spi_peripheral, + SpiConfig::default() + .with_frequency(Rate::from_khz(20_000)) + .with_mode(Mode::_0), + ) + .unwrap() + .with_sck(sck) + .with_mosi(mosi) + .with_miso(miso); + + let bus_static: &'static AtomicCell<_> = Box::leak(Box::new(AtomicCell::new(spi))); + let reset_static = + SharedPin::pre_wrap(Output::new(reset_pin, Level::High, OutputConfig::default())); + let dc_static = SharedPin::pre_wrap(Output::new(dc_pin, Level::High, OutputConfig::default())); + let mut delay = Delay::new(); + + let primary = init_primary_lcd_on_bus( + bus_static, + cs_primary, + SharedPin::new(reset_static), + SharedPin::new(dc_static), + &mut delay, + ); + + let secondary = init_secondary_oled_on_bus( + bus_static, + cs_secondary, + SharedPin::new(reset_static), + SharedPin::new(dc_static), + &mut delay, + ); + + (primary, secondary) +} diff --git a/src/display/sprite.rs b/src/display/sprite.rs index a47fe7e..e2d6d5d 100644 --- a/src/display/sprite.rs +++ b/src/display/sprite.rs @@ -13,7 +13,6 @@ where return; } - let mut src_width = 1usize; while src_width * src_width < pixel_count { src_width += 1; diff --git a/src/display/tertiary_lcd.rs b/src/display/tertiary_lcd.rs index d3326ce..e066344 100644 --- a/src/display/tertiary_lcd.rs +++ b/src/display/tertiary_lcd.rs @@ -16,7 +16,9 @@ where lcd } Err(_) => { - error!("I2C tertiary LCD init failed on PCF8574T at address 0x27; check bus wiring, power, and device address"); + error!( + "I2C tertiary LCD init failed on PCF8574T at address 0x27; check bus wiring, power, and device address" + ); panic!("tertiary LCD initialization failed"); } } @@ -35,7 +37,10 @@ where return Err(e); } if let Err(e) = lcd.print(text) { - error!("I2C LCD print failed on line {line}; payload length={} and device may be busy or disconnected", text.len()); + error!( + "I2C LCD print failed on line {line}; payload length={} and device may be busy or disconnected", + text.len() + ); return Err(e); } Ok(()) @@ -52,7 +57,9 @@ where const DISPLAY_ROWS: usize = 2; if let Err(e) = lcd.clear() { - error!("I2C LCD clear failed before wrapped write; check the shared bus and display response"); + error!( + "I2C LCD clear failed before wrapped write; check the shared bus and display response" + ); return Err(e); } @@ -70,11 +77,16 @@ where }; if let Err(e) = lcd.set_cursor(0, row as u8) { - error!("I2C LCD cursor move failed while writing wrapped row {row}; bus may be busy or device unresponsive"); + error!( + "I2C LCD cursor move failed while writing wrapped row {row}; bus may be busy or device unresponsive" + ); return Err(e); } if let Err(e) = lcd.print(chunk) { - error!("I2C LCD wrapped write failed on row {row}; chunk length={} and text may exceed display width", chunk.len()); + error!( + "I2C LCD wrapped write failed on row {row}; chunk length={} and text may exceed display width", + chunk.len() + ); return Err(e); } offset += chunk.len(); diff --git a/src/drivers/nfc_pn532.rs b/src/drivers/nfc_pn532.rs index ed5448b..1cb6554 100644 --- a/src/drivers/nfc_pn532.rs +++ b/src/drivers/nfc_pn532.rs @@ -1,11 +1,9 @@ use alloc::vec::Vec; -use core::convert::Infallible; use embedded_hal::i2c::I2c; -use esp_hal::time::{Duration, Instant}; use log::{error, info}; use pn532::i2c::I2CInterface; use pn532::requests::SAMMode; -use pn532::{nb, Pn532, Request}; +use pn532::{Pn532, Request}; pub type Pn532Device = Pn532, (), 34>; @@ -29,10 +27,11 @@ where } pub async fn configure_sam(&mut self) -> Result<(), ()> { - if let Err(e) = self.pn532.process_async( - &Request::sam_configuration(SAMMode::Normal, false), - 0, - ).await { + if let Err(e) = self + .pn532 + .process_async(&Request::sam_configuration(SAMMode::Normal, false), 0) + .await + { error!("PN532 SAM configuration failed over I2C: {e:?}"); Err(()) } else { @@ -42,7 +41,11 @@ where } pub async fn poll_target(&mut self) -> Result<(), ()> { - match self.pn532.process_async(&Request::INLIST_ONE_ISO_A_TARGET, 23).await { + match self + .pn532 + .process_async(&Request::INLIST_ONE_ISO_A_TARGET, 23) + .await + { Ok(uid) => { info!("PN532 detected NFC target UID: {uid:?}"); Ok(()) @@ -78,24 +81,23 @@ where for i in (0x0B..=230).step_by(PAGES_PER_READ) { let mut parse_result = Err(()); while parse_result.is_err() { - let Ok(result) = self.pn532.process_async(&Request::ntag_read(i), PAGES_PER_READ * 4 + 1).await else { + let Ok(result) = self + .pn532 + .process_async(&Request::ntag_read(i), PAGES_PER_READ * 4 + 1) + .await + else { continue; }; parse_result = Self::parse_nfc_page(i, result); } let bytes = parse_result.unwrap(); - let bytes = if i == 0x0B { - &bytes[1..] - } else { - &bytes - }; + let bytes = if i == 0x0B { &bytes[1..] } else { &bytes }; data.extend(bytes); } Ok(data) } - + pub fn device_mut(&mut self) -> &mut Pn532Device { &mut self.pn532 } } - diff --git a/src/navigation/navigation.rs b/src/navigation/navigation.rs index d72af27..dd8fc34 100644 --- a/src/navigation/navigation.rs +++ b/src/navigation/navigation.rs @@ -1,12 +1,15 @@ use crate::card::model::Card; +use crate::display::shared_bus::DualPrimaryDisplay; use crate::navigation::inputs::ButtonAction; +use crate::navigation::inputs::Inputs; use crate::navigation::state::NavigationState; use crate::views::view::View; -use crate::{display::primary_lcd::PrimaryLcdDisplay, navigation::inputs::Inputs}; use embassy_futures::select::{Either, select}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time::{Duration, Timer}; +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::pixelcolor::Rgb565; pub type Mutex = embassy_sync::mutex::Mutex; pub type Signal = embassy_sync::signal::Signal; @@ -26,15 +29,15 @@ pub struct NewState { } pub trait Navigable { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send; + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget + Send, + D::Error: core::fmt::Debug; fn handle_input(&self, input: Action) -> impl core::future::Future + Send; } #[embassy_executor::task] -pub async fn run(mut inputs: Inputs, display: &'static mut PrimaryLcdDisplay<'static>) { +pub async fn run(mut inputs: Inputs, display: &'static mut DualPrimaryDisplay<'static>) { log::info!("starting navigation"); let mut state = NavigationState::new(); diff --git a/src/navigation/state.rs b/src/navigation/state.rs index 8fad746..63ae293 100644 --- a/src/navigation/state.rs +++ b/src/navigation/state.rs @@ -35,7 +35,6 @@ impl NavigationState { self.screens.pop(); return self.screens.last().unwrap(); } - } } } diff --git a/src/views/card_view.rs b/src/views/card_view.rs index a5440f8..5f84710 100644 --- a/src/views/card_view.rs +++ b/src/views/card_view.rs @@ -14,7 +14,6 @@ use core::future; use crate::{ card::model::{Card, Palette}, - display::primary_lcd::PrimaryLcdDisplay, navigation::navigation::{Action, Navigable}, views::view::View, }; @@ -25,10 +24,11 @@ pub struct CardView { } impl Navigable for CardView { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget, + D::Error: core::fmt::Debug, + { display.clear(Rgb565::BLACK).unwrap(); let background = Rectangle::new(Point::new(0, 0), Size::new(240, 320)); diff --git a/src/views/journal_view.rs b/src/views/journal_view.rs index 0438786..34b7632 100644 --- a/src/views/journal_view.rs +++ b/src/views/journal_view.rs @@ -7,7 +7,9 @@ use embedded_graphics::prelude::RgbColor; use embedded_graphics_core::draw_target::DrawTarget; use crate::{ - card::model::Card, display::primary_lcd::PrimaryLcdDisplay, navigation::navigation::{Action, Navigable, NewState}, views::view::View, + card::model::Card, + navigation::navigation::{Action, Navigable, NewState}, + views::view::View, }; #[derive(Debug, Clone)] @@ -17,10 +19,11 @@ pub struct JournalView { } impl Navigable for JournalView { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget, + D::Error: core::fmt::Debug, + { display.clear(Rgb565::BLACK).unwrap(); core::future::ready(()) diff --git a/src/views/main_menu.rs b/src/views/main_menu.rs index 1755d5c..ddc61e3 100644 --- a/src/views/main_menu.rs +++ b/src/views/main_menu.rs @@ -2,7 +2,6 @@ use alloc::vec; use crate::card::model::Card; use crate::card::{decoder::split_nfc_hex, mock::*}; -use crate::display::primary_lcd::PrimaryLcdDisplay; use crate::navigation::inputs::ButtonAction; use crate::views::card_view::CardView; @@ -22,10 +21,11 @@ pub struct MainMenu { } impl Navigable for MainMenu { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget, + D::Error: core::fmt::Debug, + { display.clear(Rgb565::BLACK).unwrap(); menu_item::show(display, "Scan card", 0, self.selected); diff --git a/src/views/menu_item.rs b/src/views/menu_item.rs index c9d1ee1..5802bb4 100644 --- a/src/views/menu_item.rs +++ b/src/views/menu_item.rs @@ -1,19 +1,17 @@ +use embedded_graphics::Drawable; +use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::mono_font::MonoTextStyle; use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::Point; use embedded_graphics::prelude::RgbColor; use embedded_graphics::text::Text; -use embedded_graphics::Drawable; -use crate::display::primary_lcd::PrimaryLcdDisplay; - -pub fn show<'a>( - display: &mut PrimaryLcdDisplay<'static>, - name: &str, - position: i32, - selected: i32, -) { +pub fn show<'a, D>(display: &mut D, name: &str, position: i32, selected: i32) +where + D: DrawTarget, + D::Error: core::fmt::Debug, +{ let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); let selected_style = MonoTextStyle::new(&FONT_10X20, Rgb565::BLUE); @@ -29,4 +27,3 @@ pub fn show<'a>( .draw(display) .unwrap(); } - diff --git a/src/views/scan_menu.rs b/src/views/scan_menu.rs index 7d39c65..d9c40c9 100644 --- a/src/views/scan_menu.rs +++ b/src/views/scan_menu.rs @@ -1,4 +1,3 @@ -use crate::display::primary_lcd::PrimaryLcdDisplay; use crate::navigation::inputs::ButtonAction; use crate::navigation::navigation::CARD_DATA; use crate::navigation::navigation::NewState; @@ -6,7 +5,6 @@ use crate::navigation::navigation::NewState; use alloc::format; use embedded_graphics::Drawable; use embedded_graphics::geometry::AngleUnit as _; -use embedded_graphics::geometry::Dimensions as _; use embedded_graphics::geometry::Size; use embedded_graphics::mono_font::MonoTextStyle; use embedded_graphics::mono_font::ascii::FONT_10X20; @@ -33,10 +31,11 @@ pub struct ScanMenu { } impl Navigable for ScanMenu { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget, + D::Error: core::fmt::Debug, + { let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); display.clear(Rgb565::BLACK).unwrap(); diff --git a/src/views/settings_menu.rs b/src/views/settings_menu.rs index d6f2097..f050572 100644 --- a/src/views/settings_menu.rs +++ b/src/views/settings_menu.rs @@ -1,5 +1,3 @@ -use crate::display::primary_lcd::PrimaryLcdDisplay; - use crate::navigation::navigation::{Action, Navigable, NewState}; use crate::views::{menu_item, view::View}; @@ -14,10 +12,11 @@ pub struct SettingsMenu { } impl Navigable for SettingsMenu { - fn display( - &self, - display: &mut PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget, + D::Error: core::fmt::Debug, + { display.clear(Rgb565::BLACK).unwrap(); menu_item::show(display, "System Inforation", 0, self.selected); menu_item::show(display, "Wifi Information", 1, self.selected); diff --git a/src/views/view.rs b/src/views/view.rs index 52cf112..8683638 100644 --- a/src/views/view.rs +++ b/src/views/view.rs @@ -1,3 +1,6 @@ +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::pixelcolor::Rgb565; + use crate::views::card_view::CardView; use crate::views::{ journal_view::JournalView, main_menu::MainMenu, scan_menu::ScanMenu, @@ -16,10 +19,11 @@ pub enum View { } impl Navigable for View { - fn display( - &self, - display: &mut crate::display::primary_lcd::PrimaryLcdDisplay<'static>, - ) -> impl core::future::Future + Send { + fn display(&self, display: &mut D) -> impl core::future::Future + Send + where + D: DrawTarget + Send, + D::Error: core::fmt::Debug, + { async move { match self { View::Main(main_menu) => main_menu.display(display).await,