#include	"Sedcam10.h"


/************************ Definitions ***********************/

#define		PWR_CAL				710

#define		MOTOR_PERIOD		5	// Half the period in ms
#define		CW					1
#define		CCW					0
#define		TEETH_ON_DISK		220
#define		STEPS_PER_TOOTH		120
#define		FLUOR_TEETH			30.5		// Teeth from start to fluorometer
#define 	CAM_TEETH			36.5		// Teeth from fluorometer to camera
#define		FUNNEL_TEETH		153		// Teeth from camera to funnel
#define		HALLTOFUNNEL_TEETH	7		// Teeth from Hall sensor to funnel

#define		FLUOR_STEPS			STEPS_PER_TOOTH * FLUOR_TEETH
#define		CAM_STEPS			STEPS_PER_TOOTH * CAM_TEETH
#define		FUNNEL_STEPS		STEPS_PER_TOOTH * FUNNEL_TEETH
#define		HALLTOFUNNEL_STEPS	STEPS_PER_TOOTH * HALLTOFUNNEL_TEETH

#define		COM2_TX			13
#define		COM2_RX			14
#define		TSBUFSIZ		1024
#define		COM1_BAUD		57600L
#define		COM2_BAUD		57600L

/*********************** Global Variables *********************/

struct {
  float hall_to_funnel_teeth;
} defaults;


/********************* Function Prototypes *******************/

void 	motor_step(int steps, int dir);
void	SetupTPUCount(short chan);
long	GetTPUCount(short chan);
void	delay_w_break(long secs);
void 	TPUiorelay(void);
void 	TPUiorelay_timed(time_t delay);

void	sed_funnel(void);
void	sed_fluor(void);
void	sed_camera(void);





/*********************** Macros *********************/

#define		motor_enable()		PSet(D,3);			// Turn motor driver on
#define		motor_disable()		PClear(D,3);		// Turn motor driver off




/*********************************************************************************
	main
*******************************************************************************/

void main(void)
{
	char charbuf[10];
	int err;
  	char float_line[5];
	
/***************** Init pins ***************************/

	InitTT8(NO_WATCHDOG, TT8_TPU);   /* setup Model 8 for running C programs */
	TPUGetPin(0);					// Photo Mult. 1
	TPUGetPin(1);					// Photo Mult. 2
	TPUGetPin(2);				// Hall Sig.
  	TPUSetPin(3, 0);			// Mot Phase 1
  	TPUSetPin(4, 0);			// Mot Phase 2
  	TPUSetPin(5, 0);			// Spare
  	TPUSetPin(6, 0);			// Light for camera
  	TPUSetPin(7, 0);			// Fluorometer excitation
  	TPUSetPin(8, 0);			// Flurometer power

  	PConfOutp(D,3);				// Motor Enable
  	PClear(D,3);
  	PConfOutp(D,4);				// Turn CPU off
  	PSet(D,4);
  	PConfOutp(D,5);				// Turn Camera off
  	PSet(D,5);
  	

/**************** Setup COM ports ************************/

 	SimSetFSys(14720000L);		// Change system clock to compatible serial port rate
 	SerSetBaud(COM1_BAUD, 0);		// Change COM1 baud rate
	SerSetInBuf(malloc(TSBUFSIZ), TSBUFSIZ);
	
	// COM2 TX
	if(TSerOpen(COM2_TX, HighPrior, OUTP, malloc(TSBUFSIZ+TSER_MIN_MEM), TSBUFSIZ, COM2_BAUD, 'N', 8, 1) != tsOK)
	{
		printf("\nFailed TSerOpen output");
		return;
	}

	// COM2 RX
	if(TSerOpen(COM2_RX, HighPrior, INP, malloc(TSBUFSIZ+TSER_MIN_MEM), TSBUFSIZ, COM2_BAUD, 'N', 8, 1) != tsOK)
	{
		printf("\nFailed TSerOpen input");
		return;
	}



//*************** Setup TPU Counters for Photomults **************

	SetupTPUCount(1);
	

//************************** Read UEEPROM ***************************/

  err = UeeReadBlock(0, (uchar *)&defaults, (short) (sizeof(defaults)) );
  if (err) printf("\n Error %d reading from UEEPROM \n", err);
  else printf("\nRead of UEEPROM successful\n");
  
  


// ****************** Main Program Loop ***********************

	PutStr("\nH2O Sediment Camera\n\n\n");

  	while(1)		// Wait for commands
  	{
  		SerInFlush();
		PutStr("\n\nSedtt: ");
		gets(charbuf);

		if(!strcmp(charbuf, "sedfunnel"))		sed_funnel();
		if(!strcmp(charbuf, "sedfluor"))		sed_fluor();
		if(!strcmp(charbuf, "sedcamera"))		sed_camera();
		
		if(!strcmp(charbuf, "funnelteeth"))
		{
    		printf("\nEnter funnel teeth value [%4.1f] = ", defaults.hall_to_funnel_teeth);
	    	SerInFlush();
			if (InputLine(float_line, sizeof(float_line)))
			{
				defaults.hall_to_funnel_teeth = (float)atof(float_line);
	    	}
	    	printf("\nNew funnel teeth value [%4.1f] = ", defaults.hall_to_funnel_teeth);
		 	printf("\nhall_to_funnel_steps = %d\n",  (int)(STEPS_PER_TOOTH * defaults.hall_to_funnel_teeth));
	    	
		     
			// Write to UEEPROM
		    err = UeeWriteBlock( 0, (uchar *) &defaults, (short) sizeof(defaults) );
		    if (err) printf("\n Error %d writing to UEEPROM\n", err);
		    else printf("\n Write of UEEPROM sucessful\n", err);
		}
		
		else if(!strcmp(charbuf, "motcw"))
		{
			motor_enable();
			motor_step(120, CW);
			motor_disable();
		}

		else if(!strcmp(charbuf, "motccw"))
		{
			motor_enable();
			motor_step(120, CCW);
			motor_disable();
		}

		else if(!strcmp(charbuf, "reset"))			ResetToMon();

		else if(!strcmp(charbuf, "fluoron"))		TPUSetPin(8,1);
		else if(!strcmp(charbuf, "exciteon"))		TPUSetPin(7,1);
		else if(!strcmp(charbuf, "lighton"))		TPUSetPin(6,1);
		else if(!strcmp(charbuf, "spareon"))		TPUSetPin(5,1);
		else if(!strcmp(charbuf, "fluoroff"))		TPUSetPin(8,0);
		else if(!strcmp(charbuf, "exciteoff"))		TPUSetPin(7,0);
		else if(!strcmp(charbuf, "lightoff"))		TPUSetPin(6,0);
		else if(!strcmp(charbuf, "spareoff"))		TPUSetPin(5,0);

		else if(!strcmp(charbuf, "pccom"))			TPUiorelay();
		else if(!strcmp(charbuf, "pcon"))			PClear(D,4);
		else if(!strcmp(charbuf, "pcoff"))			PSet(D,4);
		else if(!strcmp(charbuf, "camon"))			PClear(D,5);
		else if(!strcmp(charbuf, "camoff"))			PSet(D,5);

		else if(!strcmp(charbuf, "status"))
		{
			printf("\nPower = %6.2f V\n", (float)AtoDReadWord(0)/PWR_CAL);
			printf("\nHall Sig. = %d\n", TPUGetPin(2));
		}
		
		else if(!strcmp(charbuf, "pm1"))
		{
			SetupTPUCount(0);
			DelayMilliSecs(1000L);
			printf("\nPM1 count = %ld\n", GetTPUCount(0));
		}

		else if(!strcmp(charbuf, "pm2"))
		{
			SetupTPUCount(1);
			DelayMilliSecs(1000L);
			printf("\nPM2 count = %ld\n", GetTPUCount(1));
		}

		else if(!strcmp(charbuf, "pcbaud96"))
		{
			TSerResetBaud(13, 9600L);
			TSerResetBaud(14, 9600L);
		}

		else if(!strcmp(charbuf, "pcbaud192"))
		{
			TSerResetBaud(13, 19200L);
			TSerResetBaud(14, 19200L);
		}

		else if(!strcmp(charbuf, "pcbaud384"))
		{
			TSerResetBaud(13, 38400L);
			TSerResetBaud(14, 38400L);
		}
		
		else if(!strcmp(charbuf, "pcbaud576"))
		{
			TSerResetBaud(13, 57600L);
			TSerResetBaud(14, 57600L);
		}

		else if(!strcmp(charbuf, "pcbaud1152"))
		{
			TSerResetBaud(13, 115200L);
			TSerResetBaud(14, 115200L);
		}

		else	PutStr("\nWhat?");

    }

}	/* main() */



/***************************************************/


void delay_w_break(long secs)
{
	long t;
	
	PutStr("\nWaiting...press any key to skip");
	for(t=0; t<secs; t++)
	{
		if(SerByteAvail()) break;
		DelayMilliSecs(1000);
	}
}


/***************************************************/


void motor_step(int steps, int dir)
{
	int step;

	if(dir)		// CW rotation
	{
		TPUSetPin(3, 0);	// Clear PH1
		TPUSetPin(4, 0);	// Clear PH2
		DelayMilliSecs(MOTOR_PERIOD);

		for(step=0; step<steps; step++)
		{
  			DelayMilliSecs(MOTOR_PERIOD);
			TPUSetPin(4, 1);	// Set PH2
	 		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(3, 1);	// Set PH1
	  		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(4, 0);	// Clear PH2
	  		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(3, 0);	// Clear PH1
		}
	}

	else		// CCW rotation
	{
		TPUSetPin(3, 0);	// Clear PH1
 		TPUSetPin(4, 0);	// Clear PH2
		DelayMilliSecs(MOTOR_PERIOD);
		PSet(D,3);			// Turn motor driver on
		DelayMilliSecs(MOTOR_PERIOD);

		for(step=0; step<steps; step++)
		{
	  		DelayMilliSecs(MOTOR_PERIOD);
			TPUSetPin(3, 1);	// Set PH1
	 		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(4, 1);	// Set PH2
	  		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(3, 0);	// Clear PH1
	  		DelayMilliSecs(MOTOR_PERIOD);
	  		TPUSetPin(4, 0);	// Clear PH2
		}
		PClear(D,3);		// Turn motor driver on
	}

}


//**************************************************************************
// Setup channel for count input
//**************************************************************************

void	SetupTPUCount(short chan){

	// SETUP CHANNEL
	TPUGetPin(chan);		//Set pin as input

	CHANPRIOR(chan,Disabled);
	*CISR ^= (1 << chan );		// Clear any pending interrupt
	*CIER &= ~(1 << chan);		// disable interrupt
	FUNSEL(chan,ITC);		// select input capture function

	PRAM[chan][CHAN_CTRL]	= DetRising;	// what to count (edges)
	PRAM[chan][LINK_CTRL]	= 0x0E;		// no links
	PRAM[chan][MAX_COUNT]	= 0xFFFF;	// maximum count

	HOSTSEQ(chan,ContinuousNoLinks); // continuous count, no links

	HOSTSERVREQ(chan,Initialize);	// init

	CHANPRIOR(chan,MiddlePrior);	// priority

	while(HOSTSERVSTAT(chan)&3) 	// poll until service ends (00)
		;

	}


//**************************************************************************
// Get current channel count
//**************************************************************************

long	GetTPUCount(short chan){

	// Poll Interrupt Bit to check for overflow
	if ( ((*CISR & (1 << chan )) != 0) )
	  {					// if overflow
	   *CISR ^= (1 << chan );		// Clear interrupt bit
	   PRAM[chan][TRANS_COUNT] = 0;	// reset count
	  }
	return(PRAM[chan][TRANS_COUNT]);	// get count
	}


/***************************************************
	TPUiorelay
	Connects COM1 to COM2 to allow commands to be issued.
	Function returns after Ctrl-C detected on COM1.
***************************************************/

void TPUiorelay(void)
{
	int inkey;

	printf("\nPress Ctrl-C to exit...\n");

	while(1)
	{
		if( SerByteAvail() )
		{
		  inkey = (int)SerGetByte();
		  if( inkey == 3 ) break;            /* Exit on Ctrl-C */
		  TSerPutByte(COM2_TX, inkey );
		}

		if( TSerByteAvail(COM2_RX) )
		{
		  SerPutByte((unsigned char)TSerGetByte(COM2_RX));
		}
	}

  return;
}


/***************************************************
	TPUiorelay_timed
	Connects COM1 to COM2 to allow file transfer via
	Y or ZMODEM. Function returns after "delay" seconds of
	inactivity from shoreside.
	
	In:	delay -- delay time in seconds
	Out: None
	
***************************************************/

void TPUiorelay_timed(time_t delay)
{
	int		inkey;
	time_t	timeout;
	
	timeout = time(NULL) + delay;
	
	while(1)
	{
		if( SerByteAvail() )
		{
			timeout = time(NULL) + delay;
		  	inkey = (int)SerGetByte();
		  	TSerPutByte(COM2_TX, inkey );
		}

		if( TSerByteAvail(COM2_RX) )
		{
		  	SerPutByte((unsigned char)TSerGetByte(COM2_RX));
		}
		
		if(timeout < time(NULL)) break;
	}

  	return;
}

/*********************************************************/

void sed_funnel(void)		// Rotate to funnel via Hall sensor
{

	time_t time_out;
 	int hall_to_funnel_steps;

 	hall_to_funnel_steps = (int)(STEPS_PER_TOOTH * defaults.hall_to_funnel_teeth);
 	
	motor_enable();
	DelayMilliSecs(500);
	time_out = time(NULL) + 1200;	// 20 min timeout
	PutStr("\nRotating disk to Hall sensor\n");
	
	// Rotate to start point (collection plate under funnel)
	while( TPUGetPin(2) )		// Watch Hall Effect sensor
	{
		if(time_out < time(NULL)) return;
		motor_step(30, CCW);				// 30 = quarter-tooth increment
	}

	PutStr("\nDisk at Hall sensor\n");
	DelayMilliSecs(500);

	PutStr("\nRotating disk to funnel\n");
	motor_step(HALLTOFUNNEL_STEPS, CCW);
	
	motor_disable();
	
	return;
}

/*********************************************************/

void sed_fluor(void)	// Rotate to fluorometer

{
	motor_enable();
	DelayMilliSecs(500);

	PutStr("\nRotating disk to fluorometer");
	motor_step(FLUOR_STEPS, CCW);

	PutStr("\nDisk at fluorometer");
	motor_disable();

	return;
}


/********************************************************/

void sed_camera(void)		// Rotate to camera
{
	motor_enable();
	DelayMilliSecs(500);

	PutStr("\nRotating disk to camera");
	motor_step(CAM_STEPS, CCW);

	PutStr("\nDisk at camera");
	motor_disable();
	
	return;
}