Compare commits
1
Commits
main
...
16e45d2c11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16e45d2c11 |
@@ -1,4 +1,6 @@
|
|||||||
|
use crate::storage::cardstore::CardStore;
|
||||||
use embedded_hal_bus::i2c::AtomicDevice;
|
use embedded_hal_bus::i2c::AtomicDevice;
|
||||||
|
use esp_hal::rtc_cntl::Rtc;
|
||||||
use esp_hal::{Blocking, i2c::master::I2c, time::Instant};
|
use esp_hal::{Blocking, i2c::master::I2c, time::Instant};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -14,6 +16,8 @@ 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>>>,
|
||||||
|
mut card_store: CardStore,
|
||||||
|
rtc: Rtc<'static>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
while CARD_DATA.lock().await.is_none() {
|
while CARD_DATA.lock().await.is_none() {
|
||||||
@@ -24,10 +28,22 @@ pub async fn nfc_scanner(
|
|||||||
log::error!("Failed to split NFC card data");
|
log::error!("Failed to split NFC card data");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
CARD_DATA
|
let card = match Card::try_from(split_data) {
|
||||||
.lock()
|
Ok(card) => card,
|
||||||
.await
|
Err(err) => {
|
||||||
.replace(Card::try_from(split_data).unwrap());
|
log::error!("Invalid card data: {err}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CARD_DATA.lock().await.replace(card);
|
||||||
|
|
||||||
|
match card_store.save_raw_card(split_data, rtc.current_time_us()) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(error) => {
|
||||||
|
log::error!("Error storing card in flash: {:?}", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let elapsed_ms = start.elapsed().as_millis();
|
let elapsed_ms = start.elapsed().as_millis();
|
||||||
log::info!(
|
log::info!(
|
||||||
"NFC read duration: {} ms, card data length: {}",
|
"NFC read duration: {} ms, card data length: {}",
|
||||||
@@ -35,8 +51,8 @@ pub async fn nfc_scanner(
|
|||||||
card_data.len()
|
card_data.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(_) => {
|
||||||
log::error!("NFC read failed: {e}");
|
log::info!("No NFC card found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -22,7 +22,6 @@ use creaturedex::network::wifi::setup_wifi;
|
|||||||
use creaturedex::storage::cardstore::CardStore;
|
use creaturedex::storage::cardstore::CardStore;
|
||||||
use creaturedex::storage::store::Store;
|
use creaturedex::storage::store::Store;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_time::Instant;
|
|
||||||
use embedded_graphics::pixelcolor::BinaryColor;
|
use embedded_graphics::pixelcolor::BinaryColor;
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
mono_font::{MonoTextStyle, ascii::FONT_6X10},
|
mono_font::{MonoTextStyle, ascii::FONT_6X10},
|
||||||
@@ -30,13 +29,13 @@ use embedded_graphics::{
|
|||||||
text::Text,
|
text::Text,
|
||||||
};
|
};
|
||||||
use embedded_hal_bus::i2c::AtomicDevice;
|
use embedded_hal_bus::i2c::AtomicDevice;
|
||||||
use embedded_hal_bus::util::AtomicCell;
|
|
||||||
use esp_hal::Blocking;
|
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
|
use esp_hal::rtc_cntl::Rtc;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
||||||
error!("{}", panic_info);
|
error!("{}", panic_info);
|
||||||
@@ -148,7 +147,10 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
log::info!("Setup complete, entering main loop");
|
log::info!("Setup complete, entering main loop");
|
||||||
spawner.spawn(navigation::run(inputs, outputs).expect("run task failed"));
|
spawner.spawn(navigation::run(inputs, outputs).expect("run task failed"));
|
||||||
spawner.spawn(background_tasks::nfc_scanner(nfc_driver).expect("nfc scanner task failed"));
|
spawner.spawn(
|
||||||
|
background_tasks::nfc_scanner(nfc_driver, card_store, rtc)
|
||||||
|
.expect("nfc scanner task failed"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_shit(oled: &mut SecondaryDisplay<'static>, text: &str) {
|
fn display_shit(oled: &mut SecondaryDisplay<'static>, text: &str) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod card_view;
|
pub mod card_view;
|
||||||
|
pub mod flash_info_view;
|
||||||
pub mod journal_view;
|
pub mod journal_view;
|
||||||
pub mod main_menu;
|
pub mod main_menu;
|
||||||
pub mod menu_item;
|
pub mod menu_item;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
use crate::navigation::inputs::ButtonAction;
|
||||||
|
use crate::navigation::navigation::Action;
|
||||||
|
use crate::navigation::navigation::Navigable;
|
||||||
|
use crate::navigation::navigation::NewState;
|
||||||
|
use crate::navigation::outputs::Outputs;
|
||||||
|
use crate::views::view::View;
|
||||||
|
use embedded_graphics::mono_font::MonoTextStyle;
|
||||||
|
use embedded_graphics::mono_font::ascii::FONT_10X20;
|
||||||
|
use embedded_graphics::pixelcolor::Rgb565;
|
||||||
|
use embedded_graphics::prelude::DrawTarget;
|
||||||
|
use embedded_graphics::prelude::RgbColor;
|
||||||
|
use embedded_graphics::text::Text;
|
||||||
|
|
||||||
|
use embedded_graphics::prelude::Point;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FlashInfoView {}
|
||||||
|
|
||||||
|
impl Navigable for FlashInfoView {
|
||||||
|
fn display(&self, outputs: &mut Outputs) -> impl core::future::Future<Output = ()> + Send {
|
||||||
|
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
||||||
|
Text::new("Flash Initialized: {:?}", Point::new(40, 40), style);
|
||||||
|
|
||||||
|
core::future::ready(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = NewState> + Send {
|
||||||
|
async move {
|
||||||
|
let Action::Button(input) = input else {
|
||||||
|
// Skip timer inputs
|
||||||
|
return NewState {
|
||||||
|
view: View::FlashInfo(self.clone()),
|
||||||
|
replace_view: true,
|
||||||
|
redraw: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_menu = match input {
|
||||||
|
_ => View::FlashInfo(self.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
NewState {
|
||||||
|
replace_view: matches!(new_menu, View::FlashInfo(_)),
|
||||||
|
view: new_menu,
|
||||||
|
redraw: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
use crate::navigation::navigation::{Action, Navigable, NewState};
|
use crate::navigation::navigation::{Action, Navigable, NewState};
|
||||||
use crate::navigation::outputs::Outputs;
|
use crate::navigation::outputs::Outputs;
|
||||||
use crate::views::{menu_item, view::View};
|
use crate::views::{flash_info_view::FlashInfoView, menu_item, view::View};
|
||||||
|
|
||||||
|
use crate::navigation::inputs::ButtonAction;
|
||||||
|
|
||||||
use embedded_graphics::pixelcolor::Rgb565;
|
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: i8 = 2;
|
|
||||||
|
pub const MAX_SELECTED: i32 = 2;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SettingsMenu {
|
pub struct SettingsMenu {
|
||||||
@@ -18,16 +21,50 @@ impl Navigable for SettingsMenu {
|
|||||||
display.clear(Rgb565::BLACK).unwrap();
|
display.clear(Rgb565::BLACK).unwrap();
|
||||||
menu_item::show(display, "System Inforation", 0, self.selected);
|
menu_item::show(display, "System Inforation", 0, self.selected);
|
||||||
menu_item::show(display, "Wifi Information", 1, self.selected);
|
menu_item::show(display, "Wifi Information", 1, self.selected);
|
||||||
|
menu_item::show(display, "Flash Information", 2, self.selected);
|
||||||
|
|
||||||
core::future::ready(())
|
core::future::ready(())
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
async move {
|
async move {
|
||||||
|
let Action::Button(input) = input else {
|
||||||
|
// Skip timer inputs
|
||||||
|
return NewState {
|
||||||
|
view: View::Settings(self.clone()),
|
||||||
|
replace_view: true,
|
||||||
|
redraw: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_menu = match input {
|
||||||
|
ButtonAction::Up => {
|
||||||
|
let new_selected = if (self.selected - 1) < 0 {
|
||||||
|
MAX_SELECTED - 1
|
||||||
|
} else {
|
||||||
|
self.selected - 1
|
||||||
|
};
|
||||||
|
View::Settings(SettingsMenu {
|
||||||
|
selected: new_selected,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ButtonAction::Down => {
|
||||||
|
let new_selected = self.selected.wrapping_add(1) % MAX_SELECTED;
|
||||||
|
View::Settings(SettingsMenu {
|
||||||
|
selected: new_selected,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ButtonAction::Ok => match self.selected {
|
||||||
|
2 => View::FlashInfo(FlashInfoView {}),
|
||||||
|
_ => View::Settings(self.clone()),
|
||||||
|
},
|
||||||
|
_ => View::Settings(self.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
NewState {
|
NewState {
|
||||||
view: View::Settings(SettingsMenu { selected: 0 }),
|
replace_view: matches!(new_menu, View::Settings(_)),
|
||||||
replace_view: true,
|
view: new_menu,
|
||||||
redraw: !matches!(input, Action::Timer),
|
redraw: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -1,8 +1,8 @@
|
|||||||
use crate::navigation::outputs::Outputs;
|
use crate::navigation::outputs::Outputs;
|
||||||
use crate::views::card_view::CardView;
|
use crate::views::card_view::CardView;
|
||||||
use crate::views::{
|
use crate::views::{
|
||||||
journal_view::JournalView, main_menu::MainMenu, scan_menu::ScanMenu,
|
flash_info_view::FlashInfoView, journal_view::JournalView, main_menu::MainMenu,
|
||||||
settings_menu::SettingsMenu,
|
scan_menu::ScanMenu, settings_menu::SettingsMenu,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::navigation::navigation::{Navigable, NewState};
|
use crate::navigation::navigation::{Navigable, NewState};
|
||||||
@@ -14,6 +14,7 @@ pub enum View {
|
|||||||
Settings(SettingsMenu),
|
Settings(SettingsMenu),
|
||||||
Journal(JournalView),
|
Journal(JournalView),
|
||||||
Card(CardView),
|
Card(CardView),
|
||||||
|
FlashInfo(FlashInfoView),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Navigable for View {
|
impl Navigable for View {
|
||||||
@@ -25,6 +26,7 @@ impl Navigable for View {
|
|||||||
View::Settings(settings_menu) => settings_menu.display(outputs).await,
|
View::Settings(settings_menu) => settings_menu.display(outputs).await,
|
||||||
View::Journal(journal_view) => journal_view.display(outputs).await,
|
View::Journal(journal_view) => journal_view.display(outputs).await,
|
||||||
View::Card(card_view) => card_view.display(outputs).await,
|
View::Card(card_view) => card_view.display(outputs).await,
|
||||||
|
View::FlashInfo(flash_info_view) => flash_info_view.display(outputs).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,6 +42,7 @@ impl Navigable for View {
|
|||||||
View::Settings(settings_menu) => settings_menu.handle_input(input).await,
|
View::Settings(settings_menu) => settings_menu.handle_input(input).await,
|
||||||
View::Journal(journal_view) => journal_view.handle_input(input).await,
|
View::Journal(journal_view) => journal_view.handle_input(input).await,
|
||||||
View::Card(card_view) => card_view.handle_input(input).await,
|
View::Card(card_view) => card_view.handle_input(input).await,
|
||||||
|
View::FlashInfo(flash_info_view) => flash_info_view.handle_input(input).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user