#![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()), }; let pull_down_cfg = InputConfig::default().with_pull(esp_hal::gpio::Pull::None); let pull_up_cfg = InputConfig::default().with_pull(esp_hal::gpio::Pull::None); // let mut input_1 = Output::new(peripherals.GPIO4, Level::High, OutputConfig::default()); // let mut input_2 = Output::new(peripherals.GPIO36, Level::High, OutputConfig::default()); // let mut input_3 = Output::new(peripherals.GPIO22, Level::High, OutputConfig::default()); // let mut input_4 = Output::new(peripherals.GPIO12, Level::High, OutputConfig::default()); // let mut input_5 = Output::new(peripherals.GPIO13, Level::High, OutputConfig::default()); // let mut input_6 = Output::new(peripherals.GPIO26, Level::High, OutputConfig::default()); // let mut input_7 = Output::new(peripherals.GPIO27, Level::High, OutputConfig::default()); // let input_1 = Input::new(peripherals.GPIO4, pull_up_cfg); // let input_2 = Input::new(peripherals.GPIO36, pull_up_cfg); // let input_3 = Input::new(peripherals.GPIO22, pull_up_cfg); // let input_4 = Input::new(peripherals.GPIO12, pull_up_cfg); // let input_5 = Input::new(peripherals.GPIO13, pull_up_cfg); // let input_6 = Input::new(peripherals.GPIO26, pull_up_cfg); // let input_7 = Input::new(peripherals.GPIO27, pull_up_cfg); 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) }, ); // let mut pin_1 = Output::new(peripherals.GPIO13, Level::Low, OutputConfig::default()); // let mut pin_2 = Output::new(peripherals.GPIO33, Level::High, OutputConfig::default()); // let mut pin_3 = Output::new(peripherals.GPIO15, Level::Low, OutputConfig::default()); // let mut pin_4 = Output::new(peripherals.GPIO22, Level::Low, OutputConfig::default()); // let mut pin_5 = Output::new(peripherals.GPIO26, Level::Low, OutputConfig::default()); // let mut pin_6 = Output::new(peripherals.GPIO23, Level::Low, OutputConfig::default()); // let mut pin_7 = Output::new(peripherals.GPIO25, Level::Low, OutputConfig::default()); // // let mut pins = [pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7]; // let delay = Delay::new(); // loop { // pin_3.set_low(); // delay.delay_millis(300); // pin_3.set_high(); // delay.delay_millis(300); // } // let pin_1 = Input::new( // peripherals.GPIO13, // InputConfig::default().with_pull(esp_hal::gpio::Pull::Up), // ); // let mut pin_2 = Output::new(peripherals.GPIO33, Level::High, OutputConfig::default()); // let pin_3 = Input::new( // peripherals.GPIO15, // InputConfig::default().with_pull(esp_hal::gpio::Pull::Up), // ); // let mut pin_4 = Output::new(peripherals.GPIO22, Level::High, OutputConfig::default()); // let pin_5 = Input::new( // peripherals.GPIO26, // InputConfig::default().with_pull(esp_hal::gpio::Pull::Up), // ); // let mut pin_6 = Output::new(peripherals.GPIO23, Level::High, OutputConfig::default()); // let mut pin_7 = Output::new(peripherals.GPIO25, Level::High, OutputConfig::default()); // let col_pins = [pin_3, pin_1, pin_5]; // let mut row_pins = [pin_2, pin_7, pin_6, pin_4]; // let keypad = [ // ['1', '2', '3'], // ['4', '5', '6'], // ['7', '8', '9'], // ['*', '0', '#'], // ]; // let delay = Delay::new(); // loop { // delay.delay_millis(100); // for row in 0..4usize { // row_pins[row].set_low(); // delay.delay_millis(10); // for col in 0..3usize { // if col_pins[col].is_low() { // log::info!("Key: {}", keypad[row][col]); // } // } // row_pins[row].set_high(); // delay.delay_millis(10); // } // state_mgr.update(); // state_mgr.draw(); // } 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::ATCommand::ATInformation => at_commands.raw_command("ATI".to_string()), async_io::ATCommand::EnterPin(pin) => { at_commands.raw_command(format!("AT+CPIN={}", pin)) } async_io::ATCommand::CheckPin => at_commands.raw_command("AT+CPIN?".to_string()), async_io::ATCommand::SelectSMSFormat(smsformat) => { at_commands.raw_command(format!("AT+CMGF={}", smsformat as u8)) } async_io::ATCommand::CheckSMSFormat => { at_commands.raw_command("AT+CMGF?".to_string()) } async_io::ATCommand::ListTECharacterSets => { at_commands.raw_command("AT+CSCS=?".to_string()) } async_io::ATCommand::SetTECharSet(charset) => { at_commands.raw_command(format!("AT+CSCS=\"{}\"", charset.into_str())) } async_io::ATCommand::SendSMS(da, text) => { at_commands.raw_two_part_command(format!("AT+CMGS={}", da), text) } }; unsafe { async_io.set_at_response(response) }; } if let Some(event) = at_commands.readline() { log::info!("Event: {}", event); } } }