#![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 embassy_executor::Spawner; use embassy_time::Timer; use display_interface_spi::SPIInterface; use embedded_graphics::Drawable; use embedded_graphics::mono_font::MonoTextStyle; use embedded_graphics::mono_font::ascii::FONT_6X10; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::Point; use embedded_graphics::prelude::RgbColor; use embedded_graphics::text::Text; use embedded_graphics_core::draw_target::DrawTarget; use embedded_hal_bus::spi::ExclusiveDevice; use esp_hal::clock::CpuClock; use esp_hal::delay::Delay; use esp_hal::gpio::Level; use esp_hal::gpio::Output; use esp_hal::gpio::OutputConfig; use esp_hal::spi::{ Mode, master::{Config, Spi}, }; use esp_hal::time::Rate; use esp_hal::timer::timg::TimerGroup; use ili9341::Ili9341; use ili9341::Orientation; use log::{error, info}; #[panic_handler] fn panic(panic_info: &core::panic::PanicInfo) -> ! { error!("{}", panic_info); loop {} } extern crate alloc; // This creates a default app-descriptor required by the esp-idf bootloader. // For more information see: esp_bootloader_esp_idf::esp_app_desc!(); #[cfg(not(feature = "wokwi"))] async fn setup_wifi( wifi: esp_hal::peripherals::WIFI<'static>, flash: esp_hal::peripherals::FLASH<'static>, spawner: &Spawner, ) { let nvs = esp_hal_wifimanager::Nvs::new(0x9000, 0x6000, flash).unwrap(); let mut wm_settings = esp_hal_wifimanager::WmSettings::default(); wm_settings.ssid.clear(); _ = core::fmt::write( &mut wm_settings.ssid, format_args!("CreatureDex-{:X}", esp_hal_wifimanager::get_efuse_mac()), ); wm_settings.wifi_conn_timeout = 30000; wm_settings.esp_reset_timeout = Some(300000); // 5min let wifi_res = esp_hal_wifimanager::init_wm( wm_settings, spawner, Some(&nvs), wifi, None, ) .await; log::info!("wifi_res: {wifi_res:?}"); } #[cfg(feature = "wokwi")] async fn setup_wifi( wifi: esp_hal::peripherals::WIFI<'static>, flash: esp_hal::peripherals::FLASH<'static>, spawner: &Spawner, ) { log::info!("Wokwi mode active: pre-seeding WiFi Manager with Wokwi credentials"); // Preload connection data so init_wm can connect immediately without AP setup. let nvs = match esp_hal_wifimanager::Nvs::new(0x9000, 0x6000, flash) { Ok(nvs) => nvs, Err(e) => { log::error!("Failed to initialize NVS for Wokwi: {e:?}"); return; } }; if let Err(e) = nvs .set( esp_hal_wifimanager::WIFI_NVS_KEY, "{\"ssid\":\"Wokwi-GUEST\",\"psk\":\"\",\"data\":{}}", ) .await { log::error!("Failed to store Wokwi WiFi config in NVS: {e:?}"); return; } let mut wm_settings = esp_hal_wifimanager::WmSettings::default(); // Wokwi simulation uses a default open network called "Wokwi-GUEST" wm_settings.ssid.clear(); _ = core::fmt::write(&mut wm_settings.ssid, format_args!("Wokwi-GUEST")); wm_settings.wifi_conn_timeout = 30000; // Initialize Wi-Fi connection through WiFi Manager using the pre-seeded NVS data. let wifi_res = esp_hal_wifimanager::init_wm( wm_settings, spawner, Some(&nvs), wifi, None, ) .await; log::info!("Wokwi wifi_res: {wifi_res:?}"); } #[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) { // generator version: 1.3.0 // generator parameters: --chip esp32s3 -o esp32s3-wroom-1-octal-psram -o unstable-hal -o alloc -o wifi -o log -o wokwi -o neovim -o vscode -o esp 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 // - GPIO3 // - GPIO45 // - GPIO46 // These GPIO pins are in use by some feature of the module and should not be used. let _ = peripherals.GPIO27; let _ = peripherals.GPIO28; let _ = peripherals.GPIO29; let _ = peripherals.GPIO30; let _ = peripherals.GPIO31; let _ = peripherals.GPIO32; let _ = peripherals.GPIO33; let _ = peripherals.GPIO34; let _ = peripherals.GPIO35; let _ = peripherals.GPIO36; let _ = peripherals.GPIO37; esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744); let timg0 = TimerGroup::new(peripherals.TIMG0); let sw_interrupt = esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); let spi_bus = Spi::new( peripherals.SPI2, Config::default() .with_frequency(Rate::from_khz(100)) .with_mode(Mode::_0), ) .unwrap() .with_sck(peripherals.GPIO36) .with_mosi(peripherals.GPIO35) .with_miso(peripherals.GPIO37); let cs_main = Output::new(peripherals.GPIO11, Level::High, OutputConfig::default()); let mut delay = Delay::new(); let spi_dev = ExclusiveDevice::new(spi_bus, cs_main, delay).unwrap(); let reset_main = Output::new(peripherals.GPIO10, Level::High, OutputConfig::default()); let spi_dc = Output::new(peripherals.GPIO12, Level::High, OutputConfig::default()); let iface = SPIInterface::new(spi_dev, spi_dc); let mut display = Ili9341::new( iface, reset_main, &mut delay, Orientation::Landscape, ili9341::DisplaySize240x320, ) .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE); Text::new("Hello, ESP32!", Point::new(20, 100), style) .draw(&mut display) .unwrap(); setup_wifi(peripherals.WIFI, peripherals.FLASH, &spawner).await; log::info!("Setup complete, entering main loop"); loop { info!("Hello world!"); Timer::after_millis(500).await; } // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples }