refactored to uint16

fixed panic
This commit is contained in:
Javier Peletier
2020-12-21 12:05:57 +01:00
parent 96b3f00f29
commit 9992352454
7 changed files with 69 additions and 77 deletions
+8 -10
View File
@@ -57,19 +57,17 @@ func NewBridge(config *Config) *Bridge {
func (b *Bridge) Start() error {
zw := watcher.New(&watcher.Config{
Address: FIRST_ZONE_REGISTER,
Quantity: TOTAL_ZONE_REGISTERS,
RegisterSize: 2,
SlaveID: b.SlaveID,
Modbus: b.Modbus,
Address: FIRST_ZONE_REGISTER,
Quantity: TOTAL_ZONE_REGISTERS,
SlaveID: b.SlaveID,
Modbus: b.Modbus,
})
sysw := watcher.New(&watcher.Config{
Address: FIRST_SYS_REGISTER,
Quantity: TOTAL_SYS_REGISTERS,
RegisterSize: 2,
SlaveID: b.SlaveID,
Modbus: b.Modbus,
Address: FIRST_SYS_REGISTER,
Quantity: TOTAL_SYS_REGISTERS,
SlaveID: b.SlaveID,
Modbus: b.Modbus,
})
b.zw = zw
b.sysw = sysw
+1 -1
View File
@@ -65,7 +65,7 @@ func NewSys(config *SysConfig) *Sys {
func (s *Sys) ReadRegister(n int) int {
r := s.Watcher.ReadRegister(uint16(n))
return int(r[1])
return int(r)
}
func (s *Sys) WriteRegister(n int, value uint16) error {
+2 -4
View File
@@ -1,14 +1,13 @@
package kn
import (
"encoding/binary"
"math"
average "github.com/RobinUS2/golang-moving-average"
)
type Watcher interface {
ReadRegister(address uint16) (value []byte)
ReadRegister(address uint16) (value uint16)
WriteRegister(address uint16, value uint16) error
RegisterCallback(address uint16, callback func(address uint16))
}
@@ -67,8 +66,7 @@ func (z *Zone) RegisterCallback(num int, f func()) {
}
func (z *Zone) ReadRegister(num int) uint16 {
b := z.Watcher.ReadRegister(uint16((z.ZoneNumber-1)*REG_PER_ZONE + num))
return binary.BigEndian.Uint16(b)
return z.Watcher.ReadRegister(uint16((z.ZoneNumber-1)*REG_PER_ZONE + num))
}
func (z *Zone) WriteRegister(num int, value uint16) error {
+4 -9
View File
@@ -1,7 +1,6 @@
package modbus
import (
"encoding/binary"
"errors"
)
@@ -18,28 +17,24 @@ func NewMock() Modbus {
}
}
func (ms *Mock) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []byte, err error) {
func (ms *Mock) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []uint16, err error) {
state, ok := ms.State[slaveID]
if !ok {
return nil, errors.New("Unknown slave")
}
address--
for a := address; a < address+quantity; a++ {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, state[a])
results = append(results, b...)
results = append(results, state[a])
}
return results, nil
}
func (ms *Mock) WriteRegister(slaveID byte, address uint16, value uint16) (results []byte, err error) {
func (ms *Mock) WriteRegister(slaveID byte, address uint16, value uint16) (results []uint16, err error) {
state, ok := ms.State[slaveID]
if !ok {
return nil, errors.New("Unknown slave")
}
state[address-1] = value
results = make([]byte, 2)
binary.BigEndian.PutUint16(results, value)
return results, nil
return []uint16{value}, nil
}
func (ms *Mock) Close() error { return nil }
+29 -6
View File
@@ -1,6 +1,8 @@
package modbus
import (
"encoding/binary"
"errors"
"log"
"sync"
"time"
@@ -9,8 +11,8 @@ import (
)
type Modbus interface {
ReadRegister(slaveID byte, address uint16, quantity uint16) (results []byte, err error)
WriteRegister(slaveID byte, address uint16, value uint16) (results []byte, err error)
ReadRegister(slaveID byte, address uint16, quantity uint16) (results []uint16, err error)
WriteRegister(slaveID byte, address uint16, value uint16) (results []uint16, err error)
Close() error
}
@@ -33,6 +35,8 @@ func throttle(ms int) {
time.Sleep(time.Duration(ms) * time.Millisecond)
}
var ErrIncorrectResultSize = errors.New("Incorrect number of results returned")
func New(config *Config) (Modbus, error) {
handler := gmodbus.NewRTUClientHandler(config.Port)
handler.BaudRate = config.BaudRate
@@ -51,17 +55,36 @@ func (mb *modbus) Close() error {
return mb.handler.Close()
}
func (mb *modbus) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []byte, err error) {
func parseResults(r []byte, quantity uint16) ([]uint16, error) {
if len(r) != int(quantity*2) {
return nil, ErrIncorrectResultSize
}
results := make([]uint16, quantity)
for n := uint16(0); n < quantity; n++ {
results[n] = binary.BigEndian.Uint16(r[n*2 : n*2+2])
}
return results, nil
}
func (mb *modbus) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []uint16, err error) {
err = mb.try(slaveID, func() (err error) {
results, err = mb.client.ReadHoldingRegisters(address-1, quantity)
r, err := mb.client.ReadHoldingRegisters(address-1, quantity)
if err != nil {
return err
}
results, err = parseResults(r, quantity)
return err
})
return results, err
}
func (mb *modbus) WriteRegister(slaveID byte, address uint16, value uint16) (results []byte, err error) {
func (mb *modbus) WriteRegister(slaveID byte, address uint16, value uint16) (results []uint16, err error) {
err = mb.try(slaveID, func() (err error) {
results, err = mb.client.WriteSingleRegister(address-1, value)
r, err := mb.client.WriteSingleRegister(address-1, value)
if err != nil {
return err
}
results, err = parseResults(r, 1)
return err
})
return results, err
+12 -29
View File
@@ -3,7 +3,6 @@
package watcher
import (
"bytes"
"errors"
"koolnova2mqtt/modbus"
"sync"
@@ -11,22 +10,20 @@ import (
// Config contains the configuration parameters for a new Watcher instance
type Config struct {
Address uint16 // Start address
Quantity uint16 // Number of registers to watch
SlaveID byte // SlaveID to watch
Modbus modbus.Modbus // Modbus interface
RegisterSize int // size of each register
Address uint16 // Start address
Quantity uint16 // Number of registers to watch
SlaveID byte // SlaveID to watch
Modbus modbus.Modbus // Modbus interface
}
// Watcher represents a cache of modbus registers in a device
type Watcher struct {
Config
state []byte // current view of the modbus register states
state []uint16 // current view of the modbus register states
callbacks map[uint16]func(address uint16) // set of callbacks
lock *sync.RWMutex
}
var ErrIncorrectRegisterSize = errors.New("Incorrect register size")
var ErrAddressOutOfRange = errors.New("Register address out of range")
var ErrUninitialized = errors.New("State uninitialized. Call Poll() first.")
var ErrCannotIncreaseRange = errors.New("Cannot increase range")
@@ -54,30 +51,18 @@ func (w *Watcher) Poll() error {
return err
}
if len(newState) != int(w.Quantity)*w.RegisterSize {
w.lock.Unlock()
return ErrIncorrectRegisterSize
}
oldState := w.state
w.state = newState
var callbackAddresses []uint16
first := len(oldState) != len(newState)
for n := 0; n < len(newState); n += w.RegisterSize {
address := uint16(n/w.RegisterSize) + w.Address
for n := 0; n < len(newState); n++ {
address := uint16(n) + w.Address
callback := w.callbacks[address]
if callback == nil {
continue
}
var oldValue []byte
newValue := newState[n : n+w.RegisterSize]
if first {
oldValue = nil
} else {
oldValue = oldState[n : n+w.RegisterSize]
}
if bytes.Compare(oldValue, newValue) != 0 {
if first || oldState[n] != newState[n] {
callbackAddresses = append(callbackAddresses, address)
}
}
@@ -90,7 +75,7 @@ func (w *Watcher) Poll() error {
}
// ReadRegister reads one register from the cache
func (w *Watcher) ReadRegister(address uint16) (value []byte) {
func (w *Watcher) ReadRegister(address uint16) (value uint16) {
w.lock.Lock()
defer w.lock.Unlock()
if address < w.Address || address > w.Address+uint16(w.Quantity) {
@@ -99,8 +84,7 @@ func (w *Watcher) ReadRegister(address uint16) (value []byte) {
if w.state == nil {
panic(ErrUninitialized)
}
registerOffset := int(address-w.Address) * w.RegisterSize
return w.state[registerOffset : registerOffset+w.RegisterSize]
return w.state[int(address-w.Address)]
}
@@ -112,8 +96,7 @@ func (w *Watcher) WriteRegister(address uint16, value uint16) error {
w.lock.Unlock()
return err
}
registerOffset := int(address-w.Address) * w.RegisterSize
copy(w.state[registerOffset:registerOffset+w.RegisterSize], results)
w.state[int(address-w.Address)] = results[0]
callback := w.callbacks[address]
w.lock.Unlock()
if callback != nil {
@@ -134,7 +117,7 @@ func (w *Watcher) Resize(newQuantity int) {
w.lock.Lock()
defer w.lock.Unlock()
if newQuantity <= int(w.Quantity) {
w.state = w.state[:newQuantity*w.RegisterSize]
w.state = w.state[:newQuantity]
for address := range w.callbacks {
if address > w.Address+uint16(newQuantity)-1 {
delete(w.callbacks, address)
+13 -18
View File
@@ -14,11 +14,11 @@ var modbusError error
type BuggyModbus struct {
}
func (ms *BuggyModbus) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []byte, err error) {
return []byte{1, 2}, modbusError
func (ms *BuggyModbus) ReadRegister(slaveID byte, address uint16, quantity uint16) (results []uint16, err error) {
return []uint16{0x0102}, modbusError
}
func (ms *BuggyModbus) WriteRegister(slaveID byte, address uint16, value uint16) (results []byte, err error) {
func (ms *BuggyModbus) WriteRegister(slaveID byte, address uint16, value uint16) (results []uint16, err error) {
return nil, modbusError
}
@@ -30,11 +30,10 @@ func TestWatcher(tx *testing.T) {
var err error
w := watcher.New(&watcher.Config{
Address: 1,
Quantity: 5,
RegisterSize: 2,
SlaveID: 49,
Modbus: modbus.NewMock(),
Address: 1,
Quantity: 5,
SlaveID: 49,
Modbus: modbus.NewMock(),
})
var cbAddress uint16
@@ -58,7 +57,7 @@ func TestWatcher(tx *testing.T) {
value := w.ReadRegister(1)
t.Ok(err)
t.Equals([]byte{0, 3}, value)
t.Equals(uint16(0x0003), value)
t.MustPanicWith(watcher.ErrAddressOutOfRange, func() {
w.ReadRegister(200)
@@ -80,7 +79,7 @@ func TestWatcher(tx *testing.T) {
t.Equals(uint16(3), cbAddress)
cbNewValue := w.ReadRegister(3)
t.Equals([]byte{0x12, 0x34}, cbNewValue)
t.Equals(uint16(0x1234), cbNewValue)
callbackCount = 0
err = w.Poll()
@@ -91,16 +90,12 @@ func TestWatcher(tx *testing.T) {
t.Equals(2, callbackCount)
w = watcher.New(&watcher.Config{
Address: 1,
Quantity: 5,
RegisterSize: 2,
SlaveID: 1,
Modbus: &BuggyModbus{},
Address: 1,
Quantity: 5,
SlaveID: 1,
Modbus: &BuggyModbus{},
})
err = w.Poll()
t.MustFailWith(err, watcher.ErrIncorrectRegisterSize)
modbusError = errors.New("error")
err = w.Poll()