This package is a go implementation of the modbus protocol. It aims to provide a simple-to-use, high-level API to interact with modbus devices using native Go types.
Both client and server components are available. The client can be used over both TCP and RTU (serial), and supports an RTU over TCP mode to allow the use of remote serial ports or cheap TCP to serial bridges.
The server is TCP-only for now.
A CLI client is available in cmd/modbus-cli.go and can be built with
$ go build -o modbus-cli cmd/modbus-cli.go
$ ./modbus-cli --help
$ go get github.com/simonvetter/modbus
import (
"github.com/simonvetter/modbus"
)
func main() {
var client *modbus.ModbusClient
var err error
// for a TCP endpoint
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "tcp://hostname-or-ip-address:502",
Timeout: 1 * time.Second,
})
// for an RTU (serial) device/bus
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "rtu:///dev/ttyUSB0",
Speed: 9600, // default
DataBits: 8, // default, optional
Parity: modbus.PARITY_NONE, // default, optional
StopBits: 2, // default if no parity, optional
Timeout: 300 * time.Millisecond,
})
// for an RTU over TCP device/bus (remote serial port or
// simple TCP-to-serial bridge)
client, err = modbus.NewClient(&modbus.ClientConfiguration{
URL: "rtuovertcp://hostname-or-ip-address:502",
Timeout: 1 * time.Second,
})
// read a single 16-bit holding register at address 100
var reg16 uint16
reg16, err = client.ReadRegister(100, modbus.HOLDING_REGISTER)
if err != nil {
// error out
} else {
// use value
fmt.Printf("value: %v", reg16) // as unsigned integer
fmt.Printf("value: %v", int16(reg16)) // as signed integer
}
// read 4 consecutive 16-bit input registers starting at address 100
var reg16s []uint16
reg16s, err = client.ReadRegisters(100, 4, modbus.INPUT_REGISTER)
// read the same 4 consecutive 16-bit input registers as 2 32-bit registers
var reg32s []uint32
reg32s, err = client.ReadUint32s(100, 2, modbus.INPUT_REGISTER)
// by default, 16-bit registers are decoded as big-endian and 32-bit registers
// as big-endian with the high word first.
// change the byte/word ordering of subsequent requests to little endian, with
// the low word first (note that the second argument only affects 32-bit registers)
client.SetEncoding(modbus.LITTLE_ENDIAN, modbus.LOW_WORD_FIRST)
// read the same 4 consecutive 16-bit input registers as 2 32-bit floats
var fl32s []float32
fl32s, err = client.ReadFloat32s(100, 2, modbus.INPUT_REGISTER)
// write -200 to 16-bit (holding) register 100, as a signed integer
var s int16 = -200
err = client.WriteRegister(100, uint16(s))
// Switch to unit ID (a.k.a. slave ID) #4
client.SetUnitId(4)
// write 3 floats to registers 100 to 105
err = client.WriteFloat32s(100, []float32{
3.14,
1.1,
-783.22,
})
// close the TCP connection/serial port
client.Close()
}
See examples/tcp_server.go for an example.
Function codes:
- Read coils (0x01)
- Read discrete inputs (0x02)
- Read holding registers (0x03)
- Read input registers (0x04)
- Write single coil (0x05)
- Write single register (0x06)
- Write multiple coils (0x0f)
- Write multiple registers (0x10)
Go object types:
- Booleans (coils and discrete inputs)
- Signed/Unisgned 16-bit integers (input and holding registers)
- Signed/Unsigned 32-bit integers (input and holding registers)
- 32-bit floating point numbers (input and holding registers)
Byte encoding/endianness/word ordering:
- Little and Big endian for 16-bit integers
- Little and Big endian, with and without word swap for 32-bit integers and 32-bit floating point numbers.
- Add RTU (serial) support to the server
- Add more tests
- Add diagnostics register support
- Add fifo register support
- Add file register support
- github.com/goburrow/serial for access to the serial port (thanks!)
MIT.