diff --git a/.cargo/config.toml b/.cargo/config.toml index a1297d5..aa24b04 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,13 +2,11 @@ runner = "espflash flash --monitor --chip esp32s3" [env] -ESP_LOG="info" +ESP_LOG = "debug" WM_CONN = '{"ssid": "Wokwi-GUEST", "psk": "", "data": {}}' [build] -rustflags = [ - "-C", "link-arg=-nostartfiles", -] +rustflags = ["-C", "link-arg=-nostartfiles"] target = "xtensa-esp32s3-none-elf" diff --git a/Cargo.toml b/Cargo.toml index 2e4a06e..b2f26eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,3 +83,6 @@ opt-level = 's' [features] default = [] wokwi = [] + +[lints.clippy] +manual_async_fn = "allow" diff --git a/src/background_tasks/nfc.rs b/src/background_tasks/nfc.rs index e659aaf..5aed664 100644 --- a/src/background_tasks/nfc.rs +++ b/src/background_tasks/nfc.rs @@ -1,4 +1,9 @@ -use crate::peripherals::Peripherals; +use crate::navigation::navigation::display_error; +use crate::{ + navigation::{navigation::Mutex, outputs::Outputs, state::NavigationState}, + peripherals::Peripherals, +}; +use alloc::string::ToString; use embedded_hal_bus::i2c::AtomicDevice; use esp_hal::{Blocking, i2c::master::I2c, time::Instant}; @@ -15,7 +20,9 @@ use crate::{ )] pub async fn nfc_scanner( mut nfc_driver: NfcPn532Driver>>, + outputs: &'static Mutex, peripherals: &'static Peripherals, + navigation_state: &'static Mutex, ) { loop { while CARD_DATA.lock().await.is_none() { @@ -45,7 +52,14 @@ pub async fn nfc_scanner( { Ok(()) => {} Err(error) => { - log::error!("Error storing card in flash: {:?}", error) + log::error!("Error storing card in flash: {:?}", error); + display_error( + error.to_string(), + navigation_state, + outputs, + peripherals, + ) + .await; } } diff --git a/src/bin/main.rs b/src/bin/main.rs index f001eee..e833a09 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -20,6 +20,7 @@ use creaturedex::drivers::tertiary_lcd::{ use creaturedex::navigation::navigation::Mutex; use creaturedex::navigation::inputs::Inputs; use creaturedex::navigation::navigation::{self}; +use creaturedex::navigation::state::NavigationState; use creaturedex::navigation::outputs::Outputs; use creaturedex::peripherals::Peripherals; use creaturedex::peripherals::storage::cardstore::CardStore; @@ -163,7 +164,7 @@ async fn main(spawner: Spawner) { display_shit(&mut secondaries[2], "baz 1"); display_shit_prim(&mut primary, "Hello World"); - let outputs = { + let outputs = Box::leak(Box::new(Mutex::new({ let [sec_1, sec_2, sec_3] = secondaries; Outputs { primary_display: primary, @@ -173,12 +174,14 @@ async fn main(spawner: Spawner) { tertiary_display: lcd, _led_a: (), } - }; + }))); + + let navigation_state = Box::leak(Box::new(Mutex::new(NavigationState::new()))); log::info!("Setup complete, entering main loop"); - spawner.spawn(navigation::run(inputs, outputs, peripherals).expect("run task failed")); + spawner.spawn(navigation::run(inputs, outputs, peripherals, navigation_state).expect("run task failed")); spawner.spawn( - background_tasks::nfc_scanner(nfc_driver, peripherals).expect("nfc scanner task failed"), + background_tasks::nfc_scanner(nfc_driver, outputs, peripherals, navigation_state).expect("nfc scanner task failed"), ); core::future::pending::<()>().await } diff --git a/src/navigation/navigation.rs b/src/navigation/navigation.rs index b7aa9e0..583719f 100644 --- a/src/navigation/navigation.rs +++ b/src/navigation/navigation.rs @@ -41,43 +41,56 @@ pub trait Navigable { fn handle_input(&self, input: Action) -> impl core::future::Future + Send; } -#[embassy_executor::task] -pub async fn run(mut inputs: Inputs, mut outputs: Outputs, peripherals: &'static Peripherals) { - async fn display_error( - error: String, - state: &mut NavigationState, - outputs: &mut Outputs, - peripherals: &Peripherals, - ) -> () { - let error_view = ErrorView { - error: error.to_string(), - }; - state.screens.push(View::Error(error_view)); - state - .screens - .last() - // Unwrap: we just pushed the state - .unwrap() - .display(outputs, peripherals) - .await - // Unwrap: display will panic on error in error view - .unwrap(); - } - - log::info!("starting navigation"); - - let mut state = NavigationState::new(); - if let Err(error) = state +pub async fn display_error( + error: String, + navigation_state: &Mutex, + outputs: &Mutex, + peripherals: &Peripherals, +) -> () { + let error_view = ErrorView { + error: error.to_string(), + }; + let mut state = navigation_state.lock().await; + state.screens.push(View::Error(error_view)); + let mut outs = outputs.lock().await; + state .screens .last() + // Unwrap: we just pushed the state .unwrap() - .display(&mut outputs, peripherals) + .display(&mut outs, peripherals) .await + // Unwrap: display will panic on error in error view + .unwrap(); +} + +#[embassy_executor::task] +pub async fn run( + mut inputs: Inputs, + outputs: &'static Mutex, + peripherals: &'static Peripherals, + navigation_state: &'static Mutex, +) { + log::info!("starting navigation"); + { - display_error(error.to_string(), &mut state, &mut outputs, peripherals).await; - }; + let mut outs = outputs.lock().await; + if let Err(error) = navigation_state + .lock() + .await + .screens + .last() + .unwrap() + .display(&mut outs, peripherals) + .await + { + display_error(error.to_string(), navigation_state, outputs, peripherals).await; + }; + } loop { + Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await; + let mut state = navigation_state.lock().await; let selection = select( inputs.wait_for_press(), Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)), @@ -120,17 +133,16 @@ pub async fn run(mut inputs: Inputs, mut outputs: Outputs, peripherals: &'static } state.screens.push(new_state.view); + let mut outs = outputs.lock().await; if (action != Action::Timer || new_state.redraw) && let Err(error) = state .screens .last() .unwrap() - .display(&mut outputs, peripherals) + .display(&mut outs, peripherals) .await { - display_error(error.to_string(), &mut state, &mut outputs, peripherals).await; + display_error(error.to_string(), navigation_state, outputs, peripherals).await; } - - Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await; } } diff --git a/src/peripherals/storage/flash_store.rs b/src/peripherals/storage/flash_store.rs index 76f45a1..031afad 100644 --- a/src/peripherals/storage/flash_store.rs +++ b/src/peripherals/storage/flash_store.rs @@ -21,8 +21,7 @@ impl Error for FlashStoreError {} impl Display for FlashStoreError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - use core::fmt::Debug; - self.0.fmt(f) + write!(f, "FlashStoreError:\n{:?}", self.0) } } @@ -75,7 +74,10 @@ impl FlashStore { bytes.len() ); let mut lock = self.storage.lock().await; - lock.erase(FLASH_ADDR + offset, FLASH_ADDR + bytes.len() as u32)?; + lock.erase( + FLASH_ADDR + offset, + FLASH_ADDR + offset + bytes.len() as u32, + )?; lock.write(FLASH_ADDR + offset, bytes)?; Ok(()) } diff --git a/src/views/error_view.rs b/src/views/error_view.rs index 14711a9..2524f69 100644 --- a/src/views/error_view.rs +++ b/src/views/error_view.rs @@ -34,6 +34,15 @@ impl Navigable for ErrorView { _: &Peripherals, ) -> impl core::future::Future>> + Send { async move { + outputs + .primary_display + .clear(Rgb565::BLACK) + .unwrap_or_else(|error| { + panic!( + "Error: {error:?}\nDraw error while rendering ErrorView: {}", + self.error + ) + }); let style = MonoTextStyle::new(&FONT_10X20, Rgb565::RED); let display_area = outputs.primary_display.bounding_box(); Text::new( @@ -44,7 +53,7 @@ impl Navigable for ErrorView { .draw(&mut outputs.primary_display) .unwrap_or_else(|error| { panic!( - "Error: {error:?}\nDraw error while rendering error: {}", + "Error: {error:?}\nDraw error while rendering ErrorView: {}", self.error ) }); @@ -55,13 +64,13 @@ impl Navigable for ErrorView { .alignment(HorizontalAlignment::Center) .build(); - let bounds = Rectangle::new(Point::new(0, 30), display_area.size); + let bounds = Rectangle::new(Point::new(0, 50), display_area.size); TextBox::with_textbox_style(&self.error.to_string(), bounds, style, textbox_style) .draw(&mut outputs.primary_display) .unwrap_or_else(|error| { panic!( - "Error: {error:?}\nDraw error while rendering error: {}", + "Error: {error:?}\nDraw error while rendering ErrorView: {}", self.error ) }); diff --git a/src/views/flash_info_view.rs b/src/views/flash_info_view.rs index 54a0bc6..ee7b4f9 100644 --- a/src/views/flash_info_view.rs +++ b/src/views/flash_info_view.rs @@ -34,6 +34,10 @@ impl Navigable for FlashInfoView { peripherals: &Peripherals, ) -> impl core::future::Future>> + Send { async move { + outputs + .primary_display + .clear(Rgb565::BLACK) + .map_err(PrimaryDisplayError::from)?; let _style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); let mut magic_bytes: [u8; MAGIC_REGION.size] = [0; MAGIC_REGION.size]; peripherals @@ -55,7 +59,7 @@ impl Navigable for FlashInfoView { let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); let textbox_style = TextBoxStyleBuilder::new() .height_mode(HeightMode::FitToText) - .alignment(HorizontalAlignment::Center) + .alignment(HorizontalAlignment::Justified) .build(); let display_area = outputs.primary_display.bounding_box(); diff --git a/src/views/settings_menu.rs b/src/views/settings_menu.rs index 47ceee1..c0f3fc9 100644 --- a/src/views/settings_menu.rs +++ b/src/views/settings_menu.rs @@ -12,7 +12,7 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::RgbColor; use embedded_graphics_core::draw_target::DrawTarget; -pub const MAX_SELECTED: i32 = 2; +pub const MAX_SELECTED: i32 = 3; #[derive(Debug, Clone)] pub struct SettingsMenu { @@ -27,7 +27,9 @@ impl Navigable for SettingsMenu { ) -> impl core::future::Future>> + Send { async move { let display = &mut outputs.primary_display; - display.clear(Rgb565::BLACK).unwrap(); + display + .clear(Rgb565::BLACK) + .map_err(PrimaryDisplayError::from)?; menu_item::show(display, "System Inforation", 0, self.selected) .map_err(PrimaryDisplayError::from)?; menu_item::show(display, "Wifi Information", 1, self.selected)