#![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, collections::btree_set::BTreeSet, vec::Vec}; use esp_hal::{ clock::CpuClock, delay::Delay, gpio::{Level, Output, OutputConfig}, i2c::{self, master::I2c}, 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, KeypadButton}, at_commands::ATCommands, display::{Display, Position, Rgb565, SetAddressMode}, font::FontRenderer, state::StateManager, states::InitATState, sx1509::{Register, Sx1509}, }; extern crate alloc; mod async_io; mod at_commands; mod display; mod font; mod state; mod states; mod sx1509; // 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 sx1509 = Sx1509::from( I2c::new( peripherals.I2C0, i2c::master::Config::default().with_frequency(Rate::from_khz(400)), ) .unwrap() .with_scl(peripherals.GPIO20) .with_sda(peripherals.GPIO22), Output::new(peripherals.GPIO15, Level::High, OutputConfig::default()), ); sx1509.init().unwrap(); sx1509.keypad(4, 4, 256, 2, 1); 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(), false, ); 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, sx1509) }, ); loop { state_mgr.update(); state_mgr.draw(); } } static KEYPAD_BUTTONS: [[KeypadButton; 4]; 4] = [ [ KeypadButton::Keypad1, KeypadButton::Keypad2, KeypadButton::Keypad3, KeypadButton::KeypadA, ], [ KeypadButton::Keypad4, KeypadButton::Keypad5, KeypadButton::Keypad6, KeypadButton::KeypadB, ], [ KeypadButton::Keypad7, KeypadButton::Keypad8, KeypadButton::Keypad9, KeypadButton::KeypadC, ], [ KeypadButton::KeypadStar, KeypadButton::Keypad0, KeypadButton::KeypadHash, KeypadButton::KeypadD, ], ]; fn thread_2_main( async_io: AsyncIO, mut at_commands: ATCommands<'static, 'static>, mut sx1509: Sx1509<'static>, ) { let delay = Delay::new(); loop { if let Some(command) = unsafe { async_io.clone().check_at_command() } { let response = command.execute(&mut at_commands); unsafe { async_io.set_at_response(response) }; } if let Some(event) = at_commands.readline() { log::info!("Event: {}", event); } let mut buttons_pressed = BTreeSet::new(); loop { let keypad_data = sx1509.read_keypad(); let col = bit_representation_to_number(((keypad_data & 0xFF00) >> 8) as u8) as usize; let row = bit_representation_to_number((keypad_data & 0xFF) as u8) as usize; if row == 0 || col == 0 { break; } if row > 4 || col > 4 { break; } let button = KEYPAD_BUTTONS[col - 1][row - 1]; if buttons_pressed.contains(&button) { break; } buttons_pressed.insert(button); delay.delay_millis(5); } async_io.keypad.handle_presses(buttons_pressed); } } fn bit_representation_to_number(byte: u8) -> u8 { match byte { 0b00000000 => 0, 0b00000001 => 1, 0b00000010 => 2, 0b00000100 => 3, 0b00001000 => 4, 0b00010000 => 5, 0b00100000 => 6, 0b01000000 => 7, 0b10000000 => 8, _ => 255, } }