Implemented new datasources (modbus,scpi)
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
package modbus
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/uopi/uopi/internal/datasource"
|
||||
)
|
||||
|
||||
func TestDecodeEncodings(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
reg Register
|
||||
words []uint16
|
||||
want any
|
||||
}{
|
||||
{"uint16", Register{Encoding: "uint16"}, []uint16{42}, int64(42)},
|
||||
{"int16 neg", Register{Encoding: "int16"}, []uint16{0xFFFF}, int64(-1)},
|
||||
{"uint32", Register{Encoding: "uint32"}, []uint16{0x0001, 0x0000}, int64(65536)},
|
||||
{"int32 neg", Register{Encoding: "int32"}, []uint16{0xFFFF, 0xFFFF}, int64(-1)},
|
||||
{"scaled", Register{Encoding: "int16", Scale: 0.1}, []uint16{235}, 23.5},
|
||||
{"float32", Register{Encoding: "float32"}, f32Words(3.5), 3.5},
|
||||
{"float64", Register{Encoding: "float64"}, f64Words(2.25), 2.25},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got, err := tc.reg.decode(tc.words)
|
||||
if err != nil {
|
||||
t.Errorf("%s: decode error %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
switch w := tc.want.(type) {
|
||||
case int64:
|
||||
if got != w {
|
||||
t.Errorf("%s: got %v (%T), want %v", tc.name, got, got, w)
|
||||
}
|
||||
case float64:
|
||||
gf, ok := got.(float64)
|
||||
if !ok || math.Abs(gf-w) > 1e-6 {
|
||||
t.Errorf("%s: got %v (%T), want %v", tc.name, got, got, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWordOrder(t *testing.T) {
|
||||
big := Register{Encoding: "uint32", WordOrder: "big"}
|
||||
little := Register{Encoding: "uint32", WordOrder: "little"}
|
||||
words := []uint16{0x0001, 0x0002} // big: 0x00010002, little reverses to 0x00020001
|
||||
gb, _ := big.decode(words)
|
||||
gl, _ := little.decode(words)
|
||||
if gb != int64(0x00010002) {
|
||||
t.Errorf("big = %v, want %d", gb, 0x00010002)
|
||||
}
|
||||
if gl != int64(0x00020001) {
|
||||
t.Errorf("little = %v, want %d", gl, 0x00020001)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeRoundTrip(t *testing.T) {
|
||||
for _, enc := range []string{"uint16", "int16", "uint32", "int32", "float32", "float64"} {
|
||||
reg := Register{Encoding: enc}
|
||||
words, err := reg.encode(123)
|
||||
if err != nil {
|
||||
t.Fatalf("%s encode: %v", enc, err)
|
||||
}
|
||||
got, err := reg.decode(words)
|
||||
if err != nil {
|
||||
t.Fatalf("%s decode: %v", enc, err)
|
||||
}
|
||||
var f float64
|
||||
switch v := got.(type) {
|
||||
case int64:
|
||||
f = float64(v)
|
||||
case float64:
|
||||
f = v
|
||||
}
|
||||
if math.Abs(f-123) > 1e-3 {
|
||||
t.Errorf("%s round-trip = %v, want 123", enc, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataTypeAndWritable(t *testing.T) {
|
||||
if got := (Register{Kind: "coil"}).dataType(); got != datasource.TypeBool {
|
||||
t.Errorf("coil type = %v, want bool", got)
|
||||
}
|
||||
if got := (Register{Encoding: "float32"}).dataType(); got != datasource.TypeFloat64 {
|
||||
t.Errorf("float type = %v, want float64", got)
|
||||
}
|
||||
if got := (Register{Encoding: "uint16", Scale: 0.5}).dataType(); got != datasource.TypeFloat64 {
|
||||
t.Errorf("scaled int type = %v, want float64", got)
|
||||
}
|
||||
if got := (Register{Encoding: "uint16"}).dataType(); got != datasource.TypeInt64 {
|
||||
t.Errorf("plain int type = %v, want int64", got)
|
||||
}
|
||||
if (Register{Kind: "input", Writable: true}).writable() {
|
||||
t.Error("input register must be read-only")
|
||||
}
|
||||
if (Register{Kind: "discrete", Writable: true}).writable() {
|
||||
t.Error("discrete input must be read-only")
|
||||
}
|
||||
if !(Register{Kind: "holding", Writable: true}).writable() {
|
||||
t.Error("writable holding should be writable")
|
||||
}
|
||||
}
|
||||
|
||||
func f32Words(v float32) []uint16 {
|
||||
u := math.Float32bits(v)
|
||||
return []uint16{uint16(u >> 16), uint16(u)}
|
||||
}
|
||||
|
||||
func f64Words(v float64) []uint16 {
|
||||
u := math.Float64bits(v)
|
||||
return []uint16{uint16(u >> 48), uint16(u >> 32), uint16(u >> 16), uint16(u)}
|
||||
}
|
||||
Reference in New Issue
Block a user