sfc_core/
error.rs

1//! Contains error types that can occur when attempting to communicate with the mass flow
2//! controller.
3use crate::shdlc::TranslationError;
4
5use arrayvec::CapacityError;
6
7use std::fmt::Display;
8
9/// An aggregate error type that covers every error that can occur when attempting to communicate 
10/// with the mass flow controller.
11#[derive(Debug)]
12pub enum DeviceError {
13    /// An error when writing data or reading data from the device.
14    IoError(std::io::Error),
15    ShdlcError(TranslationError),
16    StateResponse(StateResponseError),
17    PortError(serialport::Error),
18    /// An Invalid Checksum. The first value of the tuple is the recivied checksum and the second
19    /// value was the expected checksum.
20    InvalidChecksum(u8, u8),
21    /// An invalid string was sent from the device. Either missing the null terminator byte
22    /// or was not valid ASCII.
23    InvalidString,
24}
25
26impl Display for DeviceError {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        match self {
29            Self::IoError(e) => e.fmt(f),
30            Self::ShdlcError(e) => e.fmt(f),
31            Self::StateResponse(e) => e.fmt(f),
32            Self::PortError(e) => e.fmt(f),
33            Self::InvalidChecksum(recived, expected) => write!(
34                f,
35                "checksum recived: {:#02x} did not match expected value: {:#02x}",
36                recived, expected
37            ),
38            Self::InvalidString => write!(f, "invalid string data found"),
39        }
40    }
41}
42
43impl From<std::io::Error> for DeviceError {
44    fn from(value: std::io::Error) -> Self {
45        Self::IoError(value)
46    }
47}
48
49impl From<TranslationError> for DeviceError {
50    fn from(value: TranslationError) -> Self {
51        Self::ShdlcError(value)
52    }
53}
54
55impl From<StateResponseError> for DeviceError {
56    fn from(value: StateResponseError) -> Self {
57        Self::StateResponse(value)
58    }
59}
60
61impl From<serialport::Error> for DeviceError {
62    fn from(value: serialport::Error) -> Self {
63        Self::PortError(value)
64    }
65}
66
67impl From<CapacityError> for DeviceError {
68    fn from(_: CapacityError) -> Self {
69        Self::ShdlcError(TranslationError::DataTooLarge)
70    }
71}
72
73/// Errors sent back from a MISO frame.
74#[derive(Debug, PartialEq)]
75pub enum StateResponseError {
76    /// Illegal data size of the MOSI frame. Either an invalid frame was sent or
77    /// the firmware does not support the requested feature
78    DataSizeError,
79    /// The device does not know this command.
80    UnknownCommand,
81    /// A sent parameter is out of range.
82    ParameterError,
83    /// NACK recived from the I2C device.
84    I2CNackError,
85    /// Master hold not released in I2C.
86    I2CMasterHoldError,
87    /// I2C CRC missmatch
88    CRCError,
89    /// Sensor data read back differs from written value
90    DataWriteError,
91    /// Sensor measure loop is not running or runs on wrong gas number.
92    MeasureLoopNotRunning,
93    /// No valid gas calibration at given index
94    InvalidCalibration,
95    /// The sensor is busy at the moment
96    SensorBusy,
97    /// Command is not allwed in the current state.
98    CommandNotAllowed,
99    /// An error without a specifc error code.
100    FatalError,
101}
102
103impl From<u8> for StateResponseError {
104    fn from(value: u8) -> Self {
105        match value {
106            0x01 => Self::DataSizeError,
107            0x02 => Self::UnknownCommand,
108            0x04 => Self::ParameterError,
109            0x29 => Self::I2CNackError,
110            0x2A => Self::I2CMasterHoldError,
111            0x2B => Self::CRCError,
112            0x2C => Self::DataWriteError,
113            0x2D => Self::MeasureLoopNotRunning,
114            0x33 => Self::InvalidCalibration,
115            0x42 => Self::SensorBusy,
116            0x32 => Self::CommandNotAllowed,
117            0x7F => Self::FatalError,
118            _ => Self::FatalError,
119        }
120    }
121}
122
123impl Display for StateResponseError {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        match self {
126            Self::DataSizeError => write!(f, "illegal data size of MOSI frame or invalid frame"),
127            Self::UnknownCommand => write!(f, "the device does not support or know this command"),
128            Self::ParameterError => write!(f, "the sent parameter was out of range"),
129            Self::I2CNackError => write!(f, "NACK recived from the I2C device"),
130            Self::I2CMasterHoldError => write!(f, "master hold not released from I2C device"),
131            Self::CRCError => write!(f, "checksum miss match occured"),
132            Self::DataWriteError => write!(f, "sensor data read back differs from written value"),
133            Self::MeasureLoopNotRunning => write!(
134                f,
135                "sensor mesaure loop not running or runs on wrong gas number"
136            ),
137            Self::InvalidCalibration => write!(f, "no valid gas calibration at given index"),
138            Self::SensorBusy => write!(
139                f,
140                "the sensor is busy at the moment, it takes 300ms to power-up after reset"
141            ),
142            Self::CommandNotAllowed => write!(f, "command is not allowed in the current state"),
143            Self::FatalError => write!(f, "an error without a specific code occured"), // wow fatal error very specifc shdlc
144        }
145    }
146}