use embedded_devices_derive::{forward_register_fns, sensor};
use embedded_interfaces::TransportError;
use uom::si::f64::ThermodynamicTemperature;
pub mod address;
pub mod registers;
use self::registers::{AmbientTemperature, Configuration, DeviceIdRevision, ManufacturerId, Resolution, ShutdownMode};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, thiserror::Error)]
pub enum InitError<BusError> {
#[error("transport error")]
Transport(#[from] TransportError<(), BusError>),
#[error("invalid device id")]
InvalidDeviceId,
#[error("invalid manufacturer id")]
InvalidManufacturerId,
}
#[derive(Debug, embedded_devices_derive::Measurement)]
pub struct Measurement {
#[measurement(Temperature)]
pub temperature: ThermodynamicTemperature,
}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
sync(feature = "sync"),
async(feature = "async")
)]
pub struct MCP9808<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
delay: D,
interface: I,
}
pub trait MCP9808Register {}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), I2cDevice),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D, I> MCP9808<D, embedded_interfaces::i2c::I2cDevice<I, hal::i2c::SevenBitAddress>>
where
I: hal::i2c::I2c<hal::i2c::SevenBitAddress> + hal::i2c::ErrorType,
D: hal::delay::DelayNs,
{
#[inline]
pub fn new_i2c(delay: D, interface: I, address: self::address::Address) -> Self {
Self {
delay,
interface: embedded_interfaces::i2c::I2cDevice::new(interface, address.into()),
}
}
}
#[forward_register_fns]
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> MCP9808<D, I> {
pub async fn init(&mut self) -> Result<(), InitError<I::BusError>> {
let device_id = self.read_register::<DeviceIdRevision>().await?;
if device_id.read_device_id() != self::registers::DEVICE_ID_VALID {
return Err(InitError::InvalidDeviceId);
}
let manufacturer_id = self.read_register::<ManufacturerId>().await?;
if manufacturer_id.read_manufacturer_id() != self::registers::MANUFACTURER_ID_VALID {
return Err(InitError::InvalidManufacturerId);
}
Ok(())
}
}
#[sensor(Temperature)]
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
OneshotSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::OneshotSensor
for MCP9808<D, I>
{
type Error = TransportError<(), I::BusError>;
type Measurement = Measurement;
async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
let mut reg_conf = self.read_register::<Configuration>().await?;
reg_conf.write_shutdown_mode(ShutdownMode::Continuous);
self.write_register(reg_conf).await?;
let resolution = self.read_register::<Resolution>().await?;
let conversion_time = 1000 + resolution.read_temperature_resolution().conversion_time_us();
self.delay.delay_us(conversion_time).await;
reg_conf.write_shutdown_mode(ShutdownMode::Shutdown);
self.write_register(reg_conf).await?;
let temperature = self.read_register::<AmbientTemperature>().await?.read_temperature();
Ok(Measurement { temperature })
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ContinuousSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::ContinuousSensor
for MCP9808<D, I>
{
type Error = TransportError<(), I::BusError>;
type Measurement = Measurement;
async fn start_measuring(&mut self) -> Result<(), Self::Error> {
let reg_conf = self.read_register::<Configuration>().await?;
self.write_register(reg_conf.with_shutdown_mode(ShutdownMode::Continuous))
.await?;
Ok(())
}
async fn stop_measuring(&mut self) -> Result<(), Self::Error> {
let reg_conf = self.read_register::<Configuration>().await?;
self.write_register(reg_conf.with_shutdown_mode(ShutdownMode::Shutdown))
.await?;
Ok(())
}
async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
let resolution = self.read_register::<Resolution>().await?;
let conversion_time = resolution.read_temperature_resolution().conversion_time_us();
Ok(conversion_time)
}
async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
let temperature = self.read_register::<AmbientTemperature>().await?.read_temperature();
Ok(Some(Measurement { temperature }))
}
async fn is_measurement_ready(&mut self) -> Result<bool, Self::Error> {
Ok(true)
}
async fn next_measurement(&mut self) -> Result<Self::Measurement, Self::Error> {
let interval = self.measurement_interval_us().await?;
self.delay.delay_us(interval).await;
self.current_measurement()
.await?
.ok_or_else(|| TransportError::Unexpected("measurement was not ready even though we expected it to be"))
}
}