afe4404 0.2.2

AFE4404 driver for Rust embedded-hal.
Documentation
//! This module contains the value reading related functions.

use embedded_hal::i2c::I2c;
use embedded_hal::i2c::SevenBitAddress;
use uom::si::electric_potential::volt;
use uom::si::f32::ElectricPotential;

use crate::{
    device::AFE4404,
    errors::AfeError,
    modes::{LedMode, ThreeLedsMode, TwoLedsMode},
};

pub use configuration::{AveragedReadings, Readings};

mod configuration;

impl<I2C, MODE> AFE4404<I2C, MODE>
where
    I2C: I2c<SevenBitAddress>,
    MODE: LedMode,
{
    /// Returns an array of raw readings from the frontend.
    ///
    /// # Errors
    ///
    /// This function will return an error if the I2C bus encounters an error.
    #[allow(clippy::similar_names)]
    fn get_raw_readings(&mut self) -> Result<[ElectricPotential; 8], AfeError<I2C::Error>> {
        let r2ah_prev = self.registers.r2Ah.read()?;
        let r2bh_prev = self.registers.r2Bh.read()?;
        let r2ch_prev = self.registers.r2Ch.read()?;
        let r2dh_prev = self.registers.r2Dh.read()?;
        let r2eh_prev = self.registers.r2Eh.read()?;
        let r2fh_prev = self.registers.r2Fh.read()?;
        let r3fh_prev = self.registers.r3Fh.read()?;
        let r40h_prev = self.registers.r40h.read()?;

        let quantisation: ElectricPotential = ElectricPotential::new::<volt>(1.2) / 2_097_151.0;

        let mut values: [ElectricPotential; 8] = Default::default();

        // We are converting a 22 bit reading (stored in a 32 bit register) to a 32 bit float.
        // Since the 32 bit float has a 23 bits, we allow a precision loss.
        // We also allow wraps since we take the sign into account.
        #[allow(clippy::cast_precision_loss, clippy::cast_possible_wrap)]
        for (i, &register_value) in [
            r2ch_prev.led1val(),
            r2ah_prev.led2val(),
            r2dh_prev.aled1val(),
            r2bh_prev.aled2val_or_led3val(),
            r2fh_prev.led1_minus_aled1val(),
            r2eh_prev.led2_minus_aled2val(),
            r40h_prev.avg_led1_minus_aled1val(),
            r3fh_prev.avg_led2_minus_aled2val(),
        ]
        .iter()
        .enumerate()
        {
            let sign_extension_bits = ((register_value & 0x00FF_FFFF) >> 21) as u8;
            let signed_value = match sign_extension_bits {
                0b000 => register_value as i32, // The value is positive.
                0b111 => (register_value | 0xFF00_0000) as i32, // Extend the sign of the negative value.
                _ => return Err(AfeError::AdcReadingOutsideAllowedRange),
            };
            values[i] = signed_value as f32 * quantisation;
        }

        Ok(values)
    }
}

impl<I2C> AFE4404<I2C, ThreeLedsMode>
where
    I2C: I2c<SevenBitAddress>,
{
    /// Reads the sampled values.
    ///
    /// # Notes
    ///
    /// Call this function after an `ADC_RDY` pulse, data will remain valid until next `ADC_RDY` pulse.
    ///
    /// # Errors
    ///
    /// This function returns an error if the I2C bus encounters an error.
    /// This function returns an error if the ADC reading falls outside the allowed range.
    pub fn read(&mut self) -> Result<Readings<ThreeLedsMode>, AfeError<I2C::Error>> {
        let values = self.get_raw_readings()?;

        Ok(Readings::<ThreeLedsMode>::new(
            values[0], values[1], values[3], values[2], values[4],
        ))
    }

    /// Reads the values averaged over a number of samples set by the `decimation_factor`.
    ///
    /// # Notes
    ///
    /// When the decimation factor is greater than one, call this function after an `ADC_RDY` pulse, data will remain valid untill next `ADC_RDY` pulse.
    ///
    /// # Errors
    ///
    /// This function returns an error if the I2C bus encounters an error.
    /// This function returns an error if the ADC reading falls outside the allowed range.
    pub fn read_averaged(
        &mut self,
    ) -> Result<AveragedReadings<ThreeLedsMode>, AfeError<I2C::Error>> {
        let values = self.get_raw_readings()?;

        Ok(AveragedReadings::<ThreeLedsMode>::new(values[6]))
    }
}

impl<I2C> AFE4404<I2C, TwoLedsMode>
where
    I2C: I2c<SevenBitAddress>,
{
    /// Reads the sampled values.
    ///
    /// # Notes
    ///
    /// Call this function after an `ADC_RDY` pulse, data will remain valid until next `ADC_RDY` pulse.
    ///
    /// # Errors
    ///
    /// This function returns an error if the I2C bus encounters an error.
    /// This function returns an error if the ADC reading falls outside the allowed range.
    #[allow(clippy::similar_names)]
    pub fn read(&mut self) -> Result<Readings<TwoLedsMode>, AfeError<I2C::Error>> {
        let values = self.get_raw_readings()?;

        Ok(Readings::<TwoLedsMode>::new(
            values[0], values[1], values[2], values[3], values[4], values[5],
        ))
    }

    /// Reads the values averaged over a number of samples set by the `decimation_factor`.
    ///
    /// # Notes
    ///
    /// When the decimation factor is greater than one, call this function after an `ADC_RDY` pulse, data will remain valid untill next `ADC_RDY` pulse.
    ///
    /// # Errors
    ///
    /// This function returns an error if the I2C bus encounters an error.
    /// This function returns an error if the ADC reading falls outside the allowed range.
    pub fn read_averaged(&mut self) -> Result<AveragedReadings<TwoLedsMode>, AfeError<I2C::Error>> {
        let values = self.get_raw_readings()?;

        Ok(AveragedReadings::<TwoLedsMode>::new(values[6], values[7]))
    }
}