simulator

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2025 License: BSD-3-Clause Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ASCIIServer

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

ASCIIServer implements a Modbus ASCII server.

func NewASCIIServer

func NewASCIIServer(ds *DataStore, config *ASCIIServerConfig) (*ASCIIServer, error)

NewASCIIServer creates a new ASCII server with the given data store and configuration.

func (*ASCIIServer) ClientDevicePath

func (s *ASCIIServer) ClientDevicePath() string

ClientDevicePath returns the device path that clients should connect to.

func (*ASCIIServer) Start

func (s *ASCIIServer) Start() error

Start starts the ASCII server in a goroutine.

func (*ASCIIServer) Stop

func (s *ASCIIServer) Stop() error

Stop stops the ASCII server and waits for it to finish.

type ASCIIServerConfig

type ASCIIServerConfig struct {
	SlaveID  byte
	BaudRate int
	Logger   *log.Logger
}

ASCIIServerConfig holds configuration for the ASCII server.

type CoilConfig added in v0.2.0

type CoilConfig struct {
	Name  string `json:"name"`
	Value bool   `json:"value"`
}

CoilConfig represents a named coil with an initial value.

type DataStore

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

DataStore represents the in-memory storage for Modbus data. It maintains four separate address spaces: - Coils: read/write single bits (function codes 1, 5, 15) - Discrete Inputs: read-only single bits (function code 2) - Holding Registers: read/write 16-bit registers (function codes 3, 6, 16, 22, 23) - Input Registers: read-only 16-bit registers (function code 4)

func NewDataStore

func NewDataStore(config *DataStoreConfig) *DataStore

NewDataStore creates a new DataStore with optional initial configuration.

func (*DataStore) ApplyDelay added in v0.5.0

func (ds *DataStore) ApplyDelay(regType RegisterType, address uint16) bool

ApplyDelay applies the configured delay and checks for timeout simulation. Returns true if the request should proceed, false if it should timeout (no response).

func (*DataStore) ApplyDelayWithOptions added in v0.5.0

func (ds *DataStore) ApplyDelayWithOptions(regType RegisterType, address uint16, disableTimeout bool) bool

ApplyDelayWithOptions applies the configured delay and optionally checks for timeout simulation. Returns true if the request should proceed, false if it should timeout (no response). If disableTimeout is true, timeout probability is ignored (useful for RTU/ASCII where timeouts don't work with PTYs).

func (*DataStore) GetCoilName added in v0.2.0

func (ds *DataStore) GetCoilName(address uint16) string

GetCoilName returns the name of a coil at the given address, if configured.

func (*DataStore) GetDelayConfig added in v0.5.0

func (ds *DataStore) GetDelayConfig(regType RegisterType, address uint16) *DelayConfig

GetDelayConfig returns the applicable delay configuration for a given register type and address. It checks for address-specific overrides first, then falls back to global defaults. Returns nil if no delay configuration is found.

func (*DataStore) GetDiscreteInputName added in v0.2.0

func (ds *DataStore) GetDiscreteInputName(address uint16) string

GetDiscreteInputName returns the name of a discrete input at the given address, if configured.

func (*DataStore) GetHoldingRegName added in v0.2.0

func (ds *DataStore) GetHoldingRegName(address uint16) string

GetHoldingRegName returns the name of a holding register at the given address, if configured.

func (*DataStore) GetInputRegName added in v0.2.0

func (ds *DataStore) GetInputRegName(address uint16) string

GetInputRegName returns the name of an input register at the given address, if configured.

func (*DataStore) MaskWriteRegister

func (ds *DataStore) MaskWriteRegister(address, andMask, orMask uint16) error

MaskWriteRegister performs an AND/OR mask write on a holding register.

func (*DataStore) ReadCoils

func (ds *DataStore) ReadCoils(address, quantity uint16) ([]bool, error)

ReadCoils reads quantity coils starting at address.

func (*DataStore) ReadDiscreteInputs

func (ds *DataStore) ReadDiscreteInputs(address, quantity uint16) ([]bool, error)

ReadDiscreteInputs reads quantity discrete inputs starting at address.

func (*DataStore) ReadHoldingRegisters

func (ds *DataStore) ReadHoldingRegisters(address, quantity uint16) ([]uint16, error)

ReadHoldingRegisters reads quantity holding registers starting at address.

func (*DataStore) ReadInputRegisters

func (ds *DataStore) ReadInputRegisters(address, quantity uint16) ([]uint16, error)

ReadInputRegisters reads quantity input registers starting at address.

func (*DataStore) WriteMultipleCoils

func (ds *DataStore) WriteMultipleCoils(address uint16, values []bool) error

WriteMultipleCoils writes multiple coils starting at address.

func (*DataStore) WriteMultipleRegisters

func (ds *DataStore) WriteMultipleRegisters(address uint16, values []uint16) error

WriteMultipleRegisters writes multiple holding registers starting at address.

func (*DataStore) WriteSingleCoil

func (ds *DataStore) WriteSingleCoil(address uint16, value bool) error

WriteSingleCoil writes a single coil at address.

func (*DataStore) WriteSingleRegister

func (ds *DataStore) WriteSingleRegister(address, value uint16) error

WriteSingleRegister writes a single holding register at address.

type DataStoreConfig

type DataStoreConfig struct {
	// Initial values for each data type. If nil, defaults to zeros.
	// Legacy format: map[address]value
	Coils          map[uint16]bool   `json:"Coils,omitempty"`
	DiscreteInputs map[uint16]bool   `json:"DiscreteInputs,omitempty"`
	HoldingRegs    map[uint16]uint16 `json:"HoldingRegs,omitempty"`
	InputRegs      map[uint16]uint16 `json:"InputRegs,omitempty"`

	// New format: map[address]config with name
	NamedCoils          map[uint16]CoilConfig     `json:"NamedCoils,omitempty"`
	NamedDiscreteInputs map[uint16]CoilConfig     `json:"NamedDiscreteInputs,omitempty"`
	NamedHoldingRegs    map[uint16]RegisterConfig `json:"NamedHoldingRegs,omitempty"`
	NamedInputRegs      map[uint16]RegisterConfig `json:"NamedInputRegs,omitempty"`

	// Delay and timeout configuration
	Delays *DelayConfigSet `json:"delays,omitempty"`
}

DataStoreConfig allows configuring initial values for the data store.

type DelayConfig added in v0.5.0

type DelayConfig struct {
	// Base delay to apply before responding (e.g., "100ms", "1s")
	Delay string `json:"delay,omitempty"`
	// Jitter percentage (0-100) to add random variance to delay
	// e.g., 20 means ±20% of Delay
	Jitter int `json:"jitter,omitempty"`
	// TimeoutProbability (0.0-1.0) is the probability of not responding at all
	// e.g., 0.3 means 30% of requests will timeout
	TimeoutProbability float64 `json:"timeoutProbability,omitempty"`
}

DelayConfig defines delay and timeout behavior for register access.

type DelayConfigSet added in v0.5.0

type DelayConfigSet struct {
	// Global default delays per register type
	Global map[RegisterType]DelayConfig `json:"global,omitempty"`
	// Per-address delay overrides for coils
	Coils map[uint16]DelayConfig `json:"coils,omitempty"`
	// Per-address delay overrides for discrete inputs
	DiscreteInputs map[uint16]DelayConfig `json:"discreteInputs,omitempty"`
	// Per-address delay overrides for holding registers
	HoldingRegs map[uint16]DelayConfig `json:"holdingRegs,omitempty"`
	// Per-address delay overrides for input registers
	InputRegs map[uint16]DelayConfig `json:"inputRegs,omitempty"`
}

DelayConfigSet contains global defaults and per-address delay configurations.

type Handler

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

Handler processes Modbus function codes and interacts with the DataStore.

func NewHandler

func NewHandler(ds *DataStore) *Handler

NewHandler creates a new Handler with the given DataStore.

func NewHandlerWithOptions added in v0.5.0

func NewHandlerWithOptions(ds *DataStore, disableTimeoutSimulation bool) *Handler

NewHandlerWithOptions creates a new Handler with specific options.

func (*Handler) HandleRequest

func (h *Handler) HandleRequest(req *modbus.ProtocolDataUnit) *modbus.ProtocolDataUnit

HandleRequest processes a Modbus PDU request and returns a response PDU.

type PtyPair

type PtyPair struct {
	Master     *os.File
	Slave      *os.File
	MasterPath string
	SlavePath  string
	// contains filtered or unexported fields
}

PtyPair represents a pseudo-terminal pair with master and slave sides.

func CreatePtyPair

func CreatePtyPair() (*PtyPair, error)

CreatePtyPair creates a new pseudo-terminal pair natively. The master is used by the simulator to read/write, and the slave path is provided to the client for communication.

func (*PtyPair) Close

func (p *PtyPair) Close() error

Close closes both master and slave file descriptors.

func (*PtyPair) Read

func (p *PtyPair) Read(b []byte) (int, error)

Read safely reads from the master file descriptor with proper locking.

func (*PtyPair) SetReadDeadline

func (p *PtyPair) SetReadDeadline(t time.Time) error

SetReadDeadline safely sets the read deadline with proper locking.

func (*PtyPair) Sync

func (p *PtyPair) Sync() error

Sync safely syncs the master file descriptor with proper locking.

func (*PtyPair) Write

func (p *PtyPair) Write(b []byte) (int, error)

Write safely writes to the master file descriptor with proper locking.

type RTUServer

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

RTUServer implements a Modbus RTU server.

func NewRTUServer

func NewRTUServer(ds *DataStore, config *RTUServerConfig) (*RTUServer, error)

NewRTUServer creates a new RTU server with the given data store and configuration.

func (*RTUServer) ClientDevicePath

func (s *RTUServer) ClientDevicePath() string

ClientDevicePath returns the device path that clients should connect to.

func (*RTUServer) Start

func (s *RTUServer) Start() error

Start starts the RTU server in a goroutine.

func (*RTUServer) Stop

func (s *RTUServer) Stop() error

Stop stops the RTU server and waits for it to finish.

type RTUServerConfig

type RTUServerConfig struct {
	SlaveID  byte
	BaudRate int
	Logger   *log.Logger
}

RTUServerConfig holds configuration for the RTU server.

type RegisterConfig added in v0.2.0

type RegisterConfig struct {
	Name  string `json:"name"`
	Value uint16 `json:"value"`
}

RegisterConfig represents a named register with an initial value.

type RegisterType added in v0.5.0

type RegisterType string

RegisterType identifies one of the four Modbus register types.

const (
	RegisterTypeCoil          RegisterType = "coils"
	RegisterTypeDiscreteInput RegisterType = "discreteInputs"
	RegisterTypeHoldingReg    RegisterType = "holdingRegs"
	RegisterTypeInputReg      RegisterType = "inputRegs"
)

type TCPServer

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

TCPServer implements a Modbus TCP server.

func NewTCPServer

func NewTCPServer(ds *DataStore, config *TCPServerConfig) (*TCPServer, error)

NewTCPServer creates a new TCP server with the given data store and configuration.

func (*TCPServer) Address

func (s *TCPServer) Address() string

Address returns the address the server is listening on.

func (*TCPServer) Start

func (s *TCPServer) Start() error

Start starts the TCP server and begins accepting connections.

func (*TCPServer) Stop

func (s *TCPServer) Stop() error

Stop stops the TCP server and waits for all connections to close.

type TCPServerConfig

type TCPServerConfig struct {
	Address string // e.g., "localhost:5020" or ":502"
	Logger  *log.Logger
}

TCPServerConfig holds configuration for the TCP server.

Jump to

Keyboard shortcuts

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