X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fonewire.c;h=c333fead4455b9e84e0d0653c5712c8fc8d2667d;hb=04f27bdd38966e0b826b283d8790ce31fb467929;hp=0266e9b76cedfab62b0b1184ecea7e757644b871;hpb=c1219a1c9db2e8400e2ee94b87f86ccd441485d5;p=collectd.git diff --git a/src/onewire.c b/src/onewire.c index 0266e9b7..c333fead 100644 --- a/src/onewire.c +++ b/src/onewire.c @@ -1,6 +1,6 @@ /** - * collectd - src/owfs.c - * Copyright (C) 2008 Florian octo Forster + * collectd - src/onewire.c + * Copyright (C) 2008 noris network AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,10 +20,14 @@ **/ #include "collectd.h" + #include "common.h" #include "plugin.h" #include "utils_ignorelist.h" +#include +#include +#include #include #define OW_FAMILY_LENGTH 8 @@ -41,10 +45,18 @@ struct ow_family_features_s }; typedef struct ow_family_features_s ow_family_features_t; +/* internal timing info collected in debug version only */ +#if COLLECT_DEBUG +static struct timeval tv_begin, tv_end, tv_diff; +#endif /* COLLECT_DEBUG */ + +/* regexp to extract address (without family) and file from the owfs path */ +static const char *regexp_to_match = "[A-Fa-f0-9]{2}\\.([A-Fa-f0-9]{12})/([[:alnum:]]+)$"; + /* see http://owfs.sourceforge.net/ow_table.html for a list of families */ static ow_family_features_t ow_family_features[] = { - { + { /* DS18S20 Precision Thermometer and DS1920 ibutton */ /* family = */ "10.", { { @@ -54,12 +66,57 @@ static ow_family_features_t ow_family_features[] = } }, /* features_num = */ 1 + }, + { /* DS1822 Econo Thermometer */ + /* family = */ "22.", + { + { + /* filename = */ "temperature", + /* type = */ "temperature", + /* type_instance = */ "" + } + }, + /* features_num = */ 1 + }, + { /* DS18B20 Programmable Resolution Thermometer */ + /* family = */ "28.", + { + { + /* filename = */ "temperature", + /* type = */ "temperature", + /* type_instance = */ "" + } + }, + /* features_num = */ 1 + }, + { /* DS2436 Volts/Temp */ + /* family = */ "1B.", + { + { + /* filename = */ "temperature", + /* type = */ "temperature", + /* type_instance = */ "" + } + }, + /* features_num = */ 1 + }, + { /* DS2438 Volts/Temp */ + /* family = */ "26.", + { + { + /* filename = */ "temperature", + /* type = */ "temperature", + /* type_instance = */ "" + } + }, + /* features_num = */ 1 } }; static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features); static char *device_g = NULL; static cdtime_t ow_interval = 0; +static _Bool direct_access = 0; static const char *config_keys[] = { @@ -72,6 +129,152 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); static ignorelist_t *sensor_list; +static _Bool regex_direct_initialized = 0; +static regex_t regex_direct; + +/** + * List of onewire owfs "files" to be directly read + */ +typedef struct direct_access_element_s +{ + char *path; /**< The whole owfs path */ + char *address; /**< 1-wire address without family */ + char *file; /**< owfs file - e.g. temperature */ + struct direct_access_element_s *next; /**< Next in the list */ +} direct_access_element_t; + +static direct_access_element_t * direct_list = NULL; + +/* =================================================================================== */ + +#if COLLECT_DEBUG +/* Return 1 if the difference is negative, otherwise 0. */ +static int timeval_subtract(struct timeval *result, struct timeval *t2, struct timeval *t1) +{ + long int diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec); + result->tv_sec = diff / 1000000; + result->tv_usec = diff % 1000000; + + return (diff<0); +} +#endif /* COLLECT_DEBUG */ + +/* =================================================================================== */ + +static void direct_list_element_free(direct_access_element_t *el) +{ + if (el != NULL) + { + DEBUG ("onewire plugin: direct_list_element_free - deleting <%s>", el->path); + sfree (el->path); + sfree (el->address); + sfree (el->file); + free (el); + } +} + +static int direct_list_insert(const char * config) +{ + regmatch_t pmatch[3]; + size_t nmatch = 3; + direct_access_element_t *element; + + DEBUG ("onewire plugin: direct_list_insert <%s>", config); + + element = malloc (sizeof (*element)); + if (element == NULL) + { + ERROR ("onewire plugin: direct_list_insert - cannot allocate element"); + return 1; + } + element->path = NULL; + element->address = NULL; + element->file = NULL; + + element->path = strdup (config); + if (element->path == NULL) + { + ERROR ("onewire plugin: direct_list_insert - cannot allocate path"); + direct_list_element_free (element); + return 1; + } + + DEBUG ("onewire plugin: direct_list_insert - about to match %s", config); + + if (!regex_direct_initialized) + { + if (regcomp (®ex_direct, regexp_to_match, REG_EXTENDED)) + { + ERROR ("onewire plugin: Cannot compile regex"); + direct_list_element_free (element); + return (1); + } + regex_direct_initialized = 1; + DEBUG ("onewire plugin: Compiled regex!!"); + } + + if (regexec (®ex_direct, config, nmatch, pmatch, 0)) + { + ERROR ("onewire plugin: direct_list_insert - no regex match"); + direct_list_element_free (element); + return 1; + } + + if (pmatch[1].rm_so<0) + { + ERROR ("onewire plugin: direct_list_insert - no address regex match"); + direct_list_element_free (element); + return 1; + } + element->address = strndup (config+pmatch[1].rm_so, + pmatch[1].rm_eo - pmatch[1].rm_so); + if (element->address == NULL) + { + ERROR ("onewire plugin: direct_list_insert - cannot allocate address"); + direct_list_element_free (element); + return 1; + } + DEBUG ("onewire plugin: direct_list_insert - found address <%s>", + element->address); + + if (pmatch[2].rm_so<0) + { + ERROR ("onewire plugin: direct_list_insert - no file regex match"); + direct_list_element_free (element); + return 1; + } + element->file = strndup (config+pmatch[2].rm_so, + pmatch[2].rm_eo - pmatch[2].rm_so); + if (element->file == NULL) + { + ERROR ("onewire plugin: direct_list_insert - cannot allocate file"); + direct_list_element_free (element); + return 1; + } + DEBUG ("onewire plugin: direct_list_insert - found file <%s>", element->file); + + element->next = direct_list; + direct_list = element; + + return 0; +} + +static void direct_list_free(void) +{ + direct_access_element_t *traverse = direct_list; + direct_access_element_t *tmp = NULL;; + + while(traverse != NULL) + { + tmp = traverse; + traverse = traverse->next; + direct_list_element_free (tmp); + tmp = NULL; + } +} + +/* =================================================================================== */ + static int cow_load_config (const char *key, const char *value) { if (sensor_list == NULL) @@ -79,11 +282,20 @@ static int cow_load_config (const char *key, const char *value) if (strcasecmp (key, "Sensor") == 0) { - if (ignorelist_add (sensor_list, value)) + if (direct_list_insert (value)) { - ERROR ("sensors plugin: " - "Cannot add value to ignorelist."); - return (1); + DEBUG ("onewire plugin: Cannot add %s to direct_list_insert.", value); + + if (ignorelist_add (sensor_list, value)) + { + ERROR ("onewire plugin: Cannot add value to ignorelist."); + return (1); + } + } + else + { + DEBUG ("onewire plugin: %s is a direct access", value); + direct_access = 1; } } else if (strcasecmp (key, "IgnoreSelected") == 0) @@ -124,10 +336,8 @@ static int cow_load_config (const char *key, const char *value) static int cow_read_values (const char *path, const char *name, const ow_family_features_t *family_info) { - value_t values[1]; value_list_t vl = VALUE_LIST_INIT; int success = 0; - size_t i; if (sensor_list != NULL) { @@ -136,18 +346,15 @@ static int cow_read_values (const char *path, const char *name, return 0; } - vl.values = values; - vl.values_len = 1; - - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin)); sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance)); - for (i = 0; i < family_info->features_num; i++) + for (size_t i = 0; i < family_info->features_num; i++) { char *buffer; size_t buffer_size; int status; + char errbuf[1024]; char file[4096]; char *endptr; @@ -158,16 +365,18 @@ static int cow_read_values (const char *path, const char *name, buffer = NULL; buffer_size = 0; + DEBUG ("Start reading onewire device %s", file); status = OW_get (file, &buffer, &buffer_size); if (status < 0) { - ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;", - path, family_info->features[i].filename, status); + ERROR ("onewire plugin: OW_get (%s/%s) failed. error = %s;", + path, family_info->features[i].filename, sstrerror(errno, errbuf, sizeof (errbuf))); return (-1); } + DEBUG ("Read onewire device %s as %s", file, buffer); endptr = NULL; - values[0].gauge = strtod (buffer, &endptr); + gauge_t g = strtod (buffer, &endptr); if (endptr == NULL) { ERROR ("onewire plugin: Buffer is not a number: %s", buffer); @@ -178,6 +387,9 @@ static int cow_read_values (const char *path, const char *name, sstrncpy (vl.type_instance, family_info->features[i].type_instance, sizeof (vl.type_instance)); + vl.values = &(value_t) { .gauge = g }; + vl.values_len = 1; + plugin_dispatch_values (&vl); success++; @@ -202,11 +414,11 @@ static int cow_read_ds2409 (const char *path) int status; status = ssnprintf (subpath, sizeof (subpath), "%s/main", path); - if ((status > 0) && (status < sizeof (subpath))) + if ((status > 0) && (status < (int) sizeof (subpath))) cow_read_bus (subpath); status = ssnprintf (subpath, sizeof (subpath), "%s/aux", path); - if ((status > 0) && (status < sizeof (subpath))) + if ((status > 0) && (status < (int) sizeof (subpath))) cow_read_bus (subpath); return (0); @@ -217,6 +429,7 @@ static int cow_read_bus (const char *path) char *buffer; size_t buffer_size; int status; + char errbuf[1024]; char *buffer_ptr; char *dummy; @@ -226,8 +439,8 @@ static int cow_read_bus (const char *path) status = OW_get (path, &buffer, &buffer_size); if (status < 0) { - ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;", - path, status); + ERROR ("onewire plugin: OW_get (%s) failed. error = %s;", + path, sstrerror(errno, errbuf, sizeof (errbuf))); return (-1); } DEBUG ("onewire plugin: OW_get (%s) returned: %s", @@ -246,7 +459,7 @@ static int cow_read_bus (const char *path) else status = ssnprintf (subpath, sizeof (subpath), "%s/%s", path, buffer_ptr); - if ((status <= 0) || (status >= sizeof (subpath))) + if ((status <= 0) || (status >= (int) sizeof (subpath))) continue; for (i = 0; i < ow_family_features_num; i++) @@ -275,22 +488,107 @@ static int cow_read_bus (const char *path) return (0); } /* int cow_read_bus */ + +/* =================================================================================== */ + +static int cow_simple_read (void) +{ + value_list_t vl = VALUE_LIST_INIT; + char *buffer; + size_t buffer_size; + int status; + char errbuf[1024]; + char *endptr; + direct_access_element_t *traverse; + + /* traverse list and check entries */ + for (traverse = direct_list; traverse != NULL; traverse = traverse->next) + { + sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, traverse->address, sizeof (vl.plugin_instance)); + + status = OW_get (traverse->path, &buffer, &buffer_size); + if (status < 0) + { + ERROR ("onewire plugin: OW_get (%s) failed. status = %s;", + traverse->path, + sstrerror(errno, errbuf, sizeof (errbuf))); + return (-1); + } + DEBUG ("onewire plugin: Read onewire device %s as %s", traverse->path, buffer); + + endptr = NULL; + gauge_t g = strtod (buffer, &endptr); + if (endptr == NULL) + { + ERROR ("onewire plugin: Buffer is not a number: %s", buffer); + continue; + } + + sstrncpy (vl.type, traverse->file, sizeof (vl.type)); + sstrncpy (vl.type_instance, "", sizeof ("")); + + vl.values = &(value_t) { .gauge = g }; + vl.values_len = 1; + + plugin_dispatch_values (&vl); + free (buffer); + } /* for (traverse) */ + + return 0; +} /* int cow_simple_read */ + +/* =================================================================================== */ + static int cow_read (user_data_t *ud __attribute__((unused))) { - return (cow_read_bus ("/")); + int result=0; + +#if COLLECT_DEBUG + gettimeofday (&tv_begin, NULL); +#endif /* COLLECT_DEBUG */ + + if (direct_access) + { + DEBUG ("onewire plugin: Direct access read"); + result = cow_simple_read (); + } + else + { + DEBUG ("onewire plugin: Standard access read"); + result = cow_read_bus ("/"); + } + +#if COLLECT_DEBUG + gettimeofday (&tv_end, NULL); + timeval_subtract (&tv_diff, &tv_end, &tv_begin); + DEBUG ("onewire plugin: Onewire read took us %ld.%06ld s", + tv_diff.tv_sec, + tv_diff.tv_usec); +#endif /* COLLECT_DEBUG */ + + return result; } /* int cow_read */ static int cow_shutdown (void) { - OW_finish (); - ignorelist_free (sensor_list); - return (0); + OW_finish (); + ignorelist_free (sensor_list); + + direct_list_free (); + + if (regex_direct_initialized) + { + regfree(®ex_direct); + } + + return (0); } /* int cow_shutdown */ static int cow_init (void) { int status; - struct timespec cb_interval; + char errbuf[1024]; if (device_g == NULL) { @@ -298,18 +596,16 @@ static int cow_init (void) return (-1); } + DEBUG ("onewire plugin: about to init device <%s>.", device_g); status = (int) OW_init (device_g); if (status != 0) { - ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status); + ERROR ("onewire plugin: OW_init(%s) failed: %s.", device_g, sstrerror(errno, errbuf, sizeof (errbuf))); return (1); } - CDTIME_T_TO_TIMESPEC (ow_interval, &cb_interval); - plugin_register_complex_read (/* group = */ NULL, "onewire", cow_read, - (ow_interval != 0) ? &cb_interval : NULL, - /* user data = */ NULL); + ow_interval, /* user data = */ NULL); plugin_register_shutdown ("onewire", cow_shutdown); return (0); @@ -319,7 +615,7 @@ void module_register (void) { plugin_register_init ("onewire", cow_init); plugin_register_config ("onewire", cow_load_config, - config_keys, config_keys_num); + config_keys, config_keys_num); } /* vim: set sw=2 sts=2 ts=8 et fdm=marker cindent : */