use embedded_devices_derive::{forward_register_fns, sensor};
use embedded_interfaces::{TransportError, registers::WritableRegister};
use uom::si::f64::ThermodynamicTemperature;
pub mod address;
pub mod registers;
use self::registers::{AveragingMode, Configuration, ConversionMode, Temperature};
#[derive(Debug, thiserror::Error)]
pub enum InitError<BusError> {
#[error("transport error")]
Transport(#[from] TransportError<(), BusError>),
#[error("invalid device id {0:#04x}")]
InvalidDeviceId(u16),
}
#[derive(Debug, thiserror::Error)]
pub enum EepromError<BusError> {
#[error("transport error")]
Transport(#[from] TransportError<(), BusError>),
#[error("eeprom still busy")]
EepromStillBusy,
}
#[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 TMP117<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
delay: D,
interface: I,
}
pub trait TMP117Register {}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), I2cDevice),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D, I> TMP117<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]
#[sensor(Temperature)]
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> TMP117<D, I> {
pub async fn init(&mut self) -> Result<(), InitError<I::BusError>> {
use self::registers::DeviceIdRevision;
use crate::device::ResettableDevice;
self.reset().await?;
let device_id = self.read_register::<DeviceIdRevision>().await?.read_device_id();
if device_id != self::registers::DEVICE_ID_VALID {
return Err(InitError::InvalidDeviceId(device_id));
}
Ok(())
}
pub async fn write_eeprom<R>(&mut self) -> Result<(), EepromError<I::BusError>>
where
R: WritableRegister + TMP117Register,
{
use self::registers::{EepromLockMode, EepromUnlock};
self.write_register(EepromUnlock::default().with_lock_mode(EepromLockMode::Unlocked))
.await?;
self.delay.delay_ms(7).await;
const TRIES: u8 = 5;
for _ in 0..TRIES {
if !self.read_register::<EepromUnlock>().await?.read_busy() {
self.write_register(EepromUnlock::default().with_lock_mode(EepromLockMode::Locked))
.await?;
return Ok(());
}
self.delay.delay_ms(1).await;
}
Err(EepromError::EepromStillBusy)
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::device::ResettableDevice
for TMP117<D, I>
{
type Error = TransportError<(), I::BusError>;
async fn reset(&mut self) -> Result<(), Self::Error> {
self.write_register(Configuration::default().with_soft_reset(true))
.await?;
self.delay.delay_ms(2).await;
Ok(())
}
}
#[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 TMP117<D, I>
{
type Error = TransportError<(), I::BusError>;
type Measurement = Measurement;
async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
let reg_conf = self.read_register::<Configuration>().await?;
self.write_register(reg_conf.with_conversion_mode(ConversionMode::Oneshot))
.await?;
let active_conversion_time = reg_conf.read_averaging_mode().factor() as u32 * 15_500;
self.delay.delay_us(active_conversion_time).await;
let temperature = self.read_register::<Temperature>().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 TMP117<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_conversion_mode(ConversionMode::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_conversion_mode(ConversionMode::Shutdown))
.await?;
Ok(())
}
async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
let reg_conf = self.read_register::<Configuration>().await?;
let min_conversion_time = match reg_conf.read_averaging_mode() {
AveragingMode::X_1 => 0,
AveragingMode::X_8 => 125_000,
AveragingMode::X_32 => 500_000,
AveragingMode::X_64 => 1_000_000,
};
let conversion_time_us = reg_conf
.read_conversion_cycle_time()
.interval_us()
.max(min_conversion_time);
Ok(conversion_time_us)
}
async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
let temperature = self.read_register::<Temperature>().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"))
}
}