use anyhow::{bail, Result}; use log::info; use std::{ sync::{Arc, Mutex}, thread, }; use esp_idf_svc::{ eventloop::EspSystemEventLoop, hal::{ delay::FreeRtos, gpio::{self, Level, PinDriver}, i2c::{I2cConfig, I2cDriver}, peripherals::Peripherals, prelude::FromValueType, uart::{self, UartDriver}, units::Hertz, }, log::EspLogger, nvs::EspDefaultNvsPartition, sys::CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi}, }; use pmme_device::{display::oled_task, sensors::sensors_task, wifi::wifi_task, Pms7003Data}; fn main() -> Result<()> { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 esp_idf_svc::sys::link_patches(); // Initialize NVS EspLogger::initialize_default(); let nvs = EspDefaultNvsPartition::take()?; FreeRtos::delay_ms(100); let peripherals = Peripherals::take()?; FreeRtos::delay_ms(100); let mut button = PinDriver::input(peripherals.pins.gpio5)?; let mut led = PinDriver::output(peripherals.pins.gpio19)?; led.set_low()?; let i2c = peripherals.i2c0; let sda = peripherals.pins.gpio21; let scl = peripherals.pins.gpio22; let config = I2cConfig::new().baudrate(100.kHz().into()); let i2c = I2cDriver::new(i2c, sda, scl, &config)?; let tx = peripherals.pins.gpio17; let rx = peripherals.pins.gpio16; let config = uart::config::Config::new().baudrate(Hertz(9600)); let uart = UartDriver::new( peripherals.uart2, tx, rx, Option::::None, Option::::None, &config, )?; let sysloop = EspSystemEventLoop::take()?; let sysloop_clone = sysloop.clone(); let modem = peripherals.modem; let pm_data = Arc::new(Mutex::new(Pms7003Data::default())); let oled_arc = Arc::clone(&pm_data); let sensors_arc = Arc::clone(&pm_data); // let wifi_arc = Arc::clone(&pm_data); let handles = vec![ thread::spawn(move || { if let Err(e) = oled_task(oled_arc, i2c) { log::error!("OLED Task Error: {:?}", e); } }), thread::spawn(move || { if let Err(e) = sensors_task(sensors_arc, &uart) { log::error!("PM Sensor Task Error: {:?}", e); } }), std::thread::Builder::new() // NOTE: According to CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, this was set to 3072 and the wifi task // was getting a stack overflow .stack_size(12288) .spawn(move || { unsafe { let free_stack = esp_idf_svc::sys::uxTaskGetStackHighWaterMark(std::ptr::null_mut()); let stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; log::info!( "Pthread stack size configured: {} bytes, Current free stack: {} bytes", stack_size, free_stack * 4 ); } if let Err(e) = wifi_task(modem, sysloop_clone, nvs) { log::error!("PM Wifi Task Error: {:?}", e); } })?, thread::spawn(move || { let mut is_pressed = false; let mut curr_state = Level::High; loop { if curr_state == Level::High && button.is_low() { led.set_high().unwrap(); curr_state = Level::Low; is_pressed = true; } else if curr_state == Level::Low && button.is_high() { led.set_low().unwrap(); curr_state = Level::High; is_pressed = true; } if is_pressed { FreeRtos::delay_ms(100); } else { FreeRtos::delay_ms(10); } } }), ]; for h in handles { h.join().unwrap(); } Ok(()) }