mpu6000 0.3.0

Platform agnostic driver for MPU6000 6-axis IMU
Documentation
use core::slice::from_mut;

use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::blocking::{i2c, spi};
use embedded_hal::digital::v2::OutputPin;

use super::registers::Register;

pub enum SpiError<WE, TE, OE> {
    WriteError(WE),
    TransferError(TE),
    OutputPinError(OE),
}

pub struct SpiBus<BUS, CS, DELAY> {
    bus: BUS,
    cs: CS,
    delay: DELAY,
}

pub trait RegAccess {
    type Error;
    fn write(&mut self, reg: Register, value: u8) -> Result<(), Self::Error>;
    fn read(&mut self, reg: Register) -> Result<u8, Self::Error>;
    fn reads(&mut self, reg: Register, output: &mut [u8]) -> Result<(), Self::Error>;
}

impl<WE, TE, OE, SPI, CS, DELAY> SpiBus<SPI, CS, DELAY>
where
    SPI: spi::Write<u8, Error = WE> + spi::Transfer<u8, Error = TE>,
    CS: OutputPin<Error = OE>,
    DELAY: DelayUs<u8>,
{
    pub fn new(spi: SPI, cs: CS, delay: DELAY) -> Self {
        Self { bus: spi, cs, delay }
    }

    fn chip_select(&mut self, select: bool) -> Result<(), SpiError<WE, TE, OE>> {
        if select { self.cs.set_low() } else { self.cs.set_high() }
            .map_err(|e| SpiError::OutputPinError(e))
    }
}

impl<SPI, CS, DELAY> SpiBus<SPI, CS, DELAY> {
    pub fn free(self) -> (SPI, CS, DELAY) {
        (self.bus, self.cs, self.delay)
    }
}

impl<WE, TE, OE, SPI, CS, DELAY> RegAccess for SpiBus<SPI, CS, DELAY>
where
    SPI: spi::Write<u8, Error = WE> + spi::Transfer<u8, Error = TE>,
    CS: OutputPin<Error = OE>,
    DELAY: DelayUs<u8>,
{
    type Error = SpiError<WE, TE, OE>;

    fn write(&mut self, reg: Register, value: u8) -> Result<(), Self::Error> {
        self.chip_select(true)?;
        self.delay.delay_us(1);
        let result = self.bus.write(&[reg as u8, value]);
        self.chip_select(false)?;
        self.delay.delay_us(1);
        result.map_err(|e| Self::Error::WriteError(e))
    }

    fn read(&mut self, reg: Register) -> Result<u8, Self::Error> {
        let mut value = 0u8;
        self.chip_select(true)?;
        self.delay.delay_us(1);
        self.bus.write(&[reg as u8 | 0x80]).map_err(|e| Self::Error::WriteError(e))?;
        self.bus.transfer(from_mut(&mut value)).map_err(|e| Self::Error::TransferError(e))?;
        self.chip_select(false)?;
        self.delay.delay_us(1);
        Ok(value)
    }

    fn reads(&mut self, reg: Register, output: &mut [u8]) -> Result<(), Self::Error> {
        self.chip_select(true)?;
        self.delay.delay_us(1);
        self.bus.write(&[reg as u8 | 0x80]).map_err(|e| Self::Error::WriteError(e))?;
        self.bus.transfer(output).map_err(|e| Self::Error::TransferError(e))?;
        self.chip_select(false)?;
        self.delay.delay_us(1);
        Ok(())
    }
}

pub struct I2cBus<BUS, DELAY> {
    bus: BUS,
    address: u8,
    delay: DELAY,
}

impl<WE, RE, I2C, DELAY> I2cBus<I2C, DELAY>
where
    I2C: i2c::Write<Error = WE> + i2c::Read<Error = RE>,
{
    pub fn i2c(i2c: I2C, address: u8, delay: DELAY) -> Self {
        Self { bus: i2c, address, delay }
    }
}

impl<I2C, DELAY> I2cBus<I2C, DELAY> {
    pub fn free(self) -> (I2C, DELAY) {
        (self.bus, self.delay)
    }
}

pub enum I2CError<RE, WE> {
    ReadError(RE),
    WriteError(WE),
}

impl<RE, WE, I2C, DELAY> RegAccess for I2cBus<I2C, DELAY>
where
    I2C: i2c::Read<Error = RE> + i2c::Write<Error = WE>,
    DELAY: DelayUs<u8>,
{
    type Error = I2CError<RE, WE>;

    fn write(&mut self, reg: Register, value: u8) -> Result<(), Self::Error> {
        self.bus.write(self.address, &[reg as u8, value]).map_err(|e| Self::Error::WriteError(e))
    }

    fn read(&mut self, reg: Register) -> Result<u8, Self::Error> {
        let mut value = 0u8;
        self.bus
            .write(self.address, &[reg as u8 | 0x80])
            .map_err(|e| Self::Error::WriteError(e))?;

        self.bus.read(self.address, from_mut(&mut value)).map_err(|e| Self::Error::ReadError(e))?;
        Ok(value)
    }

    fn reads(&mut self, reg: Register, output: &mut [u8]) -> Result<(), Self::Error> {
        self.bus
            .write(self.address, &[reg as u8 | 0x80])
            .map_err(|e| Self::Error::WriteError(e))?;
        self.bus.read(self.address, output).map_err(|e| Self::Error::ReadError(e))?;
        Ok(())
    }
}