embedded_ccs811/
common_impl.rs

1use crate::hal::{delay::DelayNs, digital::OutputPin};
2use crate::{
3    hal, mode, ActionInProgress, BitFlags, Ccs811, Ccs811Awake, Ccs811Device, Error, ErrorAwake,
4    FirmwareMode, ModeChangeError, Register, SlaveAddr,
5};
6use core::marker::PhantomData;
7
8impl<I2C, NWAKE, WAKEDELAY> Ccs811<I2C, NWAKE, WAKEDELAY, mode::Boot> {
9    /// Create new instance of the CCS811 device.
10    ///
11    /// See `Ccs811Awake` for the case where the nWAKE pin is not used.
12    pub fn new(i2c: I2C, address: SlaveAddr, n_wake_pin: NWAKE, wake_delay: WAKEDELAY) -> Self {
13        Self::create(i2c, address.addr(), n_wake_pin, wake_delay)
14    }
15}
16
17impl<I2C, NWAKE, WAKEDELAY, MODE> Ccs811<I2C, NWAKE, WAKEDELAY, MODE> {
18    pub(crate) fn create(i2c: I2C, address: u8, n_wake_pin: NWAKE, wake_delay: WAKEDELAY) -> Self {
19        Self::from_awake_dev(Ccs811Awake::create(i2c, address), n_wake_pin, wake_delay)
20    }
21
22    pub(crate) fn from_awake_dev(
23        dev: Ccs811Awake<I2C, MODE>,
24        n_wake_pin: NWAKE,
25        wake_delay: WAKEDELAY,
26    ) -> Self {
27        Ccs811 {
28            dev,
29            n_wake_pin,
30            wake_delay,
31            _mode: PhantomData,
32        }
33    }
34}
35
36impl<I2C> Ccs811Awake<I2C, mode::Boot> {
37    /// Create new instance of an already awake CCS811 device.
38    pub fn new(i2c: I2C, address: SlaveAddr) -> Self {
39        Self::create(i2c, address.addr())
40    }
41}
42
43impl<I2C, MODE> Ccs811Awake<I2C, MODE> {
44    pub(crate) fn create(i2c: I2C, address: u8) -> Self {
45        Ccs811Awake {
46            i2c,
47            address,
48            meas_mode_reg: 0,
49            in_progress: ActionInProgress::None,
50            _mode: PhantomData,
51        }
52    }
53}
54
55impl<I2C, E, MODE> Ccs811Awake<I2C, MODE>
56where
57    I2C: hal::i2c::I2c<Error = E>,
58{
59    /// Destroy driver instance, return I²C bus instance.
60    pub fn destroy(self) -> I2C {
61        self.i2c
62    }
63}
64impl<I2C, E, MODE> Ccs811Awake<I2C, MODE>
65where
66    I2C: hal::i2c::I2c<Error = E>,
67{
68    pub(crate) fn write_sw_reset(&mut self) -> Result<(), ErrorAwake<E>> {
69        self.i2c
70            .write(self.address, &[Register::SW_RESET, 0x11, 0xE5, 0x72, 0x8A])
71            .map_err(ErrorAwake::I2C)
72    }
73}
74
75impl<I2C, CommE, PinE, NWAKE, WAKEDELAY, MODE> Ccs811<I2C, NWAKE, WAKEDELAY, MODE>
76where
77    I2C: hal::i2c::I2c<Error = CommE>,
78    NWAKE: OutputPin<Error = PinE>,
79    WAKEDELAY: DelayNs,
80{
81    /// Destroy driver instance, return I²C bus, nWAKE pin
82    /// and wake delay instances.
83    pub fn destroy(self) -> (I2C, NWAKE, WAKEDELAY) {
84        (self.dev.destroy(), self.n_wake_pin, self.wake_delay)
85    }
86
87    pub(crate) fn on_awaken<T, F>(&mut self, f: F) -> Result<T, Error<CommE, PinE>>
88    where
89        F: FnOnce(&mut Self) -> Result<T, ErrorAwake<CommE>>,
90    {
91        self.n_wake_pin.set_low().map_err(Error::Pin)?;
92        self.wake_delay.delay_us(50);
93        let result = match f(self) {
94            Ok(v) => Ok(v),
95            Err(e) => Err(e.into()),
96        };
97        self.n_wake_pin.set_high().map_err(Error::Pin)?;
98        self.wake_delay.delay_us(20);
99        result
100    }
101
102    pub(crate) fn on_awaken_nb<T, F>(&mut self, f: F) -> nb::Result<T, Error<CommE, PinE>>
103    where
104        F: FnOnce(&mut Self) -> nb::Result<T, ErrorAwake<CommE>>,
105    {
106        self.n_wake_pin
107            .set_low()
108            .map_err(Error::Pin)
109            .map_err(nb::Error::Other)?;
110        self.wake_delay.delay_us(50);
111        let result = match f(self) {
112            Ok(v) => Ok(v),
113            Err(nb::Error::Other(e)) => Err(nb::Error::Other(e.into())),
114            Err(nb::Error::WouldBlock) => Err(nb::Error::WouldBlock),
115        };
116        self.n_wake_pin
117            .set_high()
118            .map_err(Error::Pin)
119            .map_err(nb::Error::Other)?;
120        self.wake_delay.delay_us(20);
121        result
122    }
123
124    // Note: defining a type for the result would require inherent
125    // associated items: https://github.com/rust-lang/rust/issues/8995
126    // Note 2: is_verifying is always false after a mode change
127    #[allow(clippy::type_complexity)]
128    pub(crate) fn wrap_mode_change<TMODE, F>(
129        mut self,
130        f: F,
131    ) -> Result<Ccs811<I2C, NWAKE, WAKEDELAY, TMODE>, ModeChangeError<Error<CommE, PinE>, Self>>
132    where
133        F: FnOnce(
134            Ccs811Awake<I2C, MODE>,
135        ) -> Result<
136            Ccs811Awake<I2C, TMODE>,
137            ModeChangeError<ErrorAwake<CommE>, Ccs811Awake<I2C, MODE>>,
138        >,
139    {
140        if let Err(e) = self.n_wake_pin.set_low() {
141            return Err(ModeChangeError::new(self, Error::Pin(e)));
142        }
143        self.wake_delay.delay_us(50);
144        let Ccs811 {
145            dev,
146            mut n_wake_pin,
147            mut wake_delay,
148            ..
149        } = self;
150        let result = f(dev);
151        if let Err(e) = n_wake_pin.set_high() {
152            return match result {
153                Ok(Ccs811Awake { i2c, address, .. }) => Err(ModeChangeError {
154                    dev: Ccs811::create(i2c, address, n_wake_pin, wake_delay),
155                    error: Error::Pin(e),
156                }),
157                Err(ModeChangeError { dev, error }) => Err(ModeChangeError {
158                    dev: Ccs811::from_awake_dev(dev, n_wake_pin, wake_delay),
159                    error: error.into(),
160                }),
161            };
162        }
163        wake_delay.delay_us(20);
164        match result {
165            Ok(dev) => Ok(Ccs811::from_awake_dev(dev, n_wake_pin, wake_delay)),
166            Err(ModeChangeError { dev, error }) => Err(ModeChangeError {
167                dev: Ccs811::from_awake_dev(dev, n_wake_pin, wake_delay),
168                error: error.into(),
169            }),
170        }
171    }
172}
173
174impl<I2C, E, MODE> Ccs811Device for Ccs811Awake<I2C, MODE>
175where
176    I2C: hal::i2c::I2c<Error = E>,
177{
178    type Error = ErrorAwake<E>;
179
180    fn firmware_mode(&mut self) -> Result<FirmwareMode, Self::Error> {
181        let status = self.read_status()?;
182        let mode = if (status & BitFlags::FW_MODE) != 0 {
183            FirmwareMode::Application
184        } else {
185            FirmwareMode::Boot
186        };
187        Ok(mode)
188    }
189
190    fn has_valid_app(&mut self) -> Result<bool, Self::Error> {
191        let status = self.read_status()?;
192        Ok((status & BitFlags::APP_VALID) != 0)
193    }
194
195    fn hardware_id(&mut self) -> Result<u8, Self::Error> {
196        self.read_register_1byte(Register::HW_ID)
197    }
198
199    fn hardware_version(&mut self) -> Result<(u8, u8), Self::Error> {
200        let version = self.read_register_1byte(Register::HW_VERSION)?;
201        Ok(((version & 0xF0) >> 4, version & 0xF))
202    }
203
204    fn firmware_bootloader_version(&mut self) -> Result<(u8, u8, u8), Self::Error> {
205        let version = self.read_register_2bytes(Register::FW_BOOT_VERSION)?;
206        Ok(((version[0] & 0xF0) >> 4, version[0] & 0xF, version[1]))
207    }
208
209    fn firmware_application_version(&mut self) -> Result<(u8, u8, u8), Self::Error> {
210        let version = self.read_register_2bytes(Register::FW_APP_VERSION)?;
211        Ok(((version[0] & 0xF0) >> 4, version[0] & 0xF, version[1]))
212    }
213}
214
215impl<I2C, CommE, PinE, NWAKE, WAKEDELAY, MODE> Ccs811Device for Ccs811<I2C, NWAKE, WAKEDELAY, MODE>
216where
217    I2C: hal::i2c::I2c<Error = CommE>,
218    NWAKE: OutputPin<Error = PinE>,
219    WAKEDELAY: DelayNs,
220{
221    type Error = Error<CommE, PinE>;
222
223    fn firmware_mode(&mut self) -> Result<FirmwareMode, Self::Error> {
224        self.on_awaken(|s| s.dev.firmware_mode())
225    }
226
227    fn has_valid_app(&mut self) -> Result<bool, Self::Error> {
228        self.on_awaken(|s| s.dev.has_valid_app())
229    }
230
231    fn hardware_id(&mut self) -> Result<u8, Self::Error> {
232        self.on_awaken(|s| s.dev.hardware_id())
233    }
234
235    fn hardware_version(&mut self) -> Result<(u8, u8), Self::Error> {
236        self.on_awaken(|s| s.dev.hardware_version())
237    }
238
239    fn firmware_bootloader_version(&mut self) -> Result<(u8, u8, u8), Self::Error> {
240        self.on_awaken(|s| s.dev.firmware_bootloader_version())
241    }
242
243    fn firmware_application_version(&mut self) -> Result<(u8, u8, u8), Self::Error> {
244        self.on_awaken(|s| s.dev.firmware_application_version())
245    }
246}