#[cfg(feature = "rtu")]
pub(crate) mod rtu;
#[cfg(feature = "tcp")]
pub(crate) mod tcp;
use std::{error, fmt};
pub type FunctionCode = u8;
pub type Address = u16;
pub(crate) type Coil = bool;
pub(crate) type Word = u16;
pub type Quantity = u16;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Request {
ReadCoils(Address, Quantity),
ReadDiscreteInputs(Address, Quantity),
WriteSingleCoil(Address, Coil),
WriteMultipleCoils(Address, Vec<Coil>),
ReadInputRegisters(Address, Quantity),
ReadHoldingRegisters(Address, Quantity),
WriteSingleRegister(Address, Word),
WriteMultipleRegisters(Address, Vec<Word>),
MaskWriteRegister(Address, Word, Word),
ReadWriteMultipleRegisters(Address, Quantity, Address, Vec<Word>),
Custom(FunctionCode, Vec<u8>),
Disconnect,
}
#[cfg(feature = "server")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SlaveRequest {
pub slave: crate::slave::SlaveId,
pub request: Request,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Response {
ReadCoils(Vec<Coil>),
ReadDiscreteInputs(Vec<Coil>),
WriteSingleCoil(Address, Coil),
WriteMultipleCoils(Address, Quantity),
ReadInputRegisters(Vec<Word>),
ReadHoldingRegisters(Vec<Word>),
WriteSingleRegister(Address, Word),
WriteMultipleRegisters(Address, Quantity),
MaskWriteRegister(Address, Word, Word),
ReadWriteMultipleRegisters(Vec<Word>),
Custom(FunctionCode, Vec<u8>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Exception {
IllegalFunction = 0x01,
IllegalDataAddress = 0x02,
IllegalDataValue = 0x03,
ServerDeviceFailure = 0x04,
Acknowledge = 0x05,
ServerDeviceBusy = 0x06,
MemoryParityError = 0x08,
GatewayPathUnavailable = 0x0A,
GatewayTargetDevice = 0x0B,
}
impl From<Exception> for u8 {
fn from(from: Exception) -> Self {
from as u8
}
}
impl Exception {
pub(crate) fn description(&self) -> &str {
use crate::frame::Exception::*;
match *self {
IllegalFunction => "Illegal function",
IllegalDataAddress => "Illegal data address",
IllegalDataValue => "Illegal data value",
ServerDeviceFailure => "Server device failure",
Acknowledge => "Acknowledge",
ServerDeviceBusy => "Server device busy",
MemoryParityError => "Memory parity error",
GatewayPathUnavailable => "Gateway path unavailable",
GatewayTargetDevice => "Gateway target device failed to respond",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ExceptionResponse {
pub function: FunctionCode,
pub exception: Exception,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RequestPdu(pub(crate) Request);
impl From<Request> for RequestPdu {
fn from(from: Request) -> Self {
RequestPdu(from)
}
}
impl From<RequestPdu> for Request {
fn from(from: RequestPdu) -> Self {
from.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ResponsePdu(pub(crate) Result<Response, ExceptionResponse>);
impl From<Response> for ResponsePdu {
fn from(from: Response) -> Self {
ResponsePdu(Ok(from))
}
}
impl From<ExceptionResponse> for ResponsePdu {
fn from(from: ExceptionResponse) -> Self {
ResponsePdu(Err(from))
}
}
impl From<Result<Response, ExceptionResponse>> for ResponsePdu {
fn from(from: Result<Response, ExceptionResponse>) -> Self {
ResponsePdu(from.map(Into::into).map_err(Into::into))
}
}
#[cfg(feature = "server")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OptionalResponsePdu(pub(crate) Option<ResponsePdu>);
#[cfg(feature = "server")]
impl<T> From<Option<T>> for OptionalResponsePdu
where
T: Into<ResponsePdu>,
{
fn from(from: Option<T>) -> Self {
Self(from.map(Into::into))
}
}
#[cfg(feature = "server")]
impl<T> From<T> for OptionalResponsePdu
where
T: Into<ResponsePdu>,
{
fn from(from: T) -> Self {
Self(Some(from.into()))
}
}
impl From<ResponsePdu> for Result<Response, ExceptionResponse> {
fn from(from: ResponsePdu) -> Self {
from.0
}
}
impl fmt::Display for Exception {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl error::Error for Exception {
fn description(&self) -> &str {
self.description()
}
}
impl fmt::Display for ExceptionResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Modbus function {}: {}", self.function, self.exception)
}
}
impl error::Error for ExceptionResponse {
fn description(&self) -> &str {
self.exception.description()
}
}