/*
 * THIS SOFTWARE IS CREATED AS A CONTRIBUTION TO David Hulton's DSTUMBLER
 * SYSTEM; ALL RELATED RIGHTS AND LICENSES APPLY. EVERYTHING IS A TOTAL     
 * RIPOFF, EXCEPT THE PARSING CODE, AND IT WILL ONLY WORK WITH DSTUMBLER
 */

#include "config.h"

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#include <sys/termios.h>

#include "dstumbler.h"
#include "screen.h"

struct termios ttyset;

/*
 * open gps device for reading.. provide a fd and also fh for use with fgets
 */
int
gps_open(const char *device)
{
  int fd;

  if((fd = open(device, O_RDWR | O_SYNC)) < 0)
  {
    alert("error: unable to open gps device: %s", strerror(errno));
    exitclean(2);
  }
  if(!isatty(fd))
  {
    alert("error: specified gps device is not a tty: %s", strerror(errno));
    exitclean(2);
  }

  if(tcgetattr(fd, &backup.ttyset) != 0)
  {
    alert("error: unable to set attributes for gps device: %s",
     strerror(errno));
    exitclean(2);
  }

  if(ioctl(fd, TIOCGETA, &ttyset) < 0)
  {
    alert("error: unable to ioctl gps device: %s", strerror(errno));
    exitclean(2);
  }

  ttyset.c_ispeed = B9600;
  ttyset.c_ospeed = B9600;
  ttyset.c_cflag &= ~(PARENB | CRTSCTS);
  ttyset.c_cflag |= (CSIZE & CS8) | CREAD | CLOCAL ;
  ttyset.c_iflag = (tcflag_t )0;
  ttyset.c_oflag = ttyset.c_lflag = (tcflag_t) 0;
  ttyset.c_lflag |= ICANON;

  if(ioctl(fd, TIOCSETAF, &ttyset) < 0)
  {
    alert("error: unable to ioctl gps device: %s", strerror(errno));
    exitclean(2);
  }

  return fd;
}


void
gps_close(int fd)
{
  if(fd == -1)
  {
    alert("error: unable to close gps device: %s", strerror(errno));
    exitclean(2);
  }
  
  if(isatty(fd))
  {
    ttyset.c_ispeed = B0;
    ttyset.c_ospeed = B0;

    if(ioctl(fd, TIOCSETAF, &ttyset) < 0)
    {
      alert("error: unable to reset gps device: %s", strerror(errno));
      exitclean(2);
    }
  }

  if(tcsetattr(fd, TCSANOW, &backup.ttyset) != 0)
  {
    alert("error: unable to set tty attributes on gps device: %s",
     strerror(errno));
    exitclean(2);
  }

  close(fd);
}

/*
 * read from the gps device and look for the SMATC line so we can grab
 * coordinates.
 */
#define GPSBUF_LEN 1024
void
gps_parse(int fd)
{
  int len;
  int numsats = 0;
  int nsi, ewi; 
  char dop;
  int nsmi, ewmi, nsd, ewd;
  float nsm, nss, ewm, ews;
  char gpsbuf[GPSBUF_LEN];


  if((len = read(fd, gpsbuf, GPSBUF_LEN)) <= 0)
    return;
  if (strncmp(gpsbuf, "SMATC0",6)==0) {
    sscanf(gpsbuf, "SMATC0%*[^NnSs]%1c%d%1c%d+%*[^A-Z]%1c%dAH",
	&ns.dir, 
	&nsi,
	&ew.dir, &ewi 
	,&dop, &numsats);
    /*if ((numsats == 3) || (dop = 'Q')) {*/
    /* so the above line should be better, but 
       fixes very seldom work when you actually use the DOP
       metric the way (i thought) it was meant to be used;
       it appears that virtually all fixes from moving 
       vehicles are 'Q' 
    */
    if (numsats == 3) {
	ns.coordinates = ew.coordinates = 0.00;
	return;
    } else {
      nsd = nsi/100000;
      ewd = ewi/100000;
      nsm = (nsi % 100000);
      ewm = (ewi % 100000);
      nss = (nsmi);
      ews = (ewmi);

      ns.coordinates = nsd + ( nsm/60000 );
      ew.coordinates = ewd + ( ewm/60000 );

      if(gpsbuf[20]=='n')ns.dir = 'N'; 
      else if (gpsbuf[20]=='s')ns.dir = 'S';

      if(gpsbuf[28]=='w') ew.dir = 'W';
      else if( gpsbuf[28]=='e') ew.dir = 'E';
    }
  }
}

/*
 * open the gps device and make sure all the file handlers are setup
 */
void
gps_start(const char *device)
{
  if(!usegps)
    return;

  gps_fd = gps_open(device);
  backup.gps_started++;
}

/*
 * close the gps device and set the gps_started flag back to 0
 */
void
gps_stop(void)
{
  if(!usegps)
    return;

  gps_close(gps_fd);

  backup.gps_started = 0;
}

