Skip to main content

Crate pamoja_modbus

Crate pamoja_modbus 

Source
Expand description

Modbus RTU for the pamoja SDK: the frames, a server, and a client on a serial line.

Modbus is the lingua franca of cheap industrial sensing. Soil NPK probes, energy meters, water-quality transmitters, and pump controllers overwhelmingly speak Modbus over RS485, a serial bus that reaches hundreds of meters down a single cable, which is exactly what a dispersed farm or a rural water network needs. To talk to those devices a node has to put the right bytes on the wire and trust the bytes it gets back, and Modbus RTU pins down precisely what those bytes are.

The byte layer needs no serial port and no allocation:

  • crc16 - the CRC-16/MODBUS that every RTU frame ends with, the check that lets a receiver reject a frame mangled by electrical noise on a long cable.
  • Pdu - the protocol data unit: a function code and its data. Constructors build the standard requests (read and write coils and registers), the replies a device sends to each, and the exception it sends instead, so callers never hand-pack a frame, with a raw escape hatch for the function codes this crate does not name.
  • Adu - the RTU application data unit: a unit address, a PDU, and the CRC. It both assembles a frame to send and parses one received, verifying the CRC so a corrupt frame never reaches the application.
  • Response - reads the values back out of a reply: the 16-bit registers of a read-registers response and the packed bits of a read-coils response, plus the Exception a device returns when it refuses a request.
  • Request - reads a request the way a device does, checked against the quantity and value limits the specification sets.

With the alloc feature, Server is a device: a unit address and the four tables it serves, answering each frame with the reply or the exception the specification gives, and staying silent where the serial line specification says a device does.

With the port feature, which needs an operating system, Client runs transactions over a [pamoja_hal::port::SerialPort]: it leaves the line silent for 3.5 characters before each request, reads the reply to the length the request implies against a response timeout, and checks the reply’s CRC, unit, and function before a value is read out of it. A server answers on a simulated port, and a Line carries several, so a polling loop runs end to end with nothing plugged in.

§Examples

use pamoja_modbus::{Adu, Exception, Function, Pdu, Request};

// An energy meter at unit 17 keeps its voltage in tenths of a volt, its current in
// milliamps, and a fault word in the three holding registers from 107.
let request = Pdu::read_holding_registers(107, 3).to_adu(17);

// The meter reads the request the way the specification says a device does.
let asked = Request::parse(request.pdu()).expect("a request the meter can serve");
assert_eq!(asked.span(), (107, 3));

// Its reply carries the unit and a CRC, and a receiver checks both before it reads a
// value, so a frame mangled on a long cable never reaches the application.
let reply = Pdu::read_holding_registers_reply(&[2301, 418, 0])?.to_adu(17);
let received = Adu::parse(reply.as_bytes())?;
let registers: Vec<u16> = received.response().registers()?.collect();
assert_eq!(registers, [2301, 418, 0]);
assert_eq!(f64::from(registers[0]) / 10.0, 230.1);

// Asked for a register it does not have, the meter answers with an exception instead.
let function = Function::ReadHoldingRegisters.code();
let refused = Pdu::exception(function, Exception::IllegalDataAddress).to_adu(17);
let answer = Adu::parse(refused.as_bytes())?;
assert_eq!(answer.exception(), Some(Exception::IllegalDataAddress));

Structs§

Adu
A Modbus RTU frame: a unit address, a PDU, and a trailing CRC.
Client
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.
Coils
An iterator over the bits of a read-coils or read-discrete-inputs response, or of a write-multiple-coils request.
Line
Several servers on one simulated line, as devices share an RS485 pair: every frame reaches all of them, the one it is addressed to answers, and each carries out a broadcast write.
Pdu
A Modbus protocol data unit: a function code followed by its data.
Registers
An iterator over the 16-bit registers of a read-registers response, or of a write-multiple-registers request.
Response
A borrowed view over a response PDU, for reading the values a device returned.
Server
A Modbus device: a unit address and the four tables it serves, coils, discrete inputs, holding registers, and input registers, each holding only the addresses it was given.

Enums§

ClientError
Why a transaction failed.
Exception
A Modbus exception code: the reason a device gives for refusing a request.
Function
A Modbus function code, naming the operation a request asks for.
ModbusError
What can go wrong building or reading a Modbus RTU frame.
Request
A request as a device reads it, checked against the limits the specification sets.

Constants§

BROADCAST
The unit address every server acts on and none answers.
RESPONSE_TIMEOUT
How long a client waits for a reply unless told otherwise: one second, the low end of what the serial line specification suggests at 9600 baud.
TURNAROUND
How long a client leaves the line quiet after a broadcast unless told otherwise, so every device has carried it out before the next request: 100 milliseconds, the low end of the range the serial line specification gives.
UNITS
The lowest and highest address a server may have; 248 to 255 are reserved.

Functions§

crc16
Computes the CRC-16/MODBUS of a byte slice.