// flash_hex2ascii.c
// 25mar08 
// reads in the flash card hex file, created by flash2hex
// i.e., 'D_hex.txt' for data, 'V_hex.txt' for Doppler
// and creates the ascii format ('.raw' file) for distribution.
// 10Mar2010, modified to work on UNIX machine, via spray_files.h
//
// may11 addition for DO SBE43 sensor = one added column
// jan13 addition for DO SBE63 senosr = three added columns

//command line input is:
// flash_hex2ascii YYM SN M_ID C
// where YYM is Year-Month code
// SN = Spray s/n
// M_ID = mission ID for YYM (typ 1)
// C = First character of file name : 'D' = data, 'V' = doppler files.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "base_fnx.h"
#include "spray_files.h" // define spray sub-directories

/* what is used from the spray_files.h 
 char Spray_Data[]      = "k:\\d_spray\\data\\"; 
// define parameters that are OS-dependent 
	char	delim[] = "\\";
*/

// definitions -------------------------------------------
#define PRINT_ENG 1 // print out engineering line
                     
#define DIAG 0 // if=1, will print out ea packet info to screen
#define GPS_MARK 1 // use gps packet def to decide the first # to write out

#define NMAX 3000 // max # dives expected
#define NLINE 512  // max # char per each line


#define   CF_DIVE   0x0f   // dive marker
#define   CF_GPS0   0x00   // GPS record: 0=start-mission
#define   CF_GPS1   0x01   // GPS record: 1=start-dive
#define   CF_GPS2   0x02   // GPS record: 2=end-dive
#define   CF_GPS3   0x03   // GPS record: 3=end-mission
#define   CF_ABORT  0x06   // abort status record

#define   CF_DATA   0x10   // 8s data record, version 0
#define   CF_SBE    0x30   // SBE 1Hz data
#define   CF_ADP    0x50   // ADP profile data
#define   CF_ALT    0x51   // ADP altimeter data
#define   CF_ADPS   0x52   // ADP shallow data
#define   CF_CONT   0xcc   // continuation of the last record
#define   CF_ENG    0xe0   // the engineering packet already contains it's version #
#define   CF_TEST   0xfe   // Test packet

#define   CF_END    0xff   // end-file marker
#define   CF_EOF    -1     // end-of-file
#define   CF_LOST   -2     // parser function is lost
#define   CF_SB     '{'    // CF packet start-byte
#define   CF_EB     '}'    // CF packet end-byte

// globals ------------------------------------------------
struct scan_prm {   // global structure for the scan info
  int   type;       // scan type
  int   dive;       // dive #
  int   nb;         // # of byte in dat[]
  int   dat[NLINE]; // data array of bytes
};
struct scan_prm scan; // info is passed using scan

FILE  *fp_in, *fp_out, *fp_eng;
int   sn, m_id;   // Spray s/n plus mission id = m_id
char  datdir[4]; // YYM of the data directory
char  GPS_Line[200]; // last GPS line read
float YR_Day; // last GPS year-day

// prototypes ---------------------------------------------
int    read_scan       ( void   );
int    rdhex           ( char *ch,     int  num    ); 
int    rd_ushort       ( int dat[],    int i       );
int    rd_short        ( int dat[],    int i       );
float  rd_float        ( int dat[],    int i       );
int    rd_gps          ( void  );
void   rd_dat          ( void  );
void   rd_eng          (  void );
void   kluge_gps_reset ( int dive );


//*****************************************************************************
int main(int argc, char *argv[])   //******************************************
{
	int  dive  = 0; // dive = actual dive #
	int  dive0 = 0; // last dive
	int nb; // nb = #bytes in each record
	int cf_type; // compact-flash scan type
	// int dat[NLINE]; // data (byte per byte) for one scan
	int nscan=0; //#of scans processed
	int gps_phase = -1;  // not valid
	int ip; //=pressure counts in abort mode
	float pr; //pressure in abort mode, guess
	
	char infile[80], outfile[80];
	char cf = 'D'; // default value

   // read in the arguments ----------------------------------------
   switch (argc) //-------------------------------------------------
   { // read in the variables
   		case 5 : sscanf(argv[4],"%c",&cf);
   		case 4 : sscanf(argv[3],"%d",&m_id);
   		case 3 : sscanf(argv[2],"%d",&sn);
   		case 2 : sscanf(argv[1],"%s",datdir);
   } // end switch
   			// now query the rest of the variables
   switch (argc)
   { // query for the rest
   		case 1 :	printf ("Give  3-char date YYM to process\n");
   					scanf("%s",datdir); 
   		case 2 :	printf("Give s/n to process for date %s\n",datdir);
   					scanf("%d",&sn);
   		case 3 :	printf("Give the mission id \n");
   					scanf("%d",&m_id);
   		case 4 :	printf("Give the file-letter type (A,D, or V) \n");
   					scanf("%c",&cf);
   } // end switch ------------------------------------------------
   // -------------------------------------------------------------

	printf("Program will convert %cxxx files from binary to hex\n",cf);


    //open the input file ------------------------------------------
   	sprintf(infile,"%s%s%sSpray%03d_%1d%s%c_hex.txt",
   	       Spray_Data,datdir,delim,sn,m_id, delim, cf); 
	printf("input file is %s\n",infile);
	fp_in = fopen(infile,"r"); 
	if (fp_in==NULL)
	{  
	   printf("Open file failed: %s\n",infile);
	   return 0;
	}
	//--------------------------------------------------------------

    //open the output file ----------------------------------------
   	sprintf(outfile,"%s%s%s%s%03d%02d.raw",
   	       Spray_Data,datdir,delim,datdir,sn,m_id ); 
	printf("output will go to %s\n",outfile);
	fp_out = fopen(outfile,"w"); 
	if (fp_out==NULL)
	{  
	   printf("Open outfile failed: %s\n",outfile);
	   return 0;
	}
	//--------------------------------------------------------------
	//--flash eng. line
   	sprintf(outfile,"%s%s%s%s%03d%02d.eng_raw",
   	       Spray_Data,datdir,delim,datdir,sn,m_id ); 
	printf("eng output will go to %s\n",outfile);
	fp_eng = fopen(outfile,"w"); 
	if (fp_eng==NULL)
	{  
	   printf("Open engfile failed: %s\n",outfile);
	   return 0;
	}
	
	//step thru each input record -----------------------------------------
	//---------------------------------------------------------------------
	//---------------------------------------------------------------------
	scan.dive = 1; // assume the first dive is #1!
	do
	{

		nb = read_scan(); // read in the next scan
		// data is saved in struct scan
    	
    	if (nb>0) // then process the scan
    	{ //nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
    	  cf_type = scan.type; //= scan type id
    	  
    	  switch(cf_type) //ssssssssssssssssssssssssssssssssssssssss
    	  { // dependent upon scan type, write different things
    	    case CF_DIVE: 
    	         if ( gps_phase >=0 ) //last scan was GPS
    	         { fprintf(fp_out,"%s\n",GPS_Line ); gps_phase=-1; }
    	         if (dive>0) dive0 = dive; // keep a copy of the last dive #
    	         // this allows jumping over mid-mission resets where dive=0
    	         dive = rd_ushort(scan.dat,0); // read in the new one
    	         if (dive>0) scan.dive = dive;  //0=mission-start:ignore
    	         else scan.dive = dive0+1;
    	    break;
    	    
    	    case CF_GPS0 : case CF_GPS1 : case CF_GPS2 : case CF_GPS3 :
    	         if ( gps_phase >=0 ) //last scan was GPS
    	         { fprintf(fp_out,"%s\n",GPS_Line );}
    	         gps_phase = rd_gps();  // we have a new line in GPS_Line
    	         break;
    	         
    	    case CF_DATA : 
    	         if ( gps_phase >=0 ) //last scan was GPS
    	         { fprintf(fp_out,"%s\n",GPS_Line ); }
    	         if ( gps_phase == 0 && dive0>0 ) // mid-mission reset
    	           kluge_gps_reset(scan.dive);
    	         gps_phase = -1;
    	         rd_dat();
    	         break;
    	         
    	    case CF_ENG : // can use for debugging
    	         #if PRINT_ENG ==1
    	           rd_eng();
    	         #endif
    	         break;
    	         
    	    case CF_ABORT  : 
    	           ip = scan.dat[0]*256 + scan.dat[1];
    	           pr = (ip -250)*0.04;
    	           if (scan.nb==2) 
    	              printf("abort yr-day=%11.4f P = %8.1f\n",  YR_Day, pr );
    	         break;
    	         
    	    case CF_END  : 
    	         if ( gps_phase !=1 ) //last scan was GPS
    	           fprintf(fp_out,"%s\n",GPS_Line );
    	         // else ignore 1 = dangling GPS before abort
    	         gps_phase = -1; // reset
    	         break;
    	              
    fprintf(fp_out,"%s\n",GPS_Line );
   	         
    	  } //ssssssssssssssssssssssssssssssssssssssssssssssssssssss
    	  
    	  nscan++;
    	} //nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
	} while (nb>-1); //----------------------------------------------------
	//---------------------------------------------------------------------
	//---------------------------------------------------------------------

	printf("%5d scans processed\n", nscan);
	fclose(fp_in);
	fclose(fp_out);
	fclose(fp_eng);


	return 0;
} //***************************************************************************
//*****************************************************************************

int rd_ushort(int dat[],int i) //**********************************************
{ // read two bytes and return unsigned value
  int val=0;
  
  val = dat[i]*256 + dat[i+1]; // msb+lsb
  // printf("%4d %4d %4d\n",val, dat[i], dat[i+1]);
  
  return(val);
} //***************************************************************************

int rd_short(int dat[],int i) //***********************************************
{ // read two bytes and return unsigned value
  int val=0;
  
  val = rd_ushort(dat,i); // unsigned value
  if (val>32767) val -= 65536; // make signed
  
  return(val);
} //***************************************************************************


 float rd_float (int dat[], int i) //******************************************
 { // read in Motorola real # and convert to intel
    unsigned char byte[4];
    float *x;
    
    x = (float*) &byte[0]; // address of x =start of byte array
     	
 	byte[3] = dat[i++]; 
 	byte[2] = dat[i++];
 	byte[1] = dat[i++];
 	byte[0] = dat[i++]; 


 	return(*x);
} //***************************************************************************


int   rd_gps( void  ) //*******************************************************
{ // cft = compact-flash scan type
  // dat = byte array of the data
  // n = #of bytes in dat[]
  // returns the phase of the new gps line
  
  // following are as defined in the GPS structure
  int tmax, valid, t_acq;
  int ysign, ydeg;
  float ymin;
  int xsign,xdeg;
  float xmin;
  int utc_hr, utc_mn, utc_sec;
  int gps_wk, gps_day;
  int nsat, smin, savg, smax, hdop;
  float ylat, xlon, yylat, xxlon;
  float olat, olon;
  int ovalid, wing;
  int gmark = -99; //first # out: -99 = original
  
  int i=0; // pointer into the data array
  float utc, yrday; // julian day output
  int dive = scan.dive; // dive #
  int health, yr, jd, stat;
  
  //parse the GPS structure -----------------------------------------------
  tmax   = rd_ushort( scan.dat,i); i+=2; //max time to acquire, typ. 900s
  valid  = rd_ushort( scan.dat,i); i+=2; //valid flag=1 if good
  t_acq  = rd_ushort( scan.dat,i); i+=2; //time to acquire [sec/10]
  ysign  = rd_short ( scan.dat,i); i+=2; //sign of latitude
  ydeg   = rd_ushort( scan.dat,i); i+=2; //abs(latitude) degrees
  ymin   = rd_float ( scan.dat,i); i+=4; //latitude minutes (+fraction)
  xsign  = rd_short ( scan.dat,i); i+=2; //sign of longitude
  xdeg   = rd_ushort( scan.dat,i); i+=2; //abs(longitude) degrees
  xmin   = rd_float ( scan.dat,i); i+=4; //long. minutes(+fraction)
  
  utc_hr = rd_ushort( scan.dat,i); i+=2; //utc hours, 0..24
  utc_mn = rd_ushort( scan.dat,i); i+=2; //utc minutes
  utc_sec= rd_ushort( scan.dat,i); i+=2; //utc seconds
  gps_wk = rd_ushort( scan.dat,i); i+=2; //GPS week number
  gps_day= rd_ushort( scan.dat,i); i+=2; //GPS day-of-week
  
  nsat   = rd_ushort( scan.dat,i); i+=2; // # of satellites-in-view
  smin   = rd_ushort( scan.dat,i); i+=2; // minimum SNR
  savg   = rd_ushort( scan.dat,i); i+=2; // average SNR
  smax   = rd_ushort( scan.dat,i); i+=2; // maximum SNR
  hdop   = rd_ushort( scan.dat,i); i+=2; // HDOP*10
  
  yylat  = rd_float ( scan.dat,i); i+=4; //present latitude, decimal degrees
  xxlon  = rd_float ( scan.dat,i); i+=4; //present long., decimal degrees
  olat   = rd_float ( scan.dat,i); i+=4; //last valid lat.
  olon   = rd_float ( scan.dat,i); i+=4; //last valid long.
  ovalid = rd_ushort( scan.dat,i); i+=2; //flag=TRUE if last fix was valid
  wing   = rd_ushort( scan.dat,i); i+=2; //wing used for fix
  //-----------------------------------------------------------------------
  // done reading in the GPS structure
         // printf("%4d, read %4d\n",scan.nb, i);
  
  //convert to correct units to write out
  utc =  utc_hr + (utc_mn + utc_sec/60.0)/60.0; // hh.hhhh
  health = ( nsat & 0xf0) >> 4;  // health of GPS
  nsat = nsat &0x0f; // lower-nibble is # of satellites
  

   stat = gps_wkday_2_yd(gps_wk, gps_day, &yr, &jd); //convert to yr, julian-day

   if (stat==0) // -----------------------------
   { // then no error
      yrday = jd + utc/24.0; // decimal year-day
   } else
   {
      yrday = 0;
   } //-----------------------------------------
   
   if (valid==0) yrday=-98.0; // FLAG that it is not a valid number
   
   //compute xlat, xlon from decimal minutes..should be better resolution
   xlon = xsign*(xdeg+xmin/60.0);
   ylat = ysign*(ydeg+ymin/60.0);

   //decide GPS mark #, originally -99
   if (GPS_MARK) //==============================================
   { //use the packet id to create the mark
     gmark = -90 - scan.type;
   } //==========================================================
   else gmark = -99; // OLD format ==============================
   //write out the GPS line
   
   sprintf(GPS_Line,
   " %3d %4d %9.4f %11.5f %11.5f %6d %4d %4d %4d %4d %4.1f %4d %4d %2x\0",
   gmark, dive, yrday, xlon, ylat, t_acq, nsat, smin, savg, smax,
   hdop*0.1, yr, dive, health);
   
   //printf("%s\n",GPS_Line);
   YR_Day = yrday;  // save the decimal year-day
  
  
  return ( scan.type );
} //***************************************************************************

void   kluge_gps_reset ( int dive ) //*****************************************
{ // gps reset mid-mission needs a start-dive marker
  char tmp[200];
  
  sprintf(tmp," %3d %4d", -91, dive); //start string
  strcat(tmp, &GPS_Line[9] );
  fprintf(fp_out,"%s\n", tmp);
  printf("%s\n", tmp);
  
  return;
} //***************************************************************************

void   rd_dat  (  void ) //****************************************************
{ // parse a data scan and write out ******************************************
  int ti, pr, te, sa, op; //time,pressure, temp, sal, opt
  int he, pi, ro; // heading, pitch, roll
  int pp, rr; // pitch pot, roll pot
  int bat, amp, alt, sbe; //battery volts, pump current, altimeter, sbe-flag
  int dox, is_dox;  //may11 addition
  int dox63,dox_T, dox_U; // jan13 addition
  int i=0;
  
  char line[200];
  
  //---DOX may2011, kluge to read in: this should be set by reading in the
  // header lines in the .sat file, or .cfg, or elsewhere
  // but here, just relying on the # of bytes in the message
  is_dox =  ( scan.nb == 30 ); // TRUE if includes DOX SBE43
  dox63  =  ( scan.nb == 34 ); // TRUE if it is a SBE63 DO sensor
  
  //parse the data structure ----------------------------------------------
  ti   = rd_ushort( scan.dat,i); i+=2; //time [s] since start of dive
  pr   = rd_ushort( scan.dat,i); i+=2; //dBar = pr*0.04 - 10;
  te   = rd_ushort( scan.dat,i); i+=2; //degC = te*0.001 - 5;
  sa   = rd_ushort( scan.dat,i); i+=2; //PSU  = sa*0.001 -1.0;
  op   = rd_ushort( scan.dat,i); i+=2; //optical counts
  if (is_dox) // may11
  { dox= rd_ushort( scan.dat,i); i+=2; //Dissolved oxygen counts
  }
  if (dox63) // jan13 addition
  { dox   = rd_ushort( scan.dat,i); i+=2; //Dissolved oxygen mL/L
    dox_T = rd_ushort( scan.dat,i); i+=2; //Dissolved oxygen T cnts
    dox_U = rd_ushort( scan.dat,i); i+=2; //DO raw cnts
  }
  
  he   = rd_ushort( scan.dat,i); i+=2; //Heading = he*0.1;
  pi   = rd_short ( scan.dat,i); i+=2; //Pitch degrees = pi*0.1;
  ro   = rd_short ( scan.dat,i); i+=2; //Roll degrees = ro*0.1;
  
  pp   = rd_ushort( scan.dat,i); i+=2; //pitch pot counts
  rr   = rd_ushort( scan.dat,i); i+=2; //roll pot counts
  
  bat  = rd_ushort( scan.dat,i); i+=2; //volts = bat*0.01;
  amp  = rd_ushort( scan.dat,i); i+=2; //amps = amp*0.01;
  alt  = rd_ushort( scan.dat,i); i+=2; //altimeter
  sbe  = rd_ushort( scan.dat,i); i+=2; //sbe flag=1 if sbe ctd is being taken
  //-----------------------------------------------------------------------
  
  if (alt>9999) alt=9999; //if not initialized, keep to <4 digits
  
  // now write out
  if (is_dox) //---------------------------------------------------
  { // may11 create output line with DOX tacked onto the end
    sprintf(line,
     "%5d %5d %5d %5d %5d %5d %4d %4d %4d %4d %4d %4d %5d %3d %5d",
       ti, pr, te, sa, op, he, pi, ro, pp, rr,bat,amp,alt,sbe, dox);
  }  
  else if ( dox63 ) //---------------------------------------------
  { // jan13 tack on dox, dox_T, dox_U
    sprintf(line,
     "%5d %5d %5d %5d %5d %5d %4d %4d %4d %4d %4d %4d %5d %3d %5d %5d %5d",
       ti, pr, te, sa, op, he, pi, ro, pp, rr,bat,amp,alt,sbe, dox, dox_T, dox_U );
  } else 
  { // no DOX
     sprintf(line,
     "%5d %5d %5d %5d %5d %5d %4d %4d %4d %4d %4d %4d %5d %3d",
       ti, pr, te, sa, op, he, pi, ro, pp, rr,bat,amp,alt,sbe);
  } //-------------------------------------------------------------
    
  fprintf(fp_out,"%s\n",line );
    
  return;
} //***************************************************************************

// 0711 - engineering type 0xE6 - cleaned up for just this type ********************
// e7 = 0901 code: only mod is that miss_id is replaced with npro = profile counter
void   rd_eng  (  void ) //****************************************************
 { // parse the Engineering message from scan struct

   // The struct below is copied from 0711 version of SPRAY file SETUP.H
   // (beginning and ending filler bytes dropped: zmax is first datum in input 

    short zmax;       // max depth of dive in dBar
    short alt;        // altimeter counts at turning depth
    short bat;        // battery a/d counts, LSB=.01V
    short current;    // current a/d counts, LSB=.01A
    short psurf;      // feb04 avg surf P @ start of dive
    short pitch;      // pitch of dive, degrees
    short head;       // heading steered, degrees magnetic
    short drx;        // dead-reckoning in the x direction, meters
    short dry;        // dead-reckoning in the y direction, meters
    short ydeg;       // way-point degrees latitude
    short dy;         // way-point fractional latitude  x 1000
    short xdeg;       // way-point degrees longitude
    short dx;         // way-point fractional longitude x 1000
    char  n_badamp;   // #times had too high of current, jun06 moved to old MSB of navg
    char  navg;		// #points averaged for profile (changed to char jun06)
    
    short ti_pump=0;  // pump time, msbyte = pump deep going down, lsb=total ti. on ascent
    short vac;        // vacuum a/d counts 
    short idive=0;    // present dive/profile number
    short miss_id=0;  // mission id
    short max_amp=0;  // time/10 (msb) + max amps (.02 res, lsb) during bottom turn
    char  r_err;      // jun06 : accumulated roll error (was old n_badamp byte)
    unsigned int  t_SBD;      // time trying to get SBD message through, [s]
    					// jul09 change to unsigned int from char

    char  ntries;     // #connect tries from the LAST dive
    char  nsent;	  // #packets sent from the LAST DIVE
  
    char  sbdi_stat=0;// SBDI= out-bound transmission status: wing in upper nibble
    char  sbd_shore;  // status of parsing a shore-command
  
    short exc_stat;      // exception status word
    short surf_tm=0;     // time to leave the surface to 2m depth
    short z_at_alt;      // 0711, depth at altimeter reading
    short vent=0;        // 0711, air vent status :MSB=ti vented, LSB=LLD-detect
    
    //BoB values
    short zs_pump;       // time[s] pumped when shallow
    short zs_w;          // last vert. ascent rate when z>2m
    short tm_surf_pump;  // time[s] pumping at the surface

	short npro=0; //0901 = ver=7, read in same spot as e6 miss_id
   //--------------------------------------
   char sbd_stat=0,  wing=0;
   float wlat=0, wlon=0, x_alt=0, r=0, v=0, a=0, amax=0, xvac=0;
   unsigned short buoy_pmp=0, tot_pmp=0, m1, m2, m3;
   unsigned short max_amp_t=0, max_amp_i=0;
   int surf_tm1=0, surf_tm2=0;
   int vent_tm, vent_LLD, alt_db;
   int adp_alt=0, ii1=0, ii2=0;
   char mv = 'T';  // Heading flag, M=magnetic, T=True
  int i=0, ver, nbytes, dive=0;
  
  //char line[200];
  
  
  //parse the data structure ----------------------------------------------
   ver     =scan.dat[0]; // version
   nbytes  =rd_ushort( scan.dat,1); //#bytes
   i = 3;
   zmax    =rd_short(scan.dat,i); i+=2;     // max depth of dive, (1 dBar/cnt)
   alt_db  =scan.dat[i] ;  i++;     // for ADP, = strongest return signal
   alt     =scan.dat[i] ;  i++;     // distance to bottom, (1 dBar/cnt)
   bat     =rd_ushort(scan.dat,i); i+=2;     // avg volts @ bottom turn(0.01V/cnt)
   current =rd_ushort(scan.dat,i); i+=2;     // avg amps @ bottom turn (0.01A/cnt)
   psurf   =rd_ushort(scan.dat,i); i+=2;     // counts
   pitch   =rd_short(scan.dat,i) ; i+=2;     // degrees
   head    =rd_ushort(scan.dat,i); i+=2;     // degrees magnetic : True Sep06
   drx     =rd_short(scan.dat,i) ; i+=2;     // meters
   dry     =rd_short(scan.dat,i) ; i+=2;     // meters
   ydeg    =rd_short(scan.dat,i) ; i+=2;     // degrees latitiude waypoint
   dy      =rd_short(scan.dat,i) ; i+=2;     // (fraction of latitude)*1000
   xdeg    =rd_short(scan.dat,i) ; i+=2;     // degrees longitude waypoint
   dx      =rd_short(scan.dat,i) ; i+=2;     // (fraction of longitude)*1000
   n_badamp=scan.dat[i] ;  i++;     // #times had too high of current
   navg    =scan.dat[i] ;  i++;     // #8 s pts averaged for ea profile datum
   
            // buoy_pmp =MSB, tot_pmp=LSB of ti_pump 
   buoy_pmp=scan.dat[i] ;  i++;     // time pumped to get neutral (10s/cnt).
   tot_pmp =scan.dat[i] ;  i++;     // total pump time on ascent  (10s/cnt).
   vac     =rd_short(scan.dat,i) ; i+=2;     // vacuum at bottom turn (0.01 inHg/cnt)
   idive   =rd_short(scan.dat,i) ; i+=2;     // dive #
            // mission ID:: m1=MSB, m2=MSN(LSB), m3=LSN(LSB) of m_id
   m1      =scan.dat[i] ;  i++;     // year of mission ID
   m2      =scan.dat[i] ;  i++;      // month
   m3      =m2 & 0x0f;     // id
   m2      =(m2& 0xf0)>>4;
   
   max_amp_t=scan.dat[i] ;  i++;     // time that max amp occurred (s)
   max_amp_i=scan.dat[i] ;  i++;     // max amps (0.02 amps/cnt) during bottom turn
   
   r_err   =scan.dat[i] ;  i++;     // accum. roll error ( 0.5 deg/cnt)
   t_SBD   =scan.dat[i] ;  i++;     // time spent trying to send SBD [s].
   // jul09 below line didn't work because t_SBD was char...adding 256 simply wrapped it around again.
   // if (t_SBD<0) t_SBD += 256;     // Jun09 make unsigned value.
          
   // following are the SBD params from the LAST dive surface comms
   ntries     = scan.dat[i] ;  i++;  // #SBD connect tries
   nsent      = scan.dat[i] ;  i++;  // #of SBD messages sent
   wing       = scan.dat[i] ;  i++;   // wing used for SBD
   sbd_stat   = wing & 0x0f;   // OUT-BOUND transmission status
   wing = (wing & 0xf0)>>4;
   sbd_shore  = scan.dat[i] ;  i++;  // status of parsing the shore command
   
   exc_stat   = rd_short(scan.dat,i) ; i+=2;  // = 16-bit exception status
     // surface-time : MSB = end-dive  (before GPS), LSB=start-dive (to leave surf).
   surf_tm2   = scan.dat[i] ;  i++;  // = end-dive time from surfacing to GPS ON (10s/cnt)
   surf_tm1   = scan.dat[i] ;  i++;  // = start-dive time to leave the surface   (10s/cnt)
   
   //new 0711 = 0xe6 code
   z_at_alt   = rd_short(scan.dat,i) ; i+=2;  // = depth[m] of Spray @ time of altimeter reading
   vent_tm    = scan.dat[i] ;  i++;  // = time [s] needed to purge the air
   vent_LLD   = scan.dat[i] ;  i++;  // = liquid-level-detect reading of air vent
   
   //Bob 0xe8 code
   if (ver == 8)
    {
     zs_pump      = rd_short(scan.dat,i) ; i+=2;  // time[s] pumped when shallow
     zs_w         = rd_short(scan.dat,i) ; i+=2;  // last vert. ascent rate when z>2m
     tm_surf_pump = rd_short(scan.dat,i) ; i+=2;  // time[s] pumping at the surface
    }
               // compute mission ID values
   // --- end reading in parameters ---------------------------------------
   //----------------------------------------------------------------------
   
   
   //----------------------------------------------------------------------
   //--- do error checking and conversion to eng. units -------------------
   
   if (idive>0) dive = idive; // legal dive #

   v    = bat*0.01;       // battery volts
   a    = current*0.01;   // pump current
   amax = max_amp_i*0.02; // max pump current, [amps]
   xvac  = vac*0.01;      // vacuum, in-Hg
   if (xvac<0) xvac=-xvac;

   // convert waypoint info to fractional degrees
   if ( ydeg < 0 ) dy=-dy;  //watch sign!!
   wlat=ydeg+.001*dy;//way point in decimal degrees
   if ( xdeg < 0 ) dx=-dx;//watch sign!!
   wlon=xdeg+.001*dx;

   surf_tm1 *=10; // units = s
   surf_tm2 *=10; // units = s.
   
   r = r_err*0.5; // =degrees roll bias needed to go straight @ bottom of descent
   
   adp_alt = ( exc_stat & 0x4000 ); // flag = TRUE if ADP altimeter
   
   // 07mar08 fix ...remove after sn13 Mar08 is recovered!!!!!
   if (adp_alt && alt > 230 )
   { // !!!!KLUGE to parse sn13 Mar08 deployment with bug in Spray code
     alt = alt - 256 + 15; // Spray sends alt = alt - 15 by mistake
   } // -256 above corrects for alt=unsigned value
   else // not the kluge
   {  if (alt>99) { alt=99;  alt_db=0; } // keep bounded
   }
   
   x_alt = alt; // used for old 'E ' output line...soon to be obsolete???
   
   //----------------------------------------------------------------------
   //----------------------------------------------------------------------
   

     fprintf(fp_eng,"E %4hd %4hd %5.2f %4.2f %6.3f",
                 dive, zmax, v, a, x_alt);
     fprintf(fp_eng," %3hd %3hd %7hd %7hd %+7.3f %+8.3f",
             head,pitch,drx,dry,wlat,wlon);
     fprintf(fp_eng," %2hd %2hd %2hd %1hd %1hd %02hx",
             ntries,nsent,navg,wing,sbd_stat,sbd_shore );
     fprintf(fp_eng," %4hd %2hd %3hd %5hd %3hd %3hd",
             psurf,buoy_pmp,tot_pmp,vac, max_amp_t,max_amp_i);
             // new data NOT in ver<=3       
     fprintf(fp_eng," %3hd %3d %3hd %3hd %04hx\n",
                   r_err, t_SBD, surf_tm1, surf_tm2, exc_stat);
     //-----------------------------------------------------------------
     
   /*
   //--- 0902 removed EX01, as replaced by EX02 in parse_0f
   //if (ver==7) // then we have the 0901 profile #...can be handy for parsing!
   //   fprintf(fp,"EX01 %4hd %2hd\n", dive, npro );
     
   // print out the new Version Nov 06 ---------------------------------
   // these are multiple lines, divided up by function
           //  EC = Communications
   fprintf(fp,"EC01 %4hd %2hd %2hd %2hd  %02hd %3d %2hd\n",
     dive, ntries, nsent, sbd_stat, sbd_shore, t_SBD, wing );
           //  EF = Flight Info
   fprintf(fp,"EF02 %4hd %2hd %3hd %4hd %2hd %3hd %3d %4hd %5.1f %04hx\n",
     dive, navg, psurf, zmax, pitch, alt, alt_db, z_at_alt, r, exc_stat);
           //  EN = Navigation
   fprintf(fp,"EN01 %4hd %5hd %5hd  %+7.3f %+8.3f %3d %3d %3d %3hd %c\n",
     dive, drx, dry, wlat, wlon, surf_tm1, surf_tm2, 0,  head, mv);
           //  EP = Pump info
   fprintf(fp,"EP02 %4hd %4hd %5.2f %4.2f %2hd %3hd %4.2f %5.2f %3hd %3hd %3d %1d\n",
     dive, zmax, v, a, n_badamp, max_amp_t, amax, xvac, buoy_pmp, 
                                   tot_pmp, vent_tm, vent_LLD );

   if (ver == 8) // oct13
   { // BoB 0xe8; has shallow pump info
     fprintf(fp,"EB01 %4hd %4d %4d %4d\n",  // EB = BoB values
             dive, zs_pump,zs_w,tm_surf_pump );
   }
   //-------------------------------------------------------------------
   */
   
   /* removed printing out multiple Mission lines: is @ start-of-file already
   { // also print out the mission info --------------------------------
      fprintf(fp,"M %4hd %02hd/%02hd:%02hd\n",idive,m1,m2,m3);   
   } //-----------------------------------------------------------------*/
   
 return;
 } //**************************************************************************



int read_scan( void) //********************************************************
// reads the next line in fp_in, and parses out:
// updates the global structure 'scan'

// cf_type = scan id type (see description at top of program)
// dat = integer array of the data
// returns nb = #bytes in the scan
{
   char line[NLINE], ds[NLINE];
   int i, j, m, n, nb=-1, diff, ns, cf_type;
   
   n = fget_line(fp_in, line, NLINE); // n=# of char in line
   
   if (n==0) return(0);  // blank line...skip
   if (n<0)  return(-1); // EOF
   // else n>0
   
   m = sscanf(line,"%x %d %s",&cf_type, &nb, ds);
   // m=#arg actually read in, should =3
   // ds = data string
   ns = strlen(ds);
   diff = nb*2 - ns; // should = 0
   
   if (m<2 || cf_type<0 ||   diff !=0 )
   { // then something doesn't make sense
      printf("BAD scan: %s\n",line);
      return(-1);
   }
   
   // else have a valid data type, and #bytes makes sense
   for (i=0, j=0; i<nb; i++)
   {
      scan.dat[i] = rdhex( &ds[j],2); j +=2;
      // if (*cf_type==0x0f) printf("%4d\n",dat[i] );
   }
   scan.nb   = nb;      // save #bytes
   scan.type = cf_type; // and scan id type
     
   return(nb);
}  //**************************************************************************


int  rdhex ( char *ch, int  num)  //*****************************************
 {//convert num HEX characters in *ch to  integer
  // returns the value
  int val,i;
  char c;
  
  c = *ch++; val=0; i=0;
  while ( (c != '\0') && (i<num) ) 
   {
    val = val * 16; //shift value over
    c = tolower(c);
    switch (c)
     {
      case '0' : break;
      case '1' : val = val+1; break;
      case '2' : val = val+2; break;
      case '3' : val = val+3; break;
      case '4' : val = val+4; break;
      case '5' : val = val+5; break;
      case '6' : val = val+6; break;
      case '7' : val = val+7; break;
      case '8' : val = val+8; break;
      case '9' : val = val+9; break;
      case 'a' : val = val+10; break;
      case 'b' : val = val+11; break;
      case 'c' : val = val+12; break;
      case 'd' : val = val+13; break;
      case 'e' : val = val+14; break;
      case 'f' : val = val+15; break;
      default  : val = 0; i = 5;  //set to bad values
     } //end switch
    c = *ch++; //point to next character
    i++;
   } //end while
  return(val);
 }  //end rdhex ***************************************************************
 
//*****************************************************************************

