https://github.com/soypat/peamodbus
Fault tolerant, TCP modbus implementation in Go that just works. Apt for embedded systems.
https://github.com/soypat/peamodbus
Last synced: 2 months ago
JSON representation
Fault tolerant, TCP modbus implementation in Go that just works. Apt for embedded systems.
- Host: GitHub
- URL: https://github.com/soypat/peamodbus
- Owner: soypat
- License: mit
- Created: 2023-01-11T22:46:03.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-11-07T03:30:11.000Z (over 1 year ago)
- Last Synced: 2025-02-01T01:41:31.092Z (3 months ago)
- Language: Go
- Size: 1.78 MB
- Stars: 6
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-tinygo - peamodbus - Fault tolerant, TCP modbus implementation in Go that just works. Apt for embedded systems. (Embedded Systems / Protocol implementations)
README
[](https://pkg.go.dev/github.com/soypat/peamodbus)
[](https://goreportcard.com/report/github.com/soypat/peamodbus)
[](https://opensource.org/licenses/MIT)
[](https://github.com/soypat/peamodbus/actions/workflows/go.yml)
[](https://codecov.io/gh/soypat/peamodbus)# peamodbus
Fault tolerant, TCP modbus implementation in Go that just works. Apt for embedded systems.This is a WIP.
## Protocol sequence diagram:
Mermaid Sequence diagram
```mermaid
sequenceDiagram
participant Client
participant Server
critical No requests pending
note left of Client: peamodbus.Tx.Request*()
Client ->>+ Server: Request data read or write
note right of Server: peamodbus.Rx.ReceiveRequest()
option Handle request on server side
Server --> Server: Identify func. code and validate request.
note right of Server: peamodbus.Receive*Response()
Server --> Server: Access modbus data, read or write.
note right of Server: peamodbus.Receive*Response()
option Write response
note right of Server: peamodbus.Request.PutResponse()
Server ->>- Client: Write response (nominal or exception)
note left of Client: peamodbus.Receive*Response()
end
```## Examples
See up to date examples in [`examples`](./examples/) directory. These are just copy pasted from there and may occasionally be out of date.### Modbus Server via TCP
Click to see TCP example
```go
package mainimport (
"context"
"fmt"
"log"
"time""github.com/soypat/peamodbus"
"github.com/soypat/peamodbus/modbustcp"
)// This program creates a modbus server that adds 1 to
// all holding registers on every client request.func main() {
dataBank := peamodbus.ConcurrencySafeDataModel(&peamodbus.BlockedModel{})
sv, err := modbustcp.NewServer(modbustcp.ServerConfig{
Address: "localhost:8080",
ConnectTimeout: 5 * time.Second,
DataModel: dataBank,
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
for {
if !sv.IsConnected() {
fmt.Println("attempting connection")
err = sv.Accept(ctx)
if err != nil {
log.Println("error connecting", err)
}
time.Sleep(time.Second)
continue
}
err = sv.HandleNext()
if err != nil {
log.Println("error in HandleNext", err)
time.Sleep(time.Second)
} else {
for addr := 0; addr < 125; addr++ {
value, exc := dataBank.GetHoldingRegister(addr)
if exc != 0 {
panic(exc.Error())
}
dataBank.SetHoldingRegister(addr, value+1)
}
}
if err := sv.Err(); err != nil {
log.Println("server error:", err)
}
}
}
```### Modbus Client RTU via USB
Reads from 2 registers in an instrument connected on a port using the [`go.bug.st/serial`](https://github.com/bugst/go-serial) library.Click to see RTU example
```go
package mainimport (
"io"
"os"
"time""github.com/soypat/peamodbus/modbusrtu"
"go.bug.st/serial"
"golang.org/x/exp/slog"
)func main() {
const (
deviceAddress = 86
sensorRegisterAddress = 0
)port, err := serial.Open("/dev/ttyUSB0", &serial.Mode{
BaudRate: 9600,
DataBits: 8,
Parity: serial.NoParity,
StopBits: serial.OneStopBit,
})
if err != nil {
panic(err)
}
defer port.Close()logfp, _ := os.Create("log.txt")
defer logfp.Close()logger := slog.New(slog.NewTextHandler(io.MultiWriter(os.Stdout, logfp), &slog.HandlerOptions{
Level: slog.LevelDebug,
}))c := modbusrtu.NewClient(modbusrtu.ClientConfig{
Logger: logger,
})c.SetTransport(port)
for {
var tempHumidity [2]uint16
err = c.ReadHoldingRegisters(deviceAddress, sensorRegisterAddress, tempHumidity[:])
if err != nil {
panic(err)
}
logger.Info("read", "humidity", float32(tempHumidity[0])/10, "temperature", float32(tempHumidity[1])/10)
time.Sleep(time.Second)
}
}
```