#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* 16042013
- AUX included
- only determination of mean lat/long at cube start with valid GPS
- start w/o GPS now converted correctly
- fix problem handling "bad" files

xx102014 - disable outlier detection through shift expectation
11112014 - eliminate repetitive GPS tags
14092015 - exclude +-20mks instead of +-10 tshift around 0 or 1/SRATE
23092015 - added gps_check to processing pipe: statistical GPS tag analysis
26112015 - replace spaces by _ in experiment names

*/

/* global variables */

#include "cube.h"


void main(argc,argv)
int argc;
char **argv;
{  
  char 			*filename;
  FILE			*fp;
  unsigned char         byte, upper, lower, sbyte, xbyte, unit;
  long			nsample,nofvpps,b_count,ecount,header_length,i,ch,sample_tag,ibuf,ibufold,stream_written,ib;
  unsigned char		b4[4],b2[2],b3[3];
  int			**data,value,dhc,end_of_file_header,skip_next,i2;
  int			last_day,minimum_gps_counts;
  double		tshift,tshift_old,tshift_old2,adrift;
  char			gpsstring[77];


  int			first_gps, gps_not_valid, gpsoffset_flag,gpsoffset_test,gpsoffset,gps_source,gpscount,data_beyond_gps,diag,gps_age,check_for_gps_moved;
  int			gps_lat,gps_lon,gps_lat_mean,gps_lon_mean,gps_t_only,gps_utc_valid,gps_string_only,shifts_only,first_valid_pps;
  long			sec,mksec,n_gps,last_sample_with_time;
  long			first_sample_wg,sec1st,mksec1st,gps_error_count,ix1,gps_raw_mode;
  char			d[100],gps_id[1],temperature[5],elevation[6];  
  short			code,problem,ssize;
  int			obh_mode,auxout_write,a_new,b_new,first,diagnostics;

  FILE			*auxout;
  char                  *aux_file_name = NULL;

extern char *optarg;
extern int optind, opterr, optopt;
   int c,errflg; 


/* time */
  time_t t_new,t;
  struct tm ts,*ptime,*ptimex;   


/* testing */
  char			help[1000],dheader[100][1000],hh[1000];
  double		f1, f1x,last_f1,fold,tofvpps,drift,b,difference;


   putenv ("TZ=GMT");
   tzset; 
   obh_mode=0;               
   problem=0;
   errflg=0;
   gps_t_only=0;
   gps_raw_mode=0;
   gps_utc_valid=0;
   gps_string_only=0;
   data_beyond_gps=0;
   diag=0;
   shifts_only=0;
   tshift_old=1000000.0;
   tshift_old2=1000000.0;
   first_valid_pps=0;
   gpsoffset =-1;
   minimum_gps_counts = 20;
   auxout_write=0;
   gps_lat_mean=0;
   gps_lon_mean=0;
   check_for_gps_moved=1;
   ts.tm_year=0;
   ts.tm_mon=0;
   ts.tm_mday=1;
   ts.tm_hour=0;
   ts.tm_min=0;
   ts.tm_sec=0;
   skip_next=0;
   diagnostics=0;

   opterr=0; while ((c = getopt (argc, argv, "x:f:a:ugtdsmic")) != -1)
   switch (c)
       { case 'f':        /* get auxout filename */
	    aux_file_name = optarg; 
	    auxout=fopen(aux_file_name, "w");
            if (auxout == NULL)
            {
              printf("Cannot open AUX dump file %s %s \n", aux_file_name,optarg);
              exit(1);
            }
	    auxout_write=1;
	    break;
         case 'x':        /* get minimum GPS counts before valid, defaults = 20 */
/* does not work !!!!!!!!!!!!!!!!!!!!!*/
	    minimum_gps_counts = atoi(optarg);
	    break;
          case ':':       /* -o operand */
            fprintf(stderr,"%s ERROR: Option -%c requires an operand\n", argv[0], optopt);
            errflg++;
            break;
          case 'u':        /* UTC offset valid data only */
            gps_utc_valid=1;            	    
            break;
          case 'g':        /* dump gps strings only */
            gps_string_only=1;            
	    break;
          case 't':        /* gps_t_only timing info only */
            gps_t_only=1;               
	    break;
          case 'd':        /* diagnostic info */
	    diag=1;                          
	    break;
          case 'a':        /* append data beyond last GPS fix assumed drift of xx ms/day */
            data_beyond_gps=1;
  	    adrift = atof(optarg);
	    break;
          case 's':        /* OBH mode, does not check for GPS timing problems */
            obh_mode=1;               
	    break;
          case 'm':        /* does not check if cube moved */
            check_for_gps_moved=0;               
	    break;          
	  case 'i':        /* dump hardware diagnostic infos */
            diagnostics=1;            
	    break;
          case 'c':        /* no check of GPS tags */
            obh_mode=1;   
            minimum_gps_counts=0;
	    gps_raw_mode=1;
	    break;
          case '?':
            fprintf(stderr,"%s ERROR: Unrecognized option: -%c\n", argv[0], optopt);
            errflg++;
        }

    if (errflg) {
        fprintf(stderr, "Version %s\nusage: pcube2asc_mc -o gps_utc_offset value < stdin\n\t[-u time tags only with valid UTC/GPS shifts]\n\t[-a value - output data beyond last GPS fix assuming drift of xx ms/day]\n\t[-g output GPS strings only]\n\t[-t time tags only]\n\t[-d diagnostics]\n\t[-s OBH mode]\n\t[-f filename AUX out]\n\t[-m CUBE_moved_mode]\n",VERSION);
        exit(2);
    }


 /* get ASCII header */
  b_count = 0;
  byte=0;
  help[0]='\0';
  for (i=0; i<100; i++) dheader[i][0]='\0';
  dhc=0;
/*  while ( byte != 128) */
/*  while (( byte != 128 ) && ( byte != 207 ) && ( byte != 192 )) */
  while (( byte < 128 ) || ( byte==240 ))
  {
	code=fread(&byte,1,1,stdin); 
	if ((byte != 240) && (byte != 128) && ( byte != 207 ) && ( byte != 192 ))
	{	
		if ( byte == 32 ) {byte=95;} /* replaces spaces by _ in entry */		
		if ( byte == 61 ) {byte = 32;}
		if ( byte == 59 ) {byte = 32;}
		strncat(help,&byte,1);
 		if ( byte == 32 ) 
		{		
			dhc++;	
		} else
		{
			strncat(dheader[dhc],&byte,1);
		}
	}
	b_count++;
	if (code==0) { fprintf(stderr,"%s ERROR: no header/data in stream\n",argv[0]); exit(200);} 
  }

/* scan string for header values */
  for (i=0; i<=dhc/2; i++) 
  {
	if (!strcmp(dheader[2*i], "GIPP_V")) strcpy(GIPP_V, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "DEV_NO")) strcpy(DEV_NO, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "E_NAME")) strcpy(E_NAME, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "GPS_PO")) strcpy(GPS_PO, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "S_TIME")) strcpy(S_TIME, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "S_DATE")) strcpy(S_DATE, dheader[2*i+1]);
	if (!strcmp(dheader[2*i], "DAT_NO")) strcpy(DAT_NO, dheader[2*i+1]); 

	if (!strcmp(dheader[2*i], "P_AMPL")) {strcpy(hh, dheader[2*i+1]); P_AMPL=atoi(hh);}
	if (!strcmp(dheader[2*i], "CH_NUM")) {strcpy(hh, dheader[2*i+1]); CH_NUM=atoi(hh);}
	if (!strcmp(dheader[2*i], "S_RATE")) {strcpy(hh, dheader[2*i+1]); S_RATE=atoi(hh);}
	if (!strcmp(dheader[2*i], "D_FILT")) {strcpy(hh, dheader[2*i+1]); D_FILT=atoi(hh);}
	if (!strcmp(dheader[2*i], "C_MODE")) {strcpy(hh, dheader[2*i+1]); C_MODE=atoi(hh);}
	if (!strcmp(dheader[2*i], "A_CHOP")) {strcpy(hh, dheader[2*i+1]); A_CHOP=atoi(hh);}
	if (!strcmp(dheader[2*i], "F_TIME")) {strcpy(hh, dheader[2*i+1]); F_TIME=atoi(hh);}
	if (!strcmp(dheader[2*i], "GPS_TI")) {strcpy(hh, dheader[2*i+1]); GPS_TI=atoi(hh);}
	if (!strcmp(dheader[2*i], "GPS_OF")) {strcpy(hh, dheader[2*i+1]); GPS_OF=atoi(hh);}
	if (!strcmp(dheader[2*i], "A_FILT")) {strcpy(hh, dheader[2*i+1]); A_FILT=atoi(hh);}
	if (!strcmp(dheader[2*i], "A_PHAS")) {strcpy(hh, dheader[2*i+1]); A_PHAS=atoi(hh);}
	if (!strcmp(dheader[2*i], "GPS_ON")) {strcpy(hh, dheader[2*i+1]); GPS_ON=atoi(hh);}
	if (!strcmp(dheader[2*i], "ACQ_ON")) {strcpy(hh, dheader[2*i+1]); ACQ_ON=atoi(hh);}
	if (!strcmp(dheader[2*i], "PLL_XO")) {strcpy(hh, dheader[2*i+1]); PLL_XO=atoi(hh);}
	if (!strcmp(dheader[2*i], "AQ_MOD")) {strcpy(hh, dheader[2*i+1]); AQ_MOD=atoi(hh);}
	if (!strcmp(dheader[2*i], "V_TCXO")) {strcpy(hh, dheader[2*i+1]); V_TCXO=atoi(hh);}
	if (!strcmp(dheader[2*i], "D_VOLT")) {strcpy(hh, dheader[2*i+1]); D_VOLT=atoi(hh);}
	if (!strcmp(dheader[2*i], "E_VOLT")) {strcpy(hh, dheader[2*i+1]); E_VOLT=atoi(hh);}
	if (!strcmp(dheader[2*i], "B_VOLT")) {strcpy(hh, dheader[2*i+1]); B_VOLT=atoi(hh);}
  }



fprintf(stderr,"BOS: "STR_FORMAT"\n",PR_STR);


if (( gps_t_only == 0 ) && ( gps_string_only == 0 )) fprintf(stdout,STR_FORMAT"\n",PR_STR);

/*
fprintf(stdout,"%s %s %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s %s %s %d %d\n",GIPP_V,DEV_NO,E_NAME,P_AMPL,CH_NUM,S_RATE,D_FILT,C_MODE,A_CHOP,F_TIME,GPS_TI,GPS_OF,A_FILT,A_PHAS,GPS_ON,ACQ_ON,V_TCXO,GPS_PO,S_TIME,S_DATE,D_VOLT,E_VOLT);

*/

/* allocating arrays for the CH_NUM time series */
  if (!(data = malloc (CH_NUM * sizeof(int)))) { fprintf(stderr, "%s ERROR: malloc failed, not enough core memory\n",argv[0]); exit(0); }
  for (ch = 0; ch < CH_NUM; ch++) if (!(data[ch] = malloc (MXSMP * sizeof(int)))) { fprintf(stderr, "%s ERROR: malloc failed, not enough core memory\n",argv[0]); exit(0); }




  gpsoffset_flag = 1;
/*  gpsoffset=15; */

  stream_written=0;



/* ini */

  nsample = 0;
  ibuf=0;
  first_gps = 1;
  fold = 0;
  f1=-1.0;
  n_gps=0;
  end_of_file_header=0;		
  last_day=32;
  first=1;


/* ------------------------------------------ main loop ------------------------------------------*/
  do    
  {
	skip_next=0;
	upper = byte >> 4;
/* fprintf(stdout,"---- %d %d %d\n",b_count, byte, upper); */
	switch (byte)
	{
	case  0x90: /* mark sample with PPS */
/*	 	fprintf(stderr,"%d flag = %d %d\n",b_count,upper,nsample); 	*/			
		sample_tag=ibuf;
	case  0x80: /* interprete sample */
/*	 	fprintf(stderr,"%d flag = %d %d\n",b_count,upper,nsample); */		
		for (ch=0; ch<CH_NUM; ch++)
		{
			fread(&b4,1,4,stdin); b_count=b_count+4;
			value = (int) (131072*b4[0]+1024*b4[1]+8*b4[2]+b4[3]);
			if (value > 8388607) value = value - 16777216;

/*		fprintf(stderr,"%d %d %d %d %d %d\n",b1,b2,b3,b4,value,value2); */
			data[ch][ibuf]=value; 
		} 
/* mark sample with PPS */
		if ( diag == 0 ) ibuf++;		
		if (ibuf>=MXSMP) { fprintf(stderr,"%s ERROR: max number of sample w/o GPS exceeds %ld, increase MXSMP in cube.h and recompile\n",argv[0], MXSMP); exit(200); }
		if (ibuf==(S_RATE*21600L))  { fprintf(stderr,"Warning: no GPS signal for more than 6 hours!\n");}
		if (ibuf==(S_RATE*86400L))  { fprintf(stderr,"Warning: no GPS signal for more than 1   day!\n");}
		if (ibuf==(S_RATE*864000L)) { fprintf(stderr,"Warning: no GPS signal for more than 10 days!\n");}
		nsample++;
		break;
	case 0xa0: /* GPS block */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
/* get GPS string */
		fread(&gpsstring,1,76,stdin); b_count=b_count+76;
/* get time from GPS fix */		
		memset(&ts,'\0',sizeof(struct tm)); /* ini ts !!!! */
		help[0]='\0'; for (i=56; i<60; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%4d", &ts.tm_year); ts.tm_year=ts.tm_year-1900;
		help[0]='\0'; for (i=54; i<56; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &ts.tm_mon);  ts.tm_mon=ts.tm_mon-1;
		help[0]='\0'; for (i=52; i<54; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &ts.tm_mday);
		help[0]='\0'; for (i=47; i<49; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &ts.tm_sec);
  		help[0]='\0'; for (i=45; i<47; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &ts.tm_min);
  		help[0]='\0'; for (i=43; i<45; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &ts.tm_hour); 
		t_new = mktime(&ts);
		if ( problem == 1 )
		{	
			ptimex = localtime(&t_new); 
			fprintf(stderr,"%s ERROR: Cube %s timing problem until %4d-%02d-%02dT%02d:%02d:%02d\n",argv[0],DEV_NO,(int) (ptimex->tm_year+1900),(int) (ptimex->tm_mon+1),(int) (ptimex->tm_mday),(int) (ptimex->tm_hour),(int) (ptimex->tm_min),(int) (ptimex->tm_sec));
			problem=0;
		}

/* get GPS fix attributes */
                help[0]='\0'; for (i=65; i<66; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%1d", &gpsoffset_flag); 
                help[0]='\0'; for (i=60; i<62; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%2d", &gpsoffset_test); 
                help[0]='\0'; for (i=62; i<63; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%1d", &gps_source); 
                help[0]='\0'; for (i=32; i<33; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%1d", &gps_source); /*second copy */
                help[0]='\0'; for (i=33; i<34; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%1d", &gps_age); 
/* dirty !! check if GPS source is 2D or 3D , if not reset gps_age*/
		if ((gps_source==0) || (gps_source==1)) {gps_age=gps_age;} else {gps_age=0;}




/* get lat/long degrees */
  		help[0]='\0'; for (i=18; i<21; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%3d", &gps_lon);
  		help[0]='\0'; for (i=10; i<12; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%4d", &gps_lat);
/* get GPS extra info */
		strcpy(temperature, "-99.9"); 
		strcpy(elevation, "-99999"); 
  		help[0]='\0'; for (i=1; i<2; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%1s", (char *) &gps_id);
		if ( gps_id[0]=='X') 
		{  		
			help[0]='\0'; for (i=4; i<9; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%5s", (char *) &temperature);
			help[0]='\0'; for (i=26; i<32; i++) strncat(help,&gpsstring[i],1); sscanf(help, "%6s", (char *) &elevation);
		}

/* calc lat/long mean up to now */
		if ( gps_age == 2 ) 
		{
			if ( n_gps == 0 )
			{
				gps_lat_mean=gps_lat;
				gps_lon_mean=gps_lon;
			}
			else 
			{
/* take only the first 100 GPS fixes to calculate mean */
				if (n_gps<100) 
				{
					gps_lat_mean=(int) (gps_lat_mean*n_gps+gps_lat)/(n_gps+1);
					gps_lon_mean=(int) (gps_lon_mean*n_gps+gps_lon)/(n_gps+1);
				}
			}
			n_gps++;
		}
/* GPS-UTC offset removal */
		t_new = t_new + gpsoffset_test;
/* output GPS only */
		if ( gps_string_only == 1 ) 
		{
			help[0]='\0'; for (i=0; i<76; i++) strncat(help,&gpsstring[i],1); 
			ptimex = localtime(&t_new); 
			fprintf(stdout,"%76s  %5s %6s %ld %4d-%02d-%02dT%02d:%02d:%02d\n",help,temperature,elevation,t_new,(int) (ptimex->tm_year+1900),(int) (ptimex->tm_mon+1),(int) (ptimex->tm_mday),(int) (ptimex->tm_hour),(int) (ptimex->tm_min),(int) (ptimex->tm_sec));
		}

/* output warning when leapsecond detected */
		if ( gpsoffset_flag == 1 ) 
		{ 
			if (( gpsoffset != gpsoffset_test ) && (gpsoffset != -1) ) {fprintf(stderr, "Warning: GPS UTC offset changed from %d to %d during recording\n",gpsoffset,gpsoffset_test);} 
		}
		gpsoffset = gpsoffset_test;
/* get tshift from delay time block */
		fread(&byte,1,1,stdin); b_count++;
		if ( (byte >> 4) != 11 ) 
		{ 
			fprintf(stderr, "%s ERROR: no t shift after GPS string, data stream not valid\n",argv[0]); 		
			fprintf(stdout,"%ld ",-1L);		
			for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",0);
			fprintf(stdout,"%ld %ld\n",0L,0L);  
			exit(100); 
		}
		fread(&b2,1,2,stdin); b_count=b_count+2;
		tshift=(double) (b2[0]*128+b2[1])*2.44140625;

/* sub sample time shifts > 1/srate Error 
		if (tshift>1000000.0/S_RATE) 
		{ 
 fprintf(stderr,"XXX tshift %f %f\n",tshift,1000000.0/S_RATE); 
		}
*/


		fold=f1;
		f1=(double) (t_new + tshift/1000000.0 - 1.0/S_RATE * D_FILT);

/*     ----------- begin of GPS evaluation  ------------------- */
/* conditions for GPS valid */
		gps_not_valid=0;

/* check for repetitive GPS tags with the same time */
		if (fold==f1) 
		{
			fprintf(stderr, "Warning : repetitive GPS tag(s) around %4d-%02d-%02dT%02d:%02d:%02d\n",ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec);
			gps_not_valid=1;  
			gpscount=0;
		}
/* check GPS source if not in OBH mode */
		if (gps_raw_mode == 0) { if ( obh_mode == 0 ) if ( gps_age != 2 ) {gps_not_valid=1; }}
/* first GPS fix? */
		if (gps_raw_mode == 0) { if ( first_gps == 1 ) {gps_not_valid=1;} }
/* midnight boundary, drop a GPS tags 100 secondeds before and after midnight if not in OBH mode */ 
		if (gps_raw_mode == 0) { if ( ((t_new % 86400L) < 100) || ((t_new % 86400L) > (86400-100))) {gps_not_valid=1;} }
/* time difference betw. GPS fixes greater than gap (1sec) */
		if ( sqrt((f1-fold)*(f1-fold)) > 1.5 ) {gps_not_valid=1; gpscount=0;} 
/* need at least minimum_gps_counts GPS fixes to be valid */
		gpscount++;
		if (gps_raw_mode == 0) {if (gpscount < minimum_gps_counts ) {gps_not_valid=1;}} 
/* check sub sample shift if not in OBH mode */
		if (gps_raw_mode == 0) 
		{
			if ( obh_mode == 0 )
			{
/* sub sample time shift needs to be greater than 20kms */
				if ( tshift < 20 ) {gps_not_valid=1;} 
/* sub sample time shift needs to be smaller than 1/srate-20mks */
				if ((tshift > (1000000.0/S_RATE - 20)) && (tshift < (1000000.0/S_RATE + 1))) {gps_not_valid=1;} 
			}
		}

/* position of fix needs to be within 1 degree of average fixes if not in OBH mode */
		if (gps_raw_mode == 0) 
		{
			if ((sqrt((gps_lat_mean-gps_lat)*(gps_lat_mean-gps_lat)+(gps_lon_mean-gps_lon)*(gps_lon_mean-gps_lon))>2.0) && (gps_age == 2) && ( obh_mode == 0 )) 
			{
				if ( check_for_gps_moved == 1 )
				{ 
					gps_not_valid=1;
					fprintf(stderr, "Warning: GPS glitch or station has been moved >100km %d %d %d %d\n",gps_lat_mean,gps_lat,gps_lon_mean,gps_lon);
				}
			} 
		}
/* sub sample time shift needs to be close to previous two values <100mks  if not in OBH mode*/
		if (gps_raw_mode == 0) {if ( obh_mode == 0 ) if ( sqrt((tshift-tshift_old)*(tshift-tshift_old)+(tshift-tshift_old2)*(tshift-tshift_old2)) > 100 ) {gps_not_valid=1; gpscount=0;} }
		tshift_old2=tshift_old;
		tshift_old=tshift;

/* determine GPS glitches by comparing the expected sample numbers based on the actual drift if not in OBH mode */
/* search for first valid GPS */
		if (gps_raw_mode == 0) 
		{
			if ((gps_not_valid==0) && (obh_mode == 0))	 
			{		
				if (first_valid_pps==0)
				{
					first_valid_pps=1;
					tofvpps=f1;
					nofvpps=nsample;
				}
/* wait long enough to calculate average clock drift */
				if (first_valid_pps==1)
				{
					if ((f1-tofvpps)<3600.0)
					{
						drift=0;
						if (nsample!=nofvpps) drift=(f1-tofvpps)/(nsample-nofvpps);
						b=f1-drift*nsample;
					}
				}
		}
/* evaluate PPS time after waiting for 3600 seconds */
/* switch off !!!!!!!!!!!!!!!
			if ((first_valid_pps==1) && ((f1-tofvpps)>3600.0))
			{
				difference=(drift*nsample+b-f1);
				if (sqrt(difference*difference)<1.0/S_RATE)
				{
					drift=0;
					if (nsample!=nofvpps) drift=(f1-tofvpps)/(nsample-nofvpps);
					b=f1-drift*nsample;
					gps_error_count=0;
				}
				else
				{
					if ( obh_mode == 0 )
					{
						gps_error_count=gps_error_count+1;
						gps_not_valid=1;	
						gpscount=0;
						ix1=1;
						while ( ix1 <= gps_error_count )
						{
							if ( ix1 == gps_error_count ) fprintf(stderr, "Warning : potential GPS timing problem at %4d-%02d-%02dT%02d:%02d:%02d value=%lf occured %d times\n",ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec,difference,gps_error_count);
							ix1=ix1*10;
						}
					}
				}
			}
*/
		}

		if (gps_raw_mode == 0) {if (( gps_utc_valid == 1 ) && ( gpsoffset_flag == 0 )) {gps_not_valid=1;} }

/*     ----------- end of GPS evaluation  ------------------- */

/* output diagnostics: GPS & timing  */
		if ( diag == 1 )
		{
			help[0]='\0'; for (i=0; i<76; i++) strncat(help,&gpsstring[i],1);					
			sec=(long) (floor(f1));
			mksec = (long) (floor((f1-floor(f1))*1000000.0)); 
			fprintf(stdout,"D %76s %ld %ld %ld %4d-%02d-%02dT%02d:%02d:%02d %d %ld %d\n",help,t_new,sec,mksec,ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec,b2[0]*128+b2[1],nsample,gps_not_valid);  
		}

/* output of data if GPS time stamp was OK */
 if ( gps_not_valid == 1 )  
{
sec=(long) (floor(f1));
mksec = (long) (floor((f1-floor(f1))*1000000.0));
ptime = localtime(&sec); 

/*
fprintf(stderr,"XXX %4d-%02d-%02dT%02d:%02d:%02d\n",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec));
*/

}
		if (( gps_not_valid == 0 ) && ( diag == 0 ))
		{

			for ( i=0; i<ibuf; i++ )
			{
				if ( sample_tag == i ) 
				{
/* alte version */
					sec=(long) (floor(f1));
					mksec = (long) (floor((f1-floor(f1))*1000000.0));
					if ( gps_string_only == 0 ) 
					{	
						stream_written=1;
						fprintf(stdout,"%ld ",nsample-ibuf+i);
						last_sample_with_time=nsample-ibuf+i;
						last_f1=f1;
						for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",data[ch][i]);
/*						fprintf(stdout,"%ld %ld %d %d %d %f",sec,mksec,gpscount,minimum_gps_counts,gps_not_valid,tshift); */
						fprintf(stdout,"%ld %ld",sec,mksec);
						if ( gps_t_only == 1 ) 
						{
							ptime = localtime(&sec); 
							fprintf(stdout," %4d-%02d-%02dT%02d:%02d:%02d",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec));
						}
						fprintf(stdout,"\n");
					}
				} else 
				{
					if (( gps_t_only == 0 ) && ( gps_string_only ==0 )) 
					{
						fprintf(stdout,"%ld ",nsample-ibuf+i);
						for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",data[ch][i]);
						fprintf(stdout,"-1 0\n");
					}
				} 
			}
			ibufold=ibuf;
			ibuf=0;
		}
		first_gps = 0;
		fold=f1;
		break;

	case 0xb0: /* delay time block, redundant, is done within case 10 */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		break;
	case 0xc0: /* Event block from 1 byte info, from version 5.0(1C) 2.0(3C) 2 bytes */
		if (diagnostics==1) fprintf(stderr, "Info : %ld %4d-%02d-%02dT%02d:%02d:%02d xC0 value= ",nsample, ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec);
		fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d ",byte);
/* exit because data stream corrupt, buffer overrun */
		if ( byte==1 )
		{	fprintf(stderr, "ERROR: CUBE buffer overrun detected, conversion aborted! : %ld %4d-%02d-%02dT%02d:%02d:%02d\n",nsample, ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec);
			fprintf(stdout,"%ld ",-1L);		
			for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",0);
			fprintf(stdout,"%ld %ld\n",0L,0L);  			
			exit(127);     		
		}


		fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d\n",byte);
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		break;
	case 0xcf: /* diagnostics x bytes*/
		if (diagnostics==1) fprintf(stderr, "Info : %ld %4d-%02d-%02dT%02d:%02d:%02d xCF value= ",nsample, ts.tm_year+1900,ts.tm_mon+1,ts.tm_mday,ts.tm_hour,ts.tm_min,ts.tm_sec);


		upper=0;
    		while (( upper < 8 ) && (!feof(stdin)))
		{	
			fread(&byte,1,1,stdin); 
			b_count++; 			
			upper = byte >> 4;
			if (upper < 8 ) if (diagnostics==1) fprintf(stderr,"%d ",byte);                

		}
		skip_next=1;
/*

			fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d ",byte);  
			fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d ",byte);  
  			fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d ",byte);  
  			fread(&byte,1,1,stdin); b_count++; if (diagnostics==1) fprintf(stderr,"%d ",byte);  
*/

		if (diagnostics==1) fprintf(stderr,"\n");
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		break;
	case 0xd0: /* Info Block ASCII */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		break;
	case 0xd1: /* AUX channel */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		fread(&sbyte,1,1,stdin); b_count++;
		upper = sbyte >> 4;
/* mask 1st bit */
		upper = upper & 7 ;
		lower=(sbyte & 15)-2;
/* get apr. time of AUX event */
		f1x=f1+ibuf*1.0/S_RATE;
		if (first_valid_pps==0) {f1x=0;}
		sec=(long) (floor(f1x));
		mksec = (long) (floor((f1x-floor(f1x))*1000.0));
		ptime = localtime(&sec); 
/* fprintf(auxout,"\nXXX %d byte = %d upper=%d lower =%d \n",b_count,sbyte,upper,lower); */
		switch (upper)
		{
			case 4: /* ASCII new */
/*				fprintf(stderr,"ASCII string start %d byte = %d lower =%d",b_count,sbyte,lower); 	*/			
				for (ib=0; ib<lower; ib++) 
				{
					fread(&xbyte,1,1,stdin); b_count++;
					if (auxout_write==1) 
					{						
						if (first==1) fprintf(auxout,"\n%4d-%02d-%02dT%02d:%02d:%02d.%03d ",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec),(int) mksec);						
						fprintf(auxout,"%1c",(char) xbyte);
					}						
					first=0;						
				}						
				if (auxout_write==1) fprintf(auxout," ");
				first=1;		
				break;
			case 6: /* ASCII extension follows */
				for (ib=0; ib<lower; ib++) 
				{
					fread(&xbyte,1,1,stdin); b_count++;
					if (auxout_write==1) 
					{						
						if ( first==1 ) fprintf(auxout,"\n%4d-%02d-%02dT%02d:%02d:%02d.%03d ",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec),(int) mksec);						
						fprintf(auxout,"%1c",(char) xbyte);
					}						
					first=0;						
				}				
				if (auxout_write==1) fprintf(auxout," ");				
				break;

			case 0: /* Binary new */
/*				fprintf(stderr,"BINARY string start %d byte = %d lower =%d",b_count,sbyte,lower); 	*/			
				lower=lower/4; /* number of binary samples */
				for (ib=0; ib<lower; ib++) 
				{
					fread(&xbyte,1,1,stdin); b_count++;
					unit=xbyte & 127; /* to be interpreted later*/
					fread(&b3,1,3,stdin); b_count=b_count+3;
					value = (int) (16384*b3[0]+128*b3[1]+b3[2]); 
					if (value > 1048575 ) value=value - 2097152 ;  
					if (auxout_write==1) 
					{
//						if ( first==1 ) fprintf(auxout,"\n%4d-%02d-%02dT%02d:%02d:%02d.%03d ",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec),(int) mksec);
//						fprintf(auxout,"%d %s ",value,aux_units[unit-1]);					
						first=0;						
					}				
					first=0;
				}
				first=1;
				break;
			
			case 2: /* Binary extension follows */
				lower=lower/4; /* number of binary samples */
				for (ib=0; ib<lower; ib++) 
				{
					fread(&xbyte,1,1,stdin); b_count++;
					unit=xbyte & 127; /* to be interpreted later*/
					fread(&b3,1,3,stdin); b_count=b_count+3;
					value = (int) (16384*b3[0]+128*b3[1]+b3[2]);
					if (value > 1048575 ) value=value - 2097152 ;  
					if (auxout_write==1) 
					{
						if ( first==1 ) fprintf(auxout,"\n%4d-%02d-%02dT%02d:%02d:%02d.%03d ",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec),(int) mksec);
						fprintf(auxout,"%d %s ",value,aux_units[unit-1]);
					}				
					first=0;
				}
				break;


		}
		break;
	case 0xe0: /* End Block */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */
		help[0]='\0';
  		for (i2=0; i2<100; i2++) dheader[i2][0]='\0';
  		dhc=0;
/* skip 1st empty byte 
		fread(&byte,1,1,stdin); b_count++;*/
		do
		{  	
			fread(&byte,1,1,stdin); 
			if ((byte != 240) && (byte != 128))
			{
				if ( byte == 61 ) {byte = 32;}
				if ( byte == 59 ) {byte = 32;}
				if ( byte == 239 ) {byte = 32;}	
				if ( byte == 13 ) {byte = 32;}	
				if ( byte == 10 ) {byte = 32;}	
				strncat(help,&byte,1);		
				if ( byte == 32 ) 		
				{		
					dhc++;	
				} else
				{
					strncat(dheader[dhc],&byte,1);
				}
			}
			b_count++;
			end_of_file_header=1;
		} while ( !feof(stdin) );
		dhc=dhc-0;
		fprintf(stderr,"EOS: %s\n",help);
/*		for (i2=0; i2<=dhc; i2++) fprintf(stderr,"--- %d %s \n",dhc,dheader[i2]); */
		break;
	case 0xef: /* Header Block */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper); */			
		break;
	case 0xf0: /* Header Block */
/*		fprintf(stderr,"%d flag = %d\n",b_count,upper);*/
		break;

    } /* end of case */	
/* get next byte */
    if (( end_of_file_header == 0 ) && ( skip_next == 0 ))
    {
        fread(&byte,1,1,stdin);
    	b_count++;	
        upper = byte >> 4;
	ecount=0;
/* check if this the abnormal end of data stream */
	if (feof(stdin)) fprintf(stderr,"Warning: Cube %s data acquisition stopped abruptly\n",DEV_NO);
/* check if this is a header byte */
    	while (( upper == 0 ) && (!feof(stdin)))
    	{
		ecount=ecount+1;
/*      		fprintf(stderr,"Byte problem at position %d, data possibly skipped!\n",b_count); */
      		fread(&byte,1,1,stdin); 
      		b_count++;	  
      		upper = byte >> 4;
		ptime = localtime(&sec); 
		if ( upper != 0 ) 
		{
			fprintf(stderr,"%s ERROR: Cube %s timing problem from  %4d-%02d-%02dT%02d:%02d:%02d with block problem at position %ld occured %ld times\n",argv[0],DEV_NO,(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec),b_count-ecount,ecount);

		problem=1;
		}
/*
		if ( upper != 0 ) fprintf(stderr,"ERROR: Cube %s with block problem at position %d occured %d times!\n",DEV_NO,b_count-ecount,ecount);
*/
    	}
    }
  } while ( !feof(stdin) );
/* end of reading loop */

/* output of data beyond last GPS */
	if (data_beyond_gps==1)
	{
		for ( i=0; i<ibuf-1; i++ )
		{
			if ( gps_t_only == 0 )
			{
				fprintf(stdout,"%ld ",nsample-ibuf+i);
				for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",data[ch][i]);
				fprintf(stdout,"-1 0");
				fprintf(stdout,"\n");
			}
		}
		f1=last_f1+(double) (nsample-1-last_sample_with_time)/S_RATE;
// correct for assumed drift
		f1=f1+ (nsample-1-last_sample_with_time)/S_RATE/86400.0*adrift/1000.0;
		sec=(long) (floor(f1));
		mksec = (long) (floor((f1-floor(f1))*1000000.0));

		i=ibuf-1;
		fprintf(stdout,"%ld ",nsample-ibuf+i);
		for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",data[ch][i]);
		fprintf(stdout,"%ld %ld",sec,mksec);
		if ( gps_t_only == 1 ) 
		{
			ptime = localtime(&sec); 
			fprintf(stdout," %4d-%02d-%02dT%02d:%02d:%02d",(int) (ptime->tm_year+1900),(int) (ptime->tm_mon+1),(int) (ptime->tm_mday),(int) (ptime->tm_hour),(int) (ptime->tm_min),(int) (ptime->tm_sec));
		}
		fprintf(stdout,"\n");
	}
/* if no valid data -> end of data token */
	if ((stream_written==0) && ( gps_string_only == 0 ) && ( gps_t_only == 0 ))
	{
		fprintf(stdout,"%ld ",-1L);		
		for (ch=0; ch<CH_NUM; ch++) fprintf(stdout,"%d ",0);
		fprintf(stdout,"%ld %ld\n",0L,0L);      		
		fprintf(stderr,"%s ERROR: No useful data in pcube2asc! Check if input are actually CUBE files\n",argv[0]); 
	}
	if (auxout_write==1) close(auxout);
 }



