#![no_std]
use embedded_hal::blocking::{
delay::DelayMs,
i2c::{Read, Write},
};
pub struct Gy21<I2C, DL> {
i2c: I2C,
address: u8,
delay: DL,
}
pub enum CommError<I2C: Write + Read> {
Write(<I2C as Write>::Error),
Read(<I2C as Read>::Error),
}
impl<I2C: Write + Read> CommError<I2C> {
pub const fn from_write_error(err: <I2C as Write>::Error) -> Self {
Self::Write(err)
}
pub const fn from_read_error(err: <I2C as Read>::Error) -> Self {
Self::Read(err)
}
}
impl<I2C: Write + Read, DL> Gy21<I2C, DL>
where
DL: DelayMs<u8>,
{
const DEFAULT_I2C_ADDRESS: u8 = 0x40;
const READ_TEMP: u8 = 0xF3; const READ_RHUM: u8 = 0xF5;
const TWO_POW16: f32 = 65536.0;
const LAST_2BIT: u8 = 0b0000_0011;
pub const fn new(i2c: I2C, delay: DL) -> Self {
Self {
i2c,
address: Self::DEFAULT_I2C_ADDRESS,
delay,
}
}
pub const fn with_address(i2c: I2C, delay: DL, address: u8) -> Self {
Self {
i2c,
address,
delay,
}
}
fn read_sensor(&mut self, word: u8) -> Result<u16, CommError<I2C>> {
self.i2c
.write(self.address, &[word])
.map_err(CommError::from_write_error)?;
self.delay.delay_ms(50);
let mut buf = [0, 0];
self.i2c
.read(self.address, &mut buf)
.map_err(CommError::from_read_error)?;
let msb = (buf[0] as u16) << 8; let lsb = (buf[1] & !Self::LAST_2BIT) as u16; Ok(msb | lsb)
}
pub fn temperature(&mut self) -> Result<f32, CommError<I2C>> {
let reading = self.read_sensor(Self::READ_TEMP)?;
let temperature = -46.85 + 175.72 * (reading as f32 / Self::TWO_POW16);
Ok(temperature)
}
pub fn humidity(&mut self) -> Result<f32, CommError<I2C>> {
let reading = self.read_sensor(Self::READ_RHUM)?;
let rhumidty = -6.0 + 125.0 * (reading as f32 / Self::TWO_POW16);
Ok(rhumidty)
}
pub fn dew_point_temp(&mut self) -> Result<f32, CommError<I2C>> {
use libm::Libm;
let temp = self.temperature()?;
let rhum = self.humidity()?;
let (a, b, c) = (8.1332, 1762.39, 235.66);
let part_pressure = Libm::<f32>::exp10(a - (b / (temp + c)));
let dew_point_temp = -((b / (Libm::<f32>::log10(rhum * (part_pressure / 100.0)) - a)) + c);
Ok(dew_point_temp)
}
}