collectd: backport modbus improvements 8664/head
authorDaniel Golle <daniel@makrotopia.org>
Fri, 12 Apr 2019 10:13:36 +0000 (12:13 +0200)
committerDaniel Golle <daniel@makrotopia.org>
Sun, 14 Apr 2019 01:18:24 +0000 (03:18 +0200)
 * 938897a2 Add scale and shift to modbus plugin
 * 60280b80 correcting all the wrongs
 * a00ab529 Add support for RS485 to modbus plugin

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
utils/collectd/Makefile
utils/collectd/patches/051-Add-scale-and-shift-to-modbus-plugin.patch [new file with mode: 0644]
utils/collectd/patches/052-correcting-all-the-wrongs.patch [new file with mode: 0644]
utils/collectd/patches/053-Add-support-for-RS485-to-modbus-plugin.patch [new file with mode: 0644]

index 71dee42850976c06ab30d5287d8c189c1b34fc93..fea646dd9c26aa34f43af3ca0b0a4a157c5f481b 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=collectd
 PKG_VERSION:=5.8.1
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://collectd.org/files/ \
diff --git a/utils/collectd/patches/051-Add-scale-and-shift-to-modbus-plugin.patch b/utils/collectd/patches/051-Add-scale-and-shift-to-modbus-plugin.patch
new file mode 100644 (file)
index 0000000..f95df9d
--- /dev/null
@@ -0,0 +1,81 @@
+From eeabc41e703f39cae0ad7eb8a596045a5a2f25b4 Mon Sep 17 00:00:00 2001
+From: cekstam <christian.ekstam@gmail.com>
+Date: Tue, 27 Mar 2018 13:15:28 +0200
+Subject: [PATCH 1/3] Add scale and shift to modbus plugin
+
+Adding a Scale and Shift parameter to the modbus plugin in order to correct amplifed data
+---
+ src/collectd.conf.pod | 10 ++++++++++
+ src/modbus.c          | 18 ++++++++++++++----
+ 2 files changed, 24 insertions(+), 4 deletions(-)
+
+--- a/src/collectd.conf.pod
++++ b/src/collectd.conf.pod
+@@ -4169,6 +4169,16 @@ supported.
+ Sets the type instance to use when dispatching the value to I<collectd>. If
+ unset, an empty string (no type instance) is used.
++=item B<Scale> I<Value>
++
++The values taken from collectd are multiplied by I<Value>. The field is optional
++and the default is B<1.0>.
++
++=item B<Shift> I<Value>
++
++I<Value> is added to values from collectd after they have been multiplied by
++B<Scale> value. The field is optional and the default value is B<0.0>.
++
+ =back
+ =item E<lt>B<Host> I<Name>E<gt> blocks
+--- a/src/modbus.c
++++ b/src/modbus.c
+@@ -105,6 +105,8 @@ struct mb_data_s /* {{{ */
+   mb_mreg_type_t modbus_register_type;
+   char type[DATA_MAX_NAME_LEN];
+   char instance[DATA_MAX_NAME_LEN];
++  double scale;
++  double shift;
+   mb_data_t *next;
+ }; /* }}} */
+@@ -395,13 +397,13 @@ static int mb_init_connection(mb_host_t
+ #define CAST_TO_VALUE_T(ds, vt, raw)                                           \
+   do {                                                                         \
+     if ((ds)->ds[0].type == DS_TYPE_COUNTER)                                   \
+-      (vt).counter = (counter_t)(raw);                                         \
++      (vt).counter = (((counter_t)(raw) * ds[0].scale) + ds[0].shift);         \
+     else if ((ds)->ds[0].type == DS_TYPE_GAUGE)                                \
+-      (vt).gauge = (gauge_t)(raw);                                             \
++      (vt).gauge = (((gauge_t)(raw) * ds[0].scale) + ds[0].shift);             \
+     else if ((ds)->ds[0].type == DS_TYPE_DERIVE)                               \
+-      (vt).derive = (derive_t)(raw);                                           \
++      (vt).derive = (((derive_t)(raw) * ds[0].scale) + ds[0].shift);           \
+     else /* if (ds->ds[0].type == DS_TYPE_ABSOLUTE) */                         \
+-      (vt).absolute = (absolute_t)(raw);                                       \
++      (vt).absolute = (((absolute_t)(raw) * ds[0].scale) + ds[0].shift);       \
+   } while (0)
+ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
+@@ -723,6 +725,8 @@ static int mb_config_add_data(oconfig_it
+   data.name = NULL;
+   data.register_type = REG_TYPE_UINT16;
+   data.next = NULL;
++  data.scale = 1;
++  data.shift = 0;
+   status = cf_util_get_string(ci, &data.name);
+   if (status != 0)
+@@ -736,6 +740,12 @@ static int mb_config_add_data(oconfig_it
+     else if (strcasecmp("Instance", child->key) == 0)
+       status = cf_util_get_string_buffer(child, data.instance,
+                                          sizeof(data.instance));
++    else if (strcasecmp("Scale", child->key) == 0)
++      status = cf_util_get_string_buffer(child, data.scale, 
++                                         sizeof(data.scale));
++    else if (strcasecmp("Shift", child->key) == 0)
++      status = cf_util_get_string_buffer(child, data.shift, 
++                                         sizeof(data.shift));
+     else if (strcasecmp("RegisterBase", child->key) == 0)
+       status = cf_util_get_int(child, &data.register_base);
+     else if (strcasecmp("RegisterType", child->key) == 0) {
diff --git a/utils/collectd/patches/052-correcting-all-the-wrongs.patch b/utils/collectd/patches/052-correcting-all-the-wrongs.patch
new file mode 100644 (file)
index 0000000..b56fe3d
--- /dev/null
@@ -0,0 +1,120 @@
+From e596496f5c783f4bba85c4d559502c98e4050465 Mon Sep 17 00:00:00 2001
+From: cekstam <christian.ekstam@gmail.com>
+Date: Tue, 27 Mar 2018 14:11:52 +0200
+Subject: [PATCH 2/3] correcting all the wrongs
+
+, data->scale, data->shift
+---
+ src/modbus.c | 32 +++++++++++++++-----------------
+ 1 file changed, 15 insertions(+), 17 deletions(-)
+
+--- a/src/modbus.c
++++ b/src/modbus.c
+@@ -394,16 +394,16 @@ static int mb_init_connection(mb_host_t
+ } /* }}} int mb_init_connection */
+ #endif /* !LEGACY_LIBMODBUS */
+-#define CAST_TO_VALUE_T(ds, vt, raw)                                           \
++#define CAST_TO_VALUE_T(ds, vt, raw, scale, shift)                             \
+   do {                                                                         \
+     if ((ds)->ds[0].type == DS_TYPE_COUNTER)                                   \
+-      (vt).counter = (((counter_t)(raw) * ds[0].scale) + ds[0].shift);         \
++      (vt).counter = (((counter_t)(raw) * scale) + shift);                     \
+     else if ((ds)->ds[0].type == DS_TYPE_GAUGE)                                \
+-      (vt).gauge = (((gauge_t)(raw) * ds[0].scale) + ds[0].shift);             \
++      (vt).gauge = (((gauge_t)(raw) * scale) + shift);                         \
+     else if ((ds)->ds[0].type == DS_TYPE_DERIVE)                               \
+-      (vt).derive = (((derive_t)(raw) * ds[0].scale) + ds[0].shift);           \
++      (vt).derive = (((derive_t)(raw) * scale) + shift);                       \
+     else /* if (ds->ds[0].type == DS_TYPE_ABSOLUTE) */                         \
+-      (vt).absolute = (((absolute_t)(raw) * ds[0].scale) + ds[0].shift);       \
++      (vt).absolute = (((absolute_t)(raw) * scale) + shift);                   \
+   } while (0)
+ static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
+@@ -532,7 +532,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned float value is %g",
+           (double)float_value);
+-    CAST_TO_VALUE_T(ds, vt, float_value);
++    CAST_TO_VALUE_T(ds, vt, float_value, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_FLOAT_CDAB) {
+     float float_value;
+@@ -543,7 +543,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned float value is %g",
+           (double)float_value);
+-    CAST_TO_VALUE_T(ds, vt, float_value);
++    CAST_TO_VALUE_T(ds, vt, float_value, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_INT32) {
+     union {
+@@ -557,7 +557,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned int32 value is %" PRIi32,
+           v.i32);
+-    CAST_TO_VALUE_T(ds, vt, v.i32);
++    CAST_TO_VALUE_T(ds, vt, v.i32, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_INT32_CDAB) {
+     union {
+@@ -571,7 +571,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned int32 value is %" PRIi32,
+           v.i32);
+-    CAST_TO_VALUE_T(ds, vt, v.i32);
++    CAST_TO_VALUE_T(ds, vt, v.i32, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_INT16) {
+     union {
+@@ -586,7 +586,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned int16 value is %" PRIi16,
+           v.i16);
+-    CAST_TO_VALUE_T(ds, vt, v.i16);
++    CAST_TO_VALUE_T(ds, vt, v.i16, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_UINT32) {
+     uint32_t v32;
+@@ -597,7 +597,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned uint32 value is %" PRIu32,
+           v32);
+-    CAST_TO_VALUE_T(ds, vt, v32);
++    CAST_TO_VALUE_T(ds, vt, v32, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else if (data->register_type == REG_TYPE_UINT32_CDAB) {
+     uint32_t v32;
+@@ -608,7 +608,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned uint32 value is %" PRIu32,
+           v32);
+-    CAST_TO_VALUE_T(ds, vt, v32);
++    CAST_TO_VALUE_T(ds, vt, v32, data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   } else /* if (data->register_type == REG_TYPE_UINT16) */
+   {
+@@ -618,7 +618,7 @@ static int mb_read_data(mb_host_t *host,
+           "Returned uint16 value is %" PRIu16,
+           values[0]);
+-    CAST_TO_VALUE_T(ds, vt, values[0]);
++    CAST_TO_VALUE_T(ds, vt, values[0], data->scale, data->shift);
+     mb_submit(host, slave, data, vt);
+   }
+@@ -741,11 +741,9 @@ static int mb_config_add_data(oconfig_it
+       status = cf_util_get_string_buffer(child, data.instance,
+                                          sizeof(data.instance));
+     else if (strcasecmp("Scale", child->key) == 0)
+-      status = cf_util_get_string_buffer(child, data.scale, 
+-                                         sizeof(data.scale));
++      status = cf_util_get_double(child, &data.scale);
+     else if (strcasecmp("Shift", child->key) == 0)
+-      status = cf_util_get_string_buffer(child, data.shift, 
+-                                         sizeof(data.shift));
++      status = cf_util_get_double(child, &data.shift);
+     else if (strcasecmp("RegisterBase", child->key) == 0)
+       status = cf_util_get_int(child, &data.register_base);
+     else if (strcasecmp("RegisterType", child->key) == 0) {
diff --git a/utils/collectd/patches/053-Add-support-for-RS485-to-modbus-plugin.patch b/utils/collectd/patches/053-Add-support-for-RS485-to-modbus-plugin.patch
new file mode 100644 (file)
index 0000000..752689e
--- /dev/null
@@ -0,0 +1,114 @@
+From a00ab52931a587cf29c53a945e9295b4d7fe41ba Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 28 Mar 2019 01:52:04 +0100
+Subject: [PATCH] Add support for RS485 to modbus plugin
+
+Allow setting up RS485 mode for Modbus-RTU
+---
+ src/collectd.conf.pod |  6 +++++
+ src/modbus.c          | 55 +++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 57 insertions(+), 4 deletions(-)
+
+--- a/src/collectd.conf.pod
++++ b/src/collectd.conf.pod
+@@ -4234,6 +4234,12 @@ For Modbus/RTU, specifies the path to th
+ For Modbus/RTU, specifies the baud rate of the serial device.
+ Note, connections currently support only 8/N/1.
++=item B<UARTType> I<UARTType>
++
++For Modbus/RTU, specifies the type of the serial device.
++RS232, RS422 and RS485 are supported. Defaults to RS232.
++Available only on Linux systems with libmodbus>=2.9.4.
++
+ =item B<Interval> I<Interval>
+ Sets the interval (in seconds) in which the values will be collected from this
+--- a/src/modbus.c
++++ b/src/modbus.c
+@@ -95,6 +95,12 @@ enum mb_conntype_e /* {{{ */
+   MBCONN_RTU }; /* }}} */
+ typedef enum mb_conntype_e mb_conntype_t;
++enum mb_uarttype_e /* {{{ */
++{ UARTTYPE_RS232,
++  UARTTYPE_RS422,
++  UARTTYPE_RS485 }; /* }}} */
++typedef enum mb_uarttype_e mb_uarttype_t;
++
+ struct mb_data_s;
+ typedef struct mb_data_s mb_data_t;
+ struct mb_data_s /* {{{ */
+@@ -124,8 +130,9 @@ struct mb_host_s /* {{{ */
+   char host[DATA_MAX_NAME_LEN];
+   char node[NI_MAXHOST]; /* TCP hostname or RTU serial device */
+   /* char service[NI_MAXSERV]; */
+-  int port;     /* for Modbus/TCP */
+-  int baudrate; /* for Modbus/RTU */
++  int port;               /* for Modbus/TCP */
++  int baudrate;           /* for Modbus/RTU */
++  mb_uarttype_t uarttype; /* UART type for Modbus/RTU */
+   mb_conntype_t conntype;
+   cdtime_t interval;
+@@ -390,6 +397,22 @@ static int mb_init_connection(mb_host_t
+     return status;
+   }
++#if defined(linux) && LIBMODBUS_VERSION_CHECK(2, 9, 4)
++  switch (host->uarttype) {
++  case UARTTYPE_RS485:
++    if (modbus_rtu_set_serial_mode(host->connection, MODBUS_RTU_RS485))
++      DEBUG("Modbus plugin: Setting RS485 mode failed.");
++    break;
++  case UARTTYPE_RS422:
++    /* libmodbus doesn't say anything about full-duplex symmetric RS422 UART */
++    break;
++  case UARTTYPE_RS232:
++    break;
++  default:
++    DEBUG("Modbus plugin: Invalid UART type!.");
++  }
++#endif /* defined(linux) && LIBMODBUS_VERSION_CHECK(2, 9, 4) */
++
+   return 0;
+ } /* }}} int mb_init_connection */
+ #endif /* !LEGACY_LIBMODBUS */
+@@ -951,11 +974,35 @@ static int mb_config_add_host(oconfig_it
+         status = -1;
+     } else if (strcasecmp("Device", child->key) == 0) {
+       status = cf_util_get_string_buffer(child, host->node, sizeof(host->node));
+-      if (status == 0)
++      if (status == 0) {
+         host->conntype = MBCONN_RTU;
++        host->uarttype = UARTTYPE_RS232;
++      }
+     } else if (strcasecmp("Baudrate", child->key) == 0)
+       status = cf_util_get_int(child, &host->baudrate);
+-    else if (strcasecmp("Interval", child->key) == 0)
++    else if (strcasecmp("UARTType", child->key) == 0) {
++#if defined(linux) && !LEGACY_LIBMODBUS && LIBMODBUS_VERSION_CHECK(2, 9, 4)
++      char buffer[NI_MAXHOST];
++      status = cf_util_get_string_buffer(child, buffer, sizeof(buffer));
++      if (status != 0)
++        break;
++      if (strncmp(buffer, "RS485", 6) == 0)
++        host->uarttype = UARTTYPE_RS485;
++      else if (strncmp(buffer, "RS422", 6) == 0)
++        host->uarttype = UARTTYPE_RS422;
++      else if (strncmp(buffer, "RS232", 6) == 0)
++        host->uarttype = UARTTYPE_RS232;
++      else {
++        ERROR("Modbus plugin: The UARTType \"%s\" is unknown.", buffer);
++        status = -1;
++        break;
++      }
++#else
++      ERROR("Modbus plugin: Option `UARTType' not supported. Please "
++            "upgrade libmodbus to at least 2.9.4");
++      return -1;
++#endif
++    } else if (strcasecmp("Interval", child->key) == 0)
+       status = cf_util_get_cdtime(child, &host->interval);
+     else if (strcasecmp("Slave", child->key) == 0)
+       /* Don't set status: Gracefully continue if a slave fails. */