mmc5983_rs/
interface.rs

1//! I2C/SPI interfaces
2use maybe_async_cfg::maybe;
3
4#[cfg(not(feature = "async"))]
5use embedded_hal::{i2c, spi};
6#[cfg(feature = "async")]
7use embedded_hal_async::{i2c, spi};
8
9use crate::{
10    private,
11    register_address::{RegRead, RegWrite},
12    Error,
13};
14
15/// MMC5983 I2C address (7-bit)
16pub(crate) const MMC5983_ADDR: u8 = 0b0110000;
17
18/// I2C interface
19#[derive(Debug)]
20pub struct I2cInterface<I2C> {
21    pub(crate) i2c: I2C,
22}
23
24/// SPI interface
25#[derive(Debug)]
26pub struct SpiInterface<SPI> {
27    pub(crate) spi: SPI,
28}
29
30/// Write data
31#[maybe(
32    sync(cfg(not(feature = "async")), keep_self,),
33    async(cfg(feature = "async"), keep_self,)
34)]
35pub trait WriteData: private::Sealed {
36    /// Error type
37    type Error;
38
39    /// Write to register
40    async fn write_register<R: RegWrite>(&mut self, reg: R) -> Result<(), Self::Error>;
41}
42
43#[maybe(
44    sync(cfg(not(feature = "async")), keep_self,),
45    async(cfg(feature = "async"), keep_self,)
46)]
47impl<I2C, E> WriteData for I2cInterface<I2C>
48where
49    I2C: i2c::I2c<Error = E>,
50{
51    type Error = Error<E>;
52
53    async fn write_register<R: RegWrite>(&mut self, reg: R) -> Result<(), Self::Error> {
54        let payload: [u8; 2] = [R::ADDR, reg.data()];
55        self.i2c
56            .write(MMC5983_ADDR, &payload)
57            .await
58            .map_err(Error::Comm)
59    }
60}
61
62#[maybe(
63    sync(cfg(not(feature = "async")), keep_self,),
64    async(cfg(feature = "async"), keep_self,)
65)]
66impl<SPI, CommE> WriteData for SpiInterface<SPI>
67where
68    SPI: spi::SpiDevice<u8, Error = CommE>,
69{
70    type Error = Error<CommE>;
71
72    async fn write_register<R: RegWrite>(&mut self, reg: R) -> Result<(), Self::Error> {
73        let payload: [u8; 2] = [R::ADDR & !SPI_RW, reg.data()];
74        self.spi.write(&payload).await.map_err(Error::Comm)
75    }
76}
77
78/// Read data
79#[maybe(
80    sync(cfg(not(feature = "async")), keep_self,),
81    async(cfg(feature = "async"), keep_self,)
82)]
83pub trait ReadData: private::Sealed {
84    /// Error type
85    type Error;
86
87    /// Read a register
88    async fn read_register<R: RegRead>(&mut self) -> Result<R::Output, Self::Error>;
89
90    /// Read multiple consecutive registers
91    async fn read_consecutive(
92        &mut self,
93        start_addr: u8,
94        buffer: &mut [u8],
95    ) -> Result<(), Self::Error>;
96}
97
98const SPI_RW: u8 = 1 << 7;
99
100#[maybe(
101    sync(cfg(not(feature = "async")), keep_self,),
102    async(cfg(feature = "async"), keep_self,)
103)]
104impl<I2C, E> ReadData for I2cInterface<I2C>
105where
106    I2C: i2c::I2c<Error = E>,
107{
108    type Error = Error<E>;
109
110    async fn read_register<R: RegRead>(&mut self) -> Result<R::Output, Self::Error> {
111        let mut data = [0];
112        self.i2c
113            .write_read(MMC5983_ADDR, &[R::ADDR], &mut data)
114            .await
115            .map_err(Error::Comm)?;
116
117        Ok(R::from_data(data[0]))
118    }
119
120    async fn read_consecutive(
121        &mut self,
122        start_addr: u8,
123        buffer: &mut [u8],
124    ) -> Result<(), Self::Error> {
125        self.i2c
126            .write_read(MMC5983_ADDR, &[start_addr], buffer)
127            .await
128            .map_err(Error::Comm)
129    }
130}
131
132#[maybe(
133    sync(cfg(not(feature = "async")), keep_self,),
134    async(cfg(feature = "async"), keep_self,)
135)]
136impl<SPI, CommE> ReadData for SpiInterface<SPI>
137where
138    SPI: spi::SpiDevice<u8, Error = CommE>,
139{
140    type Error = Error<CommE>;
141
142    async fn read_register<R: RegRead>(&mut self) -> Result<R::Output, Self::Error> {
143        let mut data = [SPI_RW | R::ADDR, 0];
144        self.spi
145            .transfer_in_place(&mut data)
146            .await
147            .map_err(Error::Comm)?;
148
149        Ok(R::from_data(data[1]))
150    }
151
152    async fn read_consecutive(
153        &mut self,
154        start_addr: u8,
155        buffer: &mut [u8],
156    ) -> Result<(), Self::Error> {
157        // Create a new buffer with space for the address byte plus the data
158        let mut data = [0u8; 32]; // Size should be larger than any consecutive read we'll do
159        if buffer.len() >= data.len() {
160            return Err(Error::InvalidInputData);
161        }
162
163        // Setup the command byte and copy in any data
164        data[0] = SPI_RW | start_addr;
165
166        // Only use the part of the array we need
167        let data_slice = &mut data[..=buffer.len()];
168
169        self.spi
170            .transfer_in_place(data_slice)
171            .await
172            .map_err(Error::Comm)?;
173
174        buffer.copy_from_slice(&data_slice[1..]);
175        Ok(())
176    }
177}