| 1 | //! The `App` abstraction: each menu feature owns its own render/poll loop and |
| 2 | //! returns when the user presses BACK. |
| 3 | //! |
| 4 | //! This replaces the Arduino per-feature blocking `while(1)` loops. An app |
| 5 | //! borrows the shared resources through [`AppCtx`] for the duration of `run` |
| 6 | //! and releases them on return, so the menu regains control afterwards. |
| 7 | |
| 8 | use esp_idf_hal::delay::FreeRtos; |
| 9 | |
| 10 | use crate::board::board::Board; |
| 11 | use crate::drivers::buttons::{debounce, Buttons}; |
| 12 | use crate::drivers::display::Display; |
| 13 | use crate::ui::widgets; |
| 14 | |
| 15 | /// How an app finished. Only BACK exists for now; future apps may add variants |
| 16 | /// (e.g. requesting a restart). |
| 17 | pub enum AppResult { |
| 18 | Back, |
| 19 | } |
| 20 | |
| 21 | /// Everything an app may touch, borrowed for the length of `run`. |
| 22 | pub struct AppCtx<'a> { |
| 23 | pub display: &'a mut Display, |
| 24 | pub buttons: &'a mut Buttons, |
| 25 | pub board: &'a mut Board, |
| 26 | } |
| 27 | |
| 28 | pub trait App { |
| 29 | fn run(&mut self, ctx: &mut AppCtx) -> AppResult; |
| 30 | } |
| 31 | |
| 32 | /// Placeholder app for features awaiting their phase. Shows a name screen and |
| 33 | /// waits for BACK. |
| 34 | pub struct StubApp { |
| 35 | pub name: &'static str, |
| 36 | } |
| 37 | |
| 38 | impl App for StubApp { |
| 39 | fn run(&mut self, ctx: &mut AppCtx) -> AppResult { |
| 40 | widgets::stub(ctx.display, self.name); |
| 41 | loop { |
| 42 | if ctx.buttons.back() { |
| 43 | debounce(); |
| 44 | return AppResult::Back; |
| 45 | } |
| 46 | FreeRtos::delay_ms(20); |
| 47 | } |
| 48 | } |
| 49 | } |