diff --git a/pmme-device/rust-version/.dir-locals.el b/pmme-device/rust-version/.dir-locals.el new file mode 100644 index 0000000..51aa839 --- /dev/null +++ b/pmme-device/rust-version/.dir-locals.el @@ -0,0 +1,2 @@ +((nil + (lsp-rust-analyzer-exclude-dirs . ["./.embuild/"]))) diff --git a/pmme-device/rust-version/src/lib.rs b/pmme-device/rust-version/src/lib.rs new file mode 100644 index 0000000..3b0e25e --- /dev/null +++ b/pmme-device/rust-version/src/lib.rs @@ -0,0 +1 @@ +pub mod wifi; diff --git a/pmme-device/rust-version/src/main.rs b/pmme-device/rust-version/src/main.rs index 49c37a1..73531b7 100644 --- a/pmme-device/rust-version/src/main.rs +++ b/pmme-device/rust-version/src/main.rs @@ -1,29 +1,27 @@ -use anyhow::{Result, anyhow}; -use esp_idf_svc::hal::gpio; -use esp_idf_svc::hal::delay::FreeRtos; -use esp_idf_svc::hal::i2c::{I2cConfig, I2cDriver}; -use esp_idf_svc::hal::peripherals::Peripherals; -use esp_idf_svc::hal::delay::BLOCK; -use esp_idf_svc::hal::prelude::FromValueType; -use esp_idf_svc::hal::units::Hertz; -use esp_idf_svc::hal::uart::{config, UartDriver}; +use anyhow::{anyhow, Result}; +use esp_idf_svc::hal::{ + delay::{FreeRtos, BLOCK}, + gpio, + i2c::{I2cConfig, I2cDriver}, + peripherals::Peripherals, + prelude::FromValueType, + uart::{config, UartDriver}, + units::Hertz, +}; use embedded_graphics::{ - mono_font::{ - ascii::{FONT_10X20}, - MonoTextStyle, - }, image::{Image, ImageRaw}, + mono_font::{ascii::FONT_10X20, MonoTextStyle}, pixelcolor::BinaryColor, prelude::*, text::Text, }; -use ssd1306::{I2CDisplayInterface, Ssd1306, size::*, rotation::*}; use ssd1306::mode::DisplayConfig; +use ssd1306::{rotation::*, size::*, I2CDisplayInterface, Ssd1306}; -use std::thread; -use std::sync::{Arc, Mutex}; use log::{info, warn}; +use std::sync::{Arc, Mutex}; +use std::thread; #[derive(Debug, Clone, Default)] pub struct Pms7003Data { @@ -47,14 +45,16 @@ pub struct Pms7003Data { } // u16::from_be_bytes is too verbose -fn get_u16(buf: &[u8]) -> u16 { ((buf[0] as u16) << 8) | buf[1] as u16 } +fn get_u16(buf: &[u8]) -> u16 { + ((buf[0] as u16) << 8) | buf[1] as u16 +} fn read_pm_data(buf: &[u8; 32]) -> Option { let checksum: u16 = buf.iter().take(29).copied().map(u16::from).sum(); let csum_target = get_u16(&buf[30..32]); if checksum != csum_target { warn!("Checksum from PMS7003 READ does not match, skipping read"); - return None + return None; } Some(Pms7003Data { pm1_0_cf1: get_u16(&buf[ 4..6 ]), @@ -75,10 +75,7 @@ fn read_pm_data(buf: &[u8; 32]) -> Option { fn send_pms7003_command(uart: &UartDriver, cmd: u8, datah: u8, datal: u8) -> Result<()> { let mut command = [0x42u8, 0x4D, cmd, datah, datal, 0, 0]; - let mut checksum: u16 = 0; - for i in 0..5 { - checksum += command[i] as u16; - } + let checksum: u16 = command.iter().take(5).copied().map(u16::from).sum(); command[5] = ((checksum >> 8) & 0xFF) as u8; command[6] = (checksum & 0xFF) as u8; @@ -122,18 +119,26 @@ fn oled_task(pm_data: Arc>, i2c: I2cDriver) -> Result<()> { let im = Image::new(&raw, Point::new(32, 0)); im.draw(&mut display).unwrap(); - display.flush().map_err(|e| anyhow!("Could not flush display! {:?}", e))?; + display + .flush() + .map_err(|e| anyhow!("Could not flush display! {:?}", e))?; FreeRtos::delay_ms(2000); loop { let current_pm_data = pm_data.lock().unwrap().clone(); - display.clear(BinaryColor::Off).map_err(|e| anyhow!("Could not clear display! {:?}", e))?; + display + .clear(BinaryColor::Off) + .map_err(|e| anyhow!("Could not clear display! {:?}", e))?; Text::new( &format!("PM 2.5: {}", current_pm_data.pm2_5_atm), Point::new(20, 40), MonoTextStyle::new(&FONT_10X20, BinaryColor::On), - ).draw(&mut display).map_err(|e| anyhow!("Could not draw text! {:?}", e))?; - display.flush().map_err(|e| anyhow!("Could not flush display! {:?}", e))?; + ) + .draw(&mut display) + .map_err(|e| anyhow!("Could not draw text! {:?}", e))?; + display + .flush() + .map_err(|e| anyhow!("Could not flush display! {:?}", e))?; FreeRtos::delay_ms(500); } } @@ -174,7 +179,7 @@ fn main() -> Result<()> { let pm_data1 = Arc::clone(&pm_data); let pm_data2 = Arc::clone(&pm_data); - let handles = vec! [ + let handles = vec![ thread::spawn(move || { if let Err(e) = oled_task(pm_data1, i2c) { log::error!("OLED Task Error: {:?}", e); diff --git a/pmme-device/rust-version/src/wifi.rs b/pmme-device/rust-version/src/wifi.rs new file mode 100644 index 0000000..7c58fda --- /dev/null +++ b/pmme-device/rust-version/src/wifi.rs @@ -0,0 +1,78 @@ +use anyhow::bail; +use esp_idf_svc::{ + eventloop::EspSystemEventLoop, + hal::peripheral, + wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi}, +}; +use log::info; + +pub fn wifi( + ssid: &str, + pass: &str, + modem: impl peripheral::Peripheral

+ 'static, + sysloop: EspSystemEventLoop, +) -> anyhow::Result>> { + let mut auth_method = AuthMethod::WPA2Personal; + if ssid.is_empty() { + bail!("Missing WiFi name") + } + if pass.is_empty() { + auth_method = AuthMethod::None; + info!("Wifi password is empty"); + } + let mut esp_wifi = EspWifi::new(modem, sysloop.clone(), None)?; + + let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sysloop)?; + + wifi.set_configuration(&Configuration::Client(ClientConfiguration::default()))?; + + info!("Starting wifi..."); + + wifi.start()?; + + info!("Scanning..."); + + let ap_infos = wifi.scan()?; + + let ours = ap_infos.into_iter().find(|a| a.ssid == ssid); + + let channel = if let Some(ours) = ours { + info!( + "Found configured access point {} on channel {}", + ssid, ours.channel + ); + Some(ours.channel) + } else { + info!( + "Configured access point {} not found during scanning, will go with unknown channel", + ssid + ); + None + }; + + wifi.set_configuration(&Configuration::Client(ClientConfiguration { + ssid: ssid + .try_into() + .expect("Could not parse the given SSID into WiFi config"), + password: pass + .try_into() + .expect("Could not parse the given password into WiFi config"), + channel, + auth_method, + ..Default::default() + }))?; + + info!("Connecting wifi..."); + + wifi.connect()?; + + info!("Waiting for DHCP lease..."); + + wifi.wait_netif_up()?; + + let ip_info = wifi.wifi().sta_netif().get_ip_info()?; + + info!("Wifi DHCP info: {:?}", ip_info); + + Ok(Box::new(esp_wifi)) +}