Modbus: handle NaN values (#31011)
This commit is contained in:
parent
2a86cc44b1
commit
cc6bef6b82
4 changed files with 26 additions and 9 deletions
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -81,7 +82,7 @@ func decodeNaN16(f func(b []byte) float64, nan ...uint16) func(b []byte) float64
|
|||
return func(b []byte) float64 {
|
||||
u := binary.BigEndian.Uint16(b)
|
||||
if slices.Contains(nan, u) {
|
||||
return 0
|
||||
return math.NaN()
|
||||
}
|
||||
return f(b)
|
||||
}
|
||||
|
|
@ -91,7 +92,7 @@ func decodeNaN32(f func(b []byte) float64, nan ...uint32) func(b []byte) float64
|
|||
return func(b []byte) float64 {
|
||||
u := binary.BigEndian.Uint32(b)
|
||||
if slices.Contains(nan, u) {
|
||||
return 0
|
||||
return math.NaN()
|
||||
}
|
||||
return f(b)
|
||||
}
|
||||
|
|
@ -101,7 +102,7 @@ func decodeNaN64(f func(b []byte) float64, nan ...uint64) func(b []byte) float64
|
|||
return func(b []byte) float64 {
|
||||
u := binary.BigEndian.Uint64(b)
|
||||
if slices.Contains(nan, u) {
|
||||
return 0
|
||||
return math.NaN()
|
||||
}
|
||||
return f(b)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,7 +249,8 @@ func (r Register) Operation() (RegisterOperation, error) {
|
|||
func asFloat64[T constraints.Signed | constraints.Unsigned | constraints.Float](f func([]byte) T) func([]byte) float64 {
|
||||
return func(v []byte) float64 {
|
||||
res := float64(f(v))
|
||||
if math.IsNaN(res) || math.IsInf(res, 0) {
|
||||
// keep NaN so callers can map it to "not available"; sanitize Inf to 0
|
||||
if math.IsInf(res, 0) {
|
||||
res = 0
|
||||
}
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -71,10 +71,13 @@ func TestDecoding(t *testing.T) {
|
|||
out float64
|
||||
}{
|
||||
{Register{Decode: "float32"}, []byte{0x4b, 0x3c, 0x61, 0x4e}, 12345678},
|
||||
{Register{Decode: "float32"}, []byte{0xff, 0xff, 0xff, 0x7f}, 0}, // NaN
|
||||
{Register{Decode: "float32"}, []byte{0xff, 0xff, 0xff, 0x7f}, math.NaN()}, // IEEE NaN preserved
|
||||
{Register{Decode: "float32s"}, []byte{0x61, 0x4e, 0x4b, 0x3c}, 12345678},
|
||||
{Register{Decode: "float32s"}, []byte{0xff, 0x7f, 0xff, 0xff}, 0}, // NaN swapped
|
||||
{Register{Decode: "float32nans"}, []byte{0xff, 0xff, 0xff, 0x7f}, 0}, // NaN
|
||||
{Register{Decode: "float32s"}, []byte{0xff, 0x7f, 0xff, 0xff}, math.NaN()}, // IEEE NaN swapped preserved
|
||||
{Register{Decode: "float32nans"}, []byte{0xff, 0xff, 0xff, 0x7f}, math.NaN()},
|
||||
{Register{Decode: "uint16nan"}, []byte{0xff, 0xff}, math.NaN()},
|
||||
{Register{Decode: "uint32nan"}, []byte{0xff, 0xff, 0xff, 0xff}, math.NaN()},
|
||||
{Register{Decode: "uint64nan"}, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, math.NaN()},
|
||||
{Register{Decode: "uint64"}, []byte{0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01}, 0x0004000300020001},
|
||||
{Register{Decode: "uint64s"}, []byte{0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01}, 0x0001000200030004},
|
||||
}
|
||||
|
|
@ -82,6 +85,12 @@ func TestDecoding(t *testing.T) {
|
|||
for _, tc := range tc {
|
||||
fun, err := tc.r.DecodeFunc()
|
||||
require.NoError(t, err, tc)
|
||||
require.Equal(t, tc.out, fun(tc.in), tc)
|
||||
|
||||
out := fun(tc.in)
|
||||
if math.IsNaN(tc.out) {
|
||||
require.True(t, math.IsNaN(out), tc)
|
||||
continue
|
||||
}
|
||||
require.Equal(t, tc.out, out, tc)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue