modbus

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2020 License: Apache-2.0 Imports: 8 Imported by: 4

README

Simple IoT Modbus

This Simple IoT modbus packet is a package that implements both Modbus client and server functionality. Motivation for creating this library:

  • really want to be able to pass in my own io.ReadWriter into these libs. New and better serial libs are continually coming out, and it seems that hardcoding serial operations in the modbus lib makes this brittle.
  • allows use of https://pkg.go.dev/github.com/simpleiot/simpleiot/respreader to do packet framing. This may not be the most efficient, but is super easy and eliminates the need to parse packets as they come in.
  • passing in io.ReadWriter allows us to easily unit test end to end communication (see end-to-end test above)
  • library in constructed in a modular fashion from lowest units (PDU) on up, so it is easy to test
  • not satisfied with the mbserver way of hooking in register operations. Seems over complicated, and unfinished.
  • want one library for both client/server. This is necessary to test everything, and there is no big reason not to do this.
  • need a library that is maintained, accepts PRs, etc.
  • could not find any good tools for testing modbus (client or server). Most are old apps for windows (I use Linux) and are difficult to use. After messing around too long in a windows VM, I decided its time for a decent command line app that does this. Seems like there should be a simple command line tool that can be made to do this and run on any OS (Go is perfect for building this type of thing).

Documentation

Index

Constants

View Source
const (
	// Bit access
	FuncCodeReadDiscreteInputs FunctionCode = 2
	FuncCodeReadCoils                       = 1
	FuncCodeWriteSingleCoil                 = 5
	FuncCodeWriteMultipleCoils              = 15

	// 16-bit access
	FuncCodeReadInputRegisters         = 4
	FuncCodeReadHoldingRegisters       = 3
	FuncCodeWriteSingleRegister        = 6
	FuncCodeWriteMultipleRegisters     = 16
	FuncCodeReadWriteMultipleRegisters = 23
	FuncCodeMaskWriteRegister          = 22
	FuncCodeReadFIFOQueue              = 24
)

Defined valid function codes

Variables

View Source
var ErrCrc = errors.New("CRC error")

ErrCrc is returned if a crc check fails

View Source
var ErrNotEnoughData = errors.New("Not enough data to calculate CRC")

ErrNotEnoughData is returned if not enough data

Functions

func CheckRtuCrc added in v0.0.2

func CheckRtuCrc(packet []byte) error

CheckRtuCrc returns error if CRC fails

func DecodeASCIIByte

func DecodeASCIIByte(data []byte) (byte, []byte, error)

DecodeASCIIByte converts type ascii hex bytes to a binary byte

func DecodeASCIIByteEnd

func DecodeASCIIByteEnd(data []byte) (byte, []byte, error)

DecodeASCIIByteEnd converts type ascii hex bytes to a binary byte. This function takes from the end of the slice

func HexDump added in v0.0.2

func HexDump(data []byte) string

HexDump provides a string of bytes in hex format

func PutUint16Array added in v0.0.2

func PutUint16Array(value ...uint16) []byte

PutUint16Array creates a sequence of uint16 data.

func RtuCrc added in v0.0.2

func RtuCrc(buf []byte) uint16

RtuCrc calculates CRC for a Modbus RTU packet

func RtuEncode added in v0.0.2

func RtuEncode(id byte, pdu PDU) ([]byte, error)

RtuEncode encodes a RTU packet

func Uint16Array added in v0.0.2

func Uint16Array(data []byte) []uint16

Uint16Array unpacks 16 bit data values from a buffer (in big endian format)

Types

type ASCIIADU added in v0.0.2

type ASCIIADU struct {
	Address      byte
	FunctionCode FunctionCode
	Data         []byte
	LRC          byte
	End          []byte // should be "\r\n"
}

ASCIIADU is a modbus protocol data unit

func DecodeASCIIPDU

func DecodeASCIIPDU(data []byte) (ret ASCIIADU, err error)

DecodeASCIIPDU decodes a ASCII modbus packet

func (*ASCIIADU) CheckLRC added in v0.0.2

func (adu *ASCIIADU) CheckLRC() bool

CheckLRC verifies the LRC is valid

func (*ASCIIADU) DecodeFunctionData added in v0.0.2

func (adu *ASCIIADU) DecodeFunctionData() (ret interface{}, err error)

DecodeFunctionData extracts the function data from the PDU

type Client added in v0.0.2

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

Client defines a Modbus client (master)

func NewClient added in v0.0.2

func NewClient(port io.ReadWriter) *Client

NewClient is used to create a new modbus client

func (*Client) ReadCoils added in v0.0.2

func (c *Client) ReadCoils(id byte, coil, count uint16) ([]bool, error)

ReadCoils is used to read modbus coils

type FuncReadHoldingRegisterResponse

type FuncReadHoldingRegisterResponse struct {
	FunctionCode FunctionCode
	RegCount     byte
	RegValues    []uint16
}

FuncReadHoldingRegisterResponse response to read holding reg

type FuncReadHoldingRegistersRequest

type FuncReadHoldingRegistersRequest struct {
	FunctionCode    FunctionCode
	StartingAddress uint16
	RegCount        uint16
}

FuncReadHoldingRegistersRequest represents the request to read holding reg

type FuncWriteMultipleRegisterRequest

type FuncWriteMultipleRegisterRequest struct {
	FunctionCode    FunctionCode
	StartingAddress uint16
	RegCount        uint16
	ByteCount       byte
	RegValues       []uint16
}

FuncWriteMultipleRegisterRequest represents the request to write multiple regs

type FunctionCode

type FunctionCode byte

FunctionCode represents a modbus function code

type IoSim added in v0.0.2

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

IoSim simulates a serial port and provides a io.ReadWriter for both ends

func NewIoSim added in v0.0.2

func NewIoSim(debug bool) *IoSim

NewIoSim creates a new IO simulator

func (*IoSim) GetA added in v0.0.2

func (is *IoSim) GetA() io.ReadWriter

GetA returns the A port from a IoSim

func (*IoSim) GetB added in v0.0.2

func (is *IoSim) GetB() io.ReadWriter

GetB returns the B port from a IoSim

type IoSimPort added in v0.0.2

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

IoSimPort one end of a IoSim

func NewIoSimPort added in v0.0.2

func NewIoSimPort(name string, tx chan byte, rx chan byte, debug bool) *IoSimPort

NewIoSimPort returns a new port of an IoSim

func (*IoSimPort) Read added in v0.0.2

func (isp *IoSimPort) Read(data []byte) (int, error)

Read reads data from IoSimPort

func (*IoSimPort) Write added in v0.0.2

func (isp *IoSimPort) Write(data []byte) (int, error)

Write reads data from IoSimPort

type Modbus

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

Modbus is a type that implements modbus ascii communication. Currently, only "sniffing" a network is implemented

func NewModbus

func NewModbus(port io.ReadWriter) *Modbus

NewModbus creates a new Modbus

func (*Modbus) Read

func (m *Modbus) Read() ([]byte, error)

Read returns an ASCII modbus packet. Blocks until a full packet is received or error

type PDU

type PDU struct {
	FunctionCode FunctionCode
	Data         []byte
}

PDU for Modbus packets

func ReadCoils added in v0.0.2

func ReadCoils(address uint16, count uint16) PDU

ReadCoils creates PDU to read coils

func ReadHoldingRegs added in v0.0.2

func ReadHoldingRegs(address uint16, count uint16) PDU

ReadHoldingRegs creates a PDU to read a holding regs

func RtuDecode added in v0.0.2

func RtuDecode(packet []byte) (PDU, error)

RtuDecode decodes a RTU packet

func (*PDU) ProcessRequest added in v0.0.2

func (p *PDU) ProcessRequest(regs *Regs) ([]RegChange, PDU, error)

ProcessRequest a modbus request. Registers are read and written through the server interface argument. This function returns any register changes, the modbus respose, and any errors

func (*PDU) RespReadBits added in v0.0.2

func (p *PDU) RespReadBits() ([]bool, error)

RespReadBits reads coils and discrete inputs from a response PDU.

func (PDU) String added in v0.0.2

func (p PDU) String() string

type Reg added in v0.0.2

type Reg struct {
	Address uint16
	Value   uint16
}

Reg defines a Modbus register

type RegChange added in v0.0.2

type RegChange struct {
	Address uint16
	Old     uint16
	New     uint16
}

RegChange is a type that describes a modbus register change the address, old value and new value of the register are provided. This allows application software to take action when things change.

type Regs added in v0.0.2

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

Regs represents all registers in a modbus device and provides functions to read/write 16-bit and bit values. This register module assumes all register types map into one address space as described in the modbus spec (http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf) on page 6 and 7. All operations on Regs are threadsafe and protected by a mutex.

func (*Regs) AddCoil added in v0.0.2

func (r *Regs) AddCoil(num int)

AddCoil is used to add a discrete io to the register map. Note coils are aliased on top of other registers, so coil 20 would be register 1 bit 4 (16 + 4 = 20).

func (*Regs) AddReg added in v0.0.2

func (r *Regs) AddReg(address uint16)

AddReg is used to add a modbus register to the server. the callback function is called when the reg is updated The register can be updated by word or bit operations.

func (*Regs) ReadCoil added in v0.0.2

func (r *Regs) ReadCoil(num int) (bool, error)

ReadCoil gets a coil value (can also be used for discrete inputs)

func (*Regs) ReadReg added in v0.0.2

func (r *Regs) ReadReg(address uint16) (uint16, error)

ReadReg is used to read a modbus register

func (*Regs) WriteCoil added in v0.0.2

func (r *Regs) WriteCoil(num int, value bool) error

WriteCoil writes a coil value

func (*Regs) WriteReg added in v0.0.2

func (r *Regs) WriteReg(address uint16, value uint16) error

WriteReg is used to write a modbus register

type RtuADU added in v0.0.2

type RtuADU struct {
	PDU
	Address byte
	CRC     uint16
}

RtuADU defines an ADU for RTU packets

type Server added in v0.0.2

type Server struct {
	Regs Regs
	// contains filtered or unexported fields
}

Server defines a server (slave) Current Server only supports Modbus RTU, but could be expanded to do ASCII and TCP.

func NewServer added in v0.0.2

func NewServer(id byte, port io.ReadWriter) *Server

NewServer creates a new server instance port must return an entire packet for each Read(). github.com/simpleiot/simpleiot/respreader is a good way to do this.

func (*Server) Listen added in v0.0.2

func (s *Server) Listen(errorCallback func(error),
	changesCallback func([]RegChange))

Listen starts the server and listens for modbus requests this function does not return unless and error occurs

Jump to

Keyboard shortcuts

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