#![no_std]
use embedded_hal::adc::{OneShot, Channel};
use core::marker::PhantomData;
use libm::powf;
#[derive(Copy, Clone, Debug)]
pub enum GasType {
CO2,
NH3,
Benzene,
Smoke,
}
fn gas_constants(gas: GasType) -> (f32, f32) {
match gas {
GasType::CO2 => (110.47, -2.862),
GasType::NH3 => (102.2, -2.473),
GasType::Benzene => (44.947, -3.445),
GasType::Smoke => (26.572, -2.265),
}
}
pub struct Mq135<ADC, PIN, Word, Error> {
adc: ADC,
pin: PIN,
r0: f32,
rl: f32,
_word: PhantomData<Word>,
_error: PhantomData<Error>,
}
impl<ADC, PIN, Word, Error> Mq135<ADC, PIN, Word, Error>
where
ADC: OneShot<ADC, Word, PIN, Error = Error>,
Word: Into<u32>,
PIN: Channel<ADC>,
{
pub fn new(adc: ADC, pin: PIN, rl: f32) -> Self {
Mq135 {
adc,
pin,
r0: 10.0, rl,
_word: PhantomData,
_error: PhantomData,
}
}
pub fn calibrate_in_clean_air(&mut self) -> nb::Result<(), Error> {
let adc_value: u32 = self.adc.read(&mut self.pin)?.into();
let voltage = adc_value as f32 / 4095.0 * 3.3;
let rs = self.rl * (3.3 - voltage) / voltage;
self.r0 = rs / 3.6;
Ok(())
}
pub fn read_gas_ppm(&mut self, gas: GasType) -> nb::Result<f32, Error> {
let adc_value: u32 = self.adc.read(&mut self.pin)?.into();
let voltage = adc_value as f32 / 4095.0 * 3.3;
let rs = self.rl * (3.3 - voltage) / voltage;
let ratio = rs / self.r0;
let (a, b) = gas_constants(gas);
Ok(a * powf(ratio, b))
}
}