130 lines
4.2 KiB
Rust

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::<gpio::Gpio0>::None,
Option::<gpio::Gpio1>::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(())
}