//****************************************************************************
//  sbd.c  : DEC 2008
//  control of the Iridium SBD Modem
//  for the Spray 2008 CF2 controller board
//
//==== Future Expansion =======================================================
//		last update: Feb2010
//
//	1. added shore command call
//
//*****************************************************************************

#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    "sbd.h"
#include    "gpio_mux.h"
#include    "gps.h"
#include    "lifo.h"
#include    "nav.h"
#include    "pitch_roll.h"
#include    "setup.h"

// 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;

// global space for message construction
// uchar   bdat[LIFO_NBYTE];  //buffer area to make up message

short  sbd_on ( void ) //******************************************************
{  // power up the Iridium SBD modem
   short istat = 0;
   struct spi_param *ss;
   
      ss = all.sspi; // points to the spi comms struct
      setup_spi ( CS_GPIO, ss );

  istat = SBD_On; // modem should now have power
  if ( istat != SPI_CRC_OK )
  { // error sending the 'ON' command
     cprintf("Err Stat sbd_on = %d\n", istat);
  } // else continue
  DelayMilliSecs(100);
  
  istat = spi_mux( 1, SER_SBD, ss ); // turn on rs232 & configure mux
  if ( !istat  )
  { // error sending the mux command
     cprintf("Err sbd_mux_on\n" );
  } // else continue
  
  return ( istat );
} //***************************************************************************


short  sbd_off ( void ) //*****************************************************
{  // Turn off the modem
   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 );

    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 = SBD_Off; // modem now has power
  if ( istat != SPI_CRC_OK )
  { // error sending the 'OFF' command
     cprintf("Err Stat sbd_off = %d\n", istat);
  } // else continue
  DelayMilliSecs(50);  // wait 
  
  istat = spi_mux( 0, SER_SBD, ss ); // turn off rs232 
  if ( !istat  )
  { // error sending the mux command
     cprintf("Err sbd_mux_on\n" );
  } // else continue

  return ( istat );
} //***************************************************************************



short sbd_ack ( TUPort *tup ) //***********************************************
  // send AT to modem & look for '0' returned
  // ASSUMES THAT MODEM IS IN NON-VERBOSE MODE ****
  // AND IN NON-ECHO MODE **** : requires sbd_init() below
  
  // return 1=ok, 0=error occurred
{ char at[] = "AT"; 
  short nget, ok, found;
  char sget[20];

  TURxFlush( tup );   //  flush the tpu port
  
  sget[0] = '\0'; // set to NULL str
  
  tputs( tup, at); // send AT
  nget = tgets ( tup, sget, 1,1,NO_EOL,&found); // get response, includes echo
  //  if (nget>0) cprintf("ack %s\n",sget);

  ok = (sget[0] == '0');  // = TRUE if OK
  TURxFlush( tup );   //  flush the tpu port
  
  return( ok );  
} //***************************************************************************


void sbd_init ( TUPort *tup) //************************************************
{ // send the initialization commands to the modem

  char ate0[] = "ATE0"; // no echo
  char atv0[] = "ATV0"; // not verbose mode
  char atd0[] = "AT&D0"; // ignore DSR
  char atk0[] = "AT&K0"; // no handshaking
  char atx3[] = "ATX3"; // error messages include busy, no dialtone
  short nget,found;
  char sget[80];
  
  TURxFlush( tup );   //  flush the tpu port
  
  tputs       ( tup, ate0 ); // no echo
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); // get response=potential echo
  //  if (nget>0) cprintf("init: %s\n", sget);
  
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); 
  tputs       ( tup, atv0 ); // not verbose
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); 
  tputs       ( tup, atd0 ); // ignore DSR
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); 
  tputs       ( tup, atk0 ); // no handshaking
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); 
  tputs       ( tup, atx3 ); // no handshaking
  nget = tgets( tup, sget, 40,1,NO_EOL,&found); 
  
  TURxFlush(tup);   //  flush the tpu port
  
  return;
} //***************************************************************************


void sbd_init0 ( TUPort *tup) //***********************************************
{ // initialize and save the settings
  char atw0[] = "AT&W0"; // store present config into #0
  char aty0[] = "AT&Y0"; // use config #0 on power-up

  
  sbd_ack  ( tup );   //  get a response
  sbd_init ( tup );   //  send the init commands
  
  sbd_cmd_rqst ( tup, atw0 );
  sbd_cmd_rqst ( tup, aty0 );

  cprintf("Initialization saved in modem\n");
    
  return;
} //***************************************************************************


short sbd_start ( void  ) //***************************************************
{ //  power up and initialize the SBD modem
  // return 1=ok, 0 = error
  
  short ok=0, i=0;
  TUPort    *tup;
  
  tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
  
      sbd_on(  );
      DelayMilliSecs(5000);  // let warm up

      
      while ( (i++<3) && (ok==0) ) //==================================
      { // try to initialize and get correct response
        sbd_init ( tup );
        DelayMilliSecs(1000);
        ok = sbd_ack( tup );
        
        if (ok==0) //-------------------------------
        { // if still no response, try once more
          cprintf("start_SBD ack err#%d\n",i);
          DelayMilliSecs(500); 
          ok = sbd_ack ( tup ); 
        } //----------------------------------------
        
      } //=============================================================
      if ( ok ) cprintf("start_SBD ack OK\n");
  return ( ok );
} //***************************************************************************


short  sbd_power_on ( void ) //************************************************
{ // Turn on power, initialize the SBD, and get a good response
  // returns 0=error, 1=OK : If error, leaves satellite off
  short i=0, ok=0;
  
	while ( (i++<3) && (ok==0) ) //====================================
	{ // try up to 3x to power up modem & get an ACK
	
	  ok = sbd_start (  ); // turn on SBD and initialize
	  if (ok==0)  //---------------------------------------------
	  { 
	    cprintf("start_SBD failure, powering down for 5 s\n");
	    sbd_off(  ); 
	    setup_one_tpu_uart( TU_SAT ); //jan13, re-init the uart
	    all.exc->exc_stat  |= EXC_SBD_RCVRY; // add error flag to return
	    DelayMilliSecs(5000); 
	    cprintf("now trying again\n");
	  }  //------------------------------------------------------
	  
	} //===============================================================
	
	// note if ok=0, then satellite is already off
  return ( ok );
} //***************************************************************************


short  sbd_clear_momsn ( void ) //*********************************************
{ // clears the MOMSN to 0, see SBD Doc 4.1.9
  // returns status of the clear
  // 0 = cleared successfully 
  // 1 = error occurred 
  
   char in[10]  = "\0";
   char out[]   = "AT+SBDC"; //clear the MOMSN
   unsigned short istat;  // return status
   short i = 0, nget, found;
   TUPort    *tup;
  
   tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
  
  while (in[0] != '0' && i++ < 2) //===================================
  { // try up to 2x to clear
    in[0] = '\0'; // reset 1st char=NULL
    TURxFlush( tup );
    tputs    ( tup, out);
    nget = tgets( tup, in, 1, 1,NO_EOL, &found);  // get response, = '0' if OK
    
  } //=================================================================
  
  istat = in[0]=='0';
  cprintf(" MOMSN cleared ");
  if (istat) cprintf("OK\n");
  else       cprintf("ERROR\n");
  
 return ( istat );  
 }//***************************************************************************

void sbd_clear_buf( TUPort *tup, short n ) //**********************************
{ //clears binary message out of sbd buffers, see SBD Doc 4.1.7
  //n = 0 - clear out MO buffer : MO= Mobile-Originated = message out
  //n = 1 - clear out MT buffer : MT= Mobile-Terminated = incoming
  //n = 2 - clear out both buffers
  
  char in[10];
  char out[] = "AT+SBDD0"; //last char = desired cmd
  short i = 0, nget, found;
  
  out[7] = n+48; // set the cmd char = char value of n

  while (in[0] != '0' && i < 3)  //============================== 
  { //try 3 times to clear buffer
    in[0] = '\0'; // reset 1st char=NULL
    TURxFlush(tup);   //  flush the tpu port
    tputs( tup,  out );
    nget = tgets( tup, in,3,1,NO_EOL,&found);  // get response
    i++;
    
  } //===========================================================
   
   return;
} //***************************************************************************


short  sbd_load_buf ( void ) //************************************************
 /* SBD_load_buf transfers all.bdat contents to the SBD buffer.
 /* It expects bdat is already loaded w/valid message from queue_lifo.
 /* Return codes:
 /*     0 = successful
 /*     1 = fail to load buffer, but did manage to return an error code */
 /*		2 = SBD comms problem : likely needs power cycle  */
 /*		3 = SBD did not reply 'READY' : likely needs power cycle */
 
{  // see also SBD Doc 4.1.2
   short i=0,k=0,len, nget, j, found;
   unsigned long cc=0, dummy;
   char in[32] = "\0"; //rx string
   char ready[] = "READY";
   char outstr[32] = "\0";
   unsigned char c0,c1; 
   TUPort    *tup;
  
   tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
  
  //bdat[0]=X; bdat[1] and bdat[2] are 2 byte length of data.
  //we have to add on the header and idg cc (for use with GS)
  len = all.bdat[1]*256 + all.bdat[2] + 3 + 4; //3 = hdr, 4 = idg cc ;
  if (len > MAX_SBD_OUT ) len = MAX_SBD_OUT;  // keep legal

  //we will try up to 3x to get the modem to acknowledge us
  i=0;	// reset try counter, try ack_ISU() = TRUE if good response
  while (   !sbd_ack( tup )   &&   i++<3  ) 
        { DelayMilliSecs(1000); };	
        		
  if (i==3) 
  { cprintf("failed SBD ACK\n");
    return(2); // exit with FAIL flag : can't talk to the modem
  }
  
  //else we're communicating.  Send the command w/buffer length
  in[0] = '\0';  // first char=NULL = empty string
  sprintf(outstr,"AT+SBDWB=%d",len); //tell isu to write binary
  // printf("%s\n",outstr);
  TURxFlush(tup);
  tputs( tup, outstr); //send AT command
  nget = tgets( tup, in, 7, 2,'\n',&found);  // get response
  // strncmp=0 if it matches, else !=0 = no match, is bad, so return
  // for (i=0;i<nget;i++) printf("%2x.",in[i]);  printf("\n");
  // in[5] = '\0'; // set to 0 to try to get strncmp to work
  i = strncmp(in,ready,3); 

  if ( i !=0 )
  {  cprintf("SBD not ready: %s\n",in);
     return(3);  // return if bad match
  }
  
  // we're here if rcv'd "READY", now send the data & chksum
	 cc = 0; //reset checksum
	 for (i=0;i<len;i++) //==========================================
	 {   // send each data byte
		 TUTxPutByte( tup, all.bdat[i], 0); //0=don't wait for reply char
		 for(j=0;j<60;j++) dummy = j; // dec05, slow down xfr
		 cc += all.bdat[i]; //sum
	 } //============================================================
	 
	 //compute and send cc
	  c1 = ( cc & 0xff00 )>> 8;  // MSB of #bytes
	  c0 = ( cc & 0x00ff );      // LSB of bytes
	  TURxFlush(tup);;  // clear input buffer
	  TUTxPutByte( tup, c1, 0); // send MSB
	  TUTxPutByte( tup, c0, 0); // send LSB

	  in[0] = '\0';  //=NULL  
	  nget = tgets( tup, in, 1, 2, NO_EOL, &found);   //get 1 char response in 2 s

	  cprintf("Data packet to SBD buffer return status=%c ",in[0] );
	  if (in[0] =='0') cprintf(" OK\n");
	  else             cprintf(" BAD\n");
      // in[0] = command response character,
      // 0=success, 1=write timeout (not enough bytes),
      // 2=bad checksum, 3=bad message size : max = MAX_SBD_OUT, min=1
      
	  i = in[0] - 48;  //i = decimal value of the command response char.
	  k = 2;  //init k=status, value=2 implies a comms problem
	  if (i==0) k=0; // successful send
	  if ( i>0 && i<4 ) k=1; // legal command response, but have a problem
	  // else k=2 = not a legal command response
	  
  return (k);
 }//***************************************************************************	


short  sbd_status ( void ) //**************************************************
{ // requests send/rcv status, see SBD Doc 4.1.9
  // sbd->SBD->mtstat has the status of the receive buffer.
  // this is just called from bench-test to make sure SBD responds.

  // returns status of the send buffer
  // send and/or rcv value = 
  // 0 = no message, 
  // 1 = message is present 
  // 2 = not parsed correctly
  
  char in[30]  = "\0";
  char sbds[] = "AT+SBDS"; //request SBD status
  short i1, i2, i3, i4;  // return status
  short i = 0, nget, found;
  struct sbd_param *sbd;
  TUPort    *tup;
  
  sbd = all.sbd; // point to sbd info
  tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
  
  TURxFlush(tup);   //  flus. the tpu port
  
  while (in[0] != '+' && i < 3) //=========================================
  { // try up to 3x to get the status
    in[0] = '\0'; // reset 1st char=NULL
    DelayMilliSecs ( 20 );
    TURxFlush (tup);   //  flush the tpu port
    tputs     ( tup, sbds );
    nget = tgets( tup,in,29,1,NO_EOL,&found);  // get response, = '+' if OK
    i++;
  } //=====================================================================
  
   //try to parse: i = #variables successfully read in from stat
   //init to 2 = error in parsing
   i1=-99; i2=-99; i3=-99; i4=-99;
   i=sscanf(in,"+SBDS:%d,%d,%d,%d",&i1, &i2, &i3, &i4 );
        cprintf("+SBDS:%d,%d,%d,%d\n",i1,i2,i3,i4 ); //debug
   /* save values : not needed, as only used as bench-test
   sbd->SBD_mtmsn = i4; // MT sequence number
   sbd->SBD_mtstat= i3; // MT status : 1=message received
   sbd->SBD_momsn = i2; // MO sequence number
   sbd->SBD_mostat= i1; // MO status : 1=message still in buffer /**/
 	
 
 return ( i1 );  
} //***************************************************************************

void   sbd_setup ( void ) //***************************************************
{ //  setup of sbd parameters
  struct sbd_param *sbd;
  
  sbd = all.sbd;
  // use to initialize if necessary
  // presently all params are from iparam
      
  //sbd->SBD_xfer_time = iparam [ IA_sbd_pack_tm ] ; 
  // max time(s) to wait for SBD transfer to complete
  
  
  return;
} //***************************************************************************


//*** satellite modem status, settings
short sbd_cmd_rqst ( TUPort *tup, char *s ) //*********************************
{ // send command s and echo the returned info 
  // returns TRUE if got a response
  
  short nget,  j, found;
  char r[81]; // returned string
  
  // printf("%s: ",s); // show the command
  TURxFlush(tup);   //  flush the tpu port
  tputs ( tup, s); // send the string
  
  for (j=0; j<3; j++ ) //==================================================
  { // get up to 3 response lines
  
    nget = tgets( tup,r,79,1,'\n',&found); 
    if (nget>2) 
       cprintf("%s\n", r);
       //{ for (i=0;i<nget;i++) SCITxPutChar( r[i]); }  //display
  } //=====================================================================
  
  
  return( nget>0 );
} //***************************************************************************

void   get_IMEI( TUPort *tup ) //**********************************************
{  // queries modem for IMEI #, plus model #, etc.
  
   char in[80]  = "\0";   // reply
   char gsn[] = "AT+GSN"; // returns the IMEI #
   char gmr[] = "AT+GMR"; // processor info
   char cgm[] = "AT+CGMM"; // modem model #
  
   sbd_cmd_rqst( tup, gsn ); // get imei
   sbd_cmd_rqst( tup, cgm ); // show model #
   sbd_cmd_rqst( tup, gmr ); // return processor info

   
   return;
}//****************************************************************************
 
short sat_signal( TUPort *tup)    //*******************************************
{ // requests the satellite signal strength, see AT commands, +CREG, +CSQ
  // returns strength 0..5
  // -1 = ISU is not registered,
  // -2 = can not communicate
  // -3 = no reply from CSQ
  
  char  r[30]  = "\0";
  char creg[]  = "AT+CREG?";  // request registration status
  char csq[]   = "AT+CSQ"; //request the signal strength
  unsigned short i1, i2, i3;  // return status
  short i = 0, nget, ok, found;
  
  ok = -2;  // start off assuming that we can't communicate
  
  while ( r[0] != '+' && i < 3) //=========================================
  { // try up to 3x to get the registration status
  
    r[0] = '\0'; // reset 1st char=NULL
    DelayMilliSecs(1000);
    TURxFlush(tup);   //  flush the tpu port
    tputs( tup, creg);
    nget = tgets( tup, r, 29, 1,NO_EOL,&found);  // get the response
    i++;
  } //=====================================================================
  
  i=sscanf( r,"+CREG: %u,%u",&i1, &i2);
  cprintf("%s\n", r);  // echo the line

  if (i !=2 ) return(-2);  // did not get a valid reply
  if (i2 !=1 ) return(-1);  // ISU is not registered
  // else i2=1 : we're registered
  
  // we should now be able to get a signal strength
  TURxFlush( tup );   //  flush the tpu port
  tputs( tup, csq);
  nget = tgets( tup, r,29,4,NO_EOL,&found);  // wait up to 4 s for reply
  if ( r[0]=='+' && nget>3 ) //----------------------------------
  {  // valid response
     i=sscanf( r,"+CSQ:%d",&i3);
     if (i==1) ok=i3;  // we got a valid signal strength
  } else ok = -3; // ok==-3 = no reply from csq request ---------
 
 return(ok);  
 }//***************************************************************************

//*****************************************************************************
// Message formatting/parsing functions
//*****************************************************************************

void add_crc ( uchar a[], short length ) //************************************
{ // compute crc and add to the end of the message 
  uchar *buf = a;  // assign 1st addr to pointer
  unsigned long x=0;
  uchar c0=0;
  uchar c1=0;

  while (length--) x +=  *buf++; // x=sum(a)
  
  c0 = (unsigned char) x;  // assign LSByte to c0
  // turn in to nibbles to assign hexadecimal
  c1 = (c0 & 0xf0 ) >> 4;  // masked and right-shifted
  c0 =  c0 & 0x0f;  // = lower 4 bits
  // add delimiter char
  *buf++ = '$';
  // shift c0, c1 values up to readable : 48 = '0'
  // this is a kluge to get around writing out as hexadecimal
  *buf++ = c1+48;  
  *buf++ = c0+48; 
  // add end character = '>'
  *buf++ = '>';        

  return;
 }//***************************************************************************

short sbd_chk_crc ( uchar a[], short n ) //************************************
{ // a[0] = 'X' , n=#bytes from 'X' up to '$'
  // returns 1 if correct, 0 if bad
  
  uchar c0, c1;
  long x=0;
  short i, y;
  
  if (n<0) return(0);  // safeguard for illegal value
  
  for (i=0; i<n; i++) 
      x += a[i];  // accumulate bytes
  
  if ( (a[n] == '$' ) &&  (a[n+3] == '>') )
  { // then we see the right delimiters
  	c1 = a[n+1] - 48;  // range should be 0..15
  	c0 = a[n+2] - 48;  // range should be 0..15
    y = c1*16 + c0; //=chksum value encoded in packet
  }
  else
  { return(0); } // else not right delimiters, return false
  
  i = (x & 0xff);  //=LSByte of chksum, should equal y
  
  return( i==y );
 }//***************************************************************************

void format_out ( uchar *b, uchar c, short n) //*******************************
{ // format output str of data *b of n bytes with command char c
  // bdat output has format of "Cnnbbbb...$cc>'
  // where C = command character, used by the ground station,
  // nn = 2 bytes = length of the data array *b
  // bbb...=data
	short i, n0, n1;
	
	n1 = ( n & 0xff00 )>> 8;  // MSB of #bytes
	n0 = ( n & 0x00ff );      // LSB of bytes
	all.bdat[0] =  c;  // first char = command value, ie X or S
	all.bdat[1] = n1;
	all.bdat[2] = n0;
	
	for (i=0;i<n;i++) 
	    all.bdat[i+3] = *b++; // xfr over the data
	    
	add_crc ( all.bdat, n+3); // appends crc onto end of bdat
	// crc includes the first 3 bytes = 'Cnn' of the packet
	
	return;
 }//***************************************************************************


short sbd_sbdi ( void ) //**************************************************
 /*AT+SBDI is the command to do bidirectional SBD transfer. 
   The MO buff (only 1 msg) is sent to GS and anything queued by GS (only
   1 msg) is transferred to the sbd MT buffer and then parsed.  */
// RETURNS status:
//  0 = no SBD message queued in SBD to send
//  1 = SBD message was successfully sent.
//  2 = an error occurred while attempting to send.
//  3 = parsing error while reading the command response
//  8 = no satellite (<10 s for reply with error=2 )
//	9 = timeout (no command response from SBD ...not good )
{ // see also SBD Doc 4.1.6

 char xfer[10]  = "AT+SBDI\0";
 char rstat[40] = "\0";
 short i=0,j=0,mtlen,maxT, nget, found;
 unsigned short i1, i2, i3, i4, i5, i6;  //tmp values of new status
 unsigned long tnow, dt, momsn, mtmsn;
 short mostat;
 struct sbd_param *sbd;
 TUPort           *tup;
   
 tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
 
 
 sbd = all.sbd; // point to sbd info
 maxT = iparam [ IA_sbd_pack_tm ]; // time to wait for packet response
 
 // The message is already queued into the SBD buffer
 // OR we're asking to get an incoming (MT) message
 sbd_ack( tup ); //  sync with modem
 DelayMilliSecs( 100 ); // pause 
 TURxFlush(tup);   //  flush the tpu port
 tputs( tup, xfer ); // this initiates the transfer
 tnow = RTCGetTime( 0, 0 ); // get time now
 
 // wait up to maxT seconds for a response from the SBD
 do // do until we get a response or i==maxT
 {  
    nget = tgets ( tup, rstat, 39, 1, NO_EOL, &found);

 } while (  (i++ < maxT)  && ( nget<1 ) );

 
 if ( i >= maxT ) return(9); // never got an answer
 dt = RTCGetTime( 0, 0 ) - tnow;  // time (secs) until we got an answer
 cprintf("sbdi return str= %s\n", rstat);
 
 //try to parse: i = #variables successfully read in from stat
 i=sscanf(rstat, "+SBDI:%u,%u,%u,%u,%u,%u",&i1, &i2, &i3, &i4, &i5, &i6);
       //cprintf("+SBDI:%u,%u,%u,%u,%u,%u\n",i1,i2,i3,i4,i5,i6); //debug
        
 mostat=3; // err=3 = sscanf was NOT successful
 sbd->SBD_mtstat=3; // " "
 sbd->SBD_mtque =0; // init to no messages from GS in queue
 
 switch(i) { // assign the correct # of variables actually read
   case 6 : sbd->SBD_mtque = i6; //=#messages in GS waiting to still be sent
   case 5 : mtlen = i5; //=length of the incoming MT message
   case 4 : mtmsn = i4; // MT sequence number
   case 3 : sbd->SBD_mtstat= i3; // MT status : 1=message received
   case 2 : momsn = i2; // MO sequence number
   case 1 : mostat= i1; // MO status : 1=message sent
 } // end switch : note no breaks so i=n executes all cases for i<=n
 
 cprintf("msg was ");
 if      (i1==1) cprintf("sent OK\n");
 else if (i1==2) cprintf("ERR from Modem to Sat\n");
 else cprintf("NOT sent\n");
 	
 // read in/clear outgoing buffer if successful										
 if (sbd->SBD_mtstat== 1) sbd_receive( ); //get the message that came through
 
 if ( mostat== 1) sbd_clear_buf(tup, 0); //make sure MO is cleared out
 // fnx should be called again elsewhere if mtstat,mostat merit it.
 // set flag that most likely a satellite was NOT visible
 if ( dt<10  &&  mostat==2 )
   mostat = 8;  // 8=no satellite
 cprintf("#shore cmds in queue=%d\n",sbd->SBD_mtque);
 
 return ( mostat );		
} //***************************************************************************


void   sbd_receive ( void  ) //************************************************
{ // receive a message from the  SBD buffer.
  // max length is MAX_SBD_IN characters, comprised of N sub-commands 
  // Any sub-command can only by <80 characters, delimited by ';'
 unsigned char in[MAX_SBD_IN];
 char at[10] = "AT+SBDRB";
 short rstat=9,i=0,len,nget,j, pstat, found;
 long cc, csent;
 struct sbd_param *sbd;
 TUPort           *tup;
   
 tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer
  
 sbd = all.sbd; // point to sbd info
   
 while ( rstat>0 && i++<3 ) //===========================================
 { // try up to 3x to get incoming from the ISU
   in[0] = '\0';  // set to NULL
   cc=0; // checksum accum
   TURxFlush(tup);
   
   sbd_ack ( tup ); // make sure in sync
   DelayMilliSecs( 100 );
   TURxFlush(tup);   
   tputs( tup, at); //request binary transfer of MT
   nget = tgets ( tup, (char*)in, 2,1, NO_EOL, &found); // get 1st 2 bytes
   if (nget==2) //222222222222222222222222222222222222222222222222222
   {
     len = in[0]*256 + in[1]; // = #bytes to expect, add on 2 for cc
     if (Verbose) cprintf("nget=%d, rcv_len = %d \n",nget, len);
     if (len< MAX_SBD_IN ) // could be legal
     {   nget = tgets ( tup, (char*)in,len+2,1, NO_EOL, &found); // get the rest
         if (Verbose) 
         { cprintf("nget=%d, msg= %s\n", nget, in);
           for (j=0;j<nget; j++ ) cprintf("%02x ",in[j] );
           cprintf("\n");
         }
     }
     
     if ( nget >= len+2 )  //nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
     { // then got enough bytes
       for (j=0;j<len;j++)  cc += in[j]; // accum checksum
       csent = in[len]*256 + in[len+1];  // cc sent @ end of data
       
       if (Verbose) cprintf("rcv len ok = %d\n",nget);
       if ( cc == csent ) //-----------------------------------
       { if (Verbose) cprintf(" receive checksum agrees\n");
         sbd_clear_buf( tup, 1); // clear out SBD incoming buffer
         rstat = 0; // set status that we got the packet OK
         // now parse the message, which now has form:
         //in = Xnnddd;$cc>CC where CC are added by SBD
         //we need to strip these off (see ATSBRB doc for definitions)
         //xx - bytes coming, already stripped off
         //CC - 2 byte SBD checksum
         pstat = parse_X_reply( len, in );
         cprintf("rcv %d parse stat=%d\n", i, pstat );
         all.eng->sbd_shore_stat = pstat+1; //save the parsing status
       } //----------------------------------------------------
       else cprintf("rcv chksum disagree: %ld != %ld\n",cc, csent);
       
     } //nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
     else
     {  cprintf("Expected length=%d != actual=%d\n",len+2, nget);
        cprintf("msg = %s\n", in);
     }
   } //22222222222222222222222222222222222222222222222222222222222222
   else cprintf("did NOT get rcv LEN: nget=%d\n", nget);
   
 } //====================================================================
   
   if (pstat != 0) 
        all.sbd->SBD_mtstat = pstat+3; //error codes 3-7
   else all.sbd->SBD_mtstat = 0; //recieved and parsed successfully
   
  return;   
} //***************************************************************************


short  parse_X_reply ( short n, uchar *s) //***********************************
{ 
    // Used by SBD packet as well
    // s =packet from GS of n bytes
    /* returns transmit status:
 	0 = data packet received successfully
	1 = SBD received GS packet with an error, but continue anyways
	2 = SBD requests a re-transmit of the GS packet
	3 = SBD received wrong # of bytes or bad CRC
	4 = no 'X' packet found
	(above)+5 = SBD detected a bad sub-command
	/**/
  short i=0, tstat, ndat, nrec, j, crc_ok, terr, tmax;
  uchar tstr[80], ch;  // = temporary command string to parse
  char cerr;
  
  //search for 1st occurrence of 'X' = transmit packet found
  while ( (s[i]!='X') && (s[i]!='x') && (i<n-1) ) i++;
  if (i==(n-1)) return(4); // then 'X' not found, return now
  j = i + 4 + 3; // j=minimum X len, adding on nn + crc
  if (j>n) return(3); // can't possibly be right, return now

  // else X has been found : do error-checking
  ndat = s[i+1]*256 + s[i+2]; //= # data bytes in the message
  nrec = n - i - 4 - 3; //= #data bytes actually available
  if (ndat<1) return(3);  // NOT believable
  tstat = 0;  // assume is ok
  terr  = 0;  // same
  tmax  = 0;  // max value of the parsing error
  if (nrec != ndat) 
  {  tstat = 3; // bad # of bytes
     cprintf("#data bytes=%d, #avail=%d\n", ndat, nrec);
     if (ndat>nrec) ndat=nrec;  // don't go beyond what's avail.
  }
  
  crc_ok = sbd_chk_crc(&s[i],ndat+3);  //  checks CRC
  cprintf("sbd crc_ok = %d\n",crc_ok);
  
  if (crc_ok) //=======================================================
  { //then packet makes sense, go ahead and parse
    // read in command substrings, delimited by ';' until end of string
    i = i+3; // points to 1st data char, passing over 'X' & byte count
    
    //OLD: echo_store( &s[i], nrec); // store the shore cmd string
    j = 0; // = counter of characters in the command string
    while ( (i<(n-4)) && (s[i] != '$') ) //----------------------
  	{ // read in char until end of string or start of CRC = '$' char
  	  ch = s[i++]; //read in char
  	  if (ch != ';') // ';' command substring delimiter
  	    { tstr[j++] = ch; } // store character
  	  else // we found a ';' = end-of-sub-command
  	  { tstr[j] = '\0';  // add a null str id
  	    cprintf("Parsing %s\n", tstr);
  	    terr = parse_cmd(  tstr ); // parse the command string
  	    if ( terr>tmax ) tmax = terr; // keep the max value
  	    //echo command, with status
  	    if (terr==0) cerr=';'; // good
  	       else      
  	       {  cerr=':'; // bad
  	          cprintf("Parse Error= %d\n",terr );
  	       }
  	       
  	    echo_store( tstr, strlen(tstr), cerr ); // echo back
  	    j = 0; // reset for the next input string
  	  } // end if..else
  	} //---------------------------------------------------------
  	
    if (j>0) // parse the last sub-command
    { tstr[j] = '\0'; // add a null str id
      terr = parse_cmd( tstr );
      if (terr>tmax) tmax = terr; // keep the max value
  	    //echo command, with status
  	    if (terr==0) cerr=';'; // good
  	       else      
  	       {  cerr=':'; // bad
  	          cprintf("Parse Error= %d\n",terr );
  	       }
  	       
  	    echo_store( tstr, strlen(tstr), cerr ); // echo back
    }
  } //=================================================================
  else // crc was bad
  { tstat = 3; }// set tstat accordingly ==============================
  	
  if (tmax>0) //then trouble with parsing a sub-command
    tstat = tstat + 5 +tmax;

return(tstat);
} //***************************************************************************	

//*****************************************************************************
void   echo_store ( uchar *buf, short nbytes, char cerr ) //*******************
{ // echo the shore command to the all.edat buffer area
  // *buf = shore command buffer
  // nbytes = #char in *buf
  // cerr = error status, ';' =OK else ':' = bad
  // returns an updated n0
  short i, n0;
  
  n0 = all.necho; // where to start storing
  
    if (  (nbytes+n0)< LIFO_NBYTE  )
    {  // tack on the shore command
       for (i=0; i<nbytes; i++)
          all.edat[n0++] = buf[i];
       //end char
       all.edat[n0++] = cerr;
    } // else, not enough room, n0 stays the same
  all.necho = n0; // update the pointer
    
  return;
} //***************************************************************************


void   check_more_shore  ( void  ) //******************************************
{  // If there are still more shore commands, get them now
   short i=0, sbdi_stat;
   
   // all.sbd->SBD_mtque = #shore cmds waiting in the queue
   while( all.sbd->SBD_mtque>0  && i++<5 ) //==========================
   { // try up to 5x to read in more messages in the que
   
       sbdi_stat = sbd_sbdi( );  // initiate an SBD session
       all.eng->sbdi_stat  = sbdi_stat; // save the status in sbdi_stat
       if (Verbose) cprintf("cms %d %d \n",sbdi_stat, all.sbd->SBD_mtque );
       
       if (sbdi_stat>7)  //--------------------------------
       {   // no satellite, wait another 20 s
           sleep_check ( 20, PIT_ONLY, 1);  
           all.sbd->SBD_mtque=1; // set for the next while loop
        } //-----------------------------------------------
        
   } //================================================================
	
   return;
} //***************************************************************************


 
short  sbd_send ( void ) //****************************************************
{ // transmits the queued LIFO message, parses any incoming messages,
  // returns status with definitions:
  //  0 = the message was transferred successfully
  //  1 = no satellite was visible
  //  2 = data transfer unsuccessful but comms to ISU is ok
  //  3 = either a loading or parsing error : needs a power cycle
  short k, rstat,sbdi_stat;
		
	//load bdat message into the modem ------------------------------
	k=0; rstat=1;// init try counter & status=1 = try again
	while ( rstat==1 && k++<3 )
	{ // this exits if stat !=1 or tried 3x
	  rstat = sbd_load_buf ();
	} //stat=0=good, stat=1=failed load, stat=2,3 = bad comms
	if (rstat>0) return(3); // Load FAILED, set flag=power cycle request
	
	//---------------------------------------------------------------
	//now have loaded a message into the SBD, try sending up to 3x
	k=0; sbdi_stat = 2; //sbdi_stat=2 means transfer error (see SBD_ATSBDI)
	while ( sbdi_stat == 2  &&  k++ < 3 ) 
	{ //sbdi_stat=1=good, 0=no message was there to send, all else=error
	  sbdi_stat = sbd_sbdi ( ); // try to send
	  all.eng->sbdi_stat = sbdi_stat; // save the status in sbdi_stat
	}
	all.sbd->ntries +=k;  // increment #of tries to send the message
	
	k=3; // status to return, init to an error requiring a power cycle
	if (sbdi_stat==1) k=0;  // sbdi_stat=1 means success
	if (sbdi_stat==8) k=1;  // sbdi_stat=8 means no satellite
	if (sbdi_stat==2) k=2;  // sbdi_stat=2 means an unsuccessful send
	// all other sbdi_stat suggest a comms/parsing problem : do a power cycle=3
	
  return(k);
} //***************************************************************************


short   sbd_surface  (  short wc ) //******************************************
{
  // conducts data-exchange session using SBD to send all LIFO messages.
  // short wc = wing-control: do active wing control while waiting if TRUE
  // returns the number of packets successfully sent
  
  short i, rstat, iwing;
  ulong tnow, max_t,cc=0, nwait, xmit_try =0, t0, tnext, twc=120;
  short pwr_cyc=1; // set TRUE if a power cycle is desired
  short wing;
  short send_msg; // flag=TRUE if there is a message to send
  short checked_shore=FALSE; // checked for more shore commands
  struct sbd_param  *sbd;
  struct lifo_param *lifo;

	sbd  = all.sbd;   // point to sbd info
	lifo = all.lifo;  // and the lifo info
	
	tnow = RTCGetTime( 0, 0); // = time now
	sbd->t_start = tnow; // marker for flash
	max_t = tnow + iparam [ IA_sbd_max_tm ]; // = time to give up
	tnext = tnow + twc;  //do wing control every 120s
	iwing = all.wing_now[SBD_UNIT];
    if (iwing != PORT_WING) iwing = STBD_WING; // set to a legal value
    
	sbd->nsent = 0; // zero out accum of #packets sent.
	sbd->ntries= 0; // #connect tries attempted
	all.eng->sbd_shore_stat = 0;  // if get shore cmd, will be updated
	send_msg = check_lifo(lifo); // >0 if there is a message to send
	
	#if DEBUG==1
	  cprintf("DEBUG could do early exit from sbd_surface here\n");
	  // return(0);
	#endif
	all.fp_sco = open_sco (); // open the change-order file
	
	while ( send_msg && tnow<max_t ) //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	{ // while there's still something to send & not timed out...
	
	    if (tnow >tnext && wc==1 ) //--------------------------
	    { // then time to do active wing control
	      roll_wing(iwing,0); // make sure the wing is up
	      tnext += twc; // update for next desired time
	    } //---------------------------------------------------
	    
	    if (pwr_cyc) // ppppppppppppppppppppppppppppppppppppppp
	    { // power up & return if problem
	      rstat=sbd_power_on(); // power on and initialize
	      if ( rstat==0 )
	      { cprintf("sbd_power_on Failure\n");
	        return(0);
	      } // dec14, changing to PIT_IRQ2 from PIT_ONLY
	      sleep_check (20, PIT_IRQ2, 1); //waits for satellite
	    } // end power cycle pppppppppppppppppppppppppppppppppp

		i = queue_lifo(lifo); // store a message in global bdat		
		cprintf("SBD_send\n");
        t0 = RTCGetTime( 0, 0); // time right before trying to send
		rstat = sbd_send( );   // and try to send it
        xmit_try += ( RTCGetTime(0,0) - t0 ); // accum time trying to send		
		//depending on success of send, do the cmd
		pwr_cyc=0; //assume we don't want to cycle the power
		nwait = SBD_WAIT_FOR_SAT; // =time to wait if no satellite present
		
		switch (rstat) { //--------------------------------------
		  case 0 : // success
		  			sbd->nsent++; // increment success counter
		  			nwait = 0;  // go ahead & proceed to next try
		  			lifo->stat[i] = 0; // =sent w/no errors
		  			break;
		  case 1 : // no satellite is present
		  			// don't cycle power, don't change nwait
		  			break;
		  case 2 : // marginal satellite coverage
		  			// don't cycle power, don't change nwait
		  			lifo->ntry[i] += 1; // increment #tries
		  			lifo->stat[i] = 2; // tried, but didn't get through
		  			break;
		  case 3 : // comms problem to the ISU
		  			lifo->ntry[i] += 1; // increment #tries
		  			lifo->stat[i] = 2; // tried, but didn't get through
		  			pwr_cyc =1; // do a power cycle to try to fix comms
		  			nwait = 20; // & wait 20 s to try again 
		  			break;
		} // end switch -----------------------------------------
		
		if (pwr_cyc) sbd_off(); // turn off power
		if (nwait>0) // wait before trying again
		   sleep_check (nwait, PIT_IRQ2, 1);  //dec14, to PIT_IRQ2
		tnow = RTCGetTime ( 0, 0);  // = time now
		
		send_msg = check_lifo(lifo); // see if there's another message
		
		// special loop at end-of-lifo-messages: do shore cmd checks/echos
		if (send_msg==0  && !checked_shore) //=========================
		{ // no more messages, check for more shore cmds, echo back all cmds
		   cprintf("Checking for more commands\n\n");
		   check_more_shore( ); // check for more shore commands
		   checked_shore = TRUE; // set flag that we've checked
		   
		   if (all.necho>0) // then we want to echo back shore cmds
		   {  cprintf("Echo-back commands\n\n");
		      lifo_echo( ); // queue it: puts in a new message
		      
		      //append waypt list if wanted
		      if (all.sbd->send_waypts) 
		         lifo_waypts( ); //sets send_waypts=0
		      if (all.sbd->send_param) 
		         lifo_store_param( ); //sets send_eeprom=0
		      send_msg = 1; // set flag that there is a new message
		   }
		   
		} //===========================================================
		
	} //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		
	sbd_off(); // leave w/satellite turned off
	
	cprintf("Done: #of msg sent = %d\n",sbd->nsent );
	
	all.eng->nsent  = sbd->nsent;  // save for engineering packet
	all.eng->ntries = sbd->ntries; // ditto
	sbd->t_SBD = xmit_try; // t[s] spent trying to transmit
	all.eng->t_SBD  = 0x00ff & (short)xmit_try;  // keep to 1 char value
	
	// store the wing we used in the upper nibble of sbdi_stat
	wing = all.wing_now[SBD_UNIT];  // =the wing we're using
	if (wing==1) all.eng->sbdi_stat |= 0x10;  // put value in upper nibble

	fclose ( all.fp_sco );  // close the spray-change-order
    //update any files if needed
    if ( sbd->save_waypt)  	waypt_display(TRUE);
    if ( sbd->save_route)   display_route(TRUE);
    if ( sbd->calc_route)   verify_route();
	
	sbd->t_end = RTCGetTime(0,0);

	if (all.exc->reset == TRUE ) 
	{  
	   cprintf("Remote Request to Reset\n");
	   Reset_CF2(); //!!!!cause a reset
	}
	
  return(sbd->nsent); //=# of packets actually sent
} //***************************************************************************


short try_gps_sbd( short gps_ver ) //******************************************
// *** try gps and Iridium, returns >0 if gps is good and sent
{ short good, status, iprof, nsent;
  short pot_good;
  struct ublox_param *ubx;
  
  ubx = all.ubx; // used for surface drift calculations

    Pitch_Xmit; //go to right pitch
    iprof = iparam [ EA_prof_num ]; // profile #
    if ( gps_ver == 0 ) // then start-of-mission
      iprof = 0; // also mark the profile # as a start
    
    #if ANT_SWITCH  // go to desired wing and set up the switch
      pot_good = RF_Wing_Setup ( GPS_UNIT );
    #else // there is no antenna switch, use the starboard wing
	  pot_good = roll_wing (STBD_WING, 1);
	#endif  // jun06

    cprintf("get gps\n");
    if (gps_ver==0)  ubx->index = 0; // surface-start drift
    if (gps_ver==3)  ubx->index = 1; // end drift
    good = get_gps(  pot_good );  // get gps
    // now try sending through iridium
    
    all.klifo = assign_lifo ( all.lifo, iprof, 0 ); 
    //cprintf("calling lifo_dive_mark\n");
    lifo_dive_mark(); // 0902 add dive/profile/time marker
    // above starts a new packet, profile#, packet id=0
    // append gps_ver: 0=start-of-mission, 3=abort 
    if (gps_ver==3) // in abort mode, save exception status
    {  
       all.gps->smax = all.exc->exc_stat & 0x00ff;  // save LSB
       lifo_abort(); //JULY14 add
    }
    lifo_gps( gps_ver, 1);
    lifo_surface(); //JULY14 add
    
    #if ZOOG ==1 // >>> aug15
     // lifo_zooCam();  // add zooCam info: sep15, removed
    #endif
     
	  if (all.sbd->send_waypts) 
	     lifo_waypts( ); //sets send_waypts=0
	  if (all.sbd->send_param) 
	     lifo_store_param( ); //sets send_eeprom=0

    // if abort-mode, calculate surface drift as well
    if (gps_ver==3) //-------------------------------------------
    {
       if ( calc_surf_drift() ) // true if both fixes are good
          lifo_surf_drift(1); // then store to lifo
          
       if ( good ) //===================================
       {  // then bump this surface 'end-gps' to 'start-gps'
          // for the next surface calculation
          ubx->valid[0] = ubx->valid[1];
          ubx->lat[0]   = ubx->lat[1];
          ubx->lon[0]   = ubx->lon[1];
          ubx->ti[0]    = ubx->ti[1];
       } //=============================================
       // else the last good gps fix still resides in [0]
       
    } //---------------------------------------------------------
    flush_pp( 0 ); // dec14: make sure the ping-pong buffer gets written out now.

    cprintf("SBD send for profile # %d, ipp=%d\n", iprof, all.ppb->ipp);
    
    #if ANT_SWITCH  // go to desired wing and set up the switch
      pot_good = RF_Wing_Setup (  SBD_UNIT );
    #else // there is no antenna switch, use the port wing
	  pot_good = roll_wing ( PORT_WING, 1);
	#endif 
	
    #if SBD==0 // use GS command
      printf("Compilation error: SBD only!!\n")
    #else // use SBD command set
	  nsent = sbd_surface(  pot_good );
    #endif
    
  status = ( nsent>0 && good>0 );  // is >0 if both are good
  return(status);
} // **************************************************************************

void   try_cycle ( void ) //***************************************************
{ // test for trying surface transmission multiple times
  short awakened=FALSE, dt, i, n, rstat;
  short min_cyc_time= 10; // #s between tries
  ulong tnow, tmax;
  

  cprintf("give time delay [sec] before starting (if 0, will NOT pitch/roll) >\n");
  rstat = get_num(&dt);
  if (!rstat) { cprintf("Bad input\n"); return; }
  if (dt==0) cprintf("LAND TEST, will not run pitch/roll\n");
  cprintf("give # surface cycles to do >\n");
  rstat = get_num(&n);
  if (!rstat) { cprintf("Bad input\n"); return; }
  
  cprintf("starting try_cycle\n");
  tnow = RTCGetTime( 0, 0 );
  if (dt>0) // wait to start
     awakened = sleep_check(dt,PIT_IRQ2_RXD, FALSE);
  i=0;

  all.sbd->nsent    = 0; // zero out accumulator
  
  while (  !awakened  && i++<n ) //====================================
  { // cycle up to n  or until gotten a wakeup from SleepCheck

    tnow = RTCGetTime( 0, 0 );   // get present time
    tmax = tnow + min_cyc_time;  // time to try next one
    
    if (dt>0) //-----------------------------------------------
    {  // it is assumed that it is in the water
       try_gps_sbd( 0 );  // try gps-iridium cycle
       Roll_Zero; // roll wing down
       Argos_On; 
       tnow = RTCGetTime( 0, 0 );  //  present time
       dt = tmax - tnow;   // #secs to wait to try next cycle
       if (dt<10) dt=10;  // wait at least 10 s
       awakened = sleep_check ( dt, PIT_IRQ2_RXD, FALSE);
    } 
    else  //---------------------------------------------------
    { // dt==0, land test only 
       cprintf("Will use stbd wing only for both GPS and SBD\n");
       ant_switch ( GPS_UNIT, STBD_WING );
       get_gps(  0 );  // get gps, 0=NO wing control
       all.klifo = assign_lifo(all.lifo, 0, 0); 
       lifo_dive_mark(); // 0902 add dive/profile/time marker
       lifo_gps( 0, 1); 
       ant_switch ( SBD_UNIT, STBD_WING );
       cprintf("sending the SBD...\n");
       sbd_surface( 0 ); // 0= NO wing control
    } //-------------------------------------------------------
    
  } //=================================================================
  
    go_lowpower( PIT_IRQ2_RXD );  // wait in low power mode
    Argos_Off; 
    cprintf("awakened    = %d\n", awakened          );
    cprintf("last nsent  = %d\n", all.sbd->nsent    );
    
  return;
} //***************************************************************************


//*****************************************************************************
//*****************************************************************************
void Transparent_ISU( void )  //Added special for updating Benthos firmware
{ //A Transparent path between Spray's serial COMM port and the
  //Benthos modem.  Quits when both ends are idle for COM_to seconds.
  //Assumes the LOCAL modem is powered up and leaves it on when done.
  short COM_to, ifecho;
  char c;
  unsigned long now,tl_com;
  TUPort    *tup;

  tup = all.tu_port[TU_SAT].tup;  // tpu uart port pointer for ACM/ADP
  
  /*acm_off();
  printf("Power Up ");fflush(stdout);
  err=acm_Power_Up(); //make sure LOC is powered up
  if (err>=0)
    printf("OK\n");
  else 
  { printf("Err=%d\n",err);
    return;
  }*/
 
  SerInFlush();  //flush Spray COMM input buffer
  printf("Idle channel timeout (seconds)? ");fflush(stdout);
  scanf("%d",&COM_to);
  printf("Local echo of Spray output (y/n)? ");fflush(stdout);
  ifecho=YesNo();

 
  TURxFlush  ( tup );   // flush the tpu port input buffer
  SerInFlush();  //flush Spray COMM input buffer
  
  //transfer bytes in both directions until neither end has transmitted
  //for tl_com seconds
  now=tl_com=RTCGetTime(0,0);
  while( (short)(now-tl_com) <= COM_to )
  { if( SCIRxQueuedCount() )
    { //xfer byte waiting at Spray COMM port to AC modem
      c = (char)SCIRxGetChar();
      TUTxPutByte ( tup, c, 0);   
      if(ifecho)SCITxPutChar(c);  //provide local echo
      tl_com=RTCGetTime(0,0);  //secs of last char from COMM
    }
   
    if( TURxQueuedCount(tup) )
    { //xferbyte waiting at AC modem to Spray COMM port
	    c = (char)TURxGetByte(tup,FALSE);  	//read in character
	    SCITxPutChar(c);
      tl_com=RTCGetTime(0,0);  //secs of last char from modem
    }
    
    now=RTCGetTime(0,0); 
  }
  printf("Channel has been Idle for %d seconds\n",COM_to);
  
  return;
}  //end Transparen
//*****************************************************************************
void menu_sbd(void);
//*****************************************************************************
void  test_sbd  (   void  )  
{ // test all of the Iridium SBD functions
  char ch=' ';
  short pwr_on, n, tmo=0;
  TUPort    *tup;
  
  tup = all.tu_port[TU_SAT].tup;  // correct tpu uart port pointer

  cprintf("              Test of Iridium SBD : %s \n", __DATE__);
  
  sbd_setup (  ); // initialize the timing parameters
  
  menu_sbd();
  while ( ch !='Q') //=======================================================
  {
	SerInFlush();  // flush any characters

        if (ch !=' ' && ch>0 ) 
            cprintf("I_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_sbd(); break;
        case  -1 :  break; // wait for another character
	    case '+' :  toggle_verbose(); // toggle verbose mode
				    break;


		case 'A' :   // get the antenna status
			if (!pwr_on) pwr_on = sbd_power_on(  );
		    n = sat_signal( tup ); 
			cprintf("Satellite strength = %d ",n);
			if (n>-1) cprintf("OK\n");
			else cprintf("ERROR\n");
			break;

		case 'G' :   // get the general status
		    n = sbd_status(  ); 
			cprintf("Send Status = ");
			if (n<2) cprintf("OK\n");
			else cprintf("ERROR\n");
			break;


		case 'I' : // get the IMEI & model #; 
			if (!pwr_on) pwr_on = sbd_power_on(  );
			get_IMEI( tup );
			break;	
	
		case 'S' : // get the stack pointer 
			lifo_surface(  );
			break;	
	
		case 'O' : // turn off power
			cprintf("Iridium is now turning off\n");
			sbd_off(  ); 
			pwr_on = 0; // is now off
			break;  

		case 'T' : // surface comms test
			cprintf("Iridium is now turning off\n");
			try_cycle (  ); 
			break;  

		case 'W' : // turn on power and initialize
			cprintf("Powering up Iridium\n");
			// pwr_on = sbd_on(  ); 
			pwr_on = sbd_power_on(  ); //do the full power cycle
			cprintf("Status = ");
			if (pwr_on) cprintf("OK\n");
			else        cprintf("BAD\n");
			break;

		case '0' : // initialize and save in SBD eeprom; 
			if (!pwr_on) pwr_on = sbd_power_on(  );
			sbd_init0( tup );
			break;	

		case 'X' : // display all shore commands
			n = test_shore_cmd( );
			cprintf("shore_cmd_err = %d\n", n);
			break;
		case '1' : // display all shore commands
			Transparent_ISU();
			break;                    

        default  : cprintf(" input unknown \n");
    } // end switch +++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
  }  //=== end while ========================================================
   sbd_off(  );  // make sure iridium is off
   cprintf("Iridium is now off\n");

   return;
}  //**************************************************************************

void menu_sbd(void) //********************************************************
{ //print out menu selections 
 cprintf("               Iridium SBD Menu\n"
 		 "Q.uit SBD test  :  U.pdate menu \n" //  :   D.ebug tests \n"
         "G.et SBD status :  O.ff SBD       :   W.akeup SBD  \n"
         //"X. Send Shore Command Test        :   A.ntenna strength\n"
         "T.est GPS/SBD surface try         :   I.MEI #   A.ntenna strength\n"  
         "0.initial setup :  S.tack pointer\n" );

 return;
} //***************************************************************************

//*** end *********************************************************************