Add support for 64-bit integer types to modbus input (#7225)
This commit is contained in:
parent
cb42f610f4
commit
f882b8f94f
|
@ -58,7 +58,7 @@ The Modbus plugin collects Discrete Inputs, Coils, Input Registers and Holding R
|
|||
## |---BA, DCBA - Little Endian
|
||||
## |---BADC - Mid-Big Endian
|
||||
## |---CDAB - Mid-Little Endian
|
||||
## data_type - UINT16, INT16, INT32, UINT32, FLOAT32, FLOAT32-IEEE (the IEEE 754 binary representation)
|
||||
## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32, FLOAT32-IEEE (the IEEE 754 binary representation)
|
||||
## scale - the final numeric variable representation
|
||||
## address - variable address
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ const sampleConfig = `
|
|||
## |---BA, DCBA - Little Endian
|
||||
## |---BADC - Mid-Big Endian
|
||||
## |---CDAB - Mid-Little Endian
|
||||
## data_type - UINT16, INT16, INT32, UINT32, FLOAT32, FLOAT32-IEEE (the IEEE 754 binary representation)
|
||||
## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32, FLOAT32-IEEE (the IEEE 754 binary representation)
|
||||
## scale - the final numeric variable representation
|
||||
## address - variable address
|
||||
|
||||
|
@ -328,7 +328,7 @@ func validateFieldContainers(t []fieldContainer, n string) error {
|
|||
if n == cInputRegisters || n == cHoldingRegisters {
|
||||
// search byte order
|
||||
switch item.ByteOrder {
|
||||
case "AB", "BA", "ABCD", "CDAB", "BADC", "DCBA":
|
||||
case "AB", "BA", "ABCD", "CDAB", "BADC", "DCBA", "ABCDEFGH", "HGFEDCBA", "BADCFEHG", "GHEFCDAB":
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("invalid byte order '%s' in '%s' - '%s'", item.ByteOrder, n, item.Name)
|
||||
|
@ -336,7 +336,7 @@ func validateFieldContainers(t []fieldContainer, n string) error {
|
|||
|
||||
// search data type
|
||||
switch item.DataType {
|
||||
case "UINT16", "INT16", "UINT32", "INT32", "FLOAT32-IEEE", "FLOAT32":
|
||||
case "UINT16", "INT16", "UINT32", "INT32", "UINT64", "INT64", "FLOAT32-IEEE", "FLOAT32":
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("invalid data type '%s' in '%s' - '%s'", item.DataType, n, item.Name)
|
||||
|
@ -349,10 +349,12 @@ func validateFieldContainers(t []fieldContainer, n string) error {
|
|||
}
|
||||
|
||||
// check address
|
||||
if len(item.Address) == 0 || len(item.Address) > 2 {
|
||||
if len(item.Address) != 1 && len(item.Address) != 2 && len(item.Address) != 4 {
|
||||
return fmt.Errorf("invalid address '%v' length '%v' in '%s' - '%s'", item.Address, len(item.Address), n, item.Name)
|
||||
} else if n == cInputRegisters || n == cHoldingRegisters {
|
||||
if (len(item.Address) == 1 && len(item.ByteOrder) != 2) || (len(item.Address) == 2 && len(item.ByteOrder) != 4) {
|
||||
}
|
||||
|
||||
if n == cInputRegisters || n == cHoldingRegisters {
|
||||
if 2*len(item.Address) != len(item.ByteOrder) {
|
||||
return fmt.Errorf("invalid byte order '%s' and address '%v' in '%s' - '%s'", item.ByteOrder, item.Address, n, item.Name)
|
||||
}
|
||||
|
||||
|
@ -360,8 +362,7 @@ func validateFieldContainers(t []fieldContainer, n string) error {
|
|||
if len(item.Address) > len(removeDuplicates(item.Address)) {
|
||||
return fmt.Errorf("duplicate address '%v' in '%s' - '%s'", item.Address, n, item.Name)
|
||||
}
|
||||
|
||||
} else if len(item.Address) > 1 || (n == cInputRegisters || n == cHoldingRegisters) {
|
||||
} else if len(item.Address) != 1 {
|
||||
return fmt.Errorf("invalid address'%v' length'%v' in '%s' - '%s'", item.Address, len(item.Address), n, item.Name)
|
||||
}
|
||||
}
|
||||
|
@ -480,6 +481,14 @@ func convertDataType(t fieldContainer, bytes []byte) interface{} {
|
|||
e32 := convertEndianness32(t.ByteOrder, bytes)
|
||||
f32 := int32(e32)
|
||||
return scaleInt32(t.Scale, f32)
|
||||
case "UINT64":
|
||||
e64 := convertEndianness64(t.ByteOrder, bytes)
|
||||
f64 := format64(t.DataType, e64).(uint64)
|
||||
return scaleUint64(t.Scale, f64)
|
||||
case "INT64":
|
||||
e64 := convertEndianness64(t.ByteOrder, bytes)
|
||||
f64 := format64(t.DataType, e64).(int64)
|
||||
return scaleInt64(t.Scale, f64)
|
||||
case "FLOAT32-IEEE":
|
||||
e32 := convertEndianness32(t.ByteOrder, bytes)
|
||||
f32 := math.Float32frombits(e32)
|
||||
|
@ -488,9 +497,12 @@ func convertDataType(t fieldContainer, bytes []byte) interface{} {
|
|||
if len(bytes) == 2 {
|
||||
e16 := convertEndianness16(t.ByteOrder, bytes)
|
||||
return scale16toFloat32(t.Scale, e16)
|
||||
} else {
|
||||
} else if len(bytes) == 4 {
|
||||
e32 := convertEndianness32(t.ByteOrder, bytes)
|
||||
return scale32toFloat32(t.Scale, e32)
|
||||
} else {
|
||||
e64 := convertEndianness64(t.ByteOrder, bytes)
|
||||
return scale64toFloat32(t.Scale, e64)
|
||||
}
|
||||
default:
|
||||
return 0
|
||||
|
@ -523,6 +535,21 @@ func convertEndianness32(o string, b []byte) uint32 {
|
|||
}
|
||||
}
|
||||
|
||||
func convertEndianness64(o string, b []byte) uint64 {
|
||||
switch o {
|
||||
case "ABCDEFGH":
|
||||
return binary.BigEndian.Uint64(b)
|
||||
case "HGFEDCBA":
|
||||
return binary.LittleEndian.Uint64(b)
|
||||
case "BADCFEHG":
|
||||
return uint64(binary.LittleEndian.Uint16(b[0:]))<<48 | uint64(binary.LittleEndian.Uint16(b[2:]))<<32 | uint64(binary.LittleEndian.Uint16(b[4:]))<<16 | uint64(binary.LittleEndian.Uint16(b[6:]))
|
||||
case "GHEFCDAB":
|
||||
return uint64(binary.BigEndian.Uint16(b[6:]))<<48 | uint64(binary.BigEndian.Uint16(b[4:]))<<32 | uint64(binary.BigEndian.Uint16(b[2:]))<<16 | uint64(binary.BigEndian.Uint16(b[0:]))
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func format16(f string, r uint16) interface{} {
|
||||
switch f {
|
||||
case "UINT16":
|
||||
|
@ -547,6 +574,17 @@ func format32(f string, r uint32) interface{} {
|
|||
}
|
||||
}
|
||||
|
||||
func format64(f string, r uint64) interface{} {
|
||||
switch f {
|
||||
case "UINT64":
|
||||
return r
|
||||
case "INT64":
|
||||
return int64(r)
|
||||
default:
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
func scale16toFloat32(s float64, v uint16) float64 {
|
||||
return float64(v) * s
|
||||
}
|
||||
|
@ -555,6 +593,10 @@ func scale32toFloat32(s float64, v uint32) float64 {
|
|||
return float64(float64(v) * float64(s))
|
||||
}
|
||||
|
||||
func scale64toFloat32(s float64, v uint64) float64 {
|
||||
return float64(float64(v) * float64(s))
|
||||
}
|
||||
|
||||
func scaleInt16(s float64, v int16) int16 {
|
||||
return int16(float64(v) * s)
|
||||
}
|
||||
|
@ -575,6 +617,14 @@ func scaleFloat32(s float64, v float32) float32 {
|
|||
return float32(float64(v) * s)
|
||||
}
|
||||
|
||||
func scaleUint64(s float64, v uint64) uint64 {
|
||||
return uint64(float64(v) * float64(s))
|
||||
}
|
||||
|
||||
func scaleInt64(s float64, v int64) int64 {
|
||||
return int64(float64(v) * float64(s))
|
||||
}
|
||||
|
||||
// Gather implements the telegraf plugin interface method for data accumulation
|
||||
func (m *Modbus) Gather(acc telegraf.Accumulator) error {
|
||||
if !m.isConnected {
|
||||
|
|
|
@ -349,6 +349,106 @@ func TestHoldingRegisters(t *testing.T) {
|
|||
write: []byte{0xAA, 0xBB, 0xCC, 0xDD},
|
||||
read: float32(-3.3360025e-12),
|
||||
},
|
||||
{
|
||||
name: "register140_to_register143_abcdefgh_int64_scaled",
|
||||
address: []uint16{140, 141, 142, 143},
|
||||
quantity: 4,
|
||||
byteOrder: "ABCDEFGH",
|
||||
dataType: "INT64",
|
||||
scale: 10,
|
||||
write: []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},
|
||||
read: int64(10995116717570),
|
||||
},
|
||||
{
|
||||
name: "register140_to_register143_abcdefgh_int64",
|
||||
address: []uint16{140, 141, 142, 143},
|
||||
quantity: 4,
|
||||
byteOrder: "ABCDEFGH",
|
||||
dataType: "INT64",
|
||||
scale: 1,
|
||||
write: []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},
|
||||
read: int64(1099511671757),
|
||||
},
|
||||
{
|
||||
name: "register150_to_register153_hgfedcba_int64",
|
||||
address: []uint16{150, 151, 152, 153},
|
||||
quantity: 4,
|
||||
byteOrder: "HGFEDCBA",
|
||||
dataType: "INT64",
|
||||
scale: 1,
|
||||
write: []byte{0x84, 0xF6, 0x45, 0xF9, 0xBC, 0xFE, 0xFF, 0xFF},
|
||||
read: int64(-1387387292028),
|
||||
},
|
||||
{
|
||||
name: "register160_to_register163_badcfehg_int64",
|
||||
address: []uint16{160, 161, 162, 163},
|
||||
quantity: 4,
|
||||
byteOrder: "BADCFEHG",
|
||||
dataType: "INT64",
|
||||
scale: 1,
|
||||
write: []byte{0xFF, 0xFF, 0xBC, 0xFE, 0x45, 0xF9, 0x84, 0xF6},
|
||||
read: int64(-1387387292028),
|
||||
},
|
||||
{
|
||||
name: "register170_to_register173_ghefcdab_int64",
|
||||
address: []uint16{170, 171, 172, 173},
|
||||
quantity: 4,
|
||||
byteOrder: "GHEFCDAB",
|
||||
dataType: "INT64",
|
||||
scale: 1,
|
||||
write: []byte{0xF6, 0x84, 0xF9, 0x45, 0xFE, 0xBC, 0xFF, 0xFF},
|
||||
read: int64(-1387387292028),
|
||||
},
|
||||
{
|
||||
name: "register180_to_register183_abcdefgh_uint64_scaled",
|
||||
address: []uint16{180, 181, 182, 183},
|
||||
quantity: 4,
|
||||
byteOrder: "ABCDEFGH",
|
||||
dataType: "UINT64",
|
||||
scale: 10,
|
||||
write: []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},
|
||||
read: uint64(10995116717570),
|
||||
},
|
||||
{
|
||||
name: "register180_to_register183_abcdefgh_uint64",
|
||||
address: []uint16{180, 181, 182, 183},
|
||||
quantity: 4,
|
||||
byteOrder: "ABCDEFGH",
|
||||
dataType: "UINT64",
|
||||
scale: 1,
|
||||
write: []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},
|
||||
read: uint64(1099511671757),
|
||||
},
|
||||
{
|
||||
name: "register190_to_register193_hgfedcba_uint64",
|
||||
address: []uint16{190, 191, 192, 193},
|
||||
quantity: 4,
|
||||
byteOrder: "HGFEDCBA",
|
||||
dataType: "UINT64",
|
||||
scale: 1,
|
||||
write: []byte{0x84, 0xF6, 0x45, 0xF9, 0xBC, 0xFE, 0xFF, 0xFF},
|
||||
read: uint64(18446742686322259968),
|
||||
},
|
||||
{
|
||||
name: "register200_to_register203_badcfehg_uint64",
|
||||
address: []uint16{200, 201, 202, 203},
|
||||
quantity: 4,
|
||||
byteOrder: "BADCFEHG",
|
||||
dataType: "UINT64",
|
||||
scale: 1,
|
||||
write: []byte{0xFF, 0xFF, 0xBC, 0xFE, 0x45, 0xF9, 0x84, 0xF6},
|
||||
read: uint64(18446742686322259968),
|
||||
},
|
||||
{
|
||||
name: "register210_to_register213_ghefcdab_uint64",
|
||||
address: []uint16{210, 211, 212, 213},
|
||||
quantity: 4,
|
||||
byteOrder: "GHEFCDAB",
|
||||
dataType: "UINT64",
|
||||
scale: 1,
|
||||
write: []byte{0xF6, 0x84, 0xF9, 0x45, 0xFE, 0xBC, 0xFF, 0xFF},
|
||||
read: uint64(18446742686322259968),
|
||||
},
|
||||
}
|
||||
|
||||
serv := mbserver.NewServer()
|
||||
|
|
Loading…
Reference in New Issue