Skip to main content

rust_ethernet_ip/
error.rs

1// use std::error::Error;
2use std::io;
3use std::time::Duration;
4use thiserror::Error;
5
6/// Result type alias for EtherNet/IP operations
7pub type Result<T> = std::result::Result<T, EtherNetIpError>;
8
9/// Error types that can occur during EtherNet/IP communication
10#[derive(Debug, Error)]
11pub enum EtherNetIpError {
12    /// IO error (network issues, connection problems)
13    #[error("IO error: {0}")]
14    Io(#[from] io::Error),
15
16    /// Protocol error (invalid packet format, unsupported features)
17    #[error("Protocol error: {0}")]
18    Protocol(String),
19
20    /// Tag not found in PLC
21    #[error("Tag not found: {0}")]
22    TagNotFound(String),
23
24    /// Data type mismatch
25    #[error("Data type mismatch: expected {expected}, got {actual}")]
26    DataTypeMismatch { expected: String, actual: String },
27
28    /// Write error with status code
29    #[error("Write error: {message} (status: {status})")]
30    WriteError { status: u8, message: String },
31
32    /// Read error with status code
33    #[error("Read error: {message} (status: {status})")]
34    ReadError { status: u8, message: String },
35
36    /// Invalid response from PLC
37    #[error("Invalid response: {reason}")]
38    InvalidResponse { reason: String },
39
40    /// Timeout error
41    #[error("Operation timed out after {0:?}")]
42    Timeout(Duration),
43
44    /// UDT error
45    #[error("UDT error: {0}")]
46    Udt(String),
47
48    /// Connection error (PLC not responding, session issues)
49    #[error("Connection error: {0}")]
50    Connection(String),
51
52    /// Connection lost (network closed, PLC unreachable)
53    #[error("Connection lost: {0}")]
54    ConnectionLost(String),
55
56    /// CIP protocol error with status code (from PLC)
57    #[error("CIP error 0x{code:02X}: {message}")]
58    CipError { code: u8, message: String },
59
60    /// String is too long for the PLC's string type
61    #[error("String too long: max length is {max_length}, but got {actual_length}")]
62    StringTooLong {
63        max_length: usize,
64        actual_length: usize,
65    },
66
67    /// String contains invalid characters
68    #[error("Invalid string: {reason}")]
69    InvalidString { reason: String },
70
71    /// String write operation failed
72    #[error("String write failed: {message} (status: {status})")]
73    StringWriteError { status: u8, message: String },
74
75    /// String read operation failed
76    #[error("String read failed: {message} (status: {status})")]
77    StringReadError { status: u8, message: String },
78
79    /// Invalid string response from PLC
80    #[error("Invalid string response: {reason}")]
81    InvalidStringResponse { reason: String },
82
83    /// Tag error
84    #[error("Tag error: {0}")]
85    Tag(String),
86
87    /// Permission denied
88    #[error("Permission denied: {0}")]
89    Permission(String),
90
91    /// UTF-8 error
92    #[error("UTF-8 error: {0}")]
93    Utf8(#[from] std::string::FromUtf8Error),
94
95    /// Other error
96    #[error("Other error: {0}")]
97    Other(String),
98
99    /// Subscription error
100    #[error("Subscription error: {0}")]
101    Subscription(String),
102}
103
104impl EtherNetIpError {
105    /// Returns true if the error is likely retriable (e.g. timeout, connection lost).
106    /// Use this to decide whether to retry an operation or reconnect.
107    pub fn is_retriable(&self) -> bool {
108        matches!(
109            self,
110            EtherNetIpError::Timeout(_)
111                | EtherNetIpError::Connection(_)
112                | EtherNetIpError::ConnectionLost(_)
113                | EtherNetIpError::Io(_)
114        )
115    }
116}