Skip to main content

pamoja_sensors/
error.rs

1//! The error type shared by the sensor drivers.
2
3/// What can go wrong turning a part's raw bytes into a reading.
4///
5/// Most of these drivers only ever decode well-formed register values and so cannot
6/// fail, but parts that carry their own integrity check report a mismatch here so the
7/// caller re-reads rather than trusting corrupted data.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum SensorError {
10    /// A device's own checksum did not match the bytes it covered, so the read was
11    /// corrupted on the bus and must be repeated. Returned, for example, when a
12    /// DS18B20 scratchpad's CRC byte disagrees with the data bytes.
13    Crc,
14    /// A register field holds a code the datasheet leaves undefined, so the value
15    /// cannot have come from a correctly working part. Returned, for example, when an
16    /// HDC1080 configuration register carries the unassigned humidity-resolution code.
17    Invalid,
18    /// A device's identification registers did not carry the values its datasheet
19    /// fixes, so a different part, or nothing at all, answered at that address and
20    /// its readings must not be trusted. Returned, for example, when an INA226's
21    /// manufacturer or die ID register reads something other than TI's 0x5449 and
22    /// 0x226.
23    Identity,
24}
25
26impl core::fmt::Display for SensorError {
27    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28        match self {
29            SensorError::Crc => f.write_str("sensor checksum mismatch"),
30            SensorError::Invalid => f.write_str("sensor register field holds an undefined code"),
31            SensorError::Identity => f.write_str("sensor identification mismatch"),
32        }
33    }
34}
35
36// `core::error::Error` rather than `std::error::Error`, so a caller on a
37// microcontroller gets the same trait a caller on a gateway does.
38impl core::error::Error for SensorError {}
39
40/// What can go wrong driving a part over a bus, beyond decoding its bytes.
41///
42/// A driver returns this from every transfer sequence. It converts into the core
43/// [`Error`](pamoja_core::Error) so a driver used as a
44/// [`Sensor`](pamoja_core::Sensor) reports the way every other device does: a bus
45/// fault and a timeout become [`Error::Io`](pamoja_core::Error::Io), a checksum or an
46/// undefined field become [`Error::Codec`](pamoja_core::Error::Codec), and a part
47/// that identifies as something else becomes [`Error::Io`](pamoja_core::Error::Io).
48#[cfg(feature = "embedded-hal")]
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum DriverError<E> {
51    /// The bus underneath the driver failed: a missing acknowledge, a bus fault, a
52    /// pin that could not be driven.
53    Bus(E),
54    /// The part's bytes decoded to something its datasheet rules out.
55    Sensor(SensorError),
56    /// The part did not finish within the time its datasheet allows, so its data
57    /// registers never became ready.
58    Timeout,
59}
60
61#[cfg(feature = "embedded-hal")]
62impl<E> From<SensorError> for DriverError<E> {
63    fn from(error: SensorError) -> Self {
64        DriverError::Sensor(error)
65    }
66}
67
68#[cfg(feature = "embedded-hal")]
69impl<E: core::fmt::Debug> core::fmt::Display for DriverError<E> {
70    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71        match self {
72            DriverError::Bus(error) => write!(f, "bus error: {error:?}"),
73            DriverError::Sensor(error) => write!(f, "{error}"),
74            DriverError::Timeout => f.write_str("the part did not finish its conversion in time"),
75        }
76    }
77}
78
79#[cfg(feature = "embedded-hal")]
80impl<E: core::fmt::Debug> core::error::Error for DriverError<E> {}
81
82#[cfg(feature = "embedded-hal")]
83impl<E: core::fmt::Debug> From<DriverError<E>> for pamoja_core::Error {
84    fn from(error: DriverError<E>) -> Self {
85        use alloc::string::ToString;
86
87        match error {
88            DriverError::Bus(bus) => pamoja_core::Error::Io(alloc::format!("bus error: {bus:?}")),
89            DriverError::Timeout => pamoja_core::Error::Io(error.to_string()),
90            DriverError::Sensor(SensorError::Identity) => pamoja_core::Error::Io(error.to_string()),
91            DriverError::Sensor(sensor) => pamoja_core::Error::Codec(sensor.to_string()),
92        }
93    }
94}