modbus_rtu/exception.rs
1/// Enumerates the Modbus application exceptions returned by a slave device,
2/// including a catch-all for codes not defined by the specification.
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4#[repr(u8)]
5pub enum Exception {
6 /// Exception code not defined by this crate; preserves the raw value for
7 /// diagnostics.
8 Undefined(u8) = 0x00,
9
10 /// Exception code `0x01`: the function is not supported or the device state
11 /// does not allow the requested operation (for example an unconfigured unit
12 /// asked to return registers).
13 IllegalFunction = 0x01,
14
15 /// Exception code `0x02`: the combination of starting address and length
16 /// extends beyond the valid data range implemented by the device.
17 IllegalDataAddress = 0x02,
18
19 /// Exception code `0x03`: a value in the request payload is not acceptable
20 /// to the device, or the payload structure is inconsistent (for example an
21 /// incorrect implied length).
22 IllegalDataValue = 0x03,
23
24 /// Exception code `0x04`: an unrecoverable fault occurred while the device
25 /// attempted the requested action.
26 DeviceFailure = 0x04,
27
28 /// Exception code `0x05`: the device accepted the request but needs a long
29 /// interval to finish; the client should poll later (e.g., Poll Program
30 /// Complete).
31 Acknowledge = 0x05,
32
33 /// Exception code `0x06`: the device is busy processing a long-duration
34 /// command and cannot handle the new request yet; the client should retry
35 /// later.
36 DeviceBusy = 0x06,
37
38 /// Exception code `0x08`: while accessing extended file records (function
39 /// codes 20/21, reference type 6) the device detected a memory parity error.
40 MemoryParityError = 0x08,
41
42 /// Exception code `0x0A`: a gateway could not allocate an internal path
43 /// between the input and output ports, often due to misconfiguration or
44 /// overload.
45 GatewayPathUnavailable = 0x0A,
46
47 /// Exception code `0x0B`: a gateway forwarded the request but received no
48 /// response from the target device, which may be offline or unreachable.
49 GatewayTargetDeviceFailedToRespond = 0x0B,
50}
51
52impl Exception {
53 /// Returns the Modbus exception code associated with this variant.
54 ///
55 /// # Examples
56 /// ```rust
57 /// use modbus_rtu::Exception;
58 ///
59 /// assert_eq!(Exception::Undefined(0x7F).as_code(), 0x7F);
60 /// assert_eq!(Exception::IllegalDataAddress.as_code(), 0x02);
61 /// assert_eq!(Exception::DeviceBusy.as_code(), 0x06);
62 /// ```
63 ///
64 pub const fn as_code(&self) -> u8 {
65 match self {
66 Exception::Undefined(code) => *code,
67 Exception::IllegalFunction => 0x01,
68 Exception::IllegalDataAddress => 0x02,
69 Exception::IllegalDataValue => 0x03,
70 Exception::DeviceFailure => 0x04,
71 Exception::Acknowledge => 0x05,
72 Exception::DeviceBusy => 0x06,
73 Exception::MemoryParityError => 0x08,
74 Exception::GatewayPathUnavailable => 0x0A,
75 Exception::GatewayTargetDeviceFailedToRespond => 0x0B,
76 }
77 }
78
79 /// Converts a Modbus exception code into its corresponding [`Exception`]
80 /// variant. Undefined codes are wrapped in [`Exception::Undefined`].
81 ///
82 /// # Examples
83 /// ```rust
84 /// use modbus_rtu::Exception;
85 ///
86 /// assert_eq!(Exception::from_code(0x05), Exception::Acknowledge);
87 /// assert_eq!(Exception::from_code(0xFF), Exception::Undefined(0xFF));
88 /// ```
89 ///
90 pub fn from_code(code: u8) -> Self {
91 match code {
92 0x01 => Self::IllegalFunction,
93 0x02 => Self::IllegalDataAddress,
94 0x03 => Self::IllegalDataValue,
95 0x04 => Self::DeviceFailure,
96 0x05 => Self::Acknowledge,
97 0x06 => Self::DeviceBusy,
98 0x08 => Self::MemoryParityError,
99 0x0A => Self::GatewayPathUnavailable,
100 0x0B => Self::GatewayTargetDeviceFailedToRespond,
101 code => Self::Undefined(code),
102 }
103 }
104}
105
106impl std::fmt::Display for Exception {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 write!(
109 f,
110 "{}",
111 match self {
112 Exception::Undefined(code) => format!("undefined exception code 0x{:02X}", code),
113 Exception::IllegalFunction => "illegal function".to_string(),
114 Exception::IllegalDataAddress => "illegal data address".to_string(),
115 Exception::IllegalDataValue => "illegal data value".to_string(),
116 Exception::DeviceFailure => "device failure".to_string(),
117 Exception::Acknowledge => "acknowlegde".to_string(),
118 Exception::DeviceBusy => "device busy".to_string(),
119 Exception::MemoryParityError => "memory parity error".to_string(),
120 Exception::GatewayPathUnavailable => "gateway path unavailable".to_string(),
121 Exception::GatewayTargetDeviceFailedToRespond =>
122 "gateway target device failed to respond".to_string(),
123 }
124 )
125 }
126}