/******************************************************************************
    FILE:  UBWRITE.C

           Writing routines to support UBPRINT.C

   2000/01/19 EF changed gps fix outputs to write the "quality"
   field instead of the "msg_type" field.

*/

#include "geninc.h"
#include "time_.h"
#include "mem_.h"       /* move_byte() */
#include "use_db.h"     /* check_db*(), etc. */
#include "adcp.h"		/* NAVIGATION_TYPE, etc. */
#include "userbuff.h"		/* USER_BUFFER_*_TYPE, etc. */
#include "matfile.h"

#define good_short(x)  ((x) < BADSHORT)
#define good_long(x)   ((x) < BADLONG)
#define good_float(x)  ((x) < ADJ_BADFLOAT)
#define TOLERANCE      0.0002315/* dec. day difference allowed for averaging
                                 * across ensemble fixes */
/* this value is equivalent to 20 seconds */
static char *source_name[] = {"none", "gps", "transit"};
extern int ub_type;
#define N_A_VAR 	29
#define N_F_VAR 	32

#if PROTOTYPE_ALLOWED
void write_transit_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                              NAVIGATION_TYPE * navdata, int offset);
void write_user_buffer(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                            NAVIGATION_TYPE * navdata, int offset);
void write_transit_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                                NAVIGATION_TYPE * navdata, int offset);
void write_gps_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                            NAVIGATION_TYPE * navdata, int offset);
void write_avg_gps_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                                NAVIGATION_TYPE * navdata, int offset);
void write_gps_cal(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                        NAVIGATION_TYPE * navdata, int offset);
void write_L_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                        NAVIGATION_TYPE * navdata, int offset);
void write_gps_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                          NAVIGATION_TYPE * navdata, int offset);
void write_raw2_messages(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                              NAVIGATION_TYPE * navdata, int offset);
void write_ashtech_att(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime,
                            NAVIGATION_TYPE * navdata, int offset);
double dec_day(LONG fixtime, double pctime);
double average(double d1, double d2);
#else
void write_transit_fixes();
void write_user_buffer();
void write_transit_summary();
void write_gps_summary();
void write_avg_gps_summary();
void write_gps_cal();
void write_L_fixes();
void write_gps_fixes();
void write_raw2_messages();
void write_ashtech_att();
double dec_day();
double average();
#endif

#if PROTOTYPE_ALLOWED
void write_user_buffer(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_user_buffer(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   int i;
   LONG *time;
   USER_BUFFER_2240_TYPE *u;
   extern int year_base;

   typedef struct
   {
      SHORT max_avgs, first_bin, n_bins, *avg_uv;
   }      UBSHORTS_1;
   UBSHORTS_1 *ubs1;

   typedef struct
   {
      SHORT set, drift, position_source, dr_time;
   }      UBSHORTS_2;
   UBSHORTS_2 *ubs2;

   switch (ub_type)
   {
      case 1021:
         ubs1 = (UBSHORTS_1 *) & (((USER_BUFFER_1021_TYPE *) ub)->max_avgs);
         ubs2 = (UBSHORTS_2 *) & (((USER_BUFFER_1021_TYPE *) ub)->set);
         time = &(((USER_BUFFER_1021_TYPE *) ub)->time);
         break;
      case 1281:
         ubs1 = (UBSHORTS_1 *) & (((USER_BUFFER_1281_TYPE *) ub)->max_avgs);
         ubs2 = (UBSHORTS_2 *) & (((USER_BUFFER_1281_TYPE *) ub)->set);
         time = &(((USER_BUFFER_1281_TYPE *) ub)->time);
         break;
      case 1320:
         ubs1 = (UBSHORTS_1 *) & (((USER_BUFFER_1320_TYPE *) ub)->max_avgs);
         ubs2 = (UBSHORTS_2 *) & (((USER_BUFFER_1320_TYPE *) ub)->set);
         time = &(((USER_BUFFER_1320_TYPE *) ub)->time);
         break;
      case 2240:
      case 720:
      case 1920:
         u = (USER_BUFFER_2240_TYPE *) ub;
         fprintf(fp_out, "\n\nProfile Time = %f  no. of samples = %hd, seconds added = %hd\n",
                 year_day(ptime, year_base), u->n_samples, u->s_added);
         write_gps_fixes(fp_out, ub, ptime, navdata, offset);
         write_raw2_messages(fp_out, ub, ptime, navdata, offset);
         return;
      default:
         printf("\n ERROR: Unrecognized user buffer type %d", ub_type);
         return;
   }

   fprintf(fp_out,
      "\nReference layer: n = %hd, first bin = %hd, number of bins = %hd\n",
           ubs1->max_avgs, ubs1->first_bin, ubs1->n_bins);
   fprintf(fp_out, "U: (mm/s)");
   for (i = 0; i < ubs1->max_avgs * 2; i += 2)
   {
      if (good_short(ubs1->avg_uv[i]))
         fprintf(fp_out, "%5hd ", ubs1->avg_uv[i]);
      else
         fprintf(fp_out, " **** ");
   }
   fprintf(fp_out, "\nV: (mm/s)");
   for (i = 1; i < ubs1->max_avgs * 2; i += 2)
   {
      if (good_short(ubs1->avg_uv[i]))
         fprintf(fp_out, "%5hd ", ubs1->avg_uv[i]);
      else
         fprintf(fp_out, " **** ");
   }
   fprintf(fp_out, "\nDR source = %s",
           source_name[ubs2->position_source]);
   if (ubs2->position_source != PS_NONE)
   {
      fprintf(fp_out,
              ",  time = %ld, dr time = %hd, set = %f, drift = %f kts",
              *time, ubs2->dr_time, ubs2->set / 10.0, ubs2->drift / 100.0);
   }
   write_transit_fixes(fp_out, ub, ptime, navdata, offset);
   write_L_fixes(fp_out, ub, ptime, navdata, offset);
   fprintf(fp_out, "\n");
}

#if PROTOTYPE_ALLOWED
void write_transit_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_transit_fixes(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   TRANSIT_FIX_TYPE *fix;

   switch (ub_type)
   {
      case 1021:
         fix = &(((USER_BUFFER_1021_TYPE *) ub)->fix);
         break;
      case 1281:
         fix = &(((USER_BUFFER_1281_TYPE *) ub)->fix);
         break;
      case 1320:
         fix = &(((USER_BUFFER_1320_TYPE *) ub)->fix);
         break;
      case 720:
      case 2240:
      case 1920:
         return;
      default:
         printf("\n ERROR: Unrecognized user buffer type %d", ub_type);
         return;
   }

   if (fix->sat_id)
   {
      fprintf(fp_out, "\nTRANSIT FIX: PC time = %ld, fix time = %ld, PC - fix = %ld",
              fix->pc_time, fix->fix_time,
              fix->pc_time - fix->fix_time);
      fprintf(fp_out, "\nLatitude: %f, Longitude: %f",
              fix->lat / 360000.0,
              fix->lon / 360000.0);
      fprintf(fp_out, "\nReference layer since last fix: u = %hd, v = %hd, n = %hd",
              fix->ref_u, fix->ref_v, fix->ref_count);
      fprintf(fp_out, "\nDR dist = %f nm, dir = %f; sat ID = %hd,  antenna = %f m",
              fix->dr_dist / 100.0, fix->dr_dir / 10.0,
              fix->sat_id, fix->antenna / 10.0);
      fprintf(fp_out, "\nUsed for update? %s.  Quality flags: %0x %0x %0x",
              fix->used ? "yes" : "no",
              fix->q1, fix->q2, fix->q3);
      fprintf(fp_out, "\nsigma longitude = %hd m, sigma latitude = %hd m",
              fix->sigma_lon, fix->sigma_lat);
      fprintf(fp_out, "\nelevation = %hd, iterations = %hd, doppler count = %hd\n",
              fix->elevation, fix->iterations, fix->dop_count);
   }
}

#if PROTOTYPE_ALLOWED
void write_gps_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_gps_fixes(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   USER_BUFFER_2240_TYPE *u;
   int i;

   if (ub_type != 2240 && ub_type != 720 && ub_type != 1920)
      return;
   u = (USER_BUFFER_2240_TYPE *) ub;
   for (i = (2 * offset); i < u->n_samples + (2 * offset); i++)
   {
      fprintf(fp_out, "\nGPS FIX: PC time = %ld, GPS time = %ld, PC - GPS = %ld",
              u->fix[i].pc_seconds, u->fix[i].gps_seconds,

              (u->fix[i].msg_type == GGA_FIX ? u->fix[i].pc_seconds - u->fix[i].gps_seconds :
               u->fix[i].pc_seconds - u->fix[i].gps_seconds %
               SECONDS_PER_DAY));
      fprintf(fp_out, "\nLatitude: %f, Longitude: %f",
              u->fix[i].lat, u->fix[i].lon);
      fprintf(fp_out, "\nelevation = %f, dop = %d, no. of satellites = %d, quality = %d\n",
       u->fix[i].height, u->fix[i].dop, u->fix[i].nsat, u->fix[i].quality);
   }
}

#if PROTOTYPE_ALLOWED
void write_raw2_messages(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_raw2_messages(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   USER_BUFFER_2240_TYPE *u;
   int i, j;

   if (ub_type != 2240)
      return;
   u = (USER_BUFFER_2240_TYPE *) ub;
   for (i = (2 * offset); i < u->n_samples + (2 * offset); i++)
   {
      if (u->fix[i].msg_type != MSG8_FIX)
         return;
      fprintf(fp_out, "\n   2 ");
      for (j = 0; j < sizeof(RAW_2_TYPE); j++)
         fprintf(fp_out, "%c", u->raw[i].c[j]);
   }
}

#if PROTOTYPE_ALLOWED
void write_transit_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_transit_summary(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   double ddtime;
   TRANSIT_FIX_TYPE *fix;

   switch (ub_type)
   {
      case 1021:
         fix = &(((USER_BUFFER_1021_TYPE *) ub)->fix);
         break;
      case 1281:
         fix = &(((USER_BUFFER_1281_TYPE *) ub)->fix);
         break;
      case 1320:
         fix = &(((USER_BUFFER_1320_TYPE *) ub)->fix);
         break;
      case 720:
      case 2240:
      case 1920:
         return;
      default:
         printf("\n ERROR: Unrecognized user buffer type %d", ub_type);
         return;
   }

   if (fix->sat_id)
   {
      ddtime = fix->fix_time / 86400.0;
      fprintf(fp_out, "%13.7f  %13.7f %13.7f  %3hd %2hd %5.2f %2hd  %ld\n",
              ddtime,
              fix->lon / 360000.0,
              fix->lat / 360000.0,
              fix->elevation,
              fix->iterations,
              fix->dr_dist / 100.0,
              fix->used,
              fix->pc_time - fix->fix_time);
   }
}

#if PROTOTYPE_ALLOWED
void write_gps_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_gps_summary(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   extern int year_base;
   LONG fix_time;
   SHORT position_source, dr_time;
   GPS_STATUS_TYPE *gps_status;
   USER_BUFFER_2240_TYPE *u;

   if (navdata->latitude == 0.0 && navdata->longitude == 0.0)
      return;
   switch (ub_type)
   {
      case 1021:
         position_source = ((USER_BUFFER_1021_TYPE *) ub)->position_source;
         dr_time = ((USER_BUFFER_1021_TYPE *) ub)->dr_time;
         fix_time = ((USER_BUFFER_1021_TYPE *) ub)->time;
         break;
      case 1281:
         position_source = ((USER_BUFFER_1281_TYPE *) ub)->position_source;
         dr_time = ((USER_BUFFER_1281_TYPE *) ub)->dr_time;
         gps_status = &(((USER_BUFFER_1281_TYPE *) ub)->gps_status);
         fix_time = ((USER_BUFFER_1281_TYPE *) ub)->time;
         break;
      case 1320:
         position_source = ((USER_BUFFER_1320_TYPE *) ub)->position_source;
         dr_time = ((USER_BUFFER_1320_TYPE *) ub)->dr_time;
         gps_status = &(((USER_BUFFER_1320_TYPE *) ub)->gps_status);
         fix_time = ((USER_BUFFER_1320_TYPE *) ub)->time;
         break;
      case 720:
      case 2240:		/* print end fix only */
      case 1920:
         u = (USER_BUFFER_2240_TYPE *) ub;
         switch (u->fix[u->n_samples + (2 * offset) - 1].msg_type)
         {
            case GGA_FIX:
               fprintf(fp_out, "%13.7f %13.7f %13.7f",
                dec_day(u->fix[u->n_samples + (2 * offset) - 1].gps_seconds,
                        year_day(ptime, year_base)),
                       navdata->longitude, navdata->latitude);
               break;
            case MSG8_FIX:
               fprintf(fp_out, "%13.7f %13.7f %13.7f",
                       dec_day(u->fix[u->n_samples + (2 * offset) - 1].gps_seconds % SECONDS_PER_DAY,
                               year_day(ptime, year_base)),
                       navdata->longitude, navdata->latitude);
               break;
            default:
               return;
         }
         fprintf(fp_out, "  %2d %2d %3d %8.2f\n",
                 u->fix[u->n_samples + (2 * offset) - 1].nsat,
                 u->fix[u->n_samples + (2 * offset) - 1].quality,
                 u->fix[u->n_samples + (2 * offset) - 1].dop,
                 u->fix[u->n_samples + (2 * offset) - 1].height);
         return;
      default:
         printf("\n ERROR: Unrecognized user buffer type %d", ub_type);
         return;
   }

   if (position_source == PS_GPS && dr_time < 10)
   {
      fprintf(fp_out, "%13.7f %13.7f %13.7f",
              dec_day(fix_time, year_day(ptime, year_base)),
              navdata->longitude, navdata->latitude);
      if (ub_type == 1281 || ub_type == 1320)
      {
         fprintf(fp_out, "  %1hd %1hd %2hd %3hd %3hd %3hd  %3hd ",
                 gps_status->nsat,
                 gps_status->quality,
                 gps_status->hdop,
                 gps_status->dopN,
                 gps_status->dopE,
                 gps_status->dopV,
                 gps_status->altitude);
      }
      fprintf(fp_out, "\n");
   }
}

#if PROTOTYPE_ALLOWED
void write_avg_gps_summary(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_avg_gps_summary(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   static double tn[2], xn, yn;
   static int first_profile[2] = {1, 1};
   static char gps_line[60];
   static char fmt720[] = "%13.7f %13.7f %13.7f  %2d %2d %3d %8.2f \n";
   static GPS_FIX_TYPE prev_fix[2];
   USER_BUFFER_1320_TYPE *ubuf;
   USER_BUFFER_2240_TYPE *u;
   double ddtime, t0;
   extern int year_base;

   int i = 2 * offset;
   ddtime = year_day(ptime, year_base);

   switch (ub_type)
   {
      case 1320:
         ubuf = (USER_BUFFER_1320_TYPE *) ub;

         if (!first_profile[offset])
         {
            t0 = dec_day(ubuf->avg_fix[offset].time, ddtime);
            if (t0 < ADJ_BADFLOAT)
            {
               if (tn[offset] < ADJ_BADFLOAT)
               {
                  if (t0 - tn[offset] < TOLERANCE)
                     fprintf(fp_out, "%13.7f %13.7f %13.7f  %s",
                             average(tn[offset], t0),
                         average(xn, (ubuf->avg_fix[offset].lon / 60000.0)),
                         average(yn, (ubuf->avg_fix[offset].lat / 60000.0)),
                             gps_line);
                  else
                  {
                     fprintf(fp_out, "%13.7f %13.7f %13.7f  %s%13.7f %13.7f %13.7f  ",
                             tn[offset], xn, yn, gps_line, t0, (ubuf->avg_fix[offset].lon / 60000.0),
                             (ubuf->avg_fix[offset].lat / 60000.0));
                     fprintf(fp_out, "%1hd %1hd %2hd %3hd %3hd %3hd  %3hd \n",
                             ubuf->gps_status.nsat,
                             ubuf->gps_status.quality,
                             ubuf->gps_status.hdop,
                             ubuf->gps_status.dopN,
                             ubuf->gps_status.dopE,
                             ubuf->gps_status.dopV,
                             ubuf->gps_status.altitude);
                  }
               }
               else
               {
                  fprintf(fp_out, "%13.7f %13.7f %13.7f  ",
                          t0, (good_long(ubuf->avg_fix[offset].lon) ? ubuf->avg_fix[offset].lon / 60000.0 :
                               BADFLOAT),
                          (good_long(ubuf->avg_fix[offset].lat) ? ubuf->avg_fix[offset].lat / 60000.0 :
                           BADFLOAT));
                  fprintf(fp_out, "%1hd %1hd %2hd %3hd %3hd %3hd  %3hd \n",
                          ubuf->gps_status.nsat,
                          ubuf->gps_status.quality,
                          ubuf->gps_status.hdop,
                          ubuf->gps_status.dopN,
                          ubuf->gps_status.dopE,
                          ubuf->gps_status.dopV,
                          ubuf->gps_status.altitude);
               }
            }
            else if (tn[offset] < ADJ_BADFLOAT)
               fprintf(fp_out, "%13.7f %13.7f %13.7f  %s", tn[offset], xn, yn, gps_line);
         }

         tn[offset] = dec_day(ubuf->avg_fix[N_REF_AVGS_1320].time, ddtime);
         xn = good_long(ubuf->avg_fix[N_REF_AVGS_1320].lon) ?
            ubuf->avg_fix[N_REF_AVGS_1320].lon / 60000.0 : BADFLOAT;
         yn = good_long(ubuf->avg_fix[N_REF_AVGS_1320].lat) ?
            ubuf->avg_fix[N_REF_AVGS_1320].lat / 60000.0 : BADFLOAT;

         first_profile[offset] = 0;
         sprintf(gps_line, "%1hd %1hd %2hd %3hd %3hd %3hd  %3hd \n",
                 ubuf->gps_status.nsat,
                 ubuf->gps_status.quality,
                 ubuf->gps_status.hdop,
                 ubuf->gps_status.dopN,
                 ubuf->gps_status.dopE,
                 ubuf->gps_status.dopV,
                 ubuf->gps_status.altitude);
         break;
      case 720:
      case 2240:
      case 1920:
         u = (USER_BUFFER_2240_TYPE *) ub;

         if (first_profile[offset])
         {
            tn[offset] = BADFLOAT;
            first_profile[offset] = 0;
         }

         switch (u->fix[i].msg_type)
         {
            case GGA_FIX:
               t0 = dec_day(u->fix[i].gps_seconds, ddtime);
               break;
            case MSG8_FIX:
               t0 = dec_day(u->fix[i].gps_seconds % SECONDS_PER_DAY, ddtime);
               break;
            default:
               t0 = BADFLOAT;
               break;
         }
         if (t0 < ADJ_BADFLOAT)
         {
            if (tn[offset] < ADJ_BADFLOAT)
            {
               if (t0 - tn[offset] < TOLERANCE)
               {
                  fprintf(fp_out, fmt720,
                           average(tn[offset], t0),
                           average(prev_fix[offset].lon, u->fix[i].lon),
                           average(prev_fix[offset].lat, u->fix[i].lat),
                           (prev_fix[offset].nsat + u->fix[i].nsat) / 2,
                           (prev_fix[offset].quality + u->fix[i].quality) / 2,
                           (prev_fix[offset].dop + u->fix[i].dop) / 2,
                           (prev_fix[offset].height + u->fix[i].height) / 2.0);
               }
               else /* print tn and t0 separately */
               {
                  fprintf(fp_out, fmt720,
                           tn[offset],
                           prev_fix[offset].lon,
                           prev_fix[offset].lat,
                           prev_fix[offset].nsat,
                           prev_fix[offset].quality,
                           prev_fix[offset].dop,
                           prev_fix[offset].height);
                  fprintf(fp_out, fmt720,
                           t0,
                           u->fix[i].lon, u->fix[i].lat,
                           u->fix[i].nsat,
                           u->fix[i].quality,
                           u->fix[i].dop,
                           u->fix[i].height);
               } /* end of case with widely separated t0, tn */
            }
            else /* good t0 but bad tn; print t0 fix only */
            {
               fprintf(fp_out, fmt720,
                        t0,
                        u->fix[i].lon, u->fix[i].lat,
                        u->fix[i].nsat,
                        u->fix[i].quality,
                        u->fix[i].dop,
                        u->fix[i].height);
            }
         }
         else  /* t0 is bad; print tn if it is OK */
         {
            if (tn[offset] < ADJ_BADFLOAT)
               fprintf(fp_out, fmt720,
                        tn[offset],  /* jr 95/01/23 added [offset] to this, too */
                        prev_fix[offset].lon, prev_fix[offset].lat,
                        prev_fix[offset].nsat, prev_fix[offset].quality,
                        prev_fix[offset].dop, prev_fix[offset].height);
         }
         /* Set the previous fix to the last fix of the present ensemble */
         prev_fix[offset] = u->fix[u->n_samples + i - 1];

         switch (prev_fix[offset].msg_type)
         {
            case GGA_FIX:
               tn[offset] = dec_day(prev_fix[offset].gps_seconds, ddtime);
               break;
            case MSG8_FIX:
               tn[offset] = dec_day(prev_fix[offset].gps_seconds % SECONDS_PER_DAY, ddtime);
               break;
            default:
               tn[offset] = BADFLOAT;
               gps_line[0] = '\0';
               return;
         }
         break;
      default:
         return;
   } /* end switch(ub_type) */
}

#define to_ms(vel)            good_short(vel) ? ((vel) / 1000.0) : BADFLOAT

#if PROTOTYPE_ALLOWED
void write_gps_cal(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_gps_cal(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   static double t0, x0, y0;
   static char gps_line[60], uv_line[80];
   static first_profile = 1;
   USER_BUFFER_1320_TYPE *ubuf;
   extern int year_base;
   double ddtime, avg_time;
   int i_uvref, jfix;

   if (ub_type != 1320)
      return;
   ubuf = (USER_BUFFER_1320_TYPE *) ub;
   ddtime = year_day(ptime, year_base);

   if (!first_profile)		/* average & print preceding fix */
   {
      if ((avg_time = average(t0, dec_day(ubuf->avg_fix[offset].time, ddtime)))
          < ADJ_BADFLOAT
          && good_float(x0)
          && good_long(ubuf->avg_fix[offset].lon))
         fprintf(fp_out, "%13.7f %s %13.7f %13.7f %s",
                 avg_time,
                 uv_line,
                 average(x0, ubuf->avg_fix[offset].lon / 60000.0),
                 average(y0, ubuf->avg_fix[offset].lat / 60000.0),
                 gps_line);
   }
   sprintf(gps_line, "%1hd %1hd %2hd %3hd %3hd %3hd  %3hd \n",
           ubuf->gps_status.nsat,
           ubuf->gps_status.quality,
           ubuf->gps_status.hdop,
           ubuf->gps_status.dopN,
           ubuf->gps_status.dopE,
           ubuf->gps_status.dopV,
           ubuf->gps_status.altitude);
   for (jfix = 1, i_uvref = 0; jfix < N_REF_AVGS_1320; jfix++, i_uvref++)
   {
      if (good_long(ubuf->avg_fix[jfix].time)
          && good_long(ubuf->avg_fix[jfix].lon))
         fprintf(fp_out, "%13.7f %13.7f %13.7f %13.7f %13.7f %s",
                 dec_day(ubuf->avg_fix[jfix].time, ddtime),
                 to_ms(ubuf->avg_uv[i_uvref * 2]),
                 to_ms(ubuf->avg_uv[i_uvref * 2 + 1]),
                 ubuf->avg_fix[jfix].lon / 60000.0,
                 ubuf->avg_fix[jfix].lat / 60000.0,
                 gps_line);
   }
   /* save last avg_fix info, etc. for next iteration */
   t0 = dec_day(ubuf->avg_fix[jfix].time, ddtime);
   x0 = good_long(ubuf->avg_fix[jfix].lon) ?
      ubuf->avg_fix[jfix].lon / 60000.0 : BADFLOAT;
   y0 = good_long(ubuf->avg_fix[jfix].lat) ?
      ubuf->avg_fix[jfix].lat / 60000.0 : BADFLOAT;
   sprintf(uv_line, "%13.7g %13.7g",
    to_ms(ubuf->avg_uv[i_uvref * 2]), to_ms(ubuf->avg_uv[i_uvref * 2 + 1]));
   first_profile = 0;
}

#if PROTOTYPE_ALLOWED
void write_L_fixes(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_L_fixes(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   L_FIX_TYPE *avg_fix;
   int i;
   YMDHMS_TIME_TYPE ltime;

   if (ub_type == 1320)
   {
      avg_fix = ((USER_BUFFER_1320_TYPE *) ub)->avg_fix;

      fprintf(fp_out, "\nL FIX: \n");
      for (i = offset; i < N_REF_AVGS_1320 + 1; i++)
      {
         if (avg_fix[i].time < BADLONG)
         {
            ltime.hour = avg_fix[i].time / 3600L;
            ltime.minute = (avg_fix[i].time % 3600L) / 60;
            ltime.second = avg_fix[i].time % 60L;
            fprintf(fp_out,
                    "  Time: %02hd:%02hd:%02hd Longitude: %13.7f, Latitude: %13.7f\n",
                    ltime.hour, ltime.minute, ltime.second,
                    avg_fix[i].lon / 60000.0,
                    avg_fix[i].lat / 60000.0);
         }
         else
            fprintf(fp_out, "  unavailable\n");
      }
   }
}

/* New option created that works for 192-byte User Buffer */

#if PROTOTYPE_ALLOWED
void write_ashtech_att(FILE * fp_out, char *ub, YMDHMS_TIME_TYPE * ptime, NAVIGATION_TYPE * navdata, int offset)
#else
void write_ashtech_att(fp_out, ub, ptime, navdata, offset)
   FILE *fp_out;
   char *ub;
   YMDHMS_TIME_TYPE *ptime;
   NAVIGATION_TYPE *navdata;
   int offset;
#endif
{
   USER_BUFFER_1920_TYPE *u;
   ASHTECH_ATT_STAT_TYPE *att;
   extern int year_base;
   static int FLAG = 1;
   double ddtime;

   if (ub_type != 1920)
      return;

   u = (USER_BUFFER_1920_TYPE *) ub;
   ddtime = year_day(ptime, year_base);
   /* t0 = dec_day(u->fix[0].gps_seconds, ddtime); ef- 95/12/05 */
   att = &(u->att);

   if (FLAG)
   {
      fprintf(fp_out,
              "\n      time      dh_mean  dh_std  dh_min  dh_max    p_mean  p_std   r_mean   r_std   n_att  n_used\n");
      fprintf(fp_out,
              " (Decimal_days)                                                                                    \n");
      FLAG = 0;
   }

   fprintf(fp_out, "%13.7f   %6.2f  %6.2f  %6.2f  %6.2f    %6.2f  %6.2f   %6.2f  %6.2f     %3d    %3d\n",
           ddtime, /* t0, ef 95/12/05 */
           att->dh_mean * 0.01,
           att->dh_std * 0.01,
           att->dh_min * 0.01,
           att->dh_max * 0.01,
           att->p_mean * 0.01,
           att->p_std * 0.01,
           att->r_mean * 0.01,
           att->r_std * 0.01,
           att->n_att, att->n_used);
}

#if PROTOTYPE_ALLOWED
double average(double d1, double d2)
#else
double average(d1, d2)
   double d1, d2;
#endif
{
   if (d1 < ADJ_BADFLOAT && d2 < ADJ_BADFLOAT)
      return ((d1 + d2) / 2.0);
   if (d1 < ADJ_BADFLOAT)
      return (d1);
   if (d2 < ADJ_BADFLOAT)
      return (d2);
   return (BADFLOAT);
}

/*-----------------------------------------------------------------------------

    FUNCTION:  dec_day

       Given a decimal day and an offset in seconds
       from the beginning of that day,
       it returns the equivalent decimal day for that offset.

       It automatically makes the correction for
       the decimal day being off by one day in the case
       where the offset is just at the boundary between days
       and the clock sources for the decimal day argument
       and for the offset argument are not perfectly synchronized.

*/
#if PROTOTYPE_ALLOWED
double dec_day(LONG offset, double decimal_day)
#else
double dec_day(offset, decimal_day)
   LONG offset;
   double decimal_day;
#endif
{
   double ddtime;

   if (good_long(offset))
   {
      ddtime = ((int) decimal_day) + ((double) offset) / 86400.0;
      while (decimal_day - ddtime >  0.5)  ddtime += 1.0;
      while (decimal_day - ddtime < -0.5)  ddtime -= 1.0;
      return (ddtime);
   }
   return (BADFLOAT);
}

#if PROTOTYPE_ALLOWED
void write_att_indices(void)
#else
void write_att_indices()
#endif
{
   extern FILE *fp_mat;
   double id;

   id = (double) 1;
   savemat(fp_mat, 'd', "i_day", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 2;
   savemat(fp_mat, 'd', "i_lat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 3;
   savemat(fp_mat, 'd', "i_lon", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 4;
   savemat(fp_mat, 'd', "i_dh_mean", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 5;
   savemat(fp_mat, 'd', "i_dh_std", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 6;
   savemat(fp_mat, 'd', "i_dh_min", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 7;
   savemat(fp_mat, 'd', "i_dh_max", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 8;
   savemat(fp_mat, 'd', "i_p_mean", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 9;
   savemat(fp_mat, 'd', "i_p_std", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 10;
   savemat(fp_mat, 'd', "i_p_min", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 11;
   savemat(fp_mat, 'd', "i_p_max", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 12;
   savemat(fp_mat, 'd', "i_r_mean", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 13;
   savemat(fp_mat, 'd', "i_r_std", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 14;
   savemat(fp_mat, 'd', "i_r_min", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 15;
   savemat(fp_mat, 'd', "i_r_max", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 16;
   savemat(fp_mat, 'd', "i_mrms_mean", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 17;
   savemat(fp_mat, 'd', "i_mrms_std", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 18;
   savemat(fp_mat, 'd', "i_mrms_min", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 19;
   savemat(fp_mat, 'd', "i_mrms_max", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 20;
   savemat(fp_mat, 'd', "i_brms_mean", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 21;
   savemat(fp_mat, 'd', "i_brms_std", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 22;
   savemat(fp_mat, 'd', "i_brms_min", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 23;
   savemat(fp_mat, 'd', "i_brms_max", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 24;
   savemat(fp_mat, 'd', "i_n_att", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 25;
   savemat(fp_mat, 'd', "i_n_used", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 26;
   savemat(fp_mat, 'd', "i_n_reacq", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 27;
   savemat(fp_mat, 'd', "i_n_mrms", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 28;
   savemat(fp_mat, 'd', "i_n_brms", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 29;
   savemat(fp_mat, 'd', "i_n_outlier", 1, 1, 0, (char *) &id, (char *) NULL);
}


#if PROTOTYPE_ALLOWED
void write_att(USER_BUFFER_1920_TYPE * u, double dd)
#else
void write_att(u, dd)
   USER_BUFFER_1920_TYPE *u;
   double dd;
#endif
{

   extern double att[];
   extern MAT_ARRAY_FP_TYPE *mat_att_ptr;
   /* double day;
      day = dec_day(u->fix[0].gps_seconds, dd);
      att[0] = day; ef-- 94/12/11 */
   att[0] = dd;
   att[1] = u->fix[0].lat;
   att[2] = u->fix[0].lon;
   att[3] = u->att.dh_mean * 0.01;
   att[4] = u->att.dh_std * 0.01;
   att[5] = u->att.dh_min * 0.01;
   att[6] = u->att.dh_max * 0.01;
   att[7] = u->att.p_mean * 0.01;
   att[8] = u->att.p_std * 0.01;
   att[9] = u->att.p_min * 0.01;
   att[10] = u->att.p_max * 0.01;
   att[11] = u->att.r_mean * 0.01;
   att[12] = u->att.r_std * 0.01;
   att[13] = u->att.r_min * 0.01;
   att[14] = u->att.r_max * 0.01;
   att[15] = u->att.mrms_mean * 0.1;
   att[16] = u->att.mrms_std * 0.1;
   att[17] = u->att.mrms_min * 0.1;
   att[18] = u->att.mrms_max * 0.1;
   att[19] = u->att.brms_mean * 0.1;
   att[20] = u->att.brms_std * 0.1;
   att[21] = u->att.brms_min * 0.1;
   att[22] = u->att.brms_max * 0.1;
   att[23] = u->att.n_att;
   att[24] = u->att.n_used;
   att[25] = u->att.n_reacq;
   att[26] = u->att.n_mrms;
   att[27] = u->att.n_brms;
   att[28] = u->att.n_outlier;

   tonan_d(att, att, N_A_VAR);
   add_to_mat_array(mat_att_ptr, (char *) att);
   return;
}

#if PROTOTYPE_ALLOWED
void write_fix_indices(void)
#else
void write_fix_indices()
#endif
{
   extern FILE *fp_fix_att;
   double id;

   id = (double) 1;
   savemat(fp_fix_att, 'd', "i_fix1_day", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 2;
   savemat(fp_fix_att, 'd', "i_fix1_lat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 3;
   savemat(fp_fix_att, 'd', "i_fix1_lon", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 4;
   savemat(fp_fix_att, 'd', "i_fix1_height", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 5;
   savemat(fp_fix_att, 'd', "i_fix1_dop", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 6;
   savemat(fp_fix_att, 'd', "i_fix1_nsat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 7;
   savemat(fp_fix_att, 'd', "i_fix1_msg_type", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 8;
   savemat(fp_fix_att, 'd', "i_fix1_quality", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 9;
   savemat(fp_fix_att, 'd', "i_fix2_day", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 10;
   savemat(fp_fix_att, 'd', "i_fix2_lat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 11;
   savemat(fp_fix_att, 'd', "i_fix2_lon", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 12;
   savemat(fp_fix_att, 'd', "i_fix2_height", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 13;
   savemat(fp_fix_att, 'd', "i_fix2_dop", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 14;
   savemat(fp_fix_att, 'd', "i_fix2_nsat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 15;
   savemat(fp_fix_att, 'd', "i_fix2_msg_type", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 16;
   savemat(fp_fix_att, 'd', "i_fix2_quality", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 17;
   savemat(fp_fix_att, 'd', "i_fix3_day", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 18;
   savemat(fp_fix_att, 'd', "i_fix3_lat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 19;
   savemat(fp_fix_att, 'd', "i_fix3_lon", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 20;
   savemat(fp_fix_att, 'd', "i_fix3_height", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 21;
   savemat(fp_fix_att, 'd', "i_fix3_dop", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 22;
   savemat(fp_fix_att, 'd', "i_fix3_nsat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 23;
   savemat(fp_fix_att, 'd', "i_fix3_msg_type", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 24;
   savemat(fp_fix_att, 'd', "i_fix3_quality", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 25;
   savemat(fp_fix_att, 'd', "i_fix4_day", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 26;
   savemat(fp_fix_att, 'd', "i_fix4_lat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 27;
   savemat(fp_fix_att, 'd', "i_fix4_lon", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 28;
   savemat(fp_fix_att, 'd', "i_fix4_height", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 29;
   savemat(fp_fix_att, 'd', "i_fix4_dop", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 30;
   savemat(fp_fix_att, 'd', "i_fix4_nsat", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 31;
   savemat(fp_fix_att, 'd', "i_fix4_msg_type", 1, 1, 0, (char *) &id, (char *) NULL);
   id = (double) 32;
   savemat(fp_fix_att, 'd', "i_fix4_quality", 1, 1, 0, (char *) &id, (char *) NULL);

}

#if PROTOTYPE_ALLOWED
void write_fix(USER_BUFFER_1920_TYPE * u, double dd)
#else
void write_fix(u, dd)
   USER_BUFFER_1920_TYPE *u;
   double dd;
#endif
{

   extern double fix[];
   extern MAT_ARRAY_FP_TYPE *mat_fix_ptr;
   double day;
   int i, j;

   for (i = 0, j = 0; i < 4; i++)
   {
      day = dec_day(u->fix[i].gps_seconds, dd);
      fix[j++] = day;
      fix[j++] = u->fix[i].lat;
      fix[j++] = u->fix[i].lon;
      fix[j++] = u->fix[i].height;
      fix[j++] = u->fix[i].dop;
      fix[j++] = u->fix[i].nsat;
      fix[j++] = u->fix[i].msg_type;
      fix[j++] = u->fix[i].quality;
   }

   tonan_d(fix, fix, N_F_VAR);
   add_to_mat_array(mat_fix_ptr, (char *) fix);
   return;
}
