/******************************************************************************/
/** Copyright 2007 MBARI                                                      */
/******************************************************************************/
/******************************************************************************/
/** Filename : MSCSAMPLER.C                                                   */
/** Author   : Luke Coletti                                                   */
/** Project  : ISUS_ARGO                                                      */
/** Version  : 1.2                                                            */
/** Created  : 04/09/07                                                       */
/** Compiler : gcc version 7.4.0 (Rev1, Built by MSYS2 project)               */
/** Target   : i686-w64-mingw32 (32)                                          */
/** Ext_Libs : MarshallSoft Win32 WSC Version 6.0.1 (Build 1)                 */
/** Archived :                                                                */
/******************************************************************************/
/******************************************************************************/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <time.h>
#include <math.h>
#include <getopt.h>
#include <errno.h>
#include <sys\stat.h>
#include <sys\types.h>
#include <sys\timeb.h>

#include <wsc.h>
#include <keycode.h>

#include "sayerror.h"
#include "userio.h"

//---------------------------------------------------------
//
// Enable hardware flow control (USE_HARDWARE_FLOW_CONTROL)
// if and only if connected to a serial device with hardware
// flow control enabled..
//
// #define USE_HARDWARE_FLOW_CONTROL
//
//---------------------------------------------------------
//
// Enabling Overlapped I/O (USE_OVERLAPPED_IO) can improve
// application program performance. However, some virtual
// serial port drivers (such as some USB-RS232 converters)
// do not implement overlapped I/O.
//
// Overlapped I/O is disabled by default (WSC 5.4.1 & up).
//
// #define USE_OVERLAPPED_IO
//
//---------------------------------------------------------


#define FIRST_PORT 			COM1
#define LAST_PORT  			COM256

#define TRUE                1
#define FALSE               0
#define OK                  0
//#define ERROR               (-1)
#define TIMEOUT             (-2)
#define CTRL_C              0x03

#define	ISUS_MODE			1
#define DURA_MODE			2

#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 MSC_TS_DAT_TIMEOUT  25      //seconds   15 is typical, added some for testing

#define PUMP_ON          	1
#define PUMP_OFF           	0
#define SBE41CP_CTD_DATA_WITH_PRESSURE_DATA             1

typedef unsigned char       uchar;
typedef unsigned short      ushort;
typedef unsigned int        unsint;
typedef unsigned long       ulong;

/*** Global Variables ***/
static char LiveGraphHeader[]	 	= "#ALL RECORDS";
static char	LiveGraphIsusFields[] 	= "CRC, ID, DATE TIME, UTC SECS, CTD DEPTH, CTD TEMP, CTD SALINITY, SAMPLE COUNTER, POR COUNTER, ISUS_ERROR COUNTER, SYS_ERROR COUNTER, HOUSING TEMPERATURE, HOUSING HUMIDITY, INPUT VOLTAGE, INPUT CURRENT, MAX LAMP INTEN, MIN LAMP INTEN, DC MEAN, DC STDDEV, ISUS SALINITY, ISUS NITRATE, FIT ERROR, DAT PIXEL BEG, DAT PIXEL END, PACKED HEX DATA, SW DC";
static char	LiveGraphDuraFields[] 	= "CRC, ID, DATE TIME, UTC SECS, CTD DEPTH, CTD TEMP, CTD SALINITY, SAMPLE COUNTER, POR COUNTER, DURA_ERROR COUNTER, HOUSING TEMPERATURE, HOUSING HUMIDITY, INPUT VOLTAGE, INPUT CURRENT, FOOBAR PH VALUE, BACKUP BATTERY, VRS VOLTS, VRS STDDEV, VK VOLTS, VK STDDEV, IK AMPS, IB AMPS";
static char *BaudRate[10] 			= {"0","300","1200","2400","4800","9600","19200","38400","57600","115200"};

int  	MSC_port;

char 	*MscMode[3] =  {"NULL","ISUS","DURA"};
char   	fnbuf1[128];
char   	fnbuf2[128];
char   	fnbuf3[128];
char    rbuf[1024];
char	timebuf[64];

int     MSC_baud;           /* baud rate determined via initial index into BaudRate[] */
int  	CTD_port;		
int     CTD_baud;
int		MSC_syncmin;
ushort	MSC_mode;
ushort  MSC_samprate;
ushort  MSC_secondsample;
ushort  MSC_sernum;

int     inChar;
int     opt, ret;
int 	Port, Code, CountOK, CountERR; 		//used for port lister option -l
ulong   ctr, input_var;

time_t  current_time, wake_time, ctd_time;
time_t 	msc_time, pc_time;
float   ctd_temp, ctd_salinity, ctd_pressure;
float	user_temp, user_salinity, float_var;

struct  tm *tp;
struct 	stat statbuf;
FILE    *msc_log, *msc_dat, *msc2_dat;

HANDLE  hTimer  = NULL;
HANDLE  hThread = NULL;

/* Sampler prototypes */
void	MscInteractiveMode(void);
void    MscCollectSample(void);
void 	MscGetSamplerParams(void);
void 	MscGetSetTime(void);
void	MscCheckPreviousLogFile(void);
void 	MscGetConfigInfo(void);

/* MSC Command prototypes */
int    	WakeUpMsc(int port, ushort mode);
int    	SetMscToIsusMode(int port);
int    	SetMscToDuraMode(int port);
int    	SendCtdValsToMsc(int port, time_t e, float t, float s, float p);
int    	TakeMscSample(int port);
int    	GetMscSampleData(int port, char *sbuf, ushort buflen);
int    	GetMscConfigData(int port, FILE *fptr);
int    	ConfirmMscCommandMode(int port);
int    	PutMscToSleep(int port);
time_t	GetMscTime(int port);
int		SetMscTime(int port);
int		SetMscRtcToPcTime(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);
void 	InitCommLib(void);
int    	BaudMatch(char *);
void   	ExitProgram(int ExitCode);
int    	ErrorCheck(int Port, int Code);

/* Windows API prototypes */
BOOL   	WINAPI BreakHandler(DWORD dwCtrlType);
DWORD 	WINAPI Timer( LPVOID lpParam );

/* Util prototypes */
int    	IsPrintable(char c);

//---------------------------------------------------------

//---------------------------------------------------------
int main(int argc, char *argv[])
{
    DWORD tid;
    DWORD dwExitCode;
    BOOL  imLoopin;
    int   Version, Build;
    
    // ADD SWITCH TO USE OVERLAPPING I/O
    
	while( (opt = getopt(argc, argv, "P:B:p:b:lv")) != -1 ){
		switch( opt ){

			case 'P':
			MSC_port = atoi(optarg) - 1;
			if( (MSC_port<COM1) || (MSC_port>COM20) ){
				printf("Error, MSC CommPort Range = [1,20]\n");
				exit(0);
			}	
			break;

			case 'p':
			if( (CTD_port = atoi(optarg)) == -1 )
				break;
			CTD_port = CTD_port - 1;
			if( (CTD_port<COM1) || (CTD_port>COM20) ){
				printf("Error, CTD CommPort Range = [1,20]\n");
				exit(0);
			}	
			break;

			case 'B':		
			MSC_baud = BaudMatch(optarg);
			if( MSC_baud < 0 ){
				printf("Error, unrecognized MSC baud rate: %s\n",argv[2]);
				exit(0);
			}
			MSC_baud = atoi(BaudRate[MSC_baud]);		
			break;

			case 'b':
			if( (CTD_baud = atoi(optarg)) == -1 )
				break;			
			CTD_baud = BaudMatch(optarg);
			if( CTD_baud < 0 ){
				printf("Error, unrecognized MSC baud rate: %s\n",argv[2]);
				exit(0);
			}
			CTD_baud = atoi(BaudRate[CTD_baud]);		
			break;
			
			case 'l':
			InitCommLib();
			CountOK = CountERR = 0;
			printf("\nChecking COM%1d through COM%1d...\n", 1+FIRST_PORT,1+LAST_PORT);
			for( Port=FIRST_PORT; Port<=LAST_PORT; Port++ ){ // reset the port
				Code = SioReset(Port,1024,1024);
				if( Code<0 ){ // error
					if( Code==WSC_IO_ERROR ){// port exists but not enabled
						printf("COM%1d: Port exists but not enabled (event I/O error %d)\n", 1+Port, Code);
						CountERR++;
					}
				continue; // no port
				}
				printf("COM%1d: OK, port exists\n", 1+Port); // found port
				CountOK++;
				SioDone(Port);
			} // end-for
			printf("\n%d port(s) found\n", CountOK);
			if( CountERR>0 )
				printf("%d 'not ready' port(s) found (virtual port not ready?)\n", CountERR);
			ExitProgram(0);
			break;

			case 'v':
			Version = SioInfo('V');
			Build   = SioInfo('B');

			printf("\nBuild: %s Date: %s %s\n\n", __FILE__ , __DATE__ , __TIME__);
			printf("GCC  version %d.%d.%d ", __GNUC__ , __GNUC_MINOR__ , __GNUC_PATCHLEVEL__ );
			#ifdef _WIN64
				printf("(Win64 - x86_64-w64-mingw32)\n");
			#else			
				printf("(Win32 - i686-w64-mingw32)\n");			
			#endif			

			printf("WSC  version %d.%d.%d (Build %d)\n", (Version>>8),0x0f&(Version>>4),0x0f&Version, Build);

			printf("STDC version %ld\n\n", __STDC_VERSION__ );

			exit(0);
			break;

			default: // ? 
			fprintf(stderr, "Usage: %s -P MSC_Port -B MSC_Baud -p CTD_port -b CTD_baud | -l | -v\n", argv[0]);
			fprintf(stderr, "Example with    CTD: %s -P 1 -B 9600 -p 2 -b 9600\n", argv[0]);
			fprintf(stderr, "Example without CTD: %s -P 1 -B 9600 -p -1 -b -1\n", argv[0]);
			exit(0);
		}
    }
	   
	if( (optind != 9) || (argc != 9) ){
		fprintf(stderr, "Usage: %s -P MSC_Port -B MSC_Baud -p CTD_port -b CTD_baud | -l | -v\n", argv[0]);
		fprintf(stderr, "Example with    CTD: %s -P 1 -B 9600 -p 2 -b 9600\n", argv[0]);
		fprintf(stderr, "Example without CTD: %s -P 1 -B 9600 -p -1 -b -1\n", argv[0]);
		exit(0);
    }   
	   
	if( MSC_port == CTD_port ){
		printf("Error, Port Numbers can't be the same!\n");
		exit(0);
	}  


//---------------------------------------------------------

//---------------------------------------------------------	  
	printf("\n\n***MSC Sampler Parameters***\n");
	
	MscGetSamplerParams();
	
//---------------------------------------------------------

//---------------------------------------------------------	
	printf("\n\n***Initializing Communications***\n");
	
	InitCommLib();
    InitCommPort(MSC_port, MSC_baud);
    if( CTD_port != -1 )
      InitCommPort(CTD_port, CTD_baud);
   	SetConsoleCtrlHandler(BreakHandler, TRUE);	

//---------------------------------------------------------

//---------------------------------------------------------	
    printf("\n***Getting MSC and PC GMT Time***\n");
    
	MscGetSetTime();

//---------------------------------------------------------

//---------------------------------------------------------	
    printf("\n***Checking for Previous Log Files***\n");

	MscCheckPreviousLogFile();

//---------------------------------------------------------

//---------------------------------------------------------	
    printf("\n***Getting %s Configuration Info***\n", MscMode[MSC_mode]);

	MscGetConfigInfo();

//---------------------------------------------------------

//---------------------------------------------------------	  

    printf("\n*** Starting Sample Thread ( Type CTRL+H for help )***\n");
    
    MSC_syncmin = -1;
	if( QueryYesNo("\nSync start of sampling to minute value?", FALSE) ){
		input_var = 30;
		QueryNum("\nEnter minute value (mins)", "%lu", "%lu", &input_var);
		if ((input_var >= 0) && (input_var <= 59)) 
			MSC_syncmin = (int) input_var;
		else
			printf("\nError, Range = [0,59] - Sync Disabled!\n\n");
		}
	else
		printf("\n\n");

    hTimer  = CreateEvent(NULL, FALSE, FALSE, NULL);
    hThread = CreateThread(NULL, 0, Timer, &MSC_syncmin, 0, &tid);
    
	imLoopin = TRUE;
	
    while( imLoopin ){

		/* any incoming chars from the keyboard ? */
		inChar = ( getch() & 0x00ff );
		
		//printf("inChar = 0x%04x\n", inChar);
		
		switch( inChar ){

			case 0x0008:
				printf("\nCommands: CTRL+F (Force Sample), CTRL+I (Interactive Mode), CTRL+Z (Exit)\n");
				break;
				
			case 0x0009:
				printf("\nGot CTRL+I - Entering Interactive Mode\n");
				MscInteractiveMode();
				break;				

			case 0x0006:
				printf("\nGot CTRL+F - Force Sample\n");
				MscCollectSample();
				break;
				
			case 0x001a:
				printf("\nGot CTRL+Z - Terminating Sampling Thread\n");
				SetEvent(hTimer);
				WaitForSingleObject(hThread, INFINITE);
				GetExitCodeThread(hThread, &dwExitCode);
				imLoopin = FALSE;
				break;			
		
			default:
				printf("Unrecognized Charater\n");
				break;
					
		} // ed switch
		
	} /* end while */
    
	printf("Thread Exit Code = %lu\n", dwExitCode);
	Sleep( 1000 );
    
    CloseHandle(hTimer);
    CloseHandle(hThread);
    
    if( CTD_port != -1 )
		SioDone(CTD_port);
    SioDone(MSC_port);
    
	exit( 0 );
	
} /* end main */


void MscInteractiveMode( void )
{	

int cmdChar;	

    printf("\n*** Starting Command Mode ( Type CTRL+K to exit )***\n\n");
	
    while( TRUE ){
		
	    if( kbhit() ){

			cmdChar = ( getch() & 0x00ff );
			
			if( cmdChar == 0x000B ){
				printf("\nGot CTRL+K - Exiting Command Mode\n");
				Sleep(500);
				break;
			}
			else
				SioPutc(MSC_port, (char)cmdChar);
        		
		} //end if

		if( (cmdChar = SioGetc(MSC_port)) > -1 )
			putch( cmdChar );
		else	
			Sleep( 1 );	

	} /* end while */
	
	return;
}
	

//---------------------------------------------------------

/* Sampler pototypes */


void MscCollectSample(void)
{
		
        msc_log = fopen(fnbuf1, "a+");
        msc_dat = fopen(fnbuf2, "a+");

		if( (MSC_secondsample == TRUE) && (CTD_port != -1) )		
			msc2_dat = fopen(fnbuf3, "a+");

        ++ctr;

        printf("%03lu, Waking MSC %04d, %s", ctr, MSC_sernum, ctime(&current_time) );
        if( msc_log != NULL )
          fprintf(msc_log, "%03lu, Waking MSC, %s", ctr, ctime(&current_time) );

        if( WakeUpMsc(MSC_port, MSC_mode) == TRUE ){
          time( &current_time );
          printf("%03lu, MSC Wakeup OK, %s", ctr, ctime(&current_time) );
          if( msc_log != NULL )
            fprintf(msc_log, "%03lu, MSC Wakeup OK, %s", ctr, ctime(&current_time) );
		 
// BEG COLLECT_CTD_SAMPLE		

          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( msc_log != NULL )
                fprintf(msc_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( msc_log != NULL )
                  fprintf(msc_log, "%03lu, ParseCtdDat OK, %.3f, %.4f, %.4f, %s", ctr, ctd_pressure, ctd_temp, ctd_salinity, ctime(&current_time) );

                if( SendCtdValsToMsc(MSC_port, ctd_time, ctd_temp, ctd_salinity, ctd_pressure) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Send CtdDat OK, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_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( msc_log != NULL )
                    fprintf(msc_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( msc_log != NULL )
                  fprintf(msc_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( msc_log != NULL )
                fprintf(msc_log, "%03lu, Get  CtdDat ERROR, %s", ctr, ctime(&current_time) );
              }
            } // end CTD_port if
			
// END COLLECT_CTD_SAMPLE

// BEG SEND_USER_TEMP_SAL

			if( CTD_port == -1 ){

                if( SendCtdValsToMsc(MSC_port, current_time, user_temp, user_salinity, -5.0) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Send UserTempSal OK, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_log, "%03lu, Send UserTempSal OK, %s", ctr, ctime(&current_time) );
                  }
                else{
                  time( &current_time );
                  printf("%03lu, Send UserTempSal ERROR, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_log, "%03lu, Send UserTempSal ERROR, %s", ctr, ctime(&current_time) );
                  }

			}
			
// BEG SEND_USER_TEMP_SAL

// BEG COLLECT_MSC_SAMPLE	

            time( &current_time );
            printf("%03lu, Sampling %s, %s", ctr, MscMode[MSC_mode], ctime(&current_time) );

            if( TakeMscSample(MSC_port) == TRUE ){
              time( &current_time );
              printf("%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );
              if( msc_log != NULL )
                fprintf(msc_log, "%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );

              if( GetMscSampleData(MSC_port, rbuf, sizeof(rbuf)) == TRUE ){
                time( &current_time );
                printf("%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                if( msc_log != NULL )
                  fprintf(msc_log, "%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                printf("%03lu, %s\n", ctr, rbuf);
                if( msc_dat != NULL ){
                  fprintf(msc_dat, "%s\n", rbuf);
                  fclose(msc_dat);
                  }
                }
              else{
                time( &current_time );
                printf("%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                if( msc_log != NULL )
                  fprintf(msc_log, "%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                }

			  if( MSC_secondsample != TRUE ) { 	
				if( PutMscToSleep(MSC_port) == TRUE ){
					time( &current_time );
					printf("%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
					if( msc_log != NULL )
					fprintf(msc_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( msc_log != NULL )
						fprintf(msc_log, "%03lu, Enter Sleep ERROR, %s", ctr, ctime(&current_time) );
					}
				}	

              } // end TakeSecondSample if
            else{
              time( &current_time );
              printf("%03lu, Take Sample ERROR, %s", ctr, ctime(&current_time) );
              if( msc_log != NULL )
                fprintf(msc_log, "%03lu, Take Sample ERROR, %s", ctr, ctime(&current_time) );
              }
			  
// END COLLECT_MSC_SAMPLE				  

// BE COLLECT_SECOND_SAMPLE_WITH_PUMP_ON

          if( (MSC_secondsample == TRUE) && (CTD_port != -1) ){			  

            if( ToggleCtdPump(CTD_port, PUMP_ON) == TRUE ){
              time( &current_time );
              printf("%03lu, CtdPump ON OK, %s", ctr, ctime(&current_time) );
              if( msc_log != NULL )
                fprintf(msc_log, "%03lu, CtdPump ON OK, %s", ctr, ctime(&current_time) );

              time( &current_time );
              printf("%03lu, Sampling %s, %s", ctr, MscMode[MSC_mode], ctime(&current_time) );

              if( TakeMscSample(MSC_port) == TRUE ){
                time( &current_time );
                printf("%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );
                if( msc_log != NULL )
                  fprintf(msc_log, "%03lu, Take Sample OK, %s", ctr, ctime(&current_time) );

                if( GetMscSampleData(MSC_port, rbuf, sizeof(rbuf)) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_log, "%03lu, Send Sample OK, %s", ctr, ctime(&current_time) );
                  printf("%03lu, %s\n", ctr, rbuf);
                  if( msc2_dat != NULL ){
                    fprintf(msc2_dat, "%s\n", rbuf);
                    fclose(msc2_dat);
                    }
                  }
                else{
                  time( &current_time );
                  printf("%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_log, "%03lu, Send Sample ERROR, %s", ctr, ctime(&current_time) );
                  }

                if( PutMscToSleep(MSC_port) == TRUE ){
                  time( &current_time );
                  printf("%03lu, Enter Sleep OK, %s", ctr, ctime(&current_time) );
                  if( msc_log != NULL )
                    fprintf(msc_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( msc_log != NULL )
                    fprintf(msc_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( msc_log != NULL )
                  fprintf(msc_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( msc_log != NULL )
                  fprintf(msc_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( msc_log != NULL )
                fprintf(msc_log, "%03lu, CtdPump ON ERROR, %s", ctr, ctime(&current_time) );
              }

            } // end CTD_PORT != -1

// END COLLECT_SECOND_SAMPLE_WITH_PUMP_ON	
			
          } // end WakeUp if
        else{
          time( &current_time );
          printf("%03lu, MSC Wakeup ERROR, %s", ctr, ctime(&current_time) );
          if( msc_log != NULL )
            fprintf(msc_log, "%03lu, MSC Wakeup ERROR, %s", ctr, ctime(&current_time) );
          }

        printf("%03lu, Next Sample, %s\n", ctr, ctime(&wake_time) );
        if( msc_log != NULL ){
          fprintf(msc_log, "%03lu, Next Sample, %s\n", ctr, ctime(&wake_time) );
          fclose(msc_log);
          }

}


void MscGetSamplerParams(void)
{

    input_var = 0;
    QueryNum("Enter MSC Serial Number", "%lu", "%lu", &input_var);
    if ((input_var >= 1) && (input_var <= 9999)) 
		MSC_sernum = (ushort) input_var;
	else{
	    printf("\n\nError, MSC Serial Number Range = [1,9999]\n");
		exit(0);
    }	
		
    input_var = 2;
    QueryNum("\nEnter MSC Sample Rate in minutes", "%lu", "%lu", &input_var);
    if ((input_var >= 1) && (input_var <= 1440)) 
		MSC_samprate = (ushort) input_var;
	else{
	    printf("\n\nError, Sample Rate Range = [1,1440] minutes\n");
		exit(0);
    }
    
	input_var = 2;
    QueryNum("\nEnter MSC Sample MODE: ISUS=1 DURA=2", "%lu", "%lu", &input_var);
    if ((input_var == 1) || (input_var == 2)) 
		MSC_mode = (ushort) input_var;
	else{
	    printf("\n\nError, Sample Mode Range = [1,2]\n");
		exit(0);
    }		  
	
	if( CTD_port == -1 ){

		float_var = 20.0;
        QueryFloat("\nEnter Solution Temperature", "%.2f", "%f", &float_var);
        if ((float_var >= 0.0) && (float_var <= 40.00))
			user_temp = float_var;
		else{
			printf("Error, Solution Temp Range = [0.0,40.0] degC\n");
			exit(0);
		}

		float_var = 35.0;
        QueryFloat("\nEnter Solution Salinity", "%.2f", "%f", &float_var);
        if ((float_var >= 0.0) && (float_var <= 40.00))
			user_salinity = float_var;
		else{
			printf("Error, Solution Temp Range = [0.0,40.0] pss\n");
			exit(0);
		}

    }

	MSC_secondsample = FALSE;
	if( CTD_port != -1 ){
		if( QueryYesNo("\nCollect a second sample with CTD pump ON?", TRUE) )
			MSC_secondsample = TRUE;
	}
	
}

    
void MscGetSetTime( void )
{    

	msc_time = GetMscTime(MSC_port);
	tp = gmtime(&msc_time);
    strftime(timebuf, sizeof(timebuf)-1, "%a %d %b %Y %H:%M:%S", tp);	
	printf("MSC Date/Time = %s\n", timebuf);	

	time(&pc_time);
	tp = gmtime(&pc_time);
    strftime(timebuf, sizeof(timebuf)-1, "%a %d %b %Y %H:%M:%S", tp);	
	printf("PC  Date/Time = %s\n", timebuf);	
			
	if( QueryYesNo("\nSync MSC RTC to PC?", FALSE) )
	  SetMscRtcToPcTime(MSC_port);
  	else
		printf("\n");

}

	
void MscCheckPreviousLogFile( void )
{	
	
	snprintf(fnbuf1, sizeof(fnbuf1), "MSC%04d_%s.log", MSC_sernum, MscMode[MSC_mode]);	
    if( (msc_log = fopen(fnbuf1, "r")) != NULL ){
		fclose(msc_log);
		printf("LogFile %s was found, ", fnbuf1);
		if( QueryYesNo("should it be REMOVED?", FALSE) ){
			remove(fnbuf1);
			printf("\n");
        }
		else
			printf("\n");
    }
	  
	snprintf(fnbuf2, sizeof(fnbuf2), "MSC%04d_%s.dat", MSC_sernum, MscMode[MSC_mode]);	
    if( (msc_dat = fopen(fnbuf2, "r")) != NULL ){
		fclose(msc_dat);
		printf("DatFile %s was found, ", fnbuf2);
		if( QueryYesNo("should it be REMOVED?", FALSE) ){
			remove(fnbuf2);
			printf("\n");
			}
		else
			printf("\n");
    }

	snprintf(fnbuf3, sizeof(fnbuf3), "MSC%04d_%s_2.dat", MSC_sernum, MscMode[MSC_mode]);	
	if( (msc2_dat = fopen(fnbuf3, "r")) != NULL ){
		fclose(msc2_dat);
		printf("DatFile %s was found, ", fnbuf3);
		if( QueryYesNo("should it be REMOVED?", FALSE) ){
			remove(fnbuf3);
			printf("\n");
		}
	else
		printf("\n");
	}

}
	

void MscGetConfigInfo( void )
{

    if( (ret=WakeUpMsc(MSC_port, MSC_mode)) == TRUE ){
      if( (msc_dat = fopen(fnbuf2, "a+")) == NULL ){
        printf("\nERROR Opening Local Data File, exiting!\n");
        if( CTD_port != -1 )
          SioDone(CTD_port);
        SioDone(MSC_port);
        exit(1);
        }
      else{
		if( (ret=fstat(fileno(msc_dat), &statbuf)) < 0 )
			printf("\n\nError, fstat ret = %d\n\n", ret); 
		if(statbuf.st_size == 0L){
			fprintf(msc_dat, "%s\n", LiveGraphHeader);
			if( MSC_mode == ISUS_MODE )
				fprintf(msc_dat, "%s\n\n\n", LiveGraphIsusFields);
			else
				fprintf(msc_dat, "%s\n\n\n", LiveGraphDuraFields);	
		}  
        ret=GetMscConfigData(MSC_port, msc_dat);
        fclose(msc_dat);
        if( ret > 0 )
          printf("\n%d Configuration Records Received\n", ret);
        else
          printf("\nERROR Getting %s Config Data, ret = %d\n", MscMode[MSC_mode], ret);
        }
      }
    else{
      printf("ERROR Waking MSC, ret = %d, exiting!\n", ret);
      if( CTD_port != -1 )
        SioDone(CTD_port);
      SioDone(MSC_port);
      exit(1);
      }
}


//---------------------------------------------------------

/* MSC Command prototypes */


int WakeUpMsc(int port, ushort mode)
{
char rbuf[32];
short i;


    if( (mode != ISUS_MODE) && (mode != DURA_MODE) )
		return( ERROR );

    SioRxClear(port);

    SioBrkSig(port, 'A');     //send a 0.1 sec BREAK
    Sleep(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);
		  if( mode == ISUS_MODE )
			SetMscToIsusMode(port);
		  else
			SetMscToDuraMode(port);
		  SioRxClear(port);
          return( TRUE );
          }
        else if( strchr(rbuf, '>') != NULL ){
          printf("\nMSC 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 SetMscToIsusMode(int port)
{
char rbuf[32];

    SioRxClear(port);

    SerPuts(port, "MODE,1");

    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      if( strstr(rbuf, "ACK,MODE,1") != NULL ){
         SerPuts(port, "ACK\n");
         return( TRUE );
        }
      else
        return( ERROR );
      }
    else
      return( TIMEOUT );

}

int SetMscToDuraMode(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 SendCtdValsToMsc(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;

    ConfirmMscCommandMode(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 TakeMscSample(int port)
{
char rbuf[32];

    ConfirmMscCommandMode(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)MSC_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 GetMscSampleData(int port, char *sbuf, ushort buflen)
{

    ConfirmMscCommandMode(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 GetMscConfigData(int port, FILE *fptr)
{
char   rbuf[128];
int    ctr;

    ConfirmMscCommandMode(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 ConfirmMscCommandMode(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("\nMSC 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 PutMscToSleep(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("\nMSC 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 );

}

time_t GetMscTime(int port)
{
char   rbuf[128];
char   *srchptr;
time_t msc_time;

    ConfirmMscCommandMode(port);

    SioRxClear(port);

    sprintf(rbuf, "RTC,?");     //get MSC time, should always be GMT
    SerPuts(port, rbuf);

    errno = 0;
    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      srchptr = strchr(strchr(rbuf, '?'), ',');
      msc_time = strtol( ++srchptr, NULL, 10 );
      if( (msc_time <= 0) || (errno == ERANGE) )
        return( ERROR );
      else
        return( msc_time );
      }
    else
      return( TIMEOUT );


}

int SetMscTime(int port)
{
char   rbuf[128];
char   *srchptr;
time_t msc_time, pc_time;
double delta;

    ConfirmMscCommandMode(port);

    SioRxClear(port);

    time(&pc_time);
    sprintf(rbuf, "RTC,%lu", (ulong)pc_time);
    SerPuts(port, rbuf);

    errno = 0;
    if( SerGetsTmout(port, rbuf, sizeof(rbuf), (ushort)CMD_ACK_TIMEOUT) > 0 ){
      printf("\nSetMscTime() buf %s\n", rbuf);
      srchptr = strchr((strchr((strchr(rbuf, ',')+1), ',')+1), ',');
      printf("SetMscTime() ptr %s\n", srchptr+1);
      msc_time = strtol( ++srchptr, NULL, 10 );
      if( (msc_time <= 0) || (errno == ERANGE) )
        return( ERROR );

      delta = fabs( difftime(pc_time, msc_time) );

      if( delta <= 1.0 ){
        SioPuts(port, "ACK\n", 4);
        return( TRUE );
        }
      else{
        SioPuts(port, "NAK\n", 4);
        return( FALSE );
        }
      }
    else
      return( TIMEOUT );


}

int SetMscRtcToPcTime(int port)
{
int     ret;
ulong	input_var;
time_t  pc_time, msc_time;
double  delta;
struct  tm *tp;


    printf("\n***Getting Local Time Zone Offset***\n");

    if( getenv("TZ=") == NULL)
      printf("TZ environment var = NULL!\n");
    else
      printf("TZ environment var = %s\n", getenv("TZ="));

    tzset();      //update the timezone and daylight vars, see compiler's time.c

    printf("Local Time Zone Offset from GMT = %+02ld hrs, %ld secs\n", (timezone/3600), timezone );
    if( QueryYesNo("Modify", FALSE) ){
      while( TRUE ){
        input_var = (long)(timezone/3600);
        QueryNum("\nEnter local time zone offset in hours ( W is [+], E is [-] ) >", "%ld", "%ld", &input_var);
        if( (long)input_var != (timezone/3600) ){
          if( ((long)input_var >= -12) && ((long)input_var <= 12) ){
            timezone = ((long)input_var * 3600);
            printf("\nThe New Local Time Zone Offset = %+02ld hrs, %ld secs\n", (timezone/3600), timezone );
            break;
            }
          else{
            printf("\nInput Error, Time Zone Offset Range=[-12L, 12L], try again!\n");
            continue;
            }
          }
        } //end while
      } //end query if
    else
      printf("\n");

    printf("\n***Getting Local Daylight Savings Setting***\n");

    if(daylight == TRUE)
      printf("Daylight Observation = TRUE\n");
    else
      printf("Daylight Observation = FALSE\n");

    if( QueryYesNo("Modify", FALSE) ){
      while( TRUE ){
        input_var = (long)daylight;
        QueryNum("\nEnter Daylight Observation, [0]=False [1]=True >", "%lu", "%lu", &input_var);
        if( input_var != (long)daylight ){
          if( (input_var >= 0) && (input_var <= 1) ){
            daylight = (int)input_var;
            printf("\nThe New Daylight Adjusment = %d\n", daylight);
            break;
            }
          else{
            printf("\nInput Error, Daylight Adjustment Range=[0, 1], try again!\n");
            continue;
            }
          }
        } //end while
      } //end query if
    else
      printf("\n");

    printf("\n***Getting MSC Time***\n");
    if( (ret=WakeUpMsc(port, ISUS_MODE)) == TRUE ){
      if( (msc_time=GetMscTime(port)) > 0 ){
        time(&pc_time);           //corrects local time to GMT secs using timezone and daylight vars
        tp = gmtime(&pc_time);    //makes no conversion for TZ or DST, it simply takes the seconds from time() and converts it to date/time
        printf("PC  Time (GMT) = %lu = %s", pc_time, asctime(tp) );
        tp = gmtime(&msc_time);  //makes no conversion for TZ or DST, it simply takes the seconds from time() and converts it to date/time
        printf("MSC Time (GMT) = %lu = %s", msc_time, asctime(tp) );
        delta = fabs( difftime(pc_time, msc_time) );
        printf("Time Delta      = %.0lf secs\n", delta );
        if( QueryYesNo("\nTransfer PC Time to MSC", FALSE) ){
          if( (ret=SetMscTime(port)) == TRUE ){
            PutMscToSleep(port);
            printf("\nMSC Time has been set!\n");
            }
          else
            printf("\nERROR Setting MSC Time, ret = %d\n", ret);
          } //end querry if
        else{
          PutMscToSleep(port);
          printf("\n");
          }
        }
      else
        printf("\nERROR Getting MSC Time, ret = %d\n", ret);
    } //end wake if
    else{
      printf("\nERROR Waking MSC, ret = %d, exiting!\n", ret);
      }

	return( OK );

}


//---------------------------------------------------------

/* 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

	Sleep(1000);	

    //CTD should now be in Command Mode

    SioRxClear(port);

    for(i = 10; i; i--){

      SioPutc(port, '\r');
      Sleep(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);
        }
      Sleep(50);
      SerPuts(port, "QS\r");
      Sleep(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");
      Sleep(50);
      SerPuts(port, "QS\r");
      Sleep(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) );
      }

    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) ){
      while ( SioRxQue(port) != 0 ){
        switch( c = SioGetc(port) ){
          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
        
	  Sleep(1); // !!! don't be a CPU Hog !!!

      }  // 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 );
      }

}

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);
}

void InitCommPort(int port, int baud)
{

	// reset (initialize) the CTD port
	ErrorCheck( port, SioReset(port, 1024, 1024) );
	ErrorCheck( port, SioBaud(port, baud) );
		
#ifdef USE_HARDWARE_FLOW_CONTROL
	// set flow control if and only if the other side is doing flow control
	printf("Setting HW flow control\n");
	ErrorCheck( port, SioFlow(port,'H') );
	// set TX timeouts (used with hardware flow control and overlapped I/O)
	printf("TX timeout = 1 mSec/char + 2 seconds\n");
	ErrorCheck( port, SioSetTimeouts(port,(DWORD)-1,(DWORD)0,(DWORD)0,(DWORD)1,(DWORD)2000) );
#else
	printf("Port %d Flow control not set\n", port+1);
#endif


}

void InitCommLib(void)
{
int  Code;
int  Version;
int  Build;
char Temp[51];  

	Code = SioKeyCode(WSC_KEY_CODE);
	if( Code<0 ){
		printf("ERROR %d: Bad key code %d!", Code, WSC_KEY_CODE);
		ExitProgram(1);
	}
	if( Code!=999 ) 	// purchased version always returns 999
		printf("%d days left in evaluation period\n", Code);
		
	Version = SioInfo('V');
	Build   = SioInfo('B');
#ifdef _WIN64
	printf("Win64 WSC Version %d.%d.%d (Build %d)\n", (Version>>8),0x0f&(Version>>4),0x0f&Version, Build);
#else
	printf("Win32 WSC Version %d.%d.%d (Build %d)\n", (Version>>8),0x0f&(Version>>4),0x0f&Version, Build);
#endif

	Code = SioGetReg((char *)Temp, 50);
	if(Code>0)  // display registration string
		printf("%s\n", Temp);
			
#ifdef USE_OVERLAPPED_IO
	// overlapped I/O supported by Win98 and above
	SioSetInteger(-1, 'O', 1);
	printf("Overlapped I/O is enabled\n");
#else
	// overlapped I/O is disabled by default (ver 5.4.1)
	// SioSetInteger(-1, 'O', 0);
	printf("Overlapped I/O is disabled\n");
#endif

	// set defaults for all ports. Note 'Port' argument is -1
	printf("Setting DTR & RTS on\n");
	ErrorCheck( -1, SioReset(-1,1,1)); // DTR & RTS set at port initialization (all ports)
	printf("Setting no parity, 8 data bits, & one stop bit (8N1)\n");
	ErrorCheck( -1, SioParms(-1,WSC_NoParity,WSC_OneStopBit,WSC_WordLength8));
}

void ExitProgram(int ExitCode)
{
printf("(exiting)...\n");
 Beep(1000, 100);
 Sleep(2500);
 Beep(1000, 100);
 exit(ExitCode);
}

int ErrorCheck(int Port, int Code)
{
  if( Code < 0 ){
	SayError(Code, NULL);
    if( Port >= 0 ) 
      SioDone(Port);
    ExitProgram(1);
   }
 return Code;
 // trap WSC error codes 
}


//---------------------------------------------------------

/* Windows API prototypes */

BOOL WINAPI BreakHandler(DWORD dwCtrlType)
{
    //printf("Hello from handler1!\n");
	SioPutc(MSC_port, (int)CTRL_C);
	SioRxClear(MSC_port);
    return TRUE;
}


DWORD WINAPI Timer( LPVOID lpParam )
{
	int 	sync_min = -1;
	int 	min, sec;
	DWORD 	dwMilliseconds;


	//UNREFERENCED_PARAMETER( lpParam );
    
    if ( lpParam != NULL )
		sync_min = *((int*)lpParam); 

	if ( sync_min != -1 ){
		time( &current_time );
		tp  = gmtime( &current_time );
        min = sync_min - tp->tm_min;
        sec = 0 - tp->tm_sec;
                
		dwMilliseconds = (DWORD)( (min*60000L) + (sec*1000L) );
				
		if( (long)dwMilliseconds <= 0L )
			dwMilliseconds += 3600000L;

		wake_time = current_time + ( dwMilliseconds / 1000L );
		
		printf("\nSample Thread Sync Time, %s\n", ctime(&wake_time) );	
	}
	else
		dwMilliseconds = 5;   // take a sample right away

    
    ctr = 0;
   	while( TRUE ){

		if( WaitForSingleObject(hTimer, dwMilliseconds) == WAIT_OBJECT_0 )
			break;
		else{
			time( &current_time );
			wake_time = current_time + (time_t)(MSC_samprate * 60L); 
			MscCollectSample();
			time( &current_time );
			dwMilliseconds = (DWORD)((wake_time - current_time) * 1000);
			}  

		}

	ExitThread( 707 );
}


//---------------------------------------------------------

/* Util prototypes */

int IsPrintable(char c)
{
	if((c==0x0d)||(c==0x0a))
		return TRUE;
 ///if(isprint(c)) return TRUE;
	else if((c>=' ')||(c<='~'))
		return TRUE;
	else 
		return FALSE;
}







