#![no_std] #![no_main] #![feature(ascii_char)] #![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 core::mem::MaybeUninit; use alloc::{boxed::Box, format, string::ToString}; use esp_hal::{ clock::CpuClock, delay::Delay, gpio::{InputConfig, Level, Output, OutputConfig}, interrupt::software::SoftwareInterruptControl, main, spi::master::{Config, Spi}, system::Stack, time::Rate, timer::timg::TimerGroup, uart::{self, Uart}, }; use esp_backtrace as _; use crate::{ async_io::AsyncIO, at_commands::ATCommands, display::{Display, Position, Rgb565, SetAddressMode}, font::FontRenderer, state::StateManager, states::InitATState, }; extern crate alloc; mod async_io; mod at_commands; mod display; mod font; mod state; mod states; // 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" )] #[main] fn main() -> ! { // generator version: 1.3.0 // generator parameters: --chip esp32 -o esp32-wroom-32e -o alloc -o esp-backtrace -o log -o vscode esp_println::logger::init_logger_from_env(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); // The following pins are used to bootstrap the chip. They are available // for use, but check the datasheet of the module for more information on them. // - GPIO0 // - GPIO2 // - GPIO5 // - GPIO12 // - GPIO15 // These GPIO pins are in use by some feature of the module and should not be used. let _ = peripherals.GPIO6; let _ = peripherals.GPIO7; let _ = peripherals.GPIO8; let _ = peripherals.GPIO9; let _ = peripherals.GPIO10; let _ = peripherals.GPIO11; let _ = peripherals.GPIO16; let _ = peripherals.GPIO17; esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 98768); let spi = Spi::new( peripherals.SPI2, Config::default() .with_frequency(Rate::from_mhz(80)) .with_mode(esp_hal::spi::Mode::_2) .with_read_bit_order(esp_hal::spi::BitOrder::MsbFirst) .with_write_bit_order(esp_hal::spi::BitOrder::MsbFirst), ) .unwrap() .with_sck(peripherals.GPIO5) .with_mosi(peripherals.GPIO19) .with_miso(peripherals.GPIO21) .with_cs(peripherals.GPIO4); let rst = Output::new(peripherals.GPIO14, Level::Low, OutputConfig::default()); let dc = Output::new(peripherals.GPIO32, Level::Low, OutputConfig::default()); let mut display = Display { spi, dc, rst, delay: Delay::new(), }; display.init(SetAddressMode { color_order: display::ColorOrder::Rgb, ..Default::default() }); display.set_tearing(display::TearingMode::Off); let sim_rst = Output::new(peripherals.GPIO27, Level::High, OutputConfig::default()); let sim_pwr_key = Output::new(peripherals.GPIO12, Level::High, OutputConfig::default()); let uart = Uart::new( peripherals.UART2, uart::Config::default() .with_baudrate(115200) .with_data_bits(uart::DataBits::_8) .with_parity(uart::Parity::None) .with_sw_flow_ctrl(uart::SwFlowControl::Disabled), ) .unwrap() .with_rx(peripherals.GPIO7) .with_tx(peripherals.GPIO8); let mut at_commands = ATCommands::new(sim_rst, sim_pwr_key, uart); let font_renderer = FontRenderer::create(30); display.clear(Rgb565::black().as_color()); font_renderer.render( &mut display, "Please wait", Position::new(120, 120), font::HorizontalAlignment::Center, font::VerticalAlignment::Center, Rgb565::black(), Rgb565::white(), ); at_commands.init(); let async_io = AsyncIO::default(); let mut state_mgr = StateManager { data: state::StateData::from(display, async_io.clone()), curr_state: Box::new(InitATState::default()), }; static mut THREAD_2_STACK: Stack<{ 30 * 1024 }> = esp_hal::system::Stack { mem: MaybeUninit::new([0u8; 30 * 1024]), }; let timg0 = TimerGroup::new(peripherals.TIMG0); let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); esp_rtos::start(timg0.timer0, software_interrupt.software_interrupt0); esp_rtos::start_second_core( peripherals.CPU_CTRL, software_interrupt.software_interrupt1, unsafe { #[allow(static_mut_refs)] &mut THREAD_2_STACK }, { let io = async_io.clone(); || thread_2_main(io, at_commands) }, ); loop { state_mgr.update(); state_mgr.draw(); } // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples } fn thread_2_main(async_io: AsyncIO, mut at_commands: ATCommands<'static, 'static>) { loop { if let Some(command) = unsafe { async_io.check_at_command() } { let response = match command { async_io::ConstructedATCommand::Single(cmd) => at_commands.raw_command(cmd), async_io::ConstructedATCommand::AddInfo(cmd, add) => { at_commands.raw_two_part_command(cmd, add) } }; unsafe { async_io.set_at_response(response) }; } if let Some(event) = at_commands.readline() { log::info!("Event: {}", event); } } }