X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fmultimeter.c;h=72b0fed91c1f32caab8ec7b2846389d70031b513;hb=7a8cd12cc66a349106a34a7655944cfeac71d7c5;hp=317745b285ad1798761ab651bfc1057fd065d0c6;hpb=9c199c432be4160deb06233fd70420a4568ccf86;p=collectd.git diff --git a/src/multimeter.c b/src/multimeter.c index 317745b2..72b0fed9 100644 --- a/src/multimeter.c +++ b/src/multimeter.c @@ -20,215 +20,204 @@ * Peter Holik * * Used multimeter: Metex M-4650CR - * **/ -#include -#include -#include #include "collectd.h" + #include "common.h" #include "plugin.h" -#define MODULE_NAME "multimeter" - -static char *multimeter_file = "multimeter.rrd"; - -static char *ds_def[] = -{ - "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U", - NULL -}; -static int ds_num = 1; +#if HAVE_TERMIOS_H && HAVE_SYS_IOCTL_H +#include +#include +#else +#error "No applicable input method." +#endif static int fd = -1; -static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2, - struct timeval *res) -{ - if ((tv1->tv_sec < tv2->tv_sec) || - ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec < tv2->tv_usec))) - return (-1); - - res->tv_sec = tv1->tv_sec - tv2->tv_sec; - res->tv_usec = tv1->tv_usec - tv2->tv_usec; - - assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec > 0))); - - while (res->tv_usec < 0) - { - res->tv_usec += 1000000; - res->tv_sec--; - } - return (0); -} #define LINE_LENGTH 14 -static int multimeter_read_value(double *value) -{ - int retry = 3; /* sometimes we receive garbadge */ - - do - { - struct timeval time_end; - - tcflush(fd, TCIFLUSH); - - if (gettimeofday (&time_end, NULL) < 0) - { - syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s", - strerror (errno)); - return (-1); - } - time_end.tv_sec++; - - while (1) - { - char buf[LINE_LENGTH]; - char *range; - int status; - fd_set rfds; - struct timeval timeout; - struct timeval time_now; - - write(fd, "D", 1); - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - if (gettimeofday (&time_now, NULL) < 0) - { - syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s", - strerror (errno)); - return (-1); - } - if (multimeter_timeval_sub (&time_end, &time_now, &timeout) == -1) - break; - - status = select(fd+1, &rfds, NULL, NULL, &timeout); - - if (status > 0) /* usually we succeed */ - { - status = read(fd, buf, LINE_LENGTH); - - if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) - continue; - - /* Format: "DC 00.000mV \r" */ - if (status > 0 && status == LINE_LENGTH) - { - *value = strtod(buf + 2, &range); - - if ( range > (buf + 6) ) - { - range = buf + 9; - - switch ( *range ) - { - case 'p': *value *= 1.0E-12; break; - case 'n': *value *= 1.0E-9; break; - case 'u': *value *= 1.0E-6; break; - case 'm': *value *= 1.0E-3; break; - case 'k': *value *= 1.0E3; break; - case 'M': *value *= 1.0E6; break; - case 'G': *value *= 1.0E9; break; - } - } - else - return (-1); /* Overflow */ - - return (0); /* value received */ - } - else break; - } - else if (!status) /* Timeout */ - { - break; - } - else if ((status == -1) && ((errno == EAGAIN) || (errno == EINTR))) - { - continue; - } - else /* status == -1 */ - { - syslog (LOG_ERR, MODULE_NAME": select failed: %s", - strerror (errno)); - break; - } - } - } while (--retry); - - return (-2); /* no value received */ -} - -static void multimeter_init (void) -{ - int i; - char device[] = "/dev/ttyS "; - - for (i = 0; i < 10; i++) - { - device[strlen(device)-1] = i + '0'; - - if ((fd = open(device, O_RDWR | O_NOCTTY)) > 0) - { - struct termios tios; - int rts = TIOCM_RTS; - double value; - - tios.c_cflag = B1200 | CS7 | CSTOPB | CREAD | CLOCAL; - tios.c_iflag = IGNBRK | IGNPAR; - tios.c_oflag = 0; - tios.c_lflag = 0; - tios.c_cc[VTIME] = 3; - tios.c_cc[VMIN] = LINE_LENGTH; - - tcflush(fd, TCIFLUSH); - tcsetattr(fd, TCSANOW, &tios); - ioctl(fd, TIOCMBIC, &rts); - - if (multimeter_read_value(&value) < -1) - { - close(fd); - fd = -1; - } - else - { - syslog (LOG_INFO, MODULE_NAME" found (%s)", device); - return; - } - } - } - syslog (LOG_ERR, MODULE_NAME" not found"); +static int multimeter_read_value(double *value) { + int retry = 3; /* sometimes we receive garbadge */ + + do { + struct timeval time_end; + + tcflush(fd, TCIFLUSH); + + if (gettimeofday(&time_end, NULL) < 0) { + char errbuf[1024]; + ERROR("multimeter plugin: gettimeofday failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + time_end.tv_sec++; + + while (1) { + char buf[LINE_LENGTH]; + char *range; + int status; + fd_set rfds; + struct timeval timeout; + struct timeval time_now; + + status = swrite(fd, "D", 1); + if (status < 0) { + ERROR("multimeter plugin: swrite failed."); + return -1; + } + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + if (gettimeofday(&time_now, NULL) < 0) { + char errbuf[1024]; + ERROR("multimeter plugin: " + "gettimeofday failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + if (timeval_cmp(time_end, time_now, &timeout) < 0) + break; + + status = select(fd + 1, &rfds, NULL, NULL, &timeout); + + if (status > 0) /* usually we succeed */ + { + status = read(fd, buf, LINE_LENGTH); + + if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) + continue; + + /* Format: "DC 00.000mV \r" */ + if (status > 0 && status == LINE_LENGTH) { + *value = strtod(buf + 2, &range); + + if (range > (buf + 6)) { + range = buf + 9; + + switch (*range) { + case 'p': + *value *= 1.0E-12; + break; + case 'n': + *value *= 1.0E-9; + break; + case 'u': + *value *= 1.0E-6; + break; + case 'm': + *value *= 1.0E-3; + break; + case 'k': + *value *= 1.0E3; + break; + case 'M': + *value *= 1.0E6; + break; + case 'G': + *value *= 1.0E9; + break; + } + } else + return -1; /* Overflow */ + + return 0; /* value received */ + } else + break; + } else if (!status) /* Timeout */ + { + break; + } else if ((status == -1) && ((errno == EAGAIN) || (errno == EINTR))) { + continue; + } else /* status == -1 */ + { + char errbuf[1024]; + ERROR("multimeter plugin: " + "select failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + break; + } + } + } while (--retry); + + return -2; /* no value received */ +} /* int multimeter_read_value */ + +static int multimeter_init(void) { + char device[] = "/dev/ttyS "; + + for (int i = 0; i < 10; i++) { + device[strlen(device) - 1] = i + '0'; + + if ((fd = open(device, O_RDWR | O_NOCTTY)) != -1) { + struct termios tios = {0}; + int rts = TIOCM_RTS; + double value; + + tios.c_cflag = B1200 | CS7 | CSTOPB | CREAD | CLOCAL; + tios.c_iflag = IGNBRK | IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + tios.c_cc[VTIME] = 3; + tios.c_cc[VMIN] = LINE_LENGTH; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &tios); + ioctl(fd, TIOCMBIC, &rts); + + if (multimeter_read_value(&value) < -1) { + close(fd); + fd = -1; + } else { + INFO("multimeter plugin: Device " + "found at %s", + device); + return 0; + } + } + } + + ERROR("multimeter plugin: No device found"); + return -1; } #undef LINE_LENGTH -static void multimeter_write (char *host, char *inst, char *val) -{ - rrd_update_file (host, multimeter_file, val, ds_def, ds_num); -} -#define BUFSIZE 128 -static void multimeter_submit (double *value) -{ - char buf[BUFSIZE]; +static void multimeter_submit(double value) { + value_list_t vl = VALUE_LIST_INIT; - if (snprintf (buf, BUFSIZE, "%u:%f", (unsigned int) curtime, *value) >= BUFSIZE) - return; + vl.values = &(value_t){.gauge = value}; + vl.values_len = 1; + sstrncpy(vl.plugin, "multimeter", sizeof(vl.plugin)); + sstrncpy(vl.type, "multimeter", sizeof(vl.type)); - plugin_submit (MODULE_NAME, NULL, buf); + plugin_dispatch_values(&vl); } -#undef BUFSIZE -static void multimeter_read (void) -{ - double value; +static int multimeter_read(void) { + double value; - if (fd > -1 && !(multimeter_read_value(&value))) - multimeter_submit (&value); -} + if (fd < 0) + return -1; + + if (multimeter_read_value(&value) != 0) + return -1; + + multimeter_submit(value); + return 0; +} /* int multimeter_read */ + +static int multimeter_shutdown(void) { + if (fd >= 0) { + close(fd); + fd = -1; + } -void module_register (void) -{ - plugin_register (MODULE_NAME, multimeter_init, multimeter_read, multimeter_write); + return 0; } -#undef MODULE_NAME +void module_register(void) { + plugin_register_init("multimeter", multimeter_init); + plugin_register_read("multimeter", multimeter_read); + plugin_register_shutdown("multimeter", multimeter_shutdown); +} /* void module_register */