187 lines
6.7 KiB
Rust
187 lines
6.7 KiB
Rust
#![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::shared_bus::{DualSecondaryDisplay, init_dual_displays};
|
|
use creaturedex::display::tertiary_lcd::{TertiaryI2cLcd, init_tertiary_lcd, write_wrapped};
|
|
use creaturedex::drivers::nfc_pn532::NfcPn532Driver;
|
|
use creaturedex::navigation::inputs::Inputs;
|
|
use creaturedex::navigation::navigation::{self, CARD_DATA};
|
|
use creaturedex::navigation::outputs::Outputs;
|
|
use creaturedex::network::wifi::setup_wifi;
|
|
use embassy_executor::Spawner;
|
|
use embassy_time::Instant;
|
|
use embedded_graphics::pixelcolor::BinaryColor;
|
|
use embedded_graphics::{
|
|
mono_font::{MonoTextStyle, ascii::FONT_6X10},
|
|
prelude::*,
|
|
text::Text,
|
|
};
|
|
use embedded_hal_bus::i2c::AtomicDevice;
|
|
use embedded_hal_bus::util::AtomicCell;
|
|
use esp_hal::Blocking;
|
|
use esp_hal::clock::CpuClock;
|
|
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
|
|
use esp_hal::i2c::master::{Config as I2cConfig, I2c};
|
|
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: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
|
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 oled) = init_dual_displays(
|
|
peripherals.SPI2,
|
|
peripherals.GPIO36, // sck
|
|
peripherals.GPIO35, // mosi
|
|
peripherals.GPIO37, // miso
|
|
peripherals.GPIO11, // primary cs
|
|
peripherals.GPIO13, // oled cs
|
|
peripherals.GPIO10, // primary reset
|
|
peripherals.GPIO47, // secondary reset
|
|
peripherals.GPIO12, // shared dc
|
|
);
|
|
|
|
let _secondary_oled_cs_2 =
|
|
Output::new(peripherals.GPIO14, Level::High, OutputConfig::default());
|
|
let _secondary_oled_cs_3 =
|
|
Output::new(peripherals.GPIO21, Level::High, OutputConfig::default());
|
|
|
|
let config = I2cConfig::default().with_frequency(esp_hal::time::Rate::from_khz(400));
|
|
let i2c = match I2c::new(peripherals.I2C0, config) {
|
|
Ok(bus) => bus
|
|
.with_sda(peripherals.GPIO17)
|
|
.with_scl(peripherals.GPIO18),
|
|
Err(e) => {
|
|
log::error!("Shared I2C bus initialization failed for GPIO17/GPIO18: {e:?}");
|
|
panic!("Shared I2C bus initialization failed");
|
|
}
|
|
};
|
|
let shared_i2c = Box::leak(Box::new(AtomicCell::new(i2c)));
|
|
log::info!("Shared I2C bus ready on GPIO17 (SDA) and GPIO18 (SCL)");
|
|
|
|
let mut lcd: TertiaryI2cLcd = init_tertiary_lcd(AtomicDevice::new(shared_i2c));
|
|
if let Err(e) = write_wrapped(&mut lcd, "Testing more than 16 chars what happens now?") {
|
|
log::error!(
|
|
"Tertiary LCD startup text write failed over shared I2C bus; check the shared bus, wiring, and device responses: {e}"
|
|
);
|
|
}
|
|
|
|
setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await;
|
|
|
|
let mut nfc_driver = NfcPn532Driver::new(AtomicDevice::new(shared_i2c));
|
|
if nfc_driver.configure_sam().await.is_ok() {
|
|
log::info!("NFC SAM configuration successful on the shared I2C bus");
|
|
} else {
|
|
log::error!("NFC SAM configuration failed on the shared I2C bus");
|
|
}
|
|
|
|
let button_config = InputConfig::default().with_pull(Pull::Up);
|
|
let inputs = Inputs {
|
|
up: Input::new(peripherals.GPIO38, button_config),
|
|
down: Input::new(peripherals.GPIO39, button_config),
|
|
left: Input::new(peripherals.GPIO40, button_config),
|
|
right: Input::new(peripherals.GPIO41, button_config),
|
|
back: Input::new(peripherals.GPIO8, button_config),
|
|
ok: Input::new(peripherals.GPIO0, button_config),
|
|
};
|
|
|
|
display_shit(&mut oled);
|
|
|
|
let outputs = Outputs {
|
|
primary_display: display,
|
|
secondary_display_1: oled,
|
|
// secondary_display_2: todo!(),
|
|
// secondary_display_3: todo!(),
|
|
tertiary_display: lcd,
|
|
_led_a: (),
|
|
};
|
|
|
|
log::info!("Setup complete, entering main loop");
|
|
spawner.spawn(navigation::run(inputs, outputs).expect("run task failed"));
|
|
spawner.spawn(nfc_driver_task(nfc_driver).expect("nfc driver task failed"));
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
#[allow(
|
|
clippy::large_stack_frames,
|
|
reason = "ignoring this for now because it still works"
|
|
)]
|
|
async fn nfc_driver_task(
|
|
mut nfc_driver: NfcPn532Driver<AtomicDevice<'static, I2c<'static, Blocking>>>,
|
|
) {
|
|
loop {
|
|
while CARD_DATA.lock().await.is_none() {
|
|
let start = Instant::now();
|
|
match nfc_driver.read_card_data().await {
|
|
Ok(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());
|
|
let elapsed_ms = start.elapsed().as_millis();
|
|
log::info!(
|
|
"NFC read duration: {} ms, card data length: {}",
|
|
elapsed_ms,
|
|
card_data.len()
|
|
);
|
|
}
|
|
Err(_) => {
|
|
log::info!("No NFC card found");
|
|
}
|
|
}
|
|
}
|
|
embassy_time::Timer::after(embassy_time::Duration::from_millis(1000)).await;
|
|
}
|
|
}
|
|
|
|
fn display_shit(oled: &mut DualSecondaryDisplay<'static>) {
|
|
oled.clear().unwrap();
|
|
|
|
let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
|
|
Text::new("Hello OLED", Point::new(10, 20), text_style)
|
|
.draw(oled)
|
|
.unwrap();
|
|
oled.flush().unwrap();
|
|
}
|