2 * collectd - src/modbus.c
3 * Copyright (C) 2010 noris network AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian Forster <octo at noris.net>
24 #include "configfile.h"
26 #include <modbus/modbus.h>
42 * Instance "foobar" # optional
51 enum mb_register_type_e
57 typedef enum mb_register_type_e mb_register_type_t;
60 typedef struct mb_data_s mb_data_t;
65 mb_register_type_t register_type;
66 char type[DATA_MAX_NAME_LEN];
67 char instance[DATA_MAX_NAME_LEN];
75 char instance[DATA_MAX_NAME_LEN];
78 typedef struct mb_slave_s mb_slave_t;
82 char host[DATA_MAX_NAME_LEN];
83 char node[NI_MAXHOST];
84 char service[NI_MAXSERV];
90 modbus_param_t connection;
93 struct mb_data_group_s;
94 typedef struct mb_data_group_s mb_data_group_t;
95 struct mb_data_group_s
100 mb_data_group_t *next;
106 static mb_data_t *data_definitions = NULL;
111 static mb_data_t *data_get_by_name (const mb_data_t *src, const char *name) /* {{{ */
118 for (ptr = src; ptr != NULL; ptr = ptr->next)
119 if (strcasecmp (ptr->name, name) == 0)
123 } /* }}} mb_data_t *data_get_by_name */
125 static int data_append (mb_data_t **dst, const mb_data_t *src) /* {{{ */
129 if ((dst == NULL) || (src == NULL))
140 while (ptr->next != NULL)
146 } /* }}} int data_append */
148 /* Copy a single mb_data_t and append it to another list. */
149 static int data_copy (mb_data_t **dst, const mb_data_t *src) /* {{{ */
154 if ((dst == NULL) || (src == NULL))
157 tmp = malloc (sizeof (*tmp));
160 memcpy (tmp, src, sizeof (*tmp));
164 tmp->name = sstrdup (src->name);
165 if (tmp->name == NULL)
171 status = data_append (dst, tmp);
180 } /* }}} int data_copy */
182 /* Lookup a single mb_data_t instance, copy it and append the copy to another
184 static int data_copy_by_name (mb_data_t **dst, const mb_data_t *src, /* {{{ */
189 if ((dst == NULL) || (src == NULL) || (name == NULL))
192 ptr = data_get_by_name (src, name);
196 return (data_copy (dst, ptr));
197 } /* }}} int data_copy_by_name */
199 static int mb_config_add_data (oconfig_item_t *ci) /* {{{ */
205 memset (&data, 0, sizeof (data));
207 status = cf_util_get_string (ci, &data.name);
211 for (i = 0; i < ci->children_num; i++)
213 oconfig_item_t *child = ci->children + i;
216 if (strcasecmp ("Type", child->key) == 0)
217 status = cf_util_get_string_buffer (child,
218 data.type, sizeof (data.type));
219 else if (strcasecmp ("Instance", child->key) == 0)
220 status = cf_util_get_string_buffer (child,
221 data.instance, sizeof (data.instance));
222 else if (strcasecmp ("RegisterBase", child->key) == 0)
223 status = cf_util_get_int (child, &data.register_base);
224 else if (strcasecmp ("RegisterType", child->key) == 0)
227 status = cf_util_get_string_buffer (child, tmp, sizeof (tmp));
230 else if (strcasecmp ("Uint16", tmp) == 0)
231 data.register_type = REG_TYPE_UINT16;
232 else if (strcasecmp ("Uint32", tmp) == 0)
233 data.register_type = REG_TYPE_UINT32;
234 else if (strcasecmp ("Float", tmp) == 0)
235 data.register_type = REG_TYPE_FLOAT;
238 ERROR ("Modbus plugin: The register type \"%s\" is unknown.", tmp);
244 ERROR ("Modbus plugin: Unknown configuration option: %s", child->key);
250 } /* for (i = 0; i < ci->children_num; i++) */
252 /* TODO: Validate the struct. */
254 data_copy (&data_definitions, &data);
258 } /* }}} int mb_config_add_data */
260 static void mb_free_internal (mb_internal_t *i) /* {{{ */
265 free (i->connection);
267 } /* }}} void mb_free_internal */
269 static mb_internal_t *mb_alloc_internal (void) /* {{{ */
273 ret = malloc (sizeof (*ret));
276 memset (ret, 0, sizeof (*ret));
278 ret->connection = calloc (1, sizeof (*ret->connection));
279 if (ret->connection == NULL)
281 mb_free_internal (ret);
286 } /* }}} mb_internal_t *mb_alloc_internal */
288 static mb_internal_t *mb_init (void) /* {{{ */
293 ret = mb_alloc_internal ();
297 modbus_set_debug (ret->connection, 1);
299 /* We'll do the error handling ourselves. */
300 modbus_set_error_handling (ret->connection, NOP_ON_ERROR);
302 modbus_init_tcp (ret->connection,
303 /* host = */ "172.18.20.30", /* FIXME: Only IP adresses allowed. -> convert hostnames. */
304 /* post = */ MODBUS_TCP_DEFAULT_PORT); /* FIXME: Use configured port. */
306 status = modbus_connect (ret->connection);
307 printf ("mb_init: modbus_connect returned status %i\n", status);
310 mb_free_internal (ret);
315 } /* }}} mb_internal_t *mb_init */
317 static float mb_register_to_float (uint16_t hi, uint16_t lo) /* {{{ */
327 conv.b[0] = lo & 0x00ff;
328 conv.b[1] = (lo >> 8) & 0x00ff;
329 conv.b[2] = hi & 0x00ff;
330 conv.b[3] = (hi >> 8) & 0x00ff;
332 conv.b[3] = lo & 0x00ff;
333 conv.b[2] = (lo >> 8) & 0x00ff;
334 conv.b[1] = hi & 0x00ff;
335 conv.b[0] = (hi >> 8) & 0x00ff;
339 } /* }}} float mb_register_to_float */
341 static int mb_read (mb_internal_t *dev, int register_addr, _Bool is_float) /* {{{ */
350 printf ("mb_read (addr = %i, float = %s);\n", register_addr,
351 is_float ? "true" : "false");
353 memset (values, 0, sizeof (values));
359 status = read_holding_registers (dev->connection,
360 /* slave = */ 1, /* start_addr = */ register_addr,
361 /* num_registers = */ values_num, /* buffer = */ values);
362 printf ("read_coil_status returned with status %i\n", status);
368 float value = mb_register_to_float (values[0], values[1]);
369 printf ("read_coil_status returned value %g (hi %#"PRIx16", lo %#"PRIx16")\n",
370 value, values[0], values[1]);
374 printf ("read_coil_status returned value %"PRIu16"\n", values[0]);
378 } /* }}} int mb_read */
380 static int mb_shutdown (mb_internal_t *dev) /* {{{ */
382 if ((dev != NULL) && (dev->connection != NULL))
383 modbus_close (dev->connection);
384 mb_free_internal (dev);
387 } /* }}} int mb_shutdown */
389 int main (int argc, char **argv) /* {{{ */
394 argc = 0; argv = NULL;
399 for (j = 1; j < argc; j++)
401 mb_read (dev, atoi (argv[j]));
404 mb_read (dev, 4096+3, /* is_float = */ 0);
405 mb_read (dev, 2*3, /* is_float = */ 1);
412 void module_register (void)
414 plugin_register_complex_config ("modbus", mb_config);
415 plugin_register_init ("modbus", mv_init);
416 plugin_register_shutdown ("modbus", mv_shutdown);
417 } /* void module_register */
419 /* vim: set sw=2 sts=2 et fdm=marker : */