modbus_relay/errors/
transport.rs1use std::time::Duration;
2use thiserror::Error;
3use tokio::time::error::Elapsed;
4
5use super::{IoOperation, RtsError, SerialErrorKind};
6
7#[derive(Error, Debug)]
8pub enum TransportError {
9 #[error("Serial port error: {kind} on {port} - {details}")]
10 Serial {
11 kind: SerialErrorKind,
12 port: String,
13 details: String,
14 #[source]
15 source: Option<serialport::Error>,
16 },
17
18 #[error("Network error: {0}")]
19 Network(std::io::Error),
20
21 #[error("I/O error: {operation} failed on {details}")]
22 Io {
23 operation: IoOperation,
24 details: String,
25 #[source]
26 source: std::io::Error,
27 },
28
29 #[error("Transaction timeout after {elapsed:?}, limit was {limit:?}")]
30 Timeout {
31 elapsed: Duration,
32 limit: Duration,
33 #[source]
34 source: Elapsed,
35 },
36
37 #[error("No response received after {attempts} attempts over {elapsed:?}")]
38 NoResponse { attempts: u8, elapsed: Duration },
39
40 #[error("RTS error: {0}")]
41 Rts(#[from] RtsError),
42}
43
44impl From<serialport::Error> for TransportError {
45 fn from(err: serialport::Error) -> Self {
46 match err.kind {
47 serialport::ErrorKind::NoDevice => TransportError::Serial {
48 kind: SerialErrorKind::OpenFailed,
49 port: err.to_string(),
50 details: "Device not found".into(),
51 source: Some(err),
52 },
53 serialport::ErrorKind::InvalidInput => TransportError::Serial {
54 kind: SerialErrorKind::ConfigurationFailed,
55 port: err.to_string(),
56 details: "Invalid configuration".into(),
57 source: Some(err),
58 },
59 serialport::ErrorKind::Io(io_err) => TransportError::Io {
60 operation: match io_err {
61 std::io::ErrorKind::NotFound => IoOperation::Configure,
62 std::io::ErrorKind::PermissionDenied => IoOperation::Configure,
63 std::io::ErrorKind::TimedOut => IoOperation::Read,
64 std::io::ErrorKind::WriteZero => IoOperation::Write,
65 _ => IoOperation::Control,
66 },
67 details: io_err.to_string(),
68 source: std::io::Error::new(io_err, err.description),
69 },
70 _ => TransportError::Serial {
71 kind: SerialErrorKind::OpenFailed,
72 port: err.to_string(),
73 details: err.to_string(),
74 source: Some(err),
75 },
76 }
77 }
78}
79
80impl From<std::io::Error> for TransportError {
81 fn from(err: std::io::Error) -> Self {
82 TransportError::Io {
83 operation: match err.kind() {
84 std::io::ErrorKind::TimedOut => IoOperation::Read,
85 std::io::ErrorKind::WouldBlock => IoOperation::Read,
86 std::io::ErrorKind::WriteZero => IoOperation::Write,
87 std::io::ErrorKind::Interrupted => IoOperation::Control,
88 _ => IoOperation::Control,
89 },
90 details: err.to_string(),
91 source: err,
92 }
93 }
94}
95
96impl From<Elapsed> for TransportError {
97 fn from(err: Elapsed) -> Self {
98 TransportError::Timeout {
99 elapsed: Duration::from_secs(1), limit: Duration::from_secs(1), source: err,
102 }
103 }
104}