X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fonewire.c;h=1383fc5803451437e6009b801ecbc0c6c16c798c;hb=2cbd37356b2a3d3890b335d01e0d563269b448be;hp=09a6bf0926154369c3fe75e408a3c79c9b194cfe;hpb=50c6b81549e3239034f71f00ff7dde4c6a8767e5;p=collectd.git diff --git a/src/onewire.c b/src/onewire.c index 09a6bf09..1383fc58 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 @@ -24,6 +24,9 @@ #include "plugin.h" #include "utils_ignorelist.h" +#include +#include +#include #include #define OW_FAMILY_LENGTH 8 @@ -41,10 +44,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 +65,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 +128,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 = NULL; + + DEBUG ("onewire plugin: direct_list_insert <%s>", config); + + element = (direct_access_element_t *) 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 +281,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) @@ -158,6 +369,7 @@ 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) { @@ -165,6 +377,7 @@ static int cow_read_values (const char *path, const char *name, path, family_info->features[i].filename, status); return (-1); } + DEBUG ("Read onewire device %s as %s", file, buffer); endptr = NULL; values[0].gauge = strtod (buffer, &endptr); @@ -276,16 +489,104 @@ static int cow_read_bus (const char *path) return (0); } /* int cow_read_bus */ + +/* =================================================================================== */ + +static int cow_simple_read (void) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + char *buffer; + size_t buffer_size; + int status; + char *endptr; + direct_access_element_t *traverse; + + /* traverse list and check entries */ + for (traverse = direct_list; traverse != NULL; traverse = traverse->next) + { + 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, 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 = %#x;", + traverse->path, + status); + return (-1); + } + DEBUG ("onewire plugin: Read onewire device %s as %s", traverse->path, buffer); + + + endptr = NULL; + values[0].gauge = strtod (buffer, &endptr); + if (endptr == NULL) + { + ERROR ("onewire plugin: Buffer is not a number: %s", buffer); + status = -1; + continue; + } + + sstrncpy (vl.type, traverse->file, sizeof (vl.type)); + sstrncpy (vl.type_instance, "", sizeof ("")); + + 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) @@ -299,6 +600,7 @@ 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) { @@ -320,7 +622,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 : */