fix: reading multiple holding registers in modbus input plugin (#8628)

This commit is contained in:
Antonio Garcia 2021-02-26 10:45:33 -06:00 committed by GitHub
parent e1a896ca12
commit 7ed98c7e5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 118 additions and 11 deletions

View File

@ -217,23 +217,33 @@ func (m *Modbus) InitRegister(fields []fieldContainer, name string) error {
sort.Slice(addrs, func(i, j int) bool { return addrs[i] < addrs[j] })
ii := 0
maxQuantity := 1
var registersRange []registerRange
if name == cDiscreteInputs || name == cCoils {
maxQuantity = 2000
} else if name == cInputRegisters || name == cHoldingRegisters {
maxQuantity = 125
}
// Get range of consecutive integers
// [1, 2, 3, 5, 6, 10, 11, 12, 14]
// (1, 3) , (5, 2) , (10, 3), (14 , 1)
for range addrs {
if ii < len(addrs) {
start := addrs[ii]
end := start
for ii < len(addrs)-1 && addrs[ii+1]-addrs[ii] == 1 {
end = addrs[ii+1]
ii++
}
ii++
registersRange = append(registersRange, registerRange{start, end - start + 1})
if ii >= len(addrs) {
break
}
quantity := 1
start := addrs[ii]
end := start
for ii < len(addrs)-1 && addrs[ii+1]-addrs[ii] == 1 && quantity < maxQuantity {
end = addrs[ii+1]
ii++
quantity++
}
ii++
registersRange = append(registersRange, registerRange{start, end - start + 1})
}
m.registers = append(m.registers, register{name, registersRange, fields})
@ -434,7 +444,7 @@ func (m *Modbus) getFields() error {
for bitPosition := 0; bitPosition < 8; bitPosition++ {
bitRawValues[address] = getBitValue(readValue, bitPosition)
address = address + 1
if address+1 > rr.length {
if address > rr.address+rr.length {
break
}
}

View File

@ -1,6 +1,7 @@
package modbus
import (
"fmt"
"testing"
m "github.com/goburrow/modbus"
@ -657,6 +658,102 @@ func TestHoldingRegisters(t *testing.T) {
}
}
func TestReadMultipleCoilLimit(t *testing.T) {
serv := mbserver.NewServer()
err := serv.ListenTCP("localhost:1502")
assert.NoError(t, err)
defer serv.Close()
handler := m.NewTCPClientHandler("localhost:1502")
err = handler.Connect()
assert.NoError(t, err)
defer handler.Close()
client := m.NewClient(handler)
fcs := []fieldContainer{}
writeValue := uint16(0)
for i := 0; i <= 4000; i++ {
fc := fieldContainer{}
fc.Name = fmt.Sprintf("coil-%v", i)
fc.Address = []uint16{uint16(i)}
fcs = append(fcs, fc)
t.Run(fc.Name, func(t *testing.T) {
_, err = client.WriteSingleCoil(fc.Address[0], writeValue)
assert.NoError(t, err)
})
writeValue = 65280 - writeValue
}
modbus := Modbus{
Name: "TestReadCoils",
Controller: "tcp://localhost:1502",
SlaveID: 1,
Coils: fcs,
}
err = modbus.Init()
assert.NoError(t, err)
var acc testutil.Accumulator
err = modbus.Gather(&acc)
assert.NoError(t, err)
writeValue = 0
for i := 0; i <= 4000; i++ {
t.Run(modbus.registers[0].Fields[i].Name, func(t *testing.T) {
assert.Equal(t, writeValue, modbus.registers[0].Fields[i].value)
writeValue = 1 - writeValue
})
}
}
func TestReadMultipleHoldingRegisterLimit(t *testing.T) {
serv := mbserver.NewServer()
err := serv.ListenTCP("localhost:1502")
assert.NoError(t, err)
defer serv.Close()
handler := m.NewTCPClientHandler("localhost:1502")
err = handler.Connect()
assert.NoError(t, err)
defer handler.Close()
client := m.NewClient(handler)
fcs := []fieldContainer{}
for i := 0; i <= 400; i++ {
fc := fieldContainer{}
fc.Name = fmt.Sprintf("HoldingRegister-%v", i)
fc.ByteOrder = "AB"
fc.DataType = "INT16"
fc.Scale = 1.0
fc.Address = []uint16{uint16(i)}
fcs = append(fcs, fc)
t.Run(fc.Name, func(t *testing.T) {
_, err = client.WriteSingleRegister(fc.Address[0], uint16(i))
assert.NoError(t, err)
})
}
modbus := Modbus{
Name: "TestHoldingRegister",
Controller: "tcp://localhost:1502",
SlaveID: 1,
HoldingRegisters: fcs,
}
err = modbus.Init()
assert.NoError(t, err)
var acc testutil.Accumulator
err = modbus.Gather(&acc)
assert.NoError(t, err)
for i := 0; i <= 400; i++ {
assert.Equal(t, int16(i), modbus.registers[0].Fields[i].value)
}
}
func TestRetrySuccessful(t *testing.T) {
retries := 0
maxretries := 2