/******************************************************************************\
**	H2O_Jason.c				Running on Persistor CF2  
**	
*****************************************************************************
**	Filename: H2O_Jason.c
**	Description: The is the main control program for the H2O Project.
**
**	Primary Investigator: Ken Smith
**	Electronics: Mike Kirk and Skip Mikuls
**	Software: Garo Bournoutian
**	
*****************************************************************************
**	Last Modified: July 15, 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

#include	"H2O_Jason.h"


///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Function Prototypes
///////////////////////////////////////////////////
///////////////////////////////////////////////////
void TestFunctions();
void Setup();
void Deploy();


///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Global Variables
///////////////////////////////////////////////////
///////////////////////////////////////////////////
struct 	defStruct defaults;
FILE	*init_fp;


///////////////////////////////////////////////////
///////////////////////////////////////////////////
// The Main Routine
///////////////////////////////////////////////////
///////////////////////////////////////////////////
int main(int argc, char ** argv)
{
	short 	i;
	short	result = 0;		// no errors so far
	char	menu_key;
	time_t	timer;

	// 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(argc>1)
	{
		printf("%d argument(s):\n", argc-1);
		for(i = 1; i < argc; i++)
			printf("\t%s\n", argv[i]);
		printf("\n");
	}

	if ((init_fp = fopen("settings.dat", "rb")) == 0)
	{
		printf("\nCouldn't open settings.dat ...setting defaults to fallback values\n");
		defaults.start_time = 0;
		defaults.end_time = 0;
		defaults.arm_time = 1;
		defaults.use_mag_sensor = false;
		defaults.flood_time = 1;
		defaults.flood_wait = 5;
		defaults.cycle_time = 3;
		defaults.camnum = 1;
		defaults.sample_rate = 5;
		defaults.flood_on = true;
		defaults.max_boottime = 80;
		defaults.max_shuttime = 40;
		defaults.max_camtime = 45;
	}
	else
	{
		fread(&defaults, sizeof(struct defStruct), 1, init_fp);
		fclose(init_fp);
	}
	
	InitializeTPU();
	
	while(1)
  	{    
		menu_key = '0';
		kbflush();
    	timer = time(0) + 60;		// 60 seconds to press a key or CF2 will sleep

		printf("\n\nH2O_Jason Main Menu (Compiled %s %s)\n" , __DATE__ , __TIME__);
		printf("===========================================\n");
		printf("Main Battery: %.2fV\nBackup Battery: %.2fV\n", Max146Battery(), Max146BackupBat());
		printf("===========================================\n");
		printf("1.) PC104 Test Functions & Utilities\n");
		printf("2.) Setup\n");
		printf("3.) Deploy\n");
		printf("4.) Sleep\n");
		printf("9.) Reset to PicoDOS\n");
		printf("===========================================\n");

    	while(1){
      		if(kbhit())
      		{
        		menu_key = getch();		// Get the key pressed
        		fprintf(stderr, "%c", menu_key);
				break;        			
      		}
      		
      		if(time(0) > timer)			// Time to sleep?
        	{
        		menu_key = '4';			// Choose the sleep function
        		break;
      		}
    	}

    	switch(menu_key)
    	{
			case '1':					// Test
			    TestFunctions();
			    break;
		    case '2':					// Setup
			    Setup();
			    break;
		    case '3':					// Deploy
			    Deploy();          	
			    break;
		    case '4':					// Sleep
                SleepWithBreak();
                break;
		    case '9':					// Reset
		    case 13:
		    	ShutdownTPU();
				BIOSResetToPicoDOS();	// full reset, but jump to 0xE10000 (PicoDOS)
				break;
    	}
	}
	
	// We shouldn't get here, but just in case
	ShutdownTPU();

	return result;
}



///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Test Routine
///////////////////////////////////////////////////
///////////////////////////////////////////////////

void TestFunctions()
{
	char menu_key;
	
	do
	{
		menu_key = '9';
		kbflush();
		printf("\n\nH2O_Jason Test Function Menu\n");
		printf("===========================================\n");
		printf("1.) Battery Power and Magnetic Sensor\n");
		printf("2.) Turn on PC104 Power\n");
		printf("3.) Turn off PC104 Power\n");
		printf("4.) PC104 Terminal\n");
		printf("5.) Turn on Camera\n");
		printf("6.) Turn off Camera\n");
		printf("7.) Turn on Flood Light\n");
		printf("8.) Turn off Flood Light\n");
		printf("9.) Exit\n");
		printf("===========================================\n");
		QRchar("Enter Selection: ", "%c", true, &menu_key, false, false);
		
		switch(menu_key)
		{
			case '1':
				mSensorPwrOn();
				
				do
				{
					kbflush();
					printf("\n\nCurrent Sensor Readings\n");
					printf("===========================================\n");
					printf("Battery Voltage: %.2f volts\n", Max146Battery());
					printf("Backup Bat Voltage: %.2f volts\n", Max146BackupBat());
					if(mMagneticSensor())
						printf("Magnetic Sensor = Down\n");
					else
						printf("Magnetic Sensor = Up\n");
					printf("===========================================\n");
					
					DelaySecs(2, true);
				} while(!kbhit());
				
				mSensorPwrOff();
				
				break;
			case '2':
				mPC104PwrOn();
				break;
			case '3':
				mPC104PwrOff();
				break;
			case '4':
				Terminal();
				break;
			case '5':
				mCameraPwrOn();
				break;
			case '6':
				mCameraPwrOff();
				break;
			case '7':
				mFloodLightOn();
				break;
			case '8':
				mFloodLightOff();
				break;
			case '9':	// Exit
				break;
			default:
				printf("\nInvalid entry. Try again\n");
		}
	} while(menu_key != '9');
}



///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Setup Routine
///////////////////////////////////////////////////
///////////////////////////////////////////////////

void Setup()
{
	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 Deployment Start and End Time\n");
		printf("3.) Set Magnetic Switch Options\n");
		printf("4.) Set Camera Options Parameters\n");
		printf("5.) Set PC104 Timeouts\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
      			temp_time = localtime(&defaults.start_time);
				QRdatetime("\n\nEnter the Start Date and Time ", MMDDYY, 1, 1, temp_time);
				defaults.start_time = mktime(temp_time);
				temp_time = localtime(&defaults.end_time);
				QRdatetime("\nEnter the End Date and Time: ", MMDDYY, 1, 1, temp_time);
        		defaults.end_time = mktime(temp_time);
        		break;
        	
        	case '3':		// Magnetic Switch
        		defaults.use_mag_sensor = QRconfirm("\nUse magnetic sensor: ", defaults.use_mag_sensor, true);
        		QRushort("\nEnter time needed to arm for initial deployment (min): ", "%u", true, &defaults.arm_time, 1, 5);
        		QRushort("\nEnter time to keep flood light on (min): ", "%u", true, &defaults.flood_time, 1, 10);
        		QRushort("\nEnter time to wait after flood indication (min): ", "%u", true, &defaults.flood_wait, 1, 10);
        		//QRushort("\nEnter time to needed to start new cycle (min): ", "%u", true, &defaults.cycle_time, 3, 5);
        		break;
        		
      		case '4':		// Camera Parameters
        		QRushort("\n\nEnter Camera Number: ", "%u", true, &defaults.camnum, 1, 3);
        		QRushort("\nEnter Sample Rate (min): ", "%u", true, &defaults.sample_rate, 1, 14400);
        		defaults.flood_on = QRconfirm("\nFlood light enabled: ", defaults.flood_on, true);
        		break;
        	
        	case '5':		// PC104 Parameters
        		QRushort("\n\nEnter the Bootup Time Timeout (sec): ", "%u", true, &defaults.max_boottime, 1, 240);
        		QRushort("\nEnter the Shutdown Time Timeout (sec): ", "%u", true, &defaults.max_shuttime, 1, 240);
        		QRushort("\nEnter the Camera Time Timeout (sec): ", "%u", true, &defaults.max_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);
	}
}



///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Deployment Routine
///////////////////////////////////////////////////
///////////////////////////////////////////////////

void Deploy(void)
{
	FILE *info_fp;
	FILE *pc104_fp;
	struct tm *timePtr;	
	time_t temp_time, sample_start;
	int i, cnt;
	bool magneticStart = false;

	// Clear PC104 log file
	pc104_fp = fopen("PC104.txt", "w");
	if(pc104_fp != NULL)
		fclose(pc104_fp);

	printf("\n\n\nDisk space available       %ld bytes", DIRFreeSpace("c:\\"));
	temp_time = RTCGetTime(NULL, NULL);
	timePtr = localtime(&temp_time);
	printf("\nCurrent RTC clock time     %s", asctime(timePtr));
	timePtr = localtime(&defaults.start_time);
	printf(  "H2O Start Time             %s", asctime(timePtr));
	if(defaults.use_mag_sensor)
		printf(  "Use Magnetic Sensor        Enabled");
	else
		printf(  "Use Magnetic Sensor        Disabled");
	printf("\nMagnetic Arming Time       %d min", (unsigned int)defaults.arm_time);
	printf("\nFlood Ack Time On          %d min", (unsigned int)defaults.flood_time);
	printf("\nWait Time After Flood      %d min", (unsigned int)defaults.flood_wait);
	//printf("\nCycle Restart Time         %d min", (unsigned int)defaults.cycle_time);
	printf("\nPC104 Boot Timeout         %d sec", (unsigned int)defaults.max_boottime);
	printf("\nPC104 Camera Timeout       %d sec", (unsigned int)defaults.max_camtime);
	printf("\nPC104 Shutdown Timeout     %d sec", (unsigned int)defaults.max_shuttime);
	printf("\nCamera Sample Rate         every %d min", (unsigned int)defaults.sample_rate);
	if(defaults.flood_on)
		printf("\nFlood Light                Enabled");
	else
		printf("\nFlood Light                Disabled");
	timePtr = localtime(&defaults.end_time);
	printf("\nH2O End Time               %s", asctime(timePtr));

 	// Last chance to say no!
  	if(!QRconfirm("\n\nDeploy Function... do you want to continue", false, true)) return;
  	printf("\n\n\nDisconnect comm cable and deploy...\n");
	kbflush();

	// Open a deployment info file
	if((info_fp = fopen("depinfo.txt", "w")) == NULL)
	{
		fprintf(stderr, "\nCouldn't write deployment info file... aborting deployment\n");
		return;
	}
	else
	{
		fprintf(info_fp,"\nDisk space available       %ld bytes", DIRFreeSpace("c:\\"));
		temp_time = RTCGetTime(NULL, NULL);
		timePtr = localtime(&temp_time);
		fprintf(info_fp,"\nCurrent RTC clock time     %s", asctime(timePtr));
		timePtr = localtime(&defaults.start_time);
		fprintf(info_fp,  "H2O Start Time             %s", asctime(timePtr));
		if(defaults.use_mag_sensor)
			fprintf(info_fp,  "Use Magnetic Sensor        Enabled");
		else
			fprintf(info_fp,  "Use Magnetic Sensor        Disabled");
		fprintf(info_fp,"\nMagnetic Arming Time       %d min", (unsigned int)defaults.arm_time);
		fprintf(info_fp,"\nFlood Ack Time On          %d min", (unsigned int)defaults.flood_time);
		fprintf(info_fp,"\nWait Time After Flood      %d min", (unsigned int)defaults.flood_wait);
		//fprintf(info_fp,"\nCycle Restart Time         %d min", (unsigned int)defaults.cycle_time);
		fprintf(info_fp,"\nPC104 Boot Timeout         %d sec", (unsigned int)defaults.max_boottime);
		fprintf(info_fp,"\nPC104 Camera Timeout       %d sec", (unsigned int)defaults.max_camtime);
		fprintf(info_fp,"\nPC104 Shutdown Timeout     %d sec", (unsigned int)defaults.max_shuttime);
		fprintf(info_fp,"\nCamera Sample Rate         every %d min", (unsigned int)defaults.sample_rate);
		if(defaults.flood_on)
			fprintf(info_fp,"\nFlood Light                Enabled");
		else
			fprintf(info_fp,"\nFlood Light                Disabled");
		timePtr = localtime(&defaults.end_time);
		fprintf(info_fp,"\nH2O End Time               %s", asctime(timePtr));
	}
	
	printf("Waiting for start time or magnetic sensor (arm after %d min)...\n", (unsigned int)defaults.arm_time);
	printf("Press '!' key to abort\n");
	temp_time = RTCGetTime(NULL, NULL);
	timePtr = localtime(&temp_time);
	fprintf(info_fp, "\nWaiting for deployment start time - %s", asctime(timePtr));
	
	mSensorPwrOn();
	
	// Wait for start time OR Magnetic Switch
	cnt = 0;
	while(RTCGetTime(NULL, NULL) < defaults.start_time && !magneticStart)
	{
		// Do nothing until start time
		if(kbhit())
		{
			if(getch() == '!')
			{
				fclose(info_fp);
				return;
			}
		}
		
		if(mMagneticSensor() && (cnt%2)==0)
		{
			if(cnt == 0)
				temp_time = RTCGetTime(NULL, NULL);

			cnt++;
		}
		else if(!mMagneticSensor() && (cnt%2)==1)
		{
			cnt++;
		}
		
		if(cnt >= 6 && defaults.use_mag_sensor)
		{
			if(RTCGetTime(NULL, NULL) < temp_time + (defaults.arm_time*60))
			{
				printf("\nArmed for Deployment via Magnetic Switch.\n");
				fprintf(info_fp, "Armed for Deployment.\n");
				magneticStart = true;
			}
			else
				cnt = 0;
		}
	}
		
	printf("\nDeployment has begun... Press '!' key to abort\n\n");
	temp_time = RTCGetTime(NULL, NULL);
	timePtr = localtime(&temp_time);
	if(magneticStart)
		fprintf(info_fp, "Deployment has begun (magnetic)   - %s", asctime(timePtr));
	else
		fprintf(info_fp, "Deployment has begun (start time) - %s", asctime(timePtr));
	fclose(info_fp);
	
	// Indicate Initial Cycle beginning by Flood Light
	mFloodLightOn();
	for(i = 0; i < defaults.flood_time; i++)
		DelaySecs(60, true);
	mFloodLightOff();
	for(i = 0; i < defaults.flood_wait; i++)
		DelaySecs(60, true);
	
	do
	{
		info_fp = fopen("depinfo.txt", "a");
		if(info_fp == NULL)
		{
			fprintf(stderr, "\nCouldn't write deployment info file... aborting deployment\n");
			return;
		}
		fprintf(info_fp, "Battery Level Reading             - %.2f Volts\n", Max146Battery());
		printf("PC104 Power on\n");
		sample_start = RTCGetTime(NULL, NULL);
		timePtr = localtime(&sample_start);
		fprintf(info_fp, "PC104 Power on                    - %s", asctime(timePtr));
		mPC104PwrOn();
		InitializeComportPins();
		DelayPC104(BOOT, defaults.max_boottime); // MAY CHECK RETURN VALUE???
		
		printf("Syncing PC104 Date/Time\n");
		temp_time = RTCGetTime(NULL, NULL);
		timePtr = localtime(&temp_time);
		fprintf(info_fp, "Syncing PC104 Date/Time           - %s", asctime(timePtr));
		SyncDateTime();
		
		mCameraPwrOn();
		if(defaults.flood_on)
			mFloodLightOn();
		DelaySecs(1, true);
		printf("Taking Picture\n");
		temp_time = RTCGetTime(NULL, NULL);
		timePtr = localtime(&temp_time);
		fprintf(info_fp, "Taking Picture                    - %s", asctime(timePtr));
		TakePicture();
		DelayPC104(PICTURE, defaults.max_camtime);	// MAY CHECK RETURN VALUE???
		if(defaults.flood_on)
			mFloodLightOff();	// Just in case DelayPC104 failed
		mCameraPwrOff();
		
		printf("Shutting PC104 Down\n");
		temp_time = RTCGetTime(NULL, NULL);
		timePtr = localtime(&temp_time);
		fprintf(info_fp, "Shutting PC104 Down               - %s", asctime(timePtr));
		Shutdown();
		DelayPC104(SHUTDOWN, defaults.max_shuttime);	// MAY CHECK RETURN VALUE???
		
		printf("PC104 Power off\n\n");
		temp_time = RTCGetTime(NULL, NULL);
		timePtr = localtime(&temp_time);
		fprintf(info_fp, "PC104 Power off                   - %s", asctime(timePtr));
		CloseComportUARTS();
		mPC104PwrOff();

		fclose(info_fp);
		
		// Wait for remainder of sample (sample_rate)
		magneticStart = false;
		while(RTCGetTime(NULL, NULL) < sample_start + defaults.sample_rate*60)
		{
			if(kbhit())
			{
				if(getch() == '!')
					return;
			}
		
			/*temp_time = RTCGetTime(NULL, NULL);
			while(mMagneticSensor())
			{
				if(kbhit())
				{
					if(getch() == '!')
						return;
				}
			
				if(!magneticStart && RTCGetTime(NULL, NULL) > temp_time + (defaults.cycle_time*60 - (defaults.max_boottime + defaults.max_shuttime + defaults.max_camtime)))
				{
					// Cycle Start threshold reached
					printf("\nNew Cycle will begin once Magnetic Switch is Released.\n");
					info_fp = fopen("depinfo.txt", "a");
					if(info_fp != NULL)
					{
						fprintf(info_fp, "New Cycle Switch Activated\n");
						fclose(info_fp);
					}
					magneticStart = true;
				}
			}
			
			if(magneticStart)
			{
				// Indicate Initial Cycle beginning by Flood Light
				mFloodLightOn();
				for(i = 0; i < defaults.flood_time; i++)
					DelaySecs(60, true);
				mFloodLightOff();
				for(i = 0; i < defaults.flood_wait; i++)
					DelaySecs(60, true);
				break;
			}*/
		}
		
		if(kbhit())
		{
			if(getch() == '!')
				return;
		}
	} while(RTCGetTime(NULL, NULL) < defaults.end_time);
	
	mSensorPwrOff();
	
	info_fp = fopen("depinfo.txt", "a");
	if(info_fp == NULL)
	{
		fprintf(stderr, "\nCouldn't write deployment info file...\n");
		return;
	}
	printf("End Time reached!\n");
	temp_time = RTCGetTime(NULL, NULL);
	timePtr = localtime(&temp_time);
	fprintf(info_fp, "End Time reached                  - %s", asctime(timePtr));
	
	fclose(info_fp);
}