use core::{convert::Infallible, future::Future};
use device_register_async::{EditRegister, ReadRegister, WriteRegister};
use embedded_hal::{digital::ErrorType, i2c::SevenBitAddress};
use embedded_hal_async::{delay::DelayNs, digital::Wait, i2c::I2c};
use crate::{register::*, Alert, ContinuousConfig, Error, Id, CELCIUS_CONVERSION};
use self::tmp117_ll::Tmp117LL;
pub mod tmp117_ll;
pub struct DummyWait(());
impl ErrorType for DummyWait {
type Error = Infallible;
}
impl Wait for DummyWait {
async fn wait_for_high(&'_ mut self) -> Result<(), Self::Error> {
unreachable!()
}
async fn wait_for_low(&'_ mut self) -> Result<(), Self::Error> {
unreachable!()
}
async fn wait_for_rising_edge(&'_ mut self) -> Result<(), Self::Error> {
unreachable!()
}
async fn wait_for_falling_edge(&'_ mut self) -> Result<(), Self::Error> {
unreachable!()
}
async fn wait_for_any_edge(&'_ mut self) -> Result<(), Self::Error> {
unreachable!()
}
}
enum AlertPin<P> {
Unkown(P),
DataReady(P),
Alert(P),
}
impl<P> AlertPin<P> {
fn unwrap(self) -> P {
match self {
AlertPin::Unkown(p) => p,
AlertPin::DataReady(p) => p,
AlertPin::Alert(p) => p,
}
}
}
pub struct Tmp117<T, E, P> {
tmp_ll: Tmp117LL<T, E>,
alert: Option<AlertPin<P>>,
}
impl<T, E> Tmp117<T, E, DummyWait>
where
T: I2c<SevenBitAddress, Error = E>,
E: embedded_hal::i2c::Error,
{
pub fn new(i2c: T, addr: u8) -> Tmp117<T, E, DummyWait> {
Tmp117::<T, E, DummyWait> {
tmp_ll: Tmp117LL::new(i2c, addr),
alert: None,
}
}
}
impl<T, E, P> Tmp117<T, E, P>
where
T: I2c<SevenBitAddress, Error = E>,
E: embedded_hal::i2c::Error,
P: Wait,
{
pub fn new_alert(i2c: T, addr: u8, alert: P) -> Self {
Self {
tmp_ll: Tmp117LL::new(i2c, addr),
alert: Some(AlertPin::Unkown(alert)),
}
}
pub fn new_from_ll(tmp_ll: Tmp117LL<T, E>, alert: P) -> Self {
Self {
tmp_ll,
alert: Some(AlertPin::Unkown(alert)),
}
}
pub async fn id(&mut self) -> Result<Id, Error<E>> {
let id: DeviceID = self.tmp_ll.read().await?;
Ok(Id {
device: id.device_id().into(),
revision: id.revision().into(),
})
}
async fn wait_eeprom(&mut self) -> Result<(), Error<E>> {
let mut configuration: Configuration = self.tmp_ll.read().await?;
while configuration.eeprom_busy() {
configuration = self.tmp_ll.read().await?;
}
Ok(())
}
async fn read_temp_raw(&mut self) -> Result<f32, Error<E>> {
let temp: Temperature = self.tmp_ll.read().await?;
let val = (u16::from(temp) as i16) as f32 * CELCIUS_CONVERSION;
Ok(val)
}
async fn check_alert(&mut self) -> Result<Alert, Error<E>> {
let config: Configuration = self.tmp_ll.read().await?;
if config.high_alert() && config.low_alert() {
Ok(Alert::HighLow)
} else if config.high_alert() {
Ok(Alert::High)
} else if config.low_alert() {
Ok(Alert::Low)
} else {
Ok(Alert::None)
}
}
async fn set_alert(&mut self) -> Result<(), Error<E>> {
if let Some(p) = &mut self.alert {
if let AlertPin::Alert(_) = p {
} else {
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_dr_alert(AlertPinSelect::Alert);
r.set_polarity(Polarity::ActiveLow);
})
.await?;
}
self.alert = self.alert.take().map(|v| AlertPin::Alert(v.unwrap()));
}
Ok(())
}
async fn set_data_ready(&mut self) -> Result<(), Error<E>> {
if let Some(p) = &mut self.alert {
if let AlertPin::DataReady(_) = p {
} else {
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_dr_alert(AlertPinSelect::DataReady);
r.set_polarity(Polarity::ActiveLow);
})
.await?;
}
self.alert = self.alert.take().map(|v| AlertPin::DataReady(v.unwrap()));
}
Ok(())
}
async fn wait_for_data(&mut self) -> Result<(), Error<E>> {
if let Some(AlertPin::DataReady(p)) = &mut self.alert {
loop {
p.wait_for_low().await.map_err(|_| Error::AlertPin)?;
let config: Configuration = self.tmp_ll.read().await?;
if config.data_ready() {
break;
}
}
} else {
loop {
let config: Configuration = self.tmp_ll.read().await?;
if config.data_ready() {
break;
}
}
}
Ok(())
}
async fn wait_for_alert(&mut self) -> Result<Alert, Error<E>> {
if let Some(AlertPin::Alert(p)) = &mut self.alert {
p.wait_for_low().await.map_err(|_| Error::AlertPin)?;
self.check_alert().await
} else {
loop {
let alert = self.check_alert().await;
if let Ok(Alert::None) = alert {
continue;
} else {
return alert;
}
}
}
}
async fn set_continuous(
&mut self,
config: ContinuousConfig,
) -> Result<ContinuousHandler<T, E, P>, Error<E>> {
self.set_data_ready().await?;
if let Some(val) = config.high {
let high: HighLimit = ((val / CELCIUS_CONVERSION) as u16).into();
self.tmp_ll.write(high).await?;
}
if let Some(val) = config.low {
let low: LowLimit = ((val / CELCIUS_CONVERSION) as u16).into();
self.tmp_ll.write(low).await?;
}
if let Some(val) = config.offset {
let off: TemperatureOffset = ((val / CELCIUS_CONVERSION) as u16).into();
self.tmp_ll.write(off).await?;
}
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_mode(ConversionMode::Continuous);
r.set_average(config.average);
r.set_conversion(config.conversion);
})
.await?;
Ok(ContinuousHandler { tmp117: self })
}
async fn set_oneshot(&mut self, average: Average) -> Result<(), Error<E>> {
self.set_data_ready().await?;
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_mode(ConversionMode::OneShot);
r.set_average(average);
})
.await?;
Ok(())
}
async fn set_shutdown(&mut self) -> Result<(), Error<E>> {
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_mode(ConversionMode::Shutdown);
})
.await?;
Ok(())
}
pub async fn reset<D>(&mut self, delay: &mut D) -> Result<(), Error<E>>
where
D: DelayNs,
{
self.tmp_ll
.edit(|r: &mut Configuration| {
r.set_reset(true);
})
.await?;
delay.delay_ms(2).await;
self.set_shutdown().await
}
pub async fn write_eeprom(&mut self, values: [u16; 3]) -> Result<(), Error<E>> {
self.wait_eeprom().await?;
self.tmp_ll.write(UEEPROM1::from(values[0])).await?;
self.wait_eeprom().await?;
self.tmp_ll.write(UEEPROM2::from(values[1])).await?;
self.wait_eeprom().await?;
self.tmp_ll.write(UEEPROM3::from(values[2])).await?;
Ok(())
}
pub async fn read_eeprom(&mut self) -> Result<[u16; 3], Error<E>> {
let u1: UEEPROM1 = self.tmp_ll.read().await?;
let u2: UEEPROM2 = self.tmp_ll.read().await?;
let u3: UEEPROM3 = self.tmp_ll.read().await?;
Ok([u1.into(), u2.into(), u3.into()])
}
pub async fn oneshot(&mut self, average: Average) -> Result<f32, Error<E>> {
self.set_oneshot(average).await?;
self.wait_for_data().await?;
let res = self.read_temp_raw().await?;
self.set_shutdown().await?;
Ok(res)
}
pub async fn continuous<F, Fut>(
&mut self,
config: ContinuousConfig,
f: F,
) -> Result<(), Error<E>>
where
F: FnOnce(ContinuousHandler<T, E, P>) -> Fut,
Fut: Future<Output = Result<(), Error<E>>>,
{
let continuous = self.set_continuous(config).await?;
f(continuous).await?;
self.set_shutdown().await
}
}
pub struct ContinuousHandler<T, E, P> {
tmp117: *mut Tmp117<T, E, P>,
}
impl<'a, T, E, P> ContinuousHandler<T, E, P>
where
T: I2c<SevenBitAddress, Error = E>,
E: embedded_hal::i2c::Error,
P: Wait,
{
pub async fn read_temp(&mut self) -> Result<f32, Error<E>> {
let tmp117 = unsafe { &mut *self.tmp117 };
let config: Configuration = tmp117.tmp_ll.read().await?;
if !config.data_ready() {
return Err(Error::DataNotReady);
}
tmp117.read_temp_raw().await
}
pub async fn wait_temp(&mut self) -> Result<f32, Error<E>> {
let tmp117 = unsafe { &mut *self.tmp117 };
tmp117.set_data_ready().await?;
tmp117.wait_for_data().await?;
tmp117.read_temp_raw().await
}
pub async fn get_alert(&mut self) -> Result<Alert, Error<E>> {
let tmp117 = unsafe { &mut *self.tmp117 };
tmp117.check_alert().await
}
pub async fn wait_alert(&mut self) -> Result<Alert, Error<E>> {
let tmp117 = unsafe { &mut *self.tmp117 };
tmp117.set_alert().await?;
tmp117.wait_for_alert().await
}
}