📟 pmme-device: wifi.rs added along with lib.rs and ran cargo fmt

This commit is contained in:
Joseph Ferano 2025-06-11 16:48:09 +07:00
parent 385988401c
commit a164f3dda1
4 changed files with 113 additions and 27 deletions

View File

@ -0,0 +1,2 @@
((nil
(lsp-rust-analyzer-exclude-dirs . ["./.embuild/"])))

View File

@ -0,0 +1 @@
pub mod wifi;

View File

@ -1,29 +1,27 @@
use anyhow::{Result, anyhow}; use anyhow::{anyhow, Result};
use esp_idf_svc::hal::gpio; use esp_idf_svc::hal::{
use esp_idf_svc::hal::delay::FreeRtos; delay::{FreeRtos, BLOCK},
use esp_idf_svc::hal::i2c::{I2cConfig, I2cDriver}; gpio,
use esp_idf_svc::hal::peripherals::Peripherals; i2c::{I2cConfig, I2cDriver},
use esp_idf_svc::hal::delay::BLOCK; peripherals::Peripherals,
use esp_idf_svc::hal::prelude::FromValueType; prelude::FromValueType,
use esp_idf_svc::hal::units::Hertz; uart::{config, UartDriver},
use esp_idf_svc::hal::uart::{config, UartDriver}; units::Hertz,
};
use embedded_graphics::{ use embedded_graphics::{
mono_font::{
ascii::{FONT_10X20},
MonoTextStyle,
},
image::{Image, ImageRaw}, image::{Image, ImageRaw},
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::BinaryColor, pixelcolor::BinaryColor,
prelude::*, prelude::*,
text::Text, text::Text,
}; };
use ssd1306::{I2CDisplayInterface, Ssd1306, size::*, rotation::*};
use ssd1306::mode::DisplayConfig; use ssd1306::mode::DisplayConfig;
use ssd1306::{rotation::*, size::*, I2CDisplayInterface, Ssd1306};
use std::thread;
use std::sync::{Arc, Mutex};
use log::{info, warn}; use log::{info, warn};
use std::sync::{Arc, Mutex};
use std::thread;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Pms7003Data { pub struct Pms7003Data {
@ -47,14 +45,16 @@ pub struct Pms7003Data {
} }
// u16::from_be_bytes is too verbose // 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<Pms7003Data> { fn read_pm_data(buf: &[u8; 32]) -> Option<Pms7003Data> {
let checksum: u16 = buf.iter().take(29).copied().map(u16::from).sum(); let checksum: u16 = buf.iter().take(29).copied().map(u16::from).sum();
let csum_target = get_u16(&buf[30..32]); let csum_target = get_u16(&buf[30..32]);
if checksum != csum_target { if checksum != csum_target {
warn!("Checksum from PMS7003 READ does not match, skipping read"); warn!("Checksum from PMS7003 READ does not match, skipping read");
return None return None;
} }
Some(Pms7003Data { Some(Pms7003Data {
pm1_0_cf1: get_u16(&buf[ 4..6 ]), pm1_0_cf1: get_u16(&buf[ 4..6 ]),
@ -75,10 +75,7 @@ fn read_pm_data(buf: &[u8; 32]) -> Option<Pms7003Data> {
fn send_pms7003_command(uart: &UartDriver, cmd: u8, datah: u8, datal: u8) -> Result<()> { 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 command = [0x42u8, 0x4D, cmd, datah, datal, 0, 0];
let mut checksum: u16 = 0; let checksum: u16 = command.iter().take(5).copied().map(u16::from).sum();
for i in 0..5 {
checksum += command[i] as u16;
}
command[5] = ((checksum >> 8) & 0xFF) as u8; command[5] = ((checksum >> 8) & 0xFF) as u8;
command[6] = (checksum & 0xFF) as u8; command[6] = (checksum & 0xFF) as u8;
@ -122,18 +119,26 @@ fn oled_task(pm_data: Arc<Mutex<Pms7003Data>>, i2c: I2cDriver) -> Result<()> {
let im = Image::new(&raw, Point::new(32, 0)); let im = Image::new(&raw, Point::new(32, 0));
im.draw(&mut display).unwrap(); 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); FreeRtos::delay_ms(2000);
loop { loop {
let current_pm_data = pm_data.lock().unwrap().clone(); 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( Text::new(
&format!("PM 2.5: {}", current_pm_data.pm2_5_atm), &format!("PM 2.5: {}", current_pm_data.pm2_5_atm),
Point::new(20, 40), Point::new(20, 40),
MonoTextStyle::new(&FONT_10X20, BinaryColor::On), 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); FreeRtos::delay_ms(500);
} }
} }
@ -174,7 +179,7 @@ fn main() -> Result<()> {
let pm_data1 = Arc::clone(&pm_data); let pm_data1 = Arc::clone(&pm_data);
let pm_data2 = Arc::clone(&pm_data); let pm_data2 = Arc::clone(&pm_data);
let handles = vec! [ let handles = vec![
thread::spawn(move || { thread::spawn(move || {
if let Err(e) = oled_task(pm_data1, i2c) { if let Err(e) = oled_task(pm_data1, i2c) {
log::error!("OLED Task Error: {:?}", e); log::error!("OLED Task Error: {:?}", e);

View File

@ -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<P = esp_idf_svc::hal::modem::Modem> + 'static,
sysloop: EspSystemEventLoop,
) -> anyhow::Result<Box<EspWifi<'static>>> {
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))
}