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}