Skip to content

Commit

Permalink
Modbus: fix calculating write length (#11950)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Jan 29, 2024
1 parent d0d8cff commit 77330d1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 19 deletions.
2 changes: 1 addition & 1 deletion templates/definition/meter/kostal-plenticore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }} # %
Expand Down
39 changes: 21 additions & 18 deletions util/modbus/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
25 changes: 25 additions & 0 deletions util/modbus/register_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}

0 comments on commit 77330d1

Please sign in to comment.