feat(inputs.modbus): Add 8-bit integer types (#12255)
This commit is contained in:
parent
d3eec6166a
commit
75aaa8981e
|
|
@ -91,7 +91,8 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
|||
## |---BA, DCBA - Little Endian
|
||||
## |---BADC - Mid-Big Endian
|
||||
## |---CDAB - Mid-Little Endian
|
||||
## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64,
|
||||
## data_type - INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)
|
||||
## INT16, UINT16, INT32, UINT32, INT64, UINT64,
|
||||
## FLOAT32-IEEE, FLOAT64-IEEE (the IEEE 754 binary representation)
|
||||
## FLOAT32, FIXED, UFIXED (fixed-point representation on input)
|
||||
## scale - the final numeric variable representation
|
||||
|
|
@ -155,7 +156,9 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
|||
## Analog Variables, Input Registers and Holding Registers
|
||||
## address - address of the register to query. For coil and discrete inputs this is the bit address.
|
||||
## name *1 - field name
|
||||
## type *1,2 - type of the modbus field, can be INT16, UINT16, INT32, UINT32, INT64, UINT64 and
|
||||
## type *1,2 - type of the modbus field, can be
|
||||
## INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)
|
||||
## INT16, UINT16, INT32, UINT32, INT64, UINT64 and
|
||||
## FLOAT32, FLOAT64 (IEEE 754 binary representation)
|
||||
## scale *1,2 - (optional) factor to scale the variable with
|
||||
## output *1,2 - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64. Defaults to FLOAT64 if
|
||||
|
|
@ -280,6 +283,12 @@ floating-point-number. The size of the output type is assumed to be large enough
|
|||
for all supported input types. The mapping from the input type to the output
|
||||
type is fixed and cannot be configured.
|
||||
|
||||
##### Integers: `INT8L`, `INT8H`, `UINT8L`, `UINT8H`
|
||||
|
||||
These types are used for 8-bit integer values. Select the one that matches your
|
||||
modbus data source. The `L` and `H` suffix denotes the low- and high byte of
|
||||
the register respectively.
|
||||
|
||||
##### Integers: `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64`, `UINT64`
|
||||
|
||||
These types are used for integer input values. Select the one that matches your
|
||||
|
|
@ -412,15 +421,18 @@ metric identified by `measurement`, `slave_id` and `register`.
|
|||
|
||||
##### register datatype
|
||||
|
||||
The `register` setting specifies the datatype of the modbus register and can be
|
||||
set to `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64` or `UINT64` for integer
|
||||
types or `FLOAT32` and `FLOAT64` for IEEE 754 binary representations of floating
|
||||
point values. Usually the datatype of the register is listed in the datasheet of
|
||||
your modbus device in relation to the `address` described above.
|
||||
The `type` setting specifies the datatype of the modbus register and can be
|
||||
set to `INT8L`, `INT8H`, `UINT8L`, `UINT8H` where `L` is the lower byte of the
|
||||
register and `H` is the higher byte.
|
||||
Furthermore, the types `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64` or `UINT64`
|
||||
for integer types or `FLOAT32` and `FLOAT64` for IEEE 754 binary representations
|
||||
of floating point values exist. Usually the datatype of the register is listed
|
||||
in the datasheet of your modbus device in relation to the `address` described
|
||||
above.
|
||||
|
||||
This setting is ignored if the field's `omit` is set to `true` or if the
|
||||
`register` type is a bit-type (`coil` or `discrete`) and can be omitted in
|
||||
these cases.
|
||||
This setting is ignored if the field's `omit` is set to `true` or if the
|
||||
`register` type is a bit-type (`coil` or `discrete`) and can be omitted in
|
||||
these cases.
|
||||
|
||||
##### scaling
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ func removeDuplicates(elements []uint16) []uint16 {
|
|||
|
||||
func normalizeInputDatatype(dataType string) (string, error) {
|
||||
switch dataType {
|
||||
case "INT16", "UINT16", "INT32", "UINT32", "INT64", "UINT64", "FLOAT32", "FLOAT64":
|
||||
case "INT8L", "INT8H", "UINT8L", "UINT8H",
|
||||
"INT16", "UINT16", "INT32", "UINT32", "INT64", "UINT64",
|
||||
"FLOAT32", "FLOAT64":
|
||||
return dataType, nil
|
||||
}
|
||||
return "unknown", fmt.Errorf("unknown input type %q", dataType)
|
||||
|
|
|
|||
|
|
@ -177,7 +177,9 @@ func (c *ConfigurationOriginal) validateFieldDefinitions(fieldDefs []fieldDefini
|
|||
|
||||
// search data type
|
||||
switch item.DataType {
|
||||
case "UINT16", "INT16", "UINT32", "INT32", "UINT64", "INT64", "FLOAT32-IEEE", "FLOAT64-IEEE", "FLOAT32", "FIXED", "UFIXED":
|
||||
case "INT8L", "INT8H", "UINT8L", "UINT8H",
|
||||
"UINT16", "INT16", "UINT32", "INT32", "UINT64", "INT64",
|
||||
"FLOAT32-IEEE", "FLOAT64-IEEE", "FLOAT32", "FIXED", "UFIXED":
|
||||
default:
|
||||
return fmt.Errorf("invalid data type '%s' in '%s' - '%s'", item.DataType, registerType, item.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,9 +333,9 @@ func (c *ConfigurationPerRequest) fieldID(seed maphash.Seed, def requestDefiniti
|
|||
func (c *ConfigurationPerRequest) determineOutputDatatype(input string) (string, error) {
|
||||
// Handle our special types
|
||||
switch input {
|
||||
case "INT16", "INT32", "INT64":
|
||||
case "INT8L", "INT8H", "INT16", "INT32", "INT64":
|
||||
return "INT64", nil
|
||||
case "UINT16", "UINT32", "UINT64":
|
||||
case "UINT8L", "UINT8H", "UINT16", "UINT32", "UINT64":
|
||||
return "UINT64", nil
|
||||
case "FLOAT32", "FLOAT64":
|
||||
return "FLOAT64", nil
|
||||
|
|
@ -346,6 +346,8 @@ func (c *ConfigurationPerRequest) determineOutputDatatype(input string) (string,
|
|||
func (c *ConfigurationPerRequest) determineFieldLength(input string) (uint16, error) {
|
||||
// Handle our special types
|
||||
switch input {
|
||||
case "INT8L", "INT8H", "UINT8L", "UINT8H":
|
||||
return 1, nil
|
||||
case "INT16", "UINT16":
|
||||
return 1, nil
|
||||
case "INT32", "UINT32", "FLOAT32":
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,7 +28,8 @@
|
|||
## |---BA, DCBA - Little Endian
|
||||
## |---BADC - Mid-Big Endian
|
||||
## |---CDAB - Mid-Little Endian
|
||||
## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64,
|
||||
## data_type - INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)
|
||||
## INT16, UINT16, INT32, UINT32, INT64, UINT64,
|
||||
## FLOAT32-IEEE, FLOAT64-IEEE (the IEEE 754 binary representation)
|
||||
## FLOAT32, FIXED, UFIXED (fixed-point representation on input)
|
||||
## scale - the final numeric variable representation
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@
|
|||
## Analog Variables, Input Registers and Holding Registers
|
||||
## address - address of the register to query. For coil and discrete inputs this is the bit address.
|
||||
## name *1 - field name
|
||||
## type *1,2 - type of the modbus field, can be INT16, UINT16, INT32, UINT32, INT64, UINT64 and
|
||||
## type *1,2 - type of the modbus field, can be
|
||||
## INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)
|
||||
## INT16, UINT16, INT32, UINT32, INT64, UINT64 and
|
||||
## FLOAT32, FLOAT64 (IEEE 754 binary representation)
|
||||
## scale *1,2 - (optional) factor to scale the variable with
|
||||
## output *1,2 - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64. Defaults to FLOAT64 if
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ func determineConverter(inType, byteOrder, outType string, scale float64) (field
|
|||
|
||||
func determineConverterScale(inType, byteOrder, outType string, scale float64) (fieldConverterFunc, error) {
|
||||
switch inType {
|
||||
case "INT8L":
|
||||
return determineConverterI8LScale(outType, byteOrder, scale)
|
||||
case "INT8H":
|
||||
return determineConverterI8HScale(outType, byteOrder, scale)
|
||||
case "UINT8L":
|
||||
return determineConverterU8LScale(outType, byteOrder, scale)
|
||||
case "UINT8H":
|
||||
return determineConverterU8HScale(outType, byteOrder, scale)
|
||||
case "INT16":
|
||||
return determineConverterI16Scale(outType, byteOrder, scale)
|
||||
case "UINT16":
|
||||
|
|
@ -33,6 +41,14 @@ func determineConverterScale(inType, byteOrder, outType string, scale float64) (
|
|||
|
||||
func determineConverterNoScale(inType, byteOrder, outType string) (fieldConverterFunc, error) {
|
||||
switch inType {
|
||||
case "INT8L":
|
||||
return determineConverterI8L(outType, byteOrder)
|
||||
case "INT8H":
|
||||
return determineConverterI8H(outType, byteOrder)
|
||||
case "UINT8L":
|
||||
return determineConverterU8L(outType, byteOrder)
|
||||
case "UINT8H":
|
||||
return determineConverterU8H(outType, byteOrder)
|
||||
case "INT16":
|
||||
return determineConverterI16(outType, byteOrder)
|
||||
case "UINT16":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
package modbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func endianessIndex8(byteOrder string, low bool) (int, error) {
|
||||
switch byteOrder {
|
||||
case "ABCD": // Big endian (Motorola)
|
||||
if low {
|
||||
return 1, nil
|
||||
}
|
||||
return 0, nil
|
||||
case "DCBA": // Little endian (Intel)
|
||||
if low {
|
||||
return 0, nil
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
return -1, fmt.Errorf("invalid byte-order: %s", byteOrder)
|
||||
}
|
||||
|
||||
// I8 lower byte - no scale
|
||||
func determineConverterI8L(outType, byteOrder string) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return int8(b[idx])
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(int8(b[idx]))
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(int8(b[idx]))
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(int8(b[idx]))
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// I8 higher byte - no scale
|
||||
func determineConverterI8H(outType, byteOrder string) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return int8(b[idx])
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(int8(b[idx]))
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(int8(b[idx]))
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(int8(b[idx]))
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// U8 lower byte - no scale
|
||||
func determineConverterU8L(outType, byteOrder string) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return b[idx]
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(b[idx])
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(b[idx])
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(b[idx])
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// U8 higher byte - no scale
|
||||
func determineConverterU8H(outType, byteOrder string) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return b[idx]
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(b[idx])
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(b[idx])
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(b[idx])
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// I8 lower byte - scale
|
||||
func determineConverterI8LScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return int8(float64(in) * scale)
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return int64(float64(in) * scale)
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return uint64(float64(in) * scale)
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return float64(in) * scale
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// I8 higher byte - scale
|
||||
func determineConverterI8HScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return int8(float64(in) * scale)
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return int64(float64(in) * scale)
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return uint64(float64(in) * scale)
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
in := int8(b[idx])
|
||||
return float64(in) * scale
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// U8 lower byte - scale
|
||||
func determineConverterU8LScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return uint8(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(b[idx]) * scale
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
|
||||
// U8 higher byte - scale
|
||||
func determineConverterU8HScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {
|
||||
idx, err := endianessIndex8(byteOrder, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch outType {
|
||||
case "native":
|
||||
return func(b []byte) interface{} {
|
||||
return uint8(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "INT64":
|
||||
return func(b []byte) interface{} {
|
||||
return int64(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "UINT64":
|
||||
return func(b []byte) interface{} {
|
||||
return uint64(float64(b[idx]) * scale)
|
||||
}, nil
|
||||
case "FLOAT64":
|
||||
return func(b []byte) interface{} {
|
||||
return float64(b[idx]) * scale
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid output data-type: %s", outType)
|
||||
}
|
||||
Loading…
Reference in New Issue