/******************************************************************************
//	dat_fnx.c			data acq./processing functions
//	
//*****************************************************************************
//	
//	Jan2009, created
//
//  mar11 added DOX functions, modeled after BDJ 0711 mods
//  mar11 added error-catch for first bad point in avg_dat
//*****************************************************************************
//
// 22Apr10 fixed bug on S.ample All for vacuum output
// 28aug10 fixed so that optical values<0 are not averaged
// may12 0903.8 fix potential buffer overflow in eng. time series.
// jul13 make sure the GPIO A/D is correctly turned on/off.

//==== Future Expansion =======================================================
//		last update: Jan2009
//	1. 
//  2. bench-test ability for the various functions
//  3. confirm interaction of using the PID for the profile ID
//
******************************************************************************/
#include	<cfxbios.h>		// Persistor BIOS and I/O Definitions
#include	<cfxpico.h>		// Persistor PicoDOS Definitions

#include	<assert.h>
#include	<ctype.h>
#include	<errno.h>
#include	<float.h>
#include	<limits.h>
#include	<locale.h>
#include	<math.h>
#include	<setjmp.h>
#include	<signal.h>
#include	<stdarg.h>
#include	<stddef.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>


#include    "cf2_qsm332.h"
#include    "spi_cmd.h"
#include    "gpio_mux.h"
#include    "pump.h"
#include    "pitch_roll.h"
#include    "nav.h"
#include    "sbd.h"
#include    "sbe.h"
#include    "tcm2.h"
#include    "adp.h"
#include    "lifo.h"
#include    "pplus.h"
#include    "zooCam.h"
#include    "dat_fnx.h"
#include    "setup.h"
#include    "ntk.h"
#if PH==1
 #include   "ph.h"
#endif

// globals
extern char   Verbose;  // switch for displaying more info
extern char   IRQ_Flag; // interrupt flag: says what caused the interrupt
extern short  iparam [ MAX_PARAM ]; // global parameter settings
extern struct all_param all;


// internal prototypes
void   sample_sub  ( void ) ;
void   sample_all  ( void ) ;
void   daq_menu    ( void ) ;
void  test_str_read( void ) ;
void   test_DOX    ( void ) ;
void  test_dat_pack( void ) ;

//*****************************************************************************
short alloc_dat_ram(struct dat_param *DP) //***********************************
{ // allocate memory for storing profile data AND engineering data
  // returns TRUE if there was an allocation error!
  short *dptr;
  
  dptr = (short *) malloc(DATA_SIZE); // alloc profile space --------
  if (dptr == NULL ) // then allocation failed
  {
     cprintf("malloc of %ld bytes failed\n",DATA_SIZE);
     return(TRUE);
  } // else OK
  DP->dat = dptr;  // save ptr into dat_param -----------------------
  
  dptr = (short *) malloc(EDAT_SIZE); // alloc eng. space -----------
  if (dptr == NULL ) // then allocation failed
  {
     cprintf("malloc of %ld bytes failed\n",EDAT_SIZE);
     return(TRUE);
  } // else  OK
  DP->eptr = dptr;  // save ptr -------------------------------------
  
       // removed: DP->i = 0;  // by NOT setting to 0, this allows
       // old data profile to be packed after spurious reset
       
  DP->max  = ( DATA_SIZE / DATA_WORDS )/2; //=max #recs in profile buffer
  DP->nrec =   DATA_WORDS; //= # data points per record
  
  DP->emax = ( EDAT_SIZE / ( ET_WORDS +2) )/2; //=max #recs in eng. buffer
  //---may12 above doesn't account overhead of very last record
  DP->emax = DP->emax - 2; //should just need -1, but -2 just to be safe
  // ET_WORDS+2 = #want to store from eng struct + time + press
  
  printf("  data ptr = %p \n",DP->dat   );
  printf(" edata ptr = %p \n",DP->eptr  );

  return( DP->dat == NULL || DP->eptr == NULL );  // return true if in error 
} // **************************************************************************

//0902, added 2nd chances on getting values
void take_data( void ) //******************************************************
{  // Take the data and store: data_param DP is in setup.h    *****************
   // DP structure allows the calling fnx to access the data  *****************
  unsigned long now; 

  // float comp, pitch, roll;
  float press=0, temp=0, sal=0;
  ushort p=0, t=0, c=0;
  short ierr, pro_stat, dms, val;
  short opt_flag, adp_stat=0;
  long m=0;
  ulong ms;
  RTCTimer rt;
 #if DOX==1
  float dox=0;
  ushort d=0;
 #elif DO6==1 //oct12 bdj
  float dox=0,doxt=0,doxraw=0;
  ushort d=0, dT=0,dU=0;
 #endif
 #if PH==1
  float  v1=0,v2=0,v3=0,v4=0,v5=0,v6=0;
 #endif

  struct dat_param *DP;
  
  DP = all.dat;

  service_wdog();  //0902 update the watchdog heartbeat
  // 0901, this was the last call in this fnx
  // by moving it to the front, this should ensure GPIO is talking.

  opt_flag = iparam [ IA_use_opt ]; // can be changed via shore command
  if ( SBE  && !DP->sbe_pro_on ) // if SBE, assume the optical is pumped,
     opt_flag = FALSE; // if SBE is off, don't take optical data!
  
 #if DO6==1 //oct12 bdj
  if (opt_flag)
    { Opt_On; // turn on optical sensor & SBE63
      start_do6();
    }
  // >BF turn on 2nd optical as well 
 #else  
  if (opt_flag) Opt_On; // turn on optical sensor
  AD_On; //jul13, turn on the GPIO a/d; ensures that it is on
 #endif
  
  #if PH==1
   if (opt_flag)
    {
     start_ph(); //turn on pH
     ph_send_ss(); //tell it to sample
    }
  #endif
  
  
  now = RTCGetTime(0,0) - all.time->ti0;  //get time now
  //now = #s since the start-of-dive
  DP->ds.secs = ( ushort)  now;    //& cast to  ushort the # of secs
  DP->isamp++; // increment the sample counter

  #if SBE==1  // jul04 change for SBE ts command structure -----------
    if (DP->sbe_pro_on) //......................................
    { // then profiling, and we want to take data ..............
      #if SBE_1HZ ==1 // then we just get the press from SBE + sample#
            print ( " COMPILE ERROR: 1HZ option removed Oct08 ")
      #else // then doing 8 s stuff ............................
         cr_2_sbe;      // write out cr to get attn of SBE
         // go sample other stuff before getting the SBE result 
      #endif //.................................................
    } //........................................................
    else // else just get pressure .............................
    {  press = sbe_fp();
       pro_stat = m = 0; // set=0 :do NOT include in profile
    } // end else ..............................................
  
  #else // else SBE==0, use the old code  ----------------------------
    print ( " COMPILE ERROR: Code only valid for SBE CTD ")
    //get_CTD(&p,&t,&c);  // get p, t, c values : takes 0.5 s
    //pro_stat = 1; // =Good profile status, use it in profile
  #endif //-----------------------------------------------------------

  // collect all other data ===========================================
  tcm2_on(); //turn on compass & let it do the first acq.
  RTCElapsedTimerSetup(&rt);
  
  //initiate a/d transactions with ea module
  DelayMilliSecs( 5 ); //0902 changed from 20 to 5
  rqst_a2d ( CS_GPIO,  AD_AUX_V_14 );
  rqst_a2d ( CS_PITCH, AD_POT );
  rqst_a2d ( CS_ROLL,  AD_POT );
  if ( all.hyd->status != PUMP_WAIT ) 
     rqst_a2d (CS_HYD, AD_HYD_AMPS );
  // get results
  DelayMilliSecs( 300 ); //0902 changed from 20 to 300
  // this is to avoid tcm2 xmit, causing potential glitches on spi
  val = last_a2d     ( CS_GPIO, AD_AUX_V_14 ); 
  if (val<0) 
      val = r_get_a2d( CS_GPIO, AD_AUX_V_14 ); //0902 try again
  DP->es.ad_bat_14  = val;
  rqst_a2d ( CS_GPIO,  AD_AUX_V_07 );
  
  val = last_a2d     ( CS_PITCH, AD_POT );
  if (val<0) 
      val = r_get_a2d( CS_PITCH, AD_POT ); //0902 try again
  DP->es.ad_pitch   = val;

  val =      last_a2d( CS_ROLL, AD_POT );   
  if (val<0) 
      val = r_get_a2d( CS_ROLL, AD_POT ); //0902 try again
  DP->es.ad_roll    = val;

  if ( all.hyd->status == PUMP_WAIT ) //hhhhhhhhhhhhhhhhhhh
  { // then the pump is on
     get_hyd_ad ( ); // this samples all, even if pump is off
     DP->es.ad_current = all.hyd->amp;
     DP->es.ad_oil     = all.hyd->oil;
  }  // else the pump is off, just get the amps
  else {
    DP->es.ad_current = last_a2d ( CS_HYD, AD_HYD_AMPS );
    DP->es.ad_oil = 0;  
  } //hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
  
  val = last_a2d     ( CS_GPIO, AD_AUX_V_07 ); 
  if (val<0) 
      val = r_get_a2d( CS_GPIO, AD_AUX_V_07 ); //0902 try again
  DP->es.ad_bat_07  = val;

  ms = RTCElapsedTime( &rt)/1000 +1;
  dms = 800 - ms; //minimum delay time for compass
  // 0.45 s to here : 0902, 0.75s
  if (dms>0) DelayMilliSecs( dms );
  ierr = get_tcm2(  0 );  //takes 1 sample, doesn't cycle power
  DP->es.eng_err = ierr*0x10;
  if (ierr) 
  {
     ierr = get_tcm2( 0 ); // try again
     DP->es.eng_err += ierr;  //record the error flag
  }
  tcm2_off();
  ms = RTCElapsedTime( &rt)/1000 +1;
  
  // cprintf("tcm2 dms=%d,tot=%ld err=%x\n", dms, ms, DP->es.eng_err);
  if (ierr==0) //------------------------------------------------
  {  // only use good compass value
     // else the old values will be used: good enough for a glitch
     DP->es.comp  =  10*all.comp->head;  //=deci-degrees
     DP->es.roll  =  10*all.comp->roll;
     DP->es.pitch =  10*all.comp->pitch;
  } //-----------------------------------------------------------

  // minimum time to sample optics = 0.5+0.3+0.4 = 1.2 s
  if (opt_flag) //-----------------------------------------------
  {  
     val = r_get_a2d     (CS_GPIO, AD_AUX_OPT ); 
     if (val<0) 
         val = r_get_a2d (CS_GPIO, AD_AUX_OPT ); //0902 try again
     DP->ds.optic  = val;
    #if PH==1 //sep18 bdj.
     ph_get_sl(all.ph);
     all.ph->secs = ( ushort)  now;    //& cast to  ushort the # of secs
     store_ph_dat(all.ph);
     store_ph2flash (all.ph);
  	#endif
    #if DO6==1 //JUL13 bdj
      do6_get_ts(&dox,&doxt,&doxraw);
      close_do6();
      d = intDval(dox); dT = intTval(doxt); dU = intTval(doxraw);
    #endif
     Opt_Off; // turn off optical sensor  
  } //-----------------------------------------------------------
  else { DP->ds.optic = 0; } // not taken!
  AD_Off; //jul13, turn off the GPIO a/d; ensures that it is off

  #if SBE==1 // jul04 ----------------------------------------------------
    #if SBE_1HZ == 0 // then doing 8 s stuff .............................
      if ( DP->sbe_pro_on) // then profiling
      { // the above CR woke up the SBE.  Now ask for the last sample
        // this also tells SBE to take another sample
        #if DOX==1 //have SBE DOX sensor, call appropriate function
          pro_stat = sbe_get_ltso(&press,&temp,&sal,&dox); // 0=error, 1=OK
          d = intDval(dox);
        #else
          pro_stat = sbe_get_lts(&press,&temp,&sal); // 0=error, 1=OK
          printf("sbe_pro_on = 1; pro_stat = %d, press = %f, temp = %f, sal = %f\n",
          	DP->sbe_pro_on, press, temp, sal);
        #endif
        // >BF add &oxy2
        t = intTval(temp);  // convert to integer
        c = intSval(sal); 
        // oct08, store T and S as floats, for ISUS
        DP->ftemp = temp;
        DP->fsal  = sal;
        // DP->dbar = pressure: see next few lines down
      } // end if profile
    #else // doing 1 Hz stuff
      print ( " COMPILE ERROR: 1HZ option removed Oct08 ")
      t = 0;  c = 0; // place holders
    #endif //endif SBE_1HZ ..............................................

    p = intPval(press); // convert SBE pressure to integer

  #endif  // endif type SBE ---------------------------------------------
  
  DP->dbar = dBar(p, all.flt); // convert counts to dBar and save
  		   //dBar() uses a dynamic offset, based on last surface pressure
  		   //therefore, it compensates for pressure drift

  #if ZOOG==1 // sep15
      zooCam_state(); // check the state & respond approp.
      zonarState();   // aug16, also check for the zonar state.
  #endif
     
  // Sample the Doppler -------------------------------------------------
  #if ADP==1  // if code is compiled for a Doppler ----------------------
    if (DP->take_adp) //-------------------------------------------------
    {  // then we want to take adp data ---------------------------------
    
       if ( DP->dbar < DP->p_adp ) //++++++++++++++++++++++++++++++++
       {  // then it is time to take an ADP sample

          if (!all.adp->on_adp) // first time, see if the adp is on
          { // if it is NOT on:  turn on & initialize ..............
             all.adp->on_adp = adp_on();  // turn on the adp
             DelayMilliSecs(2000);
             adp_exit_sample(); // make sure we're in the main menu
             adp_set_up(1.0); // set parameters for profiling
             adp_sample_mode(); // enter the sample mode
             all.adp->iscan = 0; // store @start of ADP buffer
             all.adp->pmin = DP->p_adp; // init min press observed.
          } // end if adp was not on
          else //...................................................
          { // already on, take data
            // this should ensure 8 s btwn  above start-up & 1st sample
             adp_stat = adp_get_sample();  // get sample, increments adp->iscan.
             DP->es.ad_alt =  adp_stat;   // save; goes to flash
             // decrement to the next target depth
             if (adp_stat<1) // then it was a good sample
             { // iscan is incremented in adp_get_sample
                if ( all.adp->iscan==1) // then 1st sample taken
                {
                   DP->p_adp = DP->dbar;  //  synchronize to this depth
                }
                // decrement p_adp for the next desired sample depth
                DP->p_adp = DP->p_adp - iparam[IA_adp_cellsize]; 
             } // end valid  adp sample 
             printf("Next ADP depth=%6.1f\n",DP->p_adp);
          } // end else ............................................
          
       }  // end if pval<p_adp +++++++++++++++++++++++++++++++++++++
       
    } // end if take adp data //-----------------------------------------
  #endif      // end if Sontek ADP glider --------------------------------------
  
   //JAN14 add NTK Doppler sampling to here --------------------------------
  #if NTK==1  // if code is compiled for a Doppler ----------------------
    if (DP->take_adp) //-------------------------------------------------
    {  // then we want to take adp data ---------------------------------
       #if DEBUG ==1
         printf("want to take adp data\n");
       #endif
       if ( DP->dbar < DP->p_adp ) //++++++++++++++++++++++++++++++++
       {  // then it is time to take an ADP sample
          #if DEBUG ==1
             printf("DP->dbar=%f, DP->p_adp=%f\n",DP->dbar,DP->p_adp);
          #endif
          if (!all.adp->on_adp) // first time, see if the adp is on
          { // if it is NOT on:  turn on & initialize ..............
             // MAR13 turn on NTK ADP -----------------------------------
             adp_stat = ntk_start_pro();
             if (adp_stat == 0) //,,,,,,,,,,,,,,,,,,,,,,,,
             { // start-up failed !
               all.adp->on_adp   = ntk_off(); // turn off
               all.dat->take_adp = FALSE; // don't take adp data
             }
             else //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
             { // it started up OK, set flags 
               all.adp->on_adp   = TRUE; // it is on
               all.dat->take_adp = TRUE; // we are taking data
             } //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
             all.adp->iscan = 0; // start storing at beginning of ADP buffer
             all.adp->pmin = DP->p_adp; // 0702 initialize min pressure observed.
          } // end if adp was not on
          else //...................................................
          { // already on, take data
            // this should ensure 8 s between the above start-up & 1st sample
             adp_stat = ntk_get_sample(0);  // get sample, increments adp->iscan.
             DP->es.ad_alt =  adp_stat;   // save value; gets recorded to flash
             // decrement to the next target depth
             if (adp_stat<1) // then it was a good sample
             { // iscan is incremented in adp_get_sample
                if ( all.adp->iscan==1) // then this is the first sample taken
                {
                   DP->p_adp = DP->dbar;  // 0702 synchronize to this depth
                    printf("New p_adp...");
                }
                // decrement p_adp for the next desired sample depth
                DP->p_adp = DP->p_adp - iparam[IA_adp_cellsize]; //
             } // end valid  adp sample 
             printf("Next ADP depth=%6.1f\n",DP->p_adp);
          } // end else ............................................
          
       }  // end if pval<p_adp +++++++++++++++++++++++++++++++++++++
       
    } // end if take adp data //-----------------------------------------
  #endif      // end if ADP glider --------------------------------------
  
  
  // save the CTD info to the data structure
  DP->ds.p = p;  
  DP->ds.t = t;  
  DP->ds.c = c;  
  #if DOX==1 //mar11, save do data
    DP->ds.d = d;
  #elif DO6==1 //JUL13
    DP->ds.d = d;DP->ds.dT = dT; DP->ds.dU = dU;
    printf("d = %8d, dT = %8d, dU = %8d\n",d,dT,dU);
  #endif
  // if SBE_1HZ then pro_stat = sample #
  DP->ds.nsbe = pro_stat; //profile status: 0=bad, 1=OK, or >0 is sample #
  if ( pro_stat>0 )  store_pro_dat( DP ); // store the data to RAM
  
  store_eng_dat   ( DP ); // will store eng data if needed
  store_dat2flash ( DP ); // store data to flash card

  DP->es.ad_alt = 0; // set to 0: will remain 0 until new alt. sample taken
  // 0901 service_wdog();  //update the watchdog heartbeat
  
  /*
  #if ISUS==1 // nov08, get ISUS  if it is time
    if (all->isus->ts_mode == ISUS_GET_LAST )
       isus_get_last ( all );  // get the last sample & store
       // it also puts ISUS into lowpower mode if it retrieved the sample
    // see if it is time for the next sample   
    isus_get_pro_sample ( all ); // if time, starts another "TS"
  #endif
  */
  
  #if PPLUS==1 //mar11, polyplus cells to monitor ===========
    now =  RTCGetTime(0,0); //present time
    pp_take_dat(now); // take & store the cell voltages
  #endif //==================================================
      
  return;
} // end take_data  ***********************************************************
//*****************************************************************************

void store_pro_dat ( struct dat_param *DP ) //*********************************
{ // store the present profile data to RAM buffer area
  long offset;
  short *d; // points to next spot in RAM
  short *x; // points to the data
  short i;
  
  if (Verbose) cprintf("store_pro_dat, DP->i=%d, DP->max=%d: ",DP->i,DP->max);
  
  // store profile data====================================================
  if ( DP->i < DP->max )  
  { // still have room & is part of profile, store values to RAM
  
    offset = (long) DP->i * (long) DATA_WORDS; //Offset into dat
    d = DP->dat + offset;  //points to next output
    x = &(DP->ds.secs);  // points to first data point to write out
    
    for (i=0;i< DATA_WORDS; i++) //----------------------
    { //xfr these values
        if (Verbose) printf("ptr=%p, val=%5u\n",d,*x);  // print value
        *d++ = *x++; // xfr data to RAM
    }  //------------------------------------------------
    if (Verbose) cprintf("\n"); 

    DP->i++;  //increment index
  } //=====================================================================

  return;
} //***************************************************************************

void store_eng_dat ( struct dat_param *DP ) //*********************************
{ // store the present profile data to RAM buffer area
  long offset, n, ldt;
  short *d; // points to next spot in RAM
  ushort *x; // points to the eng data
  short ndec, b0, i;
  
  // store engineering data
  // 0903 feb11 different algorithm: use time to decide whether to store.
  // this allows different down/up sampling times

  ndec = iparam [ IA_eng_ndec ];  // # of points to decimate
  b0   = iparam [ IA_eng_mask ];  // eng. bit mask of sensors to send
  i=1; // initialize to NOT modulus = do NOT store
  // next line is obsolete with 0903
  //if (ndec>0) i = ( DP->isamp % ndec ); // if ndec is legal, get %
    
  if ( ndec>0 && b0>0 ) //===============================================
  { // then we want to store the data
    ndec  *= SAMP_DT_DN; //=#s between engineering samples.
    ldt = RTCGetTime(0,0);  //recasts as long
    ldt = ldt - all.time->ti_cyc -180;  //0903 time into this profile
    // -180 sets the first point  3minutes into sitting on the surface 
    ldt = (ldt / ndec ) + 1; // time index +1
    if ( ldt> DP->ie && DP->ie < DP->emax ) //iiiiiiiiiiiiiiiiiiiiiii
    {  // then newer value & room to store it, store the data
       n = ET_WORDS + 2; //#words per each ET scan ( +2 = secs + p)
       offset = (long) DP->ie * n; // offset into eptr
       d = DP->eptr + offset; // location to start writing
     
       *d++ = DP->ds.secs;
       *d++ = DP->ds.p;
       x =  (ushort*) &(DP->es.comp); // points to the compass
       for (i=0;i<ET_WORDS; i++) //--------------------------
       {  // xfr compass, pitch, roll, pitch_pot, roll_pot
          if (Verbose) cprintf("e_%5d ",*x);  // print value
          *d++ = *x++; // xfr
       } //--------------------------------------------------
       if (Verbose) cprintf("\n"); 
       DP->ie++; // point to the next place
    } //iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
  }
  //=====================================================================

  return;
} //***************************************************************************

void store_dat2flash ( struct dat_param *DP ) //*******************************
{ // store the present profile and eng data to flash
  uchar *cp;
  short n2;
  
     /*---- store profile data to flash ------------------------------------
    #if DO6 == 1
     n2 = ( DATA_WORDS + 2)*2; // =#bytes to store.  Add in dT and dU
    #else
     n2 = ( DATA_WORDS )*2; // =#bytes to store
    #endif
    */
    
    //JUN14 just store the whole struct to flash
    // n2 = sizeof(struct dat_param);
    //sep14 fix bug on size of data sensors struct
    n2 = sizeof(struct dat_sensor );
    
    
    //printf("DATA_WORDS = %d, n2 = %d\n",DATA_WORDS,n2);
     cp = (uchar*) &(DP->ds.secs);   // points to begin. of dat_sensor
     flash_store(n2, cp, CF_PDAT ); // profile data only

     //---- store eng data to flash ---------------------------------------
     n2 = ( ENG_WORDS )*2;    // =#bytes to store
     cp = (uchar*) &(DP->es.comp );   // points to begin. of eng_sensor
     flash_store(n2, cp, CF_EDAT ); // eng data only

  return;
} //***************************************************************************


float dBar(ushort p, struct flight_param *fp) //*******************************
{  // takes pressure counts & converts to dBars 
   float x;
   long dp;
   dp = (long) p  - (long) fp->pmin; //fp->pmin is updated ea surfacing
   x = dp* F_PR_GN; 
   return(x);
} //***************************************************************************


//*****************************************************************************
//**** functions for sampling analog sensors
//**** these are intermediate-level drivers, to help mimic old TT8 code
//*****************************************************************************

void   sample_sub  ( void ) //*************************************************
{ // sample subset of analog channels and display
  // used in normal bench-test
  //ulong ms1, ms2, ms3;
  float x;
  //RTCTimer rt;

  short err, ip, ir, v14, v7, vac ;
  //RTCElapsedTimerSetup(&rt);
  AD_On; //jul13, make sure it is on
  
  err = rqst_a2d ( CS_GPIO, AD_AUX_V_14 );
  if (err != SPI_CRC_OK) cprintf("Err rqst gpio V_14 %c\n", err);

  err = rqst_a2d ( CS_PITCH, AD_POT );
  if (err != SPI_CRC_OK) cprintf("Err rqst pitch pot %c\n", err);

  err = rqst_a2d ( CS_ROLL, AD_POT );
  if (err != SPI_CRC_OK) cprintf("Err rqst roll pot %c\n", err);
  
  DelayMilliSecs ( 100);
  
  v14 = last_a2d ( CS_GPIO, AD_AUX_V_14 );
  
  err = rqst_a2d ( CS_GPIO, AD_AUX_V_07 );
  if (err != SPI_CRC_OK) cprintf("Err rqst gpio V_07 %c\n", err);


  ip = last_a2d ( CS_PITCH, AD_POT );
  
  ir = last_a2d ( CS_ROLL, AD_POT );
  DelayMilliSecs ( 100);
  
  v7  = last_a2d (CS_GPIO, AD_AUX_V_07 );
  
  //ms1 = RTCElapsedTime( &rt)/1000 +1;
  // takes ~350ms for the 5 above ~70ms ea
  
  vac = r_get_a2d (CS_GPIO, AD_AUX_VAC );

  //ms2 = RTCElapsedTime( &rt)/1000 +1;
  // takes ~720ms for the 3 samples above: ~240ms ea
  AD_Off; // jul13, make sure it is off

  if (ip<0) cprintf("Err get pitch pot\n");
  else cprintf("Pitch pot = %6d\n", ip);

  if (ir<0) cprintf("Err get roll pot\n");
  else cprintf("Roll  pot = %6d\n", ir);

  x = c2eng( v14, W_14V )*0.01;
  if (v14>=0) printf("GPIO V_14 = %6d cnts = %5.2f V\n", v14, x);

  x = c2eng( v7, W_07V )*0.01;
  if (v7>=0) printf("GPIO V_07 = %6d cnts = %5.2f V\n", v7, x);


  x =-c2eng( vac, W_VAC )*0.01; //22Apr10 fixed bug
  if (vac>=0) printf("GPIO VAC  = %6d cnts = %5.2f in-Hg\n", vac, x);
  

  get_compass(  );
  
  return;
} //***************************************************************************

void   sample_all  ( void ) //*************************************************
{ // sample all analog channels and display
  ulong ms1, ms2, ms3;
  float x;
  RTCTimer rt;

  short err, ip, ir, v14, v7, amp=0, vac, alt, opt;
  RTCElapsedTimerSetup(&rt);
  AD_On; // jul13 make sure the a/d is on
  
  err = rqst_a2d ( CS_GPIO, AD_AUX_V_14 );
  if (err != SPI_CRC_OK) cprintf("Err rqst gpio V_14 %c\n", err);

  err = rqst_a2d ( CS_PITCH, AD_POT );
  if (err != SPI_CRC_OK) cprintf("Err rqst pitch pot %c\n", err);

  err = rqst_a2d ( CS_ROLL, AD_POT );
  if (err != SPI_CRC_OK) cprintf("Err rqst roll pot %c\n", err);
  
  if ( all.hyd->status != PUMP_WAIT ) 
     rqst_a2d (CS_HYD, AD_HYD_AMPS );
  
  v14 = last_a2d ( CS_GPIO, AD_AUX_V_14 );
  
  err = rqst_a2d ( CS_GPIO, AD_AUX_V_07 );
  if (err != SPI_CRC_OK) cprintf("Err rqst gpio V_07 %c\n", err);


  ip = last_a2d ( CS_PITCH, AD_POT );
  
  ir = last_a2d ( CS_ROLL, AD_POT );
  
  if ( all.hyd->status != PUMP_WAIT ) 
     amp = last_a2d (CS_HYD, AD_HYD_AMPS );

  v7  = last_a2d (CS_GPIO, AD_AUX_V_07 );
  
  ms1 = RTCElapsedTime( &rt)/1000 +1;
  // takes ~350ms for the 5 above ~70ms ea
  
  vac = r_get_a2d (CS_GPIO, AD_AUX_VAC );
  alt = r_get_a2d (CS_GPIO, AD_AUX_ALT );
  opt = r_get_a2d (CS_GPIO, AD_AUX_OPT );
  
  AD_Off; // jul13 make sure it is off

  ms2 = RTCElapsedTime( &rt)/1000 +1;
  // takes ~720ms for the 3 samples above: ~240ms ea

  get_hyd_ad ( );  //gets all of the hydraulic data
  // whether the pump is running or not
  // takes ~400ms pump off
  ms3 = RTCElapsedTime( &rt)/1000 +1;

  cprintf("timing = %ld %ld %ld\n",ms1, ms2, ms3 );
  //ms1 ~340, ms2 ~1085, ms3 ~1470
  if (ip<0) cprintf("Err get pitch pot\n");
  else cprintf("Pitch pot = %6d\n", ip);

  if (ir<0) cprintf("Err get roll pot\n");
  else cprintf("Roll  pot = %6d\n", ir);

  x = c2eng( v14, W_14V )*0.01;
  if (v14>=0) printf("GPIO V_14 = %6d cnts = %5.2f V\n", v14, x);

  x = c2eng( v7, W_07V )*0.01;
  if (v7>=0) printf("GPIO V_07 = %6d cnts = %5.2f V\n", v7, x);


  x =-c2eng( vac, W_VAC )*0.01;
  if (vac>=0) printf("GPIO VAC  = %6d cnts = %5.2f in-Hg\n", vac, x);
  
  if (amp>=0) printf("HYD_AMPS  = %6d\n", amp);
  if (alt>=0) printf("GPIO ALT  = %6d\n", alt);
  if (opt>=0) printf("GPIO OPT  = %6d\n", opt);
  // printf("pump status = %d\n", all.hyd->status );

  
  
  return;
} //***************************************************************************

short  altimeter( short dt ) //************************************************
{ // turn on the altimeter for dt s, take a/d
  // return a/d counts
     short ival;
     long tnow;
     tnow = RTCGetTime(0,0);
     
     Alt_On;
     AD_On;
     hibernate( &tnow, dt, PIT_ONLY );
     ival = r_get_a2d ( CS_GPIO, AD_AUX_ALT ); // get the value

     Alt_Off;
     AD_Off; 
     
     return ( ival );
} //***************************************************************************


short  c2eng ( short cnt, short type ) //**************************************
{ // type = sensor type
  // cnt = a/d cnts
  // convert from cnts to eng units
  short  off=0, gn=1.0;
  long  val=0;
  float mx = 0.01;  //used for 14V, 7V watchdog/gpio measurements
  
  switch(type) //====================================================
  { // get offset & gain for the type
    case W_14V   : gn = iparam[MA_wdt_c2v_14]; break;
    case W_07V   : gn = iparam[MA_wdt_c2v_07]; break;
    case W_VAC   : off = iparam[MA_wdt_Voff]; 
                   gn = iparam[MA_wdt_c2vac]; 
                   mx = 0.001; break;
    //case W_ALT   : gn = iparam[]; break;
    case W_OPT   : gn = iparam[MA_wdt_c2mv]; mx = 0.0001; break;
  } //===============================================================

  if ( cnt>0 )
  {
    
    val = ( cnt - off );  // difference recast as long
    val *=  gn;
    val *=  mx;
  }
  cnt = val; //recast as short
  return( cnt );
} //***************************************************************************

short battery(void) //***measure the pump battery voltage *****
{ // take a batt measurement
  // return value corrected for offset and gain * 100
  short ival;
  short  bat;
  
  AD_On; //jul13 make sure it is on
  ival = r_get_a2d ( CS_GPIO,  AD_AUX_V_14 ); // get the value
  if ( ival>0 )
  {
    // convert to V
    bat = c2eng( ival, W_14V); 
  }
  AD_Off; //make sure it is off
  
  return( bat );
} //*** end battery ********************************************

short  vacuum ( void ) //******************************************************
{ // take a vacuum measurement
  // return value corrected for offset and gain
  short ival;
  long  vac;
  
  AD_On; //jul13 make sure it is on
  ival = r_get_a2d ( CS_GPIO, AD_AUX_VAC ); // get the value
  if ( ival>0 )
  {
    cprintf("vac cnt=%5d ",ival);
    // convert to in-Hg
    vac = ( iparam[MA_wdt_Voff] - ival );  // difference recast as long
    vac *=  iparam[MA_wdt_c2vac];  //order 1000*diff
    vac *= 0.001; // now units are in-hg*100
    cprintf("Voff, gn= %d, %d  ",iparam[MA_wdt_Voff], iparam[MA_wdt_c2vac] );
    ival = vac;
    cprintf( " = %6d in-hg*100\n", ival);
  }
  AD_Off; //jul13 make sure it is off
  
  return( ival );
} //***************************************************************************

void vac_cycle ( void ) //*****************************************************
{ // show vacuum every 0.5s until '.' is entered
  short b=' ';
  cprintf("Type '.' to exit\n");
  do //==========================================================
  { // repeat until done
    vacuum();
    b =  SCIRxGetCharWithTimeout( 500 ); // get a new character
  } while ( b != '.' );
  
  return;
} //***************************************************************************

void a2d_cycle ( void ) //*****************************************************
{ // user selects sensor to sample every 1s
  short b=' ', n, j, ns, se;
  
  cprintf("Select sensor to sample every 1s\n");
  cprintf("0=14V battery, 1=7V, 2=Vacuum, 4=optical\n");
  j = get_num( &n );
  if (j !=1) return; // not valid channel, return
  
  switch(n) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  { // choose the right cs and chan for the sensor chosen
    case 0 :  j= AD_AUX_V_14; se = W_14V; break;
    case 1 :  j= AD_AUX_V_07; se = W_07V; break;
    case 2 :  j= AD_AUX_VAC;  se = W_VAC; break;
    case 4 :  j= AD_AUX_OPT;  se = W_OPT; Opt_On; break;
  } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  cprintf("Type '.' to exit\n");
  AD_On; //jul13 make sure it is on at start
  do //==========================================================
  { // repeat until done
    n = r_get_a2d ( CS_GPIO, j ); // get the value
    if ( n>0 )
    {  
       cprintf("cnt=%5d ", n );
       ns = c2eng( n, se );
       cprintf( " = %6d [unit]*100\n", ns);
    }
    b =  SCIRxGetCharWithTimeout( 700 ); // get a new character
  } while ( b != '.' );
  
  Opt_Off;
  AD_Off; // jul13 make sure that it is off at the end.
  return;
} //***************************************************************************

void opt_cycle ( void ) //*****************************************************
{ // cycle on the optical sensor, set up to mimic actual sampling
  short b=' ', n, j=0, ns, d1, d2, d3 = 500;
  
  // cprintf("Give time (#0.1s ticks) for warm-up \n");
  // j = get_num( &n );
  // if (j !=1) return; // not valid channel, return
  // d1 = n*100; // milli-sec
  d1 = 1000; // 1s warm-up
  
  /* cprintf("Give time  between samples \n");
  j = get_num( &n );
  if (j !=1) return; // not valid channel, return
  d2 = n*1000 - d1 -d3; // milli-sec
  if (d2<10) d2 = 10; */
  d2 = 2000; // 2s sample rate
  
  
  cprintf("Type '.' to exit\n");
  do //==========================================================
  { // repeat until done
    Opt_On; // turn on the optics
    AD_On; //jul13 make sure it is on at start
    DelayMilliSecs( d1 ); // wait for warm-up
    n = r_get_a2d ( CS_GPIO, AD_AUX_OPT ); // get the value
    if ( n>0 )
    {  
       cprintf("cnt=%5d ", n );
       ns = c2eng( n, W_OPT );
       cprintf( " = %6d [milli-volts]\n", ns);
    }
    Opt_Off;
    AD_Off; // jul13 make sure that it is off at the end.
    b =  SCIRxGetCharWithTimeout( d3 ); // get a new character
    DelayMilliSecs( d2 ); // wait for warm-up
    
  } while ( b != '.' ); //=======================================
  
  return;
} //***************************************************************************



//*** functions to do satellite data packing **********************************
//*** MAY03 modified for ISU
//*** feb04 modified to use all->flt->pmin value for surface
//*** mar04 modified to look for dBar>1 to start averging
//*** sep04 modified to using (long) temporary arrays for averaging/packing
//    this buys us not having to worry if using short or ushort data
//    so we can pack time series that have + and - values
//*** may05, added option to process the optical
//*** 0612 modified for new Profile data structure
//    data structure = time, Press, Temp, Sal, Optical, nsbe
//    also packs the engineering data time-series
//*****************************************************************************

short data_pack( void )  //****************************************************
{ //*** average and pack data for iridium xmit ********************************
  // does time averaging of P, T, C, & optical then does messaging
  // returns # bytes written to the temporary buffer
  short n, navg,npts, *dptr, nrec;
  short i, i0,j, num_avg, nsbe_off, jsbe ;
  long x[MAX_AVG_PTS];  //=temporary buffer of averaged data
  ushort *usp;  // will point to x output position
  ushort psurf, p;  // first value of p : should be surface
  char b[MAX_AVG_BUF]; // =tmp buffer of the packed data + overhead
  float pval;
  struct dat_param *DP;
  #if DO6==1
    short nsensors=5; //p,t,s,opt,dox,adp
  #elif DOX==1
    short nsensors=5; //p,t,s,opt,dox,adp
  #else
    short nsensors=4; // may05 default to all 4 sensors
  #endif
  //--mar11, define sensor ID: type=MSN, ver=LSN for ID byte
  //                   P, T, S, Opt,DO, 2nd opt.
  ushort s_type[6] = { 1, 2, 3, 4, 4, 4 };
  ushort s_ver[6]  = { 0, 0, 0, 0, 8, 2 };

 
  //--- initialize ------------------------------------------------------
  #if DOX==0 && DO6==0
    if ( iparam [ IA_use_opt ] ==0 ) nsensors=3;  // don't do optical
  #endif  // if DOX==1, last in array is DOX..still want to send that.
  // could add flag to pass over processing below for isensor=optical,
  // but in five years, have always sent optical, so will ignore.
  DP = all.dat;
  npts = 0;
  n = DP->i;  //=# of points written out in time series
  cprintf("#pts in series = %5d\n",n);
  nrec = DATA_WORDS; //=#variables per record
  //--jan13 offset corrected to nsbe_off: old=-1; new=-2
  nsbe_off = DATA_WORDS - 2; // = offset from P to nsbe
  // old code(-1) actually had sbe_stat pointing at time,
  // which said SBE was bad if time rolled past 32767s.
  // note, the TT8 code had it right since 0612...
  // don't know how it got wrong previously
 //---------------------------------------------------------------------
  
  
  // Search for where we're 1 m off surface -----------------------------
  // This is so we only use profile where we're off the surface ---------
  usp = (ushort*) ( DP->dat )+1; // points to first P  (+0=seconds)
  psurf = all.flt->pmin;  // =avg press from start of dive
  i0=0;  pval=0; j=1;
  while ( (i0<n) &&  (pval<1.0)  ) //------------------------------------
  { // keep looking until pval>1 
    usp += DATA_WORDS;  // point to next pressure input
    i0++; // increment counter
    p = *usp;
    jsbe = *(usp + nsbe_off); // jsbe>0 if good profile data, else=0
    // debug: printf("%d %6d %6d  \n", i0, jsbe, p );
    if (jsbe>0) 
    {
      pval = dBar(p, all.flt);
    }
    else
      pval=0; // DO NOT include in the profile
    
  } // end while pval<1 -------------------------------------------------
  //---------------------------------------------------------------------
  
  i0--; // decrement counter so it points to last one tested  
  if (i0<0) i0 = 0; // oct06, keep legal in case n=0
  n = n - i0;  // discard pts we are not using
  printf("psurf = %u p0 = %u  ",psurf,p);
  printf("1st point to use = %3d, new #=%5d\n",i0,n);
  // now have the 1st point to use --------------------------------------
  
  
  //---------------------------------------------------------------------
  // do a time-average to limit overall amount of data < MAX_AVG_PTS
  navg = n/MAX_AVG_PTS + 1;  //min averaging allowed w/o buffer overflow
  num_avg = iparam [ IA_num_avg ]; // = desired # to avg per output pt
  // use num_avg unless navg>num_avg
  if (navg > num_avg) num_avg = navg;  //this makes sure we don't overflow
  all.eng->navg = num_avg;  // save #pts averaged in engineering
  //---------------------------------------------------------------------

  //feb04, now that navg has been set, store the engineering data
  all.eng->psurf = psurf;  // = surface pressure, feb04
  // aug04 moved eng_nav_store here so drx, dry are updated for ea profile
  eng_nav_store( );  // store rest of the eng data to the eng structure

  if (n>0) //------------------------------------------------------------
  { // then pack the data -----------------------------------------------
    for (i=0;i<nsensors;i++)  // do for P, T, and C & optical
    { //.................................................................
      // >BF, can add packing option dependent upon ee_use_opt mask
      // only do the following if the right bit is set
      j = nsbe_off -i; // address distance between sensor & DP->nsbe flag
      printf("processing sensor %d offset to nsbe=%d\n",i,j);
      dptr = (all.dat->dat)+i+1;  // pointer to data buffer
      dptr += (long)i0 *nrec;  // skip past surface values
      printf("call=avg_dat(%d,%p,%d,%d,%d,%ld,%d)\n",i,dptr, nrec, num_avg,n,x,j);
      npts = avg_dat(i,dptr, nrec, num_avg,n,x,j);  //average time series
      // now we want to store npts of x to the tmp output area = b
      // >BF sensor type 5 = ADP, so following will need to be changed
      // for opt2, oxy2.  I suggest:
      // opt1, opt 2, oxy2 = sensor 4,
      // version 0, 1, 2 respectively.
      // an array of sensor type/version could be used for lookup with i
      //  s_type[6] = { 1, 2, 3, 4, 4, 4 };
      //  s_ver[6]  = { 0, 0, 0, 0, 1, 2 };
      //  pack_dat(b,x,npts, s_type[i], s_ver[i] );
      // mar11 packing change to use s_type, s_ver
	  // npts = pack_dat(b,x,npts,i+1,0 );<--DOX, replace this call with:
	  npts = pack_dat(b,x,npts, s_type[i], s_ver[i] );
	  // now append this on to the end of lifo
#if BENTHOS==1 || NPS==1
    //start a new LIFO message for profile data to make sure all of
    //profile ends up in the same Iridium message
    if(i==0)
	    new_msg_lifo(npts,(unsigned char *)b);
    else
	   append_lifo(npts,(unsigned char *)b);
#else
	  append_lifo( npts,(unsigned char *)b);
#endif
    } // end for i=0,1,2,3 = P, T, C, optical ...........................
  } // end if n>0 -------------------------------------------------------
  
  // JUL04 write out the eng at the end of the sensors, & update the dive #
  lifo_eng( ); // appends the engineering data to the lifo
  // write to the cf1 is done in lifo_eng, before it is zeroed out
  eng_pack( );  // pack engineering time-series data as well
  

  return(npts); 
} //*** end data_pack *********************************************************


#define E_SBD_CHAR 0x0c  // character to identify as eng. time series
short eng_pack( void )  //*****************************************************
{ // pack the engineering data time series ************************************
  // returns # bytes written to the temporary buffer
  // eng. data has been stored in take_data at desired decimation sample rate.
  
  short n,npts, *dptr, msk, ndec, b0, ib, j;
  long   x[MAX_AVG_PTS]; // temporary buffer of averaged data
  long   xx, x0=2000;    // tmp values
  char   b[MAX_AVG_BUF]; // tmp buffer of the packed data + overhead
  struct dat_param *DP;
  short n_sensor;
  
  n_sensor = ET_WORDS + 2; // RAM has ET_WORDS + time + press for ea scan

  // ---- initialize ----------------------------------------------------
  DP = all.dat;
  npts = 0;  // # of output points
  n = DP->ie;  //=# of points written out in eng. time series
  if (n> MAX_AVG_PTS ) n = MAX_AVG_PTS; // error-bounds checking
  //---------------------------------------------------------------------
  
  // Read in engineering choices  ---------------------------------------
  ndec = iparam [ IA_eng_ndec ];  // # of points to decimate
  b0   = iparam [ IA_eng_mask ];  // eng. bit mask of sensors to send
  if (ndec<=0 || n<=0 || b0==0 ) return(0); // nothing to pack, return
  //---------------------------------------------------------------------
  
  msk = 1;  // bit mask  +++++++++++++++++++++++++++++++++++++++++++++++++
  for (ib=0; ib<7; ib++) //+++++++++++++++++++++++++++++++++++++++++++++++
  { // check each bit to see if we need to send this info ++++++++++++++++
    
    if ( (b0 & msk)  >0) //------------------------------------------
    { // then send this sensor
       dptr = DP->eptr + ib;  // 1st point to output
       for (j=0; j<n; j++ )  //......................................
       { // copy over into temporary array x
         xx   = *dptr;
         if ( ib==5 || ib==6 )  // pitch or roll counts
         { // if xx<0, then comms error
           if  ( xx<0 ) xx = x0; //set to last good value
               else     x0 = xx; //save value as last good
         }
         x[j] = xx;
         dptr  += n_sensor; // point to next input value
       }  // ........................................................
	   npts = pack_dat(b, x, n, E_SBD_CHAR, ib );
	   // append this to the end of lifo
	   append_lifo(  npts, (unsigned char *)b);
       
    } // end if b0 is set -------------------------------------------
    
    msk = msk*2; // shift msk to the next bit to check
  } // end for ib ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    
  return(npts); 
} //***************************************************************************

//*****************************************************************************
short avg_dat(short ix,short *dptr,short nrec, short navg, //******************
              short n, long *x, short nsbe_off)
{ // average time series :
  // ix=0..3 : 0=press, 1=T, 2=S, 3=opt
  // dptr points to 1st datum,
  // each datum is offset by nrec
  // navg = #input pts to average for ea output point
  // n = total # input pts
  // x points to output array
  // nsbe_off = addr distance from sensor ix to nsbe flag
  //		nsbe = 0 if no data, else nsbe = 1
  // returns # written out to x
  
  short i,j,k, kk, jsbe;
  ushort *up, val, minval, cfake;
  long avg =0;  // accumulator for avg
  
  #if SBE==1
    minval = 20000;  // SBE  C cell min value = 19 PSU
    cfake  = 35000;  // SBE fake value = 34 PSU
  #else
    minval = 46000;  // PME C cell min value
    cfake  = 52000;  // fake PME C value to try to keep autoranging acceptable
  #endif
  
  // flag bad conductivity/salinity points ------------------------------
  if (ix==2) //----------------------------------------------------------
  {  // remove C outlier values using value of ~25 mmho/cm
     // C range is ~ 32768..65536 over 65 mmho/cm
     // don't believe anything less than 25 mmho/cm ~ 46000 cnts
     up  = (ushort*) dptr;  // point to beginning
     for (i=0;i<n;i++) //..........................................
     {   // step through all points
        val = *up;
        if ( val< minval ) *up=0;  // set to not-valid value
        up += nrec;  // point to next input
     } // end for all C points ....................................
  } // end if C outlier fix ---------------------------------------------
  else if (ix==3) //-----------------------------------------------------
  { // fix optical data series ------------------------------------------
    // aug10 addition to keep drop-outs from being averaged
     up  = (ushort*) dptr;  // point to beginning
     for (i=0;i<n;i++) //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
     {   // step through all points
        kk = (short) *up; // signed value: <0 =comms error
        if ( kk< 0 || kk>4100 ) *up=0;  // set to not-valid value
        up += nrec;  // point to next input
     } // end for all  points ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  } // end if optical fix -----------------------------------------------
  
  // initialize counters ------------------------------------------------
  i=0;  // i counts # input points processed so far
  j=0;  // j points to next output point
  k=0;  // = #pts averaged so far into temporary accum.
  kk=0; // = #valid pts
  up = (ushort*) dptr;  // point as unsigned short
  //---------------------------------------------------------------------
        if (Verbose) 
     { printf("avg_data: i=%d, n=%d, dptr=%p,up=%p\n",i,n,dptr,up);
       DelayMilliSecs(1000); // 1 second delay to let print
      }
  while (i++<n) //-------------------------------------------------------
  { // step thru all of the input samples -------------------------------
    val = *up;
    jsbe = *(up + nsbe_off);
    if(Verbose)
     printf("up = %p, val = %x\n",up,val);

    if (jsbe>0) //then it is valid ..........................
    { // we got it w/o error from SBE
      if (val>0) // ..........................
      {  // valid #, add into accum.
         avg += (long) val;   //  add value
         kk++;
      } // end if good value .................
      
      k++; // increment #valid points averaged so far
    } // end if jsbe>0 ......................................

    up += nrec;  // point to next input
    
    if (k==navg) // .........................................
    {  // then it's time to average
       if (kk>0) // then enough pts to include in avg
          x[j++] = avg/kk; //save avg value
       else  //...............................
       {// NO points in the data series, set to a fake value
        // JUL04 SBE code, only happens when Salinity<minval
           if (ix==2) 
              x[j] = cfake;  // KLUGE for C
           else 
           { //mar11, catch bad very first point, i.e. w/DOX
             if (j>0)
             { x[j] = x[j-1]; }// set to last valid value
             else { x[0] = 0; }// init to 0
           } // end handling no good point
           j++; // increment output pointer no matter ix
       } // end if kk..else ...................
       
       k=0;     // reset #valid jsbe points
       kk=0;    // reset #points>0
       avg=0;   // reset accum.
    } // end if k==navg .....................................
    
  } // end while i<n ------------------------------------------------------
  //-----------------------------------------------------------------------

  if (kk>0) //-----------------------------------------------
  { // then there are a few points left to average
    x[j++] = avg/kk; // save the last value
  } // end kk>0 ---------------------------------------------
  
  return(j);  //return # written out
} //*** end avg_dat ***********************************************************


short pack_str( char *b, char *x, char id, short n,  //************************
                short itype, short iver )
{ // pack n bytes from x to output char array b,
  // id = character id for this particular string
  // itype = data type,  iver = version #
  // Returns n=total length[bytes] of the packed string
  
  short i,k;

  b[0] = itype*0x10 + iver; // flag type of data & version
  // b[1], b[2] = # of bytes to follow, fill in at end
  b[3] = id; // store the string identifier
  
  k=4; // start string xfr at b[4]
  for (i=0;i<n;i++) //---------------------------------------------------
  {  // step thru all pts -----------------------------------------------
     b[k++] = x[i];  
  } //   end for i<n ----------------------------------------------------
  

  b[k++] = ';'; // add the end character
  
  // k= total # bytes written out
  // which gets stored after the sensor id byte:

  i = b2_store(1,(uchar*)b, k );
  
  return(k); // return #bytes in packed buffer b
  
} //***************************************************************************

//=============================================================================
//=== sep16, defining new packing that stores one more ID byte.
//=== this allows expansion of #sensors+data packets.
//=== this is first being used with zooGlider data.
short pack_dat2( char *b, long *x, short n,  //********************************
                short itype, short iver, short id2 )
{ // pack n data pts from x to output char array b,
  // itype = data type,  iver = version #
  // id2   = extra id byte, sep16
  // Returns n=total length[bytes] of the packed data
  short i,j,k;
  long y[NSUB];  // tmp array buffer

  b[0] = itype*0x10 + iver; // flag type of data & version
  // b[1], b[2] = # of data bytes to follow, fill in at end
  
  j=0;  // = points to y array
  k=3; // start filling output data at b[3]
  b[k++] = id2; // sep16, add the extra ID byte
  
  for (i=0;i<n;i++) //---------------------------------------------------
  {  // step thru all pts -----------------------------------------------
     y[j++] = x[i];  // fill up tmp array
     if (j==NSUB) //then full ...........................
     { // this does the first-difference
        pack_sub(y, b, j, &k);  //go pack the subset
        j=0;  // reset tmp ptr
     } // end if j==NSUB ................................
  } //   end for i<n ----------------------------------------------------
  
  if (j>0) pack_sub(y, b, j, &k);  //pack the last part
  b[k++] = ';'; // tack on the end data character
  
  // k = total # bytes written out
  // which gets stored after the sensor id byte:
  i = b2_store(1, b, k ); // store #of bytes @ b[1],b[2]
  
  return (k); // return #bytes in packed buffer b
} //***************************************************************************

short pack_dat( char *b, long *x, short n,  //*********************************
                short itype, short iver )
{ // pack n data pts from x to output char array b,
  // itype = data type,  iver = version #
  // Returns n=total length[bytes] of the packed data
  short i,j,k;
  long y[NSUB];  // tmp array buffer


  b[0] = itype*0x10 + iver; // flag type of data & version
  // b[1], b[2] = # of data bytes to follow, fill in at end
  
  j=0;  // = points to y array
  k=3; // start filling output data at b[3]
  for (i=0;i<n;i++) //---------------------------------------------------
  {  // step thru all pts -----------------------------------------------
     //printf("x[i]=%ul\n",x[i]);
     y[j++] = x[i];  // fill up tmp array
     if (j==NSUB) //then full ...........................
     { // this does the first-difference
        pack_sub(y, b, j, &k);  //go pack the subset
        j=0;  // reset tmp ptr
     } // end if j==NSUB ................................
  } //   end for i<n ----------------------------------------------------
  
  if (j>0) pack_sub(y, b, j, &k);  //pack the last part
  b[k++] = ';'; // tack on the end data character
  
  // k= total # bytes written out
  // which gets stored after the sensor id byte:
  // aug03 removed (char) type-casting below
  b[1] =  ( k & 0xff00 ) >> 8; // = MSB
  b[2] =  ( k & 0xff ); // LSB
  return(k); // return #bytes in packed buffer b
  
} //***************************************************************************


void pack_sub(long *y, char *b, short n, short *k) //**************************
{ // pack n points of y into b[k]
  // Takes first-diff of y and auto-scales for the n points
  
  short scale, i, kk;
  long idy, ady, tmp, dymax;
  char  btmp;

  // Compute the auto-scaling +++++++++++++++++++++++++++++++++++++++++++++
  dymax = 0;  //=maximum 1st-diff encountered
  for (i=0;i<(n-1);i++) //find maximum 1st-diff -------------------------
  {  idy =  y[i+1] -  y[i];
     ady = abs( (int) idy);
     if (ady>dymax) dymax = ady;
  } // end for i --------------------------------------------------------
  
  scale = (dymax + YMAX) / YMAX;  // scalar, rounded up
  if (scale>255) scale=255; //limit it's max value
  if (scale<1)   scale=1;   //limit it's min value
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  // save scale + first value
  kk = *k;    //=1st output index value
  b[kk++] = (char) scale;
  b[kk++] = (char) ( y[0] >>8 ); //save high byte
  b[kk++] = (char) ( y[0] & 0xff); //save low byte
  tmp  = (long) y[0];  // tmp gets re-integrated below
  
  for (i=1;i<n;i++) //---------------------------------------------------
  {  // step thru the rest of the points --------------------------------
     idy =  y[i] - tmp;  // = 1st-diff
     if (idy>0) idy = ( idy + scale/2.)/scale;  //round up
     if (idy<0) idy = ( idy - scale/2.)/scale;  //round down
     btmp = (char) (idy & 0xff);  // assign btmp low byte
     if (idy>127) btmp = 127;  // if overflow, set to max val
     if (idy<-128) btmp = -128;  // if neg. overflow, set to min value
     b[kk++] = btmp;  //save temp value
     tmp += btmp*scale;  // integrate using scaled trunc errors
  } // end for : all pts now processed //--------------------------------
  
  *k = kk;  // return new output point
  return;
} //***************************************************************************


void eng_nav_store( void ) //**************************************************
{ // store nav parameters to engineering structure
 short xdeg,  xmin;
 struct eng_param *eng;
 struct nav_param *nav;
 
 eng = all.eng;  // point to eng params
 nav = all.nav;
 
  // write out pitch and heading
  eng->head  = nav->true_theta;
  eng->pitch = iparam[ IA_glide_angle ];

  eng->drx = (short) nav->drx;
  eng->dry = (short) nav->dry;

  // write out waypoint latitude
  store_waypt( nav->wlat,&xdeg, &xmin);
     eng->ydeg = xdeg;
     eng->dy   = xmin;

  // MAY06 write out waypoint longitude
  store_waypt( nav->wlon,&xdeg, &xmin);
     eng->xdeg = xdeg;
     eng->dx   = xmin;

  return;
} //***************************************************************************


//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
void daq_test  ( void ) //*****************************************************
{
  char ch;  //input char
  short  done, tmo;
  long tnow;
  uchar dat[256];
  short i, n;

  n = 20;
  for (i=0;i<n;i++) dat[i] = i + 48;  //initialize

	cprintf("         DAQ test : %s \n", __DATE__);
	
	daq_menu();
  
	done = false;
	tnow = RTCGetTime(0,0);  // gets present time
	tmo = 0;
	while (!done) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	{  //cycle until we get a quit command

		
		while ( SCIRxQueuedCount() )
		    SCIRxFlush(); // delete any old stuff 
        if (ch !=' ' && ch>0 ) printf("D_1>\n"); // display directory prompt
	    ch = -1; // illegal value - means it timed out
	    ch = SCIRxGetCharWithTimeout( 1000 ); // get a new character
	    tmo = check_tmo ( &ch, tmo );
	    // increments the tmo counter if ch<0, and
	    // goes to sleep mode after max_tmo.  Returns *ch as upper-case
	    
	    //================================================================
	    switch(ch ) //====================================================
	    { // and depending upon the cmd, do the appropriate action =======
	    
        case 'Q' :  done=1; break; //quit function
        case '?' :  break; // causes directory prompt to be displayed
        case ' ' :  break; // wait for another character
        case 'U' :  daq_menu(); break;
        case  -1 :  break; // wait for another character


        case 'C' :  a2d_cycle(); break;
        case 'O' :  opt_cycle(); break;
  
		case 'S' :  sample_sub();break;
		case 'T' :  sample_all();break;

        case 'V' :  vac_cycle(); break;
        //22mar10, test any fnx here
        case '1' :  test_dat_pack(); break;
        #if DOX ==1 || DO6==1
        case '2' : test_DOX( ); break;
        #endif

        default  : printf(" input unknown \n");
	} // end switch ------------------------------------------------
	
  }  //*** end while ++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  return;
}  //**************************************************************************

void daq_menu(void) //*********************************************************
{ //print out menu selections 
 printf("                Data-Acquisition Menu\n"
 		"Q.uit  test     :   U.pdate menu    O.pt cycle     2.DOX test\n"
        "S.ample all     :   V.acuum cycle   C.ycle sensor  T.est all\n");
 return;
} //***************************************************************************

void test_dat_pack ( void ) //*************************************************
{ // bench test of data storage and packing
  int i, n;
  struct dat_param *DP;
  ulong tnow;

  
  tnow = RTCGetTime(0,0);
  all.time->ti_cyc = tnow -300;  //fake start time
 #if PH==1
  start_ph(); //make sure pH is powered up
 #endif
  DelayMilliSecs(1000);
  DP = all.dat;
  DP->i  = 0;
  DP->ie = 0;
  n      = DP->max; // max #data points
  n = 20;
  
  for (i=0;i<n;i++) //===========================================
  { // fill the arrays
     DP->ds.secs  = 32800 - i;  
     DP->ds.p     = 32800 - i;  
     DP->ds.t     = 20000 + i;  
     DP->ds.c     = 35000 + i;  
     DP->ds.optic = 36700 + i;  
     DP->ds.nsbe  = 1; //profile status: 0=bad, 1=OK, or >0 is sample #
 #if PH==1 //Sep 18 ==================================================
     ph_send_ss();
     DelayMilliSecs(1000);   
     ph_get_sl(all.ph);

     printf("phv1=%d, phv2=%d, phv3=%d, phv4=%d, phv5=%d, phv6=%d\n",
                  all.ph->phv1, all.ph->phv2, all.ph->phv3,
                  all.ph->phv4, all.ph->phv5, all.ph->phv6);
     DelayMilliSecs(4000);
/*         all.ph->phv1= 1 + i;
         all.ph->phv2= 10 + i;
         all.ph->phv3= 100+i;
         all.ph->phv4= 1000+i;
         all.ph->phv5= 2000+i;
         all.ph->phv6= 3000+i;
         */
     store_ph_dat(all.ph);
 #endif //=================================================================
     store_pro_dat( DP ); // store the data to RAM
     //do the same for the eng. data
     //store_eng_dat( DP ); // will store eng data if needed
     tnow += 10;
     RTCSetTime(tnow,0); // new fake time
  } //===========================================================
  
  //=== now pack the data =======================================
    all.klifo = assign_lifo(all.lifo, 1,0); //starts new packet
    cprintf("data_pack\n");
    data_pack( );
 #if PH==1
    cprintf("ph_pack\n");
    ph_data_pack();
    ph_off(); 
 #endif
    display_lifo( all.lifo );
    cprintf("parse_lifo\n");
    for (i=0;i<NSECTORS;i++) //==========================================
    {  // get info for each sector
      parse_lifo(all.lifo,  i );
    }  
  return;
} //***************************************************************************

//gain factors
#define NO3_GAIN 100.0  // specs say resolution is 0.05, but reported to 0.01 res.
#define RMS_GAIN 1e6    // sample data show 1-6e-4, so this should give 100-600 cnts

void test_str_read( void ) //**************************************************
{ // test of a formatted string read
  short err=0, n, i, j=0, k=0;  // j=ptr into the sget, k=ptr into tmp
  short nk; // final length of tmp
  short ns; // # of variables scanned in
  unsigned short uval;
  short sval;
  
  short fit[2];
  char sget[80];
  char tmp[400], c; // individual string, longest = spectra data =164bytes
  float x,  t[12];
 
  printf("Give input string with floating-point entries \n");
  gets(sget);
  printf("\n");
 
  n = strlen(sget);
  i = 0; // field identifier
  while (j<n)  //==========================================================
  { // parse all char in the string
    c = sget[j++]; // get the next char
    
    if ( c == ',' || j>=n ) //----------------------------------------
    {  // at a comma, or end of string
       // parse tmp 
       tmp[k] = 0; // put end-of-string marker
       nk = k; // =#char in tmp
       
       printf("%3d:%3d  ",i,nk );
       for (k=0;k<nk;k++)
       { printf("%c", tmp[k] );
         if ( (k+1)%60 == 0 )
           { printf("\n"); }
       }
       printf("\n");
       
       if ( i<8) // value = 3-7 = float
       { //--------------------------------------------------
          ns = sscanf(tmp,"%f",&x); // scan in the #
          if (ns != 1)  x= -1; // set to illegal value
          t[i] = x;  // store in a tmp array
       } //--------------------------------------------------
       else if ( i==8 || i == 9 )
       { sscanf(tmp,"%d", &fit[i-8] ); } // FIT BEG and END

       
       i++;   // increment field counter
       k = 0; // reset k
    }
    else tmp[k++] = c; // else store the char ----------------------
  
  } //=====================================================================
  
  n=i; //#of input arguments
  printf("Read in %d arguments\n", n);
  for (k=0;k<n;k++)\
  {
    x = t[k]*NO3_GAIN;
    // lval = (unsigned long) ( t[k] * NO3_GAIN ); //set to 0 if <0
    uval = (unsigned short) ( t[k] * NO3_GAIN ); 
    sval = (short) ( t[k]*NO3_GAIN );
    uval = (unsigned short) sval;
    printf(" t[%2d]=%8.3f scaled=%u,  %d\n",k,t[k], uval,  sval );
  }
  printf("\n");
  
  
  return;
} //***************************************************************************


#if DOX==1 || DO6==1 //********************************************************
  void   test_DOX  ( void ) //test DOX data
   {
    short  b=' ';
    unsigned short k=0;
    unsigned short npts=0;
    short  irq_flag;
    short dt;
    ulong tnow;
    
    
    tnow = RTCGetTime(0,0);  // get the time
    dt = SAMP_DT_UP;  // time between samples
    flash_open('D');  // open a new file (also adds a dive and time marker)
    
    all.klifo = assign_lifo(all.lifo, 1,0); //starts new packet
    cprintf("How many data points to take?:");
    scanf("%d",&npts);
    cprintf("\nsbe_start_profile....\n");
    sbe_start_profile( );
    cprintf("Take %d data points\n",npts);
    
    do //============================================================
    { // repeat until done
       irq_flag = hibernate( &tnow, dt, PIT_IRQ2 );
       if ( irq_flag == IRQ2_F ) //----------------------------
       { // interrupt from msp430,
         cprintf("Wake-up from CF2_ATTN\n");
         service_wdog(); // service the CF2
       } //----------------------------------------------------
       take_data( );

       b =  SCIRxGetCharWithTimeout( 500 ); // get a new character
    } while ( b != '.' && k++<npts); //==============================

    flash_close();
    
    cprintf("sbe_stop_profile\n");
    sbe_stop_profile( );
    
    cprintf("data_pack\n");
    data_pack( );
    
    cprintf("parse_lifo\n");
    parse_lifo(all.lifo,all.klifo);
    
    cprintf("\nDone with test_DOX\n");
    
    return;
   }//*************************************************************************
#endif     
//*****************************************************************************     

//*** END *********************************************************************
