Skip to content

Repository files navigation

modbus-protocol

Go Reference Go Report Card

Pure Go Modbus protocol library — typed request/response models, PDU encoding/decoding, and in-memory process image. Zero external dependencies.

Features

  • Typed request and response models for FC 01–06, 0F, 10
  • TCP and RTU frame parsing and encoding
  • In-memory process image with concurrency support
  • ExecuteRequest dispatch against any ProcessImage implementation
  • PDU-level validation (address range, byte count, quantity limits)
  • CRC16, Float32 ↔ register utilities
  • Human-readable request/response formatting for debugging

Installation

go get github.com/LanceAdd/modbus-protocol

Quick Start

Parse a request and execute it

import "github.com/LanceAdd/modbus-protocol"

// Build a process image with room for 100 holding registers.
image := modbus.NewMemoryProcessImage(0, 0, 100, 0)

// A raw Modbus RTU frame (with CRC) from a client.
frame := []byte{0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xc4, 0x0b}

req, err := modbus.ParseRTURequest(frame)
if err != nil {
    panic(err)
}
fmt.Println(modbus.FormatRequest(req))
// → FC=0x03 ReadHoldingRegisters slave=1 addr=0 qty=2

resp, err := modbus.ExecuteRequest(req, image)
if err != nil {
    panic(err)
}
fmt.Println(modbus.FormatResponse(resp))
// → FC=0x03 ReadRegisters slave=1 count=2

Build a request as a client

req := modbus.NewReadInputRegistersRequest(modbus.RTU, 1, 0, 80)
payload, _ := modbus.EncodeRTURequestPayload(req)
// payload is CRC-stripped; use an RTU codec to append CRC before sending

Build a TCP request

req := modbus.NewWriteMultipleRegistersRequest(modbus.TCP, 1, 100, []uint16{0x42C8, 0x0000})
frame, _ := modbus.EncodeTCPRequest(req, 1) // transaction ID = 1
// frame is a full Modbus TCP ADU ready to write

Encode a response back to bytes

resp, _ := modbus.ExecuteRequest(req, image)
rtuFrame, _ := modbus.EncodeRTUResponse(resp)   // full RTU frame with CRC
tcpFrame, _ := modbus.EncodeTCPResponse(resp)    // full TCP ADU

CRC16

data := []byte{0x01, 0x03, 0x00, 0x00, 0x00, 0x02}
crc := modbus.CRC16(data)
fmt.Printf("%04x\n", crc) // → c40b

Float32 conversion

lo, hi := modbus.Float32ToRegisters(3.14, modbus.LowHigh)
val := modbus.RegistersToFloat32(lo, hi, modbus.LowHigh)
fmt.Println(val) // → 3.14

Supported Function Codes

Code Name Parse Encode Execute
0x01 Read Coils
0x02 Read Discrete Inputs
0x03 Read Holding Registers
0x04 Read Input Registers
0x05 Write Single Coil
0x06 Write Single Register
0x0F Write Multiple Coils
0x10 Write Multiple Registers

Exception responses (function code + 0x80) are supported for all listed function codes.

Variants

modbus.TCP  // Modbus TCP (MBAP header + PDU)
modbus.RTU  // Modbus RTU (PDU + CRC16)

ProcessImage

ProcessImage is an interface — swap in any backend:

type ProcessImage interface {
    ReadCoils(start uint16, quantity uint16) ([]bool, error)
    ReadDiscreteInputs(start uint16, quantity uint16) ([]bool, error)
    ReadHoldingRegisters(start uint16, quantity uint16) ([]uint16, error)
    ReadInputRegisters(start uint16, quantity uint16) ([]uint16, error)
    WriteSingleCoil(address uint16, value bool) error
    WriteSingleRegister(address uint16, value uint16) error
    WriteMultipleCoils(start uint16, values []bool) error
    WriteMultipleRegisters(start uint16, values []uint16) error
}

MemoryProcessImage is the built-in concurrency-safe implementation.

License

MIT

About

Pure Go Modbus protocol — typed requests, PDU codec, process image

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages