2 * This file is Copyright (c) 2010 by the GPSD project
3 * BSD terms apply: see the file COPYING in the distribution root for details.
6 #include "gpsd_config.h"
12 #endif /* HAVE_SYSLOG_H */
20 #endif /* S_SPLINT_S */
22 #include "gpsdclient.h"
26 extern struct tm *gmtime_r(const time_t *, /*@out@*/ struct tm *tp);
27 #endif /* S_SPLINT_S */
29 /**************************************************************************
31 * Transport-layer-independent functions
33 **************************************************************************/
35 static char *author = "Amaury Jacquot, Chris Kuethe";
36 static char *license = "BSD";
37 static char *progname;
39 static time_t int_time, old_int_time;
40 static bool intrack = false;
41 static bool first = true;
42 static time_t timeout = 5; /* seconds */
43 #ifdef CLIENTDEBUG_ENABLE
45 #endif /* CLIENTDEBUG_ENABLE */
47 static void print_gpx_header(void)
49 (void)printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
50 (void)printf("<gpx version=\"1.1\" creator=\"navsys logger\"\n");
53 (" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
54 (void)printf(" xmlns=\"http://www.topografix.com/GPX/1.1\"\n");
57 (" xsi:schemaLocation=\"http://www.topografix.com/GPS/1/1\n");
58 (void)printf(" http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
59 (void)printf(" <metadata>\n");
60 (void)printf(" <name>NavSys GPS logger dump</name>\n");
61 (void)printf(" <author>%s</author>\n", author);
62 (void)printf(" <copyright>%s</copyright>\n", license);
63 (void)printf(" </metadata>\n");
67 static void print_gpx_trk_end(void)
69 (void)printf(" </trkseg>\n");
70 (void)printf(" </trk>\n");
74 static void print_gpx_footer(void)
78 (void)printf("</gpx>\n");
82 static void print_gpx_trk_start(void)
84 (void)printf(" <trk>\n");
85 (void)printf(" <trkseg>\n");
89 static void print_fix(struct gps_fix_t *fix, struct tm *time)
91 (void)printf(" <trkpt lat=\"%f\" lon=\"%f\">\n",
92 fix->latitude, fix->longitude);
93 (void)printf(" <ele>%f</ele>\n", fix->altitude);
94 (void)printf(" <time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\n",
95 time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
96 time->tm_hour, time->tm_min, time->tm_sec);
97 if (fix->mode == MODE_NO_FIX)
98 (void)fprintf(stdout, " <fix>none</fix>\n");
100 (void)fprintf(stdout, " <fix>%dd</fix>\n", fix->mode);
103 * Can't print this more detailed report because in D-Bus mode
104 * we don't necessarily have access to some of the stuff in gsdata.
105 * Might mean some of this stuff should be promoted.
107 if ((gpsdata->status >= 2) && (gpsdata->fix.mode >= MODE_3D)) {
109 if (gpsdata->fix.mode == 4) { /* military pps */
110 (void)printf(" <fix>pps</fix>\n");
111 } else { /* civilian dgps or sbas */
112 (void)printf(" <fix>dgps</fix>\n");
114 } else { /* no dgps or pps */
115 if (gpsdata->fix.mode == MODE_3D) {
116 (void)printf(" <fix>3d</fix>\n");
117 } else if (gpsdata->fix.mode == MODE_2D) {
118 (void)printf(" <fix>2d</fix>\n");
119 } else if (gpsdata->fix.mode == MODE_NOFIX) {
120 (void)printf(" <fix>none</fix>\n");
121 } /* don't print anything if no fix indicator */
124 /* print # satellites used in fix, if reasonable to do so */
125 if (gpsdata->fix.mode >= MODE_2D) {
126 (void)printf(" <hdop>%.1f</hdop>\n", gpsdata->hdop);
127 (void)printf(" <sat>%d</sat>\n", gpsdata->satellites_used);
131 (void)printf(" </trkpt>\n");
132 (void)fflush(stdout);
135 static void conditionally_log_fix(struct gps_fix_t *gpsfix)
137 int_time = (time_t) floor(gpsfix->time);
138 if ((int_time != old_int_time) && gpsfix->mode >= MODE_2D) {
141 * Make new track if the jump in time is above
142 * timeout. Handle jumps both forward and
143 * backwards in time. The clock sometimes jumps
144 * backward when gpsd is submitting junk on the
148 if (fabs(int_time - old_int_time) > timeout && !first) {
155 print_gpx_trk_start();
161 old_int_time = int_time;
162 (void)gmtime_r(&(int_time), &time);
163 print_fix(gpsfix, &time);
167 static void quit_handler(int signum)
169 /* don't clutter the logs on Ctrl-C */
170 if (signum != SIGINT)
171 syslog(LOG_INFO, "exiting, signal %d received", signum);
176 static struct gps_fix_t gpsfix;
179 /**************************************************************************
181 * Doing it with D-Bus
183 **************************************************************************/
186 #include <dbus/dbus.h>
187 #include <dbus/dbus-glib-lowlevel.h>
188 #include <dbus/dbus-glib.h>
190 #include <glib/gprintf.h>
192 #define EMIX(x, y) (((x) > (y)) ? (x) : (y))
194 DBusConnection *connection;
196 static char gpsd_devname[BUFSIZ];
198 static DBusHandlerResult handle_gps_fix(DBusMessage * message)
201 /* this packet format was designed before we split eph */
202 double eph = EMIX(gpsfix.epx, gpsfix.epy);
204 dbus_error_init(&error);
206 dbus_message_get_args(message,
208 DBUS_TYPE_DOUBLE, &gpsfix.time,
209 DBUS_TYPE_INT32, &gpsfix.mode,
210 DBUS_TYPE_DOUBLE, &gpsfix.ept,
211 DBUS_TYPE_DOUBLE, &gpsfix.latitude,
212 DBUS_TYPE_DOUBLE, &gpsfix.longitude,
213 DBUS_TYPE_DOUBLE, &eph,
214 DBUS_TYPE_DOUBLE, &gpsfix.altitude,
215 DBUS_TYPE_DOUBLE, &gpsfix.epv,
216 DBUS_TYPE_DOUBLE, &gpsfix.track,
217 DBUS_TYPE_DOUBLE, &gpsfix.epd,
218 DBUS_TYPE_DOUBLE, &gpsfix.speed,
219 DBUS_TYPE_DOUBLE, &gpsfix.eps,
220 DBUS_TYPE_DOUBLE, &gpsfix.climb,
221 DBUS_TYPE_DOUBLE, &gpsfix.epc,
222 DBUS_TYPE_STRING, &gpsd_devname, DBUS_TYPE_INVALID);
224 conditionally_log_fix(&gpsfix);
225 return DBUS_HANDLER_RESULT_HANDLED;
229 * Message dispatching function
232 static DBusHandlerResult signal_handler(DBusConnection * connection,
233 DBusMessage * message)
235 /* dummy, need to use the variable for some reason */
238 if (dbus_message_is_signal(message, "org.gpsd", "fix"))
239 return handle_gps_fix(message);
241 * ignore all other messages
244 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
247 static int dbus_mainloop(void)
252 mainloop = g_main_loop_new(NULL, FALSE);
254 dbus_error_init(&error);
255 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
256 if (dbus_error_is_set(&error)) {
257 syslog(LOG_CRIT, "%s: %s", error.name, error.message);
261 dbus_bus_add_match(connection, "type='signal'", &error);
262 if (dbus_error_is_set(&error)) {
263 syslog(LOG_CRIT, "unable to add match for signals %s: %s", error.name,
268 if (!dbus_connection_add_filter
269 (connection, (DBusHandleMessageFunction) signal_handler, NULL,
271 syslog(LOG_CRIT, "unable to register filter with the connection");
275 dbus_connection_setup_with_g_main(connection, NULL);
277 g_main_loop_run(mainloop);
281 #endif /* DBUS_ENABLE */
283 /**************************************************************************
285 * Doing it with sockets
287 **************************************************************************/
289 static struct fixsource_t source;
291 static void process(struct gps_data_t *gpsdata,
292 char *buf UNUSED, size_t len UNUSED)
294 /* this is where we implement source-device filtering */
295 if (gpsdata->dev.path[0] != '\0' && source.device != NULL
296 && strcmp(source.device, gpsdata->dev.path) != 0)
299 conditionally_log_fix(&gpsdata->fix);
302 /*@-mustfreefresh -compdestroy@*/
303 static int socket_mainloop(void)
306 struct gps_data_t gpsdata;
308 if (gps_open_r(source.server, source.port, &gpsdata) != 0) {
309 (void)fprintf(stderr,
310 "%s: no gpsd running or network error: %d, %s\n",
311 progname, errno, gps_errstr(errno));
315 gps_set_raw_hook(&gpsdata, process);
316 (void)gps_stream(&gpsdata, WATCH_ENABLE, NULL);
323 FD_SET(gpsdata.gps_fd, &fds);
327 data = select(gpsdata.gps_fd + 1, &fds, NULL, NULL, &tv);
330 (void)fprintf(stderr, "%s\n", strerror(errno));
333 (void)gps_read(&gpsdata);
335 (void)gps_close(&gpsdata);
338 /*@+mustfreefresh +compdestroy@*/
340 /**************************************************************************
344 **************************************************************************/
346 static void usage(void)
349 "Usage: %s [-V] [-h] [-i timeout] [-j casoc] [server[:port:[device]]]\n",
352 "\tdefaults to '%s -i 5 -j 0 localhost:2947'\n", progname);
356 int main(int argc, char **argv)
361 while ((ch = getopt(argc, argv, "D:hi:V")) != -1) {
363 #ifdef CLIENTDEBUG_ENABLE
365 debug = atoi(optarg);
366 gps_enable_debug(debug, stdout);
368 #endif /* CLIENTDEBUG_ENABLE */
369 case 'i': /* set polling interfal */
370 timeout = (time_t) atoi(optarg);
375 "WARNING: track timeout is an hour or more!\n");
378 (void)fprintf(stderr, "gpxlogger revision " REVISION "\n");
387 gpsd_source_spec(argv[optind], &source);
389 gpsd_source_spec(NULL, &source);
391 (void)printf("<!-- server: %s port: %s device: %s -->\n",
392 source.server, source.port, source.device);
395 /* initializes the gpsfix data structure */
396 gps_clear_fix(&gpsfix);
398 /* catch all interesting signals */
399 (void)signal(SIGTERM, quit_handler);
400 (void)signal(SIGQUIT, quit_handler);
401 (void)signal(SIGINT, quit_handler);
403 //openlog ("gpxlogger", LOG_PID | LOG_NDELAY , LOG_DAEMON);
404 //syslog (LOG_INFO, "---------- STARTED ----------");
409 /* To force socket use in the default way just give a 'localhost' arg */
411 return socket_mainloop();
413 return dbus_mainloop();
415 return socket_mainloop();