/******************************************************************************
//  adp.c  : Nov 2008
//  control of Sontek ADP
//  for the Spray 2008 CF2 controller board
//
//==== Future Expansion =======================================================
//		last update: Feb2009
//
//	1. Debug menu with most fnx's moved here
//	2. 
//  3. 
//
//****************************************************************************/

#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    "dat_fnx.h"
#include    "tcm2.h"
#include    "lifo.h"
#include    "sbe.h"
#include    "adp.h"
#include    "ntk.h"
#include    "gpio_mux.h"
#include    "setup.h"

//used to test program size...can be removed at some point
const long gdum[64] = {
0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// 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;



#define ADP_START 0xb0  // start byte for Sontek LONG format data
#define N_ADP_OFF 38 // index to first byte in the profile
   //this is after already dropping the first 2 bytes on reading it in
   //38 = 41-byte record - first 2
   
// #define MOUNT_ANGLE 17 // mounting angle in pitch axis oct14, moved to setup.h
// jun07, changed blanking distance from 2.0 to 4.0 m
#define ADP_ENS_N 16 // =#pings to avg per ensemble
#define SS 2.0 // 0711, scalar for shallow-mode

/*JAN14 moved to adp.h so ntk.c can access
// Define max #bytes write out, ADP_NCELL is defined in setup.h
#define N_ADP_PROFILE ( 12 * ADP_NCELL ) // MAX #bytes in profile = 12*ncells
#define N_ADP_BYTES ( N_ADP_PROFILE + 41 )
	 // N_ADP_BYTES =  MAX #bytes in the returned LONG ADP data stream
#define N_ADP_OUT ( N_ADP_PROFILE + 6 ) // MAX #bytes for output in one scan
#define ADP_PMIN 5    // depth to stop ADP profiling on ascent
	// start depth is in eeprom at ee_adp_zmax
	// max # of scans per ascent = ADP_NSCANS, is in setup.h
*/

// define parameters for beam-to-local coordinate transformation
#define SQRT3  1.73205  // = sqrt(3)
#define S_TDX  0.42262  // = sin(25), 25 = TDX angle wrt horizontal
#define C_TDX  0.90631  // = cos(25)

// altimeter settings
#define ALT_RANGE 30 // range [m] for csset (along system z axis)
#define ALT_BDSET 2 // blanking distance [m] in altimeter mode
#define ALT_PL 1 // pulse length [m]
#define ALT_HEADER 24 // #of bytes in the header block
#define ALT_MAX_NUM 512 // Max # points for an 40 m profile @ 0.0781 m sampling

#if NTK // define values for Nortek geometry ==================================
  // mar13
  // these are defined for pitch=17.38 deg, which for the three beams used,
  // puts their central axis the same as the vertical axis, and
  // makes all 3 tdx's angle wrt vertical = 30.12 deg, and
  // puts  the azimuth angle for the side beams = alpha = 57.36 deg from straight-ahead
  #define C_ZA 0.86498 // cos(30.12) = TDX angle @ pitch=17.38 deg.
  #define S_ZA 0.50181 // sin(30.12) = TDX angle @ pitch=17.38 deg.
  #define C_AA 0.53936 // cos(57.36) = azimuth angle @ pitch=17.38 deg.
  #define S_AA 0.84208 // sin(57.36) = azimuth angle @ pitch=17.38 deg.
   
#endif //======================================================================

//*** internal prototypes
void   menu_adp     ( void );
void   get_adp_scan ( unsigned char *abuf, short i0, unsigned short pr[],
  short phi[], short rol[], short head[], short vel[][ADP_NCELL],
  short amp[][ADP_NCELL], short noise[], short ENW  );
  
void   cross_uvw    ( float phi,short i,short j,short vel[][ADP_NCELL], short k);
float  get_sim      ( float z, float e0, float e1, float ek, float ep);
void   create_fake_adp ( void );
void   array_test      ( void );
void   adp_flash_test  ( void );
void   alt_test_check( void );

union chshort //===============================================================
{ // set up union where a short & ch[2] array are the same space
  short x;
  char  c[2];
}; //==========================================================================


short  adp_on ( void ) //******************************************************
{  // turn on the adp
   // returns TRUE if OK
   short istat = 0;
   struct spi_param *ss;
   
      ss = all.sspi; // points to the spi comms struct
      setup_spi ( CS_GPIO, ss );

  istat = spi_aux_pwr( AUX_ON_ALT, ss ); // modem now has power
  if ( istat != SPI_CRC_OK )
  { // error sending the 'ON' command
     cprintf("Err Stat on_adp = %d\n", istat);
     return (istat);
  } // else continue
  
  DelayMilliSecs(10);
  
  istat = spi_mux( 1, SER_ADP, ss ); // turn on rs232 & configure mux
  if ( !istat )
     cprintf("Err Stat mux_adp\n" );
  
  
  return ( istat );  // 1 if comms were OK 
} //***************************************************************************


short  adp_off ( void ) //*****************************************************
{  // Turn off the adp
   // returns 0 if off
   short istat = 0;
   char sleep[] = "sleep";
   struct spi_param *ss;
   //TUPort           *tup;
   
      ss = all.sspi; // points to the spi comms struct
      setup_spi ( CS_GPIO, ss );

    /*** aug11, following removed; remnant from sat_off
    tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
    tputs( tup, sleep);  // send the sleep command
    DelayMilliSecs(100);  //** wait to go to sleep
    ***/
    
    istat = spi_aux_pwr( -AUX_ON_ALT, ss );
    if (Verbose) cprintf("Err Stat off_adp = %d\n", istat);
    DelayMilliSecs(10);  // wait 
  
    istat = spi_mux( 0, SER_ADP, ss ); // turn off rs232, returns TRUE if ok
    if (!istat) cprintf("Err Stat off_mux\n");
    

  return ( !istat );  // returns 0 if spi_mux cmd was OK
} //***************************************************************************



#define CHKSUM_OFF 0xA596 // checksum offset, Sontek
// Jan2009, this fnx is not used
short adp_chk_chksum(unsigned char *sget) //***********************************
{ // check the checksum from the ADP packet
  // sget[0] = packet identifier byte
  // sget[1] = n = total #bytes in packet
  // sget[n-1] = last byte = packet checksum as calc'd from ADP
  
  unsigned short chksum;
  short i,n1;
  
  n1 = sget[1] -1; //=# of bytes in packet, -1 for the checksum
  chksum = CHKSUM_OFF; // init chksum
  for (i=0;i<n1;i++) 
    chksum +=sget[i];  // add up chksum
    
  cprintf("#bytes %d  chksum = %x , %x\n",n1+1,chksum,sget[n1] );
  chksum &= 0xff;  // just keep LSB 
  
  return(chksum);
} //***************************************************************************
  
void   adp_alloc  ( struct adp_param *adp ) //*********************************
// ** allocate memory for ADP serial in/out & data
{  unsigned char *buf;
   short i;
   long nbytes;
   long nout = N_ADP_OUT; // =max #bytes per ensemble for buffer array
   
   
   adp->pmin = 1000; //  keeps track of most-shallow adp sample

   for (i=0;i<3;i++)  // amin = noise floor for each beam
     adp->amin[i] = 0; // initialize to zero

   adp->nscans = ADP_NSCANS; // max #scans expected
   cprintf("adp max scans  = %d\n", adp->nscans);
   adp->iscan = 0;  // pointer to first data record
   nbytes = adp->nscans * nout;  // # of bytes to allocate
   //**allocate data buffer area
   buf = (unsigned char *) malloc(nbytes);
   if (buf == NULL)
   { printf("ERROR adp_alloc\n");
   }
   adp->buf = buf; // otherwise OK, store buffer pointer
   
   return;
} //***************************************************************************


void adp_setup0(void) // ******************************************************
{ // send setup commands : only needs to be done once
  // char sget[80];
    
  adp_cmd_rqst ( "compassinstalled set no"); // set to no compass
  adp_cmd_rqst ( "enableprofiling set d33b87"); // set to profile
  adp_cmd_rqst ( "tm user"); // user-supplied temperature
  adp_cmd_rqst ( "temp 13.30"); // forced temperature value
  adp_cmd_rqst ( "sal 33.90"); // forced salinity value
       // forced T, S results in sound speed = 1500 m/s
  adp_cmd_rqst ( "cy beam"); // use beam coordinate system
  adp_cmd_rqst( "CellEnd 10.0"); // jun11, make sure it is set to 10.0
  adp_cmd_rqst ( "df long"); // data format = long to include profile

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


void  adp_info ( void ) // ****************************************************
{ //  display adp setup
  
  adp_cmd_rqst ("SerNum");
  adp_cmd_rqst ("Ver");
  adp_cmd_rqst ("BD");
  adp_cmd_rqst ("plset");
  adp_cmd_rqst ("cs");
  adp_cmd_rqst ("nc");
  adp_cmd_rqst ("pingsperbeam");
  adp_cmd_rqst("PowerPing");  //Jun2011
  adp_cmd_rqst("CellEnd");    //Jun2011
  
  return;
} //***************************************************************************

short adp_cmd_rqst ( char *s ) //**********************************************
{ // give command s and echo the returned info (w/o CR/LF on the end)
  short nget, i, found;
  char r[81]; // returned string
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port

  tputs( tup, s ); // send the string
  nget = tgets( tup, r, 79, 1,'\n', &found); //=1st echo
     if (nget>2) {for (i=0;i<nget; i++) SCITxPutChar(r[i]); }  //display 1st echo
  SCITxPutChar(':');
  nget = tgets( tup, r, 79, 1,'\n', &found); //=2nd response
     if (nget>2) {for (i=0;i<nget; i++) SCITxPutChar(r[i]); } 
  SCITxPutChar(':');
  nget = tgets( tup, r, 79, 1,'\n', &found); //=2nd response
     if (nget>1) {for (i=0;i<nget; i++) SCITxPutChar(r[i]); } 
  SCITxPutChar('\n');
  
  return(nget>0);
} //***************************************************************************

short adp_wakeup ( void ) // **************************************************
{ // exit sample mode into main setup mode
  // returns TRUE if it returns with a prompt
  char sget[80];
  short nget, ok=0, found;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port
  
  tputs( tup , "++++++++++"); // this is equivalent of sending a break
  nget = tgets( tup, sget, 79, 1,'\n', &found); // get respone
  DelayMilliSecs(100); // wait for a response
  
  TURxFlush  ( tup );   // flush the tpu port
  tputs( tup, " "); // this should now return with a prompt
  nget = tgets( tup, sget, 79, 1,'\n', &found); // get respone
  if (nget>0) ok = 1;  // ok = got a response
  
  return( ok == '>');
} //***************************************************************************

void adp_sample_mode(void) // *************************************
{ // after setup, put ADP into 'sample' mode, where it will wait
  // for a requests to manually sample
  char sget[80];
  short nget, found;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port

  tputs( tup, "sample"); // sample mode
  nget = tgets( tup, sget, 79, 1,'\n', &found); // get respone
  
  DelayMilliSecs(2500);  // wait for it to enter sample mode
  return;
} //***************************************************************************

short  adp_exit_sample ( void ) //*********************************************
{ // exit sample mode, returns last char received while sending '+'
  char sget[80];
  short nget;
  // 0 = no response
  // any other = first byte response; '>'=62, '+'=43
  short i=0, ok=0, j=0, found, last=0;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port

  //Try to get a response from the ADP ================================
  while ( i++<100 && (last !='>') && (last != '+') )
  { // three '+' in a row will exit sample mode
    TURxFlush   ( tup ); // flush input buffer
    TUTxPutByte ( tup, '+', 0);   
    DelayMilliSecs(10); // wait for a response
    j=0;
    do //--------------------------------------------------
    { // flush characters (20ms time-out)
       ok = TURxGetByteWithTimeout( tup, 20 ); 
       if (ok>0) 
       {  last=ok;  // save last good char
          cprintf("%02x ",ok );
       }
    } while ( last !='+' && ok>0 && j++<10 ); //-----------
    
  } //=================================================================
  
  TURxFlush  ( tup ); // flush input buffer
  tputs( tup, "+++++++++"); // this should DEFINITELY cause an exit
  nget = tgets( tup,sget,79,1,'\n', &found); // get response
  //jul09 v3, add final check
  if (nget>0) last = sget[nget-1]; // return last value
  //jun13, modify to throwing away \r if present
  if (last == '\r' && nget>1 ) last = sget[nget-2];
  
  return( last );
} //***************************************************************************

short  adp_query ( void ) // **************************************************
{ // query the adp whilst in sample mode so it is ready to get a sample
  // -1 = no response
  // any other = first byte response
  short i=0, ok=-1;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port
  //Try up to 12x to get a response from the ADP
  while ( i++<12 && ok<0 ) //====================================
  { // I do not use a '+', as three '+' in a row will exit sample mode
    TUTxPutByte( tup,'a',0);  // 'a'=request for time remaining 
    SCITxPutChar('a'); // echo to the monitor
    ok = TURxGetByteWithTimeout( tup, 200 ); //get a byte, waits up to 200ms
    // ok<0 if timed-out...no char
    DelayMilliSecs(200); // wait for a response :
    if (ok<0) tputs( tup,"777777"); //try a LONG string to wake up
    // If the Sontek is low-power, the long string seems to work
  } //===========================================================

  TURxFlush  ( tup );   // flush the tpu port
  if (ok<0) //===================================================
  { // try to recover
    ok = adp_wakeup();
    cprintf(" query recover ok=%d\n",ok);
    if (ok==0) ok=-1; // set so adp_get_sample will fail
    adp_sample_mode(); // put in sample mode
  }  //==========================================================
  
  return(ok);
} //***************************************************************************

void   adp_set_alt ( void ) // ************************************************
{ // send setup commands for altimeter mode
  char sget[80];
  
  // set to sample ALT_RANGE out (system z axis)
     sprintf(sget,"csset %d\0", ALT_RANGE); 
     adp_cmd_rqst (sget); // send cmd & echo reply
  
   // set the blanking distance
     sprintf(sget,"bdset %d\0",ALT_BDSET);
     adp_cmd_rqst (sget); // send cmd & echo reply
  
   // set the pulse length
     sprintf(sget,"plset %d\0",ALT_PL);
     adp_cmd_rqst (sget); // send cmd & echo reply

  adp_cmd_rqst ("SaveSetup"); // save the values even when put to sleep
  
  DelayMilliSecs(1000);
  adp_info(); // display the setup

  DelayMilliSecs(1000);
  
  return;
} //***************************************************************************

void  adp_set_up ( float div ) // *********************************************
{ // send setup commands for either profile or shallow mode,
  // where cell size, pulse length, blanking distance are divided by div
  // set div=1.0 for profile mode,
  // set div=2.0 = SS for shallow mode
  char sget[80];
  short  ncell;
  float cs, pulse;

  ncell = iparam [ IA_adp_ncell ]; // #of cells processed
  cs    = (float) iparam [ IA_adp_cellsize ]/div; // vertical extent of cell
  pulse = (float) iparam [ IA_adp_pulse    ]/div; // vertical pulse length
  
  sprintf(sget,"pingsperbeam %d",ADP_ENS_N);
  adp_cmd_rqst(sget); // send cmd & echo reply
  //-----------------------------------------------------------
  adp_cmd_rqst("pm yes"); // set to profile mode
  //-----------------------------------------------------------
  sprintf(sget,"nc %d",ncell);
  adp_cmd_rqst(sget); // send cmd & echo reply
  //-----------------------------------------------------------
  sprintf(sget,"cs %4.1f",cs); // cs= cell-size (m)
  adp_cmd_rqst(sget); // send cmd & echo reply
  //-----------------------------------------------------------
  sprintf(sget,"plset %4.1f",pulse); // pulse length (m)
  adp_cmd_rqst(sget); // send cmd & echo reply
  //-----------------------------------------------------------
  // The blanking distance to be set by BD
  sprintf(sget,"bd %4.1f",BD*0.1/div); // bd = blanking distance
  adp_cmd_rqst(sget); // send cmd & echo reply
  //-----------------------------------------------------------
  adp_cmd_rqst("ai 1");  // average interval = 1 s
  adp_cmd_rqst("si 50"); // sampling interval = 50 s
  adp_cmd_rqst("om auto"); // output mode = auto
  adp_cmd_rqst("of binary"); // output format = binary
  adp_cmd_rqst( "recorder off"); // set recorder on/off dependent upon
  
  adp_cmd_rqst("SaveSetup"); // save the values even when put to sleep

  cprintf("ADP config is set to:\n");
  adp_info();
  DelayMilliSecs(1000);
    
  return;
} //***************************************************************************

short  adp_altimeter ( void ) // **********************************************
{ // Makes sure ADP is awake, gets & processes altimeter value
  // RETURNS meters above the bottom
  // 80 = no bottom detect
  // 81-84 = error = 80 + error code from adp_get_alt
  // 85 = no response at all from ADP
  // 
  short rstat=0, tmp;
  struct adp_param *adp;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer
  
  adp = all.adp;
  
  tmp = iparam [ IA_use_alt ]; // can be changed from shore
  tmp = tmp &0xf;  // look at just the first 4 bits
  // tmp=2=record raw data to cf1
  // tmp=3=record to cf1, but ignore altimeter reading.
  
  rstat = adp_exit_sample(); // get a response from the ADP
  if ( rstat==0 )
  { // then we never got a response from the adp
    adp->alt_db = 0; 
    adp->alt_z0 = 85; // set an error value for the engineering message
    return(85); // and return
  }
  
  DelayMilliSecs(100); // wait for things to wake up completely
  rstat = adp_get_alt( ); // get the altimeter reading
  tputs(  tup , "PowerOff"); // leave in lowpower
  if ( rstat )
  { // if an error, exit before trying to process a mistake.
    adp->alt_db = 0; 
    adp->alt_z0 = 80+ rstat; // save value for the engineering message
    return(80+ rstat); // return the error code
  }
  if ( tmp==2 || tmp==3 ) // record to CF1
  {
    alt_flash_dump( );  // dump to a  file
  }
    
  // we're here because we have valid data, try to find the bottom!
  rstat = process_alt( );
  adp->alt_z0 = rstat; // save value for the engineering message
  if (tmp==3) rstat=80; // DON'T use the altimeter: 80 says'no bottom found'
  
  return ( rstat );
} //***************************************************************************

#define DB_THRESHOLD 180 // in counts: dB = counts*0.43, 180 =77 dB
#define DDB 35 // in counts: 23 ~ 10 dB jump, 35 = 15 dB
short  process_alt ( void ) //*************************************************
{ // take the altimeter data & try to find the bottom
  // return meters from the bottom,
  // 80 = no bottom detected
  short iz=80, i, nsample, tmp, ithr, iddb;
  unsigned char *abuf;
  float *x, dx, off, z, db, zb=0, dbm,dd, max_db=0;
  struct adp_param *adp;
  
  adp = all.adp;

  // reset threshold values from the above default values
  tmp = iparam [ IA_use_alt ]; // can be changed from shore
  tmp = ( tmp & 0xff00 ) >> 8; // msb, contains new threshold and diff-db info
  ithr = ( tmp & 0xf0 ) >> 4; // msnibble = threshold
  iddb = ( tmp & 0x0f ); // lsnibble = diff-db
  ithr = 120 + ithr*10;  // range = 100..250
  if (ithr<121) ithr = DB_THRESHOLD; // if val=0, then use the above default
  iddb = 10 + iddb*3; // range = 10..55
  if (iddb< 11) iddb = DDB; // if val=0, then use the above default
  cprintf("Using threshold = %d, diff-threshold= %d \n",ithr, iddb);
  	
  abuf = adp->buf;  // point to data buffer: on descent, this is empty
  nsample = abuf[3] + abuf[4]*256;	
  
  // read in scale + offset; need to reverse the bytes
  x = (float*) &abuf[0];  // point to start of the buffer = word boundary
  for (i=0;i<4;i++) abuf[i] = abuf[12-i]; // shift to word boundary of scale
  dx = *x;  // dx = scale
  for (i=0;i<4;i++) abuf[i] = abuf[8-i]; // shift to word boundary of offset
  off = *x;  // off = offset
  printf("nsample=%4d, off = %8.4f, dx = %8.4f \n ", nsample, off, dx);

  z = off; // distance
  dbm = abuf[ALT_HEADER]; // first return
  for (i=0;i<nsample;i++) //===========================================
  {  // printf("%02x ",abuf[i+ALT_HEADER]);  
     // if ( (i-ALT_HEADER+1)%30==0) printf("\n"); 
     z += dx; // this cell's location
     db = abuf[i+ALT_HEADER]; // = intensity
     if (db>max_db) max_db = db;
     dd = db - dbm; // = jump in intensity
     if ( dd>iddb  || db>ithr ) // big jump from the running mean
     {  zb = z; // save altimeter value
        max_db = db; // and the value of the bottom-detect
        break; // break out of the for loop
     } // end if we think we detected the bottom
     // else compute a new weighted average of the return
     dbm = dbm*0.6 + db*0.4; // new weighted average
     // hopefully the weighted mean will help detect a ramp-up in depth
  } //=================================================================
  
  if (zb>1) iz = (short) zb; // set value to return
  // else iz = 80
  adp->alt_db = max_db; // save value for the engineering message
  //it is transferred over in bottom_turn

  return(iz);
} //***************************************************************************

short  adp_get_alt ( void ) // ************************************************
{ // requests a single-beam transmit; returns intensity
  // ADP must be in the main setup mode.
  // returns
  // 0 = successful
  // 1 = no 'OK' from ADP
  // 2 = didn't get a valid value for # of points to read
  // 3 = not correct bytes from ADP
  // 4 = bad checksum
  
  unsigned char sget[80], *abuf;
  short nget, i=0, nread, found;
  unsigned short chksum, chk2;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  TURxFlush  ( tup );   // flush the tpu port
  
  tputs( tup, "GetBeamAmpProfile 1"); // do profile on beam 1
  nget = tgets( tup, (char*)sget, 79, 1,'\n', &found); // get the echo
  nget = tgets( tup, (char*)sget, 4, 1,'\n', &found); // get the initial 'OK'
  cprintf("%d, %s\n",nget, sget);
  
  if (  nget<2 || sget[0] != 'O' )
  	return (1);  // no 'OK' response
  
  nget = tgets( tup, (char*)sget, 2, 2, NO_EOL, &found); // get # of bytes to read in
  if (nget<2) return(2); // didn't get the # of bytes
  
  nread = sget[0] + sget[1]*256; // # of bytes still to read, includes chksum
  if (nread > ALT_MAX_NUM ) return(2); // too many points...is bad
  
  abuf = all.adp->buf;  // point to data buffer: on descent, this is empty
  nget = tgets( tup, (char*)abuf,nread, 2, NO_EOL, &found); // get the profile
  cprintf("%d bytes in altimeter\n",nread);
  
  if (nget != nread )
  	return(3); // didn't get the right # of points
  
  //calculate the checksum
  for (chksum=CHKSUM_OFF, i=0;i<(nget-2);i++) chksum += abuf[i];
  chk2 = abuf[nget-1]*256 + abuf[nget-2]; // what was sent
  // printf("checksum1, 2 = %04x %04x\n",chksum, chk2);
  if (chksum != chk2 ) return (4); // return here if bad
    
  return(0);
} //***************************************************************************
 
short  adp_get_sample ( void ) // *********************************************
{ // requests an ADP sample, waits for response, & stores result
  // ADP must be in the sample mode
  // returns
  // 0 = successful
  // 1 = no '$' prompt from sample mode
  // 2 = no ADP_START byte found to signify the beginning of record
  // 3 = wrong #bytes in the record, doesn't agree with nbytes
  // 4 = didn't actually get the correct # bytes from ADP
  // 5 = bad checksum, Not-Yet-Implemented
  unsigned char sget[200];
  short nget, i=0, nbytes, found;
  // unsigned short chksum;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer

  
  nbytes = 41 + 12* iparam[ IA_adp_ncell ]; // # of bytes in returned packet
  // Sontek v10.8 has 3 extra bytes with noise level info right before the chksum
  nget = adp_query();  // get attention of adp
  if (nget<0) return(1); // never got a response
  
  TURxFlush  ( tup );   // flush the tpu port
  TUTxPutByte( tup,'G',0);  // send request for response 
  
  nget = tgets( tup,(char*)sget,79,1,'\n', &found); // get initial response=sample #

  DelayMilliSecs(3000);  // wait 3 s for acquisition
  sget[0]=0; // NULL str
  i=0; // counter
  TURxFlush  ( tup );   // flush the tpu port
  // try up to 6x to get the right start character
  while (i++<6 && sget[0] != ADP_START )
  {
    nget = tgets( tup,(char*)sget,1,1, NO_EOL, &found);  // get character
  }
  // hopefully this means we found ADP_START
  if ( sget[0] != ADP_START ) 
  {
    cprintf("start char = %x \n",sget[0] );
    return(2);  // doesn't make sense, return
  }
  
  // get next byte = total #bytes to read in
  nget = tgets( tup,(char*)sget,1,1, NO_EOL, &found); // #of bytes
  if ( sget[0] != nbytes ) 
  {
    cprintf("#bytes = %d \n",sget[0] );
    return(3); // doesn't make sense
  }
  
  // get the rest of the data, -2bytes for the ADP_START+#bytes
  nget = tgets( tup,(char*)sget, nbytes-2,1, NO_EOL, &found); // get data response
  if ( nget+2 !=nbytes ) 
  {
    cprintf("#bytes read = %d \n",nget );
    return(4); // didn't get right # bytes
  }
  
  /* dec03 checksum doesn't seem to make sense, I am ignoring
  chksum = CHKSUM_OFF + nbytes + ADP_START; // init chksum
  for (i=0;i<(nget-1);i++) chksum +=sget[i];  // add up chksum
  printf("chksum = %x , %x\n",chksum,sget[nget-1] );
  chksum &= 0xff;  // just keep LSB which should be 0 if valid
  // if bad checksum, return(5); // needs work //*/

  adp_store( sget );
  // if checksum makes sense, store the data  

  return(0);
} //***************************************************************************

void  adp_store ( unsigned char *b ) //****************************************
{ // parse binary data & store to memory
  unsigned char *abuf;  // points to place to store
  unsigned char out[N_ADP_BYTES]; //=max size of returned stream
  short i, n, ncell, m;
  long nout = N_ADP_OUT; //=size of one ensemble in buffer array
  struct adp_param *adp;
  struct dat_param *dat;
  
  dat = all.dat;
  adp = all.adp;  
  abuf = adp->buf + adp->iscan* nout ;
  ncell = iparam [IA_adp_ncell];

  //  keep track of minimum pressure
  if (adp->pmin > dat->dbar ) 
      adp->pmin = dat->dbar;
  
  	/* // test input
  	  dat->ds.p     = 65535;
  	  dat->es.comp  = 256;
  	  dat->es.pitch = 1*4;
  	  dat->es.roll  = 2*4;
  	/**/
  // construct output buffer
  
  *(unsigned short*) &out[0] = dat->ds.p;
  *(short*) &out[2] = dat->es.comp;  // compass heading
  // save pitch & roll angle at lower res of 0.4 degrees
  // which gets it into a byte format, and is certainly at/better
  // than true accuracy of the compass.
  // originally pitch/roll counts are 10 cnts = 1 degree

  out[4] = (char) ( dat->es.pitch / 4); // 1 cnt = 0.4 degrees
  out[5] = (char) ( dat->es.roll  / 4);
  
  n = 12*ncell; // #bytes in the profile data
  for (i=0;i<n;i++)
    out[6+i] = b[i + N_ADP_OFF];
  
  // Jan2006, store the listen-only noise level
  // to just before the intensity data: this overwrites zero std. dev #s
  m = n - 3*ncell - 4;  // shift down to here = 4 bytes before start of Intensity
  for (i=0;i<3;i++)
    out[6+m+i] = b[N_ADP_OFF-3 +i]; //noise is right before the profile data
  // move out to the buffer area
  n += 6; // n= 6 + #bytes in the profile area
  for (i=0; i<n; i++) 
  { abuf[i] = out[i];
    //printf("%02x",abuf[i]);
  } //printf("\n");
  
  //point to next storage area
  adp->iscan++;
  if (adp->iscan >= adp->nscans) 
      adp->iscan  = adp->nscans - 1; //keep legal
  
  return;
} //***************************************************************************

void  parse_last  ( void ) //**************************************************
{ // parse the last sample in memory
  // and display velocity and intensity for the first cell for ea beam
  unsigned char *abuf;  // points to place to store
  short i, h, p, r, v, a, aoff, voff, a0, v0,  ncell, noise;
  long nout = N_ADP_OUT; // size of one ensemble in buffer array
  unsigned short pr;
  union chshort c2s;
  
  ncell = iparam [IA_adp_ncell]; // #of cells processed
  abuf = all.adp->buf + ( all.adp->iscan-1 )* nout; //iscan-1=data here
  c2s.c[0] = abuf[0]; c2s.c[1] = abuf[1];  // read in as char array
  pr = (unsigned short) c2s.x; // convert to unsigned short
  c2s.c[0] = abuf[2]; c2s.c[1] = abuf[3];
  h =  c2s.x; // convert to short

  p = ( (char) abuf[4] )* 0.4; // pitch
  r = ( (char) abuf[5] )* 0.4; // roll 
  // printf("h=%4.1f pitch=%4.1f roll=%4.1f, ",h*0.1,p*0.1,r*0.1);
  
  voff = 2*ncell;  // byte offset between beams
  aoff = 1*ncell;  // byte offset between beams
  v0 = 6;  // points to first cell of beam 1 velocity data
  // ADP format is vel1[]vel2[]vel3[]o1[]o2[]o3[]a1[]a2[]a3[]
  // where velx[i] = 2 bytes ea velocity for cell i for beam x
  //       ox[i] = 1 byte ea std dev for cell i for beam x
  //       ax[i] = 1 byte intensity for cell i for beam x
  a0 = v0 + voff*3 +aoff*3; // includes the std deviation #s as well
  
  //  unpack the ADP stuff, starts at abuf[6]
  for (i=0;i<3;i++) //===========================================
  { // do for each beam
      c2s.c[1] = abuf[v0 + voff*i]; // lsb
      c2s.c[0] = abuf[v0 + voff*i+1]; // msb
      v = c2s.x; // recast as signed short
      // v1 = abuf[v0 + voff*i];  v2 = abuf[v0 + voff*i + 1];
      // v = v2*256 + v1; // byte swap
      a = abuf[a0 + aoff*i];
      noise = abuf[a0 - 4 + i];  // JAN2006, noise for beam i
      cprintf("v%d=%5d, i%d=%3d, n%d=%3d:  ",i+1,v,i+1,a,i+1,noise);
  } //===========================================================
  
  cprintf("\n");
  return;
} //***************************************************************************

void   adp_dump ( void ) //****************************************************
{ // dump buffer of adp data
  struct adp_param *adp;
  unsigned char *abuf;
  short i,j, n, nbytes=0;
  long nout = N_ADP_OUT; // size of one ensemble in the buffer array
  
  adp = all.adp; // point to adp structure
  n = adp->iscan; //=# of ensembles
  cprintf("# of adp ensembles = %d\n",n);
#if ADP
  nbytes = 6 + 12*iparam[IA_adp_ncell]; //=# of bytes actually in the buffer
#elif NTK
  nbytes = 6 + 12*iparam[IA_ntk_nc]; //=# of bytes actually in the buffer
#endif
  // now display
  for (i=0;i<n;i++)
  { // step thru each sample
    abuf =  adp->buf + i *nout; // point to sample #i
    
    for ( j=0;j<nbytes;j++) 
          cprintf("%02x",abuf[j]);
    cprintf("\n");
  } // end i
  
  return;
} //***************************************************************************

void  alt_flash_dump ( void ) //***********************************************
{ // dump altimeter buffer of adp data to the ping-pong buffer
  
  unsigned char *abuf;
  short i, nscan, n, j=0, nlast, pid;
  long nbytes, nb1;
  
  abuf = all.adp->buf;  // point to altimeter data buffer
  nbytes = abuf[3] + abuf[4]*256 + ALT_HEADER; //total #bytes to transfer
  if (nbytes>ALT_MAX_NUM) nbytes = 400; // keep from getting out of hand
  
  nlast = n = 200; // max #bytes to transfer in one block
  nscan = nbytes/n; // # of blocks to xfr
  nb1 = (long) nscan * n; // =#bytes in nbin blocks
  
  if ( nbytes > nb1 ) //+++++++++++++++++++++++++++++++++++++++++++++++++
  { // then there is an odd-#byte xfr at the end
    nscan++; // add one more block
    nlast = (short) (nbytes - nb1); // #of bytes in last block
  } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  cprintf("alt->flash %d blocks, nlast=%d\n",nscan,nlast);
  // we assume that the file is already open and ready to be appended
  
  pid = CF_ALT; // CF packet ID that it is start of altimeter data

  for (i=0;i<nscan;i++) //+++++++++++++++++++++++++++++++++++++++++++++++
  { // write out each bin data to the CF1
	if (i == (nscan-1) ) 
	    n = nlast; //=last block, set #bytes
	flash_store( n, abuf, pid ); // transfer to the cf1
    abuf +=  (long) n; // add #bytes xfr'd : pointing @ next byte out
    pid = CF_CONT; // set ID=continuation packet
	
  } // end for i ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  cprintf("alt->flash done\n");

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

void  adp_flash_dump (  short pid ) //*****************************************
{ // dump buffer of adp data to the  flash card
  // pid = packet id
  struct adp_param *adp;
  unsigned char *abuf;
  short i, nscan, n, j=0;
  long nout = N_ADP_OUT; // =#bytes in buffer for each ensemble
  long nbuf;

  
  nbuf = 6 + 12*iparam[IA_adp_ncell]; //=# of bytes actually in each buffer
  n = nbuf;  // re-cast as short for cf1_sbe_store call
  
  adp = all.adp; // point to adp structure
  nscan  = adp->iscan; //=#scans filled
  if ( nscan >= adp->nscans ) nscan = adp->nscans -1;
  // dec14: above makes sure nscan stays legal.
  

  for (i=0;i<nscan;i++) //+++++++++++++++++++++++++++++++++++++++++++
  { // write out each scan to the flash +++++++++++++++++++++++++++++
    abuf = adp->buf + i* nout ;
    flash_store ( n, abuf, pid ); // xfr to ping-pong buffer
	
  } // end for i ++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  cprintf("ADP->flash done\n");

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

void  create_fake_adp ( void ) //**********************************************
{ // fill up adp data with fake profile
  // assign simulation params: x = x0 + xv*cos(z/xk + xp); x0,xv,xk,xp
  float e0=5, ev=20, ek=80,  ep =90; // east component
  float n0=0, nv=20, nk=80,  np = 0; // north component
  float w0=-9,wv=2,  wk=100, wp = 0; // vertical velocity
  float h0=0, hv=30, hk=100, hp = 0; // heading
  float p0=17,pv=3,  pk=60, pp = 0; // pitch
  float r0=0, rv=3,  rk=60, rp = 90; // roll
  float xpi, xro, xhe, z, zj, u1, u2, u3;
  unsigned short pcnts;
  short vel[3][ADP_NCELL], ut;
  long nout = N_ADP_OUT; // = max #bytes per ensemble in buffer array
  float cs;
  
  struct adp_param *adp;
  short a0, i, ii, j, k, nscan, amp, ncell;
  unsigned char *abuf, c1, c2;
  
  adp = all.adp; // point to adp structure
  nscan = adp->iscan = 20; //=#ensembles to simulate
  adp->pmin = 0; // minimum pressure taken [dBar]
  ncell = iparam [IA_adp_ncell ]; // =#of cells to process
  cs = (float) iparam [ IA_adp_cellsize ];
  
  for (i=0; i<nscan; i++)
  { // step thru each ensemble; 1st ensemble=deepest
    ii = nscan-1 -i; // ii = reverse-order input, shallow goes in  last
    abuf =  adp->buf + ii *nout; // points to sample #ii
    for (j=0;j<N_ADP_OUT;j++) abuf[j] = 0; // null out array
    
    z = i*cs; // = depth of the first cell for this ensemble
    amp = 20 + ii*3;
    pcnts = ( unsigned short) ( z / F_PR_GN ) + 250; // p counts,sbe
    xpi = get_sim(z, p0,pv,pk,pp); // pitch
    xro = get_sim(z, r0,rv,rk,rp); // roll
    xhe = get_sim(z, h0,hv,hk,hp); // heading
    // store these values to the output buffer
    *(unsigned short*) &abuf[0] = pcnts;
    *(short*) &abuf[2] = ( short ) ( xhe*10); // heading
    abuf[4] = ( char ) ( xpi * 2.5 ); // pitch counts
    abuf[5] = ( char ) ( xro * 2.5 ); // roll counts
    
    // compute the velocities & store in vel array
    for (j=0;j<ncell; j++)
    {  zj = z + j*cs; // depth of this cell
       vel[0][j] = ( short ) ( 10*get_sim(zj, e0,ev,ek,ep) );
       vel[1][j] = ( short ) ( 10*get_sim(zj, n0,nv,nk,np) );
       vel[2][j] = ( short ) ( 10*get_sim(zj, w0,wv,wk,wp) );
    } // end for j 
    // we need to rotate these velocities for heading, pitch, roll
    cross_uvw(xhe-90,0,1,vel,ncell); // rotate u, v by heading
    cross_uvw(17-xpi,0,2,vel,ncell); // rotate u, w by pitch
    cross_uvw(-xro,  1,2,vel,ncell); // rotate v, w by roll
    // convert to beam velocities
    for (j=0;j<ncell; j++)
    { // do for each scan
      u1 = vel[0][j]*S_TDX - vel[2][j]*C_TDX; // beam 1
      u2 = -0.5*vel[0][j]*S_TDX + SQRT3*0.5*S_TDX*vel[1][j]
           - vel[2][j]*C_TDX;
      u3 = -0.5*vel[0][j]*S_TDX - SQRT3*0.5*S_TDX*vel[1][j]
           - vel[2][j]*C_TDX;
      vel[0][j] = (short) u1; //=beam 1
      vel[1][j] = (short) u2; // beam 2
      vel[2][j] = (short) u3; // beam 3
    }
    // and store to the output array
    ii = 6; // output index for velocity
    a0 = ii + 3*ncell*3; //=points to amplitude out
    // feb06, store fake noise
    for (j=0;j<3;j++) abuf[a0 -4 +j] = amp -ncell+1;
    
    for (j=0;j<3;j++)
    { // do for each beam
      for (k=0; k<ncell; k++ )
      { // do for each beam
        ut = vel[j][k]; // velocity, mm/s
        c1 = ( ut & 0xff00 ) >> 8; // msb
        c2 = ut & 0x00ff; // lsb
        abuf[ii++] = c2; // little endian first
        abuf[ii++] = c1; // followed by msb
        // also store amplitude
        abuf[a0++] = amp - k - j;
      } // end for k
    } // end for j
    
  } // end i...go do the next scan
  // *****
   
  return;
} //***************************************************************************
/**/

float get_sim (float z, float e0, float e1, float ek, float ep) //*************
{ // compute the simulation value for depth z
  float x;
  
  if (ek==0) ek=1; // keep legal
  // x = (z/ek + ep/360)*2*3.1416;  // in radians
  x =  z/ek*360 + ep;  // in degrees
  x = e0 + e1*cos_find(x);
  
  return(x);
} //***************************************************************************

//*****************************************************************************
void get_adp_scan(unsigned char *abuf, short i0, unsigned short pr[],
  short phi[], short rol[], short head[], short vel[][ADP_NCELL],
  short amp[][ADP_NCELL], short noise[], short ENW  )
  // *abuf points to the adp scan to analyze
  // i0 = output index for the arrays:
  // pr = pressure counts, phi = pitch angle, rol = roll angle, head=heading,
  // vel[i][j] is component/beam i of bin j in the present scan
  // amp[i][j] is intensity of beam i of bin j 
  // noise[i] = noise level for beam i
  // if ENW=1, then vel[] is ENW, else, just local UVW
{ 
  short i, j, iv, ia, aoff, voff, a0, v0, a=0, ncell ;
  float ut=0, vt=0, wt=0, p, r, h;
  union chshort c2s;
 #if NTK
  struct ntk_param *ntk;
  ntk = all.ntk;
 #endif
 
  ncell = iparam [ IA_adp_ncell ]; // #of cells processed
  
  c2s.c[0] = abuf[0]; c2s.c[1] = abuf[1];  // read in as char array
  pr[i0] = (unsigned short) c2s.x; // save as unsigned value
  c2s.c[0] = abuf[2]; c2s.c[1] = abuf[3];
  head[i0] = (long) c2s.x; 
  h = (float)head[i0]*0.1;  // degrees
  h = 90 - h; // make ccw, along with h=0 = pointing east (along x axis)
  h = limit360(h); // set within 0..360 degrees bounds
  
  phi[i0]  = ( (char) abuf[4] ); // pitch counts, 1 cnt= 0.4 degrees
  p = (float)phi[i0]*0.4 - MOUNT_ANGLE; // degrees, -17 mounting angle
  rol[i0]  = ( (char) abuf[5] ); // roll, 1 cnt = 0.4 degrees
  r = (float)rol[i0]*0.4; // degrees roll
  // correct p and r for tcm2 offsets
  // p = p - (float) iparam [ IA_tcm2_p0 ] *0.1;
  // r = r - (float) iparam [ IA_tcm2_r0 ] *0.1;
      printf("pr = %u h=%6.1f, adp_pitch=%6.1f roll=%6.1f\n",pr[i0],h,p,r);
  
  voff = 2*ncell;  // byte offset between beams for velocity
  aoff = 1*ncell;  // byte offset between beams for intensity & std dev.
  v0 = 6;  // points to first cell of beam 1 velocity data
  // ADP format is vel1[]vel2[]vel3[]o1[]o2[]o3[]a1[]a2[]a3[]
  // where velx[i] = 2 bytes ea velocity for cell i for beam x
  //       ox[i] = 1 byte ea std dev for cell i for beam x
  //       ax[i] = 1 byte intensity for cell i for beam x
  a0 = v0 + voff*3 +aoff*3; // offset to the first beam, first cell intensity
  
  //  unpack the ADP velocities +++++++++++++++++++++++++++++++++++++++++
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  for (i=0;i<3;i++) //==============================================
  { // do for each beam
    iv = v0 + voff*i;  // points to first bin for beam i
    ia = a0 + aoff*i;  // points to first bin for beam 1
    noise[i] = abuf[a0 - 4 + i]; // Jan06 noise level for this beam
    
    for (j=0;j<ncell;j++) //-------------------------------
    { // get velocities for each bin; units = mm/s
      c2s.c[1] = abuf[iv++]; // lsb
      c2s.c[0] = abuf[iv++]; // msb
      vel[i][j] = c2s.x; // store as a short
      amp[i][j] = abuf[ia++];
    } // end for j ----------------------------------------
    
  } // end for all 3 beams =========================================
  
  // go from beams to uvw in the local coordinate system
  for (j=0; j<ncell; j++) //========================================
  { // step through for each range bin
    // 0702b : 23apr07, increased resolution to 1 count = 0.1 mm/s
   #if ADP
    ut = 10* (float)(2*vel[0][j] - vel[1][j] - vel[2][j] ) / ( 3*S_TDX );
    vt = 10* (float)(  vel[1][j] - vel[2][j] ) / ( SQRT3*S_TDX );
    wt =-10* (float)(  vel[0][j] + vel[1][j] + vel[2][j] ) / ( 3*C_TDX );
   #elif NTK
    // mar13 Nortek ad2cp beam geometry:
    // vel[0]=beam 1 = aft, vel[1] = beam 2 = stbd, vel[2] = beam 4 = port
    // default scaling is 1 count = 0.1 mm/s
    ut =   (float)(    -2*vel[0][j] + vel[1][j] + vel[2][j] ) / ( S_ZA*(2 + 2*C_AA) );
    vt =-1*(float)(                   vel[1][j] - vel[2][j] ) / ( 2*S_ZA*S_AA       );
    wt =-1*(float)(C_AA*2*vel[0][j] + vel[1][j] + vel[2][j] ) / ( C_ZA*(2 + 2*C_AA) );
    
    // AUG13 Vscale read from last packet received
    ut = ut * ntk->Vscale;
    vt = vt * ntk->Vscale;
    wt = wt * ntk->Vscale;
  #endif
    
    // 0702b, vel[][] 0.1 mm/s res, ~ 320 cm/s max values
    vel[0][j] = (short) ut; // = glider long-axis, positive towards nose
    vel[1][j] = (short) vt; // = glider wing-axis, positive ->port wing
    vel[2][j] = (short) wt; // = glider tail-axis, positive upwards
    
  } // end beam vels to local uvw====================================
  
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  if (!ENW) return; // return just local coordinate system
  
  //else ENW=TRUE, do the transformations
  cross_uvw(r,1,2,vel,ncell); // rotate components 1=v, 2=w by roll
  cross_uvw(p,0,2,vel,ncell); // rotate 0=u, 2=w, by pitch
  cross_uvw(h,0,1,vel,ncell); // rotate 0=u, 1=v, by heading
  
  return;  // vel arrays for this scan are now in earth coordinates
} //***************************************************************************

void cross_uvw(float phi,short i,short j,short vel[][ADP_NCELL], short ncell)
// do one component of the cross-product
// take vel=uvw array and rotate i, j components by phi,
// where phi is in i-j plane, phi=0=along i axis, phi=90=along j axis
{
  short k;
  float ang, cp, sp, ut, vt;
  
  ang = phi*0.01745;  // in radians
  cp = cos_find( phi ); // uses lookup table, with degrees input
  sp = sin_find( phi ); // uses lookup table, with degrees input
  
  for (k=0; k<ncell; k++)
  { // step thru each range bin
    ut = vel[i][k] *cp - vel[j][k] *sp;
    vt = vel[j][k] *cp + vel[i][k] *sp;
    vel[i][k] = (short) ut;
    vel[j][k] = (short) vt;
  } // for k
  
  return;
} //***************************************************************************


// FEB06 removed wavg processing to save memory space
//   and converted other arrays to shorts to save space
void  adp_post_process ( void  ) //********************************************
{ // For each ensemble, convert to earth coord., average & pack data
  // modified to compute an average back-scatter profile as well

  short itype = 5; // sensor-type, 5=adp profile-mode
  struct adp_param *adp;
  unsigned char *abuf;
  short i, ii, i0, j,k, nscan, npts;
  short kmax=0, kbmax=0;
  short icell, minsnr, ncell;
  long  nout = N_ADP_OUT; // = max #bytes per ensemble in buffer array
  long  uavg[ADP_NSCANS], vavg[ADP_NSCANS], bsavg[ADP_NSCANS]; //wavg[ADP_NSCANS]
  long  tmp[ADP_NSCANS]; // used to re-assign output for pack_dat
  short vel[3][ADP_NCELL], amp[3][ADP_NCELL], dBcor[ADP_NCELL];
  unsigned short  pr[ADP_NSCANS], aavg[ADP_NSCANS];
  short  phi[ADP_NSCANS], rol[ADP_NSCANS], head[ADP_NSCANS];
  short navg[ADP_NSCANS], nbsavg[ADP_NSCANS];
  char  b[ADP_NSCANS+50]; // packed data buffer : 19Nov04 needs> 3 + 22*(nscan/20)
  float dp, cs, pulse, prx, x, x0, bdist;
  short noise[3], lastcell, cellgood[3];
  
  adp = all.adp; // point to adp structure
  nscan = adp->iscan; //=#ensembles in buffer
  if (nscan<1) return; // 0902, nothing to process

  minsnr = iparam [ IA_adp_minsnr  ]; // min snr for intensity
  ncell  = iparam [ IA_adp_ncell ]; // # of cells to process
  cs =    (float) iparam [ IA_adp_cellsize]; // vertical extent of cell
  pulse = (float) iparam [ IA_adp_pulse ]; // vertical pulse length
  bdist = BD*0.1; //blanking distance
  
  
  if ( ncell<2 ) return; //0902.5, bad #cells, nothing to process
  // initialize output arrays
  for (i=0;i<ADP_NSCANS;i++)
  {  // set output arrays to zero
     navg[i]   = 0;
     nbsavg[i] = 0;
     uavg[i]   = 0;
     vavg[i]   = 0;
     //wavg[i] = 0;
     aavg[i]   = 0;
     bsavg[i]  = 0;
  } // end for i<ADP_NSCANS
  
  // Sep05 : compute the spreading+absorption loss correction
  // when dBcor is added to the Intensity, we have estimate of back-scatter
  dp = bdist + ( cs + pulse)/2; // first bin location : bd=blanking distance
  x0 = log10(dp); 
  for (i=0;i<ncell;i++)
  {
    prx = dp + cs*i ; // location [m] of cell i from transducer
    x = 20*log10(prx) + ALPHA*prx*.02; // Jan06 *2: absorption is round-trip
    //  spherical    + absorption losses
    dBcor[i] = ( short ) (x*10 ); // units of dB*10
    // printf("%d dbcor=%d\n",i, dBcor[i]);
  } // end for ncells
  
  //***** for each scan compute velocities & average.
  // Work from the top-down = reverse order of the output buffer.
  // This puts output velocity bins in continuing descending order
  // i0 = 1; // i0 = bin offset from one scan to the next, should =1
  // 0702, i0 is computed directly from scan depth
  for (i=0;i<nscan;i++)
  { // step thru each ensemble
    ii = nscan-1 -i; // ii = reverse-order input into the buffer
    abuf =  adp->buf + ii *nout; // points to sample #ii
    
    // get the scan data and convert to ENW, output is in vel array
    get_adp_scan(abuf,i,pr,phi,rol,head,vel,amp,noise,1); //1=ENW
    
    // compute the avg amplitude for the last cell
    for (j=0; j<3; j++) aavg[i] += amp[j][ncell-1];
    aavg[i] /=3; //=avg amplitude of the last desired cell
        
    // JAN06 compute the last cell with good snr ----------------
    if (minsnr>-1) //--------------------------------------------
    { // then check SNR to decide on which cells to use
      for (j=0; j<3; j++) //...............................
      { // find the last good cell for each beam
         k=1;  //k=1 = cell#2 : ALWAYS process first 2
         do  // while the SNR>minsnr, step thru the cells
         {    dp = ( amp[j][k] - noise[j] ) > minsnr; // true if good SNR
              if (dp) k++; // if good, look at the next cell
         } while ( dp && k<ncell); // look until bad or gone thru all cells
         cellgood[j] = k; //=last good cell+1 = #good cells
         // printf("beam %d last good cell=%d\n",j, k);
      } // for j=0 .. for all 3 beams .....................
      
      lastcell = ncell;  // assume all cells are valid
      for (j=0; j<3; j++)
      {  if ( cellgood[j]<lastcell) lastcell=cellgood[j]; }
      // lastcell = last valid cell +1: range = 2..ncell
      if (lastcell<2) lastcell=2; // ALWAYS process at least 2 cells
    } //---------------------------------------------------------
    else  // minsnr<0, don't use SNR to decide lastcell ---------
    { lastcell = ncell; // assume all are valid
    } // end if..else -------------------------------------------
    
    
    // offset is computed from the minimum ADP pressure
    dp = dBar(pr[i], all.flt) - adp->pmin;
    i0 = (short) (dp/cs + 0.5 ); // closest depth bin
    printf("i=%d, i0 = %d, dp=%5.1f\n",i,i0, dp);
    
    
    // save the first-diff data into the averaging arrays-------------
    // lastcell is set above to the last valid cell to use
    for (j=1; j<lastcell; j++) 
    {  
       k = i0 + j-1; // 0702 output index, depth bin+cell
       // k= i + i0-1 + j-1; // old output index
       if ( k< ADP_NSCANS  && k>=0 )
       { // then it is legal
           // 0702b apr07, uavg, vavg = 0.1 mm/s resolution
           uavg[k] += vel[0][j] - vel[0][j-1];
           vavg[k] += vel[1][j] - vel[1][j-1];
                 //wavg[k] += vel[2][j] + vel[2][j-1];
           navg[k]++; // increment counter
           if (k>kmax) kmax=k;  // keep track of largest output bin index
       } // end if k is legal
    } // end for j<lastcell ------------------------------------------
    
    
    // process backscatter for all valid range cells -----------------
    // 0702 chenged to the parameter definitions from straight hard-wire
    // and depth array index k is shifted so 1st output bin=1st valid bin
    for (j=(K1_ABS-1); j<K2_ABS; j++) 
    {  
       k = i0 + j- (K1_ABS-1); // 0702 offset to this bin
       // k= i + i0-1 + j; // output index :NOTE this is +1 from uavg bins

       if ( k< ADP_NSCANS  && k>=0 )
       { // then it is legal
           // average amplitude for cell j across the 3 beams
           for (x=0, icell=0; icell<3; icell++)
              {  x += amp[icell][j]; }
           bsavg[k]+= (long) (x*4.3/3 + dBcor[j]); // backscatter, [dB*10]
           nbsavg[k]++; // increment counter
           if (k>kbmax) kbmax=k;  // keep track of largest bin index
       } // end if k is legal
    } // end for j<lastcell ------------------------------------------
    
  } // end i...go do the next scan
  kmax++; // converted from last good bin to the # of good bins
  kbmax++; // ditto for ABS data
  // *****
  
  // average the results
  for (i=0;i<kmax;i++) //========================================
  { // step thru each output bin
    j = navg[i];
    if (j>0)
    { // then we need to average
      uavg[i] /= j;
      vavg[i] /= j;
      // wavg[i] /= (2*j);  // divide by 2 due to sum above
    }
  } //===========================================================

  // average the results for backscatter
  for (i=0;i<kbmax;i++) //=======================================
  { // step thru each output bin
    j = nbsavg[i]; //Jan06, average backscatter
    if (j>0) 
    {  bsavg[i] /= j; // backscatter strength
    } // end if j>0
  } //===========================================================
  // first bin is now the first valid value.
  
  // integrate u and v so we can use the same data packing algorithms
  // as used for P, T, C, etc.
  for (i=1;i<kmax;i++)
  { // integrate the profile
    uavg[i] += uavg[i-1];
    vavg[i] += vavg[i-1];
  } // end integration
  
  for (i=0;i<kmax;i++)
      cprintf("%3d: %7ld %7ld %7ld\n",i,uavg[i],vavg[i], bsavg[i]);
      
  // uavg, vavg are 0.1 mm/s resolution ...
  // we want to pack at 1 mm/s resolution
  for (i=0;i<kmax;i++) //------------------------
  { 
    uavg[i] /= 10;
    vavg[i] /= 10;
    // wavg[i] /=10
  } //-------------------------------------------

  // pack data here; last 2 #s in pack_dat(....id,iver) are:
  // id = sensor id = 5 =  ADP profile mode
  // iver=0 = pressure, iver=1..3 = u, v, w
  // iver=4=intensity, 5=pitch, 6=roll, 7=heading, 8 = back-scatter
  // iver=15 = adp parameters
  
    // following starts a new SBD packet as well
 	#if NTK==1 //JAN14
   	 ntk_sbd_param();
	#else
   	 adp_sbd_param();
	#endif   
 	 
  // pack the pressure data and append to the lifo
  for (i=0; i<nscan; i++)  tmp[i] = (unsigned long) pr[i]; 
  
      npts = pack_dat(b,tmp,  nscan,itype,0 ); // pack pressure
      append_lifo( npts,(unsigned char *)b); // and append to lifo
      
  // pack the U velocity data and append to the lifo
      npts = pack_dat(b,uavg, kmax,itype,1 ); 
      append_lifo( npts,(unsigned char *)b); 

  // pack the V velocity data and append to the lifo
      npts = pack_dat(b,vavg, kmax,itype,2 ); 
      append_lifo( npts,(unsigned char *)b); 

  // Sep05 Pack the backscatter data instead of wavg.
      npts = pack_dat(b,bsavg, kbmax,itype,8 );  
      append_lifo( npts,(unsigned char *)b); 

  // pack aavg, phi, roll, and heading
  for (i=0; i<nscan; i++)  tmp[i] = (long) aavg[i]; // feb06
      npts = pack_dat(b,tmp,nscan,itype,4 ); 
      append_lifo( npts,(unsigned char *)b); 
  for (i=0; i<nscan; i++)  tmp[i] = (long) phi[i]; // feb06
      npts = pack_dat(b,tmp, nscan,itype,5 ); 
      append_lifo( npts,(unsigned char *)b); 
  for (i=0; i<nscan; i++)  tmp[i] = (long) rol[i]; // feb06
      npts = pack_dat(b,tmp, nscan,itype,6 ); 
      append_lifo( npts,(unsigned char *)b); 
  for (i=0; i<nscan; i++)  tmp[i] = (long) head[i]; // feb06
      npts = pack_dat(b,tmp,nscan,itype,7 ); 
      append_lifo( npts,(unsigned char *)b);
  
  return;
} //***************************************************************************

//  shallow-mode post-processing  *********************************************
void  adp_shallow_process ( void ) //******************************************
{ 
  // shallow-mode averages V, I for each beam and sends back the avg,
  // plus pitch, roll, heading, pressure info

  struct adp_param *adp;
  unsigned char *abuf;
  short itype = 6;  // shallow-mode = sensor-type 0x6_
  
  short i, j,k, nscan, ncell, npts;

  long  nout = N_ADP_OUT; // = max #bytes per ensemble in buffer array

  long  tmp[ADP_NSCANS]; // used to re-assign output for pack_dat
  short vel[3][ADP_NCELL], amp[3][ADP_NCELL];
  long  aa[6][ADP_NCELL]; //0,1,2 = vel,  4,5,6 = amp averages
  
  ushort  pr[ADP_NSCANS];
  short   phi[ADP_NSCANS], rol[ADP_NSCANS], head[ADP_NSCANS];
  short   noise[3];
  char  b[ADP_NSCANS+50]; // packed data buffer : 19Nov04 needs> 3 + 22*(nscan/20)
  
  ncell  = iparam [IA_adp_ncell ]; // # of cells to process
  adp = all.adp; // point to adp structure
  nscan = adp->iscan; //=#ensembles in buffer
  if (nscan<1) return; // nothing to pack!

  // initialize output arrays ===================
  for (i=0;i<ADP_NCELL;i++)
  {  // set to zero
  
     for (j=0;j<3;j++) //-----------------
     { // zero out each beam
        aa[j  ][i] =0;  // vel portion
        aa[j+3][i] =0;  // amp portion
     } //---------------------------------
  } //===========================================
  
  
  // accum vel and amp over all ensembles +++++++++++++++++++++++++++
  for (i=0;i<nscan;i++) //+++++++++++++++++++++++++++++++++++++++++++
  { // step thru each ensemble
    abuf =  adp->buf + i *nout; // points to sample #i
    
    // get the scan data and convert to UVW, output is in vel array
    get_adp_scan(abuf,i,pr,phi,rol,head,vel,amp,noise,0); //0=UVW, not ENW
    
    // accumulate across all cells for vel and amp
    for (j=0; j<ncell; j++) //=================================
    {  // do for each cell
       for( k=0; k<3; k++)  //--------------------------
       { // do for each beam
           aa[k  ][j] += vel[k][j]; // accum vel
           aa[k+3][j] += amp[k][j]; // accum amp
       } //---------------------------------------------
    } //=======================================================
    
  } // end i ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  // average the results
  for (i=0;i<ncell;i++) //==================
  { // do for ea cell
    for (j=0;j<3;j++) //-------
    {  // do for ea beam 
       aa[j  ][i] /= (nscan*10); // 1mm/s resolution
       aa[j+3][i] /= nscan;  // counts
    } //-----------------------
  } //end i ================================
  
  // pack data here; last 2 #s in pack_dat(....id,iver) are:
  // id = sensor type id =6 =  ADP shallow mode,
  // iver=0 = pressure, iver=1..3 = u, v, w
  // iver 4,5,6 = amp for ea beam
  // iver= 7=pitch, 8=roll, 9=heading
  
  // pack the pressure, pitch, roll, and heading
  for (i=0; i<nscan; i++)  tmp[i] = (unsigned long) pr[i]; 
      npts = pack_dat(b,tmp, nscan,itype,0 ); // pack pressure
      append_lifo( npts,(unsigned char *)b ); // append to lifo
  for (i=0; i<nscan; i++) 
  { tmp[i] = (long) head[i]; printf("%d\n",head[i]); }
      npts = pack_dat(b,tmp, nscan,itype,7 ); // heading
      append_lifo( npts,(unsigned char *)b );
  for (i=0; i<nscan; i++)  tmp[i] = (long) phi[i];
      npts = pack_dat(b,tmp, nscan,itype,8 );  // pitch
      append_lifo( npts,(unsigned char *)b ); 
  for (i=0; i<nscan; i++)  tmp[i] = (long) rol[i];
      npts = pack_dat(b,tmp, nscan,itype,9 );   // roll
      append_lifo( npts,(unsigned char *)b ); 
      
  // pack the velocity and amp data for ea cell
  for (k=0;k<6;k++) //===========================================
  { // k=0,1,2=vel,  4,5,6=amp
    for (i=0;i<ncell;i++)  tmp[i] = (long) aa[k][i];
      npts = pack_dat(b,tmp, ncell,itype,k+1 ); 
      append_lifo( npts,(unsigned char *)b ); 
  } //===========================================================

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

void  adp_sbd_param ( void ) //************************************************
{ // add the adp parameter list to the sbd message
  short n=3;
  unsigned char b[20];
  b[0] = 5*0x10 + 15; // flag type of data type 5, & version=15
  // b[1], b[2] = # of bytes, fill in at end
  
  b[n++]  = (unsigned char) iparam[IA_adp_ncell   ]; // # of cells to process
  b[n++]  = (unsigned char) iparam[IA_adp_cellsize]; // vertical extent of cell
  b[n++]  = (unsigned char) iparam[IA_adp_pulse   ]; // vertical pulse length
  b[n++]  = (unsigned char) iparam[IA_adp_minsnr  ]; // min snr for intensity
  
  /**** the following additions are on hold, as they are fixed.
  /**** calibration code output has been changed instead.
  // 0702 added the rest of ADP params; presently are fixed variables.
  //		this should make the 'B' line a complete parameter list.
  b[n++]  = (unsigned char) K1_ABS; // added back-scatter processing info
  b[n++]  = (unsigned char) K2_ABS; // added back-scatter processing info
  b[n++]  = (unsigned char) BD; // added blanking distance
  b[n++]  = (unsigned char) ALPHA; // added absorption factor
  /*****/
  
  b[n++] = ';'; // tack on the end data character
  
  // n= total # bytes written out
  // which gets stored after the sensor id byte:
  b2_store(1, b, n); //store starting at b[1]
  
  // append_lifo( n, b );  // tack onto end of lifo
  new_msg_lifo( n, b );  // create new lifo
  //  start with a new message for ADP
  //  all ADP data will end up in it's own message this way
  //  so the 'B' info 
  
  // store info to flash as well, so post-processing =====================
  // doesn't have to look up elsewhere
  b[0] = BD; // blanking distance
  b[1] = ALPHA; // alpha used in calcs
  b[2] = all.ncyc;
  n--; // throws way the ';'
  //store the min press, used in post-process for surface
  n = b2_store(n, b, all.flt->pmin ); 
  flash_store( n, b, CF_ADP_H ); 
  
  return;
} //***************************************************************************

void  adp_pro_test ( void ) //*************************************************
{ // test profile code of adp acquisition
  float pval, p_adp;
  short i, dp;
  
// the following is lifted from 'ascend' in miss_fnx.c
  i = adp_on();  // turn on the adp ( same circuit as altimeter)
  if ( !i )
  { cprintf("Failure starting ADP\n");
    return;
  }
  
  dp = iparam [ IA_adp_cellsize ];
  DelayMilliSecs(1000);
  adp_exit_sample(); // make sure that we're in the main menu
  adp_set_up(1.0); // set parameters for profiling (scalar=1.0)
  adp_sample_mode(); // enter the sample mode

// next up is the relevant code from 'glide'
  pval = 100;
  p_adp = pval + 1;
  for (i=0;i<4;i++) //-------------------------------------------
  { // for test just do 4x
    DelayMilliSecs(10000); // wait 10 s
         if (pval<p_adp)
         { // then it is time to take another ADP sample
           //  could roll flat here if needed
           adp_get_sample( );  // get sample
           p_adp -= dp; // decrement to next  depth
         }
    printf("pval %6.0f  p_adp %6.0f\n",pval, p_adp);
    pval -= dp;
  } //-----------------------------------------------------------
  
// and the shut-down sequence in 'ascend'
  adp_exit_sample(); // exit sample mode
  adp_off(); // turn off the adp
  all.adp->on_adp = 0;  // set flag that ADP is off

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

void  adp_shallow ( void ) //**************************************************
{ // collect adp data at the surface
  float p, pmin=9999;
  short i, ns, ip, ierr;
  struct adp_param *adp;
  struct dat_param *dat;
  
  adp = all.adp;
  dat = all.dat;
  

  ns = iparam [ IA_adp_nsh ]; // # of ensembles to do
  if (ns<1) return; // don't want to do any, return
  
  // initialize the adp ------------------------------------------------
  i = adp_on();  // turn on the adp ( same circuit as altimeter)
  if ( !i )
  { // error turning on the ADP (specifically talking to GPIO MUX)
    adp_off(); // try turning off
    adp->on_adp = 0; // flag that it is off
    cprintf("Failure turning on ADP in adp_shallow\n");
    return; // give up
  } 
  // ---else OK, proceed:
  
  adp->on_adp = 1;  // set flag that we're turning on ADP
  DelayMilliSecs(1000);
  adp_exit_sample(); // make sure that we're in the main menu
  DelayMilliSecs(1000);
  adp_set_up(SS);    // set parameters for shallow mode
  adp_sample_mode(); // enter the sample mode
  adp->iscan = 0;  // point to first data record in buffer
  adp->pmin  =1000;
  
 // collect the desired # of ensembles ++++++++++++++++++++++++++++++++++
  for (i=0;i<ns;i++) //++++++++++++++++++++++++++++++++++++++++++++++++++
  {  
     DelayMilliSecs(2000);   // wait 2 s
     p = sbe_fp(); 
     ip = intPval(p);
     dat->ds,p = ip; // store pressure counts
     dat->dbar = dBar(ip, all.flt); // and dbar value
     ierr = get_tcm2(  1 );  //takes 1 sample, cycles on/off the power
     if (ierr==0) //------------------------------------------------
     {  // only use good compass value
     // else the old values will be used: good enough for a glitch
       dat->es.comp  =  10*all.comp->head;  //=deci-degrees
       dat->es.roll  =  10*all.comp->roll;
       dat->es.pitch =  10*all.comp->pitch;
     } //-----------------------------------------------------------

     adp_get_sample( );    // get ensemble, takes ~5 s

  } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  // shut-down sequence -------------------------------------------------
  adp_exit_sample(); // exit sample mode
  adp_off(); // turn off the adp
  adp->on_adp = 0;  // set flag that ADP is off
  
  // post-process & add sub-packet --------------------------------------
  adp_flash_dump( CF_ADPS ); //write to flash w/correct packet id
  adp_shallow_process( ); 
  
  
  return;
} //***************************************************************************

void   adp_flash_test ( void ) //**********************************************
{ // test dumping data to the flash
  struct adp_param *adp;
  unsigned char *abuf;  // points to place to store
  short i, j, n;
  long nout = N_ADP_OUT; // = max #bytes per ensemble in buffer array
  
  adp = all.adp; // point to adp structure
  n = adp->nscans;  // max scans of adp data that can be stored
  adp->iscan = n; // save as #stored
  
  for (i=0;i<n;i++)
  { // fill up buffer with dummy data
     abuf =  adp->buf + i *nout; // point to sample #i
     for (j=0;j<nout;j++) *abuf++ = j + i; // store dummy data
  } // end for i
  adp_flash_dump ( CF_ADP ); // dump to cf1 card
  
  return;
} //***************************************************************************

#define NROW 3
#define NCOL 4
void  array_test ( void ) //***************************************************
{ // test 2-d array for memory storage
  short x[NROW][NCOL], *y;
  short i,j;
  
  for (i=0;i<NROW;i++)
  { for (j=0;j<NCOL;j++) x[i][j] = i*10 + j; }
  j=NROW*NCOL;
  y= (short*) x;  
  for (i=0;i<j;i++) cprintf("%3d",y[i]);
  cprintf("\n");
  
  return;
} //***************************************************************************

void alt_test_check( void ) //*************************************************
{ //*** test altimeter setup and first altimeter response
 short alt, alt_stat=0;
 
       if (alt_stat==0) //------------------------------------------
       {  // then we need to initialize things before sampling
          adp_on(); // send the cmd
          DelayMilliSecs(1000);
          adp_exit_sample(); // make sure that we're in the ADP main menu
          adp_set_alt(); // set up the altimeter settings
          alt_stat=1; // done initializing
          
       } // end if alt_stat==0 -------------------------------------
        
       alt = adp_altimeter( );  // get a reading
       
       cprintf("altimeter return = %d\n", alt);
} //***************************************************************************


//*****************************************************************************
void   test_adp ( void )  //***************************************************
{ // test the above functions
  char ch=' ';
  short adp_pwr_on=0;  // =true if adp is on, false if it is off
  short status, n, reply, tmo=0;
  TUPort    *tup;

  tup = all.tu_port[TU_ADP].tup;  // correct tpu uart port pointer
  n = sizeof(gdum);
  cprintf("size of gdum = %d, 1st elem= %lu\n",n, gdum[1] );
  
  adp_off();

  cprintf("              Test of ADP : %s \n", __DATE__);
  menu_adp();
  while ( ch !='Q') //=======================================================
  {
	SerInFlush();  // flush any characters

        if (ch !=' ' && ch>0 ) 
            cprintf("V_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) { // call the desired function ++++++++++++++++++++++++++++
        case 'Q' : break;  // will quit the program
        case '?' : break;  // displays the directory prompt
        case 'U' : menu_adp(); break;
        case  -1 :  break; // wait for another character

        case 'C' : // clear buffer pointer
			all.adp->iscan = 0;
			break;  // turn on adp		   
        case 'A' : // dump buffer area
			status = adp_altimeter( );
			cprintf("alt depth = %d\n",status);
			break;  		   
        case 'B' : // set params for altimeter
			alt_test_check();
			// tputs( tup, "PowerOff"); // leave in lowpower
			break;  		   
        case 'D' : // dump buffer area
			adp_dump( );
			break;  		   
        case 'F' : // fake data
			create_fake_adp();
			parse_last();
			break; 	   
        case 'G' : // get a sample
			status = adp_get_sample( );
			cprintf("G status = %d  ",status);
			if (status!=0) { cprintf("NOT "); }
			cprintf("OK\n");
			parse_last( );
			break;  
					   
        case 'I' : 
			if (!adp_pwr_on) adp_pwr_on = adp_on(); 
            adp_info(); break; 
            
        case 'O' : // turn off
			adp_pwr_on = adp_off(); 
			cprintf("ADP is off\n");
			break;  
			
        case 'P' : // set up for collecting profile data
		    cprintf("Enter 1 for profile, 2 for shallow >\n");
		    n = get_num(&reply);
			if (n>0 && reply>0) adp_set_up( (float)reply );
			break;  
					   
        case 'S' : // enter sample mode
			adp_sample_mode();
			printf("ADP is in sample mode\n");
			break;  	
				   
        case 'T' : // test dumping data to the CF1
			adp_flash_test( );
			break; 
			 		   
        case 'W' : // turn on adp
			if (!adp_pwr_on) 
			     adp_pwr_on = adp_on();
			cprintf("ADP power is on, ADP is ");
			status = adp_exit_sample(); // makes sure we're not in sample mode
			if (status) cprintf(" awake\n"); 
			else        cprintf("NOT responding\n");
			break; 
				   
        case 'X' : // exit sample mode
			status = adp_exit_sample();
			cprintf("Xstatus=%d ",status);
			if (status==43 || status==62 ) 
				{ cprintf("OK\n"); }
			else
			  { cprintf("Not recognized...try again\n"); }
			break;  // turn on adp		   
        case '0' : // do zeroth order setup
			adp_setup0();
			cprintf("Initial setup is complete\n");
			break;  // turn on adp		   
        case '7' : // Post-process for Iridium message
			all.klifo = assign_lifo (all.lifo,1,0);
			lifo_gps( 0, 1); // append gps stuff
			lifo_eng( ); // appends the engineering data to the lifo
			adp_post_process( );
			break;  		   
        case '8' : 
			array_test();
			break;  
				   
        case '9' : 
			adp_pro_test( );
			break;  
			   
        case '6' : // do adp shallow test
			all.klifo=0; // has not been assigned yet
			adp_sbd_param( );
			cprintf("calling adp_shallow\n");
			adp_shallow( );
			parse_lifo(all.lifo, all.klifo);
			break;     
			
        case '$' : // get wakeup response in sample mode
			status = adp_query();
			cprintf("$status=%d\n",status);
			break;     

        default  : cprintf(" input unknown \n");
    } // end switch +++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
  }  //=== end while ========================================================

   adp_off();  // make sure adp is off
   cprintf("ADP is off\n");
   
   return;
} //***************************************************************************

void  menu_adp ( void ) //*****************************************************  
{ //print out menu selections *************************************************
cprintf("    ADP MENU   :  Q.uit ADP test :  U.pdate menu\n"
        "O.ff ADP       :  P.rofile setup :  0. one-time setup\n" 
        "W.akeup ADP    :  S.ample mode   :  G.et sample\n"
        "X.exit sample  :  $.sample prompt:  D.ump buffer \n"
        "C.lear buffer  :  T.est CF1 dump :  I.nfo on ADP\n" 
        "F.ake ADP pro. \n" 
        "A.lt Get       :  B. Alt init \n");
 return;
} //***************************************************************************


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