This patch adds Modbus/RTU support to the modbus plugin of collectd 4.10.3. It's a quick hack and didn't receive any testing yet, but please please review and let me know what you think and help me.
Signed-off-by: Daniel Golle <[email protected]> --- a/src/modbus.c 2011-03-28 20:01:58.000000000 +0200 +++ b/src/modbus.c 2011-03-28 20:03:45.000000000 +0200 @@ -91,6 +91,16 @@ struct mb_host_s /* {{{ */ { char host[DATA_MAX_NAME_LEN]; + type_com_t type_com; +#ifdef __APPLE_CC__ + char device[64]; +#else + char device[16]; +#endif + int baud; + int data_bits; + int stop_bits; + char parity[5]; char node[NI_MAXHOST]; /* char service[NI_MAXSERV]; */ int port; @@ -265,7 +275,7 @@ return (conv.f); } /* }}} float mb_register_to_float */ -static int mb_init_connection (mb_host_t *host) /* {{{ */ +static inline int mb_init_connection_tcp (mb_host_t *host) /* {{{ */ { int status; @@ -305,6 +315,69 @@ host->is_connected = 1; host->have_reconnected = 1; return (0); +} /* }}} int mb_init_connection_tcp */ + +static inline int mb_init_connection_rtu (mb_host_t *host) /* {{{ */ +{ + int status; + + if (host == NULL) + return (EINVAL); + + if (host->is_connected) + return (0); + + /* Only reconnect once per interval. */ + if (host->have_reconnected) + return (-1); + + modbus_set_debug (&host->connection, 1); + + /* We'll do the error handling ourselves. */ + modbus_set_error_handling (&host->connection, NOP_ON_ERROR); + + if (host->baud < 300) + host->baud = 9600; + + if ((host->data_bits < 7) || (host->data_bits > 16)) + host->data_bits = 8; + + if ((host->stop_bits < 1) || (host->stop_bits > 16)) + host->stop_bits = 1; + + if ( ! (strcmp(host->parity, "even") || strcmp(host->parity, "odd") || strcmp(host->parity, "none"))) + memcpy(host->parity, "none", sizeof("none")); + + DEBUG ("Modbus plugin: Trying to open \"%s\".", + host->device); + + modbus_init_rtu (&host->connection, + /* device = */ host->device, + /* baud = */ host->baud, + /* parity = */ host->parity, + /* data_bit = */ (uint8_t)host->data_bits, + /* stop_bit = */ (uint8_t)host->stop_bits); + + status = modbus_connect (&host->connection); + if (status != 0) + { + ERROR ("Modbus plugin: modbus_connect (%s, %i baud, %i %s %i) failed with status %i.", + host->device, host->baud, host->data_bits, host->parity, host->stop_bits, status); + return (status); + } + + host->is_connected = 1; + host->have_reconnected = 1; + return (0); +} /* }}} int mb_init_connection_rtu */ + +static int mb_init_connection (mb_host_t *host) /* {{{ */ +{ + if ( host->type_com == TCP ) + return mb_init_connection_tcp(host); + else if ( host->type_com == RTU ) + return mb_init_connection_rtu(host); + else return -1; } /* }}} int mb_init_connection */ #define CAST_TO_VALUE_T(ds,vt,raw) do { \ @@ -748,6 +821,7 @@ if (host->host[0] == 0) return (EINVAL); + host->type_com = TCP; for (i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -817,6 +891,114 @@ return (status); } /* }}} int mb_config_add_host */ +static int mb_config_add_device (oconfig_item_t *ci) /* {{{ */ +{ + mb_host_t *host; + int status; + int i; + + host = malloc (sizeof (*host)); + if (host == NULL) + return (ENOMEM); + memset (host, 0, sizeof (*host)); + host->slaves = NULL; + + status = cf_util_get_string_buffer (ci, host->host, sizeof (host->host)); + if (status != 0) + return (status); + if (host->host[0] == 0) + return (EINVAL); + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + status = 0; + + if (strcasecmp ("Device", child->key) == 0) + { + status = cf_util_get_string_buffer (child, host->device, sizeof (host->device)); + if (status != 0) + return (status); + if (host->device[0] == 0) + return (EINVAL); + } + else if (strcasecmp ("Baud", child->key) == 0) + { + status = cf_util_get_int (child, &host->baud); + if (host->baud <= 0) + status = -1; + } + else if (strcasecmp ("DataBits", child->key) == 0) + { + status = cf_util_get_int (child, &host->data_bits); + if (host->data_bits < 7) + status = -1; + } + else if (strcasecmp ("StopBits", child->key) == 0) + { + status = cf_util_get_int (child, &host->stop_bits); + if (host->stop_bits <= 0) + status = -1; + } + else if (strcasecmp ("Parity", child->key) == 0) + { + status = cf_util_get_string_buffer (child, host->parity, sizeof (host->parity)); + if (status != 0) + return (status); + if (host->parity[0] == 0) + return (EINVAL); + + } + else if (strcasecmp ("Interval", child->key) == 0) + status = cf_util_get_int (child, &host->interval); + else if (strcasecmp ("Slave", child->key) == 0) + /* Don't set status: Gracefully continue if a slave fails. */ + mb_config_add_slave (host, child); + else + { + ERROR ("Modbus plugin: Unknown configuration option: %s", child->key); + status = -1; + } + + if (status != 0) + break; + } /* for (i = 0; i < ci->children_num; i++) */ + + assert (host->host[0] != 0); + if (host->host[0] == 0) + { + ERROR ("Modbus plugin: Data block \"%s\": No type has been specified.", + host->host); + status = -1; + } + + if (status == 0) + { + user_data_t ud; + char name[1024]; + struct timespec interval; + + ud.data = host; + ud.free_func = host_free; + + ssnprintf (name, sizeof (name), "modbus-%s", host->host); + + interval.tv_nsec = 0; + if (host->interval > 0) + interval.tv_sec = host->interval; + else + interval.tv_sec = 0; + + plugin_register_complex_read (/* group = */ NULL, name, + mb_read, (interval.tv_sec > 0) ? &interval : NULL, &ud); + } + else + { + host_free (host); + } + + return (status); +} /* }}} int mb_config_add_device */ + static int mb_config (oconfig_item_t *ci) /* {{{ */ { int i; @@ -832,6 +1014,8 @@ mb_config_add_data (child); else if (strcasecmp ("Host", child->key) == 0) mb_config_add_host (child); + else if (strcasecmp ("Device", child->key) == 0) + mb_config_add_device (child); else ERROR ("Modbus plugin: Unknown configuration option: %s", child->key); } --- a/src/collectd.conf.in 2011-03-28 20:05:14.000000000 +0200 +++ b/src/collectd.conf.in 2011-03-28 20:12:56.000000000 +0200 @@ -445,6 +445,19 @@ # Collect "data_name" # </Slave> # </Host> +# <Device "name"> +# Device "/dev/serial" +# Baud 9600 +# DataBits 8 +# StopBits 1 +# Parity "none" +# Interval 60 +# +# <Slave 1> +# Instance "foobar" # optional +# Collect "data_name" +# </Slave> +# </Host> #</Plugin> #<Plugin mysql> --- a/src/collectd.conf.pod 2011-03-26 18:08:53.000000000 +0200 +++ b/src/collectd.conf.pod 2011-03-28 20:10:59.000000000 +0200 @@ -1731,10 +1731,11 @@ =head2 Plugin C<modbus> -The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP and reads -register values. It supports reading single registers (unsigned 16E<nbsp>bit -values), large integer values (unsigned 32E<nbsp>bit values) and floating point -values (two registers interpreted as IEEE floats in big endian notation). +The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP or Modbus/RTU +and reads register values. +It supports reading single registers (unsigned 16E<nbsp>bit values), +large integer values (unsigned 32E<nbsp>bit values) and floating point values +(two registers interpreted as IEEE floats in big endian notation). Synopsis: @@ -1758,6 +1759,21 @@ Interval 60 <Slave 1> + Instance "power-supply" + Collect "voltage-input-1" + Collect "voltage-input-2" + </Slave> + </Host> + + <Device "SerialDevice1"> + Device "/dev/ttyS1" + Baud 9600 + DataBits 8 + StopBits 1 + Parity "none" + Interval 60 + + <Slave 1> Instance "power-supply" Collect "voltage-input-1" Collect "voltage-input-2" _______________________________________________ collectd mailing list [email protected] http://mailman.verplant.org/listinfo/collectd
