Compare commits
6
Commits
9ee4b68306
...
91948bdcf5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91948bdcf5 | ||
|
|
3c657045ca | ||
|
|
3d36885e11 | ||
|
|
af964bcc37 | ||
|
|
ccf16522bb | ||
|
|
5ac8fe9610 |
+2
-4
@@ -2,13 +2,11 @@
|
|||||||
runner = "espflash flash --monitor --chip esp32s3"
|
runner = "espflash flash --monitor --chip esp32s3"
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
ESP_LOG="info"
|
ESP_LOG = "debug"
|
||||||
WM_CONN = '{"ssid": "Wokwi-GUEST", "psk": "", "data": {}}'
|
WM_CONN = '{"ssid": "Wokwi-GUEST", "psk": "", "data": {}}'
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
rustflags = [
|
rustflags = ["-C", "link-arg=-nostartfiles"]
|
||||||
"-C", "link-arg=-nostartfiles",
|
|
||||||
]
|
|
||||||
|
|
||||||
target = "xtensa-esp32s3-none-elf"
|
target = "xtensa-esp32s3-none-elf"
|
||||||
|
|
||||||
|
|||||||
@@ -83,3 +83,6 @@ opt-level = 's'
|
|||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
wokwi = []
|
wokwi = []
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
manual_async_fn = "allow"
|
||||||
|
|||||||
@@ -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 embedded_hal_bus::i2c::AtomicDevice;
|
||||||
use esp_hal::{Blocking, i2c::master::I2c, time::Instant};
|
use esp_hal::{Blocking, i2c::master::I2c, time::Instant};
|
||||||
|
|
||||||
@@ -15,7 +20,9 @@ use crate::{
|
|||||||
)]
|
)]
|
||||||
pub async fn nfc_scanner(
|
pub async fn nfc_scanner(
|
||||||
mut nfc_driver: NfcPn532Driver<AtomicDevice<'static, I2c<'static, Blocking>>>,
|
mut nfc_driver: NfcPn532Driver<AtomicDevice<'static, I2c<'static, Blocking>>>,
|
||||||
|
outputs: &'static Mutex<Outputs>,
|
||||||
peripherals: &'static Peripherals,
|
peripherals: &'static Peripherals,
|
||||||
|
navigation_state: &'static Mutex<NavigationState>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
while CARD_DATA.lock().await.is_none() {
|
while CARD_DATA.lock().await.is_none() {
|
||||||
@@ -45,7 +52,14 @@ pub async fn nfc_scanner(
|
|||||||
{
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(error) => {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -20,6 +20,7 @@ use creaturedex::drivers::tertiary_lcd::{
|
|||||||
use creaturedex::navigation::navigation::Mutex;
|
use creaturedex::navigation::navigation::Mutex;
|
||||||
use creaturedex::navigation::inputs::Inputs;
|
use creaturedex::navigation::inputs::Inputs;
|
||||||
use creaturedex::navigation::navigation::{self};
|
use creaturedex::navigation::navigation::{self};
|
||||||
|
use creaturedex::navigation::state::NavigationState;
|
||||||
use creaturedex::navigation::outputs::Outputs;
|
use creaturedex::navigation::outputs::Outputs;
|
||||||
use creaturedex::peripherals::Peripherals;
|
use creaturedex::peripherals::Peripherals;
|
||||||
use creaturedex::peripherals::storage::cardstore::CardStore;
|
use creaturedex::peripherals::storage::cardstore::CardStore;
|
||||||
@@ -163,7 +164,7 @@ async fn main(spawner: Spawner) {
|
|||||||
display_shit(&mut secondaries[2], "baz 1");
|
display_shit(&mut secondaries[2], "baz 1");
|
||||||
display_shit_prim(&mut primary, "Hello World");
|
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;
|
let [sec_1, sec_2, sec_3] = secondaries;
|
||||||
Outputs {
|
Outputs {
|
||||||
primary_display: primary,
|
primary_display: primary,
|
||||||
@@ -173,12 +174,14 @@ async fn main(spawner: Spawner) {
|
|||||||
tertiary_display: lcd,
|
tertiary_display: lcd,
|
||||||
_led_a: (),
|
_led_a: (),
|
||||||
}
|
}
|
||||||
};
|
})));
|
||||||
|
|
||||||
|
let navigation_state = Box::leak(Box::new(Mutex::new(NavigationState::new())));
|
||||||
|
|
||||||
log::info!("Setup complete, entering main loop");
|
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(
|
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
|
core::future::pending::<()>().await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,43 +41,56 @@ pub trait Navigable {
|
|||||||
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = NewState> + Send;
|
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = NewState> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
pub async fn display_error(
|
||||||
pub async fn run(mut inputs: Inputs, mut outputs: Outputs, peripherals: &'static Peripherals) {
|
|
||||||
async fn display_error(
|
|
||||||
error: String,
|
error: String,
|
||||||
state: &mut NavigationState,
|
navigation_state: &Mutex<NavigationState>,
|
||||||
outputs: &mut Outputs,
|
outputs: &Mutex<Outputs>,
|
||||||
peripherals: &Peripherals,
|
peripherals: &Peripherals,
|
||||||
) -> () {
|
) -> () {
|
||||||
let error_view = ErrorView {
|
let error_view = ErrorView {
|
||||||
error: error.to_string(),
|
error: error.to_string(),
|
||||||
};
|
};
|
||||||
|
let mut state = navigation_state.lock().await;
|
||||||
state.screens.push(View::Error(error_view));
|
state.screens.push(View::Error(error_view));
|
||||||
|
let mut outs = outputs.lock().await;
|
||||||
state
|
state
|
||||||
.screens
|
.screens
|
||||||
.last()
|
.last()
|
||||||
// Unwrap: we just pushed the state
|
// Unwrap: we just pushed the state
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.display(outputs, peripherals)
|
.display(&mut outs, peripherals)
|
||||||
.await
|
.await
|
||||||
// Unwrap: display will panic on error in error view
|
// Unwrap: display will panic on error in error view
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
pub async fn run(
|
||||||
|
mut inputs: Inputs,
|
||||||
|
outputs: &'static Mutex<Outputs>,
|
||||||
|
peripherals: &'static Peripherals,
|
||||||
|
navigation_state: &'static Mutex<NavigationState>,
|
||||||
|
) {
|
||||||
log::info!("starting navigation");
|
log::info!("starting navigation");
|
||||||
|
|
||||||
let mut state = NavigationState::new();
|
{
|
||||||
if let Err(error) = state
|
let mut outs = outputs.lock().await;
|
||||||
|
if let Err(error) = navigation_state
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
.screens
|
.screens
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.display(&mut outputs, peripherals)
|
.display(&mut outs, peripherals)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
display_error(error.to_string(), &mut state, &mut outputs, peripherals).await;
|
display_error(error.to_string(), navigation_state, outputs, peripherals).await;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await;
|
||||||
|
let mut state = navigation_state.lock().await;
|
||||||
let selection = select(
|
let selection = select(
|
||||||
inputs.wait_for_press(),
|
inputs.wait_for_press(),
|
||||||
Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)),
|
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);
|
state.screens.push(new_state.view);
|
||||||
|
|
||||||
|
let mut outs = outputs.lock().await;
|
||||||
if (action != Action::Timer || new_state.redraw)
|
if (action != Action::Timer || new_state.redraw)
|
||||||
&& let Err(error) = state
|
&& let Err(error) = state
|
||||||
.screens
|
.screens
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.display(&mut outputs, peripherals)
|
.display(&mut outs, peripherals)
|
||||||
.await
|
.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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ impl Error for FlashStoreError {}
|
|||||||
|
|
||||||
impl Display for FlashStoreError {
|
impl Display for FlashStoreError {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
use core::fmt::Debug;
|
write!(f, "FlashStoreError:\n{:?}", self.0)
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +74,10 @@ impl FlashStore {
|
|||||||
bytes.len()
|
bytes.len()
|
||||||
);
|
);
|
||||||
let mut lock = self.storage.lock().await;
|
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)?;
|
lock.write(FLASH_ADDR + offset, bytes)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -34,6 +34,15 @@ impl Navigable for ErrorView {
|
|||||||
_: &Peripherals,
|
_: &Peripherals,
|
||||||
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
||||||
async move {
|
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 style = MonoTextStyle::new(&FONT_10X20, Rgb565::RED);
|
||||||
let display_area = outputs.primary_display.bounding_box();
|
let display_area = outputs.primary_display.bounding_box();
|
||||||
Text::new(
|
Text::new(
|
||||||
@@ -44,7 +53,7 @@ impl Navigable for ErrorView {
|
|||||||
.draw(&mut outputs.primary_display)
|
.draw(&mut outputs.primary_display)
|
||||||
.unwrap_or_else(|error| {
|
.unwrap_or_else(|error| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error: {error:?}\nDraw error while rendering error: {}",
|
"Error: {error:?}\nDraw error while rendering ErrorView: {}",
|
||||||
self.error
|
self.error
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@@ -55,13 +64,13 @@ impl Navigable for ErrorView {
|
|||||||
.alignment(HorizontalAlignment::Center)
|
.alignment(HorizontalAlignment::Center)
|
||||||
.build();
|
.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)
|
TextBox::with_textbox_style(&self.error.to_string(), bounds, style, textbox_style)
|
||||||
.draw(&mut outputs.primary_display)
|
.draw(&mut outputs.primary_display)
|
||||||
.unwrap_or_else(|error| {
|
.unwrap_or_else(|error| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error: {error:?}\nDraw error while rendering error: {}",
|
"Error: {error:?}\nDraw error while rendering ErrorView: {}",
|
||||||
self.error
|
self.error
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ impl Navigable for FlashInfoView {
|
|||||||
peripherals: &Peripherals,
|
peripherals: &Peripherals,
|
||||||
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
||||||
async move {
|
async move {
|
||||||
|
outputs
|
||||||
|
.primary_display
|
||||||
|
.clear(Rgb565::BLACK)
|
||||||
|
.map_err(PrimaryDisplayError::from)?;
|
||||||
let _style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
let _style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
||||||
let mut magic_bytes: [u8; MAGIC_REGION.size] = [0; MAGIC_REGION.size];
|
let mut magic_bytes: [u8; MAGIC_REGION.size] = [0; MAGIC_REGION.size];
|
||||||
peripherals
|
peripherals
|
||||||
@@ -55,7 +59,7 @@ impl Navigable for FlashInfoView {
|
|||||||
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
||||||
let textbox_style = TextBoxStyleBuilder::new()
|
let textbox_style = TextBoxStyleBuilder::new()
|
||||||
.height_mode(HeightMode::FitToText)
|
.height_mode(HeightMode::FitToText)
|
||||||
.alignment(HorizontalAlignment::Center)
|
.alignment(HorizontalAlignment::Justified)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let display_area = outputs.primary_display.bounding_box();
|
let display_area = outputs.primary_display.bounding_box();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use embedded_graphics::pixelcolor::Rgb565;
|
|||||||
use embedded_graphics::prelude::RgbColor;
|
use embedded_graphics::prelude::RgbColor;
|
||||||
use embedded_graphics_core::draw_target::DrawTarget;
|
use embedded_graphics_core::draw_target::DrawTarget;
|
||||||
|
|
||||||
pub const MAX_SELECTED: i32 = 2;
|
pub const MAX_SELECTED: i32 = 3;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SettingsMenu {
|
pub struct SettingsMenu {
|
||||||
@@ -27,7 +27,9 @@ impl Navigable for SettingsMenu {
|
|||||||
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
) -> impl core::future::Future<Output = Result<(), Box<dyn error::Error>>> + Send {
|
||||||
async move {
|
async move {
|
||||||
let display = &mut outputs.primary_display;
|
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)
|
menu_item::show(display, "System Inforation", 0, self.selected)
|
||||||
.map_err(PrimaryDisplayError::from)?;
|
.map_err(PrimaryDisplayError::from)?;
|
||||||
menu_item::show(display, "Wifi Information", 1, self.selected)
|
menu_item::show(display, "Wifi Information", 1, self.selected)
|
||||||
|
|||||||
Reference in New Issue
Block a user