4 * a simple program to connect to a gpsd daemon and dump the received data
7 * This will dump the raw NMEA from gpsd to stdout
10 * This will dump the super-raw data (gps binary) from gpsd to stdout
13 * This will dump the GPSD sentences from gpsd to stdout
16 * This will dump the GPSD and the NMEA sentences from gpsd to stdout
19 * Original code by: Gary E. Miller <gem@rellim.com>. Cleanup by ESR.
21 * This file is Copyright (c) 2010 by the GPSD project
22 * BSD terms apply: see the file COPYING in the distribution root for details.
28 #include "gpsd_config.h"
29 #include <sys/types.h>
33 #include <sys/socket.h>
34 #endif /* HAVE_SYS_SOCKET_H */
36 #endif /* S_SPLINT_S */
44 #endif /* HAVE_TERMIOS */
47 #include "gpsdclient.h"
50 static struct gps_data_t gpsdata;
51 static void spinner(unsigned int, unsigned int);
53 /* NMEA-0183 standard baud rate */
54 #define BAUDRATE B4800
56 /* Serial port variables */
57 static struct termios oldtio, newtio;
58 static int fd_out = 1; /* output initially goes to standard output */
59 static char serbuf[255];
62 static void daemonize(void)
68 /* Run as my child. */
71 exit(1); /* fork error */
73 exit(0); /* parent exits */
75 /* Obtain a new process group. */
78 /* Close all open descriptors. */
79 for (i = getdtablesize(); i >= 0; --i)
82 /* Reopen STDIN, STDOUT, STDERR to /dev/null. */
83 i = open("/dev/null", O_RDWR); /* STDIN */
85 assert(dup(i) != -1); /* STDOUT */
86 assert(dup(i) != -1); /* STDERR */
91 /* Run from a known spot. */
92 assert(chdir("/") != -1);
96 (void)signal(SIGCHLD, SIG_IGN);
98 /* Ignore tty signals */
99 (void)signal(SIGTSTP, SIG_IGN);
100 (void)signal(SIGTTOU, SIG_IGN);
101 (void)signal(SIGTTIN, SIG_IGN);
104 static void open_serial(char *device)
105 /* open the serial port and set it up */
108 * Open modem device for reading and writing and not as controlling
111 if ((fd_out = open(device, O_RDWR | O_NOCTTY)) == -1) {
112 fprintf(stderr, "gpspipe: error opening serial port\n");
116 /* Save current serial port settings for later */
117 if (tcgetattr(fd_out, &oldtio) != 0) {
118 fprintf(stderr, "gpspipe: error reading serial port settings\n");
122 /* Clear struct for new port settings. */
123 /*@i@*/ bzero(&newtio, sizeof(newtio));
126 (void)cfmakeraw(&newtio);
128 /*@i@*/ (void)cfsetospeed(&newtio, BAUDRATE);
130 /* Clear the modem line and activate the settings for the port. */
131 (void)tcflush(fd_out, TCIFLUSH);
132 if (tcsetattr(fd_out, TCSANOW, &newtio) != 0) {
133 (void)fprintf(stderr, "gpspipe: error configuring serial port\n");
138 static void usage(void)
140 (void)fprintf(stderr,
141 "Usage: gpspipe [OPTIONS] [server[:port[:device]]]\n\n"
142 "-d Run as a daemon.\n" "-f [file] Write output to file.\n"
143 "-h Show this help.\n" "-r Dump raw NMEA.\n"
144 "-R Dump super-raw mode (GPS binary).\n"
145 "-w Dump gpsd native data.\n"
146 "-l Sleep for ten seconds before connecting to gpsd.\n"
147 "-t Time stamp the data.\n"
148 "-T [format] set the timestamp format (strftime(3)-like; implies '-t')\n"
149 "-s [serial dev] emulate a 4800bps NMEA GPS on serial port (use with '-r').\n"
150 "-n [count] exit after count packets.\n"
151 "-v Print a little spinner.\n"
152 "-V Print version and exit.\n\n"
153 "You must specify one, or both, of -r/-w.\n"
154 "You must use -f if you use -d.\n");
158 int main(int argc, char **argv)
161 bool timestamp = false;
167 bool new_line = true;
172 unsigned int vflag = 0, l = 0;
176 struct fixsource_t source;
177 char *serialport = NULL;
178 char *outfile = NULL;
181 flags = WATCH_ENABLE;
182 while ((option = getopt(argc, argv, "?dD:lhrRwtT:vVn:s:o:")) != -1) {
185 debug = atoi(optarg);
186 #ifdef CLIENTDEBUG_ENABLE
187 gps_enable_debug(debug, stderr);
188 #endif /* CLIENTDEBUG_ENABLE */
191 count = strtol(optarg, 0, 0);
196 * Yes, -r invokes NMEA mode rather than proper raw mode.
197 * This emulates the behavior under the old protocol.
226 (void)fprintf(stderr, "%s: %s (revision %s)\n",
227 argv[0], VERSION, REVISION);
244 /* Grok the server, port, and device. */
246 gpsd_source_spec(argv[optind], &source);
248 gpsd_source_spec(NULL, &source);
250 if (serialport != NULL && !raw) {
251 (void)fprintf(stderr, "gpspipe: use of '-s' requires '-r'.\n");
255 if (outfile == NULL && daemon) {
256 (void)fprintf(stderr, "gpspipe: use of '-d' requires '-f'.\n");
260 if (!raw && !watch && !binary) {
261 (void)fprintf(stderr,
262 "gpspipe: one of '-R', '-r' or '-w' is required.\n");
266 /* Daemonize if the user requested it. */
270 /* Sleep for ten seconds if the user requested it. */
274 /* Open the output file if the user requested it. If the user
275 * requested '-R', we use the 'b' flag in fopen() to "do the right
276 * thing" in non-linux/unix OSes. */
277 if (outfile == NULL) {
281 fp = fopen(outfile, "wb");
283 fp = fopen(outfile, "w");
286 (void)fprintf(stderr,
287 "gpspipe: unable to open output file: %s\n",
293 /* Open the serial port and set it up. */
295 open_serial(serialport);
297 /*@ -nullpass -onlytrans @*/
298 if (gps_open_r(source.server, source.port, &gpsdata) != 0) {
299 (void)fprintf(stderr,
300 "gpspipe: could not connect to gpsd %s:%s, %s(%d)\n",
301 source.server, source.port, strerror(errno), errno);
304 /*@ +nullpass +onlytrans @*/
306 if (source.device != NULL)
307 flags |= WATCH_DEVICE;
308 (void)gps_stream(&gpsdata, flags, source.device);
310 if ((isatty(STDERR_FILENO) == 0) || daemon)
321 /* reading directly from the socket avoids decode overhead */
322 readbytes = (int)read(gpsdata.gps_fd, buf, sizeof(buf));
324 for (i = 0; i < readbytes; i++) {
326 if (j < (int)(sizeof(serbuf) - 1)) {
327 serbuf[j++] = buf[i];
329 if (new_line && timestamp) {
330 time_t now = time(NULL);
332 struct tm *tmp_now = localtime(&now);
333 (void)strftime(tmstr, sizeof(tmstr), format, tmp_now);
335 if (fprintf(fp, "%.24s :", tmstr) <= 0) {
336 (void)fprintf(stderr,
337 "gpspipe: write error, %s(%d)\n",
338 strerror(errno), errno);
342 if (fputc(c, fp) == EOF) {
343 fprintf(stderr, "gpspipe: Write Error, %s(%d)\n",
344 strerror(errno), errno);
349 if (serialport != NULL) {
350 if (write(fd_out, serbuf, (size_t) j) == -1) {
352 "gpspipe: Serial port write Error, %s(%d)\n",
353 strerror(errno), errno);
360 /* flush after every good line */
362 (void)fprintf(stderr,
363 "gpspipe: fflush Error, %s(%d)\n",
364 strerror(errno), errno);
369 /* completed count */
376 if (readbytes == -1) {
377 (void)fprintf(stderr, "gpspipe: read error %s(%d)\n",
378 strerror(errno), errno);
387 if (serialport != NULL) {
388 /* Restore the old serial port settings. */
389 if (tcsetattr(fd_out, TCSANOW, &oldtio) != 0) {
390 (void)fprintf(stderr, "Error restoring serial port settings\n");
394 #endif /* __UNUSED__ */
401 static void spinner(unsigned int v, unsigned int num)
403 char *spin = "|/-\\";
405 (void)fprintf(stderr, "\010%c", spin[(num / (1 << (v - 1))) % 4]);
406 (void)fflush(stderr);