modbus

package module
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2026 License: MIT Imports: 17 Imported by: 0

README

github.com/boeboe/modbus

A production-ready Go implementation of the Modbus application protocol — v2.0.0.

The library exposes a high-level, idiomatic Go API for both client and server roles, working with native Go types across all supported transports. Every request carries a context.Context for cancellation and deadline propagation. Advanced features — connection pooling, automatic retries, structured logging, and metrics hooks — are built in.

For the complete type signatures, configuration options, and runnable examples see API.md.


Table of Contents


Install

go get github.com/boeboe/modbus

Requires Go 1.21 or later.


Transport modes

The transport is selected by the scheme://address URL in ClientConfiguration.URL or ServerConfiguration.URL.

Scheme Transport Client Server
tcp://<host:port> Modbus TCP (MBAP)
tcp+tls://<host:port> Modbus TCP over TLS (MBAPS / Modbus Security)
udp://<host:port> Modbus TCP framing over UDP
rtu://<device> Modbus RTU over serial (RS-232 / RS-485)
rtuovertcp://<host:port> Modbus RTU framing tunnelled over TCP
rtuoverudp://<host:port> Modbus RTU framing tunnelled over UDP

Note: UDP transports are not part of the official Modbus specification. Both MBAP-over-UDP (udp://) and RTU-over-UDP (rtuoverudp://) are provided because different vendors use different framing conventions. When unsure, try both.


Client

Client supported function codes

All client methods accept a context.Context as their first argument and a unitId uint8 (slave / unit ID) as their second, enabling per-request deadline and cancellation control independent of the connection lifecycle.

FC Hex Name Client method(s)
01 0x01 Read Coils ReadCoil, ReadCoils
02 0x02 Read Discrete Inputs ReadDiscreteInput, ReadDiscreteInputs
03 0x03 Read Holding Registers ReadRegister, ReadRegisters, ReadUint16(s), ReadInt16(s), ReadUint32(s), ReadInt32(s), ReadUint48(s), ReadInt48(s), ReadUint64(s), ReadInt64(s), ReadFloat32(s), ReadFloat64(s), ReadAscii, ReadAsciiReverse, ReadBCD, ReadPackedBCD, ReadBytes, ReadRawBytes
04 0x04 Read Input Registers same methods as FC03, passing InputRegister
05 0x05 Write Single Coil WriteCoil, WriteCoilValue
06 0x06 Write Single Register WriteRegister
15 0x0F Write Multiple Coils WriteCoils
16 0x10 Write Multiple Registers WriteRegisters, WriteUint32(s), WriteUint64(s), WriteFloat32(s), WriteFloat64(s), WriteBytes, WriteRawBytes
20 0x14 Read File Record ReadFileRecords
21 0x15 Write File Record WriteFileRecords
08 0x08 Diagnostics Diagnostics
11 0x11 Report Server ID ReportServerId
23 0x17 Read/Write Multiple Registers ReadWriteMultipleRegisters
24 0x18 Read FIFO Queue ReadFIFOQueue
43/14 0x2B/0x0E Read Device Identification ReadDeviceIdentification, ReadAllDeviceIdentification

Device detection: IsModbusDevice(ctx, unitId) probes the target with read-only, structurally validated requests (FC08, FC43, FC03, FC04, FC01, FC02) and returns whether the given unit ID responds with Modbus-compliant structure. Configurable via DetectionMode: DetectAggressive (default, full sequence), DetectStrict (FC08/FC43/FC03), DetectBasic (FC03 only). DetectUnitID(ctx) scans all 256 unit IDs (0–255) and returns every responding one. FingerprintDevice(ctx, unitId) records which FCs the device supports. See API.md.

Supported Go types
Modbus data model Go types
Coils / discrete inputs bool, []bool
16-bit registers uint16, []uint16, int16, []int16
32-bit registers (2 × 16-bit) uint32, []uint32, int32, []int32, float32, []float32
48-bit registers (3 × 16-bit) uint64, []uint64 (unsigned), int64, []int64 (signed)
64-bit registers (4 × 16-bit) uint64, []uint64, int64, []int64, float64, []float64
ASCII string (N × 16-bit) string (trailing spaces stripped)
BCD / Packed BCD (N × 16-bit) string (decimal digits)
Raw wire bytes []byte (endianness-aware or unmodified)
File records []FileRecordRequest (read) / []FileRecord (write)
Encoding / byte order

SetEncoding(endianness, wordOrder) controls how multi-byte and multi-register values are decoded and encoded. Defaults to BigEndian, HighWordFirst. Changes apply to all subsequent requests on that client instance.

Setting Constants Meaning
Byte order BigEndian (default), LittleEndian Byte order within each 16-bit register
Word order HighWordFirst (default), LowWordFirst Which 16-bit word of a 32/64-bit value sits at the lower register address

Server

Server supported function codes

The server dispatches decoded requests to a user-provided RequestHandler implementation. All four handler methods cover the full set of supported function codes:

FC(s) Hex Name Handler method IsWrite
01 0x01 Read Coils HandleCoils false
02 0x02 Read Discrete Inputs HandleDiscreteInputs
03 0x03 Read Holding Registers HandleHoldingRegisters false
04 0x04 Read Input Registers HandleInputRegisters
05 0x05 Write Single Coil HandleCoils true
06 0x06 Write Single Register HandleHoldingRegisters true
15 0x0F Write Multiple Coils HandleCoils true
16 0x10 Write Multiple Registers HandleHoldingRegisters true

Returning a Modbus sentinel error (e.g. ErrIllegalDataAddress) causes the server to send the corresponding exception code back to the client. Any other non-nil error maps to ServerDeviceFailure.


Logging

Both ClientConfiguration and ServerConfiguration expose a Logger field. When nil, the library writes through slog.Default() — the Go standard structured logger.

Constructor Behaviour
NewStdLogger(l *log.Logger) Wraps a stdlib *log.Logger; pass nil for a default stdout logger
NewSlogLogger(h slog.Handler) Wraps any slog.Handler (e.g. slog.NewJSONHandler, slog.NewTextHandler)
NopLogger() Discards all output — useful in tests

The Logger interface is straightforward to implement for any custom logging library (zap, zerolog, logrus, …). See API.md § 5 for details and an adapter example.


Error handling

All client methods return a typed error. The library defines sentinel errors that can be tested with errors.Is:

Sentinel Cause
ErrConfigurationError Invalid configuration passed to NewClient / NewServer
ErrRequestTimedOut Request exceeded its deadline or configured timeout
ErrIllegalFunction Modbus exception 0x01
ErrIllegalDataAddress Modbus exception 0x02
ErrIllegalDataValue Modbus exception 0x03
ErrServerDeviceFailure Modbus exception 0x04
ErrAcknowledge Modbus exception 0x05
ErrServerDeviceBusy Modbus exception 0x06
ErrMemoryParityError Modbus exception 0x08
ErrGWPathUnavailable Modbus exception 0x0A
ErrGWTargetFailedToRespond Modbus exception 0x0B
ErrBadCRC RTU CRC mismatch
ErrShortFrame Frame too short to decode
ErrProtocolError Malformed or unexpected response
ErrBadUnitId Response unit ID does not match request
ErrBadTransactionId TCP transaction ID mismatch (MBAP)
ErrUnknownProtocolId Non-zero MBAP protocol identifier
ErrUnexpectedParameters Invalid arguments passed to a client method

When the remote device sends a Modbus exception response, the error is additionally wrapped in *ExceptionError, which carries the raw FunctionCode and ExceptionCode bytes. errors.As gives access to those fields while errors.Is still works against the sentinel:

var excErr *modbus.ExceptionError
if errors.As(err, &excErr) {
    fmt.Printf("fc=0x%02x exception=0x%02x\n", excErr.FunctionCode, excErr.ExceptionCode)
}
if errors.Is(err, modbus.ErrIllegalDataAddress) {
    // address does not exist on this device
}

See API.md § 4 for the full reference.


Advanced features

Retry policy

Configure automatic retry with exponential back-off on transient errors. The client re-dials the transport between attempts (or replaces the failed pool connection when pooling is enabled).

Set ClientConfiguration.RetryPolicy to one of the built-in implementations or provide a custom RetryPolicy implementation. See API.md § 7.

Connection pool

Set MaxConns > 1 to enable a bounded connection pool. Multiple goroutines sharing a single *ModbusClient can then execute requests concurrently, each on its own connection, without serialising on a single TCP socket.

MinConns controls how many connections are pre-warmed during Open(). Applies to TCP-based transports only; RTU (serial) always uses a single connection. See API.md § 8.

Metrics hooks

Implement ClientMetrics and/or ServerMetrics and assign them to the Metrics field of the respective configuration struct. Callbacks (OnRequest, OnResponse, OnError, OnTimeout) fire synchronously on every request outcome and must be non-blocking. See API.md § 6.


CLI client

A command-line Modbus client is included in cmd/modbus-cli.go:

go build -o modbus-cli cmd/modbus-cli.go
./modbus-cli --help

Examples

File Description
examples/tcp_server.go Modbus TCP server with an in-memory RequestHandler
examples/tls_server.go MBAPS (Modbus over TLS) server with client certificate authentication
examples/tls_client.go MBAPS client with mutual TLS

For the full public API reference — all types, method signatures, configuration details, and annotated examples — see API.md.


Dependencies


License

MIT.

Documentation

Index

Constants

View Source
const (
	ParityNone Parity = 0
	ParityEven Parity = 1
	ParityOdd  Parity = 2

	HoldingRegister RegType = 0
	InputRegister   RegType = 1

	// endianness of 16-bit registers.
	BigEndian    Endianness = 1
	LittleEndian Endianness = 2

	// word order of 32-bit registers.
	HighWordFirst WordOrder = 1
	LowWordFirst  WordOrder = 2
)
View Source
const (
	ReadDeviceIdBasic      = 0x01 // Basic: VendorName, ProductCode, MajorMinorRevision (mandatory)
	ReadDeviceIdRegular    = 0x02 // Regular: Basic + VendorUrl, ProductName, ModelName, UserApplicationName
	ReadDeviceIdExtended   = 0x03 // Extended: Regular + private/vendor objects (0x80–0xFF)
	ReadDeviceIdIndividual = 0x04 // Individual: request a single object by objectId
)

Read Device ID codes for FC43 (Read Device Identification). Use with ReadDeviceIdentification; ReadAllDeviceIdentification uses Extended internally.

Variables

View Source
var (
	ErrConfigurationError      = errors.New("modbus: configuration error")
	ErrRequestTimedOut         = errors.New("modbus: request timed out")
	ErrIllegalFunction         = errors.New("modbus: illegal function")
	ErrIllegalDataAddress      = errors.New("modbus: illegal data address")
	ErrIllegalDataValue        = errors.New("modbus: illegal data value")
	ErrServerDeviceFailure     = errors.New("modbus: server device failure")
	ErrAcknowledge             = errors.New("modbus: acknowledge")
	ErrServerDeviceBusy        = errors.New("modbus: server device busy")
	ErrMemoryParityError       = errors.New("modbus: memory parity error")
	ErrGWPathUnavailable       = errors.New("modbus: gateway path unavailable")
	ErrGWTargetFailedToRespond = errors.New("modbus: gateway target failed to respond")
	ErrBadCRC                  = errors.New("modbus: bad crc")
	ErrShortFrame              = errors.New("modbus: short frame")
	ErrProtocolError           = errors.New("modbus: protocol error")
	ErrBadUnitId               = errors.New("modbus: bad unit id")
	ErrBadTransactionId        = errors.New("modbus: bad transaction id")
	ErrUnknownProtocolId       = errors.New("modbus: unknown protocol identifier")
	ErrUnexpectedParameters    = errors.New("modbus: unexpected parameters")
)

Sentinel error variables. Use errors.Is to test for a specific condition; use errors.As with *ExceptionError to inspect Modbus exception details.

Functions

func LoadCertPool

func LoadCertPool(filePath string) (cp *x509.CertPool, err error)

LoadCertPool loads a certificate store from a file into a CertPool object.

Types

type ClientConfiguration

type ClientConfiguration struct {
	// URL sets the client mode and target location in the form
	// <mode>://<serial device or host:port> e.g. tcp://plc:502
	URL string
	// Speed sets the serial link speed (in bps, rtu only)
	Speed uint
	// DataBits sets the number of bits per serial character (rtu only)
	DataBits uint
	// Parity sets the serial link parity mode (rtu only)
	Parity Parity
	// StopBits sets the number of serial stop bits (rtu only)
	StopBits uint
	// Timeout sets the request timeout value
	Timeout time.Duration
	// TLSClientCert sets the client-side TLS key pair (tcp+tls only)
	TLSClientCert *tls.Certificate
	// TLSRootCAs sets the list of CA certificates used to authenticate
	// the server (tcp+tls only). Leaf (i.e. server) certificates can also
	// be used in case of self-signed certs, or if cert pinning is required.
	TLSRootCAs *x509.CertPool
	// Logger provides a custom sink for log messages.
	// If nil, the slog default logger (slog.Default()) is used.
	// Use NewStdLogger, NewSlogLogger, or NopLogger to build a value.
	Logger Logger

	// RetryPolicy controls whether and how failed requests are retried.
	// A nil RetryPolicy (the default) is equivalent to NoRetry() — errors are
	// returned to the caller immediately without any retry attempt.
	// Use ExponentialBackoff or NewExponentialBackoff to configure automatic retries.
	// On retry the client closes and re-dials the transport before each attempt;
	// when a connection pool is configured only the failed connection is replaced.
	RetryPolicy RetryPolicy

	// Metrics receives callbacks for every request outcome.
	// A nil Metrics (the default) disables metric collection.
	Metrics ClientMetrics

	// MinConns is the number of connections pre-warmed during Open().
	// Applies only to TCP-based transports (tcp, rtuovertcp, rtuoverudp, udp).
	// Zero disables pre-warming.
	MinConns int

	// MaxConns is the maximum number of concurrent connections maintained by the
	// internal connection pool. When > 1, multiple goroutines sharing a single
	// ModbusClient can execute requests concurrently, each on its own connection.
	// Applies only to TCP-based transports. Zero and 1 both mean a single connection
	// (no pool). Values greater than 1 allocate a pool of up to MaxConns connections.
	MaxConns int

	// DetectionMode controls which probes IsModbusDevice and DetectUnitID execute.
	// DetectAggressive (default, zero value) uses the full set: FC08, FC43, FC03, FC04, FC01, FC02.
	// DetectStrict uses FC08, FC43, FC03. DetectBasic uses FC03 only.
	DetectionMode DetectionMode
}

Modbus client configuration object.

type ClientMetrics

type ClientMetrics interface {
	// OnRequest is called immediately before the first attempt to send a request.
	// unitId and functionCode identify the target device and operation.
	OnRequest(unitId uint8, functionCode uint8)

	// OnResponse is called after a successful round-trip.
	// duration covers the total elapsed time including any retry delays.
	OnResponse(unitId uint8, functionCode uint8, duration time.Duration)

	// OnError is called when a request ultimately fails with a non-timeout error
	// (after all retry attempts are exhausted).
	// duration covers the total elapsed time including any retry delays.
	OnError(unitId uint8, functionCode uint8, duration time.Duration, err error)

	// OnTimeout is called when a request ultimately fails because it exceeded
	// its deadline (errors.Is(err, ErrRequestTimedOut) or context deadline exceeded).
	// duration covers the total elapsed time including any retry delays.
	OnTimeout(unitId uint8, functionCode uint8, duration time.Duration)
}

ClientMetrics is an optional callback interface for observing client-side request outcomes. All methods are called synchronously in the goroutine executing the request; implementations must be non-blocking (e.g. increment an atomic counter, send on a buffered channel). A nil ClientMetrics is valid and disables collection.

type CoilsRequest

type CoilsRequest struct {
	ClientAddr string // the source (client) IP address
	ClientRole string // the client role as encoded in the client certificate (tcp+tls only)
	UnitId     uint8  // the requested unit id (slave id)
	Addr       uint16 // the base coil address requested
	Quantity   uint16 // the number of consecutive coils covered by this request
	// (first address: Addr, last address: Addr + Quantity - 1)
	IsWrite bool   // true if the request is a write, false if a read
	Args    []bool // a slice of bool values of the coils to be set, ordered

}

Request object passed to the coil handler.

type DetectionMode added in v1.0.3

type DetectionMode int

DetectionMode controls the probe sequence used by IsModbusDevice. The zero value (DetectAggressive) uses the full probe set for maximum coverage.

const (
	// DetectAggressive uses the full probe sequence: FC08, FC43, FC03, FC04, FC01, FC02.
	// This is the default (zero value) and provides the highest detection confidence.
	DetectAggressive DetectionMode = iota
	// DetectStrict uses a reduced probe set: FC08, FC43, FC03.
	// Good balance between speed and coverage.
	DetectStrict
	// DetectBasic uses only FC03 (Read Holding Registers, addr 0, qty 1).
	// Fastest but may miss devices that don't implement FC03.
	DetectBasic
)

type DeviceIdentification

type DeviceIdentification struct {
	ReadDeviceIdCode uint8
	ConformityLevel  uint8
	MoreFollows      uint8
	NextObjectId     uint8
	Objects          []DeviceIdentificationObject
}

DeviceIdentification groups all decoded data from an FC43/MEI response.

type DeviceIdentificationObject

type DeviceIdentificationObject struct {
	Id    uint8
	Name  string
	Value string
}

DeviceIdentificationObject represents one object from an FC43/MEI response.

type DiagnosticResponse added in v1.0.3

type DiagnosticResponse struct {
	SubFunction DiagnosticSubFunction
	Data        []byte
}

DiagnosticResponse is the response from Diagnostics (FC 0x08). SubFunction is echoed from the request; Data is the sub-function-specific data (e.g. loopback data, diagnostic register value).

type DiagnosticSubFunction added in v1.0.3

type DiagnosticSubFunction uint16

DiagnosticSubFunction is the two-byte sub-function code for Diagnostics (FC 0x08). Use the constants below for well-known sub-functions; raw uint16 values are valid.

const (
	DiagReturnQueryData                  DiagnosticSubFunction = 0x0000 // Loopback request data
	DiagRestartCommunications            DiagnosticSubFunction = 0x0001
	DiagReturnDiagnosticRegister         DiagnosticSubFunction = 0x0002
	DiagChangeASCIIInputDelimiter        DiagnosticSubFunction = 0x0003
	DiagForceListenOnlyMode              DiagnosticSubFunction = 0x0004
	DiagClearCountersAndDiagnosticReg    DiagnosticSubFunction = 0x000A
	DiagReturnBusMessageCount            DiagnosticSubFunction = 0x000B
	DiagReturnBusCommunicationErrorCount DiagnosticSubFunction = 0x000C
	DiagReturnBusExceptionErrorCount     DiagnosticSubFunction = 0x000D
	DiagReturnServerMessageCount         DiagnosticSubFunction = 0x000E
	DiagReturnServerNoResponseCount      DiagnosticSubFunction = 0x000F
	DiagReturnServerNAKCount             DiagnosticSubFunction = 0x0010
	DiagReturnServerBusyCount            DiagnosticSubFunction = 0x0011
	DiagReturnBusCharacterOverrunCount   DiagnosticSubFunction = 0x0012
	DiagClearOverrunCounterAndFlag       DiagnosticSubFunction = 0x0014
)

func (DiagnosticSubFunction) String added in v1.0.3

func (s DiagnosticSubFunction) String() string

String returns a short name for the sub-function for logging and debugging.

type DiscreteInputsRequest

type DiscreteInputsRequest struct {
	ClientAddr string // the source (client) IP address
	ClientRole string // the client role as encoded in the client certificate (tcp+tls only)
	UnitId     uint8  // the requested unit id (slave id)
	Addr       uint16 // the base discrete input address requested
	Quantity   uint16 // the number of consecutive discrete inputs covered by this request
}

Request object passed to the discrete input handler.

type Endianness

type Endianness uint

type ExceptionError

type ExceptionError struct {
	FunctionCode  byte  // originating Modbus function code (high bit clear)
	ExceptionCode byte  // raw Modbus exception code (0x01–0x0b)
	Sentinel      error // one of the Err* sentinel variables below
}

ExceptionError is returned by client methods when the remote device responds with a Modbus exception. It gives callers structured access to the raw function and exception codes while remaining compatible with errors.Is / errors.As:

var excErr *modbus.ExceptionError
if errors.As(err, &excErr) {
    fmt.Printf("fc=0x%02x exception=0x%02x\n", excErr.FunctionCode, excErr.ExceptionCode)
}
if errors.Is(err, modbus.ErrIllegalDataAddress) { ... }

func (*ExceptionError) Error

func (e *ExceptionError) Error() string

func (*ExceptionError) Is

func (e *ExceptionError) Is(target error) bool

func (*ExceptionError) Unwrap

func (e *ExceptionError) Unwrap() error

type ExponentialBackoffConfig

type ExponentialBackoffConfig struct {
	// BaseDelay is the wait after the first failure; doubles each subsequent attempt.
	// Defaults to 100 ms when zero.
	BaseDelay time.Duration

	// MaxDelay caps the computed delay. Defaults to 30 s when zero.
	MaxDelay time.Duration

	// MaxAttempts is the maximum number of retries (not counting the original attempt).
	// Zero means unlimited retries — use with care; always pass a context with a deadline.
	MaxAttempts int

	// RetryOnTimeout controls whether ErrRequestTimedOut triggers a retry.
	// Default false: timed-out requests are NOT retried (the deadline has already elapsed).
	RetryOnTimeout bool
}

ExponentialBackoffConfig is the full configuration set for exponential back-off.

type FileRecord

type FileRecord struct {
	FileNumber   uint16   // file number (1–0xFFFF)
	RecordNumber uint16   // starting record number within the file (0–0x270F)
	Data         []uint16 // register values to write (len gives record length)
}

FileRecord describes one sub-request for WriteFileRecords (FC21). Each record writes a contiguous slice of registers to a single file. The record length is implied by len(Data).

type FileRecordRequest

type FileRecordRequest struct {
	FileNumber   uint16 // file number (1–0xFFFF)
	RecordNumber uint16 // starting record number within the file (0–0x270F)
	RecordLength uint16 // number of 16-bit registers to read (≥ 1)
}

FileRecordRequest describes one sub-request for ReadFileRecords (FC20). Each sub-request reads a contiguous slice of registers from a single file.

type HoldingRegistersRequest

type HoldingRegistersRequest struct {
	ClientAddr string   // the source (client) IP address
	ClientRole string   // the client role as encoded in the client certificate (tcp+tls only)
	UnitId     uint8    // the requested unit id (slave id)
	Addr       uint16   // the base register address requested
	Quantity   uint16   // the number of consecutive registers covered by this request
	IsWrite    bool     // true if the request is a write, false if a read
	Args       []uint16 // a slice of register values to be set, ordered from

}

Request object passed to the holding register handler.

type InputRegistersRequest

type InputRegistersRequest struct {
	ClientAddr string // the source (client) IP address
	ClientRole string // the client role as encoded in the client certificate (tcp+tls only)
	UnitId     uint8  // the requested unit id (slave id)
	Addr       uint16 // the base register address requested
	Quantity   uint16 // the number of consecutive registers covered by this request
}

Request object passed to the input register handler.

type Logger

type Logger interface {
	Debugf(format string, args ...any)
	Infof(format string, args ...any)
	Warnf(format string, args ...any)
	Errorf(format string, args ...any)
}

Logger is the logging interface accepted by ClientConfiguration and ServerConfiguration. Implement this interface to integrate any structured or levelled logging library (e.g. zap, zerolog, slog, logrus).

func NewSlogLogger

func NewSlogLogger(h slog.Handler) Logger

NewSlogLogger wraps a slog.Handler so it satisfies the Logger interface. Use slog.NewJSONHandler, slog.NewTextHandler, or any third-party handler.

func NewStdLogger

func NewStdLogger(l *log.Logger) Logger

NewStdLogger wraps a stdlib *log.Logger so it satisfies the Logger interface. If l is nil, output is written to os.Stdout with no flags.

func NopLogger

func NopLogger() Logger

NopLogger returns a Logger that discards all log output. Useful in tests or when logging is intentionally disabled.

type ModbusClient

type ModbusClient struct {
	// contains filtered or unexported fields
}

Modbus client object.

func NewClient

func NewClient(conf *ClientConfiguration) (mc *ModbusClient, err error)

NewClient creates, configures and returns a modbus client object.

func (*ModbusClient) Close

func (mc *ModbusClient) Close() (err error)

Closes the underlying transport (or connection pool).

func (*ModbusClient) DetectUnitID added in v1.0.3

func (mc *ModbusClient) DetectUnitID(ctx context.Context) ([]uint8, error)

DetectUnitID scans the full unit-ID range (0–255) and returns every unit ID that responds with a valid Modbus frame. The scan order is optimised for speed: common IDs first (1, 255, 0), then ascending 2–254.

Returns (ids, nil) on success where ids may be empty, or (nil, err) on context cancellation or transport error.

func (*ModbusClient) Diagnostics added in v1.0.3

func (mc *ModbusClient) Diagnostics(ctx context.Context, unitId uint8, subFunction DiagnosticSubFunction, data []byte) (dr *DiagnosticResponse, err error)

Diagnostics sends a Diagnostics request (FC 0x08). subFunction selects the diagnostic (use DiagnosticSubFunction constants). data is optional request data (sub-function-specific; use nil or empty for none). The response echoes the sub-function and returns sub-function-specific data.

func (*ModbusClient) FingerprintDevice added in v1.0.3

func (mc *ModbusClient) FingerprintDevice(ctx context.Context, unitId uint8) (*ModbusFingerprint, error)

FingerprintDevice runs all detection probes against the given unit ID and records which function codes the device actively supports. A function is marked as supported when the device responds with a normal (non-exception) response or an exception other than Illegal Function (0x01). Use after Open().

func (*ModbusClient) IsModbusDevice added in v1.0.2

func (mc *ModbusClient) IsModbusDevice(ctx context.Context, unitId uint8) (bool, error)

IsModbusDevice probes the target with a minimal, read-only request sequence to determine whether the given unit ID responds with Modbus-compliant structure (valid MBAP where applicable, structurally valid normal or exception response). Use after Open(); does not mutate server state.

The probe sequence depends on ClientConfiguration.DetectionMode:

DetectAggressive (default) : FC08 → FC43 → FC03 → FC04 → FC01 → FC02
DetectStrict               : FC08 → FC43 → FC03
DetectBasic                : FC03

Returns true on first structurally validated response (normal or exception), false if no probe succeeds. Caller decides which unit IDs to try.

func (*ModbusClient) Open

func (mc *ModbusClient) Open() (err error)

Opens the underlying transport (network socket or serial line). If MaxConns > 1 and the transport is TCP-based, a connection pool pre-warmed with MinConns connections is created; subsequent requests draw from the pool and may execute concurrently. For serial transports, a single transport is used.

func (*ModbusClient) ReadAllDeviceIdentification added in v1.0.1

func (mc *ModbusClient) ReadAllDeviceIdentification(ctx context.Context, unitId uint8) (*DeviceIdentification, error)

ReadAllDeviceIdentification reads all device identification the unit supports: basic, regular, and extended (FC43 / MEI 0x0E). It requests the Extended category (ReadDeviceIdExtended); the device responds with all objects it implements, up to its conformity level. Use this when you want a single, complete snapshot of device identification without calling ReadDeviceIdentification multiple times.

func (*ModbusClient) ReadAscii

func (mc *ModbusClient) ReadAscii(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (value string, err error)

Reads quantity registers (function code 03 or 04) as an ASCII string. The high byte of each register is the first character, the low byte the second. Trailing spaces are stripped from the returned string.

func (*ModbusClient) ReadAsciiReverse

func (mc *ModbusClient) ReadAsciiReverse(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (value string, err error)

Reads quantity registers (function code 03 or 04) as an ASCII string with byte-swapped register words. The low byte of each register is the first character, the high byte the second. Trailing spaces are stripped.

func (*ModbusClient) ReadBCD

func (mc *ModbusClient) ReadBCD(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (value string, err error)

Reads quantity registers (function code 03 or 04) as a Binary Coded Decimal (BCD) string. Each byte encodes one decimal digit (0–9). Returns a string of decimal digits, most-significant digit first.

func (*ModbusClient) ReadBytes

func (mc *ModbusClient) ReadBytes(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []byte, err error)

Reads one or multiple 16-bit registers (function code 03 or 04) as bytes. A per-register byteswap is performed if endianness is set to LittleEndian.

func (*ModbusClient) ReadCoil

func (mc *ModbusClient) ReadCoil(ctx context.Context, unitId uint8, addr uint16) (value bool, err error)

Reads a single coil (function code 01).

func (*ModbusClient) ReadCoils

func (mc *ModbusClient) ReadCoils(ctx context.Context, unitId uint8, addr uint16, quantity uint16) (values []bool, err error)

Reads multiple coils (function code 01).

func (*ModbusClient) ReadDeviceIdentification

func (mc *ModbusClient) ReadDeviceIdentification(ctx context.Context, unitId uint8, readDeviceIdCode uint8, objectId uint8) (di *DeviceIdentification, err error)

ReadDeviceIdentification reads device identification objects using FC43 / MEI type 0x0E. It automatically pages through MoreFollows and returns all objects for the requested category.

readDeviceIdCode selects the category (use constants from this package):

  • ReadDeviceIdBasic (0x01): VendorName, ProductCode, MajorMinorRevision (mandatory)
  • ReadDeviceIdRegular (0x02): Basic + VendorUrl, ProductName, ModelName, UserApplicationName
  • ReadDeviceIdExtended (0x03): Regular + private/vendor objects (0x80–0xFF)
  • ReadDeviceIdIndividual (0x04): single object by objectId (objectId must be set)

For objectId use 0x00 to start from the first object (stream access); for Individual, pass the desired object ID. The device responds at its conformity level if a higher category is requested (e.g. requesting Extended on a basic-only device returns Basic).

func (*ModbusClient) ReadDiscreteInput

func (mc *ModbusClient) ReadDiscreteInput(ctx context.Context, unitId uint8, addr uint16) (value bool, err error)

Reads a single discrete input (function code 02).

func (*ModbusClient) ReadDiscreteInputs

func (mc *ModbusClient) ReadDiscreteInputs(ctx context.Context, unitId uint8, addr uint16, quantity uint16) (values []bool, err error)

Reads multiple discrete inputs (function code 02).

func (*ModbusClient) ReadFIFOQueue

func (mc *ModbusClient) ReadFIFOQueue(ctx context.Context, unitId uint8, addr uint16) (values []uint16, err error)

Reads the contents of a FIFO queue of holding registers (function code 24). addr is the FIFO Pointer Address (the count register); registers are returned as big-endian uint16 values exactly as they arrive from the device. The FIFO queue may contain at most 31 registers; an exception response is returned by the server if the count exceeds 31.

func (*ModbusClient) ReadFileRecords

func (mc *ModbusClient) ReadFileRecords(ctx context.Context, unitId uint8, requests []FileRecordRequest) (records [][]uint16, err error)

Reads one or more groups of file records (function code 20). Each FileRecordRequest selects a contiguous run of registers from one file. The returned slice has one []uint16 entry per request, in the same order. Register data is returned as big-endian uint16 values as received from the device.

Spec limits:

FileNumber   must be 1–0xFFFF
RecordNumber must be 0–0x270F (decimal 0–9999)
Total request byte count must not exceed 0xF5 (at most 35 sub-requests)

func (*ModbusClient) ReadFloat32

func (mc *ModbusClient) ReadFloat32(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value float32, err error)

Reads a single 32-bit float register.

func (*ModbusClient) ReadFloat32s

func (mc *ModbusClient) ReadFloat32s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []float32, err error)

Reads multiple 32-bit float registers.

func (*ModbusClient) ReadFloat64

func (mc *ModbusClient) ReadFloat64(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value float64, err error)

Reads a single 64-bit float register.

func (*ModbusClient) ReadFloat64s

func (mc *ModbusClient) ReadFloat64s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []float64, err error)

Reads multiple 64-bit float registers.

func (*ModbusClient) ReadInt16

func (mc *ModbusClient) ReadInt16(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value int16, err error)

Reads a single 16-bit signed register (function code 03 or 04). The raw 16-bit value is reinterpreted as int16.

func (*ModbusClient) ReadInt16s

func (mc *ModbusClient) ReadInt16s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []int16, err error)

Reads multiple 16-bit signed registers (function code 03 or 04). The raw 16-bit value of each register is reinterpreted as int16.

func (*ModbusClient) ReadInt32

func (mc *ModbusClient) ReadInt32(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value int32, err error)

Reads a single 32-bit signed register (function code 03 or 04). The value occupies 2 consecutive 16-bit registers.

func (*ModbusClient) ReadInt32s

func (mc *ModbusClient) ReadInt32s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []int32, err error)

Reads multiple 32-bit signed registers (function code 03 or 04). Each value occupies 2 consecutive 16-bit registers. Byte and word order are controlled by SetEncoding.

func (*ModbusClient) ReadInt48

func (mc *ModbusClient) ReadInt48(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value int64, err error)

Reads a single 48-bit signed value (function code 03 or 04), returned as int64. The value occupies 3 consecutive 16-bit registers.

func (*ModbusClient) ReadInt48s

func (mc *ModbusClient) ReadInt48s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []int64, err error)

Reads multiple 48-bit signed values (function code 03 or 04), returned as int64. Each value occupies 3 consecutive 16-bit registers. The 48-bit value is sign-extended to 64 bits. Byte and word order are controlled by SetEncoding.

func (*ModbusClient) ReadInt64

func (mc *ModbusClient) ReadInt64(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value int64, err error)

Reads a single 64-bit signed register (function code 03 or 04). The value occupies 4 consecutive 16-bit registers.

func (*ModbusClient) ReadInt64s

func (mc *ModbusClient) ReadInt64s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []int64, err error)

Reads multiple 64-bit signed registers (function code 03 or 04). Each value occupies 4 consecutive 16-bit registers. Byte and word order are controlled by SetEncoding.

func (*ModbusClient) ReadPackedBCD

func (mc *ModbusClient) ReadPackedBCD(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (value string, err error)

Reads quantity registers (function code 03 or 04) as a Packed BCD string. Each nibble encodes one decimal digit (0–9): the high nibble is the more- significant digit. Returns a string of decimal digits, most-significant digit first.

func (*ModbusClient) ReadRawBytes

func (mc *ModbusClient) ReadRawBytes(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []byte, err error)

Reads one or multiple 16-bit registers (function code 03 or 04) as bytes. No byte or word reordering is performed: bytes are returned exactly as they come off the wire, allowing the caller to handle encoding/endianness/word order manually.

func (*ModbusClient) ReadRegister

func (mc *ModbusClient) ReadRegister(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value uint16, err error)

Reads a single 16-bit register (function code 03 or 04).

func (*ModbusClient) ReadRegisters

func (mc *ModbusClient) ReadRegisters(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []uint16, err error)

Reads multiple 16-bit registers (function code 03 or 04).

func (*ModbusClient) ReadUint16

func (mc *ModbusClient) ReadUint16(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value uint16, err error)

Reads a single 16-bit unsigned register (function code 03 or 04). Equivalent to ReadRegister; provided for naming consistency.

func (*ModbusClient) ReadUint16s

func (mc *ModbusClient) ReadUint16s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []uint16, err error)

Reads multiple 16-bit unsigned registers (function code 03 or 04). Equivalent to ReadRegisters; provided for naming consistency.

func (*ModbusClient) ReadUint32

func (mc *ModbusClient) ReadUint32(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value uint32, err error)

Reads a single 32-bit register.

func (*ModbusClient) ReadUint32s

func (mc *ModbusClient) ReadUint32s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []uint32, err error)

Reads multiple 32-bit registers.

func (*ModbusClient) ReadUint48

func (mc *ModbusClient) ReadUint48(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value uint64, err error)

Reads a single 48-bit unsigned value (function code 03 or 04), returned as uint64. The value occupies 3 consecutive 16-bit registers.

func (*ModbusClient) ReadUint48s

func (mc *ModbusClient) ReadUint48s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []uint64, err error)

Reads multiple 48-bit unsigned values (function code 03 or 04), returned as uint64. Each value occupies 3 consecutive 16-bit registers. Byte and word order are controlled by SetEncoding.

func (*ModbusClient) ReadUint64

func (mc *ModbusClient) ReadUint64(ctx context.Context, unitId uint8, addr uint16, regType RegType) (value uint64, err error)

Reads a single 64-bit register.

func (*ModbusClient) ReadUint64s

func (mc *ModbusClient) ReadUint64s(ctx context.Context, unitId uint8, addr uint16, quantity uint16, regType RegType) (values []uint64, err error)

Reads multiple 64-bit registers.

func (*ModbusClient) ReadWriteMultipleRegisters

func (mc *ModbusClient) ReadWriteMultipleRegisters(ctx context.Context, unitId uint8, readAddr, readQty, writeAddr uint16, writeValues []uint16) (values []uint16, err error)

Performs a combined read/write in a single Modbus transaction (function code 23). The write is executed on the server before the read. writeValues are encoded using the client's current endianness setting. The returned slice contains the registers read, also decoded with the current endianness setting.

Limits (per spec):

readQty:  1–125 (0x7D)
writeQty: 1–121 (0x79), implied by len(writeValues)

func (*ModbusClient) ReportServerId added in v1.0.3

func (mc *ModbusClient) ReportServerId(ctx context.Context, unitId uint8) (rs *ReportServerIdResponse, err error)

ReportServerId requests the Report Server ID (FC 0x11). The response contains device-specific server ID, run indicator status, and optional additional data.

func (*ModbusClient) SetEncoding

func (mc *ModbusClient) SetEncoding(endianness Endianness, wordOrder WordOrder) (err error)

Sets the encoding (endianness and word ordering) of subsequent requests.

func (*ModbusClient) WriteBytes

func (mc *ModbusClient) WriteBytes(ctx context.Context, unitId uint8, addr uint16, values []byte) (err error)

Writes the given slice of bytes to 16-bit registers starting at addr. A per-register byteswap is performed if endianness is set to LittleEndian. Odd byte quantities are padded with a null byte to fall on 16-bit register boundaries.

func (*ModbusClient) WriteCoil

func (mc *ModbusClient) WriteCoil(ctx context.Context, unitId uint8, addr uint16, value bool) (err error)

Writes a single coil (function code 05).

func (*ModbusClient) WriteCoilValue

func (mc *ModbusClient) WriteCoilValue(ctx context.Context, unitId uint8, addr uint16, payload uint16) (err error)

Sends a write coil request (function code 05) with a specific payload value instead of the standard 0xff00 (true) or 0x0000 (false). This is a violation of the modbus spec and should almost never be necessary, but a handful of vendors seem to be hiding various DO/coil control modes behind it (e.g. toggle, interlock, delayed open/close, etc.).

func (*ModbusClient) WriteCoils

func (mc *ModbusClient) WriteCoils(ctx context.Context, unitId uint8, addr uint16, values []bool) (err error)

Writes multiple coils (function code 15).

func (*ModbusClient) WriteFileRecords

func (mc *ModbusClient) WriteFileRecords(ctx context.Context, unitId uint8, records []FileRecord) (err error)

Writes one or more groups of file records (function code 21). Each FileRecord specifies the target file, starting record number, and the register values to write. The normal response is an echo of the request. Register data is encoded as big-endian uint16 values on the wire.

Spec limits:

FileNumber   must be 1–0xFFFF
RecordNumber must be 0–0x270F (decimal 0–9999)
Total request data length must be in the range 0x09–0xFB

func (*ModbusClient) WriteFloat32

func (mc *ModbusClient) WriteFloat32(ctx context.Context, unitId uint8, addr uint16, value float32) (err error)

Writes a single 32-bit float register.

func (*ModbusClient) WriteFloat32s

func (mc *ModbusClient) WriteFloat32s(ctx context.Context, unitId uint8, addr uint16, values []float32) (err error)

Writes multiple 32-bit float registers.

func (*ModbusClient) WriteFloat64

func (mc *ModbusClient) WriteFloat64(ctx context.Context, unitId uint8, addr uint16, value float64) (err error)

Writes a single 64-bit float register.

func (*ModbusClient) WriteFloat64s

func (mc *ModbusClient) WriteFloat64s(ctx context.Context, unitId uint8, addr uint16, values []float64) (err error)

Writes multiple 64-bit float registers.

func (*ModbusClient) WriteRawBytes

func (mc *ModbusClient) WriteRawBytes(ctx context.Context, unitId uint8, addr uint16, values []byte) (err error)

Writes the given slice of bytes to 16-bit registers starting at addr. No byte or word reordering is performed: bytes are pushed to the wire as-is, allowing the caller to handle encoding/endianness/word order manually. Odd byte quantities are padded with a null byte to fall on 16-bit register boundaries.

func (*ModbusClient) WriteRegister

func (mc *ModbusClient) WriteRegister(ctx context.Context, unitId uint8, addr uint16, value uint16) (err error)

Writes a single 16-bit register (function code 06).

func (*ModbusClient) WriteRegisters

func (mc *ModbusClient) WriteRegisters(ctx context.Context, unitId uint8, addr uint16, values []uint16) (err error)

Writes multiple 16-bit registers (function code 16).

func (*ModbusClient) WriteUint32

func (mc *ModbusClient) WriteUint32(ctx context.Context, unitId uint8, addr uint16, value uint32) (err error)

Writes a single 32-bit register.

func (*ModbusClient) WriteUint32s

func (mc *ModbusClient) WriteUint32s(ctx context.Context, unitId uint8, addr uint16, values []uint32) (err error)

Writes multiple 32-bit registers.

func (*ModbusClient) WriteUint64

func (mc *ModbusClient) WriteUint64(ctx context.Context, unitId uint8, addr uint16, value uint64) (err error)

Writes a single 64-bit register.

func (*ModbusClient) WriteUint64s

func (mc *ModbusClient) WriteUint64s(ctx context.Context, unitId uint8, addr uint16, values []uint64) (err error)

Writes multiple 64-bit registers.

type ModbusFingerprint added in v1.0.3

type ModbusFingerprint struct {
	UnitId       uint8
	SupportsFC01 bool // Read Coils
	SupportsFC02 bool // Read Discrete Inputs
	SupportsFC03 bool // Read Holding Registers
	SupportsFC04 bool // Read Input Registers
	SupportsFC08 bool // Diagnostics
	SupportsFC11 bool // Report Server ID
	SupportsFC18 bool // Read FIFO Queue
	SupportsFC20 bool // Read File Record
	SupportsFC43 bool // Read Device Identification
}

ModbusFingerprint records which function codes a unit actively supports. A function is marked as supported when the device responds with a non-exception normal response, or with an exception other than Illegal Function (0x01). Use FingerprintDevice to populate.

type ModbusServer

type ModbusServer struct {
	// contains filtered or unexported fields
}

Modbus server object.

func NewServer

func NewServer(conf *ServerConfiguration, reqHandler RequestHandler) (
	ms *ModbusServer, err error)

Returns a new modbus server. reqHandler should be a user-provided handler object satisfying the RequestHandler interface.

func (*ModbusServer) Start

func (ms *ModbusServer) Start() (err error)

Starts accepting client connections.

func (*ModbusServer) Stop

func (ms *ModbusServer) Stop() (err error)

Stops accepting new client connections and closes any active session. Blocks until all in-flight client goroutines have exited.

type Parity

type Parity uint

type RegType

type RegType uint

type ReportServerIdResponse added in v1.0.3

type ReportServerIdResponse struct {
	ByteCount uint8
	Data      []byte
}

ReportServerIdResponse is the response from Report Server ID (FC 0x11). ByteCount is the number of following bytes; Data contains device-specific server ID, run indicator status (0x00 = OFF, 0xFF = ON), and optional additional data.

type RequestHandler

type RequestHandler interface {
	// HandleCoils handles the read coils (0x01), write single coil (0x05)
	// and write multiple coils (0x0f) function codes.
	// A CoilsRequest object is passed to the handler (see above).
	//
	// Expected return values:
	// - res:	a slice of bools containing the coil values to be sent to back
	//		to the client (only sent for reads; the return value is
	//		ignored for write requests),
	// - err:	either nil if no error occurred, a modbus error (see
	//		mapErrorToExceptionCode() in modbus.go for a complete list),
	//		or any other error.
	//		If nil, a positive modbus response is sent back to the client
	//		along with the returned data.
	//		If non-nil, a negative modbus response is sent back, with the
	//		exception code set depending on the error
	//		(again, see mapErrorToExceptionCode()).
	HandleCoils(ctx context.Context, req *CoilsRequest) (res []bool, err error)

	// HandleDiscreteInputs handles the read discrete inputs (0x02) function code.
	// A DiscreteInputsRequest oibject is passed to the handler (see above).
	//
	// Expected return values:
	// - res:	a slice of bools containing the discrete input values to be
	//		sent back to the client,
	// - err:	either nil if no error occurred, a modbus error (see
	//		mapErrorToExceptionCode() in modbus.go for a complete list),
	//		or any other error.
	HandleDiscreteInputs(ctx context.Context, req *DiscreteInputsRequest) (res []bool, err error)

	// HandleHoldingRegisters handles the read holding registers (0x03),
	// write single register (0x06) and write multiple registers (0x10).
	// A HoldingRegistersRequest object is passed to the handler (see above).
	//
	// Expected return values:
	// - res:	a slice of uint16 containing the register values to be sent
	//		to back to the client (only sent for reads; the return value is
	//		ignored for write requests),
	// - err:	either nil if no error occurred, a modbus error (see
	//		mapErrorToExceptionCode() in modbus.go for a complete list),
	//		or any other error.
	HandleHoldingRegisters(ctx context.Context, req *HoldingRegistersRequest) (res []uint16, err error)

	// HandleInputRegisters handles the read input registers (0x04) function code.
	// An InputRegistersRequest object is passed to the handler (see above).
	//
	// Expected return values:
	// - res:	a slice of uint16 containing the register values to be sent
	//		back to the client,
	// - err:	either nil if no error occurred, a modbus error (see
	//		mapErrorToExceptionCode() in modbus.go for a complete list),
	//		or any other error.
	HandleInputRegisters(ctx context.Context, req *InputRegistersRequest) (res []uint16, err error)
}

The RequestHandler interface should be implemented by the handler object passed to NewServer (see reqHandler in NewServer()). After decoding and validating an incoming request, the server will invoke the appropriate handler function, depending on the function code of the request.

type RetryPolicy

type RetryPolicy interface {
	// ShouldRetry returns (true, waitDuration) to schedule another attempt after
	// waitDuration, or (false, 0) to stop and propagate the error to the caller.
	ShouldRetry(attempt int, err error) (bool, time.Duration)
}

RetryPolicy controls whether and how a failed request is retried. Each call to ShouldRetry receives the zero-based attempt index (0 = first failure) and the error that caused it, and returns whether to retry and how long to wait.

The wait duration is honoured by the client but capped by the remaining context deadline. A nil RetryPolicy is equivalent to NoRetry().

func ExponentialBackoff

func ExponentialBackoff(base, maxDelay time.Duration, maxAttempts int) RetryPolicy

ExponentialBackoff returns an exponential back-off RetryPolicy with common defaults. delay grows as base × 2^attempt, capped at maxDelay; retries stop after maxAttempts. Passing maxAttempts = 0 means unlimited retries.

func NewExponentialBackoff

func NewExponentialBackoff(cfg ExponentialBackoffConfig) RetryPolicy

NewExponentialBackoff constructs an exponential back-off RetryPolicy from a full ExponentialBackoffConfig, allowing control over RetryOnTimeout and unlimited attempts.

func NoRetry

func NoRetry() RetryPolicy

NoRetry returns a RetryPolicy that never retries; requests fail on the first error. This is the default behaviour when ClientConfiguration.RetryPolicy is nil.

type ServerConfiguration

type ServerConfiguration struct {
	// URL defines where to listen at e.g. tcp://[::]:502
	URL string
	// Timeout sets the idle session timeout (client connections will
	// be closed if idle for this long)
	Timeout time.Duration
	// MaxClients sets the maximum number of concurrent client connections
	MaxClients uint
	// TLSServerCert sets the server-side TLS key pair (tcp+tls only)
	TLSServerCert *tls.Certificate
	// TLSClientCAs sets the list of CA certificates used to authenticate
	// client connections (tcp+tls only). Leaf (i.e. client) certificates can
	// also be used in case of self-signed certs, or if cert pinning is required.
	TLSClientCAs *x509.CertPool
	// TLSHandshakeTimeout sets the maximum time allowed to complete the TLS
	// handshake for incoming connections. Defaults to 30 seconds when zero.
	TLSHandshakeTimeout time.Duration
	// Logger provides a custom sink for log messages.
	// If nil, the slog default logger (slog.Default()) is used.
	// Use NewStdLogger, NewSlogLogger, or NopLogger to build a value.
	Logger Logger

	// Metrics receives callbacks for every request handled by the server.
	// A nil Metrics (the default) disables metric collection.
	Metrics ServerMetrics
}

Server configuration object.

type ServerMetrics

type ServerMetrics interface {
	// OnRequest is called immediately before the handler is invoked.
	// unitId and functionCode identify the incoming request.
	OnRequest(unitId uint8, functionCode uint8)

	// OnResponse is called after the handler returns without error.
	// duration is the handler execution time.
	OnResponse(unitId uint8, functionCode uint8, duration time.Duration)

	// OnError is called when the handler returns an error.
	// duration is the handler execution time.
	OnError(unitId uint8, functionCode uint8, duration time.Duration, err error)
}

ServerMetrics is an optional callback interface for observing server-side request outcomes. All methods are called synchronously; implementations must be non-blocking. A nil ServerMetrics is valid and disables collection.

type WordOrder

type WordOrder uint

Directories

Path Synopsis
examples
tcp_server command
tls_client command
tls_server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL