bme280_multibus/spi0.rs
1/// BME280 bus.
2#[derive(Debug)]
3pub struct Bme280Bus<SPI, CS> {
4 bus: SPI,
5 cs: CS,
6}
7
8/// SPI mode for the BME280.
9///
10/// The BME280 also supports mode 3.
11pub const MODE: eh0::spi::Mode = eh0::spi::MODE_0;
12
13/// Maximum SPI bus frequency in hertz.
14pub const MAX_FREQ: u32 = 10_000_000;
15
16/// BME280 error type.
17#[derive(Debug)]
18pub enum Error<SpiError, PinError> {
19 /// SPI bus error wrapper.
20 Spi(SpiError),
21 /// GPIO pin error wrapper.
22 Pin(PinError),
23}
24
25impl<SpiError, PinError> From<PinError> for Error<SpiError, PinError> {
26 #[inline]
27 fn from(e: PinError) -> Self {
28 Error::Pin(e)
29 }
30}
31
32impl<SPI, CS, SpiError, PinError> Bme280Bus<SPI, CS>
33where
34 SPI: eh0::blocking::spi::Transfer<u8, Error = SpiError>
35 + eh0::blocking::spi::Write<u8, Error = SpiError>,
36 CS: eh0::digital::v2::OutputPin<Error = PinError>,
37{
38 /// Creates a new `Bme280Bus` from a SPI peripheral and a chip select
39 /// digital I/O pin.
40 ///
41 /// # Safety
42 ///
43 /// The chip select pin must be high before being passed to this function.
44 ///
45 /// # Example
46 ///
47 /// ```
48 /// # let spi = ehm::eh0::spi::Mock::new(&[]);
49 /// # let mut pin = ehm::eh0::pin::Mock::new(&[
50 /// # ehm::eh0::pin::Transaction::set(ehm::eh0::pin::State::High),
51 /// # ]);
52 /// use bme280_multibus::spi0::Bme280Bus;
53 /// use eh0::digital::v2::OutputPin;
54 ///
55 /// pin.set_high()?;
56 /// let mut bme: Bme280Bus<_, _> = Bme280Bus::new(spi, pin);
57 /// # let (mut spi, mut pin) = bme.free();
58 /// # spi.done(); pin.done();
59 /// # Ok::<(), ehm::eh0::MockError>(())
60 /// ```
61 #[inline]
62 #[allow(clippy::unnecessary_safety_doc)]
63 pub fn new(bus: SPI, cs: CS) -> Self {
64 Bme280Bus { bus, cs }
65 }
66
67 /// Free the SPI bus and CS pin from the BME280.
68 ///
69 /// # Example
70 ///
71 /// ```
72 /// # let spi = ehm::eh0::spi::Mock::new(&[]);
73 /// # let mut pin = ehm::eh0::pin::Mock::new(&[
74 /// # ehm::eh0::pin::Transaction::set(ehm::eh0::pin::State::High),
75 /// # ]);
76 /// use bme280_multibus::spi0::Bme280Bus;
77 /// use eh0::digital::v2::OutputPin;
78 ///
79 /// pin.set_high()?;
80 /// let mut bme: Bme280Bus<_, _> = Bme280Bus::new(spi, pin);
81 /// let (mut spi, mut pin) = bme.free();
82 /// # spi.done(); pin.done();
83 /// # Ok::<(), ehm::eh0::MockError>(())
84 /// ```
85 #[inline]
86 pub fn free(self) -> (SPI, CS) {
87 (self.bus, self.cs)
88 }
89
90 #[inline]
91 fn with_chip_enable<T, E, F>(&mut self, mut f: F) -> Result<T, E>
92 where
93 F: FnMut(&mut SPI) -> Result<T, E>,
94 E: core::convert::From<Error<SpiError, PinError>>,
95 {
96 self.cs.set_low().map_err(Error::Pin)?;
97 let result: Result<T, E> = f(&mut self.bus);
98 self.cs.set_high().map_err(Error::Pin)?;
99 result
100 }
101}
102
103impl<SPI, CS, SpiError, PinError> crate::Bme280Bus for Bme280Bus<SPI, CS>
104where
105 SPI: eh0::blocking::spi::Transfer<u8, Error = SpiError>
106 + eh0::blocking::spi::Write<u8, Error = SpiError>,
107 CS: eh0::digital::v2::OutputPin<Error = PinError>,
108{
109 type Error = Error<SpiError, PinError>;
110
111 fn read_regs(&mut self, reg: u8, buf: &mut [u8]) -> Result<(), Self::Error> {
112 self.with_chip_enable(|spi| {
113 spi.write(&[reg | (1 << 7)]).map_err(Error::Spi)?;
114 spi.transfer(buf).map_err(Error::Spi)?;
115 Ok(())
116 })
117 }
118
119 fn write_reg(&mut self, reg: u8, data: u8) -> Result<(), Self::Error> {
120 let mut buf: [u8; 2] = [reg & !(1 << 7), data];
121 self.with_chip_enable(|spi| {
122 spi.transfer(&mut buf).map_err(Error::Spi)?;
123 Ok(())
124 })
125 }
126}
127
128/// BME280 SPI bus implementation with an infallible GPIO
129pub mod infallible_gpio {
130 /// BME280 bus.
131 #[derive(Debug)]
132 pub struct Bme280Bus<SPI, CS> {
133 bus: SPI,
134 cs: CS,
135 }
136
137 impl<SPI, CS, E> Bme280Bus<SPI, CS>
138 where
139 SPI: eh0::blocking::spi::Transfer<u8, Error = E> + eh0::blocking::spi::Write<u8, Error = E>,
140 CS: eh0::digital::v2::OutputPin<Error = core::convert::Infallible>,
141 {
142 /// Creates a new `Bme280Bus` from a SPI peripheral and a chip select
143 /// digital I/O pin.
144 ///
145 /// # Safety
146 ///
147 /// The chip select pin must be high before being passed to this function.
148 ///
149 /// # Example
150 ///
151 /// ```
152 /// # let spi = ehm::eh0::spi::Mock::new(&[]);
153 /// # struct Pin {};
154 /// # impl eh0::digital::v2::OutputPin for Pin {
155 /// # type Error = core::convert::Infallible;
156 /// # fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) }
157 /// # fn set_high(&mut self) -> Result<(), Self::Error> { Ok(()) }
158 /// # }
159 /// # let mut pin = Pin {};
160 /// use bme280_multibus::spi0::infallible_gpio::Bme280Bus;
161 /// use eh0::digital::v2::OutputPin;
162 ///
163 /// pin.set_high().unwrap();
164 /// let mut bme: Bme280Bus<_, _> = Bme280Bus::new(spi, pin);
165 /// # let (mut spi, mut pin) = bme.free();
166 /// # spi.done();
167 /// # Ok::<(), ehm::eh0::MockError>(())
168 /// ```
169 #[inline]
170 #[allow(clippy::unnecessary_safety_doc)]
171 pub fn new(bus: SPI, cs: CS) -> Self {
172 Bme280Bus { bus, cs }
173 }
174
175 /// Free the SPI bus and CS pin from the BME280.
176 ///
177 /// # Example
178 ///
179 /// ```
180 /// # let spi = ehm::eh0::spi::Mock::new(&[]);
181 /// # struct Pin {};
182 /// # impl eh0::digital::v2::OutputPin for Pin {
183 /// # type Error = core::convert::Infallible;
184 /// # fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) }
185 /// # fn set_high(&mut self) -> Result<(), Self::Error> { Ok(()) }
186 /// # }
187 /// # let mut pin = Pin {};
188 /// use bme280_multibus::spi0::infallible_gpio::Bme280Bus;
189 /// use eh0::digital::v2::OutputPin;
190 ///
191 /// pin.set_high().unwrap();
192 /// let mut bme: Bme280Bus<_, _> = Bme280Bus::new(spi, pin);
193 /// let (mut spi, pin) = bme.free();
194 /// # spi.done();
195 /// # Ok::<(), ehm::eh0::MockError>(())
196 /// ```
197 #[inline]
198 pub fn free(self) -> (SPI, CS) {
199 (self.bus, self.cs)
200 }
201
202 #[inline]
203 fn with_chip_enable<T, F>(&mut self, mut f: F) -> Result<T, E>
204 where
205 F: FnMut(&mut SPI) -> Result<T, E>,
206 {
207 self.cs.set_low().unwrap();
208 let result: Result<T, E> = f(&mut self.bus);
209 self.cs.set_high().unwrap();
210 result
211 }
212 }
213
214 impl<SPI, CS, E> crate::Bme280Bus for Bme280Bus<SPI, CS>
215 where
216 SPI: eh0::blocking::spi::Transfer<u8, Error = E> + eh0::blocking::spi::Write<u8, Error = E>,
217 CS: eh0::digital::v2::OutputPin<Error = core::convert::Infallible>,
218 {
219 type Error = E;
220
221 fn read_regs(&mut self, reg: u8, buf: &mut [u8]) -> Result<(), Self::Error> {
222 self.with_chip_enable(|spi| {
223 spi.write(&[reg | (1 << 7)])?;
224 spi.transfer(buf)?;
225 Ok(())
226 })
227 }
228
229 fn write_reg(&mut self, reg: u8, data: u8) -> Result<(), Self::Error> {
230 let mut buf: [u8; 2] = [reg & !(1 << 7), data];
231 self.with_chip_enable(|spi| {
232 spi.transfer(&mut buf)?;
233 Ok(())
234 })
235 }
236 }
237}