📟 pmme-device: Project now split into separate modules
This commit is contained in:
parent
a164f3dda1
commit
9d5b9366d5
49
pmme-device/rust-version/src/display.rs
Normal file
49
pmme-device/rust-version/src/display.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::Pms7003Data;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use log::info;
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use embedded_graphics::{Drawable, image::{Image, ImageRaw}, mono_font::{ascii::FONT_10X20, MonoTextStyle}, pixelcolor::BinaryColor, prelude::Point, text::Text};
|
||||||
|
use embedded_graphics::draw_target::DrawTarget;
|
||||||
|
use esp_idf_svc::hal::{delay::FreeRtos, i2c::I2cDriver};
|
||||||
|
use ssd1306::{mode::DisplayConfig, prelude::DisplayRotation, size::DisplaySize128x64, I2CDisplayInterface, Ssd1306};
|
||||||
|
|
||||||
|
pub fn oled_task(pm_data: Arc<Mutex<Pms7003Data>>, i2c: I2cDriver) -> Result<()> {
|
||||||
|
info!("Staring OLED Task");
|
||||||
|
|
||||||
|
let interface = I2CDisplayInterface::new(i2c);
|
||||||
|
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||||
|
.into_buffered_graphics_mode();
|
||||||
|
|
||||||
|
display.init().unwrap();
|
||||||
|
|
||||||
|
let raw: ImageRaw<BinaryColor> = ImageRaw::new(include_bytes!("../rust.raw"), 64);
|
||||||
|
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))?;
|
||||||
|
|
||||||
|
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))?;
|
||||||
|
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)
|
||||||
|
})?;
|
||||||
|
FreeRtos::delay_ms(500);
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,24 @@
|
|||||||
pub mod wifi;
|
pub mod wifi;
|
||||||
|
pub mod sensors;
|
||||||
|
pub mod display;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct Pms7003Data {
|
||||||
|
// PM concentrations (CF=1, standard particle) in μg/m³
|
||||||
|
pub pm1_0_cf1: u16,
|
||||||
|
pub pm2_5_cf1: u16,
|
||||||
|
pub pm10_cf1: u16,
|
||||||
|
|
||||||
|
// PM concentrations (atmospheric environment) in μg/m³
|
||||||
|
pub pm1_0_atm: u16,
|
||||||
|
pub pm2_5_atm: u16,
|
||||||
|
pub pm10_atm: u16,
|
||||||
|
|
||||||
|
// Particle counts (particles per 0.1L air)
|
||||||
|
pub particles_0_3um: u16,
|
||||||
|
pub particles_0_5um: u16,
|
||||||
|
pub particles_1_0um: u16,
|
||||||
|
pub particles_2_5um: u16,
|
||||||
|
pub particles_5_0um: u16,
|
||||||
|
pub particles_10um: u16,
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use std::{sync::{Arc, Mutex}, thread};
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
use esp_idf_svc::hal::{
|
use esp_idf_svc::hal::{
|
||||||
delay::{FreeRtos, BLOCK},
|
|
||||||
gpio,
|
gpio,
|
||||||
i2c::{I2cConfig, I2cDriver},
|
i2c::{I2cConfig, I2cDriver},
|
||||||
peripherals::Peripherals,
|
peripherals::Peripherals,
|
||||||
@ -8,140 +9,7 @@ use esp_idf_svc::hal::{
|
|||||||
uart::{config, UartDriver},
|
uart::{config, UartDriver},
|
||||||
units::Hertz,
|
units::Hertz,
|
||||||
};
|
};
|
||||||
|
use pmme_device::{display::oled_task, sensors::pm_sensor_task, Pms7003Data};
|
||||||
use embedded_graphics::{
|
|
||||||
image::{Image, ImageRaw},
|
|
||||||
mono_font::{ascii::FONT_10X20, MonoTextStyle},
|
|
||||||
pixelcolor::BinaryColor,
|
|
||||||
prelude::*,
|
|
||||||
text::Text,
|
|
||||||
};
|
|
||||||
use ssd1306::mode::DisplayConfig;
|
|
||||||
use ssd1306::{rotation::*, size::*, I2CDisplayInterface, Ssd1306};
|
|
||||||
|
|
||||||
use log::{info, warn};
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct Pms7003Data {
|
|
||||||
// PM concentrations (CF=1, standard particle) in μg/m³
|
|
||||||
pub pm1_0_cf1: u16,
|
|
||||||
pub pm2_5_cf1: u16,
|
|
||||||
pub pm10_cf1: u16,
|
|
||||||
|
|
||||||
// PM concentrations (atmospheric environment) in μg/m³
|
|
||||||
pub pm1_0_atm: u16,
|
|
||||||
pub pm2_5_atm: u16,
|
|
||||||
pub pm10_atm: u16,
|
|
||||||
|
|
||||||
// Particle counts (particles per 0.1L air)
|
|
||||||
pub particles_0_3um: u16,
|
|
||||||
pub particles_0_5um: u16,
|
|
||||||
pub particles_1_0um: u16,
|
|
||||||
pub particles_2_5um: u16,
|
|
||||||
pub particles_5_0um: u16,
|
|
||||||
pub particles_10um: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
// u16::from_be_bytes is too verbose
|
|
||||||
fn get_u16(buf: &[u8]) -> u16 {
|
|
||||||
((buf[0] as u16) << 8) | buf[1] as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pm_data(buf: &[u8; 32]) -> Option<Pms7003Data> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Some(Pms7003Data {
|
|
||||||
pm1_0_cf1: get_u16(&buf[ 4..6 ]),
|
|
||||||
pm2_5_cf1: get_u16(&buf[ 6..8 ]),
|
|
||||||
pm10_cf1: get_u16(&buf[ 8..10]),
|
|
||||||
pm1_0_atm: get_u16(&buf[10..12]),
|
|
||||||
pm2_5_atm: get_u16(&buf[12..14]),
|
|
||||||
pm10_atm: get_u16(&buf[14..16]),
|
|
||||||
particles_0_3um: get_u16(&buf[16..18]),
|
|
||||||
particles_0_5um: get_u16(&buf[18..20]),
|
|
||||||
particles_1_0um: get_u16(&buf[20..22]),
|
|
||||||
particles_2_5um: get_u16(&buf[22..24]),
|
|
||||||
particles_5_0um: get_u16(&buf[24..26]),
|
|
||||||
particles_10um: get_u16(&buf[26..28]),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_pms7003_command(uart: &UartDriver, cmd: u8, datah: u8, datal: u8) -> Result<()> {
|
|
||||||
let mut command = [0x42u8, 0x4D, cmd, datah, datal, 0, 0];
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
uart.write(&command)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pm_sensor_task(pm_data: Arc<Mutex<Pms7003Data>>, uart: &UartDriver) -> Result<()> {
|
|
||||||
info!("Staring UART PM Sensor Task");
|
|
||||||
|
|
||||||
send_pms7003_command(uart, 0xE1, 0x00, 0x00)?;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
send_pms7003_command(uart, 0xE2, 0x00, 0x00)?;
|
|
||||||
|
|
||||||
let mut buf = [0_u8; 32];
|
|
||||||
let len = uart.read(&mut buf, BLOCK)?;
|
|
||||||
if len > 0 {
|
|
||||||
if let Some(data) = read_pm_data(&buf) {
|
|
||||||
let mut pm_data = pm_data.lock().unwrap();
|
|
||||||
*pm_data = data;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// info!("No bytes read");
|
|
||||||
}
|
|
||||||
uart.clear_rx()?;
|
|
||||||
FreeRtos::delay_ms(5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn oled_task(pm_data: Arc<Mutex<Pms7003Data>>, i2c: I2cDriver) -> Result<()> {
|
|
||||||
info!("Staring OLED Task");
|
|
||||||
|
|
||||||
let interface = I2CDisplayInterface::new(i2c);
|
|
||||||
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
|
||||||
.into_buffered_graphics_mode();
|
|
||||||
|
|
||||||
display.init().unwrap();
|
|
||||||
|
|
||||||
let raw: ImageRaw<BinaryColor> = ImageRaw::new(include_bytes!("../rust.raw"), 64);
|
|
||||||
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))?;
|
|
||||||
|
|
||||||
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))?;
|
|
||||||
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))?;
|
|
||||||
FreeRtos::delay_ms(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// It is necessary to call this function once. Otherwise some patches to the runtime
|
// It is necessary to call this function once. Otherwise some patches to the runtime
|
||||||
|
69
pmme-device/rust-version/src/sensors.rs
Normal file
69
pmme-device/rust-version/src/sensors.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use crate::Pms7003Data;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use log::{info, warn};
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use esp_idf_svc::hal::{delay::{FreeRtos, BLOCK}, uart::UartDriver};
|
||||||
|
|
||||||
|
// u16::from_be_bytes is too verbose
|
||||||
|
fn get_u16(buf: &[u8]) -> u16 {
|
||||||
|
((buf[0] as u16) << 8) | buf[1] as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_pm_data(buf: &[u8; 32]) -> Option<Pms7003Data> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Some(Pms7003Data {
|
||||||
|
pm1_0_cf1: get_u16(&buf[ 4..6 ]),
|
||||||
|
pm2_5_cf1: get_u16(&buf[ 6..8 ]),
|
||||||
|
pm10_cf1: get_u16(&buf[ 8..10]),
|
||||||
|
pm1_0_atm: get_u16(&buf[10..12]),
|
||||||
|
pm2_5_atm: get_u16(&buf[12..14]),
|
||||||
|
pm10_atm: get_u16(&buf[14..16]),
|
||||||
|
particles_0_3um: get_u16(&buf[16..18]),
|
||||||
|
particles_0_5um: get_u16(&buf[18..20]),
|
||||||
|
particles_1_0um: get_u16(&buf[20..22]),
|
||||||
|
particles_2_5um: get_u16(&buf[22..24]),
|
||||||
|
particles_5_0um: get_u16(&buf[24..26]),
|
||||||
|
particles_10um: get_u16(&buf[26..28]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_pms7003_command(uart: &UartDriver, cmd: u8, datah: u8, datal: u8) -> Result<()> {
|
||||||
|
let mut command = [0x42u8, 0x4D, cmd, datah, datal, 0, 0];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
uart.write(&command)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pm_sensor_task(pm_data: Arc<Mutex<Pms7003Data>>, uart: &UartDriver) -> Result<()> {
|
||||||
|
info!("Staring UART PM Sensor Task");
|
||||||
|
|
||||||
|
send_pms7003_command(uart, 0xE1, 0x00, 0x00)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
send_pms7003_command(uart, 0xE2, 0x00, 0x00)?;
|
||||||
|
|
||||||
|
let mut buf = [0_u8; 32];
|
||||||
|
let len = uart.read(&mut buf, BLOCK)?;
|
||||||
|
if len > 0 {
|
||||||
|
if let Some(data) = read_pm_data(&buf) {
|
||||||
|
let mut pm_data = pm_data.lock().unwrap();
|
||||||
|
*pm_data = data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// info!("No bytes read");
|
||||||
|
}
|
||||||
|
uart.clear_rx()?;
|
||||||
|
FreeRtos::delay_ms(5000);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
|
use log::info;
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
|
||||||
use esp_idf_svc::{
|
use esp_idf_svc::{
|
||||||
eventloop::EspSystemEventLoop,
|
eventloop::EspSystemEventLoop,
|
||||||
hal::peripheral,
|
hal::peripheral,
|
||||||
wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi},
|
wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi},
|
||||||
};
|
};
|
||||||
use log::info;
|
|
||||||
|
|
||||||
pub fn wifi(
|
pub fn wifi(
|
||||||
ssid: &str,
|
ssid: &str,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user