Skip to main content

mabi_modbus/
error.rs

1//! Modbus error types.
2
3use thiserror::Error;
4use mabi_core::Error as CoreError;
5
6/// Modbus result type.
7pub type ModbusResult<T> = Result<T, ModbusError>;
8
9/// Modbus error types.
10#[derive(Debug, Error)]
11pub enum ModbusError {
12    /// Invalid function code.
13    #[error("Invalid function code: {0}")]
14    InvalidFunction(u8),
15
16    /// Invalid address.
17    #[error("Invalid address: {address} (range: 0-{max})")]
18    InvalidAddress { address: u16, max: u16 },
19
20    /// Invalid quantity.
21    #[error("Invalid quantity: {quantity} (range: 1-{max})")]
22    InvalidQuantity { quantity: u16, max: u16 },
23
24    /// Invalid data.
25    #[error("Invalid data: {0}")]
26    InvalidData(String),
27
28    /// Device not found.
29    #[error("Device not found: unit {unit_id}")]
30    DeviceNotFound { unit_id: u8 },
31
32    /// Server error.
33    #[error("Server error: {0}")]
34    Server(String),
35
36    /// Connection error.
37    #[error("Connection error: {0}")]
38    Connection(String),
39
40    /// I/O error.
41    #[error("I/O error: {0}")]
42    Io(#[from] std::io::Error),
43
44    /// Core error.
45    #[error("Core error: {0}")]
46    Core(#[from] CoreError),
47
48    /// Internal error (for server implementation details).
49    #[error("Internal error: {0}")]
50    Internal(String),
51
52    /// Invalid unit ID.
53    #[error("Invalid unit ID {unit_id}: {reason}")]
54    InvalidUnitId { unit_id: u8, reason: String },
55
56    /// Unit not found.
57    #[error("Unit not found: {unit_id}")]
58    UnitNotFound { unit_id: u8 },
59
60    /// Unit already exists.
61    #[error("Unit already exists: {unit_id}")]
62    UnitAlreadyExists { unit_id: u8 },
63
64    /// Unit limit reached.
65    #[error("Unit limit reached: maximum {max} units allowed")]
66    UnitLimitReached { max: usize },
67
68    /// Unit disabled.
69    #[error("Unit {unit_id} is disabled")]
70    UnitDisabled { unit_id: u8 },
71
72    /// Configuration error.
73    #[error("Configuration error: {0}")]
74    Config(String),
75}
76
77impl ModbusError {
78    /// Convert to Modbus exception code.
79    pub fn to_exception_code(&self) -> u8 {
80        match self {
81            Self::InvalidFunction(_) => 0x01,     // Illegal Function
82            Self::InvalidAddress { .. } => 0x02,  // Illegal Data Address
83            Self::InvalidQuantity { .. } => 0x03, // Illegal Data Value
84            Self::InvalidData(_) => 0x03,         // Illegal Data Value
85            Self::DeviceNotFound { .. } => 0x0B,  // Gateway Target Device Failed to Respond
86            Self::Server(_) => 0x04,              // Server Device Failure
87            Self::Connection(_) => 0x0A,          // Gateway Path Unavailable
88            Self::Io(_) => 0x04,                  // Server Device Failure
89            Self::Core(_) => 0x04,                // Server Device Failure
90            Self::Internal(_) => 0x04,            // Server Device Failure
91            Self::InvalidUnitId { .. } => 0x0B,   // Gateway Target Device Failed to Respond
92            Self::UnitNotFound { .. } => 0x0B,    // Gateway Target Device Failed to Respond
93            Self::UnitAlreadyExists { .. } => 0x04, // Server Device Failure
94            Self::UnitLimitReached { .. } => 0x04,  // Server Device Failure
95            Self::UnitDisabled { .. } => 0x0B,    // Gateway Target Device Failed to Respond
96            Self::Config(_) => 0x04,              // Server Device Failure
97        }
98    }
99
100    /// Create an invalid address error.
101    pub fn invalid_address(address: u16, max: u16) -> Self {
102        Self::InvalidAddress { address, max }
103    }
104
105    /// Create an invalid quantity error.
106    pub fn invalid_quantity(quantity: u16, max: u16) -> Self {
107        Self::InvalidQuantity { quantity, max }
108    }
109}
110
111impl From<ModbusError> for CoreError {
112    fn from(err: ModbusError) -> Self {
113        CoreError::Protocol(err.to_string())
114    }
115}