1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// SPDX-License-Identifier: Apache-2.0
// Copyright © 2021 Will Ross
#[cfg(feature = "std")]
extern crate std;

use core::fmt;

use embedded_hal::blocking::i2c;

/// Specific kinds of errors that don't involve I²C.
#[derive(Clone, Debug, PartialEq)]
pub enum LibraryError {
    /// When a value from the camera is malformed in some way.
    InvalidData(&'static str),

    /// Other error messages.
    Other(&'static str),

    /// Failures when decoding a checksum.
    ///
    /// The MLX90641 uses a checksum with its [EEPROM][crate::mlx90641::hamming], and will return
    /// this error is it encounters an uncorrectable error.
    Checksum(u16),
}

impl fmt::Display for LibraryError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            LibraryError::InvalidData(msg) => write!(f, "{}", msg),
            LibraryError::Other(msg) => write!(f, "{}", msg),
            LibraryError::Checksum(invalid_word) => {
                write!(f, "Invalid checksum for data {:#06X}", invalid_word)
            }
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for LibraryError {}

/// Errors originating from this library.
pub enum Error<I2C>
where
    I2C: i2c::WriteRead + i2c::Write,
{
    /// Errors involved with reading from I²C.
    ///
    /// All reads done by this library are preceded by a short write.
    I2cWriteReadError(<I2C as i2c::WriteRead>::Error),

    /// Errors involved with only writing to I²C.
    I2cWriteError(<I2C as i2c::Write>::Error),

    /// Other errors originating from within this library.
    LibraryError(LibraryError),
}

// Custom Debug implementation so that I2C doesn't need to implement Debug (like the one from
// linux-embedded-hal).
impl<I2C> fmt::Debug for Error<I2C>
where
    I2C: i2c::WriteRead + i2c::Write,
    <I2C as i2c::WriteRead>::Error: fmt::Debug,
    <I2C as i2c::Write>::Error: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::I2cWriteReadError(i2c_error) => f
                .debug_tuple("Error::I2cWriteReadError")
                .field(i2c_error)
                .finish(),
            Error::I2cWriteError(i2c_error) => f
                .debug_tuple("Error::I2cWriteError")
                .field(i2c_error)
                .finish(),
            Error::LibraryError(err) => f.debug_tuple("Error::LibraryError").field(err).finish(),
        }
    }
}

impl<I2C> fmt::Display for Error<I2C>
where
    I2C: i2c::WriteRead + i2c::Write,
    <I2C as i2c::WriteRead>::Error: fmt::Debug,
    <I2C as i2c::Write>::Error: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::I2cWriteReadError(i2c_error) => write!(f, "I2C Error: {:?}", i2c_error),
            Error::I2cWriteError(i2c_error) => write!(f, "I2C Error: {:?}", i2c_error),
            Error::LibraryError(err) => write!(f, "Library Error: {:?}", err),
        }
    }
}

#[cfg(feature = "std")]
impl<I2C> std::error::Error for Error<I2C>
where
    I2C: i2c::WriteRead + i2c::Write,
    <I2C as i2c::WriteRead>::Error: std::error::Error + 'static,
    <I2C as i2c::Write>::Error: std::error::Error + 'static,
{
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Error::I2cWriteReadError(err) => Some(err),
            Error::I2cWriteError(err) => Some(err),
            Error::LibraryError(lib_err) => Some(lib_err),
        }
    }
}

impl<I2C> From<LibraryError> for Error<I2C>
where
    I2C: i2c::WriteRead + i2c::Write,
{
    fn from(lib_err: LibraryError) -> Self {
        Self::LibraryError(lib_err)
    }
}