sen6x-driver 0.0.3

embedded-hal driver for the sensirion sen6x sensors
use crate::commands::CommandId;
use crate::connection::State;
use crate::io::{FromBytes, ToBytes};
use crate::types::Milliseconds;
use crate::{Sen6x, SensorConnectionSync, SensorState, errors};
use core::cell::RefCell;
use embedded_hal::delay::DelayNs;
use embedded_hal::i2c::{I2c, Operation};

impl<'a, I2C, D, E> SensorConnectionSync for Sen6x<'a, RefCell<&'a mut I2C>, D>
where
    I2C: I2c<Error = E>,
    D: DelayNs,
{
    type I2c = I2C;
    type Error = E;
    type Delay = D;

    fn transaction<R>(&self, f: impl FnOnce(&mut I2C) -> R) -> R {
        let mut i2c = self.i2c.borrow_mut();
        f(&mut i2c)
    }

    fn delay(&self, delay: Milliseconds) {
        self.delay.borrow_mut().delay_ms(delay as u32);
    }
}

impl<S, T> crate::connection::Sen6xConnection<S, T::Error> for T
where
    T: SensorConnectionSync + SensorState<T::Error>,
    S: crate::connection::SensorModel,
{
    fn send(
        &mut self,
        cmd: CommandId,
        execution_time: Milliseconds,
        valid_in: &[State],
    ) -> Result<(), crate::Error<T::Error>> {
        self.check_state(valid_in)?;
        let this = &*self;
        this.transaction(move |i2c| {
            i2c.write(S::I2C_ADDRESS, &(cmd as u16).to_be_bytes())
                .map_err(errors::Error::I2c)?;
            this.delay(execution_time);
            Ok(())
        })
    }

    fn write<const N: usize, Tx: ToBytes<N>>(
        &mut self,
        cmd: CommandId,
        execution_time: Milliseconds,
        data: Tx,
        valid_in: &[State],
    ) -> Result<(), crate::Error<T::Error>> {
        self.check_state(valid_in)?;
        let this = &*self;

        this.transaction(move |i2c| {
            i2c.transaction(
                S::I2C_ADDRESS,
                &mut [
                    Operation::Write(&(cmd as u16).to_be_bytes()),
                    Operation::Write(&data.to_bytes()),
                ],
            )
            .map_err(errors::Error::I2c)?;
            this.delay(execution_time);
            Ok(())
        })
    }

    fn read<const N: usize, Rx: FromBytes<N, Rx>>(
        &mut self,
        cmd: CommandId,
        execution_time: Milliseconds,
        valid_in: &[State],
    ) -> Result<Rx, crate::Error<T::Error>> {
        self.check_state(valid_in)?;
        let this = &*self;
        this.transaction(move |i2c| {
            i2c.write(S::I2C_ADDRESS, &(cmd as u16).to_be_bytes())
                .map_err(errors::Error::I2c)?;
            this.delay(execution_time);
            let mut buffer = [0u8; N];
            i2c.read(S::I2C_ADDRESS, &mut buffer)
                .map_err(errors::Error::I2c)?;
            Rx::from_bytes_with_crc(&buffer)
        })
    }

    fn fetch<const NT: usize, const NR: usize, Rx: FromBytes<NR, Rx>, Tx: ToBytes<NT>>(
        &mut self,
        cmd: CommandId,
        execution_time: Milliseconds,
        data: Tx,
        valid_in: &[State],
    ) -> Result<Rx, crate::Error<T::Error>> {
        self.check_state(valid_in)?;
        let this = &*self;

        this.transaction(move |i2c| {
            i2c.transaction(
                S::I2C_ADDRESS,
                &mut [
                    Operation::Write(&(cmd as u16).to_be_bytes()),
                    Operation::Write(&data.to_bytes()),
                ],
            )
            .map_err(errors::Error::I2c)?;
            this.delay(execution_time);
            let mut buffer = [0u8; NR];
            i2c.read(S::I2C_ADDRESS, &mut buffer)
                .map_err(errors::Error::I2c)?;
            Rx::from_bytes_with_crc(&buffer)
        })
    }

    fn update_state(&mut self, state: State) {
        *self.state() = state;
    }
}