|
@ -0,0 +1,179 @@ |
|
|
|
|
|
From 6028f89df95b12219d735b277863f83e9f5ee9e9 Mon Sep 17 00:00:00 2001 |
|
|
|
|
|
From: PJ Bostley <pbostley@gmail.com> |
|
|
|
|
|
Date: Sat, 20 Jan 2018 16:39:36 -0700 |
|
|
|
|
|
Subject: [PATCH 1/2] Adding support for CDAB endian 32-bit modbus polls |
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
src/modbus.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
|
|
|
|
|
1 file changed, 56 insertions(+), 5 deletions(-) |
|
|
|
|
|
|
|
|
|
|
|
diff --git a/src/modbus.c b/src/modbus.c
|
|
|
|
|
|
index 31f0c2da81..daa3c028f5 100644
|
|
|
|
|
|
--- a/src/modbus.c
|
|
|
|
|
|
+++ b/src/modbus.c
|
|
|
|
|
|
@@ -76,9 +76,13 @@
|
|
|
|
|
|
enum mb_register_type_e /* {{{ */ |
|
|
|
|
|
{ REG_TYPE_INT16, |
|
|
|
|
|
REG_TYPE_INT32, |
|
|
|
|
|
+ REG_TYPE_INT32_CDAB,
|
|
|
|
|
|
REG_TYPE_UINT16, |
|
|
|
|
|
REG_TYPE_UINT32, |
|
|
|
|
|
- REG_TYPE_FLOAT }; /* }}} */
|
|
|
|
|
|
+ REG_TYPE_UINT32_CDAB,
|
|
|
|
|
|
+ REG_TYPE_FLOAT,
|
|
|
|
|
|
+ REG_TYPE_FLOAT_CDAB }; /* }}} */
|
|
|
|
|
|
+
|
|
|
|
|
|
enum mb_mreg_type_e /* {{{ */ |
|
|
|
|
|
{ MREG_HOLDING, |
|
|
|
|
|
MREG_INPUT }; /* }}} */ |
|
|
|
|
|
@@ -425,7 +429,9 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
|
|
|
|
|
|
if ((ds->ds[0].type != DS_TYPE_GAUGE) && |
|
|
|
|
|
(data->register_type != REG_TYPE_INT32) && |
|
|
|
|
|
- (data->register_type != REG_TYPE_UINT32)) {
|
|
|
|
|
|
+ (data->register_type != REG_TYPE_INT32_CDAB) &&
|
|
|
|
|
|
+ (data->register_type != REG_TYPE_UINT32) &&
|
|
|
|
|
|
+ (data->register_type != REG_TYPE_UINT32_CDAB)) {
|
|
|
|
|
|
NOTICE( |
|
|
|
|
|
"Modbus plugin: The data source of type \"%s\" is %s, not gauge. " |
|
|
|
|
|
"This will most likely result in problems, because the register type " |
|
|
|
|
|
@@ -434,8 +440,11 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((data->register_type == REG_TYPE_INT32) || |
|
|
|
|
|
+ (data->register_type == REG_TYPE_INT32_CDAB) ||
|
|
|
|
|
|
(data->register_type == REG_TYPE_UINT32) || |
|
|
|
|
|
- (data->register_type == REG_TYPE_FLOAT))
|
|
|
|
|
|
+ (data->register_type == REG_TYPE_UINT32_CDAB) ||
|
|
|
|
|
|
+ (data->register_type == REG_TYPE_FLOAT) ||
|
|
|
|
|
|
+ (data->register_type == REG_TYPE_FLOAT_CDAB))
|
|
|
|
|
|
values_num = 2; |
|
|
|
|
|
else |
|
|
|
|
|
values_num = 1; |
|
|
|
|
|
@@ -496,8 +505,8 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
} |
|
|
|
|
|
if (status != values_num) { |
|
|
|
|
|
ERROR("Modbus plugin: modbus read function (%s/%s) failed. " |
|
|
|
|
|
- " status = %i, values_num = %i. Giving up.",
|
|
|
|
|
|
- host->host, host->node, status, values_num);
|
|
|
|
|
|
+ " status = %i, start_addr = %i, values_num = %i. Giving up.",
|
|
|
|
|
|
+ host->host, host->node, status, data->register_base, values_num);
|
|
|
|
|
|
#if LEGACY_LIBMODBUS |
|
|
|
|
|
modbus_close(&host->connection); |
|
|
|
|
|
#else |
|
|
|
|
|
@@ -521,6 +530,17 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
"Returned float value is %g", |
|
|
|
|
|
(double)float_value); |
|
|
|
|
|
|
|
|
|
|
|
+ CAST_TO_VALUE_T(ds, vt, float_value);
|
|
|
|
|
|
+ mb_submit(host, slave, data, vt);
|
|
|
|
|
|
+ } else if (data->register_type == REG_TYPE_FLOAT_CDAB) {
|
|
|
|
|
|
+ float float_value;
|
|
|
|
|
|
+ value_t vt;
|
|
|
|
|
|
+
|
|
|
|
|
|
+ float_value = mb_register_to_float(values[1], values[0]);
|
|
|
|
|
|
+ DEBUG("Modbus plugin: mb_read_data: "
|
|
|
|
|
|
+ "Returned float value is %g",
|
|
|
|
|
|
+ (double)float_value);
|
|
|
|
|
|
+
|
|
|
|
|
|
CAST_TO_VALUE_T(ds, vt, float_value); |
|
|
|
|
|
mb_submit(host, slave, data, vt); |
|
|
|
|
|
} else if (data->register_type == REG_TYPE_INT32) { |
|
|
|
|
|
@@ -535,6 +555,20 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
"Returned int32 value is %" PRIi32, |
|
|
|
|
|
v.i32); |
|
|
|
|
|
|
|
|
|
|
|
+ CAST_TO_VALUE_T(ds, vt, v.i32);
|
|
|
|
|
|
+ mb_submit(host, slave, data, vt);
|
|
|
|
|
|
+ } else if (data->register_type == REG_TYPE_INT32_CDAB) {
|
|
|
|
|
|
+ union {
|
|
|
|
|
|
+ uint32_t u32;
|
|
|
|
|
|
+ int32_t i32;
|
|
|
|
|
|
+ } v;
|
|
|
|
|
|
+ value_t vt;
|
|
|
|
|
|
+
|
|
|
|
|
|
+ v.u32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
|
|
|
|
|
|
+ DEBUG("Modbus plugin: mb_read_data: "
|
|
|
|
|
|
+ "Returned int32 value is %" PRIi32,
|
|
|
|
|
|
+ v.i32);
|
|
|
|
|
|
+
|
|
|
|
|
|
CAST_TO_VALUE_T(ds, vt, v.i32); |
|
|
|
|
|
mb_submit(host, slave, data, vt); |
|
|
|
|
|
} else if (data->register_type == REG_TYPE_INT16) { |
|
|
|
|
|
@@ -561,6 +595,17 @@ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
|
|
|
|
|
|
"Returned uint32 value is %" PRIu32, |
|
|
|
|
|
v32); |
|
|
|
|
|
|
|
|
|
|
|
+ CAST_TO_VALUE_T(ds, vt, v32);
|
|
|
|
|
|
+ mb_submit(host, slave, data, vt);
|
|
|
|
|
|
+ } else if (data->register_type == REG_TYPE_UINT32_CDAB) {
|
|
|
|
|
|
+ uint32_t v32;
|
|
|
|
|
|
+ value_t vt;
|
|
|
|
|
|
+
|
|
|
|
|
|
+ v32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
|
|
|
|
|
|
+ DEBUG("Modbus plugin: mb_read_data: "
|
|
|
|
|
|
+ "Returned uint32 value is %" PRIu32,
|
|
|
|
|
|
+ v32);
|
|
|
|
|
|
+
|
|
|
|
|
|
CAST_TO_VALUE_T(ds, vt, v32); |
|
|
|
|
|
mb_submit(host, slave, data, vt); |
|
|
|
|
|
} else /* if (data->register_type == REG_TYPE_UINT16) */ |
|
|
|
|
|
@@ -702,12 +747,18 @@ static int mb_config_add_data(oconfig_item_t *ci) /* {{{ */
|
|
|
|
|
|
data.register_type = REG_TYPE_INT16; |
|
|
|
|
|
else if (strcasecmp("Int32", tmp) == 0) |
|
|
|
|
|
data.register_type = REG_TYPE_INT32; |
|
|
|
|
|
+ else if (strcasecmp("Int32LE", tmp) == 0)
|
|
|
|
|
|
+ data.register_type = REG_TYPE_INT32_CDAB;
|
|
|
|
|
|
else if (strcasecmp("Uint16", tmp) == 0) |
|
|
|
|
|
data.register_type = REG_TYPE_UINT16; |
|
|
|
|
|
else if (strcasecmp("Uint32", tmp) == 0) |
|
|
|
|
|
data.register_type = REG_TYPE_UINT32; |
|
|
|
|
|
+ else if (strcasecmp("Uint32LE", tmp) == 0)
|
|
|
|
|
|
+ data.register_type = REG_TYPE_UINT32_CDAB;
|
|
|
|
|
|
else if (strcasecmp("Float", tmp) == 0) |
|
|
|
|
|
data.register_type = REG_TYPE_FLOAT; |
|
|
|
|
|
+ else if (strcasecmp("FloatLE", tmp) == 0)
|
|
|
|
|
|
+ data.register_type = REG_TYPE_FLOAT_CDAB;
|
|
|
|
|
|
else { |
|
|
|
|
|
ERROR("Modbus plugin: The register type \"%s\" is unknown.", tmp); |
|
|
|
|
|
status = -1; |
|
|
|
|
|
|
|
|
|
|
|
From 67afd2685892e69ababb489f48b9033ab5908f4d Mon Sep 17 00:00:00 2001 |
|
|
|
|
|
From: PJ Bostley <pbostley@gmail.com> |
|
|
|
|
|
Date: Tue, 23 Jan 2018 15:33:23 -0700 |
|
|
|
|
|
Subject: [PATCH 2/2] Adding documentation for the Modbus little endian modes |
|
|
|
|
|
where 32 bit values have thier registers swapped |
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
src/collectd.conf.pod | 18 +++++++++++++----- |
|
|
|
|
|
1 file changed, 13 insertions(+), 5 deletions(-) |
|
|
|
|
|
|
|
|
|
|
|
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
|
|
|
|
|
|
index dfd785a2c8..e9715126e6 100644
|
|
|
|
|
|
--- a/src/collectd.conf.pod
|
|
|
|
|
|
+++ b/src/collectd.conf.pod
|
|
|
|
|
|
@@ -4128,11 +4128,19 @@ Configures the base register to read from the device. If the option
|
|
|
|
|
|
B<RegisterType> has been set to B<Uint32> or B<Float>, this and the next |
|
|
|
|
|
register will be read (the register number is increased by one). |
|
|
|
|
|
|
|
|
|
|
|
-=item B<RegisterType> B<Int16>|B<Int32>|B<Uint16>|B<Uint32>|B<Float>
|
|
|
|
|
|
-
|
|
|
|
|
|
-Specifies what kind of data is returned by the device. If the type is B<Int32>,
|
|
|
|
|
|
-B<Uint32> or B<Float>, two 16E<nbsp>bit registers will be read and the data is
|
|
|
|
|
|
-combined into one value. Defaults to B<Uint16>.
|
|
|
|
|
|
+=item B<RegisterType> B<Int16>|B<Int32>|B<Uint16>|B<Uint32>|B<Float>|B<Int32LE>|B<Uint32LE>|B<FloatLE>
|
|
|
|
|
|
+
|
|
|
|
|
|
+Specifies what kind of data is returned by the device. This defaults to
|
|
|
|
|
|
+B<Uint16>. If the type is B<Int32>, B<Int32LE>, B<Uint32>, B<Uint32LE>,
|
|
|
|
|
|
+B<Float> or B<FloatLE>, two 16E<nbsp>bit registers at B<RegisterBase>
|
|
|
|
|
|
+and B<RegisterBase+1> will be read and the data is combined into one
|
|
|
|
|
|
+32E<nbsp>value. For B<Int32>, B<Uint32> and B<Float> the most significant
|
|
|
|
|
|
+16E<nbsp>bits are in the register at B<RegisterBase> and the least
|
|
|
|
|
|
+significant 16E<nbsp>bits are in the register at B<RegisterBase+1>.
|
|
|
|
|
|
+For B<Int32LE>, B<Uint32LE>, or B<Float32LE>, the high and low order
|
|
|
|
|
|
+registers are swapped with the most significant 16E<nbsp>bits in
|
|
|
|
|
|
+the B<RegisterBase+1> and the least significant 16E<nbsp>bits in
|
|
|
|
|
|
+B<RegisterBase>.
|
|
|
|
|
|
|
|
|
|
|
|
=item B<RegisterCmd> B<ReadHolding>|B<ReadInput> |
|
|
|
|
|
|