/******************************************************************************/
/** Copyright 2007 MBARI                                                      */
/******************************************************************************/
/******************************************************************************/
/** Filename : SAMPLER.C                                                      */
/** Author   : Luke Coletti                                                   */
/** Project  : ISUS_ARGO                                                      */
/** Version  : 1.00                                                           */
/** Created  : 04/09/07                                                       */
/** Compiler : Mix Power C ver 2.2.0                                          */
/** Ext_Libs : MarshallSoft PCL4C Comms Lib v 6.2                             */
/** Archived :                                                                */
/** Summary  : Program to initiate an ISUS Sample Cycle at a specified rate:  */
/**            0) Retrieve ISUS Configuration Data (C command)                */
/**            1) Wake ISUS (W command)                                       */
/**            2) Send CTD values to ISUS (CTD command)                       */
/**            3) Initiate Sample Collection (TS command)                     */
/**            4) Retrieve Sample Data (SL command)                           */
/**            5) Put ISUS to Sleep (SLP command)                             */
/**            6) Do it again...                                              */
/******************************************************************************/
/** Modification History:                                                     */
/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <conio.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <sys\types.h>
#include <sys\timeb.h>
#include <pcl4c.h>
#include <userio.h>


#define TRUE                1
#define FALSE               0
#define OK                  0
#define ERROR               (-1)
#define TIMEOUT             (-2)

#define CTRL_C              0x03

#define CMD_ACK_TIMEOUT     2       //seconds
#define CTD_PROMPT_TIMEOUT  2       //seconds
#define CTD_TS_DATA_TIMEOUT 45      //seconds   TSWAIT cmd affects duration of TS, default is 8 Dana sets this to 20. Then there is the time the DAQ actually takes, so, it's roughly TSWAIT+5
#define ISUS_TS_DAT_TIMEOUT 25      //seconds   15 is typical, added some for testing

#define SBE41CP_CTD_DATA_WITH_PRESSURE_DATA             1

#define COLLECT_SECOND_SAMPLE_WITH_PUMP_ON              1
#define PUMP_ON                                         1
#define PUMP_OFF                                        0

typedef unsigned char       uchar;
typedef unsigned short      ushort;
typedef unsigned int        unsint;
typedef unsigned long       ulong;

/*** Global Variables ***/
char *UartString[4] = {"8250/16450", "16550", "16650", "16750"};
char *BaudRate[10] =  {"0","300","1200","2400","4800","9600",
                       "19200","38400","57600","115200"};

char APF_RxBuffer[1024+16];
char APF_TxBuffer[512+16];

char CTD_RxBuffer[1024+16];
char CTD_TxBuffer[512+16];

int  APF_port;
int  CTD_port;

/* ISUS Command prototypes */
int    WakeUpIsus(int port);int    SetIsusMode(int port);
int    SendCtdValsToIsus(int port, time_t e, float t, float s, float p);
int    TakeIsusSample(int port);
int    GetIsusSampleData(int port, char *sbuf, ushort buflen);
int    GetIsusConfigData(int port, FILE *fptr);
int    ConfirmCommandMode(int port);
int    PutIsusToSleep(int port);

/* CTD Command prototypes */
int    WakeUpCtd(int port);
int    GetCtdSampleData(int port, char *sbuf, ushort buflen);
int    ParseCtdSampleData(char *sbuf, time_t *e, float *t, float *s, float *p, int datafmt);
int    ToggleCtdPump(int port, ushort state);

/* Serial I/O prototypes */
int    SerGetcTmout(int port, ushort secs);
int    SerGetsTmout(int port, char *buf, ushort buflen, ushort secs);
int    SerPuts(int port, char *str);
long   msSleep(long ms);
long   msStopWatch(long ms);
void   InitCommPort(int port, int baud);
int    ErrorCheck(int code);
int    BaudMatch(char *);
int    breakhandler(void);

/* main */
void main(int argc, char *argv[])
{
char    rbuf[1024];
int     APF_baud;           /* baud rate code ( index into BaudRate[] ) */
int     CTD_baud;
int     SampRate;
int     inChar;
int     ret;
ulong   ctr;
time_t  current_time, last_sample, wake_time, ctd_time;
float   ctd_temp, ctd_salinity, ctd_pressure;
FILE    *apf_dat, *apf2_dat, *apf_log;

    if( argc != 6 ){
      printf("Usage: SAMP_CF2 <APF port> <APF baud> <CTD port> <CTD baud> <samp_rate_mins>\n");
      exit(1);
      }

    /* get port number from command line */
    APF_port = atoi(argv[1]) - 1;
    if( (APF_port<COM1) || (APF_port>COM20) ){
      printf("Error, APF CommPort Range = [1,20]\n");
      exit(1);
      }

    /* get baud rate from command line */
    APF_baud = BaudMatch(argv[2]);
    if( APF_baud < 0 ){
      printf("Error, unrecognized APF baud rate: %s\n",argv[2]);
      exit(1);
      }

    /* get port number from command line */
    CTD_port = atoi(argv[3]);
    if( CTD_port > 0 ){
      CTD_port = CTD_port - 1;
      if( (CTD_port<COM1) || (CTD_port>COM20) ){
        printf("Error, CTD CommPort Range = [1,20]\n");
        exit(1);
        }
      }
    else
      CTD_port = -1;

    /* get baud rate from command line */
    if( CTD_port != -1 ){
      CTD_baud = atoi(argv[4]);
      if( CTD_baud != -1 ){
        CTD_baud = BaudMatch(argv[4]);
        if( CTD_baud < 0 ){
          printf("Error, unrecognized CTD baud rate: %s\n",argv[4]);
          exit(1);
          }
        }
      }

   if( APF_port == CTD_port ){
     printf("Error, Port Numbers can't be the same!\n");
     exit(1);
     }

    /* get sample collection rate from command line */
    SampRate = atoi(argv[5]);
    if( (SampRate<=0) || (SampRate>=120) ){
      printf("Error, Sample Rate Range = [1,120] minutes\n");
      exit(1);
      }

    ctrlbrk(breakhandler);

    InitCommPort(APF_port, APF_baud);

    if( CTD_port != -1 )
      InitCommPort(CTD_port, CTD_baud);

    printf("\n***Checking for PC Log Files***\n");

    if( (apf_log = fopen("apf.log", "r")) != NULL ){
      fclose(apf_dat);
      if( QueryYesNo("The APF.LOG LogFile was found, REMOVE", FALSE) ){
        remove("apf.log");
        printf("\n");
        }
      else
        printf("\n");
      }

    if( (apf_dat = fopen("apf.dat", "r")) != NULL ){
      fclose(apf_dat);
      if( QueryYesNo("The APF.DAT LogFile was found, REMOVE", FALSE) ){
        remove("apf.dat");
        printf("\n");
        }
      else
        printf("\n");
      }

#ifdef COLLECT_SECOND_SAMPLE_WITH_PUMP_ON

    if( (apf2_dat = fopen("apf2.dat", "r")) != NULL ){
      fclose(apf_dat);
      if( QueryYesNo("The APF2.DAT LogFile was found, REMOVE", FALSE) ){
        remove("apf2.dat");
        printf("\n");
        }
      else
        printf("\n");
      }

#endif

    printf("\n***Getting ISUS Configuration Info***\n");

    if( (ret=WakeUpIsus(APF_port)) == TRUE ){
      if( (apf_dat = fopen("apf.dat", "a+")) == NULL ){
        printf("ERROR Opening Local Data File, exiting!\n");
        if( CTD_port != -1 )
          SioDone(CTD_port);
        SioDone(APF_port);
        exit(1);
        }
      else{
        ret=GetIsusConfigData(APF_port, apf_dat);
        fclose(apf_dat);
        if( ret > 0 )
          printf("\n%d Configuration Records Received\n", ret);
        else
          printf("\nERROR Getting ISUS Config Data, ret = %d\n", ret);
        }
      }
    else{
      printf("ERROR Waking ISUS, ret = %d, exiting!\n", ret);
      if( CTD_port != -1 )
        SioDone(CTD_port);
      SioDone(APF_port);
      exit(1);
      }

    printf("\n***Entering sample loop ( Type ^Z to exit )***\n\n");

    ctr = 0;
    time( &current_time );
    wake_time = current_time;   // take a sample first thing...

    while( TRUE ){

      /* time to take a sample yet? */
      time( &current_time );
      if( difftime(wake_time, current_time) <= 0.0 ){
        wake_time = current_time + (time_t)(SampRate * 60L);  //next wake time
        apf_log = fopen("apf.log", "a+");
        apf_dat = fopen("apf.dat", "a+");
#ifdef COLLECT_SECOND_SAMPLE_WITH_PUMP_ON
        apf2_dat = fopen("apf2.dat", "a+");
#endif
        ++ctr;

        printf("%03lu, Waking ISUS, %s", ctr, ctime(&current_time) );
        if( apf_log != NULL )
          fprintf(apf_log, "%03lu, Waking ISUS, %s", ctr, ctime(&current_time) );

        if( WakeUpIsus(APF_port) == TRUE ){
          time( &current_time );
          printf("%03lu, ISUS Wakeup OK, %s", ctr, ctime(&current_time) );
          if( apf_log != NULL )
            fprintf(apf_log, "%03lu, ISUS Wakeup OK, %s", ctr, ctime(&current_time) );

          if( CTD_port != -1 ){

            time( &current_time );
            printf("%03lu, Sampling CTD, %s", ctr, ctime(&current_time) );

            if( GetCtdSampleData(CTD_port, &rbuf, sizeof(rbuf)) == TRUE ){
              time( &current_time );
              printf("%03lu, Get  CtdDat OK, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, Get  CtdDat OK, %s", ctr, ctime(&current_time) );

              if( ParseCtdSampleData(&rbuf, &ctd_time, &ctd_temp, &ctd_salinity, &ctd_pressure, SBE41CP_CTD_DATA_WITH_PRESSURE_DATA) == TRUE ){
                time( &current_time );
                printf("%03lu, ParseCtdDat OK, %.3f, %.4f, %.4f, %s", ctr, ctd_pressure, ctd_temp, ctd_salinity, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, ParseCtdDat OK, %.3f, %.4f, %.4f, %s", ctr, ctd_pressure, ctd_temp, ctd_salinity, ctime(&current_time) );

                if( SendCtdValsToIsus(APF_port, ctd_time, ctd_temp, ctd_salinity, ctd_pressure) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Send CtdDat OK, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Send CtdDat OK, %s", ctr, ctime(&current_time) );
                  }
                else{
                  time( &current_time );
                  printf("%03lu, Send CtdDat ERROR, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Send CtdDat ERROR, %s", ctr, ctime(&current_time) );
                  }
                } // end Parse if

              else{
                time( &current_time );
                printf("%03lu, ParseCtdDat ERROR, rbuf= %s, %s", ctr, rbuf, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, ParseCtdDat ERROR, %s", ctr, ctime(&current_time) );
                }
              } // end Get if

            else{
              time( &current_time );
              printf("%03lu, Get  CtdDat ERROR, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, Get  CtdDat ERROR, %s", ctr, ctime(&current_time) );
              }
            } // end CTD_port if

            time( &current_time );
            printf("%03lu, Sampling ISUS, %s", ctr, ctime(&current_time) );

            if( TakeIsusSample(APF_port) == TRUE ){
              time( &current_time );
              printf("%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );

              if( GetIsusSampleData(APF_port, &rbuf, sizeof(rbuf)) == TRUE ){
                time( &current_time );
                printf("%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                printf("%03lu, %s\n", ctr, rbuf);
                if( apf_dat != NULL ){
                  fprintf(apf_dat, "%s\n", rbuf);
                  fclose(apf_dat);
                  }
                }
              else{
                time( &current_time );
                printf("%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                }

#ifndef COLLECT_SECOND_SAMPLE_WITH_PUMP_ON

              if( PutIsusToSleep(APF_port) == TRUE ){
                time( &current_time );
                printf("%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
                }
              else{
                time( &current_time );
                printf("%03lu, Enter Sleep ERROR, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, Enter Sleep ERROR, %s", ctr, ctime(&current_time) );
                }
#endif

              } // end TakeSample if
            else{
              time( &current_time );
              printf("%03lu, Take Sample ERROR, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, Take Sample ERROR, %s", ctr, ctime(&current_time) );
              }

#ifdef COLLECT_SECOND_SAMPLE_WITH_PUMP_ON

          if( CTD_port != -1 ){
            if( ToggleCtdPump(CTD_port, PUMP_ON) == TRUE ){
              time( &current_time );
              printf("%03lu, CtdPump ON OK, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, CtdPump ON OK, %s", ctr, ctime(&current_time) );

              time( &current_time );
              printf("%03lu, Sampling ISUS, %s", ctr, ctime(&current_time) );

              if( TakeIsusSample(APF_port) == TRUE ){
                time( &current_time );
                printf("%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );

                if( GetIsusSampleData(APF_port, &rbuf, sizeof(rbuf)) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                  printf("%03lu, %s\n", ctr, rbuf);
                  if( apf2_dat != NULL ){
                    fprintf(apf2_dat, "%s\n", rbuf);
                    fclose(apf2_dat);
                    }
                  }
                else{
                  time( &current_time );
                  printf("%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                  }

                if( PutIsusToSleep(APF_port) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
                  }
                else{
                  time( &current_time );
                  printf("%03lu, Enter Sleep ERROR, %s", ctr, ctime(&current_time) );
                  if( apf_log != NULL )
                    fprintf(apf_log, "%03lu, Enter Sleep ERROR, %s", ctr, ctime(&current_time) );
                  }

                } // end TakeSample if

              if( ToggleCtdPump(CTD_port, PUMP_OFF) == TRUE ){
                time( &current_time );
                printf("%03lu, CtdPump OFF OK, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, CtdPump OFF OK, %s", ctr, ctime(&current_time) );
                }
               else{
                time( &current_time );
                printf("%03lu, CtdPump OFF ERROR, %s", ctr, ctime(&current_time) );
                if( apf_log != NULL )
                  fprintf(apf_log, "%03lu, CtdPump OFF ERROR, %s", ctr, ctime(&current_time) );
                }

              } // end ToggleCtdPump if

            else{
              time( &current_time );
              printf("%03lu, CtdPump ON ERROR, %s", ctr, ctime(&current_time) );
              if( apf_log != NULL )
                fprintf(apf_log, "%03lu, CtdPump ON ERROR, %s", ctr, ctime(&current_time) );
              }

            } // end CTD_PORT != -1

#endif
          } // end WakeUp if
        else{
          time( &current_time );
          printf("%03lu, ISUS Wakeup ERROR, %s", ctr, ctime(&current_time) );
          if( apf_log != NULL )
            fprintf(apf_log, "%03lu, ISUS Wakeup ERROR, %s", ctr, ctime(&current_time) );
          }

        printf("%03lu, Next Sample, %s\n", ctr, ctime(&wake_time) );
        if( apf_log != NULL ){
          fprintf(apf_log, "%03lu, Next Sample, %s\n", ctr, ctime(&wake_time) );
          fclose(apf_log);
          }

        } //end difftime if

      /* any incoming chars from the keyboard ? */
      if( kbhit() ){
        inChar = getch();
        if( (char)inChar == 0x1a ){
          if( CTD_port != -1 )
            SioDone(CTD_port);
          SioDone(APF_port);
          exit(1);
          }
        else{
          SioPutc(APF_port, (char)inChar);
          }
        } /* end if */

      /* any incoming chars from the serial port ? */
      if( (inChar = SioGetc(APF_port,0)) > -1 )
        putch( (char)inChar );

    } /* end while */

} /* end main */


/* ISUS Command prototypes */

int WakeUpIsus(int port)
{
char rbuf[32];
short i;

    SioRxClear(port);

    SioBrkSig(port, 'A');     //send a 0.1 sec BREAK
    msSleep(0);
    msSleep(100);
    SioBrkSig(port, 'C');

    for(i = 10; i; i--){

      SioPutc(port, 'W');

      if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
        if( strstr(rbuf, "ACK") != NULL ){
          SioRxClear(port);
          SetIsusMode(port);
          SioRxClear(port);
          return( TRUE );
          }
        else if( strchr(rbuf, '>') != NULL ){
          printf("\nISUS is in MENU MODE, sending a CTRL_C\n");
          SioPutc(port, (int)CTRL_C);
          SioRxClear(port);
          continue;
          }
        else{
          SioRxClear(port);
          continue;
          }
        }
      else
        SioRxClear(port);
      }

    return( TIMEOUT );

}

int SetIsusMode(int port)
{
char rbuf[32];

    SioRxClear(port);

    SerPuts(port, "MODE,2");

    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      if( strstr(rbuf, "ACK,MODE,2") != NULL ){
         SerPuts(port, "ACK\n");
         return( TRUE );
        }
      else
        return( ERROR );
      }
    else
      return( TIMEOUT );

}

int SendCtdValsToIsus(int port, time_t e, float t, float s, float p)
{
char rbuf[128];
char tbuf[128];
char *srchptr, *endptr;
int    i, gotVal;
time_t CTD_Time;
float  CTD_Temp, CTD_Salinity, CTD_Depth;

    ConfirmCommandMode(port);

    errno = 0;

    SioRxClear(port);

    sprintf(tbuf, "CTD,%lu,%.4f,%.4f,%.2f", e, t, s, p);

    SerPuts(port, tbuf);

    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){

      if( (srchptr=strstr(rbuf, "CTD,")) != NULL ){

        i = gotVal = 0;
        srchptr = strtok(srchptr, ",");
        while( (srchptr = strtok(NULL, ",")) != NULL ){
          ++i;
          if(i == 1){
            if(strchr(srchptr, '-') != NULL){
              printf("NAK,CTD,ESignErr: %s\n", srchptr);
              break;
              }
            CTD_Time = strtoul(srchptr, NULL, 10);
            //printf("\n srchptr = %p endptr = %p\n", srchptr, endptr);
            if( errno == ERANGE ){
              printf("NAK,CTD,EOverflowErr: %s\n", srchptr);
              break;
              }
            else if( CTD_Time == 0 ){
              printf("NAK,CTD,EConvertErr: %s\n", srchptr);
              break;
              }
            else if( CTD_Time != e ){
              printf("NAK,CTD,EMatchErr %lu, %s\n", e, srchptr);
              break;
              }
            else
              ++gotVal;
            }
          else if(i == 2){
            CTD_Temp = (float)strtod(srchptr, &endptr);
            if( errno == ERANGE ){
              printf("NAK,CTD,TOverflowErr: %s\n", srchptr);
              break;
              }
            else if( (CTD_Temp == 0.0) && (endptr == srchptr) ){
              printf("NAK,CTD,TConvertErr: %s\n", srchptr);
              break;
              }
            else if( CTD_Temp != t ){
              printf("NAK,CTD,TMatchErr %f, %s\n", t, srchptr);
              break;
              }
            else
              ++gotVal;
            }
          else if(i == 3){
            CTD_Salinity = (float)strtod(srchptr, &endptr);
            if( errno == ERANGE ){
              printf("NAK,CTD,SOverflowErr: %s\n", srchptr);
              break;
              }
            else if( (CTD_Salinity == 0.0) && (endptr == srchptr) ){
              printf("NAK,CTD,SConvertErr: %s\n", srchptr);
              break;
              }
            else if( CTD_Salinity != s ){
              printf("NAK,CTD,SMatchErr %f, %s\n", s, srchptr);
              break;
              }
            else
              ++gotVal;
            }
          else if(i == 4){
            CTD_Depth = (float)strtod(srchptr, &endptr);
            if( errno == ERANGE ){
              printf("NAK,CTD,POverflowErr: %s\n", srchptr);
              break;
              }
            else if( (CTD_Depth == 0.0) && (endptr == srchptr) ){
              printf("NAK,CTD,PConvertErr: %s\n", srchptr);
              break;
              }
            else if( fabs(CTD_Depth - p) > 0.5 ){
              printf("NAK,CTD,PMatchErr %f, %s\n", p, srchptr);
              break;
              }
            else
              ++gotVal;
            }
          else
            break;
          } //end strtok while

         if( gotVal == 4 ){
           SerPuts(port, "ACK\n");
           return( TRUE );
           }
         else{
           SerPuts(port, "NAK\n");
           return( FALSE );
           }

        } // end strstr() if
      else
        return( ERROR );

      } // end SerGetsTmout() if
    else
      return( TIMEOUT );

}


int TakeIsusSample(int port)
{
char rbuf[32];

    ConfirmCommandMode(port);

    SioRxClear(port);

    SerPuts(port, "TS");

    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      if( strstr(rbuf, "ACK,TS,CMD") != NULL ){
        SioRxClear(port);
        if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)ISUS_TS_DAT_TIMEOUT ) > 0 ){
          if( strstr(rbuf, "ACK,TS,DAT") != NULL )
            return( TRUE );
          else if( strstr(rbuf, "NAK,TS,DAT") != NULL )
            return( FALSE );
          else
            return( ERROR );
          }
        else
          return( TIMEOUT );
        }
      else
        return( ERROR );
      }
    else
      return( TIMEOUT );

}


int GetIsusSampleData(int port, char *sbuf, ushort buflen)
{

    ConfirmCommandMode(port);

    SioRxClear(port);

    SerPuts(port, "SL");

    if( SerGetsTmout(port, sbuf, buflen, (ushort)CMD_ACK_TIMEOUT) > 0 ){
      if( strstr(sbuf, "NAK,SL") != NULL )
        return( FALSE );
      else
        return( TRUE );
      }
    else
      return( TIMEOUT );

}


int GetIsusConfigData(int port, FILE *fptr)
{
char   rbuf[128];
int    ctr;

    ConfirmCommandMode(port);

    ctr = 0;

    SioRxClear(port);

    SioPutc(port, 'C');

    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      if( strstr(rbuf, "NAK") != NULL )
        return( ERROR );
      else
        fprintf(fptr, "%s\n", rbuf);
      while( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
        fprintf(fptr, "%s\n", rbuf);
        ++ctr;
        }
      return( ctr );
      }
    else
      return( TIMEOUT );

}


int ConfirmCommandMode(int port)
{
char rbuf[32];
short i;

    SioRxClear(port);

    for(i = 10; i; i--){

      SioPutc(port, 'W');

      if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
        if( strstr(rbuf, "ACK") != NULL ){
          SioRxClear(port);
          return( TRUE );
          }
        else if( strchr(rbuf, '>') != NULL ){
          printf("\nISUS is in MENU MODE, sending a CTRL_C\n");
          SioPutc(port, (int)CTRL_C);
          SioRxClear(port);
          continue;
          }
        else{
          SioRxClear(port);
          continue;
          }
        }
      else
        SioRxClear(port);
      }

    return( TIMEOUT );

}


int PutIsusToSleep(int port)
{
char rbuf[32];
short i;

    SioRxClear(port);

    for(i = 10; i; i--){

      SerPuts(port, "SLP");

      if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
        if( strstr(rbuf, "ACK,SLP") != NULL ){
          SioRxClear(port);
          return( TRUE );
          }
        else if( strchr(rbuf, '>') != NULL ){
          printf("\nISUS is in MENU MODE, sending a CTRL_C\n");
          SioPutc(port, (int)CTRL_C);
          SioRxClear(port);
          continue;
          }
        else{
          SioRxClear(port);
          continue;
          }
        }
      else
        SioRxClear(port);
      }

    return( TIMEOUT );

}

/* CTD Command prototypes */

int WakeUpCtd(int port)
{
#define NCHARS 30
char c;
int  i, j;

    SioRTS(port,'C');   //Put CTD into Command Mode, clear CTD Wakeup Line
    msSleep(0);
    msSleep(1000);

    //CTD should now be in Command Mode

    SioRxClear(port);

    for(i = 10; i; i--){

      SioPutc(port, '\r');
      msSleep(0);
      msSleep(250);

      for (j = NCHARS; j && ((c = SerGetcTmout(port, (ushort)CTD_PROMPT_TIMEOUT)) != ERROR); j--){
        if( c == '>' ){
          SioRxClear(port);
          return( TRUE );
          }
        }
      }

    SioRTS(port,'S');   //Take CTD out of Command Mode, set CTD Wakeup Line

    return( TIMEOUT );                  /* loop finished = TIMEOUT */

}

int GetCtdSampleData(int port, char *sbuf, ushort buflen)
{
ushort nchars;

    // Get the CTD prompt
    if( WakeUpCtd(port) != TRUE )
      return( ERROR );

    // Send Take Sample command
    SerPuts(port, "pts\r");

    // If pts command will be echoed collect the real CTD data on the 2nd read
    if( SerGetsTmout(port, sbuf, buflen, (ushort)CTD_TS_DATA_TIMEOUT) > 0 ){
      //printf("\nTS command1 = %s\n", sbuf);
      if( strstr(sbuf, "pts") != NULL ){
        SerGetsTmout(port, sbuf, buflen, (ushort)CTD_TS_DATA_TIMEOUT);
        //printf("\nTS command2 = %s\n", sbuf);
        }
      msSleep(0);
      msSleep(50);
      SerPuts(port, "QS\r");
      msSleep(0);
      msSleep(50);
      SioRTS(port,'S'); //Take CTD out of Command Mode, set CTD Wakeup Line
      return( TRUE );
      }
    else
      return( TIMEOUT );

}

int ParseCtdSampleData(char *sbuf, time_t *e, float *t, float *s, float *p, int datafmt)
{

    //printf("\n Got Here p1 input string = %s\n", sbuf);

    if(datafmt == SBE41CP_CTD_DATA_WITH_PRESSURE_DATA){
      if(sscanf(sbuf, "%f, %f, %f", p, t, s) != 3)
        return( ERROR );
      }
    else
      return( ERROR );

    //printf("\n Got Here p2, p=%.3f t=%.4f s=%.4f\n", *p, *t, *s);

    time(e);

    return( TRUE );

}

int ToggleCtdPump(int port, ushort state)
{

    // Get the CTD prompt
    if( WakeUpCtd(port) != TRUE )
      return( ERROR );

    if(state == PUMP_ON){
      SerPuts(port, "pumpon\r");
      return( TRUE );
      }
    else if(state == PUMP_OFF){
      SerPuts(port, "pumpoff\r");
      msSleep(0);
      msSleep(50);
      SerPuts(port, "QS\r");
      msSleep(0);
      msSleep(50);
      SioRTS(port,'S'); //Take CTD out of Command Mode, set CTD Wakeup Line
      return( TRUE );
      }
    else
      return( ERROR );


}

/* Serial I/O prototypes */

int SerGetcTmout(int port, ushort secs)
{

    msStopWatch(0);

    while( msStopWatch(1) < (long)(secs*1000) ){
      if ( SioRxQue(port) )
        return( SioGetc(port, 0) );
      }

    return( ERROR );

}


int SerGetsTmout(int port, char *buf, ushort buflen, ushort secs)
{
register int   c;
register int   nchars;

    msStopWatch(0);

    nchars = 0;
    buf[0] = '\0';

    while( msStopWatch(1) < (long)(secs*1000) ){
      if ( SioRxQue(port) ){
        switch( c = SioGetc(port, 0) ){
          case '\n':
          case '\r':
            if(nchars > 0)
              return( nchars );
            else
              break;

          default:
            buf[nchars++] = (char)c;
            buf[nchars] = '\0';
            if ( nchars >= (buflen-1) )
              return( nchars );
            break;
          } // end switch
        } // end if
      }  // end while

    if( nchars > 0 )
      return( nchars );
    else
      return( ERROR );

}


int SerPuts(int port, char *str)
{

    while( *str ){
      if (*str == '\n')
         SioPutc(port, '\r');
       SioPutc(port, *str++);
      }

    /* wait for Transmit Buffer to empty before returning */
    while( SioTxQue(port) != 0 ){
      continue;
      }

    return( TRUE );

}


long msStopWatch(long ms)
{
static struct timeb start, finish;
register long  deltasecs, deltamsecs;

    if( ms == 0 ){
      ftime(&start);
      return( 0 );
      }
    else{
      ftime(&finish);

      deltasecs = (long)(finish.time - start.time);

      deltamsecs = (long)((long)finish.millitm - (long)start.millitm);

      if( deltamsecs < 0 ){
        if( deltasecs != 0 )
          deltasecs--;
        deltamsecs += 1000L;
        }

      deltamsecs = deltamsecs + (deltasecs * 1000L);

      return( deltamsecs );
      }

}

long msSleep(long ms)
{
static struct timeb start, finish;
register long  deltasecs, deltamsecs;
int   i;

    if( ms == 0 ){
      ftime(&start);
      return( 0 );
      }
    else{
      i = 0;
      do{
        ftime(&finish);

        deltasecs = (long)(finish.time - start.time);

        deltamsecs = (long)((long)finish.millitm - (long)start.millitm);

        if( deltamsecs < 0 ){
          if( deltasecs != 0 )
            deltasecs--;
          deltamsecs += 1000L;
          }

        deltamsecs = deltamsecs + (deltasecs * 1000L);

        if( i == 0 ){
          if( deltamsecs > ms )
            return( -1 );       //we've already missed it!
          i = 1;
          }

        }while( deltamsecs < ms );                                                                                                                                                                                                                        \

      return( deltamsecs );
      }

}


void InitCommPort(int port, int baud)
{
char far *Ptr;
int  Seg;
int  Version;
int  i;

    Version = SioInfo('V');
    printf("Configuring Port #%d, PCL4C Version %d.%d\n\n", port+1, Version>>4, 0x0f&Version);

    if( port == APF_port ){
      /* setup 1024 byte receive buffer */
      Ptr = (char far *)APF_RxBuffer;
      Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
      ErrorCheck( SioRxBuf(port,Seg,Size1024) );

      /* setup 512 byte transmit buffer */
      Ptr = (char far *)APF_TxBuffer;
      Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
      ErrorCheck( SioTxBuf(port,Seg,Size512) );

      /* set port parmameters */
      ErrorCheck( SioParms(port,NoParity,OneStopBit,WordLength8) );

      /* reset the port */
      ErrorCheck( SioReset(port, baud) );

      /* set DTR and RTS */
      ErrorCheck( SioDTR(port,'S') );
      ErrorCheck( SioRTS(port,'S') );
      }
    else if( port == CTD_port ){
      /* setup 1024 byte receive buffer */
      Ptr = (char far *)CTD_RxBuffer;
      Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
      ErrorCheck( SioRxBuf(port,Seg,Size1024) );

      /* setup 512 byte transmit buffer */
      Ptr = (char far *)CTD_TxBuffer;
      Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
      ErrorCheck( SioTxBuf(port,Seg,Size512) );

      /* set port parmameters */
      ErrorCheck( SioParms(port,NoParity,OneStopBit,WordLength8) );

      /* reset the port */
      ErrorCheck( SioReset(port, baud) );

      /* set DTR and RTS */
      ErrorCheck( SioRTS(port,'S') ); //clear SBE41 Wakeup Line
      ErrorCheck( SioDTR(port,'S') ); //clear SBE41 Mode Control Line
      }


}

int ErrorCheck(int code)
{
    if(code<0){
      printf("ERROR %d:", code);
      SioError(code);
      if( CTD_port != -1 )
        SioDone(CTD_port);
      SioDone(APF_port);
      exit(1);
      }

    return( OK );
}


int BaudMatch(char *P)
{
int  i;

    /* find baud rate in table */
    for(i=0;i<10;i++) if(strcmp(BaudRate[i],P)==0) return(i);

    return(-1);
}

int breakhandler(void)
{
    SioPutc(APF_port, (int)CTRL_C);
    SioRxClear(APF_port);
    return(1);
}

