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