123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- #include "gpsd_config.h"
- #include <assert.h>
- #include <errno.h>
- #include <libgen.h>
- #include <math.h>
- #include <signal.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <unistd.h>
- #include "gps.h"
- #include "gpsdclient.h"
- #include "os_compat.h"
- #include "timespec.h"
- static char *progname;
- static struct fixsource_t source;
- static struct gps_data_t gpsdata;
- static FILE *logfile;
- static bool intrack = false;
- static time_t timeout = 5;
- static double minmove = 0;
- static int debug;
- static void print_gpx_header(void)
- {
- char tbuf[CLIENT_DATE_MAX+1];
- (void)fprintf(logfile, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
- (void)fprintf(logfile, "<gpx version=\"1.1\" creator=\"GPSD %s - %s\"\n",
- VERSION, GPSD_URL);
- (void)fprintf(logfile,
- " xmlns:xsi=\"https://www.w3.org/2001/XMLSchema-instance\"\n");
- (void)fprintf(logfile,
- " xmlns=\"http://www.topografix.com/GPX/1/1\"\n");
- (void)fprintf(logfile
- ," xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1\n");
- (void)fprintf(logfile
- ," http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
- (void)fprintf(logfile, " <metadata>\n");
- (void)fprintf(logfile, " <time>%s</time>\n",
- now_to_iso8601(tbuf, sizeof(tbuf)));
- (void)fprintf(logfile," </metadata>\n");
- (void)fflush(logfile);
- }
- static void print_gpx_trk_end(void)
- {
- (void)fprintf(logfile," </trkseg>\n");
- (void)fprintf(logfile," </trk>\n");
- (void)fflush(logfile);
- }
- static void print_gpx_footer(void)
- {
- if (intrack)
- print_gpx_trk_end();
- (void)fprintf(logfile,"</gpx>\n");
- (void)fclose(logfile);
- }
- static void print_gpx_trk_start(void)
- {
- (void)fprintf(logfile," <trk>\n");
- (void)fprintf(logfile," <src>GPSD %s</src>\n", VERSION);
- (void)fprintf(logfile," <trkseg>\n");
- (void)fflush(logfile);
- }
- static void print_fix(struct gps_data_t *gpsdata, timespec_t ts_time)
- {
- char tbuf[CLIENT_DATE_MAX+1];
-
- (void)fprintf(logfile," <trkpt lat=\"%f\" lon=\"%f\">\n",
- gpsdata->fix.latitude, gpsdata->fix.longitude);
- if ((isfinite(gpsdata->fix.altHAE) != 0))
- (void)fprintf(logfile," <ele>%f</ele>\n", gpsdata->fix.altHAE);
- (void)fprintf(logfile," <time>%s</time>\n",
- timespec_to_iso8601(ts_time, tbuf, sizeof(tbuf)));
- if (gpsdata->fix.status == STATUS_DGPS_FIX)
- (void)fprintf(logfile," <fix>dgps</fix>\n");
- else
- switch (gpsdata->fix.mode) {
- case MODE_3D:
- (void)fprintf(logfile," <fix>3d</fix>\n");
- break;
- case MODE_2D:
- (void)fprintf(logfile," <fix>2d</fix>\n");
- break;
- case MODE_NO_FIX:
- (void)fprintf(logfile," <fix>none</fix>\n");
- break;
- default:
-
- break;
- }
- if ((gpsdata->fix.mode > MODE_NO_FIX) && (gpsdata->satellites_used > 0))
- (void)fprintf(logfile," <sat>%d</sat>\n", gpsdata->satellites_used);
- if (isfinite(gpsdata->dop.hdop) != 0)
- (void)fprintf(logfile," <hdop>%.1f</hdop>\n", gpsdata->dop.hdop);
- if (isfinite(gpsdata->dop.vdop) != 0)
- (void)fprintf(logfile," <vdop>%.1f</vdop>\n", gpsdata->dop.vdop);
- if (isfinite(gpsdata->dop.pdop) != 0)
- (void)fprintf(logfile," <pdop>%.1f</pdop>\n", gpsdata->dop.pdop);
- (void)fprintf(logfile," </trkpt>\n");
- (void)fflush(logfile);
- }
- static void conditionally_log_fix(struct gps_data_t *gpsdata)
- {
- static timespec_t ts_time, old_ts_time, ts_diff;
- static double old_lat, old_lon;
- static bool first = true;
- ts_time = gpsdata->fix.time;
- if (TS_EQ(&ts_time, &old_ts_time) || gpsdata->fix.mode < MODE_2D)
- return;
-
- if (0 < minmove && !first && earth_distance(
- gpsdata->fix.latitude,
- gpsdata->fix.longitude,
- old_lat, old_lon) < minmove)
- return;
-
- TS_SUB(&ts_diff, &ts_time, &old_ts_time);
- if (labs((long)ts_diff.tv_sec) > timeout && !first) {
- print_gpx_trk_end();
- intrack = false;
- }
- if (!intrack) {
- print_gpx_trk_start();
- intrack = true;
- if (first)
- first = false;
- }
- old_ts_time = ts_time;
- if (0 < minmove) {
- old_lat = gpsdata->fix.latitude;
- old_lon = gpsdata->fix.longitude;
- }
- print_fix(gpsdata, ts_time);
- }
- static void quit_handler(int signum)
- {
-
- if (signum != SIGINT)
- syslog(LOG_INFO, "exiting, signal %d received", signum);
- print_gpx_footer();
- (void)gps_close(&gpsdata);
- exit(EXIT_SUCCESS);
- }
- static void usage(void)
- {
- (void)fprintf(stderr,
- "Usage: %s [-V] [-h] [-l] [-d] [-D debuglevel]"
- " [-i timeout] [-f filename] [-m minmove]\n"
- "\t[-r] [-e exportmethod] [server[:port:[device]]]\n\n"
- "defaults to '%s -i 5 -e %s localhost:2947'\n",
- progname, progname, export_default()->name);
- exit(EXIT_FAILURE);
- }
- int main(int argc, char **argv)
- {
- int ch;
- bool daemonize = false;
- bool reconnect = false;
- unsigned int flags = WATCH_ENABLE;
- struct exportmethod_t *method = NULL;
- progname = argv[0];
- method = export_default();
- if (method == NULL) {
- (void)fprintf(stderr, "%s: no export methods.\n", progname);
- exit(EXIT_FAILURE);
- }
- logfile = stdout;
- while ((ch = getopt(argc, argv, "dD:e:f:hi:lm:rV")) != -1) {
- switch (ch) {
- case 'd':
- openlog(basename(progname), LOG_PID | LOG_PERROR, LOG_DAEMON);
- daemonize = true;
- break;
- case 'D':
- debug = atoi(optarg);
- gps_enable_debug(debug, logfile);
- break;
- case 'e':
- method = export_lookup(optarg);
- if (method == NULL) {
- (void)fprintf(stderr,
- "%s: %s is not a known export method.\n",
- progname, optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'f':
- {
- char *fname = NULL;
- time_t t;
- size_t s = 0;
- size_t fnamesize = strlen(optarg) + 1;
- t = time(NULL);
- while (s == 0) {
- char *newfname = realloc(fname, fnamesize);
- if (newfname == NULL) {
- syslog(LOG_ERR, "realloc failed.");
- goto bailout;
- } else {
- fname = newfname;
- }
- s = strftime(fname, fnamesize-1, optarg, localtime(&t));
- if (!s) {
-
- fnamesize += 1024;
- }
- }
- fname[s] = '\0';;
- logfile = fopen(fname, "w");
- if (logfile == NULL) {
- syslog(LOG_ERR,
- "Failed to open %s: %s, logging to stdout.",
- fname, strerror(errno));
- logfile = stdout;
- }
- bailout:
- free(fname);
- break;
- }
- case 'i':
- timeout = (time_t) atoi(optarg);
- if (timeout < 1)
- timeout = 1;
- if (timeout >= 3600)
- (void)fprintf(stderr,
- "WARNING: track timeout is an hour or more!\n");
- break;
- case 'l':
- export_list(stderr);
- exit(EXIT_SUCCESS);
- case 'm':
- minmove = (double )atoi(optarg);
- break;
- case 'r':
- reconnect = true;
- break;
- case 'V':
- (void)fprintf(stderr, "%s: version %s (revision %s)\n",
- progname, VERSION, REVISION);
- exit(EXIT_SUCCESS);
- default:
- usage();
-
- }
- }
- if (daemonize && logfile == stdout) {
- syslog(LOG_ERR, "Daemon mode with no valid logfile name - exiting.");
- exit(EXIT_FAILURE);
- }
- if (method->magic != NULL) {
- source.server = (char *)method->magic;
- source.port = NULL;
- source.device = NULL;
- } else {
- source.server = (char *)"localhost";
- source.port = (char *)DEFAULT_GPSD_PORT;
- source.device = NULL;
- }
- if (optind < argc) {
-
- gpsd_source_spec(argv[optind], &source);
- }
- #if 0
- (void)fprintf(logfile,"<!-- server: %s port: %s device: %s -->\n",
- source.server, source.port, source.device);
- #endif
-
- (void)signal(SIGTERM, quit_handler);
- (void)signal(SIGQUIT, quit_handler);
- (void)signal(SIGINT, quit_handler);
-
- if (daemonize) {
-
- if (os_daemon(0, 0) != 0)
- (void) fprintf(stderr,"daemonization failed: %s\n", strerror(errno));
- }
-
- if (gps_open(source.server, source.port, &gpsdata) != 0) {
- (void)fprintf(stderr,
- "%s: no gpsd running or network error: %d, %s\n",
- progname, errno, gps_errstr(errno));
- exit(EXIT_FAILURE);
- }
- if (source.device != NULL)
- flags |= WATCH_DEVICE;
- (void)gps_stream(&gpsdata, flags, source.device);
- print_gpx_header();
- while (gps_mainloop(&gpsdata, timeout * 1000000, conditionally_log_fix) < 0 &&
- reconnect) {
-
- (void)sleep(timeout);
- syslog(LOG_INFO, "timeout; about to reconnect");
- }
- print_gpx_footer();
- (void)gps_close(&gpsdata);
- exit(EXIT_SUCCESS);
- }
|