onewire plugin: Imported the code for DS2409 hubs.
[collectd.git] / src / onewire.c
1 /**
2  * collectd - src/owfs.c
3  * Copyright (C) 2008  Florian octo Forster
4  *
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.
8  *
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.
13  *
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
17  *
18  * Authors:
19  *   Florian octo Forster <octo at noris.net>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "utils_ignorelist.h"
26
27 #include <owcapi.h>
28
29 #define OW_FAMILY_LENGTH 8
30 #define OW_FAMILY_MAX_FEATURES 2
31 struct ow_family_features_s
32 {
33   char family[OW_FAMILY_LENGTH];
34   struct
35   {
36     char filename[DATA_MAX_NAME_LEN];
37     char type[DATA_MAX_NAME_LEN];
38     char type_instance[DATA_MAX_NAME_LEN];
39   } features[OW_FAMILY_MAX_FEATURES];
40   size_t features_num;
41 };
42 typedef struct ow_family_features_s ow_family_features_t;
43
44 /* see http://owfs.sourceforge.net/ow_table.html for a list of families */
45 static ow_family_features_t ow_family_features[] =
46 {
47   {
48     /* family = */ "10.",
49     {
50       {
51         /* filename = */ "temperature",
52         /* type = */ "temperature",
53         /* type_instance = */ ""
54       }
55     },
56     /* features_num = */ 1
57   }
58 };
59 static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
60
61 static char *device_g = NULL;
62
63 static const char *config_keys[] =
64 {
65   "Alias",
66   "Device",
67   "IgnoreSelected",
68   "Sensor",
69 };
70 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
71
72 static ignorelist_t *sensor_list;
73
74 static int cow_load_config (const char *key, const char *value)
75 {
76   if (sensor_list == NULL)
77     sensor_list = ignorelist_create (1);
78
79   if (strcasecmp (key, "Sensor") == 0)
80   {
81     if (ignorelist_add (sensor_list, value))
82     {
83       ERROR ("sensors plugin: "
84           "Cannot add value to ignorelist.");
85       return (1);
86     }
87   }
88   else if (strcasecmp (key, "IgnoreSelected") == 0)
89   {
90     ignorelist_set_invert (sensor_list, 1);
91     if ((strcasecmp (value, "True") == 0)
92         || (strcasecmp (value, "Yes") == 0)
93         || (strcasecmp (value, "On") == 0))
94       ignorelist_set_invert (sensor_list, 0);
95   }
96   else if (strcasecmp (key, "Device") == 0)
97   {
98     char *temp;
99     temp = strdup (value);
100     if (temp == NULL)
101     {
102       ERROR ("onewire plugin: strdup failed.");
103       return (1);
104     }
105     sfree (device_g);
106     device_g = temp;
107   }
108   else if (strcasecmp (key, "Alias") == 0)
109   {
110     /* azogtodo alias-list */
111   }
112   else
113   {
114     return (-1);
115   }
116
117   return (0);
118 }
119
120 static int cow_init (void)
121 {
122   int status;
123
124   if (device_g == NULL)
125   {
126     ERROR ("onewire plugin: cow_init: No device configured.");
127     return (-1);
128   }
129
130   status = (int) OW_init (device_g);
131   if (status != 0)
132   {
133     ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status);
134     return (1);
135   }
136
137   return (0);
138 } /* int cow_init */
139
140 static int cow_read_values (const char *path, const char *name,
141     const ow_family_features_t *family_info)
142 {
143   value_t values[1];
144   value_list_t vl = VALUE_LIST_INIT;
145   int success = 0;
146   size_t i;
147
148   if (sensor_list != NULL)
149   {
150     DEBUG ("onewire plugin: Checking ignorelist for `%s'", name);
151     if (ignorelist_match (sensor_list, name) != 0)
152       return 0;
153   }
154
155   vl.values = values;
156   vl.values_len = 1;
157   vl.time = time (NULL);
158
159   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
160   sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin));
161   sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance));
162
163   for (i = 0; i < family_info->features_num; i++)
164   {
165     char *buffer;
166     size_t buffer_size;
167     int status;
168
169     char file[4096];
170     char *endptr;
171
172     snprintf (file, sizeof (file), "%s/%s",
173         path, family_info->features[i].filename);
174     file[sizeof (file) - 1] = 0;
175
176     buffer = NULL;
177     buffer_size = 0;
178     status = OW_get (file, &buffer, &buffer_size);
179     if (status < 0)
180     {
181       ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;",
182           path, family_info->features[i].filename, status);
183       return (-1);
184     }
185
186     endptr = NULL;
187     values[0].gauge = strtod (buffer, &endptr);
188     if (endptr == NULL)
189     {
190       ERROR ("onewire plugin: Buffer is not a number: %s", buffer);
191       status = -1;
192       continue;
193     }
194
195     sstrncpy (vl.type, family_info->features[i].type, sizeof (vl.type));
196     sstrncpy (vl.type_instance, family_info->features[i].type_instance,
197         sizeof (vl.type_instance));
198
199     plugin_dispatch_values (&vl);
200     success++;
201
202     free (buffer);
203   } /* for (i = 0; i < features_num; i++) */
204
205   return ((success > 0) ? 0 : -1);
206 } /* int cow_read_values */
207
208 /* Forward declaration so the recursion below works */
209 static int cow_read_bus (const char *path);
210
211 /*
212  * cow_read_ds2409
213  *
214  * Handles:
215  * - DS2409 - MicroLAN Coupler
216  */
217 static int cow_read_ds2409 (const char *path)
218 {
219   char subpath[4096];
220   int status;
221
222   status = ssnprintf (subpath, sizeof (subpath), "%s/main", path);
223   if ((status > 0) && (status < sizeof (subpath)))
224     cow_read_bus (subpath);
225
226   status = ssnprintf (subpath, sizeof (subpath), "%s/aux", path);
227   if ((status > 0) && (status < sizeof (subpath)))
228     cow_read_bus (subpath);
229
230   return (0);
231 } /* int cow_read_ds2409 */
232
233 static int cow_read_bus (const char *path)
234 {
235   char *buffer;
236   size_t buffer_size;
237   int status;
238
239   char *buffer_ptr;
240   char *dummy;
241   char *saveptr;
242   char subpath[4096];
243
244   status = OW_get (path, &buffer, &buffer_size);
245   if (status < 0)
246   {
247     ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
248         path, status);
249     return (-1);
250   }
251   DEBUG ("onewire plugin: OW_get (%s) returned: %s",
252       path, buffer);
253
254   dummy = buffer;
255   saveptr = NULL;
256   while ((buffer_ptr = strtok_r (dummy, ",/", &saveptr)) != NULL)
257   {
258     int i;
259
260     dummy = NULL;
261
262     if (strcmp ("/", path) == 0)
263       status = ssnprintf (subpath, sizeof (subpath), "/%s", buffer_ptr);
264     else
265       status = ssnprintf (subpath, sizeof (subpath), "%s/%s",
266           path, buffer_ptr);
267     if ((status <= 0) || (status >= sizeof (subpath)))
268       continue;
269
270     for (i = 0; i < ow_family_features_num; i++)
271     {
272       if (strncmp (ow_family_features[i].family, buffer_ptr,
273             strlen (ow_family_features[i].family)) != 0)
274         continue;
275
276       cow_read_values (subpath,
277           buffer_ptr + strlen (ow_family_features[i].family),
278           ow_family_features + i);
279       break;
280     }
281     if (i < ow_family_features_num)
282       continue;
283
284     /* DS2409 */
285     if (strncmp ("1F.", buffer_ptr, strlen ("1F.")) == 0)
286     {
287       cow_read_ds2409 (subpath);
288       continue;
289     }
290   } /* while (strtok_r) */
291
292   free (buffer);
293   return (0);
294 } /* int cow_read_bus */
295
296 static int cow_read (void)
297 {
298   return (cow_read_bus ("/"));
299 } /* int cow_read */
300
301 static int cow_shutdown (void)
302 {
303   OW_finish ();
304   ignorelist_free (sensor_list);
305   return (0);
306 } /* int cow_shutdown */
307
308 void module_register (void)
309 {
310   plugin_register_init ("onewire", cow_init);
311   plugin_register_read ("onewire", cow_read);
312   plugin_register_shutdown ("onewire", cow_shutdown);
313   plugin_register_config ("onewire", cow_load_config,
314     config_keys, config_keys_num);
315 }
316
317 /* vim: set sw=2 sts=2 ts=8 et fdm=marker cindent : */