/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>

#include "task.h"
#include "memory_debug.h"
#include "locator.h"
#include "gps.h"


LOCATOR_TABLE locator_table_gps = {
	kill_locator_gps,
	0,
	0
};

void locator_gps(TKEY t);

LOCATOR_INFO *
init_locator_gps(LOCATOR_INIT *init)
{
LOCATOR_INFO *info;
	info = d_alloc(sizeof(*info));
	memcpy(&info->h, init, sizeof(*init));
	info->h.tbl = &locator_table_gps;
	info->gps.running = 1;
	create_task(locator_gps, (int)info, 4);
	return init_locator(info);
}

int
kill_locator_gps(LOCATOR_INFO *info)
{
	info->gps.running = 0;
	return 0;
}

void
send_location_info_gps(
	LOCATOR_INFO *li,
	GPGGA *gga,
	GPGSA *gsa,
	GPRMC *rmc,
	PGRME *pgrme)
{
LOCATION_INFO loc_info;
/*
	printf("***  N %d %f  E %d %f  elev  %.1f m\n", 
	gga->ndeg, gga->nmin, gga->edeg, gga->emin, gga->elev);
	printf("***      accuracy :horizonal %.1f  m  vertical %.1f m\n", pgrme->hpe, pgrme->vpe);
	printf("***      time : %02d.%2d.%2d %2d:%02d:%04.1f\n",
	rmc->year, rmc->month, rmc->day, rmc->hour, rmc->min, rmc->sec);
	printf("***      direction : %f      quality : %d\n", rmc->direction, gga->quality);
	printf("\n");
*/
	loc_info.locator_type =
		gga->quality == 2 ? LT_GPS_DGPS :
		gga->quality == 8 ? LT_GPS_SIM : LT_GPS_STD;
	loc_info.crd = NULL;
	loc_info.state = (li->h.locator_type & loc_info.locator_type) ?
		LS_OK : LS_UNABLE;
	loc_info.unit_uri = "base";
	loc_info.x_unit = loc_info.y_unit = "degree";
	loc_info.z_unit = "m";
	loc_info.sx_unit = loc_info.sy_unit = loc_info.sz_unit = "m";
	if ( gga->deg_valid ) {
		loc_info.x = gga->edeg + gga->emin / 60;
		loc_info.y = gga->ndeg + gga->nmin / 60;
		loc_info.z = gga->elev;
		loc_info.sx = pgrme->hpe;
		loc_info.sy = pgrme->hpe;
		loc_info.sz = pgrme->vpe;
	}
	else
		loc_info.state |= LS_LOC_UNABLE;
	if ( rmc->time_valid && rmc->date_valid ) {
		struct tm t, u;
		t.tm_sec = (int)rmc->sec;
		t.tm_min = rmc->min;
		t.tm_hour = rmc->hour;
		t.tm_mday = rmc->day;
		t.tm_mon = rmc->month-1;
		t.tm_year = (rmc->year+2000)-1900;
		t.tm_isdst = 0;
		
		u.tm_sec = 0;
		u.tm_min = 0;
		u.tm_hour = 0;
		u.tm_mday = 1;
		u.tm_mon = 1-1;
		u.tm_year = 2001-1900;
		u.tm_isdst = 0;
		loc_info.t = difftime(mktime(&t), mktime(&u));
		loc_info.st = 0.5;
	}
	else
		loc_info.state |= LS_TIME_UNABLE;
	
	send_location_info(li, &loc_info);
}

void
locator_gps(TKEY t)
{
LOCATOR_INFO *info = (LOCATOR_INFO*)GET_TKEY(t);
GPS_GET_SENTENCE *ggs;
GPGGA gga;
GPGSA gsa;
GPRMC rmc;
PGRME pgrme;
const char *sentence;
	
	ggs = gps_get_sentence_start(info->h.st);
	
	 while ( 1 ) {
		sentence = gps_get_sentence(ggs);
		if ( sentence == 0 ) {
			printf("*** no sentence ***\n");
			break;
		}
		if ( ! info->gps.running )
			break;
		
		if ( memcmp(sentence+1, "GPRMC", 5) == 0 )
			read_sentence_rmc(sentence, &rmc);
		else if ( memcmp(sentence+1, "GPGGA", 5) == 0 )
			read_sentence_gga(sentence, &gga);
		else if ( memcmp(sentence+1, "GPGSA", 5) == 0 )
			read_sentence_gsa(sentence, &gsa);
		else if ( memcmp(sentence+1, "PGRME", 5) == 0 ) {
			read_sentence_pgrme(sentence, &pgrme);
			send_location_info_gps(info, &gga, &gsa, &rmc, &pgrme);
		}
	}
	
	if ( info->h.close_func )
		(*info->h.close_func)(info);
	
	gps_get_sentence_end(ggs);
	
	d_f_ree(info);
}

