ariel_os_sensors/
sensor.rs

1//! Provides a [`Sensor`] trait abstracting over implementation details of a sensor driver.
2
3mod channels_samples_zip;
4mod reading_channels;
5mod samples;
6
7use core::{
8    future::Future,
9    pin::Pin,
10    task::{Context, Poll},
11};
12
13use crate::{Category, Label, MeasurementUnit, signal};
14use channels_samples_zip::ChannelsSamplesZip;
15use samples::InnerSamples;
16
17#[doc(inline)]
18pub use crate::Reading;
19pub use crate::sample::{Sample, SampleError, SampleMetadata};
20pub use reading_channels::ReadingChannels;
21pub use samples::{Samples, SensorAccess};
22
23/// This trait must be implemented by sensor drivers.
24///
25/// See [the module level documentation](crate) for more.
26pub trait Sensor: Send + Sync {
27    /// Triggers a measurement.
28    /// Clears the previous reading.
29    ///
30    /// To obtain readings from every sensor drivers this method can be called in a loop over all
31    /// sensors returned by `Registry::sensors()`, before obtaining the readings with
32    /// [`Self::wait_for_reading()`] in a second loop, so that the measurements happen
33    /// concurrently.
34    ///
35    /// # For implementors
36    ///
37    /// This method should return quickly.
38    ///
39    /// # Errors
40    ///
41    /// Returns [`TriggerMeasurementError::NonEnabled`] if the sensor driver is not enabled.
42    fn trigger_measurement(&self) -> Result<(), TriggerMeasurementError>;
43
44    /// Waits for the reading and returns it asynchronously.
45    /// Depending on the sensor device and the sensor driver, this may use a sensor interrupt or
46    /// data polling.
47    /// Interpretation of the reading requires data from [`Sensor::reading_channels()`] as well.
48    /// See [the module level documentation](crate) for more.
49    ///
50    /// # Note
51    ///
52    /// It is necessary to trigger a measurement by calling [`Sensor::trigger_measurement()`]
53    /// beforehand, even if the sensor device carries out periodic measurements on its own.
54    ///
55    /// # Errors
56    ///
57    /// - Quickly returns [`ReadingError::NonEnabled`] if the sensor driver is not enabled.
58    /// - Quickly returns [`ReadingError::NotMeasuring`] if no measurement has been triggered
59    ///   beforehand using [`Sensor::trigger_measurement()`].
60    /// - Returns [`ReadingError::SensorAccess`] if the sensor device cannot be accessed.
61    fn wait_for_reading(&'static self) -> ReadingWaiter;
62
63    /// Provides information about the reading returned by [`Sensor::wait_for_reading()`].
64    #[must_use]
65    fn reading_channels(&self) -> ReadingChannels;
66
67    /// Sets the sensor driver mode and returns the previous state.
68    /// Allows to put the sensor device to sleep if supported.
69    ///
70    /// # Errors
71    ///
72    /// Returns [`SetModeError::Uninitialized`] if the sensor driver is not initialized.
73    fn set_mode(&self, mode: Mode) -> Result<State, SetModeError>;
74
75    /// Returns the current sensor driver state.
76    #[must_use]
77    fn state(&self) -> State;
78
79    /// Returns the categories the sensor device is part of.
80    #[must_use]
81    fn categories(&self) -> &'static [Category];
82
83    /// String label of the sensor driver *instance*.
84    /// For instance, in the case of a temperature sensor, this allows to specify whether this
85    /// specific sensor device is placed indoor or outdoor.
86    #[must_use]
87    fn label(&self) -> Option<&'static str>;
88
89    /// Returns a human-readable name of the *sensor driver*.
90    /// For instance, "push button" and "3-axis accelerometer" are appropriate display names.
91    ///
92    /// # Note
93    ///
94    /// Different sensor drivers for the same sensor device may have different display names.
95    #[must_use]
96    fn display_name(&self) -> Option<&'static str>;
97
98    /// Returns the sensor device part number.
99    /// Returns `None` when the sensor device does not have a part number.
100    /// For instance, "DS18B20" is a valid part number.
101    #[must_use]
102    fn part_number(&self) -> Option<&'static str>;
103
104    /// Returns the sensor driver version number.
105    #[must_use]
106    fn version(&self) -> u8;
107}
108
109/// Future returned by [`Sensor::wait_for_reading()`].
110#[must_use = "futures do nothing unless you `.await` or poll them"]
111pub struct ReadingWaiter {
112    inner: ReadingWaiterInner,
113}
114
115impl ReadingWaiter {
116    /// Creates a new [`Future`] to send back [`Samples`].
117    ///
118    /// # Note
119    ///
120    /// For sensor driver implementors only.
121    pub fn new(fut: signal::ReceiveFuture<'static, ReadingResult<Samples>>) -> Self {
122        Self {
123            inner: ReadingWaiterInner::Waiter { waiter: fut },
124        }
125    }
126
127    /// Creates a new [`Future`] to send back an error that happened when obtaining a reading.
128    ///
129    /// # Note
130    ///
131    /// For sensor driver implementors only.
132    pub fn new_err(err: ReadingError) -> Self {
133        Self {
134            inner: ReadingWaiterInner::Err { err },
135        }
136    }
137}
138
139impl Future for ReadingWaiter {
140    type Output = ReadingResult<Samples>;
141
142    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
143        core::pin::pin!(&mut self.inner).poll(cx)
144    }
145}
146
147pin_project_lite::pin_project! {
148    #[must_use = "futures do nothing unless you `.await` or poll them"]
149    #[project = ReadingWaiterInnerProj]
150    enum ReadingWaiterInner {
151        Waiter {
152            #[pin]
153            waiter: signal::ReceiveFuture<'static, ReadingResult<Samples>>,
154        },
155        Err {
156            err: ReadingError,
157        },
158        Resolved,
159    }
160}
161
162impl Future for ReadingWaiterInner {
163    type Output = ReadingResult<Samples>;
164
165    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
166        let this = self.as_mut().project();
167        match this {
168            ReadingWaiterInnerProj::Waiter { waiter } => waiter.poll(cx),
169            ReadingWaiterInnerProj::Err { err } => {
170                // Replace the error with a dummy error value, crafted from thin air, and mark the
171                // future as resolved, so that we do not take this dummy value into account later.
172                // This avoids requiring `Clone` on `ReadingError`.
173                let err = core::mem::replace(err, ReadingError::NonEnabled);
174                *self = Self::Resolved;
175
176                Poll::Ready(Err(err))
177            }
178            ReadingWaiterInnerProj::Resolved => unreachable!(),
179        }
180    }
181}
182
183/// Mode of a sensor driver.
184#[derive(Debug, Copy, Clone, PartialEq, Eq)]
185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186pub enum Mode {
187    /// The sensor driver is disabled.
188    Disabled,
189    /// The sensor driver is enabled.
190    Enabled,
191    /// The sensor driver is sleeping.
192    /// The sensor device may be in a low-power mode.
193    Sleeping,
194}
195
196/// Possible errors when attempting to set the mode of a sensor driver.
197#[derive(Debug)]
198#[cfg_attr(feature = "defmt", derive(defmt::Format))]
199pub enum SetModeError {
200    /// The sensor driver is uninitialized.
201    /// It has not been initialized yet, or initialization could not succeed.
202    Uninitialized,
203}
204
205impl core::fmt::Display for SetModeError {
206    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207        match self {
208            Self::Uninitialized => write!(f, "sensor driver is not initialized"),
209        }
210    }
211}
212
213impl core::error::Error for SetModeError {}
214
215/// State of a sensor driver.
216#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
217#[cfg_attr(feature = "defmt", derive(defmt::Format))]
218#[repr(u8)]
219pub enum State {
220    /// The sensor driver is uninitialized.
221    /// It has not been initialized yet, or initialization could not succeed.
222    #[default]
223    Uninitialized = 0,
224    /// The sensor driver is disabled.
225    Disabled = 1,
226    /// The sensor driver is enabled.
227    Enabled = 2,
228    /// The sensor driver is enabled and a measurement has been triggered.
229    Measuring = 3,
230    /// The sensor driver is sleeping.
231    Sleeping = 4,
232}
233
234impl From<Mode> for State {
235    fn from(mode: Mode) -> Self {
236        match mode {
237            Mode::Disabled => Self::Disabled,
238            Mode::Enabled => Self::Enabled,
239            Mode::Sleeping => Self::Sleeping,
240        }
241    }
242}
243
244impl TryFrom<u8> for State {
245    type Error = TryFromIntError;
246
247    fn try_from(int: u8) -> Result<Self, Self::Error> {
248        match int {
249            0 => Ok(Self::Uninitialized),
250            1 => Ok(Self::Disabled),
251            2 => Ok(Self::Enabled),
252            3 => Ok(Self::Measuring),
253            4 => Ok(Self::Sleeping),
254            _ => Err(TryFromIntError),
255        }
256    }
257}
258
259/// The error type returned when a checked integral type conversion fails.
260#[derive(Debug)]
261#[cfg_attr(feature = "defmt", derive(defmt::Format))]
262pub struct TryFromIntError;
263
264impl core::fmt::Display for TryFromIntError {
265    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
266        write!(f, "out of range integral type conversion attempted")
267    }
268}
269
270impl core::error::Error for TryFromIntError {}
271
272/// Provides metadata about a [`Sample`].
273#[derive(Debug, Copy, Clone, PartialEq)]
274#[cfg_attr(feature = "defmt", derive(defmt::Format))]
275// NOTE(derive): we do not implement `Eq` on purpose: its would prevent us from possibly adding
276// floats in the future.
277pub struct ReadingChannel {
278    label: Label,
279    scaling: i8,
280    unit: MeasurementUnit,
281}
282
283impl ReadingChannel {
284    /// Creates a new [`ReadingChannel`].
285    ///
286    /// This constructor is intended for sensor driver implementors only.
287    #[must_use]
288    pub fn new(label: Label, scaling: i8, unit: MeasurementUnit) -> Self {
289        Self {
290            label,
291            scaling,
292            unit,
293        }
294    }
295
296    /// Returns the [`Label`] for this channel.
297    #[must_use]
298    pub fn label(&self) -> Label {
299        self.label
300    }
301
302    /// Returns the [scaling](Sample) for this channel.
303    #[must_use]
304    pub fn scaling(&self) -> i8 {
305        self.scaling
306    }
307
308    /// Returns the unit of measurement for this channel.
309    #[must_use]
310    pub fn unit(&self) -> MeasurementUnit {
311        self.unit
312    }
313}
314
315/// Represents errors happening when *triggering* a sensor measurement.
316#[derive(Debug)]
317#[cfg_attr(feature = "defmt", derive(defmt::Format))]
318pub enum TriggerMeasurementError {
319    /// The sensor driver is not enabled (e.g., it may be disabled or sleeping).
320    NonEnabled,
321}
322
323impl core::fmt::Display for TriggerMeasurementError {
324    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325        match self {
326            Self::NonEnabled => write!(f, "sensor driver is not enabled"),
327        }
328    }
329}
330
331impl core::error::Error for TriggerMeasurementError {}
332
333/// Represents errors happening when accessing a sensor reading.
334#[derive(Debug)]
335#[cfg_attr(feature = "defmt", derive(defmt::Format))]
336pub enum ReadingError {
337    /// The sensor driver is not enabled (e.g., it may be disabled or sleeping).
338    NonEnabled,
339    /// Cannot access the sensor device (e.g., because of a bus error).
340    SensorAccess,
341    /// No measurement has been triggered before waiting for a reading.
342    /// It is necessary to call [`Sensor::trigger_measurement()`] before calling
343    /// [`Sensor::wait_for_reading()`].
344    NotMeasuring,
345}
346
347impl core::fmt::Display for ReadingError {
348    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
349        match self {
350            Self::NonEnabled => write!(f, "sensor driver is not enabled"),
351            Self::SensorAccess => write!(f, "sensor device could not be accessed"),
352            Self::NotMeasuring => write!(f, "no measurement has been triggered"),
353        }
354    }
355}
356
357impl core::error::Error for ReadingError {}
358
359/// A specialized [`Result`] type for [`Reading`] operations.
360pub type ReadingResult<R> = Result<R, ReadingError>;
361
362#[cfg(test)]
363mod tests {
364    use super::*;
365
366    // Assert that the Sensor trait is object-safe
367    static _SENSOR_REFS: &[&dyn Sensor] = &[];
368
369    #[test]
370    fn assert_type_sizes() {
371        // The size of these types is not a functional requirement of the API, but this makes sure
372        // they stay small to keep resource usage down.
373        assert!(size_of::<Category>() <= size_of::<u8>());
374        assert!(size_of::<Label>() <= size_of::<u8>());
375        assert!(size_of::<MeasurementUnit>() <= size_of::<u8>());
376        assert!(size_of::<ReadingChannel>() <= size_of::<u32>());
377    }
378}