Skip to main content

huawei_inverter/
error.rs

1use thiserror::Error;
2use tokio_modbus::ProtocolError;
3
4use crate::{DecodeError, ValidationError};
5
6/// This error is returned if a communication fails because of a timeout
7/// or underlying modbus error.
8#[derive(Debug, Error)]
9pub enum ModbusError {
10    /// A timeout occured
11    #[error("Timeout")]
12    Timeout,
13    /// The requested device does not implement modbus correctly and the
14    /// underlying modbus implementation reported an error.
15    #[error(transparent)]
16    Protocol(#[from] ProtocolError),
17    /// I/O error
18    #[error("I/O error: {0}")]
19    IO(#[from] std::io::Error),
20    /// The function code received in the query is not an allowable action for
21    /// the server (or slave). This may be because the function code is only
22    /// applicable to newer devices, and was not implemented in the unit
23    /// selected. It could also indicate that the server (or slave) is in the
24    /// wrong state to process a request of this type, for example because it is
25    /// unconfigured and is being asked to return register values.
26    #[error("Illegal function")]
27    IllegalFunction,
28    /// The data address received in the query is not an allowable address for
29    /// the server (or slave). More specifically, the combination of reference
30    /// number and transfer length is invalid. For a controller with 100
31    /// registers, the PDU addresses the first register as 0, and the last one
32    /// as 99. If a request is submitted with a starting register address of 96
33    /// and a quantity of registers of 4, then this request will successfully
34    /// operate (address-wise at least) on registers 96, 97, 98, 99. If a
35    /// request is submitted with a starting register address of 96 and a
36    /// quantity of registers of 5, then this request will fail with Exception
37    /// Code 0x02 “Illegal Data Address” since it attempts to operate on
38    /// registers 96, 97, 98, 99 and 100, and there is no register with address
39    /// 100.
40    #[error("Illegal data address")]
41    IllegalDataAddress,
42    /// A value contained in the query data field is not an allowable value for
43    /// server (or slave). This indicates a fault in the structure of the
44    /// remainder of a complex request, such as that the implied length is
45    /// incorrect. It specifically does NOT mean that a data item submitted for
46    /// storage in a register has a value outside the expectation of the
47    /// application program, since the MODBUS protocol is unaware of the
48    /// significance of any particular value of any particular register.
49    #[error("Illegal data value")]
50    IllegalDataValue,
51    /// An unrecoverable error occurred while the server (or slave) was
52    /// attempting to perform the requested action.
53    #[error("Server device failure")]
54    ServerDeviceFailure,
55    /// Specialized use in conjunction with programming
56    /// commands. The server (or slave) has accepted the request and is
57    /// processing it, but a long duration of time will be required to do so.
58    /// This response is returned to prevent a timeout error from occurring in
59    /// the client (or master). The client (or master) can next issue a Poll
60    /// Program Complete message to determine if processing is completed.
61    #[error("Acknowledge")]
62    Acknowledge,
63    /// Specialized use in conjunction with programming commands. The server (or
64    /// slave) is engaged in processing a long–duration program command. The
65    /// client (or master) should retransmit the message later when the server
66    /// (or slave) is free.
67    #[error("Server device busy")]
68    ServerDeviceBusy,
69    /// Specialized use in conjunction with function codes 20 and 21 and
70    /// reference type 6, to indicate that the extended file area failed to pass
71    /// a consistency check. The server (or slave) attempted to read record
72    /// file, but detected a parity error in the memory. The client (or master)
73    /// can retry the request, but service may be required on the server (or
74    /// slave) device.
75    #[error("Memory parity error")]
76    MemoryParityError,
77    /// Specialized use in conjunction with gateways, indicates that the gateway
78    /// was unable to allocate an internal communication path from the input
79    /// port to the output port for processing the request. Usually means that
80    /// the gateway is misconfigured or overloaded.
81    #[error("Gateway path unavailable")]
82    GatewayPathUnavailable,
83    /// Specialized use in conjunction with gateways, indicates that no response
84    /// was obtained from the target device. Usually means that the device is
85    /// not present on the network.
86    #[error("Gateway target device")]
87    GatewayTargetDevice,
88    /// Custom modbus error
89    #[error("Custom: {0}")]
90    Custom(u8),
91}
92
93/// This error is returned if there was an error loading the
94/// requested model.
95#[derive(Debug, Error)]
96pub enum ReadError {
97    /// Some error occured while communicating via the modbus. This
98    /// error is implementation specific.
99    #[error("Modbus error: {0}")]
100    Modbus(#[from] ModbusError),
101    /// The decoding of the point data failed.
102    #[error("Decode error: {0}")]
103    DecodeError(#[from] DecodeError),
104}
105
106/// This error is returned if there was an error while
107/// writing data to a point.
108#[derive(Debug, Error)]
109pub enum WriteError {
110    /// Communication error.
111    #[error("Modbus error: {0}")]
112    Modbus(#[from] ModbusError),
113    // /// The encoded value was too large for the point.
114    #[error("Encoded value too large for point")]
115    ValueTooLarge,
116    #[error("This point is not writable")]
117    NotWritable,
118    #[error("Validation error: {0}")]
119    Validation(#[from] ValidationError),
120}
121
122impl From<tokio_modbus::Error> for ModbusError {
123    fn from(value: tokio_modbus::Error) -> Self {
124        match value {
125            tokio_modbus::Error::Protocol(e) => Self::Protocol(e),
126            tokio_modbus::Error::Transport(e) => Self::IO(e),
127        }
128    }
129}
130
131impl From<tokio_modbus::ExceptionCode> for ModbusError {
132    fn from(value: tokio_modbus::ExceptionCode) -> Self {
133        match value {
134            tokio_modbus::ExceptionCode::IllegalFunction => Self::IllegalFunction,
135            tokio_modbus::ExceptionCode::IllegalDataAddress => Self::IllegalDataAddress,
136            tokio_modbus::ExceptionCode::IllegalDataValue => Self::IllegalDataValue,
137            tokio_modbus::ExceptionCode::ServerDeviceFailure => Self::ServerDeviceFailure,
138            tokio_modbus::ExceptionCode::Acknowledge => Self::Acknowledge,
139            tokio_modbus::ExceptionCode::ServerDeviceBusy => Self::ServerDeviceBusy,
140            tokio_modbus::ExceptionCode::MemoryParityError => Self::MemoryParityError,
141            tokio_modbus::ExceptionCode::GatewayPathUnavailable => Self::GatewayPathUnavailable,
142            tokio_modbus::ExceptionCode::GatewayTargetDevice => Self::GatewayTargetDevice,
143            tokio_modbus::ExceptionCode::Custom(x) => Self::Custom(x),
144        }
145    }
146}