Skip to main content

Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

A Modbus RTU client on a serial line: the gateway, the master in the specification’s words, that sends each request and waits for its reply.

Each transaction follows the Modbus over Serial Line specification. The client leaves the line silent for 3.5 characters, or 1.75 ms above 19200 baud, so the request starts a new frame; drops anything stale waiting in the port; writes the request; and reads the reply to the length the request implies, against the response timeout. The reply’s CRC, unit, and function are checked before a value is read out of it, and a refusal comes back as ClientError::Exception. A write to BROADCAST reaches every device and draws no reply, so the client waits out the turnaround delay instead. The specification reserves units 248 to 255, and a client still sends to them, since some devices answer on one.

On the kernel’s serial device every wait is real. On a simulated, paired, or scripted port nothing waits: the waits are counted in the port’s waited_micros, so a test of a meter that never answers runs at once and still says how long a real one would have taken.

§Examples

use std::sync::{Arc, Mutex};

use pamoja_hal::port::{Parity, SerialPort, Settings};
use pamoja_modbus::{Client, Server};

// A power meter at unit 17, simulated on the far end of a 19200 8E1 line.
let meter = Server::new(17)?.with_holding_registers(107, &[2301, 418, 0]);
let meter = Arc::new(Mutex::new(meter));
let line = Settings::new(19_200).with_parity(Parity::Even);
let mut client = Client::new(SerialPort::simulated(line, Arc::clone(&meter)));

assert_eq!(client.read_holding_registers(17, 107, 3)?, [2301, 418, 0]);
client.write_single_register(17, 109, 1)?;
assert_eq!(meter.lock().unwrap().holding_register(109), Some(1));

Implementations§

Source§

impl Client

Source

pub fn new(port: SerialPort) -> Client

Makes a client on a port, with a one-second response timeout and a 100 ms turnaround.

§Arguments
  • port - the line, opened at the speed and format the devices on it use.
§Returns

The client.

Source

pub fn with_response_timeout(self, timeout: Duration) -> Client

Sets how long the client waits for a whole reply once a request has gone out.

§Arguments
  • timeout - the response timeout; a slow device or a slow line needs more.
§Returns

The client.

Source

pub fn with_turnaround(self, delay: Duration) -> Client

Sets how long the client leaves the line quiet after a broadcast.

§Arguments
  • delay - the turnaround delay, long enough for the slowest device to carry out the write.
§Returns

The client.

Source

pub fn set_response_timeout(&mut self, timeout: Duration)

Changes how long the client waits for a whole reply, as with_response_timeout does when the client is made.

§Arguments
  • timeout - the response timeout.
Source

pub fn set_turnaround(&mut self, delay: Duration)

Changes how long the client leaves the line quiet after a broadcast, as with_turnaround does when the client is made.

§Arguments
  • delay - the turnaround delay.
Source

pub fn port(&self) -> &SerialPort

Returns the port the client runs on.

Source

pub fn response_timeout(&self) -> Duration

Returns how long the client waits for a reply.

Source

pub fn turnaround(&self) -> Duration

Returns how long the client leaves the line quiet after a broadcast.

Source

pub fn frame_gap(settings: Settings) -> Duration

Returns the silence that separates two frames, 3.5 characters at the line’s speed and format, and a fixed 1.75 ms above 19200 baud, where the specification stops scaling it.

§Arguments
  • settings - the line’s speed and character format.
§Returns

The silence, rounded up to the nanosecond.

Source

pub fn read_coils( &mut self, unit: u8, start: u16, quantity: u16, ) -> Result<Vec<bool>, ClientError>

Reads coils, function 0x01.

§Arguments
  • unit - the device, 1 to 247.
  • start - the first coil’s address.
  • quantity - how many, 1 to 2000.
§Returns

The coils’ states, in address order.

§Errors

Any ClientError: a quantity out of range, a broadcast, a port failure, a timeout, a reply that fails its checks, or the device’s exception.

Source

pub fn read_discrete_inputs( &mut self, unit: u8, start: u16, quantity: u16, ) -> Result<Vec<bool>, ClientError>

Reads discrete inputs, function 0x02.

§Arguments
  • unit - the device, 1 to 247.
  • start - the first input’s address.
  • quantity - how many, 1 to 2000.
§Returns

The inputs’ states, in address order.

§Errors

Any ClientError, as for read_coils.

Source

pub fn read_holding_registers( &mut self, unit: u8, start: u16, quantity: u16, ) -> Result<Vec<u16>, ClientError>

Reads holding registers, function 0x03.

§Arguments
  • unit - the device, 1 to 247.
  • start - the first register’s address.
  • quantity - how many, 1 to 125.
§Returns

The registers’ values, in address order.

§Errors

Any ClientError, as for read_coils.

Source

pub fn read_input_registers( &mut self, unit: u8, start: u16, quantity: u16, ) -> Result<Vec<u16>, ClientError>

Reads input registers, function 0x04.

§Arguments
  • unit - the device, 1 to 247.
  • start - the first register’s address.
  • quantity - how many, 1 to 125.
§Returns

The registers’ values, in address order.

§Errors

Any ClientError, as for read_coils.

Source

pub fn write_single_coil( &mut self, unit: u8, address: u16, on: bool, ) -> Result<(), ClientError>

Writes one coil, function 0x05.

§Arguments
  • unit - the device, 1 to 247, or BROADCAST for every device.
  • address - the coil’s address.
  • on - the state to write.
§Errors

Any ClientError but BroadcastRead.

Source

pub fn write_single_register( &mut self, unit: u8, address: u16, value: u16, ) -> Result<(), ClientError>

Writes one holding register, function 0x06.

§Arguments
  • unit - the device, 1 to 247, or BROADCAST for every device.
  • address - the register’s address.
  • value - the value to write.
§Errors

Any ClientError but BroadcastRead.

Source

pub fn write_multiple_coils( &mut self, unit: u8, start: u16, values: &[bool], ) -> Result<(), ClientError>

Writes a run of coils, function 0x0F.

§Arguments
  • unit - the device, 1 to 247, or BROADCAST for every device.
  • start - the first coil’s address.
  • values - the states to write, 1 to 1968 of them, in address order.
§Errors

Any ClientError but BroadcastRead.

Source

pub fn write_multiple_registers( &mut self, unit: u8, start: u16, values: &[u16], ) -> Result<(), ClientError>

Writes a run of holding registers, function 0x10.

§Arguments
  • unit - the device, 1 to 247, or BROADCAST for every device.
  • start - the first register’s address.
  • values - the values to write, 1 to 123 of them, in address order.
§Errors

Any ClientError but BroadcastRead.

Trait Implementations§

Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.