Merge branch 'GPSd'
[collectd.git] / src / gps.c
1 /**
2  * This plug-in helps to monitor the GPS connected to a system.
3  * It reads the data comming from GPSd.
4  It look for the following parameters.
5  */
6
7 #include "collectd.h"
8 #include "common.h"
9 #include "plugin.h"
10
11 #if HAVE_GPS_H
12 #include <gps.h>
13 #endif
14
15 #if HAVE_LIBPTHREAD
16 #include <pthread.h>
17 #endif
18
19 typedef struct
20 {
21   char *host;
22   char *port;
23   int timeout;
24 } gps_definition_t;
25 static gps_definition_t gps_data_config;
26
27 typedef struct {
28  int satellites;
29  double vdop;
30  double hdop;
31 } gpsDATA_t;
32 static gpsDATA_t gps_data_read;
33
34
35 static const char *config_keys[] =
36 {
37   "Host",
38   "Port",
39   "Timeout"
40 };
41 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
42
43
44 // Thread items:
45 static pthread_t connector = (pthread_t) 0;
46 static pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER;
47
48
49 /**
50  * Thread reading from GPSd.
51  */
52 static void * gps_collectd_thread (void * pData)
53 {
54   struct gps_data_t gps_data;
55
56   while (1)
57   {
58     if (gps_open(gps_data_config.host, gps_data_config.port, &gps_data) < 0)
59     {
60       printf ("cannot connect to: %s:%s", gps_data_config.host, gps_data_config.port);
61       sleep(60);
62       continue;
63     }
64
65     gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
66
67     while (1)
68     {
69       if (gps_waiting (&gps_data, gps_data_config.timeout))
70       {
71         if (gps_read (&gps_data) == -1)
72         {
73             WARNING ("incorrect data.\n");
74         } 
75         else {
76           pthread_mutex_lock (&data_mutex);
77
78           // Dop data:
79           if (isnan(gps_data.dop.vdop) == 0)
80           {
81             gps_data_read.vdop = gps_data.dop.vdop;
82           }
83           if (isnan(gps_data.dop.hdop) == 0)
84           {
85             gps_data_read.hdop = gps_data.dop.hdop;
86           }
87
88           // Sat in view:
89           if ((gps_data.set & LATLON_SET))
90           {
91             gps_data_read.satellites = gps_data.satellites_used;
92           }
93
94           pthread_mutex_unlock (&data_mutex);
95         }
96       }
97     }
98   }
99
100   gps_stream(&gps_data, WATCH_DISABLE, NULL);
101   gps_close(&gps_data);
102
103   pthread_exit ((void *)0);
104 }
105
106
107 /**
108  * Submit the data.
109  */
110 static void gps_collectd_submit (const char *type, gauge_t value)
111 {
112   value_t values[1];
113   value_list_t vl = VALUE_LIST_INIT;
114
115   values[0].gauge = value;
116
117   vl.values = values;
118   vl.values_len = 1;
119   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
120   sstrncpy (vl.plugin, "gps", sizeof (vl.plugin));
121   sstrncpy (vl.type, type, sizeof (vl.type));
122   sstrncpy (vl.type_instance, "gps", sizeof (vl.type_instance));
123
124   plugin_dispatch_values (&vl);
125 }
126
127
128 /**
129  * Read the data and submit.
130  */
131 static int gps_collectd_read ()
132 {
133   pthread_mutex_lock (&data_mutex);
134   gps_collectd_submit("gps_hdop", (gauge_t) gps_data_read.hdop);
135   gps_collectd_submit("gps_vdop", (gauge_t) gps_data_read.vdop);
136   gps_collectd_submit("gps_sat", (gauge_t) gps_data_read.satellites);
137   printf ("gps: hdop=%1.3f, vdop=%1.3f, sat=%02d.\n", 
138     gps_data_read.hdop,
139     gps_data_read.vdop,
140     gps_data_read.satellites
141   );
142   pthread_mutex_unlock (&data_mutex);
143   return (0);
144 }
145
146
147 /**
148  * Read configuration.
149  */
150 static int gps_collectd_config (const char *key, const char *value)
151 {
152   if (strcasecmp (key, "Host") == 0) {
153     if (gps_data_config.host != NULL) free (gps_data_config.host);
154       gps_data_config.host = sstrdup (value);
155   }
156   if (strcasecmp (key, "Port") == 0) {
157     if (gps_data_config.port != NULL) free (gps_data_config.port);
158       gps_data_config.port = sstrdup (value);
159   }
160   if (strcasecmp (key, "Timeout") == 0) {
161      gps_data_config.timeout = (int) strtol (value, NULL, 1000);
162   }
163   return (0);
164 }
165
166
167 /**
168  * Init.
169  */
170 static int gps_collectd_init (void)
171 {
172   int err = 0;
173
174   printf ("gps: will use %s:%s with timeout %d.\n", gps_data_config.host, gps_data_config.port, gps_data_config.timeout);
175
176   err = plugin_thread_create (&connector, NULL, gps_collectd_thread, NULL);
177
178   if (err != 0) {
179     WARNING ("pthread_create() failed.");
180     return (-1);
181   }
182
183   return (0);
184 }
185
186
187 /**
188  * Shutdown.
189  */
190 static int gps_collectd_shutdown (void)
191 {
192   if (connector != ((pthread_t) 0)) {
193     pthread_kill (connector, SIGTERM);
194     connector = (pthread_t) 0;
195   }
196
197   sfree (gps_data_config.port);
198   sfree (gps_data_config.host);
199
200   return (0);
201 }
202
203 /**
204  * Register the module.
205  */
206 void module_register (void)                                                                    
207 {
208   gps_data_config.host = sstrdup ("localhost");
209   gps_data_config.port = sstrdup ("2947");
210   gps_data_read.hdop = 0;
211   gps_data_read.vdop = 0;
212   gps_data_read.satellites = 0;
213
214   // Read the config params:
215   plugin_register_config ("gps", gps_collectd_config, config_keys, config_keys_num);
216   // Create the thread:
217   plugin_register_init ("gps", gps_collectd_init);
218   // Kill the thread and stop.
219   plugin_register_shutdown ("gps", gps_collectd_shutdown);
220   // Read plugin:
221   plugin_register_read ("gps", gps_collectd_read);
222 }
223