#![no_std] #![no_main] #![deny( clippy::mem_forget, reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ holding buffers for the duration of a data transfer." )] #![deny(clippy::large_stack_frames)] 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::drivers::nfc_pn532::NfcPn532Driver; use creaturedex::navigation::inputs::Inputs; use creaturedex::navigation::navigation::{self, CARD_DATA}; use creaturedex::network::wifi::setup_wifi; use embassy_executor::Spawner; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Pull}; use esp_hal::timer::timg::TimerGroup; use log::error; #[panic_handler] fn panic(panic_info: &core::panic::PanicInfo) -> ! { error!("{}", panic_info); loop {} } extern crate alloc; const HEAP_SIZE: usize = 73744; // This creates a default app-descriptor required by the esp-idf bootloader. // For more information see: esp_bootloader_esp_idf::esp_app_desc!(); #[allow( clippy::large_stack_frames, reason = "it's not unusual to allocate larger buffers etc. in main" )] #[esp_rtos::main] async fn main(spawner: Spawner) { esp_println::logger::init_logger_from_env(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: HEAP_SIZE); let sw_interrupt = esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); 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( peripherals.SPI2, peripherals.GPIO36, // sck peripherals.GPIO35, // mosi peripherals.GPIO37, // miso peripherals.GPIO11, // primary cs peripherals.GPIO10, // shared reset peripherals.GPIO12, // shared dc ))); setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await; let mut nfc_driver = NfcPn532Driver::new(peripherals.I2C0, peripherals.GPIO17, peripherals.GPIO18); if nfc_driver.configure_sam().await.is_ok() { log::info!("NFC SAM configuration successful"); } else { log::error!("NFC SAM configuration failed"); } let button_config = InputConfig::default().with_pull(Pull::Up); let inputs = Inputs { up: Input::new(peripherals.GPIO38, button_config.clone()), down: Input::new(peripherals.GPIO39, button_config.clone()), left: Input::new(peripherals.GPIO40, button_config.clone()), right: Input::new(peripherals.GPIO41, button_config.clone()), back: Input::new(peripherals.GPIO42, button_config.clone()), ok: Input::new(peripherals.GPIO45, button_config.clone()), }; 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<'static>) { loop { while CARD_DATA.lock().await.is_none() { match nfc_driver.read_card_data().await { Ok(card_data) => { log::info!("NFC Card Data Read: {:?}", card_data); let Some(split_data) = split_nfc_hex(&card_data) else { log::error!("Failed to split NFC card data"); continue; }; CARD_DATA.lock().await.replace(Card::try_from(split_data).unwrap()); } Err(_) => { log::info!("No NFC card found"); } } } embassy_time::Timer::after(embassy_time::Duration::from_millis(1000)).await; } }