- Encoding of requests: Less allocations
- Decoding of requests/responses: More strict validation
- Increased MSRV from 1.65 to 1.76
- Limit request/response PDU size to 253 bytes (encoding/decoding)
- Implement
Report Server ID
(function code 17). - Added
ExceptionCode::new
.
- Added all
FunctionCode
s defined in the protocol specification. - Renamed
Exception
toExceptionCode
to be more consistent withFunctionCode
. - Added
ExceptionCode::Custom
. - Removed
TryFrom<u8>
and#[repr(u8)]
forException
. - Removed
FunctionCode::Disconnect
. - Client: Added new
disconnect()
method to trait that returnsstd::io::Result
.
- Yanked: Adding
FunctionCode::ReportServerId
is a breaking change.
- Server: Added associated types
Response
andException
toService
trait.
- Fix: Do not panic on disconnect.
- Added
FunctionCode::Disconnect
.
- Fix: Do not panic on mismatching request/response function codes.
- Client: Replace
std::io::Error
with a custom error type that handles both protocol and transport errors.
- Client: Support handling of Modbus exceptions by using nested
Result
s.
-
Client: All methods in the
Client
,Reader
andWriter
traits now return nestedResult
values that both need to be handled explicitly.async fn read_coils(&mut self, _: Address, _: Quantity) - -> Result<Vec<Coil>, std::io::Error>; + -> Result<Result<Vec<Coil>, Exception>, std::io::Error>;
The type alias tokio_modbus::Result<T>
facilitates referencing the new return
types.
pub type Result<T> = Result<Result<T, Exception>, std::io::Error>
- Server: Remove
Sync
andUnpin
trait bounds fromService::call()
future result. - Feature: Add
Exception
to the public API. - Example: Update examples with new
Service
trait for the Server. - Tests: Add
Exception
integration tests fortcp-server
,rtu-server
andrtu-over-tcp-server
.
- Server: Update
Service::Future
generic associated type. - Server: Remove
Service::Response
andService::Error
generic associated type.
- Feature: Retrieve the
FunctionCode
of aRequest
/Response
. - Feature: Add
rtu-over-tcp-server
for RTU over TCP server skeleton.
- Exclude
rtu-server
/tcp-server
from default features. FunctionCode
: Replacetype
alias withenum
.
- Optimization: Avoid allocations when writing multiple coils/registers.
- Optimization: Avoid allocations when receiving custom responses.
Request
: Requires a lifetime and stores multiple coils/registers wrapped intoCow
to avoid allocations.Response::Custom
: The payload is returned asBytes
instead ofVec
to avoid allocations.
- Clear rx buffer before sending to help with error recovery on unreliable physical connections #198
- Fix
rtu-sync
build
- TCP Server: Replace
NewService
trait with closures and never panic - TCP Server: Stabilize "tcp-server" feature
- TCP Client: Allow to attach a generic transport layer, e.g. for TLS support
- RTU Server: Remove
NewService
trait and pass instance directly - Fix (sync): No timeout while establishing serial RTU connections
- Add: TLS client and server examples
- Fix: Limit retrying Modbus RTU communication to 20 times instead of looping infinitely
- Increase Minimum Supported Rust Version to 1.65
- RTU: Replaced the async and fallible
connect()
andconnect_slave()
functions with synchronous and infallible variants namedattach()
andattach_slave()
in correspondence to their TCP counterparts.
- Fix (sync): Panic when using client-side timeouts #155
- tcp-server: Upgrade socket2 dependency
- Added: Optional timeout for synchronous RTU/TCP operations #125.
- Features: Added "rtu-sync" as a replacement and superset of "rtu" and "sync"
- Features: Added "tcp-sync" as a replacement and superset of "tcp" and "sync"
- Features: Added "rtu-server" as a replacement and superset of "rtu" and "server"
- Server: Removed inconsistent
server::*
re-exports fromprelude::tcp
- Server: Provide access to
SlaveId
in request - Server: Allow requests without a response
- Added support for the
MaskWriteRegister
function code.
- Masked write register requests and responses are now handled by the new
MaskWriteRegister
variant, not under theCustom
variant.
- Fix (Windows): Upgrade dependencies to fix build failures on Windows for Tokio 1.23.0 and later.
- Fix (RTU/sync): Execute SerialStream::open within an async runtime #116
- Fix (RTU): Wrong byte count offset when writing multiple coils/registers
- Fix: require tokio/rt for sync feature
- Changed: Update methods on TCP server to be async (only concerns
tcp-server
feature)
- Removed
sync
from default features - Derived
Debug
for client-side RTU/TCPContext
- Removed client-side
SharedContext
- Upgraded tokio version from 0.2 to 1
- Switched from deprecated net2 to socket2
- Fix (RTU): Wrong byte count offset when writing multiple coils/registers
- Fixed handling of broken pipe errors in RTU service
- Fixed multiplication overflow for function 1 and 2 #87
- New public API: moved to async/await and tokio v0.2.x
- Removed unmaintained dependency
tokio-proto
- Make
Exception
andExceptionResponse
public - Fixed
WriteSingleCoil
response to include data - Hide server traits
Service
/NewService
traits behindserver
feature - Hide TCP server implementation behind
tcp-server
feature - Improved documentation
Due to the move to async/await and tokio v0.2.x you'll need to adjust your current code. Here are some lines as example:
-let mut core = Core::new().unwrap();
-let handle = core.handle();
let socket_addr = "127.0.0.1:5502".parse().unwrap();
-let task = tcp::connect(&handle, socket_addr).and_then(move |ctx|
- ctx.read_input_registers(0x1000, 7).and_then(move |data|
- // ...
- )
-);
+let mut ctx = tcp::connect(socket_addr).await?;
+let data = ctx.read_input_registers(0x1000, 7).await?;
- Added missing implementation of
disconnect()
for TCP clients - Upgraded tokio-serial to version 3.3
- Disabled the default features of tokio-serial to exclude an unused dependency on libudev inherited from mio-serial
- Fixed reading coils: Truncate response payload to match the requested number of coils or discrete inputs.
- Client: Added a
Disconnect
request as poison pill for stopping the client service and to release the underlying transport - Added utilities to share a single Modbus context within a thread for communicating with multiple devices
- Added utility functions to disconnect and reconnect stale connections after errors
- Minimal Rust version:
1.34.0
Extending the Request
enum with the new variant Disconnect
might break
existing code. This variant is only used internally within the client and will
never be sent across the wire and can safely be ignored by both clients and
servers!
- RTU client: Use a generic async transport instead of
Serial
- New public API
- Client: Change devices while connected
- TCP Client: Connect to RTU devices via gateway (unit identifier)
- RTU Client: Try to recover from frame errors
-
Make all public crate exports accessible in the new
prelude
module- use tokio_modbus::*; + use tokio_modbus::prelude::*;
-
Rename and relocate client traits
- client::ModbusClient + client::Client
- client::SyncModbusClient + client::sync::Client
-
Rename and relocate Client structs into Context
- client::Client + client::Context
- client::SyncClient + client::sync::Context
-
Split
Client
trait intoClient
+Reader
+Writer
traits -
Use free functions in (nested) submodules for creating/connecting a client context
- Client::connect_tcp(...); + tcp::connect(...) or tcp::connect_device(...);
- Client::connect_rtu(...); + rtu::connect_device(...);
- SyncClient::connect_tcp(...); + sync::tcp::connect(...) or sync::tcp::connect_device(...);
- SyncClient::connect_rtu(...); + sync::rtu::connect_device(...);
-
Reorder parameters of asynchronous connect() functions, i.e. the Tokio handle is always the first parameter
-
Move TCP server into submodule
- Server::new_tcp(socket_addr).serve(...); + tcp::Server::new(socket_addr).serve(...);
- fix decoding of incomplete RTU frames
- fix compilation with
features = ["rtu"]
- refactor: use
tokio-codec
- refactor: use
put_u16_be
instead ofput_u16::<BigEndian>
- refactor: prepare for compilation with
edition = "2018"
- fix codec: create buffers with correct capacity
- add simple tcp server implementation
- add sync clients
- use tokio-serial v0.6.x
-
Changed Client API
- use tokio_modbus::{Client, TcpClient}; + use tokio_modbus::*;
- RtuClient::connect(port, server_addr, &handle) + Client::connect_rtu(port, server_addr, &handle)
- TcpClient::connect(&addr, &handle) + Client::connect_tcp(&addr, &handle)
- initial implementation