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}