gh-24 updateCoils and updateRegisters now use common modbus.Client

This commit is contained in:
Jarno Rankinen 2023-03-09 21:26:28 +02:00
parent a49978ee5f
commit 602a560cf9
1 changed files with 62 additions and 63 deletions

View File

@ -24,12 +24,14 @@ type pingvinCoil struct {
// unit modbus data // unit modbus data
type PingvinKL struct { type PingvinKL struct {
Coils []pingvinCoil Coils []pingvinCoil
Registers []pingvinRegister Registers []pingvinRegister
Status pingvinStatus Status pingvinStatus
buslock *sync.Mutex buslock *sync.Mutex
statuslock *sync.Mutex statuslock *sync.Mutex
Debug PingvinLogger handler *modbus.RTUClientHandler
modbusclient modbus.Client
Debug PingvinLogger
} }
// single register data // single register data
@ -145,33 +147,35 @@ func readCsvLines(file string) [][]string {
return data return data
} }
// Configure the modbus parameters func (p *PingvinKL) createModbusClient() {
func (p PingvinKL) getHandler() *modbus.RTUClientHandler {
// TODO: read configuration from file, hardcoded for now // TODO: read configuration from file, hardcoded for now
handler := modbus.NewRTUClientHandler("/dev/ttyS0") p.handler = modbus.NewRTUClientHandler("/dev/ttyS0")
handler.BaudRate = 19200 p.handler.BaudRate = 19200
handler.DataBits = 8 p.handler.DataBits = 8
handler.Parity = "N" p.handler.Parity = "N"
handler.StopBits = 1 p.handler.StopBits = 1
handler.SlaveId = 1 p.handler.SlaveId = 1
handler.Timeout = 1500 * time.Millisecond p.handler.Timeout = 1500 * time.Millisecond
return handler err := p.handler.Connect()
if err != nil {
log.Fatal("createModbusClient: p.handler.Connect: ", err)
}
p.Debug.Println("Handler connected")
p.modbusclient = modbus.NewClient(p.handler)
}
func (p *PingvinKL) Quit() {
err := p.handler.Close()
if err != nil {
log.Println("ERROR: Quit:", err)
}
} }
func (p *PingvinKL) updateCoils() { func (p *PingvinKL) updateCoils() {
handler := p.getHandler() results, err := p.modbusclient.ReadCoils(0, uint16(len(p.Coils)))
p.buslock.Lock()
err := handler.Connect()
if err != nil {
log.Fatal("updateCoils: handler.Connect: ", err)
}
defer handler.Close()
client := modbus.NewClient(handler)
results, err := client.ReadCoils(0, uint16(len(p.Coils)))
if err != nil { if err != nil {
log.Fatal("updateCoils: client.ReadCoils: ", err) log.Fatal("updateCoils: client.ReadCoils: ", err)
} }
p.buslock.Unlock()
// modbus.ReadCoils returns a byte array, with the first byte's bits representing coil values 0-7, // modbus.ReadCoils returns a byte array, with the first byte's bits representing coil values 0-7,
// second byte coils 8-15 etc. // second byte coils 8-15 etc.
// Within each byte, LSB represents the lowest n coil while MSB is the highest // Within each byte, LSB represents the lowest n coil while MSB is the highest
@ -192,17 +196,17 @@ func (p *PingvinKL) updateCoils() {
} }
func (p *PingvinKL) ReadRegister(addr uint16) (int, error) { func (p *PingvinKL) ReadRegister(addr uint16) (int, error) {
handler := p.getHandler() // handler := p.getHandler()
p.buslock.Lock() p.buslock.Lock()
defer p.buslock.Unlock() defer p.buslock.Unlock()
err := handler.Connect() err := p.handler.Connect()
if err != nil { if err != nil {
log.Println("ERROR: ReadRegister:", err) log.Println("ERROR: ReadRegister:", err)
return 0, err return 0, err
} }
defer handler.Close() // defer handler.Close()
client := modbus.NewClient(handler) // client := modbus.NewClient(handler)
results, err := client.ReadHoldingRegisters(addr, 1) results, err := p.modbusclient.ReadHoldingRegisters(addr, 1)
if err != nil { if err != nil {
log.Println("ERROR: ReadRegister:", err) log.Println("ERROR: ReadRegister:", err)
return 0, err return 0, err
@ -218,17 +222,17 @@ func (p *PingvinKL) ReadRegister(addr uint16) (int, error) {
} }
func (p *PingvinKL) WriteRegister(addr uint16, value uint16) (uint16, error) { func (p *PingvinKL) WriteRegister(addr uint16, value uint16) (uint16, error) {
handler := p.getHandler() // handler := p.getHandler()
p.buslock.Lock() p.buslock.Lock()
defer p.buslock.Unlock() defer p.buslock.Unlock()
err := handler.Connect() err := p.handler.Connect()
if err != nil { if err != nil {
log.Println("ERROR: WriteRegister:", err) log.Println("ERROR: WriteRegister:", err)
return 0, err return 0, err
} }
defer handler.Close() defer p.handler.Close()
client := modbus.NewClient(handler) // client := modbus.NewClient(handler)
_, err = client.WriteSingleRegister(addr, value) _, err = p.modbusclient.WriteSingleRegister(addr, value)
if err != nil { if err != nil {
log.Println("ERROR: WriteRegister:", err) log.Println("ERROR: WriteRegister:", err)
return 0, err return 0, err
@ -241,14 +245,7 @@ func (p *PingvinKL) WriteRegister(addr uint16, value uint16) (uint16, error) {
} }
func (p *PingvinKL) updateRegisters() { func (p *PingvinKL) updateRegisters() {
handler := p.getHandler() var err error
p.buslock.Lock()
err := handler.Connect()
if err != nil {
log.Fatal("updateRegisters: handler.Connect: ", err)
}
defer handler.Close()
client := modbus.NewClient(handler)
regs := len(p.Registers) regs := len(p.Registers)
k := 0 k := 0
// modbus.ReadHoldingRegisters can read 125 regs at a time, so first we loop // modbus.ReadHoldingRegisters can read 125 regs at a time, so first we loop
@ -261,7 +258,8 @@ func (p *PingvinKL) updateRegisters() {
} }
results := []byte{} results := []byte{}
for retries := 0; retries < 5; retries++ { for retries := 0; retries < 5; retries++ {
results, err = client.ReadHoldingRegisters(uint16(k), uint16(r)) p.Debug.Println("Reading registers, attempt", retries, "k:", k)
results, err = p.modbusclient.ReadHoldingRegisters(uint16(k), uint16(r))
if len(results) > 0 { if len(results) > 0 {
break break
} else if retries == 4 { } else if retries == 4 {
@ -307,25 +305,25 @@ func (p *PingvinKL) updateRegisters() {
msb = !msb msb = !msb
} }
} }
p.buslock.Unlock()
} }
func (p *PingvinKL) Update() { func (p *PingvinKL) Update() {
p.updateCoils() p.updateCoils()
p.updateRegisters() p.updateRegisters()
p.populateStatus() p.populateStatus()
log.Println(p.Status)
} }
func (p PingvinKL) ReadCoil(n uint16) []byte { func (p PingvinKL) ReadCoil(n uint16) []byte {
handler := p.getHandler() // handler := p.getHandler()
p.buslock.Lock() p.buslock.Lock()
err := handler.Connect() err := p.handler.Connect()
if err != nil { if err != nil {
log.Fatal("ReadCoil: handler.Connect: ", err) log.Fatal("ReadCoil: handler.Connect: ", err)
} }
defer handler.Close() defer p.handler.Close()
client := modbus.NewClient(handler) // client := modbus.NewClient(handler)
results, err := client.ReadCoils(n, 1) results, err := p.modbusclient.ReadCoils(n, 1)
p.buslock.Unlock() p.buslock.Unlock()
if err != nil { if err != nil {
log.Fatal("ReadCoil: client.ReadCoils: ", err) log.Fatal("ReadCoil: client.ReadCoils: ", err)
@ -335,23 +333,23 @@ func (p PingvinKL) ReadCoil(n uint16) []byte {
} }
func (p *PingvinKL) WriteCoil(n uint16, val bool) bool { func (p *PingvinKL) WriteCoil(n uint16, val bool) bool {
handler := p.getHandler() // handler := p.getHandler()
p.buslock.Lock() p.buslock.Lock()
err := handler.Connect() err := p.handler.Connect()
if val { if val {
p.checkMutexCoils(n, handler) p.checkMutexCoils(n, p.handler)
} }
if err != nil { if err != nil {
log.Println("WARNING: WriteCoil: failed to connect handler") log.Println("WARNING: WriteCoil: failed to connect handler")
return false return false
} }
defer handler.Close() defer p.handler.Close()
var value uint16 = 0 var value uint16 = 0
if val { if val {
value = 0xff00 value = 0xff00
} }
client := modbus.NewClient(handler) // client := modbus.NewClient(handler)
results, err := client.WriteSingleCoil(n, value) results, err := p.modbusclient.WriteSingleCoil(n, value)
p.buslock.Unlock() p.buslock.Unlock()
if err != nil { if err != nil {
log.Println("ERROR: WriteCoil: ", err) log.Println("ERROR: WriteCoil: ", err)
@ -368,14 +366,14 @@ func (p *PingvinKL) WriteCoil(n uint16, val bool) bool {
} }
func (p *PingvinKL) WriteCoils(startaddr uint16, quantity uint16, vals []bool) error { func (p *PingvinKL) WriteCoils(startaddr uint16, quantity uint16, vals []bool) error {
handler := p.getHandler() // handler := p.getHandler()
p.buslock.Lock() p.buslock.Lock()
err := handler.Connect() err := p.handler.Connect()
if err != nil { if err != nil {
log.Println("WARNING: WriteCoils: failed to connect handler:", err) log.Println("WARNING: WriteCoils: failed to connect handler:", err)
return err return err
} }
defer handler.Close() defer p.handler.Close()
p.updateCoils() p.updateCoils()
coilslice := p.Coils[startaddr:(startaddr + quantity)] coilslice := p.Coils[startaddr:(startaddr + quantity)]
if len(coilslice) != len(vals) { if len(coilslice) != len(vals) {
@ -413,8 +411,8 @@ func (p *PingvinKL) WriteCoils(startaddr uint16, quantity uint16, vals []bool) e
p.Debug.Println("index:", i/8, "value:", bits[i/8], "shift:", i%8) p.Debug.Println("index:", i/8, "value:", bits[i/8], "shift:", i%8)
} }
log.Println(bits) log.Println(bits)
client := modbus.NewClient(handler) // client := modbus.NewClient(handler)
results, err := client.WriteMultipleCoils(startaddr, quantity, bits) results, err := p.modbusclient.WriteMultipleCoils(startaddr, quantity, bits)
p.buslock.Unlock() p.buslock.Unlock()
if err != nil { if err != nil {
log.Println("ERROR: WriteCoils: ", err) log.Println("ERROR: WriteCoils: ", err)
@ -429,7 +427,7 @@ func (p *PingvinKL) checkMutexCoils(addr uint16, handler *modbus.RTUClientHandle
if mutexcoil == addr { if mutexcoil == addr {
for _, n := range mutexcoils { for _, n := range mutexcoils {
if p.Coils[n].Value { if p.Coils[n].Value {
_, err := modbus.NewClient(handler).WriteSingleCoil(n, 0) _, err := p.modbusclient.WriteSingleCoil(n, 0)
if err != nil { if err != nil {
log.Println("ERROR: checkMutexCoils:", err) log.Println("ERROR: checkMutexCoils:", err)
return err return err
@ -553,6 +551,7 @@ func New(debug bool) PingvinKL {
pingvin := PingvinKL{} pingvin := PingvinKL{}
pingvin.Debug.dbg = debug pingvin.Debug.dbg = debug
pingvin.buslock = &sync.Mutex{} pingvin.buslock = &sync.Mutex{}
pingvin.createModbusClient()
log.Println("Parsing coil data...") log.Println("Parsing coil data...")
coilData := readCsvLines("coils.csv") coilData := readCsvLines("coils.csv")
for i := 0; i < len(coilData); i++ { for i := 0; i < len(coilData); i++ {