/*
 * gpspipe
 *
 * a simple program to connect to a gpsd daemon and dump the received data
 * to stdout
 *
 * This will dump the raw NMEA from gpsd to stdout
 *      gpspipe -r
 *
 * This will dump the GPSD sentences from gpsd to stdout
 *      gpspipe -w
 *
 * This will dump the GPSD and the NMEA sentences from gpsd to stdout
 *      gpspipe -wr
 *
 * bad code by: Gary E. Miller <gem@rellim.com>
 * all rights given to the gpsd project to release under whatever open source
 * license they use.  A thank would be nice if you use this code.
 *
 * just needs to be linked to netlib like this:
 *	gcc gpspipe.c ../netlib.c -o gpspipe
 *
 *
  $Id: gpspipe.c 3185 2005-09-01 02:57:46Z esr $
 */

#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <fcntl.h>
#include <termios.h>
#include "gpsd.h"


/* NMEA-0183 standard baud rate */
#define BAUDRATE B4800

/* POSIX compliant source */
#define _POSIX_SOURCE 1

/* Serial port vars */
static struct termios oldtio,newtio;
static int fd;
#define SERBUF 255
static char serbuf[SERBUF];

/* open the serial port and set it up */
static int open_serial(char* device) {

	/*  Open modem device for reading and writing and not as controlling
	 *  tty. */
	if((fd = open(device, O_RDWR|O_NOCTTY)) < 0) {
		fprintf(stderr,"Error opening serial port\n");
		exit(1);
	}

	/* Save current serial port settings for later */
	if ( tcgetattr(fd, &oldtio) != 0 ) {
		fprintf(stderr,"Error reading serial port settings\n");
		exit(1);
	}

	/* Clear struct for new port settings. */
	/*@i@*/bzero(&newtio, sizeof(newtio));

	/* make it raw */
	(void)cfmakeraw(&newtio);
	/* set speed */
	/*@i@*/(void)cfsetospeed(&newtio, BAUDRATE);
	 
	/* Clear the modem line and activate the settings for the port. */
	(void)tcflush(fd,TCIFLUSH);
	if ( tcsetattr(fd,TCSANOW,&newtio) != 0 ) {
		(void)fprintf(stderr,"Error setting serial port settings\n");
		exit(1);
	}

	return(fd);
}


/* Send a string to the serial port. */
static int send_string(char *buf, size_t len) {

	/* Send the string and  Return the result. */
	return ((int)write(fd, buf, len ) );
}


static void usage(void) {
	fprintf(stderr, "Usage: gpspipe [OPTIONS] [server[:port]]\n\n"
	        "SVN ID: $Id: gpspipe.c 3185 2005-09-01 02:57:46Z esr $ \n"
		"-h show this help\n"
		"-r Dump raw NMEA\n"
	        "-w Dump gpsd native data\n"
	        "-t time stamp the data\n"
		"-s [serial dev] emulate a 4800bps NMEA GPS on serial port (use with '-r')\n"
	        "-n [count] exit after count packets\n"
	        "-V print version and exit\n\n"
	        "You must specify one, or both, of -r/-w\n"
		);
}

int main( int argc, char **argv) {

	int s = 0;
        char buf[4096];
	char *cstr = NULL;
        ssize_t wrote = 0;
        bool dump_nmea = false;
        bool dump_gpsd = false;
        bool timestamp = false;
	bool new_line = true;
	long count = -1;
	int option;
        char *arg = NULL, *colon1, *colon2, *device = NULL; 
        char *port = DEFAULT_GPSD_PORT, *server = "127.0.0.1";
	//extern char *optarg;

	char *serialport = NULL;

	while ((option = getopt(argc, argv, "?hrwtVn:s:")) != -1) {
		switch (option) {
		case 'n':
			count = strtol(optarg, 0, 0);
			break;
		case 'r':
			dump_nmea = true;
			break;
		case 't':
			timestamp = true;
			break;
		case 'w':
			dump_gpsd = true;
			break;
		case 'V':
	                (void)fprintf(stderr, "%s: SVN ID: $Id: gpspipe.c 3185 2005-09-01 02:57:46Z esr $ \n", argv[0]);
			exit(0);
		case 's':
		        serialport = optarg;
		        break;
		case '?':
		case 'h':
		default:
			usage( );
			exit(1);
		}
	}

	if( serialport != NULL && !dump_nmea ) {
	  fprintf(stderr,"Use of '-s' requires '-r'\n");
	  exit(1);
	}

	if ( dump_nmea ) {
		if ( dump_gpsd ) {
			cstr = "rw\n";
		} else {
			cstr = "r\n";
		}
	} else if ( dump_gpsd ) {
		cstr = "w\n";
	} else {
		usage( );
		exit(1);
	}
	/* Grok the server, port, and device. */
	/*@ -branchstate @*/
	if (optind < argc) {
		arg = strdup(argv[optind]);
		/*@i@*/colon1 = strchr(arg, ':');
		server = arg;
		if (colon1 != NULL) {
			if (colon1 == arg) {
				server = NULL;
			} else {
				*colon1 = '\0';
			}
			port = colon1 + 1;
			colon2 = strchr(port, ':');
			if (colon2 != NULL) {
				if (colon2 == port) {
					port = NULL;
				} else {
					*colon2 = '\0';
				}
				device = colon2 + 1;
			}
		}
		colon1 = colon2 = NULL;
	}
	/*@ +branchstate @*/

	/* Open the serial port and set it up. */
	if(serialport) {
	    (int)open_serial(serialport);
	}

	/*@ -nullpass @*/
	s = netlib_connectsock( server, port, "tcp");
	if ( s < 0 ) {
		fprintf( stderr, "%s: could not connect to gpsd %s:%s, %s(%d)\n"
			, argv[0] , server, port, strerror(errno), errno);
		exit (1);
	}
	/*@ +nullpass @*/

	wrote = write( s, cstr, strlen(cstr) );
	if ( (ssize_t)strlen(cstr) != wrote ) {
		fprintf( stderr, "%s: write error, %s(%d)\n", argv[0]
			, strerror(errno), errno);
		exit (1);
	}

	for(;;) {
		int i = 0;
		int j = 0;
		int readbytes = 0;

		readbytes = (int)read( s, buf, sizeof(buf));
		if ( readbytes > 0 ) {
		    for ( i = 0 ; i < readbytes ; i++ ) {
			char c = buf[i];
			if( j < (SERBUF - 1) ) {
				serbuf[j++] = buf[i];
			}
			if ( new_line && timestamp ) {
				time_t now = time(NULL);

				new_line = 0;
				if ( 0 > fprintf( stdout, "%.24s :",
					 ctime( &now )) ) {
					fprintf( stderr
						, "%s: Write Error, %s(%d)\n"
						, argv[0]
						, strerror(errno), errno);
					exit (1);
				}
			}
			if ( EOF == fputc( c, stdout) ) {
				fprintf( stderr, "%s: Write Error, %s(%d)\n"
					, argv[0]
					, strerror(errno), errno);
				exit (1);
			}

		
			if ( c == '\n' ) {

			    if( serialport != NULL) {
			      if ( -1 == send_string( serbuf, (size_t)j )) {
			        fprintf( stderr, "%s: Serial port write Error, %s(%d)\n"
				       , argv[0]
				       , strerror(errno), errno);
			        exit (1);
			      }
			      j = 0;
			    }

			    new_line = true;
			    /* flush after every good line */
			    if (  fflush( stdout ) ) {
				fprintf( stderr, "%s: fflush Error, %s(%d)\n"
					, argv[0]
					, strerror(errno), errno);
				exit (1);
			    }
			    if ( 0 <= count ) {
			        if ( 0 >= --count ) {
				    /* completed count */
			            exit(0);
			        }
			    }
			       
			}
		    }
		} else if ( readbytes < 0 ) {
			fprintf( stderr, "%s: Read Error %s(%d)\n", argv[0]
				, strerror(errno), errno);
		
			exit(1);
		}
	}

#ifdef __UNUSED__
	if( serialport != NULL ) {
		/* Restore the old serial port settings. */
		if ( tcsetattr(fd, TCSANOW, &oldtio) != 0 ) {
			fprintf(stderr, "Error restoring serial port settings\n");
			exit(1);
		}
	}

	exit(0);
#endif /* __UNUSED__ */  
}


syntax highlighted by Code2HTML, v. 0.9.1