/******************************************************************************\
**	h2octrl.c				H2O Main Controller
**	
*****************************************************************************
**	Updated by Garo Bournoutian
**	07/29/2005
*****************************************************************************
**	
**	
\******************************************************************************/

#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	<dirent.h>		// PicoDOS POSIX-like Directory Access Defines
#include	<dosdrive.h>	// PicoDOS DOS Drive and Directory Definitions
#include	<fcntl.h>		// PicoDOS POSIX-like File Access Definitions
#include	<stat.h>		// PicoDOS POSIX-like File Status Definitions
#include	<termios.h>		// PicoDOS POSIX-like Terminal I/O Definitions
#include	<unistd.h>		// PicoDOS POSIX-like UNIX Function Definitions


// MAX146 definitions
#define 	AD_48V			0		// A/D Channels
#define		AD_5V			1
#define		AD_GFI			2
#define		AD_TILT_X		3
#define		AD_TILT_Y		4
#define		AD_GND			7
#define		CAL_48V			806
#define		CAL_5V			4372
#define		CAL_GFI			11
#define		CAL_TILT_X		360		// 55.55 mV per degree @ 5V supply
#define		CAL_TILT_Y		360		 
#define 	TILTX_OFFSET   	45      // Tilt outputs 2.5V when level
#define 	TILTY_OFFSET   	45
#define		UNIPOLAR		1
#define		BIPOLAR			0

enum { 	Max146CMD		= 0x80	};
enum { 	Max146SGL		= 0x04, 		Max146DIF		= 0x00	};
enum { 	Max146UNI		= 0x08, 		Max146BIP		= 0x00	};
enum { 	Max146PDFull	= 0x00,			Max146PDFast	= 0x01,
		Max146INT		= 0x02, 		Max146EXT		= 0x03	};


const uchar Max146Sgl[8] = 	// convert chan to single-ended selector
		{ 0x00, 0x40, 0x10, 0x50, 0x20, 0x60, 0x30, 0x70 };
const uchar Max146Dif[8] = 	// convert chan to differential selector
		{ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };


// U10 definitions
#define		CURRMET		1
#define		SEDCAM		2
#define		CAM2		4
#define		CAM1		8
#define		ON			1
#define		OFF			0

// COM definitions
#define		CAM1_TT		1
#define		CAM1_PC		2
#define		CAM2_TT		3
#define		CAM2_PC		4
#define		SEDCAM_TT	5
#define		SEDCAM_PC	6
#define		CM_COM		7
#define		TT_BAUD		57600L
#define		PC_BAUD		19200L
#define		CM_BAUD		1200L



static QPBDev U10_DevTemplate = 
{
	NMPCS2,				// qslot, non-multiplexed connection to PCS3
	"U10",				// devName			C string with device name (15 max)
	2000000,			// maxBaud			maximum baud rate in Hz for device
	8,					// bits				Bits Per Transfer
	iaLowSCK,			// clockPolar		SPI Clock Polarity
	captLead,			// clockPhase		SPI Clock Phase
	false,				// contCSMulti		Continue CS assert between mult xfrs
	true,				// autoTiming		Auto adjust timing to clock flag
	1000000,			// psDelaySCK		Min. Delay Before SCK (picoSecs)
	1000000,			// psDelayTXFR		Min. Delay After Transfer
	0,					// *rcvData			pointer to received data buffer
	0					// xfrCount			words transferred
};

static QPBDev MAX146_DevTemplate = 
{
	NMPCS3,				// qslot, non-multiplexed connection to PCS3
	"MAX146",			// devName			C string with device name (15 max)
	2000000,			// maxBaud			maximum baud rate in Hz for device
	16,					// bits				Bits Per Transfer
	iaLowSCK,			// clockPolar		SPI Clock Polarity
	captLead,			// clockPhase		SPI Clock Phase
	true,				// contCSMulti		Continue CS assert between mult xfrs
	true,				// autoTiming		Auto adjust timing to clock flag
	1000000,			// psDelaySCK		Min. Delay Before SCK (picoSecs)
	1000000,			// psDelayTXFR		Min. Delay After Transfer
	0,					// *rcvData			pointer to received data buffer
	0					// xfrCount			words transferred
};


static QPB		*QPB_U10_Slot = NULL;
static QPB		*QPB_MAX146_Slot = NULL;

// Function Prototypes
void	OriginalStuff(void);
void	SetupTest(void);
void	ContinuousTest(void);
void 	init(void);
void 	status(void);
void 	inst_pwr(ushort inst, char on_off);
void	inst_com(ushort inst, int delay);
short 	Max146(ushort chan, bool uni, bool sgl, bool pd);
int		cam_pic(int camera, int strobe_high, int strobe_low, char size, char quality,
				int iso, int tv);
int		cam_picGARO(int camera, int strobe_high, int strobe_low, char size, char quality,
				int iso, int tv, char *logfile);
void 	GetDateAndTime(char *dateTimeStr);
int		sedcam_pic(char size, char quality, int iso, int tv);
void 	cam_download(int camera, char* filename);
void 	delay(int seconds);


// Structures
struct defStruct {
	ushort sample_rate;
	bool cam1_on;
	bool cam2_on;
	ushort highstrobe;
	ushort lowstrobe;
	ushort boottime;
	ushort camtime;
};


// Global Variables
TUPort		*cam1_tt,
			*cam1_pc,
			*cam2_tt,
			*cam2_pc,
			*sedcam_tt,
			*sedcam_pc,
			*currmet;
			
FILE 		*init_fp;
struct		defStruct defaults;

static ushort 	g_U10_byte = 0;		// Power control byte


/******************************************************************************\
**	main
\******************************************************************************/
int main(void)
{
	char menu_key;
	
	// Identify the progam and build
	printf("\nProgram: %s: %s %s \n", __FILE__, __DATE__, __TIME__);
	// Identify the device and its firmware
	printf("Persistor CF%d SN:%ld   BIOS:%d.%d   PicoDOS:%d.%d\n\n", CFX,
		BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
		BIOSGVT.PICOVersion, BIOSGVT.PICORelease);
		
	if ((init_fp = fopen("settings.dat", "rb")) == 0)
	{
		printf("\nCouldn't open settings.dat ...setting defaults to fallback values\n");
		defaults.sample_rate = 10;
		defaults.cam1_on = true;
		defaults.cam2_on = false;
		defaults.highstrobe = 90;
		defaults.lowstrobe = 30;
		defaults.boottime = 60;
		defaults.camtime = 45;
	}
	else
	{
		fread(&defaults, sizeof(struct defStruct), 1, init_fp);
		fclose(init_fp);
	}

	init();
	
	do
	{
		menu_key = '9';
		kbflush();
		printf("\n\nH2O Controller Main Menu\n");
		printf("===========================================\n");
		printf("1.) Original Command Mode\n");
		printf("2.) Setup Parameters\n");
		printf("3.) Run Continuous Test\n");
		printf("9.) Exit\n");
		printf("===========================================\n");
		QRchar("Enter Selection: ", "%c", true, &menu_key, false, false);
		
		switch(menu_key)
		{
			case '1':
				OriginalStuff();
				break;
			case '2':
				SetupTest();
				break;
			case '3':
				ContinuousTest();
				break;
			case '9':	// Exit
				break;
			default:
				printf("\nInvalid entry. Try again\n");
		}
	} while(menu_key != '9');

	BIOSResetToPicoDOS();
	
	return 0;
}

void OriginalStuff(void)
{
	char charbuf[80];
		
	while(1)		// Wait for commands
  	{
		printf("\n\nH2OCON: ");		// Prompt identifies central controller
		gets(charbuf);

		if(!strcmp(charbuf, "status"))		status();
		
		else if(!strcmp(charbuf, "cmon"))		inst_pwr(CURRMET, OFF);	// Note that current meter OFF and ON are reversed
		else if(!strcmp(charbuf, "cmoff"))		inst_pwr(CURRMET, ON);
		else if(!strcmp(charbuf, "cmcom"))		inst_com(CM_COM, 30);

		else if(!strcmp(charbuf, "cam1on"))		inst_pwr(CAM1, ON);		// Cam1 power on
		else if(!strcmp(charbuf, "cam1off"))	inst_pwr(CAM1, OFF);	// Cam1 power off
		else if(!strcmp(charbuf, "cam1tt"))		inst_com(CAM1_TT, 30);	// Talk to Cam1 Tattletale
		else if(!strcmp(charbuf, "cam1pc"))		inst_com(CAM1_PC, 30);	// Talk to Cam1 PC/104
		else if(!strcmp(charbuf, "cam1pic14"))	cam_pic(CAM1, 1, 4, 's', 'n', 100, 30);			// Take a picture
		else if(!strcmp(charbuf, "cam1pic23"))	cam_pic(CAM1, 2, 3, 's', 'n', 100, 30);			// Take a picture
		else if(!strcmp(charbuf, "cam1dl"))		cam_download(CAM1, "temp.jpg");	// Download picture using Zmodem

		else if(!strcmp(charbuf, "cam2on"))		inst_pwr(CAM2, ON);
		else if(!strcmp(charbuf, "cam2off"))	inst_pwr(CAM2, OFF);
		else if(!strcmp(charbuf, "cam2tt"))		inst_com(CAM2_TT, 30);
		else if(!strcmp(charbuf, "cam2pc"))		inst_com(CAM2_PC, 30);
		else if(!strcmp(charbuf, "cam2pic14"))	cam_pic(CAM2, 1, 4, 's', 'n', 100, 30);			// Take a picture
		else if(!strcmp(charbuf, "cam2pic23"))	cam_pic(CAM2, 2, 3, 's', 'n', 100, 30);			// Take a picture
		else if(!strcmp(charbuf, "cam2dl"))		cam_download(CAM2, "temp.jpg");	// Download picture using Zmodem


		else if(!strcmp(charbuf, "sedon"))		inst_pwr(SEDCAM, ON);
		else if(!strcmp(charbuf, "sedoff"))		inst_pwr(SEDCAM, OFF);
		else if(!strcmp(charbuf, "sedtt"))		inst_com(SEDCAM_TT, 30);
		else if(!strcmp(charbuf, "sedpc"))		inst_com(SEDCAM_PC, 30);
		else if(!strcmp(charbuf, "sedpic"))		sedcam_pic('s', 'n', 100, 30);			// Take a picture
		else if(!strcmp(charbuf, "seddl"))		cam_download(SEDCAM, "temp.jpg");	// Download picture using Zmodem

		else if(!strcmp(charbuf, "help"))
		{
			printf("\nCommonly used H2O camera controller commands:\n");
			printf("\ncmon, cmoff, cmcom");
			printf("\ncam1pic14, cam1pic23, cam1dl");
			printf("\ncam2pic14, cam2pic23, cam2dl");
			printf("\nsedon, sedoff, sedtt, sedpic, seddl");
			printf("\nreset\n");
			
		}

		else if(!strcmp(charbuf, "reset"))	BIOSResetToPicoDOS();
		
		else	printf("\nWhat?");

    }
	
	return;

	}	//____ main() ____//


void SetupTest()
{
	char menu_key;
	struct tm * temp_time;
	time_t ttTemp;
	
	do
  	{
		menu_key = '9';
		kbflush();
		printf("\n\nSetup Menu\n");
		printf("===========================================\n");
		printf("1.) Set System Date and Time\n");
		printf("2.) Set Sample Rate and Camera Options\n");
		printf("3.) Set Strobe Parameters\n");
		printf("4.) Set PC104 Parameters\n");
		printf("9.) Exit Setup (will save changes)\n");
		printf("===========================================\n");
		QRchar("Enter Selection: ", "%c", true, &menu_key, false, false);

		kbflush();
    	switch(menu_key)
    	{
      		case '1':		// Date/Time
				ttTemp = CmdSetDateTime("\n\nEnter the Date and Time ", RTCGetTime(NULL,NULL));
				RTCSetTime(ttTemp, 0);
				ttTemp = RTCGetTime(NULL,NULL); 
				temp_time = localtime(&ttTemp);
				printf("\nCurrent RTC Clock Time: %s\n", asctime(temp_time));	
	    		break;

      		case '2':		// Start Time
        		QRushort("\n\nEnter Sample Rate (min): ", "%u", true, &defaults.sample_rate, 1, 14400);
        		defaults.cam1_on = QRconfirm("\nCamera 1 Enabled: ", defaults.cam1_on, true);
        		defaults.cam2_on = QRconfirm("\nCamera 2 Enabled: ", defaults.cam2_on, true);
        		break;
        		
      		case '3':		// Strobe Parameters
      			QRushort("\n\nEnter High Strobe Charge Time (sec): ", "%u", true, &defaults.highstrobe, 0, 240);
      			QRushort("\nEnter Low Strobe Charge Time (sec): ", "%u", true, &defaults.lowstrobe, 0, 240);
        		break;
        	
        	case '4':		// PC104 Parameters
        		QRushort("\n\nEnter the Bootup Time (sec): ", "%u", true, &defaults.boottime, 1, 240);
        		QRushort("\nEnter the Camera Time (sec): ", "%u", true, &defaults.camtime, 1, 240);
        		break;
        		
        	case '9':		// Exit
				break;
				
			default:
				printf("\nInvalid entry. Try again\n");
    	}
    	
  	} while(menu_key != '9');

	if ((init_fp = fopen("settings.dat", "wb")) == 0)
	{
		printf("\nCouldn't open scaninfo.dat file!\n");
		return;
	}
	else
	{
		fwrite(&defaults, sizeof(struct defStruct), 1, init_fp);
		fclose(init_fp);
	}
}

void ContinuousTest()
{
	FILE *cam114;
	FILE *cam123;
	FILE *cam214;
	FILE *cam223;
	time_t temp_time;
	char cam114file[] = "cam1_14.txt";
	char cam123file[] = "cam1_23.txt";
	char cam214file[] = "cam2_14.txt";
	char cam223file[] = "cam2_23.txt";
	ushort ad_sample;
	
	ad_sample = Max146(AD_48V, UNIPOLAR, true, true); 
	if( (float)ad_sample/CAL_48V < 39 )
	{
		printf("\n\nSystem Voltage currently less than 40V. The system may not run properly.\n");
		if(!QRconfirm("Do you want to continue? ", false, true))
			return;
	}
	
	printf("\n\nPress '!' to end continuous test...\nNOTE: you will have to wait for the current cycle to end.\n");

	if(defaults.cam1_on)
	{	
		cam114 = fopen(cam114file, "a");
		cam123 = fopen(cam123file, "a");
		fprintf(cam114, "\n\nCamera 1, Strobes 1 (high) & 4 (low)\n");
		fprintf(cam114, "Date          \tCam1Vlt\tS1Chrgd\tDischgd\tS4Chrgd\tDischgd\n");
		fprintf(cam123, "\n\nCamera 1, Strobes 2 (high) & 3 (low)\n");
		fprintf(cam123, "Date          \tCam1Vlt\tS2Chrgd\tDischgd\tS3Chrgd\tDischgd\n");
		fclose(cam114);
		fclose(cam123);
	}

	if(defaults.cam2_on)
	{
		cam214 = fopen(cam214file, "a");
		cam223 = fopen(cam223file, "a");	
		fprintf(cam214, "\n\nCamera 2, Strobes 1 (high) & 4 (low)\n");
		fprintf(cam214, "Date          \tCam2Vlt\tS1Chrgd\tDischgd\tS4Chrgd\tDischgd\n");
		fprintf(cam223, "\n\nCamera 2, Strobes 2 (high) & 3 (low)\n");
		fprintf(cam223, "Date          \tCam2Vlt\tS2Chrgd\tDischgd\tS3Chrgd\tDischgd\n");
		fclose(cam214);
		fclose(cam223);
	}
	
	while(1)
	{
		temp_time = RTCGetTime(NULL, NULL);
		
		if(defaults.cam1_on)
		{
			printf("\nCamera 1 with Strobe 1 and 4...\n");
			inst_pwr(CAM1, ON);
			cam_picGARO(CAM1, 1, 4, 's', 'n', 100, 30, cam114file);
			inst_pwr(CAM1, OFF);
			printf("\nDone.\n");
		
			while(kbhit())
			{
				if(getch() == '!')
					goto EndContinuous;
			}
			
			printf("\nCamera 1 with Strobe 2 and 3...\n");
			inst_pwr(CAM1, ON);
			cam_picGARO(CAM1, 2, 3, 's', 'n', 100, 30, cam123file);
			inst_pwr(CAM1, OFF);
			printf("\nDone.\n");

			while(kbhit())
			{
				if(getch() == '!')
					goto EndContinuous;
			}
		}
		
		if(defaults.cam2_on)
		{
			printf("\nCamera 2 with Strobe 1 and 4...\n");
			inst_pwr(CAM2, ON);
			cam_picGARO(CAM2, 1, 4, 's', 'n', 100, 30, cam214file);
			inst_pwr(CAM2, OFF);
			printf("\nDone.\n");

			while(kbhit())
			{
				if(getch() == '!')
					goto EndContinuous;
			}
			
			printf("\nCamera 2 with Strobe 2 and 3...\n");
			inst_pwr(CAM2, ON);
			cam_picGARO(CAM2, 2, 3, 's', 'n', 100, 30, cam223file);
			inst_pwr(CAM2, OFF);
			printf("\nDone.\n");
		}
		
		printf("\nOne set complete...\n\n");
		
		while(RTCGetTime(NULL, NULL) < (defaults.sample_rate*60) + temp_time)
		{
			if(kbhit())
			{
				if(getch() == '!')
					goto EndContinuous;
			}
		}
	}
	
EndContinuous:

	kbflush();
}

/**********************************************************************/

void init(void)
{
	// Init U10 and shutdown external instrument power 
	QPB_U10_Slot = QPBInitSlot(&U10_DevTemplate);	
	if(QPB_U10_Slot == NULL)
	{
		printf("\nError opening QPB_U10_Slot");
		return;
	}
	QPBTransact(QPB_U10_Slot, 0, 1, &g_U10_byte);	// All off
	QPBFreeSlot(&U10_DevTemplate);
	
	inst_pwr(CURRMET, ON); // This actually shuts the current meter off

	// RS-422 COM port stuff
	EIAForceOff(true);			// Shutdown RS-232 chip on CF2
	SCIRxSetBuffered(true);		// Make port buffered
	SCITxSetBuffered(true);	

	// Init TPU UART
	TUInit(calloc, free);		// give TU manager access to our heap

	// Open Cam1 TT
	cam1_tt = TUOpen(2, 1, TT_BAUD, 0);
	if (cam1_tt == 0)
	{
		cprintf("\n!!! Unexpected error opening TU channel 1\n");
	}

	// Open Cam1 PC
	cam1_pc = TUOpen(4, 3, PC_BAUD, 0);
	if (cam1_pc == 0)
	{
		cprintf("\n!!! Unexpected error opening TU channel 2\n");
	}

	// Open Cam2 TT
	cam2_tt = TUOpen(6, 5, TT_BAUD, 0);
	if (cam2_tt == 0)
	{
		cprintf("\n!!! Unexpected error opening TU channel 3\n");
	}

	// Open Cam2 PC
	cam2_pc = TUOpen(8, 7, PC_BAUD, 0);
	if (cam2_pc == 0)
	{
		cprintf("\nError opening TU channel 4\n");
	}

	// Open Sedcam TT
	sedcam_tt = TUOpen(10, 9, TT_BAUD, 0);
	if (sedcam_tt == 0)
	{
		cprintf("\nError opening TU channel 5\n");
	}

	// Open Sedcam PC
	sedcam_pc = TUOpen(12, 11, PC_BAUD, 0);
	if (sedcam_pc == 0)
	{
		cprintf("\nError opening TU channel 6\n");
	}

	// Open Current Meter
	currmet = TUOpen(14, 13, CM_BAUD, 0);
	if (currmet == 0)
	{
		cprintf("\nError opening TU channel 7\n");
	}


}

/******************************************************************************/

int	cam_pic(int camera, int strobe_high, int strobe_low, char size, char quality, int iso, int tv)
{
	char strb_high_cmd[20], strb_low_cmd[20];
	TUPort tuport;
	
	switch(camera)
	{
		case CAM1:
			inst_pwr(CAM1, ON);
			tuport = cam1_tt;
			break;
			
		case CAM2:
			inst_pwr(CAM2, ON);
			tuport = cam2_tt;
			break;
		
		default:
			printf("\nUnrecognized camera in campic");
	}

	// Select high power strobe 
	switch(strobe_high)
	{
		case 1:
			strcpy(strb_high_cmd, "strb1on\n");
			break;
		case 2:
			strcpy(strb_high_cmd, "strb2on\n");
			break;
		default:
			printf("\nUnrecognized high strobe in campic");
			return 0;
	}
		

	// Select low power strobe
	switch(strobe_low)
	{
		case 3:
			strcpy(strb_low_cmd, "strb3on\n");
			break;
		case 4:
			strcpy(strb_low_cmd, "strb4on\n");
			break;
		default:
			printf("\nUnrecognized low strobe in campic");
			return 0;
	}

	// Let camera power up
	delay(5);	
	TUTxPrintf(tuport, "\n");		// Send <CR> to clear any junk in buffer
	delay(1);
	

	// Charge strobes
	TUTxPrintf(tuport, strb_high_cmd);
	printf("\nCharging high power strobe...wait 60 seconds\n");
	delay(60);
	TUTxPrintf(tuport, strb_low_cmd);
	printf("\nCharging low power strobe...wait 30 seconds\n");
	delay(30);
	
	// Shut off strobe power
	TUTxPrintf(tuport, "strb1off\n");
	delay(1);
	TUTxPrintf(tuport, "strb2off\n");
	delay(1);
	TUTxPrintf(tuport, "strb3off\n");
	delay(1);
	TUTxPrintf(tuport, "strb4off\n");
	delay(1);
	
	// Turn on PC/104
	TUTxPrintf(tuport, "pcon\n");
	printf("\nCamera PC104 power on...wait 60 seconds\n");
	delay(60);
	
	// Turn on D60 
	TUTxPrintf(tuport, "camon\n");
	printf("\nCamera D60 on...wait 5 seconds\n");
	delay(5);
	
	// Take picture
	TUTxPrintf(tuport, "pccom\n");
	delay(1);
	TUTxPrintf(tuport, "\\bin\\h2ocam10\\h2ocam10 /%c /%c /i%d /t%d\r\n",
										size, quality, iso, tv);

	printf("\nCamera picture about to be taken...downloading to PC-104\n");
	delay(45);
	printf("\nCamera picture downloaded...shutting down camera\n");
	
	// Shutdown D60 and PC/104
	TUTxPrintf(tuport, "\x3");		// Send Ctrl-C to exit "pccom" command
	delay(1);
	TUTxPrintf(tuport, "camoff\n");
	delay(1);
	TUTxPrintf(tuport, "pcoff\n");
	delay(1);
	
	
	// Shutdown camera
	inst_pwr(CAM1, OFF);
	inst_pwr(CAM2, OFF);
	printf("\nCamera system off\n");
	
	return 0;
}

/******************************************************************************/

int	cam_picGARO(int camera, int strobe_high, int strobe_low, char size, char quality, int iso, int tv, char *logfile)
{
	char strb_high_cmd[20], strb_low_cmd[20];
	TUPort tuport;
	float camVolt, strb1Volt, strb2Volt, strb3Volt, strb4Volt;
	char inputBuf[80];
	int inputPos;
	char dateTimeStr[40];
	time_t temp_time;
	FILE *fp;
	
	switch(camera)
	{
		case CAM1:
			inst_pwr(CAM1, ON);
			tuport = cam1_tt;
			break;
			
		case CAM2:
			inst_pwr(CAM2, ON);
			tuport = cam2_tt;
			break;
		
		default:
			printf("\nUnrecognized camera in campic");
	}

	// Select high power strobe 
	switch(strobe_high)
	{
		case 1:
			strcpy(strb_high_cmd, "strb1on\n");
			break;
		case 2:
			strcpy(strb_high_cmd, "strb2on\n");
			break;
		default:
			printf("\nUnrecognized high strobe in campic");
			return 0;
	}
		

	// Select low power strobe
	switch(strobe_low)
	{
		case 3:
			strcpy(strb_low_cmd, "strb3on\n");
			break;
		case 4:
			strcpy(strb_low_cmd, "strb4on\n");
			break;
		default:
			printf("\nUnrecognized low strobe in campic");
			return 0;
	}

	// Let camera power up
	delay(5);	
	TUTxPrintf(tuport, "\n");		// Send <CR> to clear any junk in buffer
	delay(1);
	
	// Charge strobes
	TUTxPrintf(tuport, strb_high_cmd);
	printf("\nCharging high power strobe...wait %d seconds\n", defaults.highstrobe-defaults.lowstrobe);
	delay(defaults.highstrobe - defaults.lowstrobe);
	TUTxPrintf(tuport, strb_low_cmd);
	printf("\nCharging low power strobe...wait %d seconds\n", defaults.lowstrobe);
	delay(defaults.lowstrobe);
		
	// Turn on PC/104
	TUTxPrintf(tuport, "pcon\n");
	printf("\nCamera PC104 power on...wait %d seconds\n", defaults.boottime);
	delay(defaults.boottime);
	
	// Turn on D60 
	TUTxPrintf(tuport, "camon\n");
	printf("\nCamera D60 on...wait 5 seconds\n");
	delay(1);

	if(strobe_high == 1)
		TUTxPrintf(tuport, "sendstatus14\n");
	else
		TUTxPrintf(tuport, "sendstatus23\n");
	delay(1);
	TURxFlush(tuport);
		
	inputPos = 0;
	
	camVolt = 0;
	strb1Volt = 0;
	strb3Volt = 0;
	temp_time = RTCGetTime(NULL, NULL);
	
	while(RTCGetTime(NULL, NULL) < temp_time + 10) // 5sec timeout
	{
		if(tgetq(tuport))
		{
			inputBuf[inputPos] = tgetc(tuport);
			inputPos++;
			if(inputPos > 24)
			{
				sscanf(&inputBuf[0], "%f", &camVolt);
				sscanf(&inputBuf[8], "%f", &strb1Volt);
				sscanf(&inputBuf[16], "%f", &strb3Volt);
				break;
			}
		}
	}
	
	GetDateAndTime(dateTimeStr);
	
	delay(3);

	// Shut off strobe power
	TUTxPrintf(tuport, "strb1off\n");
	delay(1);
	TUTxPrintf(tuport, "strb2off\n");
	delay(1);
	TUTxPrintf(tuport, "strb3off\n");
	delay(1);
	TUTxPrintf(tuport, "strb4off\n");
	delay(1);

	// Take picture
	TUTxPrintf(tuport, "pccom\n");
	delay(1);
	TUTxPrintf(tuport, "\\bin\\h2ocam10\\h2ocam10 /%c /%c /i%d /t%d\r\n",
										size, quality, iso, tv);

	printf("\nCamera picture about to be taken/downloaded to PC-104 (wait %d secs)\n", defaults.camtime);
	delay(defaults.camtime);
	printf("\nCamera picture downloaded...shutting down camera\n");
	
	// Shutdown D60 and PC/104
	TUTxPrintf(tuport, "\x3");		// Send Ctrl-C to exit "pccom" command
	delay(1);

	if(strobe_high == 1)
		TUTxPrintf(tuport, "sendstatus14\n");
	else
		TUTxPrintf(tuport, "sendstatus23\n");
	delay(1);
	TURxFlush(tuport);
	
	inputPos = 0;
	
	strb2Volt = 0;
	strb4Volt = 0;
	temp_time = RTCGetTime(NULL, NULL);
	
	while(RTCGetTime(NULL, NULL) < temp_time + 10) // 5sec timeout
	{
		if(tgetq(tuport))
		{
			inputBuf[inputPos] = tgetc(tuport);
			inputPos++;
			if(inputPos > 24)
			{
				sscanf(&inputBuf[8], "%f", &strb2Volt);
				sscanf(&inputBuf[16], "%f", &strb4Volt);
				break;
			}
		}
	}
	
	delay(1);
	TUTxPrintf(tuport, "camoff\n");
	delay(1);
	TUTxPrintf(tuport, "pcoff\n");
	delay(1);
	
	
	// Shutdown camera
	inst_pwr(CAM1, OFF);
	inst_pwr(CAM2, OFF);
	printf("\nCamera system off\n");
	
	fp = fopen(logfile, "a");
	fprintf(fp, "%s\t%7.2f\t%7.2f\t%7.2f\t%7.2f\t%7.2f\n", dateTimeStr, camVolt, strb1Volt, strb2Volt, strb3Volt, strb4Volt);
	fclose(fp);
	
	return 0;
}

/*******************************************************************************/

void GetDateAndTime(char *dateTimeStr)
{
	unsigned long tmp;
	int year;
	RTCtm * myTm = NULL;
	RTCtime(&tmp);
	myTm = RTClocaltime(&tmp);
	year = myTm->tm_year;
	if(year > 99)
		year -= 100;
	if(dateTimeStr != NULL)
		snprintf(dateTimeStr, 40, "%02d/%02d/%02d %02d:%02d", (myTm->tm_mon) + 1, myTm->tm_mday, year, myTm->tm_hour, myTm->tm_min);
}

/*******************************************************************************/

int	sedcam_pic(char size, char quality, int iso, int tv)
{

	// Turn on Sediment Camera
	inst_pwr(SEDCAM, ON);
	printf("\nSediment camera system on\n");
	delay(5);
	TUTxPrintf(sedcam_tt, "\n");	// Send <CR> to clear any junk in buffer
	delay(1);
	
	// Turn on PC/104
	TUTxPrintf(sedcam_tt, "pcon\n");
	printf("\nSediment camera PC-104 on...wait 60 seconds\n");
	delay(60);
	
	// Turn on D60 
	TUTxPrintf(sedcam_tt, "camon\n");
	printf("\nSediment camera D60 on...wait 5 seconds\n");
	delay(5);
	
	// Take picture
	TUTxPrintf(sedcam_tt, "pccom\n");
	delay(1);
	TUTxPrintf(sedcam_tt, "\\bin\\h2ocam10\\h2ocam10 /%c /%c /i%d /t%d\r\n",
										size, quality, iso, tv);
	printf("\nSediment camera picture taken...downloading to PC-104\n");
	delay(45);
	printf("\nSediment camera picture downloaded...shutting down camera\n");
	
	// Shutdown D60 and PC/104
	TUTxPrintf(sedcam_tt, "\x3");		// Send Ctrl-C to exit "pccom" command
	delay(1);
	TUTxPrintf(sedcam_tt, "camoff\n");
	delay(1);
	TUTxPrintf(sedcam_tt, "pcoff\n");
	delay(1);
	
	
	// Shutdown sediment camera
	inst_pwr(SEDCAM, OFF);
	printf("\nSediment camera system off\n");
	
	return 0;
}


/******************************************************************************/

void cam_download(int camera, char* filename)
{
	TUPort tuport_tt, tuport_pc;
	ushort inst;
	
	switch(camera)
	{
		case CAM1:
			inst_pwr(CAM1, ON);
			tuport_tt = cam1_tt;
			tuport_pc = cam1_pc;
			inst = CAM1_PC;
			break;
			
		case CAM2:
			inst_pwr(CAM2, ON);
			tuport_tt = cam2_tt;
			tuport_pc = cam2_pc;
			inst = CAM2_PC;
			break;
		
		case SEDCAM:
			inst_pwr(SEDCAM, ON);
			tuport_tt = sedcam_tt;
			tuport_pc = sedcam_pc;
			inst = SEDCAM_PC;
			break;
		
		default:
			printf("\nUnrecognized camera in cam_download");
			return;
	}
	
	delay(2);		// Let camera power up
	
	// Turn on PC/104
	TUTxPrintf(tuport_tt, "pcon\n");
	printf("\nCamera PC104 power on...wait 60 seconds\n");
	printf("\nMake sure ZMODEM receive mode is ready in your terminal program\n");
	delay(60);
	
	// Start Zmodem send on PC/104 at 19200 bps
	TUTxPrintf(tuport_tt, "pccom\n");
	delay(1);
	TUTxPrintf(tuport_tt, "\\bin\\zm192 /s %s\r\n", filename);
 	inst_com(inst, 30);			// Connect PC port to RS-422 port


	// Shutdown PC/104
	TUTxPrintf(tuport_tt, "\x3");		// Send Ctrl-C to exit "pccom" command
	delay(1);
	TUTxPrintf(tuport_tt, "pcoff\n");
	delay(1);

	// Shutdown camera
	inst_pwr(CAM1, OFF);
	inst_pwr(CAM2, OFF);
	inst_pwr(SEDCAM, OFF);
	

}


/******************************************************************************/

void status(void)
{
	ushort 	ad_sample;
	bool	sgl = true;		// true for single-ended, false for differential
	bool	pd = false;		// false for no power down
	
	ad_sample = Max146(AD_48V, UNIPOLAR, sgl, pd); 
	printf("\n48V = %.2f Volts", (float)ad_sample/CAL_48V);

	ad_sample = Max146(AD_5V, UNIPOLAR, sgl, pd); 
	printf("\n5V = %.2f Volts", (float)ad_sample/CAL_5V);

	ad_sample = Max146(AD_GFI, UNIPOLAR, sgl, pd); 
	printf("\nGFI = %.2f mA", (float)ad_sample/CAL_GFI);

	ad_sample = Max146(AD_TILT_X, UNIPOLAR, sgl, pd); 
	printf("\nTILT_X = %.2f", (float)ad_sample/CAL_TILT_X - TILTX_OFFSET);

	ad_sample = Max146(AD_TILT_Y, UNIPOLAR, sgl, pd); 
	printf("\nTILT_Y = %.2f", (float)ad_sample/CAL_TILT_Y - TILTY_OFFSET);

	ad_sample = Max146(AD_GND, UNIPOLAR, sgl, pd); 
	printf("\nGND = %d", (int)ad_sample);

 }

/******************************************************************************/

void inst_pwr(ushort inst, char on_off)		// Controls power to instruments
{
	if(on_off) g_U10_byte |= inst;		// Turn on or turn off?
	else g_U10_byte &= ~inst;
	
	QPB_U10_Slot = QPBInitSlot(&U10_DevTemplate);		// Init U10 slot
	if(QPB_U10_Slot == NULL)
	{
		printf("\nError opening QPB_U10_Slot");
		return;
	}

	QPBTransact(QPB_U10_Slot, 0, 1, &g_U10_byte);
	QPBFreeSlot(&U10_DevTemplate);

}


/****************************************************************/

void inst_com(ushort inst, int delay)
{
	short char_count;
	time_t time_out;
	TUPort	tuport;
	
	switch(inst)
	{
		case CAM1_TT:
			tuport = cam1_tt;
			break;
		case CAM1_PC:
			tuport = cam1_pc;
			break;
		case CAM2_TT:
			tuport = cam2_tt;
			break;
		case CAM2_PC:
			tuport = cam2_pc;
			break;
		case SEDCAM_TT:
			tuport = sedcam_tt;
			break;
		case SEDCAM_PC:
			tuport = sedcam_pc;
			break;
		case CM_COM:
			tuport = currmet;
			break;
		default:
			printf("\nUnrecognized tuport");
			return;
	}
	
	time_out = delay + time(NULL);
	
	while(1)
	{
		// Main COM port to instrument
		char_count = SCIRxQueuedCount();
		if(char_count)	// Character in receive queue?
		{
			time_out = delay + time(NULL);		// Reset timeout
			while(char_count)
			{
				TUTxPutByte(tuport, SCIRxGetByte(false), false);
				char_count--;
			}
		}
		
		// Instrument to main COM port
		char_count = TURxQueuedCount(tuport);
		if(char_count)	// Characters in TPU port queue?
		{
			while(char_count)
			{
				SCITxPutChar(TURxGetByte(tuport, false));
				char_count--;
			}
		}
		
		if(time(NULL) > time_out) break;
	}
	
}

/******************************************************************************/

short Max146(ushort chan, bool uni, bool sgl, bool pd)
	{
	ushort		adcmd[3];
	short		count = 2, result;

	// Initialize QPB.
	QPB_MAX146_Slot = QPBInitSlot(&MAX146_DevTemplate);	// Init MAX146 Slot
	if(QPB_MAX146_Slot == NULL)
	{
		printf("\nError opening QPB_MAX146_Slot");
		return 0;
	}


//	Setup the command word we send to the Max146 which is a combination of
//	selector bits that pick the channel, mode, and clocking.
	adcmd[0] = adcmd[1] =
			 		(sgl	? (Max146Sgl[chan] | Max146SGL)
							: (Max146Dif[chan] | Max146DIF))
				|	(uni	? Max146UNI : Max146BIP)
				|	Max146CMD;

	adcmd[0] |= Max146EXT;
	if (pd)
		{
		adcmd[1] |= Max146PDFast;
		adcmd[count++] = 0;
		}
	else
		adcmd[1] |= Max146EXT;
		
//	Perform a QSPI transaction with two transfers, the first sets up the next
//	conversion, and the second value clocks out the previous channel results.
//	We don't set the QPBASync bit in the command count so the function will
//	wait for the conversion to complete before returning.

	QPBTransact(QPB_MAX146_Slot, 0, count, adcmd);
	result = QPB_MAX146_Slot->dev->rcvData[1];
	QPBFreeSlot(&MAX146_DevTemplate);

//	The rcvData array contains the real result in its second word since word
//	one is the result of some previous conversion. Note that the result is 
//  left-shifted four places and full-scale output is 32768 rather than 4096.
	return result;

	}	//____ Max146Sample() ____//


/*********************************************************************/

void delay(int seconds)
{

	RTCDelayMicroSeconds ((ulong)seconds * 1000000);

}