Skip to main content

Serial RTU Server

The library supports serial communication using the RTU transmission mode. RTU uses a similar Modbus addressing scheme but adds a CRC to each transmitted frame.

Multi-drop communications may be implemented by having a single client communicating with multiple servers sharing the same serial channel. Broadcasts messages may be used to write requests simultaneously to all server on a channel.

Special addresses

Broadcast

When a write request is received with the broadcast unit ID (0x00), it is automatically forwarded to all registered handlers. No response will be returned.

Reserved addresses

Addresses 248 (0xF8) to 255 (0xFF) (inclusive) are reserved in the specification and should not be used. The library does not enforce this requirement, but a warning message is generated as a reminder that it may not be interoperable.

Creating a server

To create a RTU server, first build a DeviceMap for each unit ID to which the server will respond. The is similar to how it's done in the TCP server. Then use the Server.CreateRtu factory method to create the background task.

The Server.CreateRtu method takes the following arguments:

  • runtime: tokio runtime used to drive the async process. See Runtime for more details.
  • path: path of the serial device.
    • On Windows, it's generally something like COM3
    • On Linux, it's generally something like /dev/ttyS3. You need to have the adequate permissions to access these devices.
  • serial_port_settings: structure with various serial port settings:
    • Baud rate in bit per second
    • Data bits. Note that Modbus should use 8 data bits.
    • Stop bits
    • Parity
    • Flow control
  • port_retry_delay: how long to wait before reopening after a failed open or port error.
  • map: Map of unit ids and their corresponding callback handlers.
  • level: Initial decoding level for the port which can be adjusted later via the returned Channel.
tip

The task handling the port is tolerant to the hardware device being added and removed from the system as might occur with USB to serial adapters.

let handler =
SimpleHandler::new(vec![false; 10], vec![false; 10], vec![0; 10], vec![0; 10]).wrap();

// map unit ids to a handler for processing requests
let map = ServerHandlerMap::single(UnitId::new(1), handler.clone());

let server = rodbus::server::spawn_rtu_server_task(
"/dev/ttySIM1",
rodbus::SerialSettings::default(),
default_retry_strategy(),
map,
DecodeLevel::new(
AppDecodeLevel::DataValues,
FrameDecodeLevel::Payload,
PhysDecodeLevel::Data,
),
)?;