/*
 * dstumbler v1.0 [gps.c]
 * by h1kari - (c) Dachb0den Labs 2001
 */

/*
 * Copyright (c) 2001 Dachb0den Labs.
 *      David Hulton <h1kari@dachb0den.com>.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by David Hulton.
 * 4. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY David Hulton AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL David Hulton OR THE VOICES IN HIS HEAD
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#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 = B4800;
  ttyset.c_ospeed = B4800;
  ttyset.c_cflag &= ~(PARENB | CRTSCTS);
  ttyset.c_cflag |= (CSIZE & CS8) | CREAD | CLOCAL;
  ttyset.c_iflag = 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 GPGAA line so we can grab
 * coordinates.
 */
#define GPSBUF_LEN 1024
void
gps_parse(int fd)
{
  int len;
  int numsats = 0;
  int nsi, ewi, nsmi, ewmi;
  int nsd, ewd;
  float nsm, nss, ewm, ews;
  char gpsbuf[GPSBUF_LEN];


  if((len = read(fd, gpsbuf, GPSBUF_LEN)) <= 0)
    return;

  if(ETAKNMEA) {
    if(strncmp(gpsbuf, "$GPGGA",6) == 0)
    { 
      sscanf(gpsbuf, "%*[^,],%*d,%d.%d,%c,%d.%d,%c,,%d,i",
	&nsi, &nsmi, &ns.dir,
	&ewi, &ewmi, &ew.dir,
	&numsats
	);
      if (numsats < 2)
      {
	ns.coordinates = 0.00;
        ew.coordinates = 0.00;
        return;
      }

      if(ns.dir == '\0') ns.dir = 'N';
      if(ew.dir == '\0') ew.dir = 'E';
      nsd = (nsi/100);
      ewd = (ewi/100);
      nsm = (nsi % 100);
      ewm = (ewi % 100);
      nss = (nsmi);
      ews = (ewmi);

      ns.coordinates = nsd + (nsm/60) + (nss/60000);
      ew.coordinates = ewd + (ewm/60) + (ews/60000);
    }
  } else {
    if(strncmp(gpsbuf, "$GPGGA", 6)==0)
    {
      sscanf(gpsbuf, "%*[^,],%*d,%f,%c,%f,%c,", &ns.coordinates, &ns.dir, 
	&ew.coordinates, &ew.dir);
      if(ns.dir == '\0') ns.dir = 'N';
      if(ew.dir == '\0') ew.dir = 'E';
      ns.coordinates /= 100;
      ew.coordinates /= 100;
   }
  }
}

/*
 * 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;
}

