Skip to main content

bmi323_driver/
transport.rs

1use embedded_hal::i2c::I2c;
2use embedded_hal::spi::{Operation, SpiDevice};
3use embedded_hal_async::i2c::I2c as AsyncI2c;
4use embedded_hal_async::spi::SpiDevice as AsyncSpiDevice;
5
6use crate::{Bmi323, Bmi323Async};
7
8/// Blocking I2C transport wrapper used by [`Bmi323`].
9///
10/// Most users do not need to construct this directly. Prefer
11/// [`Bmi323::new_i2c`](crate::Bmi323::new_i2c).
12pub struct SyncI2cTransport<I2C> {
13    pub(crate) bus: I2C,
14    pub(crate) address: u8,
15}
16
17/// Blocking SPI transport wrapper used by [`Bmi323`].
18///
19/// Most users do not need to construct this directly. Prefer
20/// [`Bmi323::new_spi`](crate::Bmi323::new_spi).
21pub struct SyncSpiTransport<SPI> {
22    pub(crate) bus: SPI,
23}
24
25/// Async I2C transport wrapper used by [`Bmi323Async`].
26///
27/// Most users do not need to construct this directly. Prefer
28/// [`Bmi323Async::new_i2c`](crate::Bmi323Async::new_i2c).
29pub struct AsyncI2cTransport<I2C> {
30    pub(crate) bus: I2C,
31    pub(crate) address: u8,
32}
33
34/// Async SPI transport wrapper used by [`Bmi323Async`].
35///
36/// Most users do not need to construct this directly. Prefer
37/// [`Bmi323Async::new_spi`](crate::Bmi323Async::new_spi).
38pub struct AsyncSpiTransport<SPI> {
39    pub(crate) bus: SPI,
40}
41
42/// Low-level blocking register access contract used by the blocking driver.
43///
44/// This trait is public so the driver can remain transport-agnostic, but most
45/// users will rely on the built-in I2C and SPI implementations.
46pub trait SyncAccess {
47    /// Underlying bus error type returned by the transport.
48    type BusError;
49
50    /// Read a single 16-bit register payload from the BMI323.
51    fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError>;
52
53    /// Write a single 16-bit register payload to the BMI323.
54    fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError>;
55
56    /// Read multiple consecutive 16-bit register payloads starting at `reg`.
57    fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError>;
58}
59
60#[allow(async_fn_in_trait)]
61/// Low-level async register access contract used by the async driver.
62///
63/// This trait is public so the driver can remain transport-agnostic, but most
64/// users will rely on the built-in I2C and SPI implementations.
65pub trait AsyncAccess {
66    /// Underlying bus error type returned by the transport.
67    type BusError;
68
69    /// Read a single 16-bit register payload from the BMI323.
70    async fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError>;
71
72    /// Write a single 16-bit register payload to the BMI323.
73    async fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError>;
74
75    /// Read multiple consecutive 16-bit register payloads starting at `reg`.
76    async fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError>;
77}
78
79impl<I2C> SyncAccess for Bmi323<SyncI2cTransport<I2C>>
80where
81    I2C: I2c,
82{
83    type BusError = I2C::Error;
84
85    fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError> {
86        let mut bytes = [0u8; 4];
87        self.transport
88            .bus
89            .write_read(self.transport.address, &[reg], &mut bytes)?;
90        Ok(u16::from_le_bytes([bytes[2], bytes[3]]))
91    }
92
93    fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError> {
94        let [lo, hi] = word.to_le_bytes();
95        self.transport
96            .bus
97            .write(self.transport.address, &[reg, lo, hi])
98    }
99
100    fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError> {
101        let mut bytes = [0u8; 2 * 64 + 2];
102        let byte_len = words.len() * 2 + 2;
103        self.transport
104            .bus
105            .write_read(self.transport.address, &[reg], &mut bytes[..byte_len])?;
106        for (index, word) in words.iter_mut().enumerate() {
107            let offset = 2 + index * 2;
108            *word = u16::from_le_bytes([bytes[offset], bytes[offset + 1]]);
109        }
110        Ok(())
111    }
112}
113
114impl<SPI> SyncAccess for Bmi323<SyncSpiTransport<SPI>>
115where
116    SPI: SpiDevice<u8>,
117{
118    type BusError = SPI::Error;
119
120    fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError> {
121        let cmd = 0x80 | (reg & 0x7F);
122        let mut bytes = [0u8; 3];
123        let mut ops = [Operation::Write(&[cmd]), Operation::Read(&mut bytes)];
124        self.transport.bus.transaction(&mut ops)?;
125        Ok(u16::from_le_bytes([bytes[1], bytes[2]]))
126    }
127
128    fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError> {
129        let [lo, hi] = word.to_le_bytes();
130        let payload = [reg & 0x7F, lo, hi];
131        self.transport.bus.write(&payload)
132    }
133
134    fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError> {
135        let cmd = 0x80 | (reg & 0x7F);
136        let mut bytes = [0u8; 2 * 64 + 1];
137        let byte_len = words.len() * 2 + 1;
138        let mut ops = [
139            Operation::Write(&[cmd]),
140            Operation::Read(&mut bytes[..byte_len]),
141        ];
142        self.transport.bus.transaction(&mut ops)?;
143        for (index, word) in words.iter_mut().enumerate() {
144            let offset = 1 + index * 2;
145            *word = u16::from_le_bytes([bytes[offset], bytes[offset + 1]]);
146        }
147        Ok(())
148    }
149}
150
151impl<I2C> AsyncAccess for Bmi323Async<AsyncI2cTransport<I2C>>
152where
153    I2C: AsyncI2c,
154{
155    type BusError = I2C::Error;
156
157    async fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError> {
158        let mut bytes = [0u8; 4];
159        self.transport
160            .bus
161            .write_read(self.transport.address, &[reg], &mut bytes)
162            .await?;
163        Ok(u16::from_le_bytes([bytes[2], bytes[3]]))
164    }
165
166    async fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError> {
167        let [lo, hi] = word.to_le_bytes();
168        self.transport
169            .bus
170            .write(self.transport.address, &[reg, lo, hi])
171            .await
172    }
173
174    async fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError> {
175        let mut bytes = [0u8; 2 * 64 + 2];
176        let byte_len = words.len() * 2 + 2;
177        self.transport
178            .bus
179            .write_read(self.transport.address, &[reg], &mut bytes[..byte_len])
180            .await?;
181        for (index, word) in words.iter_mut().enumerate() {
182            let offset = 2 + index * 2;
183            *word = u16::from_le_bytes([bytes[offset], bytes[offset + 1]]);
184        }
185        Ok(())
186    }
187}
188
189impl<SPI> AsyncAccess for Bmi323Async<AsyncSpiTransport<SPI>>
190where
191    SPI: AsyncSpiDevice<u8>,
192{
193    type BusError = SPI::Error;
194
195    async fn read_word(&mut self, reg: u8) -> Result<u16, Self::BusError> {
196        let cmd = 0x80 | (reg & 0x7F);
197        let mut bytes = [0u8; 3];
198        let mut ops = [Operation::Write(&[cmd]), Operation::Read(&mut bytes)];
199        self.transport.bus.transaction(&mut ops).await?;
200        Ok(u16::from_le_bytes([bytes[1], bytes[2]]))
201    }
202
203    async fn write_word(&mut self, reg: u8, word: u16) -> Result<(), Self::BusError> {
204        let [lo, hi] = word.to_le_bytes();
205        let payload = [reg & 0x7F, lo, hi];
206        self.transport.bus.write(&payload).await
207    }
208
209    async fn read_words(&mut self, reg: u8, words: &mut [u16]) -> Result<(), Self::BusError> {
210        let cmd = 0x80 | (reg & 0x7F);
211        let mut bytes = [0u8; 2 * 64 + 1];
212        let byte_len = words.len() * 2 + 1;
213        let mut ops = [
214            Operation::Write(&[cmd]),
215            Operation::Read(&mut bytes[..byte_len]),
216        ];
217        self.transport.bus.transaction(&mut ops).await?;
218        for (index, word) in words.iter_mut().enumerate() {
219            let offset = 1 + index * 2;
220            *word = u16::from_le_bytes([bytes[offset], bytes[offset + 1]]);
221        }
222        Ok(())
223    }
224}