1use thiserror::Error;
4use mabi_core::Error as CoreError;
5
6pub type ModbusResult<T> = Result<T, ModbusError>;
8
9#[derive(Debug, Error)]
11pub enum ModbusError {
12 #[error("Invalid function code: {0}")]
14 InvalidFunction(u8),
15
16 #[error("Invalid address: {address} (range: 0-{max})")]
18 InvalidAddress { address: u16, max: u16 },
19
20 #[error("Invalid quantity: {quantity} (range: 1-{max})")]
22 InvalidQuantity { quantity: u16, max: u16 },
23
24 #[error("Invalid data: {0}")]
26 InvalidData(String),
27
28 #[error("Device not found: unit {unit_id}")]
30 DeviceNotFound { unit_id: u8 },
31
32 #[error("Server error: {0}")]
34 Server(String),
35
36 #[error("Connection error: {0}")]
38 Connection(String),
39
40 #[error("I/O error: {0}")]
42 Io(#[from] std::io::Error),
43
44 #[error("Core error: {0}")]
46 Core(#[from] CoreError),
47
48 #[error("Internal error: {0}")]
50 Internal(String),
51
52 #[error("Invalid unit ID {unit_id}: {reason}")]
54 InvalidUnitId { unit_id: u8, reason: String },
55
56 #[error("Unit not found: {unit_id}")]
58 UnitNotFound { unit_id: u8 },
59
60 #[error("Unit already exists: {unit_id}")]
62 UnitAlreadyExists { unit_id: u8 },
63
64 #[error("Unit limit reached: maximum {max} units allowed")]
66 UnitLimitReached { max: usize },
67
68 #[error("Unit {unit_id} is disabled")]
70 UnitDisabled { unit_id: u8 },
71
72 #[error("Configuration error: {0}")]
74 Config(String),
75}
76
77impl ModbusError {
78 pub fn to_exception_code(&self) -> u8 {
80 match self {
81 Self::InvalidFunction(_) => 0x01, Self::InvalidAddress { .. } => 0x02, Self::InvalidQuantity { .. } => 0x03, Self::InvalidData(_) => 0x03, Self::DeviceNotFound { .. } => 0x0B, Self::Server(_) => 0x04, Self::Connection(_) => 0x0A, Self::Io(_) => 0x04, Self::Core(_) => 0x04, Self::Internal(_) => 0x04, Self::InvalidUnitId { .. } => 0x0B, Self::UnitNotFound { .. } => 0x0B, Self::UnitAlreadyExists { .. } => 0x04, Self::UnitLimitReached { .. } => 0x04, Self::UnitDisabled { .. } => 0x0B, Self::Config(_) => 0x04, }
98 }
99
100 pub fn invalid_address(address: u16, max: u16) -> Self {
102 Self::InvalidAddress { address, max }
103 }
104
105 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}