#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct ModbusMessage {
pub transaction_id: u16,
pub unit_id: u8,
pub raw_function_code: u8,
pub function: ModbusFunction,
pub is_exception: bool,
pub exception_code: Option<ModbusExceptionCode>,
pub address: Option<u16>,
pub quantity: Option<u16>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[non_exhaustive]
pub enum ModbusFunction {
ReadCoils,
ReadDiscreteInputs,
ReadHoldingRegisters,
ReadInputRegisters,
WriteSingleCoil,
WriteSingleRegister,
ReadExceptionStatus,
Diagnostics,
GetCommEventCounter,
GetCommEventLog,
WriteMultipleCoils,
WriteMultipleRegisters,
ReportServerId,
ReadFileRecord,
WriteFileRecord,
MaskWriteRegister,
ReadWriteMultipleRegisters,
ReadFifoQueue,
EncapsulatedInterfaceTransport,
Other(u8),
}
impl ModbusFunction {
pub fn from_raw(code: u8) -> Self {
let base = code & 0x7f;
match base {
1 => Self::ReadCoils,
2 => Self::ReadDiscreteInputs,
3 => Self::ReadHoldingRegisters,
4 => Self::ReadInputRegisters,
5 => Self::WriteSingleCoil,
6 => Self::WriteSingleRegister,
7 => Self::ReadExceptionStatus,
8 => Self::Diagnostics,
11 => Self::GetCommEventCounter,
12 => Self::GetCommEventLog,
15 => Self::WriteMultipleCoils,
16 => Self::WriteMultipleRegisters,
17 => Self::ReportServerId,
20 => Self::ReadFileRecord,
21 => Self::WriteFileRecord,
22 => Self::MaskWriteRegister,
23 => Self::ReadWriteMultipleRegisters,
24 => Self::ReadFifoQueue,
43 => Self::EncapsulatedInterfaceTransport,
n => Self::Other(n),
}
}
pub fn is_read(&self) -> bool {
matches!(
self,
Self::ReadCoils
| Self::ReadDiscreteInputs
| Self::ReadHoldingRegisters
| Self::ReadInputRegisters
)
}
pub fn is_write(&self) -> bool {
matches!(
self,
Self::WriteSingleCoil
| Self::WriteSingleRegister
| Self::WriteMultipleCoils
| Self::WriteMultipleRegisters
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[non_exhaustive]
pub enum ModbusExceptionCode {
IllegalFunction,
IllegalDataAddress,
IllegalDataValue,
ServerDeviceFailure,
Acknowledge,
ServerDeviceBusy,
MemoryParityError,
GatewayPathUnavailable,
GatewayTargetDeviceFailedToRespond,
Other(u8),
}
impl ModbusExceptionCode {
pub fn from_raw(code: u8) -> Self {
match code {
1 => Self::IllegalFunction,
2 => Self::IllegalDataAddress,
3 => Self::IllegalDataValue,
4 => Self::ServerDeviceFailure,
5 => Self::Acknowledge,
6 => Self::ServerDeviceBusy,
8 => Self::MemoryParityError,
10 => Self::GatewayPathUnavailable,
11 => Self::GatewayTargetDeviceFailedToRespond,
n => Self::Other(n),
}
}
}