#![no_std]
extern crate byteorder;
extern crate embedded_hal;
use byteorder::{ByteOrder, BigEndian};
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
pub struct SHT3x<I2C, D> {
i2c: I2C,
delay: D,
address: Address,
}
impl<I2C, D, E> SHT3x<I2C, D>
where
I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
D: DelayMs<u8>,
{
pub fn new(i2c: I2C, delay: D, address: Address) -> Self {
SHT3x { i2c, delay, address }
}
fn command(&mut self, command: Command) -> Result<(), Error<E>> {
let mut cmd_bytes = [0; 2];
BigEndian::write_u16(&mut cmd_bytes, command.value());
self.i2c
.write(self.address as u8, &cmd_bytes)
.map_err(Error::I2c)
}
pub fn measure(&mut self, rpt: Repeatability) -> Result<Measurement, Error<E>> {
self.command(Command::SingleShot(ClockStretch::Disabled, rpt))?;
self.delay.delay_ms(rpt.max_duration());
let mut buf = [0; 6];
self.i2c.read(self.address as u8, &mut buf)
.map_err(Error::I2c)?;
let temperature = convert_temperature(BigEndian::read_u16(&buf[0..2]));
let humidity = convert_humidity(BigEndian::read_u16(&buf[3..5]));
Ok(Measurement{ temperature, humidity })
}
pub fn status(&mut self) -> Result<u16, Error<E>> {
self.command(Command::Status)?;
let mut status_bytes = [0; 2];
self.i2c
.read(self.address as u8, &mut status_bytes)
.map_err(Error::I2c)?;
Ok(BigEndian::read_u16(&status_bytes))
}
}
fn convert_temperature(raw: u16) -> i32 {
-4500 + (17500 * raw as i32) / 65535
}
fn convert_humidity(raw: u16) -> i32 {
(10000 * raw as i32) / 65535
}
#[derive(Debug)]
pub enum Error<E> {
Crc,
I2c(E),
}
#[derive(Copy, Clone)]
pub enum Address {
High = 0x45,
Low = 0x44,
}
enum Command {
SingleShot(ClockStretch, Repeatability),
Periodic(Rate, Repeatability),
FetchData,
PeriodicWithART,
Break,
SoftReset,
HeaterEnable,
HeaterDisable,
Status,
ClearStatus,
}
enum ClockStretch {
Enabled,
Disabled,
}
#[allow(non_camel_case_types)]
enum Rate {
R0_5,
R1,
R2,
R4,
R10,
}
#[derive(Copy, Clone)]
pub enum Repeatability {
High,
Medium,
Low,
}
impl Repeatability {
fn max_duration(&self) -> u8 {
match *self {
Repeatability::Low => 4,
Repeatability::Medium => 6,
Repeatability::High => 15,
}
}
}
#[derive(Debug)]
pub struct Measurement {
pub temperature: i32,
pub humidity: i32,
}
impl Command {
fn value(&self) -> u16 {
use ClockStretch::Enabled as CSEnabled;
use ClockStretch::Disabled as CSDisabled;
use Rate::*;
use Repeatability::*;
match *self {
Command::SingleShot(CSEnabled, High) => 0x2C06,
Command::SingleShot(CSEnabled, Medium) => 0x2C0D,
Command::SingleShot(CSEnabled, Low) => 0x2C10,
Command::SingleShot(CSDisabled, High) => 0x2400,
Command::SingleShot(CSDisabled, Medium) => 0x240B,
Command::SingleShot(CSDisabled, Low) => 0x2416,
Command::Periodic(R0_5, High) => 0x2032,
Command::Periodic(R0_5, Medium) => 0x2024,
Command::Periodic(R0_5, Low) => 0x202F,
Command::Periodic(R1, High) => 0x2130,
Command::Periodic(R1, Medium) => 0x2126,
Command::Periodic(R1, Low) => 0x212D,
Command::Periodic(R2, High) => 0x2236,
Command::Periodic(R2, Medium) => 0x2220,
Command::Periodic(R2, Low) => 0x222B,
Command::Periodic(R4, High) => 0x2334,
Command::Periodic(R4, Medium) => 0x2322,
Command::Periodic(R4, Low) => 0x2329,
Command::Periodic(R10, High) => 0x2737,
Command::Periodic(R10, Medium) => 0x2721,
Command::Periodic(R10, Low) => 0x272A,
Command::FetchData => 0xE000,
Command::PeriodicWithART => 0x2B32,
Command::Break => 0x3093,
Command::SoftReset => 0x30A2,
Command::HeaterEnable => 0x306D,
Command::HeaterDisable => 0x3066,
Command::Status => 0xF32D,
Command::ClearStatus => 0x3041,
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}