From 0aa5d11811b6bbba57d0dab1e447a6a867f1186d Mon Sep 17 00:00:00 2001 From: Marcel Springer Date: Wed, 18 Oct 2023 05:48:04 +0000 Subject: [PATCH] reverted FunctionCode newtype --- examples/tcp-client-custom-fn.rs | 7 +- examples/tcp-rtu-server-async.rs | 3 +- src/codec/mod.rs | 156 +++++++++++++------- src/codec/rtu.rs | 5 +- src/codec/tcp.rs | 5 +- src/frame/mod.rs | 238 +++---------------------------- src/lib.rs | 4 +- 7 files changed, 130 insertions(+), 288 deletions(-) diff --git a/examples/tcp-client-custom-fn.rs b/examples/tcp-client-custom-fn.rs index 91293f66..93a2b481 100644 --- a/examples/tcp-client-custom-fn.rs +++ b/examples/tcp-client-custom-fn.rs @@ -5,8 +5,6 @@ use std::borrow::Cow; -use tokio_modbus::FunctionCode; - #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), Box> { use tokio_modbus::prelude::*; @@ -17,10 +15,7 @@ async fn main() -> Result<(), Box> { println!("Fetching the coupler ID"); let rsp = ctx - .call(Request::Custom( - FunctionCode::Custom(0x66), - Cow::Borrowed(&[0x11, 0x42]), - )) + .call(Request::Custom(0x66, Cow::Borrowed(&[0x11, 0x42]))) .await?; match rsp { diff --git a/examples/tcp-rtu-server-async.rs b/examples/tcp-rtu-server-async.rs index 3a807f77..212576c8 100644 --- a/examples/tcp-rtu-server-async.rs +++ b/examples/tcp-rtu-server-async.rs @@ -14,8 +14,7 @@ use tokio::{net::TcpListener, sync::Mutex}; use tokio_modbus::{ prelude::*, server::tcp::{accept_tcp_connection, Server}, - Address, Exception, ExceptionResponse, ExtractExceptionResponse, GetFunctionCode, Quantity, - ResponsePdu, + Address, Exception, ExceptionResponse, ExtractExceptionResponse, Quantity, ResponsePdu, }; use tokio_serial::SerialStream; diff --git a/src/codec/mod.rs b/src/codec/mod.rs index 68639f71..d90271da 100644 --- a/src/codec/mod.rs +++ b/src/codec/mod.rs @@ -45,7 +45,7 @@ impl<'a> TryFrom> for Bytes { use crate::frame::Request::*; let cnt = request_byte_count(&req); let mut data = BytesMut::with_capacity(cnt); - data.put_u8(req.function_code().into()); + data.put_u8(req_to_fn_code(&req)); match req { ReadCoils(address, quantity) | ReadDiscreteInputs(address, quantity) @@ -121,7 +121,7 @@ impl From for Bytes { use crate::frame::Response::*; let cnt = response_byte_count(&rsp); let mut data = BytesMut::with_capacity(cnt); - data.put_u8(rsp.function_code().into()); + data.put_u8(rsp_to_fn_code(&rsp)); match rsp { ReadCoils(coils) | ReadDiscreteInputs(coils) => { let packed_coils = pack_coils(&coils); @@ -168,9 +168,8 @@ impl From for Bytes { impl From for Bytes { fn from(ex: ExceptionResponse) -> Bytes { let mut data = BytesMut::with_capacity(2); - let function: u8 = ex.function.into(); - debug_assert!(function < 0x80); - data.put_u8(function + 0x80); + debug_assert!(ex.function < 0x80); + data.put_u8(ex.function + 0x80); data.put_u8(ex.exception.into()); data.freeze() } @@ -188,19 +187,15 @@ impl TryFrom for Request<'static> { fn try_from(bytes: Bytes) -> Result { use crate::frame::Request::*; let mut rdr = Cursor::new(&bytes); - let fn_code: FunctionCode = rdr.read_u8()?.into(); + let fn_code = rdr.read_u8()?; let req = match fn_code { - FunctionCode::ReadCoils => { - ReadCoils(rdr.read_u16::()?, rdr.read_u16::()?) - } - FunctionCode::ReadDiscreteInputs => { - ReadDiscreteInputs(rdr.read_u16::()?, rdr.read_u16::()?) - } - FunctionCode::WriteSingleCoil => WriteSingleCoil( + 0x01 => ReadCoils(rdr.read_u16::()?, rdr.read_u16::()?), + 0x02 => ReadDiscreteInputs(rdr.read_u16::()?, rdr.read_u16::()?), + 0x05 => WriteSingleCoil( rdr.read_u16::()?, coil_to_bool(rdr.read_u16::()?)?, ), - FunctionCode::WriteMultipleCoils => { + 0x0F => { let address = rdr.read_u16::()?; let quantity = rdr.read_u16::()?; let byte_count = rdr.read_u8()?; @@ -210,17 +205,13 @@ impl TryFrom for Request<'static> { let x = &bytes[6..]; WriteMultipleCoils(address, unpack_coils(x, quantity).into()) } - FunctionCode::ReadInputRegisters => { - ReadInputRegisters(rdr.read_u16::()?, rdr.read_u16::()?) - } - FunctionCode::ReadHoldingRegisters => { + 0x04 => ReadInputRegisters(rdr.read_u16::()?, rdr.read_u16::()?), + 0x03 => { ReadHoldingRegisters(rdr.read_u16::()?, rdr.read_u16::()?) } - FunctionCode::WriteSingleRegister => { - WriteSingleRegister(rdr.read_u16::()?, rdr.read_u16::()?) - } + 0x06 => WriteSingleRegister(rdr.read_u16::()?, rdr.read_u16::()?), - FunctionCode::WriteMultipleRegisters => { + 0x10 => { let address = rdr.read_u16::()?; let quantity = rdr.read_u16::()?; let byte_count = rdr.read_u8()?; @@ -233,13 +224,13 @@ impl TryFrom for Request<'static> { } WriteMultipleRegisters(address, data.into()) } - FunctionCode::MaskWriteRegister => { + 0x16 => { let address = rdr.read_u16::()?; let and_mask = rdr.read_u16::()?; let or_mask = rdr.read_u16::()?; MaskWriteRegister(address, and_mask, or_mask) } - FunctionCode::ReadWriteMultipleRegisters => { + 0x17 => { let read_address = rdr.read_u16::()?; let read_quantity = rdr.read_u16::()?; let write_address = rdr.read_u16::()?; @@ -254,10 +245,8 @@ impl TryFrom for Request<'static> { } ReadWriteMultipleRegisters(read_address, read_quantity, write_address, data.into()) } - FunctionCode::Custom(fn_code) if fn_code < 0x80 => { - Custom(FunctionCode::Custom(fn_code), bytes[1..].to_vec().into()) - } - FunctionCode::Custom(fn_code) => { + fn_code if fn_code < 0x80 => Custom(fn_code, bytes[1..].to_vec().into()), + fn_code => { return Err(Error::new( ErrorKind::InvalidData, format!("Invalid function code: 0x{fn_code:0>2X}"), @@ -346,7 +335,7 @@ impl TryFrom for Response { } _ => { let mut bytes = bytes; - Custom(FunctionCode::Custom(fn_code), bytes.split_off(1)) + Custom(fn_code, bytes.split_off(1)) } }; Ok(rsp) @@ -366,7 +355,6 @@ impl TryFrom for ExceptionResponse { )); } let function = fn_err_code - 0x80; - let function = FunctionCode::from(function); let exception = Exception::try_from(rdr.read_u8()?)?; Ok(ExceptionResponse { function, @@ -450,6 +438,41 @@ fn unpack_coils(bytes: &[u8], count: u16) -> Vec { res } +pub(crate) const fn req_to_fn_code(req: &Request<'_>) -> u8 { + use crate::frame::Request::*; + match *req { + ReadCoils(_, _) => 0x01, + ReadDiscreteInputs(_, _) => 0x02, + WriteSingleCoil(_, _) => 0x05, + WriteMultipleCoils(_, _) => 0x0F, + ReadInputRegisters(_, _) => 0x04, + ReadHoldingRegisters(_, _) => 0x03, + WriteSingleRegister(_, _) => 0x06, + WriteMultipleRegisters(_, _) => 0x10, + MaskWriteRegister(_, _, _) => 0x16, + ReadWriteMultipleRegisters(_, _, _, _) => 0x17, + Custom(code, _) => code, + Disconnect => unreachable!(), + } +} + +const fn rsp_to_fn_code(rsp: &Response) -> u8 { + use crate::frame::Response::*; + match *rsp { + ReadCoils(_) => 0x01, + ReadDiscreteInputs(_) => 0x02, + WriteSingleCoil(_, _) => 0x05, + WriteMultipleCoils(_, _) => 0x0F, + ReadInputRegisters(_) => 0x04, + ReadHoldingRegisters(_) => 0x03, + WriteSingleRegister(_, _) => 0x06, + WriteMultipleRegisters(_, _) => 0x10, + MaskWriteRegister(_, _, _) => 0x16, + ReadWriteMultipleRegisters(_) => 0x17, + Custom(code, _) => code, + } +} + fn request_byte_count(req: &Request<'_>) -> usize { use crate::frame::Request::*; match *req { @@ -528,10 +551,51 @@ mod tests { assert_eq!(unpack_coils(&[0xff, 0b11], 10), &[true; 10]); } + #[test] + fn function_code_from_request() { + use crate::frame::Request::*; + assert_eq!(req_to_fn_code(&ReadCoils(0, 0)), 1); + assert_eq!(req_to_fn_code(&ReadDiscreteInputs(0, 0)), 2); + assert_eq!(req_to_fn_code(&WriteSingleCoil(0, true)), 5); + assert_eq!( + req_to_fn_code(&WriteMultipleCoils(0, Cow::Borrowed(&[]))), + 0x0F + ); + assert_eq!(req_to_fn_code(&ReadInputRegisters(0, 0)), 0x04); + assert_eq!(req_to_fn_code(&ReadHoldingRegisters(0, 0)), 0x03); + assert_eq!(req_to_fn_code(&WriteSingleRegister(0, 0)), 0x06); + assert_eq!( + req_to_fn_code(&WriteMultipleRegisters(0, Cow::Borrowed(&[]))), + 0x10 + ); + assert_eq!(req_to_fn_code(&MaskWriteRegister(0, 0, 0)), 0x16); + assert_eq!( + req_to_fn_code(&ReadWriteMultipleRegisters(0, 0, 0, Cow::Borrowed(&[]))), + 0x17 + ); + assert_eq!(req_to_fn_code(&Custom(88, Cow::Borrowed(&[]))), 88); + } + + #[test] + fn function_code_from_response() { + use crate::frame::Response::*; + assert_eq!(rsp_to_fn_code(&ReadCoils(vec![])), 1); + assert_eq!(rsp_to_fn_code(&ReadDiscreteInputs(vec![])), 2); + assert_eq!(rsp_to_fn_code(&WriteSingleCoil(0x0, false)), 5); + assert_eq!(rsp_to_fn_code(&WriteMultipleCoils(0x0, 0x0)), 0x0F); + assert_eq!(rsp_to_fn_code(&ReadInputRegisters(vec![])), 0x04); + assert_eq!(rsp_to_fn_code(&ReadHoldingRegisters(vec![])), 0x03); + assert_eq!(rsp_to_fn_code(&WriteSingleRegister(0, 0)), 0x06); + assert_eq!(rsp_to_fn_code(&WriteMultipleRegisters(0, 0)), 0x10); + assert_eq!(rsp_to_fn_code(&MaskWriteRegister(0, 0, 0)), 0x16); + assert_eq!(rsp_to_fn_code(&ReadWriteMultipleRegisters(vec![])), 0x17); + assert_eq!(rsp_to_fn_code(&Custom(99, Bytes::from_static(&[]))), 99); + } + #[test] fn exception_response_into_bytes() { let bytes: Bytes = ExceptionResponse { - function: FunctionCode::ReadHoldingRegisters, + function: 0x03, exception: Exception::IllegalDataAddress, } .into(); @@ -548,7 +612,7 @@ mod tests { assert_eq!( rsp, ExceptionResponse { - function: FunctionCode::ReadHoldingRegisters, + function: 0x03, exception: Exception::IllegalDataAddress, } ); @@ -559,7 +623,7 @@ mod tests { let req_pdu: Bytes = Request::ReadCoils(0x01, 5).try_into().unwrap(); let rsp_pdu: Bytes = Response::ReadCoils(vec![]).into(); let ex_pdu: Bytes = ExceptionResponse { - function: FunctionCode::ReadHoldingRegisters, + function: 0x03, exception: Exception::ServerDeviceFailure, } .into(); @@ -763,12 +827,9 @@ mod tests { #[test] fn custom() { - let bytes: Bytes = Request::Custom( - FunctionCode::Custom(0x55), - Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF]), - ) - .try_into() - .unwrap(); + let bytes: Bytes = Request::Custom(0x55, Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF])) + .try_into() + .unwrap(); assert_eq!(bytes[0], 0x55); assert_eq!(bytes[1], 0xCC); assert_eq!(bytes[2], 0x88); @@ -899,10 +960,7 @@ mod tests { let req = Request::try_from(bytes).unwrap(); assert_eq!( req, - Request::Custom( - FunctionCode::Custom(0x55), - Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF]) - ) + Request::Custom(0x55, Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF])) ); } } @@ -1014,11 +1072,8 @@ mod tests { #[test] fn custom() { - let bytes: Bytes = Response::Custom( - FunctionCode::Custom(0x55), - Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF]), - ) - .into(); + let bytes: Bytes = + Response::Custom(0x55, Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF])).into(); assert_eq!(bytes[0], 0x55); assert_eq!(bytes[1], 0xCC); assert_eq!(bytes[2], 0x88); @@ -1142,10 +1197,7 @@ mod tests { let rsp = Response::try_from(bytes).unwrap(); assert_eq!( rsp, - Response::Custom( - FunctionCode::Custom(0x55), - Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF]) - ) + Response::Custom(0x55, Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF])) ); } } diff --git a/src/codec/rtu.rs b/src/codec/rtu.rs index 444249ab..d2e60075 100644 --- a/src/codec/rtu.rs +++ b/src/codec/rtu.rs @@ -710,10 +710,7 @@ mod tests { let ResponseAdu { pdu, .. } = codec.decode(&mut buf).unwrap().unwrap(); if let ResponsePdu(Err(err)) = pdu { - assert_eq!( - format!("{err}"), - "Modbus function FunctionCode::ReadDiscreteInputs: Illegal data value" - ); + assert_eq!(format!("{err}"), "Modbus function 2: Illegal data value"); assert_eq!(buf.len(), 0); } else { panic!("unexpected response") diff --git a/src/codec/tcp.rs b/src/codec/tcp.rs index f379ae41..547c0cb1 100644 --- a/src/codec/tcp.rs +++ b/src/codec/tcp.rs @@ -243,10 +243,7 @@ mod tests { assert_eq!(hdr.transaction_id, TRANSACTION_ID); assert_eq!(hdr.unit_id, UNIT_ID); if let ResponsePdu(Err(err)) = pdu { - assert_eq!( - format!("{err}"), - "Modbus function FunctionCode::ReadDiscreteInputs: Illegal data value" - ); + assert_eq!(format!("{err}"), "Modbus function 2: Illegal data value"); assert_eq!(buf.len(), 1); } else { panic!("unexpected response") diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 4f957a3c..6bc198c6 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -9,83 +9,10 @@ pub(crate) mod tcp; use std::{borrow::Cow, error, fmt}; -use crate::bytes::Bytes; +use crate::{bytes::Bytes, codec::req_to_fn_code}; /// A Modbus function code is represented by an unsigned 8 bit integer. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FunctionCode { - ReadCoils, //=> 0x01, - ReadDiscreteInputs, // => 0x02, - WriteSingleCoil, //(_, _) => 0x05, - WriteMultipleCoils, //(_, _) => 0x0F, - ReadInputRegisters, //(_) => 0x04, - ReadHoldingRegisters, //(_) => 0x03, - WriteSingleRegister, //(_, _) => 0x06, - WriteMultipleRegisters, //(_, _) => 0x10, - MaskWriteRegister, //(_, _, _) => 0x16, - ReadWriteMultipleRegisters, //(_) => 0x17, - Custom(u8), // => code, -} - -impl From for u8 { - fn from(val: FunctionCode) -> u8 { - match val { - FunctionCode::ReadCoils => 0x01, - FunctionCode::ReadDiscreteInputs => 0x02, - FunctionCode::WriteSingleCoil => 0x05, - FunctionCode::WriteMultipleCoils => 0x0f, - FunctionCode::ReadInputRegisters => 0x04, - FunctionCode::ReadHoldingRegisters => 0x03, - FunctionCode::WriteSingleRegister => 0x06, - FunctionCode::WriteMultipleRegisters => 0x10, - FunctionCode::MaskWriteRegister => 0x16, - FunctionCode::ReadWriteMultipleRegisters => 0x17, - FunctionCode::Custom(code) => code, - } - } -} - -impl From for FunctionCode { - fn from(value: u8) -> Self { - match value { - 0x01 => FunctionCode::ReadCoils, - 0x02 => FunctionCode::ReadDiscreteInputs, - 0x05 => FunctionCode::WriteSingleCoil, - 0x0f => FunctionCode::WriteMultipleCoils, - 0x04 => FunctionCode::ReadInputRegisters, - 0x03 => FunctionCode::ReadHoldingRegisters, - 0x06 => FunctionCode::WriteSingleRegister, - 0x10 => FunctionCode::WriteMultipleRegisters, - 0x16 => FunctionCode::MaskWriteRegister, - 0x17 => FunctionCode::ReadWriteMultipleRegisters, - value => FunctionCode::Custom(value), - } - } -} - -impl std::fmt::Display for FunctionCode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - FunctionCode::ReadCoils => f.write_str("FunctionCode::ReadCoils"), - FunctionCode::ReadDiscreteInputs => f.write_str("FunctionCode::ReadDiscreteInputs"), - FunctionCode::WriteSingleCoil => f.write_str("FunctionCode::WriteSingleCoil"), - FunctionCode::WriteMultipleCoils => f.write_str("FunctionCode::WriteMultipleCoils"), - FunctionCode::ReadInputRegisters => f.write_str("FunctionCode::ReadInputRegisters"), - FunctionCode::ReadHoldingRegisters => f.write_str("FunctionCode::ReadHoldingRegisters"), - FunctionCode::WriteSingleRegister => f.write_str("FunctionCode::WriteSingleRegister"), - FunctionCode::WriteMultipleRegisters => { - f.write_str("FunctionCode::WriteMultipleRegisters") - } - FunctionCode::MaskWriteRegister => f.write_str("FunctionCode::MaskWriteRegister"), - FunctionCode::ReadWriteMultipleRegisters => { - f.write_str("FunctionCode::ReadWriteMultipleRegisters") - } - FunctionCode::Custom(value) => { - f.write_str(format!("FunctionCode::Custom({value})").as_str()) - } - } - } -} +pub type FunctionCode = u8; /// A Modbus protocol address is represented by 16 bit from `0` to `65535`. /// @@ -109,11 +36,6 @@ pub(crate) type Word = u16; /// Number of items to process. pub type Quantity = u16; -/// A Trait that is implemented on types that have a function code -pub trait GetFunctionCode { - fn function_code(&self) -> FunctionCode; -} - /// A request represents a message from the client (master) to the server (slave). #[derive(Debug, Clone, PartialEq, Eq)] pub enum Request<'a> { @@ -217,28 +139,9 @@ impl<'a> Request<'a> { } } - // pub fn into_exception(self, exception: Exception) -> ExceptionResponse{ - - // } -} - -impl<'a> GetFunctionCode for Request<'a> { - fn function_code(&self) -> FunctionCode { - use Request::*; - match *self { - ReadCoils(_, _) => FunctionCode::ReadCoils, - ReadDiscreteInputs(_, _) => FunctionCode::ReadDiscreteInputs, - WriteSingleCoil(_, _) => FunctionCode::WriteSingleCoil, - WriteMultipleCoils(_, _) => FunctionCode::WriteMultipleCoils, - ReadInputRegisters(_, _) => FunctionCode::ReadInputRegisters, - ReadHoldingRegisters(_, _) => FunctionCode::ReadHoldingRegisters, - WriteSingleRegister(_, _) => FunctionCode::WriteSingleRegister, - WriteMultipleRegisters(_, _) => FunctionCode::WriteMultipleRegisters, - MaskWriteRegister(_, _, _) => FunctionCode::MaskWriteRegister, - ReadWriteMultipleRegisters(_, _, _, _) => FunctionCode::ReadWriteMultipleRegisters, - Custom(code, _) => code, - Disconnect => unreachable!(), - } + #[must_use] + pub fn function_code(&self) -> FunctionCode { + req_to_fn_code(self) } } @@ -327,25 +230,6 @@ pub enum Response { Custom(FunctionCode, Bytes), } -impl GetFunctionCode for Response { - fn function_code(&self) -> FunctionCode { - use Response::*; - match *self { - ReadCoils(_) => FunctionCode::ReadCoils, - ReadDiscreteInputs(_) => FunctionCode::ReadDiscreteInputs, - WriteSingleCoil(_, _) => FunctionCode::WriteSingleCoil, - WriteMultipleCoils(_, _) => FunctionCode::WriteMultipleCoils, - ReadInputRegisters(_) => FunctionCode::ReadInputRegisters, - ReadHoldingRegisters(_) => FunctionCode::ReadHoldingRegisters, - WriteSingleRegister(_, _) => FunctionCode::WriteSingleRegister, - WriteMultipleRegisters(_, _) => FunctionCode::WriteMultipleRegisters, - MaskWriteRegister(_, _, _) => FunctionCode::MaskWriteRegister, - ReadWriteMultipleRegisters(_) => FunctionCode::ReadWriteMultipleRegisters, - Custom(code, _) => code, - } - } -} - /// A server (slave) exception. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -393,6 +277,21 @@ pub struct ExceptionResponse { } /// Convenience trait for downcasting `std::io::Error` to `ExceptionResponse` +/// An Easy way to extract an `ExceptionResponse` from `std::io::Error` +/// ``` +/// use tokio_modbus::{Exception, ExceptionResponse}; +/// use tokio_modbus::client::Reader; +/// use tokio_modbus::ExtractExceptionResponse; +/// async fn read_holding_registeres(mut ctx: impl Reader){ +/// let response: Result, std::io::Error> = ctx.read_holding_registers(0x100, 1).await; +/// assert!(response.is_err()); +/// // The call to exception_response() extracts the `ExceptionsResponse`` if it is one. Otherwise the `std::io::Error` is returned +/// let maybe_exception_response: Result = response.err().unwrap().exception_response(); +/// assert!(maybe_exception_response.is_ok()); +/// let exception_response: ExceptionResponse = maybe_exception_response.ok().unwrap(); +/// assert_eq!(exception_response.exception, Exception::IllegalDataAddress); +/// } +/// ``` pub trait ExtractExceptionResponse { fn exception_response(self) -> Result; } @@ -507,100 +406,3 @@ impl error::Error for ExceptionResponse { self.exception.description() } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn function_code_from_request() { - use crate::frame::Request::*; - assert_eq!(ReadCoils(0, 0).function_code(), FunctionCode::ReadCoils); - assert_eq!( - ReadDiscreteInputs(0, 0).function_code(), - FunctionCode::ReadDiscreteInputs - ); - assert_eq!( - WriteSingleCoil(0, true).function_code(), - FunctionCode::WriteSingleCoil - ); - assert_eq!( - WriteMultipleCoils(0, Cow::Borrowed(&[])).function_code(), - FunctionCode::WriteMultipleCoils - ); - assert_eq!( - ReadInputRegisters(0, 0).function_code(), - FunctionCode::ReadInputRegisters - ); - assert_eq!( - ReadHoldingRegisters(0, 0).function_code(), - FunctionCode::ReadHoldingRegisters - ); - assert_eq!( - WriteSingleRegister(0, 0).function_code(), - FunctionCode::WriteSingleRegister - ); - assert_eq!( - WriteMultipleRegisters(0, Cow::Borrowed(&[])).function_code(), - FunctionCode::WriteMultipleRegisters - ); - assert_eq!( - MaskWriteRegister(0, 0, 0).function_code(), - FunctionCode::MaskWriteRegister - ); - assert_eq!( - ReadWriteMultipleRegisters(0, 0, 0, Cow::Borrowed(&[])).function_code(), - FunctionCode::ReadWriteMultipleRegisters - ); - assert_eq!( - Custom(FunctionCode::Custom(88), Cow::Borrowed(&[])).function_code(), - FunctionCode::Custom(88) - ); - } - - #[test] - fn function_code_from_response() { - use crate::frame::Response::*; - assert_eq!(ReadCoils(vec![]).function_code(), FunctionCode::ReadCoils); - assert_eq!( - ReadDiscreteInputs(vec![]).function_code(), - FunctionCode::ReadDiscreteInputs - ); - assert_eq!( - WriteSingleCoil(0x0, false).function_code(), - FunctionCode::WriteSingleCoil - ); - assert_eq!( - WriteMultipleCoils(0x0, 0x0).function_code(), - FunctionCode::WriteMultipleCoils - ); - assert_eq!( - ReadInputRegisters(vec![]).function_code(), - FunctionCode::ReadInputRegisters - ); - assert_eq!( - ReadHoldingRegisters(vec![]).function_code(), - FunctionCode::ReadHoldingRegisters - ); - assert_eq!( - WriteSingleRegister(0, 0).function_code(), - FunctionCode::WriteSingleRegister - ); - assert_eq!( - WriteMultipleRegisters(0, 0).function_code(), - FunctionCode::WriteMultipleRegisters - ); - assert_eq!( - MaskWriteRegister(0, 0, 0).function_code(), - FunctionCode::MaskWriteRegister - ); - assert_eq!( - ReadWriteMultipleRegisters(vec![]).function_code(), - FunctionCode::ReadWriteMultipleRegisters - ); - assert_eq!( - Custom(FunctionCode::Custom(99), Bytes::from_static(&[])).function_code(), - FunctionCode::Custom(99) - ); - } -} diff --git a/src/lib.rs b/src/lib.rs index 42f97461..1890464c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,8 +43,8 @@ mod codec; mod frame; pub use self::frame::{ - Address, Exception, ExceptionResponse, ExtractExceptionResponse, FunctionCode, GetFunctionCode, - Quantity, Request, Response, ResponsePdu, + Address, Exception, ExceptionResponse, ExtractExceptionResponse, FunctionCode, Quantity, + Request, Response, ResponsePdu, }; mod service;