Modbus: fix calculating write length (#11950)

This commit is contained in:
andig 2024-01-29 22:41:53 +01:00 • committed by GitHub
parent d0d8cfff0d
commit 77330d1635
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 19 deletions

View file

@ -79,7 +79,7 @@ render: |
register:
address: 1042 # limit soc
type: writemultiple
decode: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
encoding: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
capacity: {{ .capacity }} # kWh
minsoc: {{ .minsoc }} # %
maxsoc: {{ .maxsoc }} # %

View file

@ -44,10 +44,30 @@ func (r Register) encoding() string {
return r.Decode
}
func (r Register) Length() (uint16, error) {
enc := r.encoding()
switch {
case strings.Contains(enc, "8") || strings.Contains(enc, "16"):
return 1, nil
case strings.Contains(enc, "32") || strings.Contains(enc, "754"):
return 2, nil
case strings.Contains(enc, "64"):
return 4, nil
default:
return 0, fmt.Errorf("invalid register encoding: %s", enc)
}
}
// Operation creates a modbus operation from a register definition
func (r Register) Operation() (RegisterOperation, error) {
len, err := r.Length()
if err != nil {
return RegisterOperation{}, err
}
op := RegisterOperation{
Addr: r.Address,
Addr: r.Address,
Length: len,
}
switch strings.ToLower(r.Type) {
@ -72,65 +92,48 @@ func (r Register) Operation() (RegisterOperation, error) {
// 8 bit (coil)
case "bool8":
op.Decode = decodeBool8
op.Length = 1
// 16 bit
case "int16":
op.Decode = asFloat64(encoding.Int16)
op.Length = 1
case "int16nan":
op.Decode = decodeNaN16(asFloat64(encoding.Int16), 1<<15, 1<<15-1)
op.Length = 1
case "uint16":
op.Decode = asFloat64(encoding.Uint16)
op.Length = 1
case "uint16nan":
op.Decode = decodeNaN16(asFloat64(encoding.Uint16), 1<<16-1)
op.Length = 1
case "bool16":
mask, err := decodeMask(r.BitMask)
if err != nil {
return op, err
}
op.Decode = decodeBool16(mask)
op.Length = 1
// 32 bit
case "int32":
op.Decode = asFloat64(encoding.Int32)
op.Length = 2
case "int32nan":
op.Decode = decodeNaN32(asFloat64(encoding.Int32), 1<<31, 1<<31-1)
op.Length = 2
case "int32s":
op.Decode = asFloat64(encoding.Int32LswFirst)
op.Length = 2
case "uint32":
op.Decode = asFloat64(encoding.Uint32)
op.Length = 2
case "uint32s":
op.Decode = asFloat64(encoding.Uint32LswFirst)
op.Length = 2
case "uint32nan":
op.Decode = decodeNaN32(asFloat64(encoding.Uint32), 1<<32-1)
op.Length = 2
case "float32", "ieee754":
op.Decode = asFloat64(encoding.Float32)
op.Length = 2
case "float32s", "ieee754s":
op.Decode = asFloat64(encoding.Float32LswFirst)
op.Length = 2
// 64 bit
case "uint64":
op.Decode = asFloat64(encoding.Uint64)
op.Length = 4
case "uint64nan":
op.Decode = decodeNaN64(asFloat64(encoding.Uint64), 1<<64-1)
op.Length = 4
case "float64":
op.Decode = encoding.Float64
op.Length = 4
default:
return RegisterOperation{}, fmt.Errorf("invalid register decoding: %s", r.Decode)

View file

@ -0,0 +1,25 @@
package modbus
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestLength(t *testing.T) {
tc := []struct {
value string
want uint16
}{
{"bool8", 1},
{"int16", 1},
{"float32", 2},
{"uint64s", 4},
}
for _, tc := range tc {
res, err := Register{Encoding: tc.value}.Length()
require.NoError(t, err, tc)
require.Equal(t, tc.want, res, tc)
}
}