3 * Copyright (C) 2015 Nicolas JOURDEN
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Nicolas JOURDEN <nicolas.jourden at laposte.net>
34 #define GPS_DEFAULT_HOST "localhost"
35 #define GPS_DEFAULT_PORT "2947"
36 #define GPS_DEFAULT_TIMEOUT 15
37 #define GPS_DEFAULT_PAUSE 1
56 static gps_definition_t gps_data_config;
64 static gpsdata_t gps_data_read;
67 static const char *config_keys[] =
74 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
78 static pthread_t connector = (pthread_t) 0;
79 static pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER;
83 * Thread reading from gpsd.
85 static void * gps_collectd_thread (void * pData)
87 struct gps_data_t gps_data;
91 if (gps_open(gps_data_config.host, gps_data_config.port, &gps_data) < 0)
93 WARNING ("gps: cannot connect to: %s:%s", gps_data_config.host, gps_data_config.port);
98 gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON | WATCH_NEWSTYLE, NULL);
99 gps_send(&gps_data, "?WATCH={\"enable\":true,\"json\":true,\"nmea\":false}\r\n");
103 if (gps_waiting (&gps_data, gps_data_config.timeout ) )
105 DEBUG ("gps: reading\n");
107 if (gps_read (&gps_data) == -1)
109 WARNING ("gps: incorrect data !\n");
112 pthread_mutex_lock (&data_mutex);
113 DEBUG ("gps: parsing\n");
116 if (isnan(gps_data.dop.vdop) == 0)
118 DEBUG ("gps: isnan(gps_data.dop.vdop) == 0 [OK]\n");
119 gps_data_read.vdop = gps_data.dop.vdop;
121 if (isnan(gps_data.dop.hdop) == 0)
123 DEBUG ("gps: isnan(gps_data.dop.hdop) == 0 [OK]\n");
124 gps_data_read.hdop = gps_data.dop.hdop;
128 if ((gps_data.set & LATLON_SET))
130 DEBUG ("gps: gps_data.set & LATLON_SET [OK] ... \n");
131 gps_data_read.satellites = gps_data.satellites_used;
134 DEBUG ("gps: raw is hdop=%1.3f, vdop=%1.3f, sat-used=%02d, lat=%02.05f, lon=%03.05f\n",
137 gps_data.satellites_used,
138 gps_data.fix.latitude,
139 gps_data.fix.longitude
142 pthread_mutex_unlock (&data_mutex);
143 sleep(gps_data_config.pause);
149 gps_stream(&gps_data, WATCH_DISABLE, NULL);
150 gps_close(&gps_data);
152 pthread_exit ((void *)0);
157 * Submit a piece of the data.
159 static void gps_collectd_submit (const char *type, gauge_t value, const char *type_instance)
162 value_list_t vl = VALUE_LIST_INIT;
164 values[0].gauge = value;
168 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
169 sstrncpy (vl.plugin, "gps", sizeof (vl.plugin));
170 sstrncpy (vl.type, type, sizeof (vl.type));
171 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
173 plugin_dispatch_values (&vl);
178 * Read the data and submit by piece.
180 static int gps_collectd_read ()
182 pthread_mutex_lock (&data_mutex);
183 gps_collectd_submit("dilution_of_precision", (gauge_t) gps_data_read.hdop, "horizontal");
184 gps_collectd_submit("dilution_of_precision", (gauge_t) gps_data_read.vdop, "vertical");
185 gps_collectd_submit("satellites", (gauge_t) gps_data_read.satellites, "gps");
186 DEBUG ("gps: hdop=%1.3f, vdop=%1.3f, sat=%02d.\n",
189 gps_data_read.satellites
191 pthread_mutex_unlock (&data_mutex);
197 * Read configuration.
199 static int gps_collectd_config (const char *key, const char *value)
203 if (strcasecmp (key, "Host") == 0)
205 if (gps_data_config.host != NULL)
207 free (gps_data_config.host);
209 gps_data_config.host = sstrdup (value);
211 if (strcasecmp (key, "Port") == 0)
213 if (gps_data_config.port != NULL)
215 free (gps_data_config.port);
217 gps_data_config.port = sstrdup (value);
219 if (strcasecmp (key, "Timeout") == 0)
221 gps_data_config.timeout = (int) ( strtod(value, &endptr) * 1000 );
222 DEBUG ("gps: will use pause %s - %d.\n", value, gps_data_config.timeout);
224 if (strcasecmp (key, "Pause") == 0)
226 gps_data_config.pause = (int) (strtod (value, &endptr));
227 DEBUG ("gps: will use pause %s - %d.\n", value, gps_data_config.pause);
236 static int gps_collectd_init (void)
240 DEBUG ("gps: will use %s:%s, timeout %d ms, pause %d sec.\n", gps_data_config.host, gps_data_config.port, gps_data_config.timeout, gps_data_config.pause);
242 err = plugin_thread_create (&connector, NULL, gps_collectd_thread, NULL);
246 ERROR ("gps: pthread_create() failed.");
257 static int gps_collectd_shutdown (void)
259 if (connector != ((pthread_t) 0))
261 pthread_kill (connector, SIGTERM);
262 connector = (pthread_t) 0;
265 sfree (gps_data_config.port);
266 sfree (gps_data_config.host);
272 * Register the module.
274 void module_register (void)
276 gps_data_config.host = sstrdup (GPS_DEFAULT_HOST);
277 gps_data_config.port = sstrdup (GPS_DEFAULT_PORT);
278 gps_data_config.timeout = GPS_DEFAULT_TIMEOUT;
279 gps_data_config.pause = GPS_DEFAULT_PAUSE;
280 gps_data_read.hdop = 0;
281 gps_data_read.vdop = 0;
282 gps_data_read.satellites = 0;
284 // Read the config params:
285 plugin_register_config ("gps", gps_collectd_config, config_keys, config_keys_num);
286 // Create the thread:
287 plugin_register_init ("gps", gps_collectd_init);
288 // Kill the thread and stop.
289 plugin_register_shutdown ("gps", gps_collectd_shutdown);
291 plugin_register_read ("gps", gps_collectd_read);