Documentation
¶
Overview ¶
Package mbserver implements a Modbus server (slave).
Example ¶
Start a Modbus server and use a client to write to and read from the serer.
// Start the server.
serv := NewServer()
err := serv.ListenTCP("127.0.0.1:1502")
if err != nil {
log.Fatalln(err)
return
}
defer serv.Shutdown()
go serv.Start()
// Wait for the server to start
time.Sleep(1 * time.Millisecond)
// Connect a client.
handler := modbus.NewTCPClientHandler("localhost:1502")
err = handler.Connect()
if err != nil {
log.Fatalln(err)
return
}
defer handler.Close()
client := modbus.NewClient(handler)
// Write some registers.
_, err = client.WriteMultipleRegisters(0, 3, []byte{0, 3, 0, 4, 0, 5})
if err != nil {
log.Fatalln(err)
}
// Read those registers back.
results, err := client.ReadHoldingRegisters(0, 3)
if err != nil {
log.Fatalln(err)
}
fmt.Printf("results %v\n", results)
Output: results [0 3 0 4 0 5]
Index ¶
- func BytesToUint16(bytes []byte) []uint16
- func SetDataWithRegisterAndNumber(frame Framer, register, number uint16)
- func SetDataWithRegisterAndNumberAndBytes(frame Framer, register, number uint16, bytes []byte)
- func SetDataWithRegisterAndNumberAndValues(frame Framer, register, number uint16, values []uint16)
- func Uint16ToBytes(values []uint16) []byte
- type Exception
- type Framer
- type Function
- type MemRegister
- func (r *MemRegister) ReadCoils(start, count int) ([]bool, Exception)
- func (r *MemRegister) ReadDiscreteInputs(start, count int) ([]bool, Exception)
- func (r *MemRegister) ReadHoldingRegisters(start, count int) ([]uint16, Exception)
- func (r *MemRegister) ReadInputRegisters(start, count int) ([]uint16, Exception)
- func (r *MemRegister) WriteMultipleCoils(start int, values []bool) Exception
- func (r *MemRegister) WriteMultipleRegisters(start int, values []uint16) Exception
- func (r *MemRegister) WriteSingleCoil(start int, value bool) Exception
- func (r *MemRegister) WriteSingleRegister(start int, value uint16) Exception
- type OptionFunc
- type RTUFrame
- type Register
- type Request
- type Server
- type TCPFrame
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BytesToUint16 ¶
BytesToUint16 converts a big endian array of bytes to an array of unit16s
func SetDataWithRegisterAndNumber ¶
SetDataWithRegisterAndNumber sets the RTUFrame Data byte field to hold a register and number of registers
func SetDataWithRegisterAndNumberAndBytes ¶
SetDataWithRegisterAndNumberAndBytes sets the TCPFrame Data byte field to hold a register and number of registers and coil bytes
func SetDataWithRegisterAndNumberAndValues ¶
SetDataWithRegisterAndNumberAndValues sets the TCPFrame Data byte field to hold a register and number of registers and values
func Uint16ToBytes ¶
Uint16ToBytes converts an array of uint16s to a big endian array of bytes
Types ¶
type Exception ¶
type Exception uint8
Exception codes.
const ( // Success operation successful. Success Exception = iota // IllegalFunction function code received in the query is not recognized or allowed by slave. IllegalFunction // IllegalDataAddress data address of some or all the required entities are not allowed or do not exist in slave. IllegalDataAddress // IllegalDataValue value is not accepted by slave. IllegalDataValue // SlaveDeviceFailure Unrecoverable error occurred while slave was attempting to perform requested action. SlaveDeviceFailure // AcknowledgeSlave has accepted request and is processing it, but a long duration of time is required. This response is returned to prevent a timeout error from occurring in the master. Master can next issue a Poll Program Complete message to determine whether processing is completed. AcknowledgeSlave // SlaveDeviceBusy is engaged in processing a long-duration command. Master should retry later. SlaveDeviceBusy // NegativeAcknowledge Slave cannot perform the programming functions. Master should request diagnostic or error information from slave. NegativeAcknowledge // MemoryParityError Slave detected a parity error in memory. Master can retry the request, but service may be required on the slave device. MemoryParityError GatewayPathUnavailable Exception = 10 // GatewayTargetDeviceFailedToRespond Specialized for Modbus gateways. Sent when slave fails to respond. GatewayTargetDeviceFailedToRespond Exception = 11 )
func GetException ¶
GetException returns the Modbus exception or Success (indicating not exception).
type Framer ¶
type Framer interface {
Bytes() []byte
Copy() Framer
GetData() []byte
GetFunction() uint8
SetException(Exception)
SetData(data []byte)
}
Framer is the interface that wraps Modbus frames.
type MemRegister ¶
type MemRegister struct {
Coils []bool
DiscreteInputs []bool
HoldingRegisters []uint16
InputRegisters []uint16
}
func NewMemRegister ¶
func NewMemRegister() *MemRegister
func (*MemRegister) ReadCoils ¶
func (r *MemRegister) ReadCoils(start, count int) ([]bool, Exception)
func (*MemRegister) ReadDiscreteInputs ¶
func (r *MemRegister) ReadDiscreteInputs(start, count int) ([]bool, Exception)
func (*MemRegister) ReadHoldingRegisters ¶
func (r *MemRegister) ReadHoldingRegisters(start, count int) ([]uint16, Exception)
func (*MemRegister) ReadInputRegisters ¶
func (r *MemRegister) ReadInputRegisters(start, count int) ([]uint16, Exception)
func (*MemRegister) WriteMultipleCoils ¶
func (r *MemRegister) WriteMultipleCoils(start int, values []bool) Exception
func (*MemRegister) WriteMultipleRegisters ¶
func (r *MemRegister) WriteMultipleRegisters(start int, values []uint16) Exception
func (*MemRegister) WriteSingleCoil ¶
func (r *MemRegister) WriteSingleCoil(start int, value bool) Exception
func (*MemRegister) WriteSingleRegister ¶
func (r *MemRegister) WriteSingleRegister(start int, value uint16) Exception
type OptionFunc ¶
type OptionFunc func(s *Server)
OptionFunc is a function type used to configure options for the Server.
func WithRegister ¶
func WithRegister(register Register) OptionFunc
WithRegister sets the memory register for the server.
func WithRegisterFunction ¶
func WithRegisterFunction(funcCode uint8, function Function) OptionFunc
WithRegisterFunction registers a custom function handler for a specific function code. Parameter funcCode is the function code, and function is the custom handler for that code.
Example ¶
Override the default ReadDiscreteInputs function.
// Override ReadDiscreteInputs function.
wf := WithRegisterFunction(2, func(r Register, frame Framer) ([]byte, Exception) {
register, numRegs := registerAddressAndNumber(frame)
// Check the request is within the allocated memory
if register+numRegs > 65535 {
return []byte{}, IllegalDataAddress
}
dataSize := numRegs / 8
if (numRegs % 8) != 0 {
dataSize++
}
data := make([]byte, 1+dataSize)
data[0] = byte(dataSize)
discreteInputs, exception := r.ReadDiscreteInputs(register, numRegs)
if exception != Success {
return []byte{}, exception
}
for i, value := range discreteInputs {
if value {
shift := uint(i) % 8
data[1+i/8] |= byte(1 << shift)
}
}
return data, Success
})
wr := WithRegister(&MemRegister{
DiscreteInputs: []bool{
true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true,
},
})
serv := NewServer(wf, wr)
// Start the server.
err := serv.ListenTCP("localhost:4321")
if err != nil {
log.Fatalln(err)
return
}
defer serv.Shutdown()
go serv.Start()
// Wait for the server to start
time.Sleep(1 * time.Millisecond)
// Connect a client.
handler := modbus.NewTCPClientHandler("localhost:4321")
err = handler.Connect()
if err != nil {
log.Fatalln(err)
}
defer handler.Close()
client := modbus.NewClient(handler)
// Read discrete inputs.
results, err := client.ReadDiscreteInputs(0, 16)
if err != nil {
log.Fatalln(err)
}
fmt.Printf("results %v\n", results)
Output: results [255 255]
type RTUFrame ¶
RTUFrame is the Modbus TCP frame.
func NewRTUFrame ¶
NewRTUFrame converts a packet to a Modbus TCP frame.
func (*RTUFrame) GetFunction ¶
GetFunction returns the Modbus function code.
func (*RTUFrame) SetData ¶
SetData sets the RTUFrame Data byte field and updates the frame length accordingly.
func (*RTUFrame) SetException ¶
SetException sets the Modbus exception code in the frame.
type Register ¶
type Register interface {
ReadCoils(int, int) ([]bool, Exception)
ReadDiscreteInputs(int, int) ([]bool, Exception)
ReadHoldingRegisters(int, int) ([]uint16, Exception)
ReadInputRegisters(int, int) ([]uint16, Exception)
WriteSingleCoil(int, bool) Exception
WriteSingleRegister(int, uint16) Exception
WriteMultipleCoils(int, []bool) Exception
WriteMultipleRegisters(int, []uint16) Exception
}
type Request ¶
type Request struct {
// contains filtered or unexported fields
}
Request contains the connection and Modbus frame.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a Modbus slave with allocated memory for discrete inputs, coils, etc.
func NewServer ¶
func NewServer(opts ...OptionFunc) *Server
NewServer creates a new Modbus server (slave).
func (*Server) ListenRTU ¶
ListenRTU starts the Modbus server listening to a serial device. For example: err := s.ListenRTU(&serial.Config{Address: "/dev/ttyUSB0"})
type TCPFrame ¶
type TCPFrame struct {
TransactionIdentifier uint16
ProtocolIdentifier uint16
Length uint16
Device uint8
Function uint8
Data []byte
}
TCPFrame is the Modbus TCP frame.
func NewTCPFrame ¶
NewTCPFrame converts a packet to a Modbus TCP frame.
func (*TCPFrame) GetFunction ¶
GetFunction returns the Modbus function code.
func (*TCPFrame) SetData ¶
SetData sets the TCPFrame Data byte field and updates the frame length accordingly.
func (*TCPFrame) SetException ¶
SetException sets the Modbus exception code in the frame.