/**---------------------------------------------------------------------------
 ** 
 ** io_read.c -- Plugin for io.c 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/15 15:06:25
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/09/22 15:05:04
 ** Update Count    : 13
 ** Directory       : /pcdata1/jaccard/codas3c/gfi/src/libs/nav/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    This file contains low-level functions for reading navigation data. It
 **    is included by file io.c
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **
 ** 1999/09/03 Pierre Jaccard
 **            Addding support for RMC message
 ** 1999/09/04 Pierre Jaccard
 **            Addding support for GLL message
 **------------------------------------------------------------------------**/

#ifndef gfilib_nav_io_read_already_included
#define gfilib_nav_io_read_already_included

/* ------------------------------------------------------------------
	 The next functions read specific navigation lines and fill the
	 corresponding navigation structures. No test is done if the line is not of
	 the expected type. 

	 The format for reading these lines includes a terminating ','. This is to
	 ensure that the last field has been successfully read.
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 GGA information does not contain full date. Therefore, it is necessary to
	 pass both the last time and the year_base in order to calculate the decimal
	 day for it. A check for day changes is done, using the value of [[last]].
	 If this one is bad, a reference day of 1970/01/01 is used.

	 RETURNS: 1 if successful or 
            0 if failed
	 ------------------------------------------------------------------ */
 
#if PROTOTYPE_ALLOWED
int read_gga_line(/* Pointer to first field of GGA data */
                  char *ptr, 
                  /* pointer to GGA structure */
                  GGA_LINE_TYPE *data, 
                  /* Last time */
                  double last, 
                  /* Base year to use */
                  int year_base)
#else
int read_gga_line(ptr, data, last, year_base)
char *ptr;
GGA_LINE_TYPE data;
double last;
int year_base;
#endif
{

	YMDHMS_TIME_TYPE time;
	DMSH_POSITION_TYPE lat, lon;
	double dsec, ds, dlat, dlon;
	int s, h;
	char hlat, hlon;
	char c='\0';
	
	int n;
	const int good = 12; /* Only up to quality */

	/* Fill date data */
	if(last < ADJ_BADFLOAT)
		yd_to_ymdhmh_time(last, year_base, &time);
	else{
		time.year = 1970;
		time.month = time.day = 1;
	}

	/* Read data from the line and fill data structure */
	n = sscanf(ptr, 
						 "%2hu%2hu%lf,%2hd%2hd%lf,%c,%3hd%2hd%lf,%c,%hu,%hu,%lf,%lf%c",
						 &(time.hour), &(time.minute), &dsec, 
 						 &(lat.degree), &(lat.minute), &dlat, &hlat,
						 &(lon.degree), &(lon.minute), &dlon, &hlon,
						 &(data->qual), &(data->nsat), &(data->hdop),&(data->height),
						 &c);
						 
	/* Control read status */
	if((n < good+1) || (c != ','))
		return(0);
	else if(data->qual == 0){
		data->nsat = 0;
		data->hdop = 0.0;
		data->height = 0.0;
	}

	/* Convert decimal day */
	/* 98/01/12 PJ
		 Seconds vary from 00.00 to 60.00, inclusive 60.00 !!! This bug from the
		 navigation must be corrected.
		 */
	if(dsec > 59.99){
		dsec = 0.0;
		time.minute += 1;
	}
	time.second = set_hs(dsec);
	data->yd = year_day(&time, year_base);
	/* Check for day changes */
	if((last < ADJ_BADFLOAT) && (last > data->yd))
		data->yd += 1.0;
	
	/* Convert latitude into decimal degrees */
	ds = dlat * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lat.second = (SHORT) s;
	lat.hundredth = (SHORT) h;
	data->pos.lat = ((DOUBLE) POSHUN(&lat))/360000.0;
	if(hlat == 'S')
		data->pos.lat *= -1.0;

	/* Convert longitude into decimal degrees */
	ds = dlon * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lon.second = (SHORT) s;
	lon.hundredth = (SHORT) h;
	data->pos.lon = ((DOUBLE) POSHUN(&lon))/360000.0;
	if(hlon == 'W')
		data->pos.lon *= -1.0;

	return(1);

}

/* ------------------------------------------------------------------
	 RMC information.

	 RETURNS: 1 if successful or 
            0 if failed
	 ------------------------------------------------------------------ */
 
#if PROTOTYPE_ALLOWED
int read_rmc_line(/* Pointer to first field of RMC data */
                  char *ptr, 
                  /* pointer to RMC structure */
                  RMC_LINE_TYPE *data,
                  /* Base year to use */
                  int year_base)
#else
int read_rmc_line(ptr, data, year_base)
char *ptr;
RMC_LINE_TYPE *data;
int year_base;
#endif
{

	YMDHMS_TIME_TYPE time;
	DMSH_POSITION_TYPE lat, lon;
	double ds, dlat, dlon;
	int s, h;
	char hlat, hlon;
	char c='\0';
	
	int n;
	const int good = 17; /* Only up to quality */

	/* Read data from the line and fill data structure */
	n = sscanf(ptr, 
			 "%2hu%2hu%2hu,%c,%2hd%2hd%lf,%c,%3hd%2hd%lf,%c,%lf,%lf,%2hu%2hu%2hu%c",
						 &(time.hour), &(time.minute), &(time.second),&c,             
 						 &(lat.degree), &(lat.minute), &dlat, &hlat,
						 &(lon.degree), &(lon.minute), &dlon, &hlon,
             &(data->speed), &(data->course), 
             &(time.day), &(time.month), &(time.year), &c);
  
	/* Control read status */
	if((n < good+1) || (c != ','))
		return(0);

	/* Convert decimal day */
  if(time.year < 1900) time.year += 1900;
	data->yd = year_day(&time, year_base);
	
	/* Convert latitude into decimal degrees */
	ds = dlat * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lat.second = (SHORT) s;
	lat.hundredth = (SHORT) h;
	data->pos.lat = ((DOUBLE) POSHUN(&lat))/360000.0;
	if(hlat == 'S')
		data->pos.lat *= -1.0;

	/* Convert longitude into decimal degrees */
	ds = dlon * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lon.second = (SHORT) s;
	lon.hundredth = (SHORT) h;
	data->pos.lon = ((DOUBLE) POSHUN(&lon))/360000.0;
	if(hlon == 'W')
		data->pos.lon *= -1.0;

	return(1);

}

/* ------------------------------------------------------------------
	 GLL information.

	 RETURNS: 1 if successful or 
            0 if failed
	 ------------------------------------------------------------------ */
 
#if PROTOTYPE_ALLOWED
int read_gll_line(/* Pointer to first field of RMC data */
                  char *ptr, 
                  /* pointer to RMC structure */
                  GLL_LINE_TYPE *data)
#else
int read_gll_line(ptr, data)
char *ptr;
RMC_LINE_TYPE *data;
#endif
{

	DMSH_POSITION_TYPE lat, lon;
	double ds, dlat, dlon;
	int s, h;
	char hlat, hlon;
	
	int n;
	const int good = 8; /* Only up to quality */

	/* Read data from the line and fill data structure */
	n = sscanf(ptr, 
			 "%2hd%2hd%lf,%c,%3hd%2hd%lf,%c",
 						 &(lat.degree), &(lat.minute), &dlat, &hlat,
						 &(lon.degree), &(lon.minute), &dlon, &hlon);

  
	/* Control read status */
	if(n < good)
		return(0);
	
	/* Convert latitude into decimal degrees */
	ds = dlat * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lat.second = (SHORT) s;
	lat.hundredth = (SHORT) h;
	data->pos.lat = ((DOUBLE) POSHUN(&lat))/360000.0;
	if(hlat == 'S')
		data->pos.lat *= -1.0;

	/* Convert longitude into decimal degrees */
	ds = dlon * 60.0;
	s  = (int) ds;
	h  = (int) ((ds-s)*100.0);
	lon.second = (SHORT) s;
	lon.hundredth = (SHORT) h;
	data->pos.lon = ((DOUBLE) POSHUN(&lon))/360000.0;
	if(hlon == 'W')
		data->pos.lon *= -1.0;

	return(1);
}

/* ------------------------------------------------------------------
   HDT lines ccontain heading information.
	 
	 RETURNS: 1 if successful or
	          0 if failed
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED	
int read_hdt_line(/* Pointer to first field of HDT data */
                  char *ptr, 
                  /* Pointer to HDT data structure */
                  HDT_LINE_TYPE *data)
#else
int read_hdt_line(ptr, data)
char *ptr;
HDT_LINE_TYPE *data;
#endif
{
	
	char c='\0';
	int n;
	const int good = 1;

	/* Read data from line and fill data structure */
	n = sscanf(ptr, "%lf%c", &(data->heading), &c);
	
	/* Error Check */
	if((n != good+1) || (c != ','))
		return(0);

	return(1);

}

/* ------------------------------------------------------------------
   VTG lines contain course and speed.
	 
	 RETURNS: 1 if successful or
	          0 if failed
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED	
int read_vtg_line(/* pointer to first field of VTG data */
                  char *ptr, 
                  /* pointer to structure for VTG data */
                  VTG_LINE_TYPE *data)
#else
int read_vtg_line(ptr, data)
char *ptr;
VTG_LINE_TYPE *data;
#endif
{
	
	char c='\0';
	int n;
	const int good = 2;

	/* Read data from line and fill data structure */
	n = sscanf(ptr, "%lf,T,,M,%lf%c", &(data->course), &(data->speed), &c);
	
	/* Error Check */
	if((n != good+1) || (c != ','))
		return(0);

	return(1);

}

/* ------------------------------------------------------------------
   ZDA lines contain full date.
	 
	 RETURNS: 1 if successful
	          0 if failed
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int read_zda_line(/* pointer to first field of ZDA data */
                  char *ptr, 
                  /* pointer to structure for ZDA data */
                  ZDA_LINE_TYPE *data, 
                  /* year_base used to calculate decimal day */
                  int year_base)
#else
int read_zda_line(ptr, data, year_base)
char *ptr;
ZDA_LINE_TYPE *data;
int year_base;
#endif
{

	YMDHMS_TIME_TYPE time;
	double dsec;
	char c='\0';
	int n;
	const int good = 6;

	/* Read data from the line and fill data structure */
	n = sscanf(ptr, 
						 "%2hu%2hu%lf,%2hu,%2hu,%4hu%c",
						 &(time.hour), &(time.minute), &dsec, 
						 &(time.day), &(time.month), &(time.year), &c);
						 
	if((n != good+1) || (c != ','))
		return(0);

	/* Convert decimal seconds */
	/* 98/01/12 PJ
		 Seconds vary from 00.00 to 60.00, inclusive 60.00 !!! This bug from the
		 navigation must be corrected.
		 */
	if(dsec > 59.99){
		dsec = 0.0;
		time.minute += 1;
	}
	time.second = set_hs(dsec);
	data->yd = year_day(&time, year_base);

	return(1);

}

/* ------------------------------------------------------------------
	 PRDID lines are RDI's proprietary format with pitch, roll and heading. 
	 
	 RETURNS: 1 if successful
	          0 if failed
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED	
int read_prdid_line(/* pointer to first field of PRDID data */
                    char *ptr, 
                    /* pointer to structure for PRDID data */
                    PRDID_LINE_TYPE *data)
#else
int read_prdid_line(ptr, data)
char *ptr;
PRDID_LINE_TYPE *data;
#endif
{
	
	char c='\0';
	int n;
	const int good = 3;
		
	/* Read data from line and fill data structure */
	n = sscanf(ptr, "%lf,%lf,%lf%c", &(data->pitch),  &(data->roll), 
						 &(data->heading), &c);
	
	/* Error Check */
	if((n != good+1) || (c != ','))
		return(0);

	return(1);

}

/* ------------------------------------------------------------------
	 Transect does not take leap years into account, and according to the author
	 of [[loadtnbp]], pc_time is one day later than it should be. Hence, pc_time
	 from transect will most of the time be incorrect. Therefore, there is no
	 decimal year calculation here. It is assumed that the time is entirely
	 available from GPS or other sources.
	 
	 RETURNS: 1 if successful or
	          0 if failed
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED	
int read_transect_line(/* pointer to beginning of TRANSECT data */
                       char *ptr,
                       /* pointer to structure for TRANSECT data */
                       TRANSECT_LINE_TYPE *data)
#else
int read_transect_line(ptr, data)
char *ptr;
TRANSECT_LINE_TYPE *data;
#endif
{
	
	int n;
	const int good = 4;
	char str[20];

	/* Read data from line and fill data structure */
	n = sscanf(ptr, "%8s%hu%6s%lu", 
						 str, &(data->ensemble_number), str, &(data->pc_time));
	
	if(n != good)
		return(0);

	return(1);

}

#endif /* gfilib_nav_io_read_already_included */
