moonbit-modbus

A portable Modbus RTU, ASCII, and TCP protocol stack with device simulation and gateway primitives for MoonBit.

modbus
industrial
protocol
rtu
ascii
tcp
plc
moon add qyt1234567/moonbit-modbus@0.2.0
Download zip
Version
0.2.0
License
Apache-2.0
Last updated
2 hours ago
Downloads
2
README

#moonbit-modbus

moonbit-modbus 是一个面向工业设备接入的 MoonBit Modbus 协议栈。它把 PDU、RTU、ASCII 和 TCP MBAP 统一到同一套类型安全 API,并提供设备内存、客户端事务、轮询、网关和虚拟链路等可组合模块,适合 PLC、变频器、仪表、数据采集器和协议测试工具。

#核心能力

  • 协议编解码:Modbus RTU、ASCII、TCP,CRC16、LRC、MBAP 事务标识和异常响应。
  • 功能码覆盖:线圈、离散输入、保持寄存器、输入寄存器的读写,以及掩码写、读写组合、诊断、事件计数器、文件记录、设备识别和 FIFO。
  • 流式处理:有界增量解析器支持分段输入、多帧输入和坏帧恢复,避免无界缓存。
  • 设备与内存:寄存器/线圈 bank、地址空间、schema、文件记录存储、设备状态和异常统计。
  • 集成组件:客户端重试与超时、请求规划、轮询计划、批处理、网关映射、服务器池和虚拟传输链路。
  • 工程质量:无第三方运行时依赖,支持 native、wasm 和 wasm-gc 目标;公共接口生成 .mbti 文件并由 CI 校验。

#快速开始

需要已安装 MoonBit stable 工具链。仓库根目录执行:

moon update moon check --target all --deny-warn moon test --target all --deny-warn moon run cmd/main

最小 API 示例:

///|
let request = @moonbit-modbus.read_holding(1, 0, 4)

///|
let rtu_bytes = @moonbit-modbus.encode_rtu(request)

///|
let parsed = @moonbit-modbus.decode_rtu(rtu_bytes)

增量解析示例:

///|
let parser = @moonbit-modbus.IncrementalParser::new(@moonbit-modbus.rtu_mode())

///|
let frames = parser.feed(rtu_bytes)

#CLI

仓库包含两个可直接运行的示例程序:

# 展示请求编码、虚拟设备处理和响应格式化 moon run --target native cmd/main # 运行 1000 次 CRC、RTU、TCP 和设备读工作负载 moon run --target native cmd/bench

cmd/bench 输出确定性的迭代次数、成功数、失败数和处理字节数;独立的端到端命令耗时记录在 BENCHMARK.md

#架构

代码按协议边界拆分为几个层次:

  1. types.mbtvalidation.mbtlimits.mbt 定义公共类型、功能码、异常码和边界规则。
  2. codec.mbtchecksum.mbtparser.mbtframe_text.mbt 负责 PDU/ADU 编解码、校验和流式解析。
  3. functions.mbtresponses.mbtcoils.mbtregister_codec.mbtfile_records.mbt 提供功能码与数据表示。
  4. banks.mbtdevice.mbtregister_schema.mbtaddress_space.mbt 组成可测试的设备内存层。
  5. client.mbttransport.mbtpolling.mbtgateway.mbtserver_pool.mbtsimulation.mbt 提供系统集成能力。
  6. conformance.mbtpreflight.mbtquality.mbtmetrics.mbtbenchmark_core.mbt 提供一致性检查、运行指标和可复现基准。

核心层只依赖 MoonBit 标准能力;真实串口和 TCP socket 可在上层适配,而不改变协议模型和测试夹具。

#基准

基准使用 native 目标和固定的 1000 次迭代,覆盖 CRC16、RTU 编解码往返、TCP 编解码往返和设备读路径。结果分为确定性工作量统计与主机端到端耗时两部分,避免把不同机器的时钟结果伪装成协议吞吐率。复现实验方法和原始测量值见 BENCHMARK.md

#测试

测试覆盖正常路径和边界路径,包括:

  • 地址、单位号、数量、PDU/ADU 长度、字节计数和广播请求边界;
  • CRC/LRC、ASCII/TCP/RTU 错帧、分段输入、多帧输入和截断输入;
  • 线圈 bit packing、寄存器字节序、32/64 位数值、游标越界和写入器容量;
  • 设备读写、异常响应、busy 状态、文件记录、设备识别、客户端事务和网关映射;
  • schema、轮询、批处理、预检、指标、虚拟传输和文本帧工具。

本地质量门槛:

moon fmt --check moon info moon check --target all --deny-warn moon test --target all --deny-warn

#CI

.github/workflows/check.yml 在 Ubuntu、macOS 和 Windows 上安装 MoonBit stable,执行 moon update、格式检查、全目标检查、构建、测试、CLI smoke test 和 .mbti 清洁工作树校验。.github/workflows/publish.yml 仅支持手动触发,用于在配置发布凭据后执行 Mooncakes 发布流程。

#许可证

本项目采用 Apache-2.0 许可证。协议实现依据公开的 Modbus 应用协议与串行链路规范重新实现,源码和测试夹具均保留在本仓库中。

#
AddressAllocator

pub struct AddressAllocator {
capacity : Int
used : Array[AddressRange]
}

A first-fit allocator for contiguous register or coil ranges.

#
AddressAllocator::allocate

fn AddressAllocator::allocate(self : AddressAllocator, length : Int) -> Result[AddressRange, ModbusError]

#
AddressAllocator::free_capacity

fn AddressAllocator::free_capacity(self : AddressAllocator) -> Int

#
AddressAllocator::new

fn AddressAllocator::new(capacity : Int) -> Result[AddressAllocator, ModbusError]

#
AddressAllocator::release

fn AddressAllocator::release(self : AddressAllocator, range : AddressRange) -> Result[Unit, ModbusError]

#
AddressAllocator::snapshot

#
AddressAllocator::used_capacity

fn AddressAllocator::used_capacity(self : AddressAllocator) -> Int

#
AddressAllocator::used_count

fn AddressAllocator::used_count(self : AddressAllocator) -> Int

#
AddressRange

pub(all) struct AddressRange {
start : UInt16
length : Int
}

A half-open address range in the Modbus 16-bit address space.

#
AddressRange::contains

fn AddressRange::contains(self : AddressRange, address : UInt16) -> Bool

#
AddressRange::contains_range

fn AddressRange::contains_range(self : AddressRange, other : AddressRange) -> Bool

#
AddressRange::end_exclusive

fn AddressRange::end_exclusive(self : AddressRange) -> Int

#
AddressRange::length

fn AddressRange::length(self : AddressRange) -> Int

#
AddressRange::new

fn AddressRange::new(start : UInt16, length : Int) -> Result[AddressRange, ModbusError]

#
AddressRange::offset

fn AddressRange::offset(self : AddressRange, address : UInt16) -> Result[Int, ModbusError]

#
AddressRange::overlaps

fn AddressRange::overlaps(self : AddressRange, other : AddressRange) -> Bool

#
AddressRange::slice

fn AddressRange::slice(self : AddressRange, offset : Int, length : Int) -> Result[AddressRange, ModbusError]

#
AddressRange::split

fn AddressRange::split(self : AddressRange, segment_length : Int) -> Result[Array[AddressRange], ModbusError]

Split a range into non-overlapping segments of at most segment_length.

#
AddressRange::start

fn AddressRange::start(self : AddressRange) -> UInt16

#
AlarmMonitor

pub(all) struct AlarmMonitor {
threshold : Threshold
state : ThresholdState
transitions : Int
last_value : Int?
}

Stateful threshold monitor that counts state transitions.

#
AlarmMonitor::last_value

fn AlarmMonitor::last_value(self : AlarmMonitor) -> Int?

#
AlarmMonitor::new

fn AlarmMonitor::new(threshold : Threshold) -> AlarmMonitor

#
AlarmMonitor::observe

fn AlarmMonitor::observe(self : AlarmMonitor, value : Int) -> ThresholdState

#
AlarmMonitor::reset

fn AlarmMonitor::reset(self : AlarmMonitor) -> Unit

#
AlarmMonitor::state

#
AlarmMonitor::threshold

fn AlarmMonitor::threshold(self : AlarmMonitor) -> Threshold

#
AlarmMonitor::transitions

fn AlarmMonitor::transitions(self : AlarmMonitor) -> Int

#
AuditEntry

pub(all) struct AuditEntry {
sequence : Int
direction : String
mode : Mode
transaction_id : UInt16
summary : FrameSummary
outcome : String
}

A trace record suitable for debugging a gateway or device exchange.

#
AuditLog

pub struct AuditLog {
entries : Array[AuditEntry]
max_entries : Int
next_sequence : Int
}

#
AuditLog::clear

fn AuditLog::clear(self : AuditLog) -> Unit

#
AuditLog::length

fn AuditLog::length(self : AuditLog) -> Int

#
AuditLog::new

fn AuditLog::new(max_entries? : Int) -> Result[AuditLog, ModbusError]

#
AuditLog::record

fn AuditLog::record(self : AuditLog, direction : String, mode : Mode, transaction_id : UInt16, frame : Frame, outcome : String) -> Unit

#
AuditLog::snapshot

fn AuditLog::snapshot(self : AuditLog) -> Array[AuditEntry]

#
BatchItem

pub(all) struct BatchItem {
id : Int
request : Frame
}

A named request in a batch operation.

#
BatchItem::new

fn BatchItem::new(id : Int, request : Frame) -> Result[BatchItem, ModbusError]

#
BatchPlan

pub struct BatchPlan {
items : Array[BatchItem]
max_items : Int
}

An ordered batch plan used to pipeline independent requests.

#
BatchPlan::add

fn BatchPlan::add(self : BatchPlan, item : BatchItem) -> Result[Unit, ModbusError]

#
BatchPlan::execute

fn BatchPlan::execute(self : BatchPlan, device : Device) -> Array[BatchResult]

Execute an ordered plan against a deterministic device.

#
BatchPlan::item

fn BatchPlan::item(self : BatchPlan, index : Int) -> Result[BatchItem, ModbusError]

#
BatchPlan::length

fn BatchPlan::length(self : BatchPlan) -> Int

#
BatchPlan::new

fn BatchPlan::new(max_items? : Int) -> Result[BatchPlan, ModbusError]

#
BatchPlan::snapshot

fn BatchPlan::snapshot(self : BatchPlan) -> Array[BatchItem]

#
BatchResult

pub(all) enum BatchResult {
Completed(Int, Frame)
Failed(Int, ModbusError)
}

The result of executing one batch item.

#
BenchmarkResult

pub(all) struct BenchmarkResult {
name : String
iterations : Int
successful : Int
failed : Int
bytes : Int
}

Deterministic benchmark counters emitted by the command-line benchmark.

#
BenchmarkResult::operations

fn BenchmarkResult::operations(self : BenchmarkResult) -> Int

#
BenchmarkResult::success_rate

fn BenchmarkResult::success_rate(self : BenchmarkResult) -> Float

#
BenchmarkResult::summary

fn BenchmarkResult::summary(self : BenchmarkResult) -> String

#
BitVector

pub(all) struct BitVector {
length : Int
storage : Array[Byte]
}

A mutable bounded bit vector for coils and discrete inputs.

#
BitVector::bit_and

fn BitVector::bit_and(self : BitVector, other : BitVector) -> Result[BitVector, ModbusError]

Apply a bitwise AND to two equally sized vectors.

#
BitVector::byte_length

fn BitVector::byte_length(self : BitVector) -> Int

#
BitVector::copy

fn BitVector::copy(self : BitVector) -> BitVector

Copy a bit vector and keep its logical length.

#
BitVector::count

fn BitVector::count(self : BitVector) -> Int

#
BitVector::equal

fn BitVector::equal(self : BitVector, other : BitVector) -> Bool

Compare two bit vectors including their logical lengths.

#
BitVector::fill

fn BitVector::fill(self : BitVector, value : Bool) -> Unit

#
BitVector::from_bits

fn BitVector::from_bits(values : Array[Bool]) -> BitVector

#
BitVector::get

fn BitVector::get(self : BitVector, index : Int) -> Result[Bool, ModbusError]

#
BitVector::length

fn BitVector::length(self : BitVector) -> Int

#
BitVector::new

fn BitVector::new(length : Int) -> Result[BitVector, ModbusError]

Create a zero-filled bit vector.

#
BitVector::not

fn BitVector::not(self : BitVector) -> BitVector

Invert all logical bits, keeping padding bits clear.

#
BitVector::or

fn BitVector::or(self : BitVector, other : BitVector) -> Result[BitVector, ModbusError]

Apply a bitwise OR to two equally sized vectors.

#
BitVector::pack_range

fn BitVector::pack_range(self : BitVector, start : Int, quantity : Int) -> Result[Array[Byte], ModbusError]

Pack a range of bits from a vector for a Modbus response.

#
BitVector::set

fn BitVector::set(self : BitVector, index : Int, value : Bool) -> Result[Unit, ModbusError]

#
BitVector::shift_left

fn BitVector::shift_left(self : BitVector, distance : Int) -> Result[BitVector, ModbusError]

Shift logical bits left, dropping values that fall outside the vector.

#
BitVector::shift_right

fn BitVector::shift_right(self : BitVector, distance : Int) -> Result[BitVector, ModbusError]

Shift logical bits right, dropping values that fall outside the vector.

#
BitVector::to_bits

fn BitVector::to_bits(self : BitVector) -> Array[Bool]

#
BitVector::to_bytes

fn BitVector::to_bytes(self : BitVector) -> Array[Byte]

#
BitVector::unpack_into

fn BitVector::unpack_into(self : BitVector, start : Int, quantity : Int, bytes : Array[Byte]) -> Result[Unit, ModbusError]

Replace a range of bits from packed input bytes.

#
ByteQueue

pub struct ByteQueue {
data : Array[Byte]
max_length : Int
}

A bounded byte queue for adapters that receive arbitrary chunk sizes.

#
ByteQueue::clear

fn ByteQueue::clear(self : ByteQueue) -> Unit

#
ByteQueue::contains_sequence

fn ByteQueue::contains_sequence(self : ByteQueue, pattern : Array[Byte]) -> Bool

#
ByteQueue::find

fn ByteQueue::find(self : ByteQueue, value : Byte) -> Int?

#
ByteQueue::is_empty

fn ByteQueue::is_empty(self : ByteQueue) -> Bool

#
ByteQueue::length

fn ByteQueue::length(self : ByteQueue) -> Int

#
ByteQueue::new

fn ByteQueue::new(max_length? : Int) -> Result[ByteQueue, ModbusError]

#
ByteQueue::peek

fn ByteQueue::peek(self : ByteQueue, index : Int) -> Result[Byte, ModbusError]

#
ByteQueue::push

fn ByteQueue::push(self : ByteQueue, bytes : Array[Byte]) -> Result[Unit, ModbusError]

#
ByteQueue::push_byte

fn ByteQueue::push_byte(self : ByteQueue, byte : Byte) -> Result[Unit, ModbusError]

#
ByteQueue::remaining

fn ByteQueue::remaining(self : ByteQueue) -> Int

#
ByteQueue::snapshot

fn ByteQueue::snapshot(self : ByteQueue) -> Array[Byte]

#
ByteQueue::take

fn ByteQueue::take(self : ByteQueue, count : Int) -> Result[Array[Byte], ModbusError]

#
ByteQueue::take_all

fn ByteQueue::take_all(self : ByteQueue) -> Array[Byte]

#
Client

pub struct Client {
mode : Mode
config : ClientConfig
next_transaction : UInt16
pending : Array[PendingExchange]
}

A stateful protocol client that does not assume a particular socket runtime.

#
Client::accept

fn Client::accept(self : Client, request : ClientRequest, bytes : Array[Byte]) -> Result[Frame, ModbusError]

Accept bytes from the transport and correlate them with a pending request.

#
Client::accept_frame

fn Client::accept_frame(self : Client, request : ClientRequest, transaction_id : UInt16, response : Frame) -> Result[Frame, ModbusError]

Accept an already decoded response frame.

#
Client::allocate_transaction

fn Client::allocate_transaction(self : Client) -> UInt16

Allocate a non-zero transaction id for TCP and a stable zero id for serial modes.

#
Client::attempts

fn Client::attempts(self : Client, transaction_id : UInt16) -> Int

Return a request's retry count, or zero when it is not tracked.

#
Client::begin

fn Client::begin(self : Client, frame : Frame) -> Result[ClientRequest, ModbusError]

Begin an exchange at logical tick zero.

#
Client::begin_at

fn Client::begin_at(self : Client, frame : Frame, now : Int) -> Result[ClientRequest, ModbusError]

Begin an exchange at a caller-supplied logical tick.

#
Client::cancel

fn Client::cancel(self : Client, transaction_id : UInt16) -> Result[Unit, ModbusError]

#
Client::completed_count

fn Client::completed_count(self : Client) -> Int

#
Client::config

fn Client::config(self : Client) -> ClientConfig

#
Client::expire

fn Client::expire(self : Client, now : Int) -> Array[UInt16]

Mark all timed-out exchanges as failed and return their transaction ids.

#
Client::failed_count

fn Client::failed_count(self : Client) -> Int

#
Client::mode

fn Client::mode(self : Client) -> Mode

#
Client::new

fn Client::new(mode : Mode, config? : ClientConfig) -> Client

#
Client::next_transaction

fn Client::next_transaction(self : Client) -> UInt16

#
Client::pending_active

fn Client::pending_active(self : Client) -> Int

#
Client::pending_request

fn Client::pending_request(self : Client, transaction_id : UInt16) -> PendingExchange?

Find a pending request by transaction id.

#
Client::pending_snapshot

fn Client::pending_snapshot(self : Client) -> Array[PendingExchange]

Return a copy of all pending records for an external scheduler.

#
Client::retry_due

fn Client::retry_due(self : Client, now : Int) -> Array[UInt16]

Return pending exchanges that can be retried at a logical tick.

#
ClientConfig

pub(all) struct ClientConfig {
timeout_ticks : Int
retries : Int
max_pending : Int
strict_unit : Bool
}

Client retry and framing policy.

#
ClientRequest

pub(all) struct ClientRequest {
transaction_id : UInt16
frame : Frame
bytes : Array[Byte]
}

A request prepared for a transport adapter.

#
ClientRequest::encoded_length

fn ClientRequest::encoded_length(self : ClientRequest) -> Int

#
ClientResult

pub(all) enum ClientResult {
Success(Frame)
Exception(ExceptionCode)
}

A decoded client result with a typed success/exception branch.

#
CoilBank

pub(all) struct CoilBank {
start : UInt16
bits : BitVector
writable : Bool
}

A bounded coil/discrete-input bank backed by a bit vector.

#
CoilBank::clear

fn CoilBank::clear(self : CoilBank) -> Unit

#
CoilBank::contains

fn CoilBank::contains(self : CoilBank, address : UInt16, quantity : Int) -> Bool

#
CoilBank::fill

fn CoilBank::fill(self : CoilBank, value : Bool) -> Unit

#
CoilBank::get

fn CoilBank::get(self : CoilBank, address : UInt16) -> Result[Bool, ModbusError]

#
CoilBank::is_writable

fn CoilBank::is_writable(self : CoilBank) -> Bool

#
CoilBank::length

fn CoilBank::length(self : CoilBank) -> Int

#
CoilBank::new

fn CoilBank::new(start : UInt16, length : Int, writable? : Bool) -> Result[CoilBank, ModbusError]

#
CoilBank::read

fn CoilBank::read(self : CoilBank, address : UInt16, quantity : Int) -> Result[Array[Bool], ModbusError]

#
CoilBank::set

fn CoilBank::set(self : CoilBank, address : UInt16, value : Bool) -> Result[Unit, ModbusError]

#
CoilBank::snapshot

fn CoilBank::snapshot(self : CoilBank) -> Array[Bool]

#
CoilBank::snapshot_bytes

fn CoilBank::snapshot_bytes(self : CoilBank) -> Array[Byte]

#
CoilBank::start

fn CoilBank::start(self : CoilBank) -> UInt16

#
CoilBank::write

fn CoilBank::write(self : CoilBank, address : UInt16, values : Array[Bool]) -> Result[Unit, ModbusError]

#
ConformanceResult

pub(all) struct ConformanceResult {
name : String
passed : Bool
detail : String
}

A vector execution result.

#
ConformanceSuite

pub struct ConformanceSuite {
vectors : Array[ConformanceVector]
}

A reusable conformance suite.

#
ConformanceSuite::add

fn ConformanceSuite::add(self : ConformanceSuite, vector : ConformanceVector) -> Unit

#
ConformanceSuite::length

fn ConformanceSuite::length(self : ConformanceSuite) -> Int

#
ConformanceSuite::new

#
ConformanceSuite::run

#
ConformanceVector

pub(all) struct ConformanceVector {
name : String
mode : Mode
bytes : Array[Byte]
expected_function : Byte?
expected_error : ModbusError?
}

A portable conformance vector for transport and frame decoders.

#
ConformanceVector::invalid

fn ConformanceVector::invalid(name : String, mode : Mode, bytes : Array[Byte], expected_error : ModbusError) -> ConformanceVector

#
ConformanceVector::valid

fn ConformanceVector::valid(name : String, mode : Mode, bytes : Array[Byte], expected_function : Byte) -> ConformanceVector

#
Counter

pub(all) struct Counter {
name : String
value : Int
}

A small integer counter used for protocol telemetry.

#
Counter::add

fn Counter::add(self : Counter, amount : Int) -> Result[Unit, ModbusError]

#
Counter::inc

fn Counter::inc(self : Counter) -> Unit

#
Counter::name

fn Counter::name(self : Counter) -> String

#
Counter::new

fn Counter::new(name : String) -> Counter

#
Counter::reset

fn Counter::reset(self : Counter) -> Unit

#
Counter::value

fn Counter::value(self : Counter) -> Int

#
Crc16State

pub(all) struct Crc16State {
value : UInt16
}

Incremental CRC16 accumulator for serial readers.

#
Crc16State::finalize

fn Crc16State::finalize(self : Crc16State) -> UInt16

#
Crc16State::finalize_bytes

fn Crc16State::finalize_bytes(self : Crc16State) -> Array[Byte]

#
Crc16State::new

fn Crc16State::new() -> Crc16State

#
Crc16State::update

fn Crc16State::update(self : Crc16State, bytes : Array[Byte]) -> Unit

#
Crc16State::update_byte

fn Crc16State::update_byte(self : Crc16State, byte : Byte) -> Unit

#
Device

pub struct Device {
unit_id : Byte
memory : DeviceMemory
file_store : FileRecordStore
server_id : Array[Byte]
event_count : UInt16
busy : Bool
exception_count : Int
}

A protocol-level Modbus device backed by four bounded data tables.

#
Device::event_count

fn Device::event_count(self : Device) -> UInt16

#
Device::exception_count

fn Device::exception_count(self : Device) -> Int

#
Device::file_store

fn Device::file_store(self : Device) -> FileRecordStore

#
Device::handle

fn Device::handle(self : Device, request : Frame) -> Result[Frame, ModbusError]

Handle a request and return a normal or exception response.

#
Device::health

fn Device::health(self : Device) -> DeviceHealth

#
Device::is_busy

fn Device::is_busy(self : Device) -> Bool

#
Device::memory

fn Device::memory(self : Device) -> DeviceMemory

#
Device::new

fn Device::new(unit_id : Byte, coil_capacity? : Int, register_capacity? : Int) -> Result[Device, ModbusError]

Create a device with configurable table capacities.

#
Device::serve

fn Device::serve(self : Device, request : Frame) -> Result[DeviceResponse, ModbusError]

Handle a request while making broadcast no-response semantics explicit.

#
Device::server_id

fn Device::server_id(self : Device) -> Array[Byte]

#
Device::set_busy

fn Device::set_busy(self : Device, busy : Bool) -> Unit

#
Device::set_server_id

fn Device::set_server_id(self : Device, values : Array[Byte]) -> Result[Unit, ModbusError]

#
Device::unit_id

fn Device::unit_id(self : Device) -> Byte

#
DeviceHealth

pub(all) struct DeviceHealth {
unit_id : Byte
event_count : UInt16
exception_count : Int
busy : Bool
}

A compact device health snapshot for dashboards and polling logs.

#
DeviceIdCategory

pub(all) enum DeviceIdCategory {
Basic
Regular
Extended
Individual(Byte)
} derive(Eq,
Debug
)

Device-identification access category used by MEI type 0x0E.

#
DeviceIdCategory::to_byte

fn DeviceIdCategory::to_byte(category : DeviceIdCategory) -> Byte

#
DeviceIdObject

pub(all) struct DeviceIdObject {
object_id : Byte
value : String
}

One TLV object returned by a device-identification response.

#
DeviceIdObject::new

fn DeviceIdObject::new(object_id : Byte, value : String) -> Result[DeviceIdObject, ModbusError]

#
DeviceIdentification

pub(all) struct DeviceIdentification {
category : DeviceIdCategory
conformity : Byte
more_follows : Bool
next_object_id : Byte
objects : Array[DeviceIdObject]
}

Parsed MEI device-identification response metadata.

#
DeviceIdentityCatalog

pub struct DeviceIdentityCatalog {
category : DeviceIdCategory
objects : Array[DeviceIdObject]
conformity : Byte
}

A reusable identity catalogue for virtual devices.

#
DeviceIdentityCatalog::add

fn DeviceIdentityCatalog::add(self : DeviceIdentityCatalog, object : DeviceIdObject) -> Result[Unit, ModbusError]

#
DeviceIdentityCatalog::length

#
DeviceIdentityCatalog::new

#
DeviceIdentityCatalog::objects

#
DeviceIdentityCatalog::response

fn DeviceIdentityCatalog::response(self : DeviceIdentityCatalog, request : Frame) -> Result[Frame, ModbusError]

#
DeviceIdentityCatalog::set_conformity

fn DeviceIdentityCatalog::set_conformity(self : DeviceIdentityCatalog, conformity : Byte) -> Unit

#
DeviceMemory

pub(all) struct DeviceMemory {
coils : CoilBank
discrete_inputs : CoilBank
input_registers : RegisterBank
holding_registers : RegisterBank
}

The four standard Modbus data tables exposed by a device.

#
DeviceMemory::clear

fn DeviceMemory::clear(self : DeviceMemory) -> Unit

#
DeviceMemory::coils

fn DeviceMemory::coils(self : DeviceMemory) -> CoilBank

#
DeviceMemory::discrete_inputs

fn DeviceMemory::discrete_inputs(self : DeviceMemory) -> CoilBank

#
DeviceMemory::holding_registers

fn DeviceMemory::holding_registers(self : DeviceMemory) -> RegisterBank

#
DeviceMemory::input_registers

fn DeviceMemory::input_registers(self : DeviceMemory) -> RegisterBank

#
DeviceMemory::load_discrete

fn DeviceMemory::load_discrete(self : DeviceMemory, address : UInt16, values : Array[Bool]) -> Result[Unit, ModbusError]

#
DeviceMemory::load_holding

fn DeviceMemory::load_holding(self : DeviceMemory, address : UInt16, values : Array[UInt16]) -> Result[Unit, ModbusError]

#
DeviceMemory::load_input

fn DeviceMemory::load_input(self : DeviceMemory, address : UInt16, values : Array[UInt16]) -> Result[Unit, ModbusError]

#
DeviceMemory::new

fn DeviceMemory::new(coil_capacity? : Int, register_capacity? : Int) -> Result[DeviceMemory, ModbusError]

Create a device memory map with all tables starting at address zero.

#
DeviceResponse

pub(all) enum DeviceResponse {
Reply(Frame)
NoReply
}

A response returned by a virtual or embedded device service.

#
EncodedAdu

pub(all) struct EncodedAdu {
mode : Mode
transaction_id : UInt16
bytes : Array[Byte]
}

An encoded ADU that can be handed to a socket or serial adapter.

#
EncodedAdu::bytes

fn EncodedAdu::bytes(self : EncodedAdu) -> Array[Byte]

#
EncodedAdu::decode

fn EncodedAdu::decode(self : EncodedAdu) -> Result[Frame, ModbusError]

#
EncodedAdu::mode

fn EncodedAdu::mode(self : EncodedAdu) -> Mode

#
EncodedAdu::new

fn EncodedAdu::new(mode : Mode, transaction_id : UInt16, frame : Frame) -> Result[EncodedAdu, ModbusError]

#
EncodedAdu::transaction_id

fn EncodedAdu::transaction_id(self : EncodedAdu) -> UInt16

#
EndpointConfig

pub(all) enum EndpointConfig {
Serial(SerialConfig)
Tcp(TcpConfig)
}

A transport endpoint configuration.

#
EndpointConfig::mode

fn EndpointConfig::mode(config : EndpointConfig) -> Mode

#
EndpointConfig::name

fn EndpointConfig::name(config : EndpointConfig) -> String

#
EndpointHealth

pub(all) struct EndpointHealth {
unit_id : Byte
ready : Bool
event_count : UInt16
exceptions : Int
requests : Int
responses : Int
errors : Int
}

Aggregated endpoint health used by operations dashboards.

#
EndpointRuntime

pub(all) struct EndpointRuntime {
config : EndpointConfig
state : EndpointState
opened_at : Int
last_error : ModbusError?
reconnects : Int
frames_in : Int
frames_out : Int
}

Runtime state tracked independently from operating-system handles.

#
EndpointRuntime::backoff

fn EndpointRuntime::backoff(self : EndpointRuntime) -> Unit

#
EndpointRuntime::close

fn EndpointRuntime::close(self : EndpointRuntime) -> Unit

#
EndpointRuntime::config

#
EndpointRuntime::fail

fn EndpointRuntime::fail(self : EndpointRuntime, error : ModbusError) -> Unit

#
EndpointRuntime::frames_in

fn EndpointRuntime::frames_in(self : EndpointRuntime) -> Int

#
EndpointRuntime::frames_out

fn EndpointRuntime::frames_out(self : EndpointRuntime) -> Int

#
EndpointRuntime::last_error

fn EndpointRuntime::last_error(self : EndpointRuntime) -> ModbusError?

#
EndpointRuntime::new

#
EndpointRuntime::open

fn EndpointRuntime::open(self : EndpointRuntime, now : Int) -> Result[Unit, ModbusError]

#
EndpointRuntime::reconnects

fn EndpointRuntime::reconnects(self : EndpointRuntime) -> Int

#
EndpointRuntime::record_in

fn EndpointRuntime::record_in(self : EndpointRuntime) -> Result[Unit, ModbusError]

#
EndpointRuntime::record_out

fn EndpointRuntime::record_out(self : EndpointRuntime) -> Result[Unit, ModbusError]

#
EndpointRuntime::state

#
EndpointRuntime::uptime

fn EndpointRuntime::uptime(self : EndpointRuntime, now : Int) -> Int

#
EndpointState

pub(all) enum EndpointState {
Closed
Connecting
Ready
Backoff
Faulted
} derive(Eq,
Debug
)

Lifecycle state of a transport endpoint.

#
ExceptionCode

pub(all) enum ExceptionCode {
IllegalFunction
IllegalDataAddress
IllegalDataValue
ServerDeviceFailure
Acknowledge
ServerDeviceBusy
NegativeAcknowledge
MemoryParityError
GatewayPathUnavailable
GatewayTargetFailedToRespond
UnknownException(Byte)
} derive(Eq,
Debug
)

Standard exception codes returned by a Modbus server.

#
ExceptionCode::to_byte

fn ExceptionCode::to_byte(code : ExceptionCode) -> Byte

#
ExchangeEnvelope

pub(all) struct ExchangeEnvelope {
source : String
destination : String
adu : EncodedAdu
}

A transport-neutral request envelope.

#
ExchangeEnvelope::new

fn ExchangeEnvelope::new(source : String, destination : String, adu : EncodedAdu) -> ExchangeEnvelope

#
ExchangeEnvelope::size

fn ExchangeEnvelope::size(self : ExchangeEnvelope) -> Int

#
ExchangeState

pub(all) enum ExchangeState {
Pending
Completed
Failed
Cancelled
} derive(Eq,
Debug
)

Lifecycle of a client-side exchange.

#
FaultMode

pub(all) enum FaultMode {
NoFault
DropResponse
CorruptCrc
CorruptLrc
WrongTransaction
BusyDevice
InvalidFunction
} derive(Eq,
Debug
)

Deterministic fault modes for protocol integration tests.

#
FileRecordReference

pub(all) struct FileRecordReference {
reference_type : Byte
file_number : UInt16
record_number : UInt16
record_length : UInt16
}

A Modbus file-record selector.

#
FileRecordReference::encoded_length

fn FileRecordReference::encoded_length(_self : FileRecordReference) -> Int

#
FileRecordReference::new

fn FileRecordReference::new(file_number : UInt16, record_number : UInt16, record_length : UInt16, reference_type? : Byte) -> Result[FileRecordReference, ModbusError]

#
FileRecordStore

pub(all) struct FileRecordStore {
records : Array[FileRecordWrite]
max_records : Int
}

A bounded in-memory store for file records used by simulators.

#
FileRecordStore::clear

fn FileRecordStore::clear(self : FileRecordStore) -> Unit

#
FileRecordStore::get

fn FileRecordStore::get(self : FileRecordStore, reference : FileRecordReference) -> Result[Array[UInt16], ModbusError]

#
FileRecordStore::length

fn FileRecordStore::length(self : FileRecordStore) -> Int

#
FileRecordStore::new

fn FileRecordStore::new(max_records? : Int) -> Result[FileRecordStore, ModbusError]

#
FileRecordStore::put

fn FileRecordStore::put(self : FileRecordStore, record : FileRecordWrite) -> Result[Unit, ModbusError]

#
FileRecordWrite

pub(all) struct FileRecordWrite {
reference : FileRecordReference
values : Array[UInt16]
}

A file-record write item combines a selector and its register payload.

#
FileRecordWrite::new

fn FileRecordWrite::new(reference : FileRecordReference, values : Array[UInt16]) -> Result[FileRecordWrite, ModbusError]

#
Frame

pub(all) struct Frame {
unit_id : Byte
pdu : Pdu
}

A decoded frame, including the unit identifier.

#
Frame::data_length

fn Frame::data_length(self : Frame) -> Int

#
Frame::function_code

fn Frame::function_code(self : Frame) -> FunctionCode

#
Frame::is_exception

fn Frame::is_exception(self : Frame) -> Bool

#
Frame::new

fn Frame::new(unit_id : Byte, function : Byte, data : Array[Byte]) -> Frame

#
FrameSequence

pub struct FrameSequence {
frames : Array[Frame]
max_frames : Int
}

A bounded ordered collection of frames for gateways and batch adapters.

#
FrameSequence::encoded_bytes

fn FrameSequence::encoded_bytes(self : FrameSequence, mode : Mode) -> Int

#
FrameSequence::filter_function

fn FrameSequence::filter_function(self : FrameSequence, function : Byte) -> Array[Frame]

#
FrameSequence::filter_unit

fn FrameSequence::filter_unit(self : FrameSequence, unit_id : Byte) -> Array[Frame]

#
FrameSequence::get

fn FrameSequence::get(self : FrameSequence, index : Int) -> Result[Frame, ModbusError]

#
FrameSequence::length

fn FrameSequence::length(self : FrameSequence) -> Int

#
FrameSequence::new

fn FrameSequence::new(max_frames? : Int) -> Result[FrameSequence, ModbusError]

#
FrameSequence::push

fn FrameSequence::push(self : FrameSequence, frame : Frame) -> Result[Unit, ModbusError]

#
FrameSequence::snapshot

fn FrameSequence::snapshot(self : FrameSequence) -> Array[Frame]

#
FrameSequence::validate

fn FrameSequence::validate(self : FrameSequence, allow_broadcast : Bool) -> Result[Unit, ModbusError]

#
FrameStream

pub struct FrameStream {
mode : Mode
parser : IncrementalParser
queue : ByteQueue
chunks : Int
frames : Int
}

A frame stream combines a byte queue with the protocol parser.

#
FrameStream::chunks

fn FrameStream::chunks(self : FrameStream) -> Int

#
FrameStream::finish

fn FrameStream::finish(self : FrameStream) -> Result[Frame, ModbusError]

#
FrameStream::frames

fn FrameStream::frames(self : FrameStream) -> Int

#
FrameStream::mode

fn FrameStream::mode(self : FrameStream) -> Mode

#
FrameStream::new

fn FrameStream::new(mode : Mode, role? : ParserRole, max_buffer? : Int, max_frame? : Int) -> Result[FrameStream, ModbusError]

#
FrameStream::push

fn FrameStream::push(self : FrameStream, bytes : Array[Byte]) -> Result[Array[Frame], ModbusError]

#
FrameStream::reset

fn FrameStream::reset(self : FrameStream) -> Unit

#
FrameSummary

pub(all) struct FrameSummary {
unit_id : Byte
function : Byte
data_length : Int
exception : Bool
}

A compact description useful for logs and metrics.

#
FrameTextLog

pub struct FrameTextLog {
entries : Array[String]
max_entries : Int
}

A bounded text trace used by CLI tools and embedded diagnostics.

#
FrameTextLog::clear

fn FrameTextLog::clear(self : FrameTextLog) -> Unit

#
FrameTextLog::length

fn FrameTextLog::length(self : FrameTextLog) -> Int

#
FrameTextLog::lines

fn FrameTextLog::lines(self : FrameTextLog) -> Array[String]

#
FrameTextLog::new

fn FrameTextLog::new(max_entries? : Int) -> Result[FrameTextLog, ModbusError]

#
FrameTextLog::push

fn FrameTextLog::push(self : FrameTextLog, line : String) -> Unit

#
FrameTextLog::record

fn FrameTextLog::record(self : FrameTextLog, direction : String, frame : Frame) -> Unit

#
FrameTextLog::record_wire

fn FrameTextLog::record_wire(self : FrameTextLog, direction : String, mode : Mode, transaction_id : UInt16, frame : Frame) -> Unit

#
FunctionCode

pub(all) enum FunctionCode {
ReadCoils
ReadDiscreteInputs
ReadHoldingRegisters
ReadInputRegisters
WriteSingleCoil
WriteSingleRegister
ReadExceptionStatus
Diagnostics
GetCommEventCounter
GetCommEventLog
ReportServerId
WriteMultipleCoils
WriteMultipleRegisters
ReportServerIdExtended
ReadFileRecord
WriteFileRecord
MaskWriteRegister
ReadWriteMultipleRegisters
ReadFifoQueue
EncapsulatedInterface
Unknown(Byte)
} derive(Eq,
Debug
)

The function codes defined by the Modbus application protocol.

#
FunctionCode::to_byte

fn FunctionCode::to_byte(code : FunctionCode) -> Byte

Return the numeric representation of a typed function code.

#
FunctionDescriptor

pub(all) struct FunctionDescriptor {
function : Byte
name : String
request_min : Int
request_max : Int
response_variable : Bool
writable : Bool
description : String
}

Metadata used by configuration UIs and validation tools.

#
FunctionDescriptor::description

fn FunctionDescriptor::description(self : FunctionDescriptor) -> String

#
FunctionDescriptor::function

fn FunctionDescriptor::function(self : FunctionDescriptor) -> Byte

#
FunctionDescriptor::is_write

fn FunctionDescriptor::is_write(self : FunctionDescriptor) -> Bool

#
FunctionDescriptor::name

fn FunctionDescriptor::name(self : FunctionDescriptor) -> String

#
FunctionDescriptor::supports_request

fn FunctionDescriptor::supports_request(self : FunctionDescriptor, length : Int) -> Bool

#
Gateway

pub struct Gateway {
rules : Array[GatewayRule]
forwarded : Int
rejected : Int
translated : Int
}

A deterministic frame gateway that rewrites unit ids and register/coil addresses.

#
Gateway::add_rule

fn Gateway::add_rule(self : Gateway, rule : GatewayRule) -> Result[Unit, ModbusError]

#
Gateway::forwarded_count

fn Gateway::forwarded_count(self : Gateway) -> Int

#
Gateway::new

fn Gateway::new() -> Gateway

#
Gateway::rejected_count

fn Gateway::rejected_count(self : Gateway) -> Int

#
Gateway::reset_metrics

fn Gateway::reset_metrics(self : Gateway) -> Unit

#
Gateway::reverse

fn Gateway::reverse(self : Gateway, request : Frame, response : Frame) -> Result[Frame, ModbusError]

Translate a response back to the source address space.

#
Gateway::rule_count

fn Gateway::rule_count(self : Gateway) -> Int

#
Gateway::rules

fn Gateway::rules(self : Gateway) -> Array[GatewayRule]

#
Gateway::translate

fn Gateway::translate(self : Gateway, frame : Frame) -> Result[Frame, ModbusError]

Translate one request according to the first matching rule.

#
Gateway::translated_count

fn Gateway::translated_count(self : Gateway) -> Int

#
GatewayRoute

pub(all) struct GatewayRoute {
name : String
gateway : Gateway
device : Device
client : Client
}

A gateway route that combines a rule set, client, and virtual device.

#
GatewayRoute::add_rule

fn GatewayRoute::add_rule(self : GatewayRoute, rule : GatewayRule) -> Result[Unit, ModbusError]

#
GatewayRoute::exchange

fn GatewayRoute::exchange(self : GatewayRoute, request : Frame) -> Result[Frame, ModbusError]

#
GatewayRoute::metrics

fn GatewayRoute::metrics(self : GatewayRoute) -> (Int, Int, Int)

#
GatewayRoute::name

fn GatewayRoute::name(self : GatewayRoute) -> String

#
GatewayRoute::new

fn GatewayRoute::new(name : String, mode : Mode, device : Device) -> GatewayRoute

#
GatewayRule

pub(all) struct GatewayRule {
source_unit : Byte
target_unit : Byte
function : Byte
source_start : UInt16
target_start : UInt16
span : Int
enabled : Bool
}

Address mapping rule for a protocol gateway.

#
GatewayRule::enable

fn GatewayRule::enable(self : GatewayRule, enabled : Bool) -> Unit

#
GatewayRule::matches

fn GatewayRule::matches(self : GatewayRule, frame : Frame) -> Bool

#
GatewayRule::new

fn GatewayRule::new(source_unit : Byte, target_unit : Byte, function : Byte, source_start : UInt16, target_start : UInt16, span : Int) -> Result[GatewayRule, ModbusError]

#
IncrementalParser

pub struct IncrementalParser {
mode : Mode
role : ParserRole
buffer : Array[Byte]
max_frame : Int
frames_seen : Int
errors_seen : Int
}

A bounded incremental parser for stream transports.

#
IncrementalParser::buffered

fn IncrementalParser::buffered(self : IncrementalParser) -> Int

Return the number of bytes waiting in the parser.

#
IncrementalParser::errors_seen

fn IncrementalParser::errors_seen(self : IncrementalParser) -> Int

#
IncrementalParser::feed

fn IncrementalParser::feed(self : IncrementalParser, input : Array[Byte]) -> Result[Array[Frame], ModbusError]

Feed bytes and return every complete frame currently available.

#
IncrementalParser::feed_byte

fn IncrementalParser::feed_byte(self : IncrementalParser, byte : Byte) -> Result[Array[Frame], ModbusError]

Feed a single byte without allocating an input array at the call site.

#
IncrementalParser::finish

fn IncrementalParser::finish(self : IncrementalParser) -> Result[Frame, ModbusError]

Finish a serial frame at an externally supplied RTU silent interval.

#
IncrementalParser::frames_seen

fn IncrementalParser::frames_seen(self : IncrementalParser) -> Int

#
IncrementalParser::max_frame

fn IncrementalParser::max_frame(self : IncrementalParser) -> Int

#
IncrementalParser::mode

#
IncrementalParser::new

fn IncrementalParser::new(mode : Mode, max_frame? : Int, role? : ParserRole) -> IncrementalParser

Create a stream parser. max_frame prevents unbounded input growth.

#
IncrementalParser::reset

fn IncrementalParser::reset(self : IncrementalParser) -> Unit

Discard buffered bytes after a transport reset.

#
IncrementalParser::role

#
IncrementalParser::set_max_frame

fn IncrementalParser::set_max_frame(self : IncrementalParser, max_frame : Int) -> Result[Unit, ModbusError]

Change the maximum frame size for a parser that is already in use.

#
IncrementalParser::take_buffer

fn IncrementalParser::take_buffer(self : IncrementalParser) -> Array[Byte]

Take the current buffered bytes and reset the parser.

#
LatencyHistogram

pub(all) struct LatencyHistogram {
bounds : Array[Int]
counts : Array[Int]
total : Int
sum : Int
}

Fixed latency buckets, expressed in logical ticks.

#
LatencyHistogram::bucket_counts

fn LatencyHistogram::bucket_counts(self : LatencyHistogram) -> Array[Int]

#
LatencyHistogram::mean

fn LatencyHistogram::mean(self : LatencyHistogram) -> Float

#
LatencyHistogram::new

fn LatencyHistogram::new(bounds : Array[Int]) -> Result[LatencyHistogram, ModbusError]

#
LatencyHistogram::observe

fn LatencyHistogram::observe(self : LatencyHistogram, ticks : Int) -> Result[Unit, ModbusError]

#
LatencyHistogram::sum

fn LatencyHistogram::sum(self : LatencyHistogram) -> Int

#
LatencyHistogram::total

fn LatencyHistogram::total(self : LatencyHistogram) -> Int

#
ModbusError

pub(all) enum ModbusError {
Incomplete
InvalidLength
InvalidChecksum
InvalidAscii
InvalidMbap
InvalidUnitId
InvalidFunction
InvalidAddress
InvalidQuantity
InvalidByteCount
InvalidData
InvalidTransaction
Unsupported
UnitMismatch
CapacityExceeded
NoResponse
Busy
} derive(Eq,
Debug
)

Errors produced by the protocol core and its in-memory services.

#
Mode

pub(all) enum Mode {
Rtu
Ascii
Tcp
} derive(Eq,
Debug
)

A Modbus wire mode.

#
ParserRole

pub(all) enum ParserRole {
Request
Response
Either
} derive(Eq,
Debug
)

The side of a stream that an incremental parser is consuming.

#
Pdu

pub(all) struct Pdu {
function : Byte
data : Array[Byte]
}

A Modbus application data unit without transport framing.

#
Pdu::data_length

fn Pdu::data_length(self : Pdu) -> Int

#
Pdu::function_code

fn Pdu::function_code(self : Pdu) -> FunctionCode

#
Pdu::is_exception

fn Pdu::is_exception(self : Pdu) -> Bool

#
Pdu::new

fn Pdu::new(function : Byte, data : Array[Byte]) -> Pdu

#
PendingExchange

pub(all) struct PendingExchange {
transaction_id : UInt16
frame : Frame
attempts : Int
created_at : Int
last_sent_at : Int
state : ExchangeState
}

A pending exchange retained for correlation and retry accounting.

#
PlanSummary

pub(all) struct PlanSummary {
requests : Int
total_registers : Int
total_coils : Int
total_bytes : Int
}

A request plan summary used to size queues before dispatch.

#
PlannedRequest

pub(all) struct PlannedRequest {
id : Int
frame : Frame
address : AddressRange
}

A range request planner that splits large logical reads into legal PDUs.

#
PollJob

pub(all) struct PollJob {
id : Int
name : String
request : Frame
interval : Int
timeout : Int
retries : Int
next_due : Int
attempts : Int
runs : Int
failures : Int
last_response : Frame?
}

A polling job with a deterministic logical-clock schedule.

#
PollJob::is_due

fn PollJob::is_due(self : PollJob, now : Int) -> Bool

#
PollJob::mark_failure

fn PollJob::mark_failure(self : PollJob, now : Int) -> Unit

#
PollJob::mark_success

fn PollJob::mark_success(self : PollJob, now : Int, response : Frame) -> Unit

#
PollJob::new

fn PollJob::new(id : Int, name : String, request : Frame, interval? : Int, timeout? : Int, retries? : Int) -> Result[PollJob, ModbusError]

#
PollJob::success_rate

fn PollJob::success_rate(self : PollJob) -> Float

#
PollPlan

pub struct PollPlan {
jobs : Array[PollJob]
max_jobs : Int
}

A polling plan keeps jobs ordered and addresses them by stable ids.

#
PollPlan::add

fn PollPlan::add(self : PollPlan, job : PollJob) -> Result[Unit, ModbusError]

#
PollPlan::due

fn PollPlan::due(self : PollPlan, now : Int) -> Array[PollJob]

#
PollPlan::job

fn PollPlan::job(self : PollPlan, id : Int) -> PollJob?

#
PollPlan::length

fn PollPlan::length(self : PollPlan) -> Int

#
PollPlan::mark_failure

fn PollPlan::mark_failure(self : PollPlan, id : Int, now : Int) -> Result[Unit, ModbusError]

#
PollPlan::mark_success

fn PollPlan::mark_success(self : PollPlan, id : Int, now : Int, response : Frame) -> Result[Unit, ModbusError]

#
PollPlan::new

fn PollPlan::new(max_jobs? : Int) -> Result[PollPlan, ModbusError]

#
PollPlan::remove

fn PollPlan::remove(self : PollPlan, id : Int) -> Result[Unit, ModbusError]

#
PollPlan::run_once

fn PollPlan::run_once(self : PollPlan, device : Device, now : Int) -> PollReport

Execute due jobs against a deterministic device.

#
PollPlan::snapshot

fn PollPlan::snapshot(self : PollPlan) -> Array[PollJob]

#
PollReport

pub(all) struct PollReport {
now : Int
attempted : Int
succeeded : Int
failed : Int
responses : Array[Frame]
}

One scheduler run result.

#
PollScheduler

pub struct PollScheduler {
plan : PollPlan
device : Device
mode : Mode
last_report : PollReport?
}

A scheduler that records the last report and applies a transport mode.

#
PollScheduler::last_report

fn PollScheduler::last_report(self : PollScheduler) -> PollReport?

#
PollScheduler::mode

fn PollScheduler::mode(self : PollScheduler) -> Mode

#
PollScheduler::new

fn PollScheduler::new(plan : PollPlan, device : Device, mode : Mode) -> PollScheduler

#
PollScheduler::plan

#
PollScheduler::tick

fn PollScheduler::tick(self : PollScheduler, now : Int) -> PollReport

#
PreflightReport

pub(all) struct PreflightReport {
errors : Array[String]
warnings : Array[String]
checked_frames : Int
checked_devices : Int
}

A structured preflight report for deployment and CI diagnostics.

#
PreflightReport::error_count

fn PreflightReport::error_count(self : PreflightReport) -> Int

#
PreflightReport::errors

fn PreflightReport::errors(self : PreflightReport) -> Array[String]

#
PreflightReport::new

#
PreflightReport::ok

fn PreflightReport::ok(self : PreflightReport) -> Bool

#
PreflightReport::warning_count

fn PreflightReport::warning_count(self : PreflightReport) -> Int

#
PreflightReport::warnings

fn PreflightReport::warnings(self : PreflightReport) -> Array[String]

#
ProtocolLimits

pub(all) struct ProtocolLimits {
max_adu : Int
max_pdu : Int
max_registers : Int
max_coils : Int
max_buffer : Int
}

A small immutable configuration snapshot used by clients and servers.

#
ProtocolMetrics

pub(all) struct ProtocolMetrics {
requests : Int
responses : Int
exceptions : Int
errors : Int
bytes_in : Int
bytes_out : Int
active : Int
latency : LatencyHistogram
}

A snapshot-friendly metrics set for a protocol endpoint.

#
ProtocolMetrics::active

fn ProtocolMetrics::active(self : ProtocolMetrics) -> Int

#
ProtocolMetrics::errors

fn ProtocolMetrics::errors(self : ProtocolMetrics) -> Int

#
ProtocolMetrics::exceptions

fn ProtocolMetrics::exceptions(self : ProtocolMetrics) -> Int

#
ProtocolMetrics::new

#
ProtocolMetrics::record_error

fn ProtocolMetrics::record_error(self : ProtocolMetrics) -> Unit

#
ProtocolMetrics::record_request

fn ProtocolMetrics::record_request(self : ProtocolMetrics, bytes : Int) -> Result[Unit, ModbusError]

#
ProtocolMetrics::record_response

fn ProtocolMetrics::record_response(self : ProtocolMetrics, bytes : Int, latency : Int, exception : Bool) -> Result[Unit, ModbusError]

#
ProtocolMetrics::requests

fn ProtocolMetrics::requests(self : ProtocolMetrics) -> Int

#
ProtocolMetrics::responses

fn ProtocolMetrics::responses(self : ProtocolMetrics) -> Int

#
ProtocolMetrics::throughput

fn ProtocolMetrics::throughput(self : ProtocolMetrics, ticks : Int) -> Float

#
RegisterBank

pub(all) struct RegisterBank {
start : UInt16
values : Array[UInt16]
writable : Bool
}

A contiguous, bounds-checked register bank.

#
RegisterBank::clear

fn RegisterBank::clear(self : RegisterBank) -> Unit

#
RegisterBank::contains

fn RegisterBank::contains(self : RegisterBank, address : UInt16, quantity : Int) -> Bool

#
RegisterBank::end_exclusive

fn RegisterBank::end_exclusive(self : RegisterBank) -> Int

#
RegisterBank::fill

fn RegisterBank::fill(self : RegisterBank, value : UInt16) -> Unit

#
RegisterBank::get

fn RegisterBank::get(self : RegisterBank, address : UInt16) -> Result[UInt16, ModbusError]

#
RegisterBank::is_writable

fn RegisterBank::is_writable(self : RegisterBank) -> Bool

#
RegisterBank::length

fn RegisterBank::length(self : RegisterBank) -> Int

#
RegisterBank::new

fn RegisterBank::new(start : UInt16, length : Int, writable? : Bool) -> Result[RegisterBank, ModbusError]

Create a register bank in the 16-bit address space.

#
RegisterBank::read

fn RegisterBank::read(self : RegisterBank, address : UInt16, quantity : Int) -> Result[Array[UInt16], ModbusError]

#
RegisterBank::set

fn RegisterBank::set(self : RegisterBank, address : UInt16, value : UInt16) -> Result[Unit, ModbusError]

#
RegisterBank::snapshot

fn RegisterBank::snapshot(self : RegisterBank) -> Array[UInt16]

#
RegisterBank::start

fn RegisterBank::start(self : RegisterBank) -> UInt16

#
RegisterBank::write

fn RegisterBank::write(self : RegisterBank, address : UInt16, values : Array[UInt16]) -> Result[Unit, ModbusError]

#
RegisterBank::write_mask

fn RegisterBank::write_mask(self : RegisterBank, address : UInt16, and_mask : UInt16, or_mask : UInt16) -> Result[UInt16, ModbusError]

#
RegisterByteOrder

pub(all) enum RegisterByteOrder {
BigEndian
LittleEndian
} derive(Eq,
Debug
)

Register byte order used when mapping multi-register values.

#
RegisterCursor

pub(all) struct RegisterCursor {
values : Array[UInt16]
position : Int
}

A bounds-checked cursor over an owned register array.

#
RegisterCursor::at_end

fn RegisterCursor::at_end(self : RegisterCursor) -> Bool

#
RegisterCursor::new

fn RegisterCursor::new(values : Array[UInt16]) -> RegisterCursor

#
RegisterCursor::position

fn RegisterCursor::position(self : RegisterCursor) -> Int

#
RegisterCursor::read_f32

fn RegisterCursor::read_f32(self : RegisterCursor, order : RegisterWordOrder) -> Result[Float, ModbusError]

#
RegisterCursor::read_i16

fn RegisterCursor::read_i16(self : RegisterCursor) -> Result[Int, ModbusError]

#
RegisterCursor::read_i32

fn RegisterCursor::read_i32(self : RegisterCursor, order : RegisterWordOrder) -> Result[Int, ModbusError]

#
RegisterCursor::read_u16

fn RegisterCursor::read_u16(self : RegisterCursor) -> Result[UInt16, ModbusError]

#
RegisterCursor::read_u32

fn RegisterCursor::read_u32(self : RegisterCursor, order : RegisterWordOrder) -> Result[UInt, ModbusError]

#
RegisterCursor::read_u64

fn RegisterCursor::read_u64(self : RegisterCursor, order : RegisterWordOrder) -> Result[UInt64, ModbusError]

#
RegisterCursor::remaining

fn RegisterCursor::remaining(self : RegisterCursor) -> Int

#
RegisterCursor::seek

fn RegisterCursor::seek(self : RegisterCursor, position : Int) -> Result[Unit, ModbusError]

#
RegisterCursor::skip

fn RegisterCursor::skip(self : RegisterCursor, count : Int) -> Result[Unit, ModbusError]

#
RegisterField

pub(all) struct RegisterField {
name : String
address : UInt16
kind : RegisterFieldKind
writable : Bool
scale : Float
}

A named register field with an explicit wire representation.

#
RegisterField::address

fn RegisterField::address(self : RegisterField) -> UInt16

#
RegisterField::is_writable

fn RegisterField::is_writable(self : RegisterField) -> Bool

#
RegisterField::kind

#
RegisterField::name

fn RegisterField::name(self : RegisterField) -> String

#
RegisterField::new

fn RegisterField::new(name : String, address : UInt16, kind : RegisterFieldKind, writable? : Bool, scale? : Float) -> Result[RegisterField, ModbusError]

#
RegisterField::scale

fn RegisterField::scale(self : RegisterField) -> Float

#
RegisterField::width

fn RegisterField::width(self : RegisterField) -> Int

#
RegisterFieldKind

pub(all) enum RegisterFieldKind {
Unsigned16
Signed16
Unsigned32
Signed32
Float32
Unsigned64
BitField(Int)
} derive(Eq,
Debug
)

Typed interpretation for a register-backed device schema.

#
RegisterFieldKind::name

fn RegisterFieldKind::name(self : RegisterFieldKind) -> String

#
RegisterFieldKind::width

fn RegisterFieldKind::width(self : RegisterFieldKind) -> Int

#
RegisterSchema

pub struct RegisterSchema {
fields : Array[RegisterField]
max_fields : Int
}

A schema with unique named fields and no overlapping wire ranges.

#
RegisterSchema::add

fn RegisterSchema::add(self : RegisterSchema, field : RegisterField) -> Result[Unit, ModbusError]

#
RegisterSchema::field

fn RegisterSchema::field(self : RegisterSchema, name : String) -> RegisterField?

#
RegisterSchema::fields

#
RegisterSchema::length

fn RegisterSchema::length(self : RegisterSchema) -> Int

#
RegisterSchema::new

fn RegisterSchema::new(max_fields? : Int) -> Result[RegisterSchema, ModbusError]

#
RegisterSchema::read

fn RegisterSchema::read(self : RegisterSchema, name : String, bank : RegisterBank) -> Result[RegisterValue, ModbusError]

Decode one schema field from a register bank.

#
RegisterSchema::read_all

fn RegisterSchema::read_all(self : RegisterSchema, bank : RegisterBank) -> Result[Array[(String, RegisterValue)], ModbusError]

Return the values of every field that fits in a bank snapshot.

#
RegisterSchema::validate_against

fn RegisterSchema::validate_against(self : RegisterSchema, bank : RegisterBank) -> Result[Unit, ModbusError]

Validate a schema against a register bank before starting a service.

#
RegisterSchema::write

fn RegisterSchema::write(self : RegisterSchema, name : String, value : RegisterValue, bank : RegisterBank) -> Result[Unit, ModbusError]

Encode a typed value and write it to a schema field.

#
RegisterValue

pub(all) enum RegisterValue {
U16(UInt16)
I16(Int)
U32(UInt)
I32(Int)
F32(Float)
U64(UInt64)
Bits(Array[Bool])
}

A value returned by schema-aware reads.

#
RegisterWordOrder

pub(all) enum RegisterWordOrder {
HighWordFirst
LowWordFirst
} derive(Eq,
Debug
)

Word order used for values wider than one register.

#
RegisterWriter

pub(all) struct RegisterWriter {
values : Array[UInt16]
capacity : Int
}

A register writer that grows only up to a configured capacity.

#
RegisterWriter::length

fn RegisterWriter::length(self : RegisterWriter) -> Int

#
RegisterWriter::new

fn RegisterWriter::new(capacity : Int) -> Result[RegisterWriter, ModbusError]

#
RegisterWriter::push

fn RegisterWriter::push(self : RegisterWriter, value : UInt16) -> Result[Unit, ModbusError]

#
RegisterWriter::push_f32

fn RegisterWriter::push_f32(self : RegisterWriter, value : Float, order : RegisterWordOrder) -> Result[Unit, ModbusError]

#
RegisterWriter::push_i16

fn RegisterWriter::push_i16(self : RegisterWriter, value : Int) -> Result[Unit, ModbusError]

#
RegisterWriter::push_u32

fn RegisterWriter::push_u32(self : RegisterWriter, value : UInt, order : RegisterWordOrder) -> Result[Unit, ModbusError]

#
RegisterWriter::push_u64

fn RegisterWriter::push_u64(self : RegisterWriter, value : UInt64, order : RegisterWordOrder) -> Result[Unit, ModbusError]

#
RegisterWriter::remaining

fn RegisterWriter::remaining(self : RegisterWriter) -> Int

#
RegisterWriter::to_array

fn RegisterWriter::to_array(self : RegisterWriter) -> Array[UInt16]

#
ResponseValue

pub(all) enum ResponseValue {
Normal(Frame)
Exception(Frame, ExceptionCode)
}

A raw PDU result that retains whether a response was an exception.

#
Scenario

pub(all) struct Scenario {
name : String
requests : Array[Frame]
mode : Mode
}

A deterministic multi-request scenario.

#
Scenario::add

fn Scenario::add(self : Scenario, request : Frame) -> Result[Unit, ModbusError]

#
Scenario::length

fn Scenario::length(self : Scenario) -> Int

#
Scenario::mode

fn Scenario::mode(self : Scenario) -> Mode

#
Scenario::name

fn Scenario::name(self : Scenario) -> String

#
Scenario::new

fn Scenario::new(name : String, mode : Mode) -> Scenario

#
Scenario::run

fn Scenario::run(self : Scenario, simulation : Simulation) -> Array[SimulationResult]

#
SerialConfig

pub(all) struct SerialConfig {
path : String
baud : Int
data_bits : Int
stop_bits : Int
parity : Byte
mode : Mode
}

Serial-line parameters independent of any concrete serial-port library.

#
SerialConfig::new

fn SerialConfig::new(path : String, baud : Int, mode : Mode, data_bits? : Int, stop_bits? : Int, parity? : Byte) -> Result[SerialConfig, ModbusError]

#
SerialConfig::parity_name

fn SerialConfig::parity_name(self : SerialConfig) -> String

#
Server

pub struct Server {
config : ServerConfig
devices : Array[Device]
parser : IncrementalParser
metrics : ProtocolMetrics
audit : AuditLog
}

A multi-unit server that owns device instances and performs transport framing.

#
Server::add_device

fn Server::add_device(self : Server, device : Device) -> Result[Unit, ModbusError]

#
Server::audit

fn Server::audit(self : Server) -> AuditLog

#
Server::broadcast

fn Server::broadcast(self : Server, request : Frame) -> Array[Frame]

Run a request against every configured unit and return normal replies.

#
Server::config

fn Server::config(self : Server) -> ServerConfig

#
Server::device

fn Server::device(self : Server, unit_id : Byte) -> Device?

#
Server::device_count

fn Server::device_count(self : Server) -> Int

#
Server::handle

fn Server::handle(self : Server, request : Frame) -> Result[Frame, ModbusError]

Handle a decoded request and return a decoded reply.

#
Server::handle_adu

fn Server::handle_adu(self : Server, bytes : Array[Byte]) -> Result[Array[Byte], ModbusError]

Decode an ADU, dispatch it, and encode the reply.

#
Server::metrics

fn Server::metrics(self : Server) -> ProtocolMetrics

#
Server::mode

fn Server::mode(self : Server) -> Mode

#
Server::new

fn Server::new(config : ServerConfig) -> Result[Server, ModbusError]

#
Server::parser

fn Server::parser(self : Server) -> IncrementalParser

#
Server::remove_device

fn Server::remove_device(self : Server, unit_id : Byte) -> Result[Unit, ModbusError]

#
ServerConfig

pub(all) struct ServerConfig {
mode : Mode
max_devices : Int
max_frame : Int
allow_broadcast : Bool
max_pending_bytes : Int
}

Configuration for an in-process Modbus server.

#
Simulation

pub struct Simulation {
device : Device
mode : Mode
fault : FaultMode
clock : Int
metrics : ProtocolMetrics
audit : AuditLog
}

A portable protocol simulation with no operating-system I/O.

#
Simulation::advance

fn Simulation::advance(self : Simulation, ticks : Int) -> Result[Unit, ModbusError]

#
Simulation::audit

fn Simulation::audit(self : Simulation) -> AuditLog

#
Simulation::clock

fn Simulation::clock(self : Simulation) -> Int

#
Simulation::device

fn Simulation::device(self : Simulation) -> Device

#
Simulation::fault

fn Simulation::fault(self : Simulation) -> FaultMode

#
Simulation::metrics

fn Simulation::metrics(self : Simulation) -> ProtocolMetrics

#
Simulation::mode

fn Simulation::mode(self : Simulation) -> Mode

#
Simulation::new

fn Simulation::new(device : Device, mode : Mode) -> Result[Simulation, ModbusError]

#
Simulation::request

fn Simulation::request(self : Simulation, transaction_id : UInt16, request : Frame) -> SimulationResult

Send one request through the selected fault model.

#
Simulation::reset

fn Simulation::reset(self : Simulation) -> Unit

#
Simulation::set_fault

fn Simulation::set_fault(self : Simulation, fault : FaultMode) -> Unit

#
SimulationResult

pub(all) enum SimulationResult {
Delivered(Frame)
Dropped
Rejected(ModbusError)
}

Result of one deterministic simulation step.

#
TcpConfig

pub(all) struct TcpConfig {
host : String
port : Int
connect_timeout : Int
keep_alive : Bool
}

TCP endpoint settings.

#
TcpConfig::address

fn TcpConfig::address(self : TcpConfig) -> String

#
TcpConfig::new

fn TcpConfig::new(host : String, port : Int, connect_timeout? : Int, keep_alive? : Bool) -> Result[TcpConfig, ModbusError]

#
TelemetryRing

pub(all) struct TelemetryRing {
values : Array[Int]
capacity : Int
cursor : Int
count : Int
}

A bounded ring of integer telemetry samples for device dashboards.

#
TelemetryRing::at

fn TelemetryRing::at(self : TelemetryRing, logical : Int) -> Result[Int, ModbusError]

Read a sample from oldest to newest order.

#
TelemetryRing::average

fn TelemetryRing::average(self : TelemetryRing) -> Float

#
TelemetryRing::capacity

fn TelemetryRing::capacity(self : TelemetryRing) -> Int

#
TelemetryRing::clear

fn TelemetryRing::clear(self : TelemetryRing) -> Unit

#
TelemetryRing::delta

fn TelemetryRing::delta(self : TelemetryRing) -> Result[Int, ModbusError]

#
TelemetryRing::is_full

fn TelemetryRing::is_full(self : TelemetryRing) -> Bool

#
TelemetryRing::latest

fn TelemetryRing::latest(self : TelemetryRing) -> Result[Int, ModbusError]

#
TelemetryRing::length

fn TelemetryRing::length(self : TelemetryRing) -> Int

#
TelemetryRing::maximum

fn TelemetryRing::maximum(self : TelemetryRing) -> Result[Int, ModbusError]

#
TelemetryRing::minimum

fn TelemetryRing::minimum(self : TelemetryRing) -> Result[Int, ModbusError]

#
TelemetryRing::new

fn TelemetryRing::new(capacity : Int) -> Result[TelemetryRing, ModbusError]

#
TelemetryRing::previous

fn TelemetryRing::previous(self : TelemetryRing) -> Result[Int, ModbusError]

#
TelemetryRing::record

fn TelemetryRing::record(self : TelemetryRing, value : Int) -> Unit

Add a sample and overwrite the oldest sample when the ring is full.

#
TelemetryRing::snapshot

fn TelemetryRing::snapshot(self : TelemetryRing) -> Array[Int]

#
TelemetryRing::sum

fn TelemetryRing::sum(self : TelemetryRing) -> Int

#
Threshold

pub(all) struct Threshold {
low : Int
high : Int
}

A closed interval used for a device alarm threshold.

#
Threshold::classify

fn Threshold::classify(self : Threshold, value : Int) -> ThresholdState

#
Threshold::high

fn Threshold::high(self : Threshold) -> Int

#
Threshold::low

fn Threshold::low(self : Threshold) -> Int

#
Threshold::new

fn Threshold::new(low : Int, high : Int) -> Result[Threshold, ModbusError]

#
ThresholdState

pub(all) enum ThresholdState {
Below
Within
Above
} derive(Eq,
Debug
)

#
TransactionFrame

pub(all) struct TransactionFrame {
transaction_id : UInt16
request : Frame
response : Frame?
}

A request/response pair associated with a TCP transaction identifier.

#
TransactionFrame::complete

fn TransactionFrame::complete(self : TransactionFrame, response : Frame) -> TransactionFrame

#
TransactionFrame::is_complete

fn TransactionFrame::is_complete(self : TransactionFrame) -> Bool

#
TransactionFrame::new

fn TransactionFrame::new(transaction_id : UInt16, request : Frame) -> TransactionFrame

#
TransportCapabilities

pub(all) struct TransportCapabilities {
mode : Mode
max_adu : Int
supports_broadcast : Bool
preserves_transaction_id : Bool
}

A transport capability report for startup diagnostics.

#
TransportKind

pub(all) enum TransportKind {
SerialRtu
SerialAscii
ModbusTcp
} derive(Eq,
Debug
)

Named transport choices used by adapters.
pub struct VirtualLink {
mode : Mode
max_queue : Int
master_to_device : Array[Array[Byte]]
device_to_master : Array[Array[Byte]]
sent : Int
received : Int
dropped : Int
}

A deterministic in-memory transport used by tests, demos, and simulators.

#
VirtualLink::clear

fn VirtualLink::clear(self : VirtualLink) -> Unit

#
VirtualLink::dropped_count

fn VirtualLink::dropped_count(self : VirtualLink) -> Int

#
VirtualLink::mode

fn VirtualLink::mode(self : VirtualLink) -> Mode

#
VirtualLink::new

fn VirtualLink::new(mode : Mode, max_queue? : Int) -> Result[VirtualLink, ModbusError]

#
VirtualLink::queued_requests

fn VirtualLink::queued_requests(self : VirtualLink) -> Int

#
VirtualLink::queued_responses

fn VirtualLink::queued_responses(self : VirtualLink) -> Int

#
VirtualLink::receive_request

fn VirtualLink::receive_request(self : VirtualLink) -> Result[Frame, ModbusError]

#
VirtualLink::receive_response

fn VirtualLink::receive_response(self : VirtualLink) -> Result[Array[Byte], ModbusError]

#
VirtualLink::received_count

fn VirtualLink::received_count(self : VirtualLink) -> Int

#
VirtualLink::round_trip

fn VirtualLink::round_trip(self : VirtualLink, device : Device, transaction_id : UInt16, request : Frame) -> Result[DeviceResponse, ModbusError]

Execute one request against a device and enqueue its response.

#
VirtualLink::send_request

fn VirtualLink::send_request(self : VirtualLink, transaction_id : UInt16, frame : Frame) -> Result[Unit, ModbusError]

#
VirtualLink::send_response

fn VirtualLink::send_response(self : VirtualLink, transaction_id : UInt16, frame : Frame) -> Result[Unit, ModbusError]

#
VirtualLink::sent_count

fn VirtualLink::sent_count(self : VirtualLink) -> Int

#
accepts_broadcast

fn accepts_broadcast(mode : Mode) -> Bool

#
address_bytes

fn address_bytes(address : UInt16) -> Array[Byte]

Make the two-byte address representation used by request builders.

#
append_u16_be

fn append_u16_be(out : Array[Byte], value : UInt16) -> Unit

Append a big-endian unsigned 16-bit value.

#
append_u32_be

fn append_u32_be(out : Array[Byte], value : UInt) -> Unit

Append a big-endian unsigned 32-bit value.

#
ascii_boundary

fn ascii_boundary(bytes : Array[Byte]) -> Int?

Return a complete ASCII frame boundary if CRLF is present.

#
ascii_mode

fn ascii_mode() -> Mode

#
base_function

fn base_function(frame : Frame) -> Byte

Return the function number without the exception bit.

#
batch_completed

fn batch_completed(results : Array[BatchResult]) -> Int

#
batch_failed

fn batch_failed(results : Array[BatchResult]) -> Int

#
batch_register_values

fn batch_register_values(results : Array[BatchResult]) -> Result[Array[UInt16], ModbusError]

Merge successful register responses from a batch into one ordered array.

#
benchmark_crc

fn benchmark_crc(iterations : Int) -> Result[BenchmarkResult, ModbusError]

Run repeated CRC work over a representative RTU payload.

#
benchmark_device_reads

fn benchmark_device_reads(iterations : Int) -> Result[BenchmarkResult, ModbusError]

Run a device read workload over the in-memory server path.

#
benchmark_rtu_round_trip

fn benchmark_rtu_round_trip(iterations : Int) -> Result[BenchmarkResult, ModbusError]

Run encode/decode round trips for the RTU transport.

#
benchmark_suite

fn benchmark_suite(iterations : Int) -> Result[Array[BenchmarkResult], ModbusError]

Run the standard local benchmark suite.

#
benchmark_tcp_round_trip

fn benchmark_tcp_round_trip(iterations : Int) -> Result[BenchmarkResult, ModbusError]

Run encode/decode round trips for the TCP transport.

#
boundary_vectors

fn boundary_vectors(frame : Frame) -> Array[ConformanceVector]

Generate boundary vectors for empty, short, and corrupt inputs.

#
byte_sum

fn byte_sum(bytes : Array[Byte]) -> Byte

#
byte_xor

fn byte_xor(bytes : Array[Byte]) -> Byte

#
bytes_equal

fn bytes_equal(left : Array[Byte], right : Array[Byte]) -> Bool

#
bytes_to_hex_string

fn bytes_to_hex_string(bytes : Array[Byte]) -> String

Convert a byte array to a printable uppercase hexadecimal string.

#
bytes_to_register

fn bytes_to_register(bytes : Array[Byte], offset : Int, order : RegisterByteOrder) -> Result[UInt16, ModbusError]

Decode two bytes as one register.

#
bytes_to_registers

fn bytes_to_registers(bytes : Array[Byte], order : RegisterByteOrder) -> Result[Array[UInt16], ModbusError]

Convert an even-length byte array to registers.

#
capabilities

fn capabilities(mode : Mode) -> TransportCapabilities

#
chunk_bytes

fn chunk_bytes(bytes : Array[Byte], chunk_size : Int) -> Result[Array[Array[Byte]], ModbusError]

Split a byte array into bounded chunks for transport fuzzing and tests.

#
clamp_int

fn clamp_int(value : Int, minimum : Int, maximum : Int) -> Result[Int, ModbusError]

#
client_result

fn client_result(response : Frame) -> ClientResult

#
conformance_failed

fn conformance_failed(results : Array[ConformanceResult]) -> Int

#
conformance_passed

fn conformance_passed(results : Array[ConformanceResult]) -> Int

#
copy_bytes

fn copy_bytes(bytes : Array[Byte]) -> Array[Byte]

Make an owned byte-array copy. Protocol parsers use this to avoid retaining views.

#
copy_range

fn copy_range(bytes : Array[Byte], start : Int, end : Int) -> Result[Array[Byte], ModbusError]

Copy a half-open range and return a protocol error when the range is invalid.

#
count_bits

fn count_bits(bytes : Array[Byte]) -> Int

Count the set bits in a packed byte array.

#
crc16

fn crc16(bytes : Array[Byte]) -> UInt16

Modbus polynomial CRC16, low byte first on the wire.

#
crc16_range

fn crc16_range(bytes : Array[Byte], start : Int, end : Int) -> Result[UInt16, ModbusError]

Compute CRC16 for a half-open range without allocating a slice.

#
crc16_update

fn crc16_update(crc : UInt16, byte : Byte) -> UInt16

Update a CRC16 accumulator with one byte.

#
crc_bytes

fn crc_bytes(bytes : Array[Byte]) -> Array[Byte]

Return CRC bytes in Modbus RTU order.

#
decode_ascii

fn decode_ascii(bytes : Array[Byte]) -> Result[Frame, ModbusError]

Decode one complete Modbus ASCII frame.

#
decode_bits_response

fn decode_bits_response(request : Frame, response : Frame) -> Result[Array[Bool], ModbusError]

Decode a read-coils or read-discrete-inputs response.

#
decode_comm_event_counter

fn decode_comm_event_counter(request : Frame, response : Frame) -> Result[(UInt16, UInt16), ModbusError]

Decode the communication event counter response.

#
decode_device_identification

fn decode_device_identification(request : Frame, response : Frame) -> Result[DeviceIdentification, ModbusError]

Decode a Read Device Identification response into TLV objects.

#
decode_diagnostics

fn decode_diagnostics(request : Frame, response : Frame) -> Result[(UInt16, Array[Byte]), ModbusError]

Decode the two-byte diagnostics subfunction and its data.

#
decode_exception_status

fn decode_exception_status(request : Frame, response : Frame) -> Result[Byte, ModbusError]

Decode an exception-status response.

#
decode_fifo_queue

fn decode_fifo_queue(request : Frame, response : Frame) -> Result[Array[UInt16], ModbusError]

Decode a FIFO response into the queue values.

#
decode_file_record_response

fn decode_file_record_response(request : Frame, response : Frame) -> Result[Array[Array[UInt16]], ModbusError]

Decode the values returned for a Read File Record response.

#
decode_file_record_write_response

fn decode_file_record_write_response(request : Frame, response : Frame) -> Result[Unit, ModbusError]

Decode the echo of a Write File Record response.

#
decode_hex

fn decode_hex(bytes : Array[Byte]) -> Result[Array[Byte], ModbusError]

Decode an even-length hexadecimal ASCII array.

#
decode_mask_write

fn decode_mask_write(request : Frame, response : Frame) -> Result[(UInt16, UInt16), ModbusError]

Decode a mask-write response and return (and_mask, or_mask).

#
decode_mode

fn decode_mode(mode : Mode, bytes : Array[Byte]) -> Result[Frame, ModbusError]

Decode a complete frame when the transport does not carry a TCP transaction id.

#
decode_multiple_write

fn decode_multiple_write(request : Frame, response : Frame) -> Result[(UInt16, UInt16), ModbusError]

Decode a multiple-write echo and return (address, quantity).

#
decode_read_write_response

fn decode_read_write_response(request : Frame, response : Frame) -> Result[Array[UInt16], ModbusError]

Decode the register payload of a combined read/write response.

#
decode_register_response

fn decode_register_response(request : Frame, response : Frame) -> Result[Array[UInt16], ModbusError]

Decode a function 03 or 04 register response.

#
decode_response

fn decode_response(request : Frame, response : Frame) -> Result[ResponseValue, ModbusError]

Decode any response while preserving exception information.

#
decode_rtu

fn decode_rtu(bytes : Array[Byte]) -> Result[Frame, ModbusError]

Decode one complete Modbus RTU frame.

#
decode_server_id

fn decode_server_id(request : Frame, response : Frame) -> Result[Array[Byte], ModbusError]

Decode a Report Server ID response into its raw payload.

#
decode_tcp

fn decode_tcp(bytes : Array[Byte]) -> Result[(UInt16, Frame), ModbusError]

Decode one complete Modbus TCP ADU and return its transaction id.

#
decode_transaction

fn decode_transaction(mode : Mode, bytes : Array[Byte]) -> Result[(UInt16, Frame), ModbusError]

Decode an encoded frame and preserve a TCP transaction identifier when present.

#
decode_write_single_coil

fn decode_write_single_coil(request : Frame, response : Frame) -> Result[Bool, ModbusError]

Decode a single-coil echo and return its logical value.

#
decode_write_single_register

fn decode_write_single_register(request : Frame, response : Frame) -> Result[UInt16, ModbusError]

Decode a single-register write echo.

#
default_client_config

fn default_client_config() -> ClientConfig

#
default_frame_limit

fn default_frame_limit(mode : Mode) -> Int

#
default_limits

fn default_limits() -> ProtocolLimits

#
default_queue_limit

fn default_queue_limit(mode : Mode) -> Int

#
default_server_config

fn default_server_config(mode : Mode) -> ServerConfig

#
device_id_category

fn device_id_category(value : Byte) -> DeviceIdCategory

#
diagnostics

fn diagnostics(unit_id : Byte, subfunction : UInt16, data : Array[Byte]) -> Result[Frame, ModbusError]

Build a diagnostics request (function 08).

#
diagnostics_return_query_data

fn diagnostics_return_query_data(unit_id : Byte, data : Array[Byte]) -> Result[Frame, ModbusError]

Build the common Return Query Data diagnostics request.

#
encapsulated_interface

fn encapsulated_interface(unit_id : Byte, mei_type : Byte, payload : Array[Byte]) -> Result[Frame, ModbusError]

Build a generic encapsulated-interface request (function 43).

#
encode_ascii

fn encode_ascii(frame : Frame) -> Array[Byte]

Encode a frame as Modbus ASCII, including : prefix and CRLF suffix.

#
encode_device_identification

fn encode_device_identification(unit_id : Byte, category : DeviceIdCategory, conformity : Byte, more_follows : Bool, next_object_id : Byte, objects : Array[DeviceIdObject]) -> Result[Frame, ModbusError]

Encode an identification response from typed objects.

#
encode_hex

fn encode_hex(bytes : Array[Byte]) -> Array[Byte]

Encode an owned byte array as uppercase hexadecimal ASCII.

#
encode_mode

fn encode_mode(mode : Mode, frame : Frame) -> Array[Byte]

Encode a frame for a mode; TCP uses transaction id zero for this convenience API.

#
encode_rtu

fn encode_rtu(frame : Frame) -> Array[Byte]

Encode a frame as Modbus RTU.

#
encode_tcp

fn encode_tcp(transaction_id : UInt16, frame : Frame) -> Array[Byte]

Encode a frame as Modbus TCP, using a caller-provided transaction id.

#
encoded_length

fn encoded_length(mode : Mode, frame : Frame) -> Int

Return the encoded size of a frame on a transport.

#
endpoint_health

fn endpoint_health(device : Device, metrics : ProtocolMetrics) -> EndpointHealth

#
endpoint_health_summary

fn endpoint_health_summary(health : EndpointHealth) -> String

Summarize health in stable key/value form for a CLI or metrics exporter.

#
endpoint_score

fn endpoint_score(health : EndpointHealth) -> Int

Return a score in [0, 100] suitable for a small status indicator.

#
error_name

fn error_name(error : ModbusError) -> String

Convert a protocol error to a stable diagnostic name.

#
error_or_unit

fn error_or_unit(result : Result[Unit, ModbusError]) -> String

#
error_response

fn error_response(request : Frame, error : ModbusError) -> Frame

Construct an exception from a protocol error.

#
exception_code

fn exception_code(value : Byte) -> ExceptionCode

#
exception_for_error

fn exception_for_error(error : ModbusError) -> ExceptionCode

#
exception_from_frame

fn exception_from_frame(frame : Frame) -> Result[ExceptionCode, ModbusError]

Decode the exception code from a standard exception response.

#
exception_response

fn exception_response(unit_id : Byte, function : Byte, code : Byte) -> Frame

Build a standard Modbus exception response.

#
expected_response_function

fn expected_response_function(request : Frame) -> Byte

Return the expected response function byte for a request.

#
expected_tcp_length

fn expected_tcp_length(bytes : Array[Byte]) -> Result[Int, ModbusError]

Return the expected TCP ADU size from a partial header.

#
f32_to_registers

fn f32_to_registers(value : Float, word_order : RegisterWordOrder) -> Array[UInt16]

Encode a Float in IEEE-754 binary32 form as two registers.

#
fault_mode_name

fn fault_mode_name(mode : FaultMode) -> String

#
fits_mode_limit

fn fits_mode_limit(mode : Mode, frame : Frame) -> Bool

Return whether a frame can be represented by a mode's ADU limit.

#
fits_queue_budget

fn fits_queue_budget(frames : Array[Frame], mode : Mode, budget : Int) -> Bool

Check that an entire sequence stays below a caller's queue budget.

#
fleet_score

fn fleet_score(health : Array[EndpointHealth]) -> Int

Compute an overall score for a fleet of devices.

#
float_words

fn float_words(high : UInt16, low : UInt16) -> UInt64

Decode two registers as the raw IEEE-754 single precision words.

#
format_error

fn format_error(error : ModbusError) -> String

Produce a one-line protocol error for a CLI diagnostic.

#
format_frame

fn format_frame(frame : Frame) -> String

Format a complete frame for logs without exposing transport framing.

#
format_wire_frame

fn format_wire_frame(mode : Mode, transaction_id : UInt16, frame : Frame) -> String

Format a frame with its RTU, ASCII, or TCP wire representation.

#
frame_budget_available

fn frame_budget_available(mode : Mode, frame : Frame, budget : Int) -> Bool

#
frame_count_for_coils

fn frame_count_for_coils(quantity : Int) -> Result[Int, ModbusError]

Calculate the number of frames needed for a logical coil read.

#
frame_count_for_registers

fn frame_count_for_registers(quantity : Int) -> Result[Int, ModbusError]

Calculate the number of frames needed for a logical register read.

#
frame_data_copy

fn frame_data_copy(frame : Frame) -> Array[Byte]

#
frame_is_empty

fn frame_is_empty(frame : Frame) -> Bool

#
frame_is_valid

fn frame_is_valid(frame : Frame) -> Bool

#
frame_with_data_copy

fn frame_with_data_copy(frame : Frame, data : Array[Byte]) -> Frame

#
frames_equal

fn frames_equal(left : Frame, right : Frame) -> Bool

Compare frames at the logical PDU level.

#
function_catalog

fn function_catalog() -> Array[FunctionDescriptor]

Return every descriptor in numeric order.

#
function_code

fn function_code(value : Byte) -> FunctionCode

Convert a function code byte into the typed function-code vocabulary.

#
function_descriptor

fn function_descriptor(function : Byte) -> FunctionDescriptor?

#
function_name

fn function_name(function : Byte) -> String

Human-readable function-code name used by diagnostic output.

#
gateway_function_supported

fn gateway_function_supported(function : Byte) -> Bool

Return whether a gateway rule can safely carry a function code.

#
get_bit

fn get_bit(bytes : Array[Byte], index : Int) -> Result[Bool, ModbusError]

Read a single bit from a packed byte array.

#
get_comm_event_counter

fn get_comm_event_counter(unit_id : Byte) -> Result[Frame, ModbusError]

Build a request for the communication event counter (function 11).

#
get_comm_event_log

fn get_comm_event_log(unit_id : Byte) -> Result[Frame, ModbusError]

Build a request for the communication event log (function 12).

#
hex_string_to_bytes

fn hex_string_to_bytes(text : String) -> Result[Array[Byte], ModbusError]

Convert a string containing hexadecimal digits and optional whitespace to bytes.

#
i32_to_registers

fn i32_to_registers(value : Int, word_order : RegisterWordOrder) -> Array[UInt16]

Encode a signed 32-bit value using two's-complement bits.

#
is_broadcast

fn is_broadcast(unit_id : Byte) -> Bool

True when the frame uses the serial-line broadcast address.

#
is_client_input_error

fn is_client_input_error(error : ModbusError) -> Bool

#
is_exception

fn is_exception(frame : Frame) -> Bool

Whether a PDU is an exception response.

#
is_read_function

fn is_read_function(function : Byte) -> Bool

#
is_retryable

fn is_retryable(error : ModbusError) -> Bool

Return whether an error is recoverable by a retry policy.

#
is_supported_mode

fn is_supported_mode(mode : Mode) -> Bool

#
is_transport_error

fn is_transport_error(error : ModbusError) -> Bool

#
is_valid_unit_id

fn is_valid_unit_id(unit_id : Byte, broadcast? : Bool) -> Bool

True for a legal serial-line unit identifier, including broadcast.

#
is_write_echo

fn is_write_echo(request : Frame, response : Frame) -> Bool

Check an ordinary write response without decoding its fields.

#
is_write_function

fn is_write_function(function : Byte) -> Bool

#
join_chunks

fn join_chunks(chunks : Array[Array[Byte]], max_length : Int) -> Result[Array[Byte], ModbusError]

Reassemble byte chunks and check their total size.

#
least_healthy

fn least_healthy(health : Array[EndpointHealth]) -> EndpointHealth?

Return the least healthy endpoint, if any.

#
limits_for

fn limits_for(mode : Mode) -> ProtocolLimits

#
lrc

fn lrc(bytes : Array[Byte]) -> Byte

LRC used by Modbus ASCII.

#
lrc_from_sum

fn lrc_from_sum(sum : Byte) -> Byte

Compute the LRC from a running sum, using the Modbus two's-complement rule.

#
lrc_with_sum

fn lrc_with_sum(bytes : Array[Byte]) -> (Byte, Byte)

Return both the LRC and the modulo-256 sum for diagnostics.

#
mask_write_register

fn mask_write_register(unit_id : Byte, address : UInt16, and_mask : UInt16, or_mask : UInt16) -> Result[Frame, ModbusError]

Build a mask-write-register request (function 22).

#
max_request_adu

fn max_request_adu(mode : Mode, function : Byte) -> Int

Return a conservative maximum request size for a function and mode.

#
minimum_frame_length

fn minimum_frame_length(mode : Mode) -> Int

Calculate how many bytes are needed for the shortest frame of a mode.

#
mode_description

fn mode_description(mode : Mode) -> String

#
mode_name

fn mode_name(mode : Mode) -> String

Return the stable display name of a transport mode.

#
mode_payload_capacity

fn mode_payload_capacity(mode : Mode) -> Int

Return the number of data bytes available after transport framing.

#
offset_frame_address

fn offset_frame_address(frame : Frame, delta : Int) -> Result[Frame, ModbusError]

Add a signed address offset while preserving 16-bit bounds.

#
ordinary_function

fn ordinary_function(function : Byte) -> Byte

Return the ordinary function code for an exception response.

#
pack_bits

fn pack_bits(values : Array[Bool]) -> Array[Byte]

Pack boolean values into Modbus LSB-first coil bytes.

#
parse_hex_byte

fn parse_hex_byte(high : Byte, low : Byte) -> Result[Byte, ModbusError]

Convert one ASCII hex byte into a binary byte.

#
parse_wire_frame

fn parse_wire_frame(mode : Mode, text : String) -> Result[(UInt16, Frame), ModbusError]

Parse a wire representation in the selected mode.

#
parser_load

fn parser_load(parser : IncrementalParser) -> Int

Return the number of bytes currently held across parser metrics.

#
payload_is_bounded

fn payload_is_bounded(mode : Mode, size : Int) -> Bool

#
pdu_bytes

fn pdu_bytes(frame : Frame) -> Array[Byte]

Return the PDU bytes following the unit identifier.

#
pdus_equal

fn pdus_equal(left : Pdu, right : Pdu) -> Bool

#
plan_read_coils

fn plan_read_coils(unit_id : Byte, address : UInt16, quantity : Int, discrete? : Bool) -> Result[Array[PlannedRequest], ModbusError]

#
plan_read_registers

fn plan_read_registers(unit_id : Byte, address : UInt16, quantity : Int, function? : Byte) -> Result[Array[PlannedRequest], ModbusError]

#
plan_write_registers

fn plan_write_registers(unit_id : Byte, address : UInt16, values : Array[UInt16]) -> Result[Array[PlannedRequest], ModbusError]

Plan a write block, respecting the protocol's maximum register quantity.

#
preflight_device

fn preflight_device(report : PreflightReport, device : Device) -> Unit

Check a device's table capacities and unit id.

#
preflight_frame

fn preflight_frame(report : PreflightReport, mode : Mode, frame : Frame) -> Unit

Check a frame's unit, PDU shape, and transport envelope constraints.

#
preflight_plan

fn preflight_plan(report : PreflightReport, plan : PollPlan, mode : Mode) -> Unit

Check every job in a polling plan.

#
preflight_server

fn preflight_server(server : Server) -> PreflightReport

Validate a complete server configuration and its registered devices.

#
preflight_summary

fn preflight_summary(report : PreflightReport) -> String

Return a compact result line for CI logs.

#
quantity_bytes_checked

fn quantity_bytes_checked(quantity : UInt16) -> Array[Byte]

Make a quantity representation used by request builders.

#
read_coils

fn read_coils(unit_id : Byte, address : UInt16, quantity : UInt16) -> Result[Frame, ModbusError]

Build a read-coils request (function 01).

#
read_device_identification

fn read_device_identification(unit_id : Byte, category : DeviceIdCategory, object_id : Byte) -> Result[Frame, ModbusError]

Build a Read Device Identification request.

#
read_discrete_inputs

fn read_discrete_inputs(unit_id : Byte, address : UInt16, quantity : UInt16) -> Result[Frame, ModbusError]

Build a read-discrete-inputs request (function 02).

#
read_exception_status

fn read_exception_status(unit_id : Byte) -> Result[Frame, ModbusError]

Build a request for the exception status byte (function 07).

#
read_fifo_queue

fn read_fifo_queue(unit_id : Byte, address : UInt16) -> Result[Frame, ModbusError]

Build a Read FIFO Queue request (function 24).

#
read_file_record

fn read_file_record(unit_id : Byte, references : Array[FileRecordReference]) -> Result[Frame, ModbusError]

Build a Read File Record request (function 20).

#
read_holding

fn read_holding(unit_id : Byte, address : UInt16, quantity : UInt16) -> Frame

A request for reading holding registers (function 03).

#
read_holding_checked

fn read_holding_checked(unit_id : Byte, address : UInt16, quantity : UInt16) -> Result[Frame, ModbusError]

Checked variant of read_holding for application code.

#
read_holding_registers

fn read_holding_registers(unit_id : Byte, address : UInt16, quantity : UInt16) -> Result[Frame, ModbusError]

Build a read-holding-registers request (function 03).

#
read_input_registers

fn read_input_registers(unit_id : Byte, address : UInt16, quantity : UInt16) -> Result[Frame, ModbusError]

Build a read-input-registers request (function 04).

#
read_quantity_limit

fn read_quantity_limit(function : Byte) -> Int

Return the maximum legal request quantity for a read function.

#
read_u16_be

fn read_u16_be(bytes : Array[Byte], offset : Int) -> Result[UInt16, ModbusError]

Read a big-endian unsigned 16-bit value from a byte array.

#
read_u32_be

fn read_u32_be(bytes : Array[Byte], offset : Int) -> Result[UInt, ModbusError]

Read a big-endian unsigned 32-bit value using MoonBit's platform unsigned type.

#
read_write_multiple_registers

fn read_write_multiple_registers(unit_id : Byte, read_address : UInt16, read_quantity : UInt16, write_address : UInt16, write_values : Array[UInt16]) -> Result[Frame, ModbusError]

Build a combined read/write-multiple-registers request (function 23).
fn recommended_parser_role(function : Byte) -> ParserRole

Return the recommended parser role for a function family.

#
register_byte_order_name

fn register_byte_order_name(order : RegisterByteOrder) -> String

#
register_to_bytes

fn register_to_bytes(value : UInt16, order : RegisterByteOrder) -> Array[Byte]

Convert one register to two bytes in the requested byte order.

#
register_value_name

fn register_value_name(value : RegisterValue) -> String

Render a typed value as a compact diagnostic string.

#
register_word_order_name

fn register_word_order_name(order : RegisterWordOrder) -> String

#
registers

fn registers(frame : Frame) -> Result[Array[UInt16], ModbusError]

Decode the data portion of a register-oriented frame without a byte count.

#
registers_to_bytes

fn registers_to_bytes(values : Array[UInt16], order : RegisterByteOrder) -> Array[Byte]

Convert an array of registers to bytes with a selected byte order.

#
registers_to_f32

fn registers_to_f32(values : Array[UInt16], word_order : RegisterWordOrder) -> Result[Float, ModbusError]

Decode two registers as an IEEE-754 binary32 Float.

#
registers_to_i32

fn registers_to_i32(values : Array[UInt16], word_order : RegisterWordOrder) -> Result[Int, ModbusError]

Decode a signed 32-bit value from two registers.

#
registers_to_u32

fn registers_to_u32(values : Array[UInt16], word_order : RegisterWordOrder) -> Result[UInt, ModbusError]

Decode two registers as an unsigned 32-bit value.

#
registers_to_u64

fn registers_to_u64(values : Array[UInt16], word_order : RegisterWordOrder) -> Result[UInt64, ModbusError]

Decode four registers as a 64-bit value.

#
replace_frame_unit

fn replace_frame_unit(frame : Frame, unit_id : Byte) -> Result[Frame, ModbusError]

#
report_server_id

fn report_server_id(unit_id : Byte) -> Result[Frame, ModbusError]

Build a Report Server ID request (function 17).

#
response_frame

fn response_frame(request : Frame, data : Array[Byte]) -> Frame

Construct a response with an explicit function and owned data array.

#
response_payload_length

fn response_payload_length(frame : Frame) -> Int

#
response_quality

fn response_quality(request : Frame, response : Frame) -> String

Return a short response quality classification for metrics.

#
response_timeout_hint

fn response_timeout_hint(mode : Mode) -> Int

#
response_value

fn response_value(frame : Frame) -> ResponseValue

#
retry_limit_for

fn retry_limit_for(mode : Mode) -> Int

#
reverse_registers

fn reverse_registers(values : Array[UInt16]) -> Array[UInt16]

Reverse register order in a copied array.

#
round_trip_all_modes

fn round_trip_all_modes(frame : Frame) -> Result[Array[Frame], ModbusError]

Run the same frame through every transport codec.

#
round_trip_vectors

fn round_trip_vectors(frame : Frame) -> Array[ConformanceVector]

Build protocol vectors from a known request in all three transports.

#
rtu_mode

fn rtu_mode() -> Mode

Standard constructors kept as named entry points for configuration files.

#
rtu_payload

fn rtu_payload(frame : Frame) -> Array[Byte]

Return the RTU payload before its two-byte CRC.

#
safe_address

fn safe_address(value : UInt16, quantity : Int) -> Result[Unit, ModbusError]

#
safe_byte_at

fn safe_byte_at(bytes : Array[Byte], index : Int) -> Result[Byte, ModbusError]

#
safe_quantity

fn safe_quantity(value : UInt16, limit : Int) -> Result[Int, ModbusError]

#
set_bit

fn set_bit(bytes : Array[Byte], index : Int, value : Bool) -> Result[Unit, ModbusError]

Set a single bit in a packed byte array.

#
should_retry

fn should_retry(mode : Mode, error : ModbusError) -> Bool

#
signed_register

fn signed_register(value : UInt16) -> Int

Decode a signed 16-bit register using two's-complement representation.

#
simulation_failures

fn simulation_failures(results : Array[SimulationResult]) -> Int

#
simulation_successes

fn simulation_successes(results : Array[SimulationResult]) -> Int

Count successful deliveries in a scenario result.

#
summarize

fn summarize(frame : Frame) -> FrameSummary

#
summarize_plan

fn summarize_plan(items : Array[PlannedRequest]) -> PlanSummary

#
supported_function

fn supported_function(function : Byte) -> Bool

Check that a function code is in the supported public subset.

#
swap_register_bytes

fn swap_register_bytes(values : Array[UInt16]) -> Array[UInt16]

Rotate bytes inside every register, useful for devices with byte-swapped words.

#
tcp_mode

fn tcp_mode() -> Mode

#
transport_is_network

fn transport_is_network(mode : Mode) -> Bool

#
transport_is_serial

fn transport_is_serial(mode : Mode) -> Bool

#
transport_kind_mode

fn transport_kind_mode(kind : TransportKind) -> Mode

#
transport_kind_name

fn transport_kind_name(kind : TransportKind) -> String

#
try_encode_ascii

fn try_encode_ascii(frame : Frame) -> Result[Array[Byte], ModbusError]

Checked ASCII encoder.

#
try_encode_mode

fn try_encode_mode(mode : Mode, transaction_id : UInt16, frame : Frame) -> Result[Array[Byte], ModbusError]

Checked transport encoder with an explicit TCP transaction id.

#
try_encode_rtu

fn try_encode_rtu(frame : Frame) -> Result[Array[Byte], ModbusError]

Checked RTU encoder for code that wants validation errors instead of a raw frame.

#
try_encode_tcp

fn try_encode_tcp(transaction_id : UInt16, frame : Frame) -> Result[Array[Byte], ModbusError]

Checked TCP encoder.

#
typed_exception_response

fn typed_exception_response(unit_id : Byte, function : Byte, code : ExceptionCode) -> Frame

Build a typed exception response.

#
u32_to_registers

fn u32_to_registers(value : UInt, word_order : RegisterWordOrder) -> Array[UInt16]

Encode an unsigned 32-bit value into two registers.

#
u64_to_registers

fn u64_to_registers(value : UInt64, word_order : RegisterWordOrder) -> Array[UInt16]

Encode a 64-bit value into four registers.

#
unpack_bits

fn unpack_bits(bytes : Array[Byte], quantity : Int) -> Result[Array[Bool], ModbusError]

Unpack exactly quantity coil values from LSB-first bytes.

#
valid_address_range

fn valid_address_range(address : UInt16, quantity : Int) -> Bool

Check whether an address/count pair fits in the 16-bit Modbus address space.

#
validate_catalog_request

fn validate_catalog_request(frame : Frame) -> Result[Unit, ModbusError]

Validate a request against the catalog before invoking a builder.

#
validate_endpoint

fn validate_endpoint(config : EndpointConfig) -> Result[Unit, ModbusError]

#
validate_endpoint_health

fn validate_endpoint_health(health : EndpointHealth) -> Result[Unit, ModbusError]

Validate that endpoint counters are internally consistent.

#
validate_frame

fn validate_frame(frame : Frame, allow_broadcast : Bool) -> Result[Unit, ModbusError]

Validate a complete logical frame before encoding it on any transport.

#
validate_mode_payload

fn validate_mode_payload(mode : Mode, data_length : Int) -> Result[Unit, ModbusError]

#
validate_pdu

fn validate_pdu(pdu : Pdu) -> Result[Unit, ModbusError]

Validate a request PDU's byte-level shape and protocol limits.

#
validate_plan_order

fn validate_plan_order(items : Array[PlannedRequest]) -> Result[Unit, ModbusError]

Validate that planned ranges are ordered and non-overlapping.

#
validate_poll_plan

fn validate_poll_plan(plan : PollPlan) -> Result[Unit, ModbusError]

Validate plan timing invariants before deployment.

#
validate_response_header

fn validate_response_header(request : Frame, response : Frame) -> Result[Unit, ModbusError]

Validate the common unit/function relationship of a response.

#
validate_server_config

fn validate_server_config(config : ServerConfig) -> Result[Unit, ModbusError]

#
validate_unit

fn validate_unit(unit_id : Byte, allow_broadcast : Bool) -> Result[Unit, ModbusError]

Validate a unit identifier for a request.

#
validate_wire_frame

fn validate_wire_frame(frame : Frame, allow_broadcast : Bool) -> Result[Unit, ModbusError]

Validate a frame for wire encoding without assuming request-only payload shapes.

#
validate_write_shape

fn validate_write_shape(function : Byte, quantity : Int) -> Result[Unit, ModbusError]

Check whether a write payload is legal before allocating its data array.

#
variable_response_function_names

fn variable_response_function_names() -> Array[String]

Return the names of all functions whose response contains a byte count.

#
verify_crc16

fn verify_crc16(bytes : Array[Byte]) -> Result[Unit, ModbusError]

Verify a CRC16 trailer in low-byte-first wire order.

#
verify_lrc

fn verify_lrc(bytes : Array[Byte]) -> Result[Unit, ModbusError]

Verify an LRC trailer at the end of a byte array.

#
with_data

fn with_data(frame : Frame, data : Array[Byte]) -> Frame

Return a copy of a frame with a different data payload.

#
with_function

fn with_function(frame : Frame, function : Byte) -> Frame

Return a copy of a frame with a different function code.

#
with_unit

fn with_unit(frame : Frame, unit_id : Byte) -> Frame

Return a copy of a frame with a different unit identifier.

#
writable_function_names

fn writable_function_names() -> Array[String]

Return the names of all writable functions.

#
write_file_record

fn write_file_record(unit_id : Byte, records : Array[FileRecordWrite]) -> Result[Frame, ModbusError]

Build a Write File Record request (function 21).

#
write_multiple_coils

fn write_multiple_coils(unit_id : Byte, address : UInt16, values : Array[Bool]) -> Result[Frame, ModbusError]

Build a write-multiple-coils request (function 15).

#
write_multiple_registers

fn write_multiple_registers(unit_id : Byte, address : UInt16, values : Array[UInt16]) -> Result[Frame, ModbusError]

Build a write-multiple-registers request (function 16).

#
write_quantity_limit

fn write_quantity_limit(function : Byte) -> Int

Return the maximum legal write quantity for a write-multiple function.

#
write_single_coil

fn write_single_coil(unit_id : Byte, address : UInt16, value : Bool) -> Result[Frame, ModbusError]

Build a write-single-coil request (function 05).

#
write_single_register

fn write_single_register(unit_id : Byte, address : UInt16, value : UInt16) -> Frame

A request for writing one holding register (function 06).

#
write_single_register_checked

fn write_single_register_checked(unit_id : Byte, address : UInt16, value : UInt16) -> Result[Frame, ModbusError]

Build a write-single-register request (function 06) with validation.