/**************************************************************************
**                                                                        *
**  FILE        :  mvp.c                                                  *
**                                                                        *
**  DESCRIPTION :  Program to control Buoyancy Engine and logging		  *
**                 instruments on MBARI Vertical Profiler                 *
**                                                                        *
**  COPYRIGHT   :  2000 Monterey Bay Aquarium Research Institute          *
**                                                                        *
**	REVISION HISTORY:													  *
**		1.0.0	Initial release										  	  *
**																		  *
**************************************************************************/
#ifndef PRECOMPHDRS 
#include	<TT8.h>			/* Tattletale Model 8 Definitions */
#include	<tat332.h>		/* 68332 Tattletale (7,8) Hardware Definitions */
#include	<sim332.h>		/* 68332 System Integration Module Definitions */
#include	<qsm332.h>		/* 68332 Queued Serial Module Definitions */
#include	<tpu332.h>		/* 68332 Time Processing Unit Definitions */
#include	<dio332.h>		/* 68332 Digital I/O Port Pin Definitions */
#include	<tt8pic.h>		/* Model 8 PIC Parallel Slave Port Definitions */

#include	<tt8lib.h>		/* definitions and prototypes for Model 8 library */
#include	<userio.h>		/* common convenient user I/O routines */

#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>
#endif 
 
//#include	mvp.h

#define VERSION "1.0.0"
#define MXLINE  80			/* max command line length */
#define MXARGS	2			/* max number of command line arguments */
#define TRUE    1
#define FALSE   0
#define ON		1
#define OFF		0
#define FORWARD	1
#define REVERSE	0
#define NUMCOMMANDS (sizeof(commands)/sizeof(commands[0]))
#define CMD_BUF_SIZE    132
#define PROMPT  "\nMVP> "
#define MTR_CUR	0			/* A/D chan for motor current */
#define POT_POS	1			/* A/D chan for pot position */
#define MTR_RUN	15			/* TPU chan for motor run */
#define NUMSAMPS	16		/* number of AtoD samples to average */
#define LOLIM	614			/* lower limit of engine travel on 0-4095 scale */
#define UPLIM	3481		/* upper limit of engine travel on 0-4095 scale */
#define RANGE	(UPLIM-LOLIM)	/* total range of allowed motion */


/* Define the routines that do the work for each command */
typedef enum {
	kEmpty,
	kUnknown,
	kSetEngPos,
	kReadEngPos,
	kSetClkTime,
	kReadClkTime,
	kExitToMon,
	kHelp
} CmdNum;

typedef struct {
	char    *theCommand;
	char    *theExplanation;
	CmdNum  theNumber;
} ACommand;

ACommand commands[] = {
	"SEP", "[0..100]         Set engine position", kSetEngPos,
	"REP", "                 Read engine position", kReadEngPos,
	"SCT", "                 Set clock time", kSetClkTime,
	"RCT", "                 Read clock time", kReadClkTime,
	"ETM", "                 Exit to TOM8 monitor", kExitToMon,
	"HELP", NULL, kHelp,
	"?", NULL, kHelp,
};
short   cmdPointer, baseCommand;
char    cmdBuffer[CMD_BUF_SIZE+2];
char    waiting, loopMode = FALSE;
short   cmdArg[MXARGS];
struct	tm	gTime;

/* function prototypes */
void Init(void);
void SetEngPos(int);
void ReadEngPos(void);
void SetClkTime(void);
void ReadClkTime(void);
void Help(void);
void EnaDCDrive(void);
void DisDCDrive(void);
short AtoDReadAvg(short, short);
void GetLine(char *, int);
void DoCommand(void);
short ParseCommand(void);
void MakeWordUpper(char *);

void main(void)
{
	Init();							/* set up hardware and program variables */

	printf("\n\nMVP Controller version %s\n", VERSION);

	while(TRUE) {                   /* loop forever */
		printf(PROMPT);
		kbflush();                  /* clear command buffer */
		GetLine(cmdBuffer, CMD_BUF_SIZE);	/* get next command */
		do {
			DoCommand();            /* go do it */
			waiting = loopMode;
			while(waiting);        	/* pause if in loop mode */
		} while(!kbhit() && loopMode);  /* exit if any key is hit */
		loopMode = FALSE;
	} /* end while */

} /* end main */


/* Initialize hardware and program variables */
void Init(void) {

	InitTT8(NO_WATCHDOG, TT8_TPU);	/* setup Model 8 for running C programs */
	
	PConfOutp(E, 1);				/* config direction pin (Port E bit 1) as output */
	TPUSetPin(MTR_RUN, OFF);		/* config mtr enable pin (TPU bit 15) as output, and turn off */
	DisDCDrive();					/* disable the motor driver */
	
} /* end function Init() */


/* Get a command line into the command buffer */
void GetLine(char s[], int lim)
{
	char c;
    int i;
    
    i = 0;
    while(--lim > 0 && (c = getchar()) && c != '\n') {
	    if(c == '\x08' || c == '\x10') {	/* if backspace or delete */
	    	if(i > 0) {				/* if not beginning of buffer */
            	i--;				/* throw previous char away */
			} else {
            	putchar('\x20');	/* print a space */
            } /* end if */
	        lim++;
		} else {
	    	s[i++] = c;				/* put char in buffer */
        } /* end if */
    } /* end while */
    s[i] = '\0';					/* mark end of line */
    printf("\n");					/* echo end of line */

} /* end function GetLine() */


/* Read a command from the command buffer and execute it */
void DoCommand(void)
{
	short   cmdNum;
	
	MakeWordUpper(cmdBuffer);
	cmdNum = ParseCommand();
	switch(cmdNum) {
		case kEmpty:
			break;

		case kUnknown:
			printf("Unknown command.");
			loopMode = FALSE;
			break;

		case kHelp:
			Help();
			break;

		case kSetEngPos:
			SetEngPos(cmdArg[0]);
            break;

		case kReadEngPos:
			ReadEngPos();
			break;
			
		case kSetClkTime:
			SetClkTime();
			break;
			
		case kReadClkTime:
			ReadClkTime();
			break;
			
		case kExitToMon:
			ResetToMon();			/* Exit program */
			break;

		default:
			loopMode = FALSE;
			printf("Unrecognized command");
			
	} /* end switch */

} /* end function DoCommand */


/* Set the engine position, given a position on a 0-100 percent scale */
void SetEngPos(int desPosition)
{
	short	actPosition, delta, fault = FALSE, abort = FALSE;
	
	if(desPosition >= 0 && desPosition <= 100) {
		EnaDCDrive();						/* power up the motor driver */
		desPosition = (long)desPosition * RANGE / 100 + LOLIM;	/* convert percent to count */
		actPosition = AtoDReadAvg(POT_POS, NUMSAMPS);	/* read actual pos */
		delta = desPosition - actPosition;	/* diff is desired pos minus actual pos */
		if(delta > 0) {						/* extend buoyancy engine */
			PSet(E, 1);						/* set direction forward */
			TPUSetPin(MTR_RUN, ON);			/* start motor */
			DelayMilliSecs(1L);				/* wait for motor power transient to die */
			while(actPosition < desPosition) {	/* read pot until we get there */
				actPosition = AtoDReadAvg(POT_POS, NUMSAMPS);
				if(!Pin(E, 0)) {			/* check for overcurrent trip */
					fault = TRUE;
					break;
				} /* end if */
				if(kbhit()) {				/* check for operator abort */
					abort = TRUE;
					break;
				} /* end if */
			} /* end while */
		} else {							/* retract buoyancy engine */
			PClear(E, 1);					/* set direction reverse */
			TPUSetPin(MTR_RUN, ON);			/* start motor */
			DelayMilliSecs(1L);				/* wait for motor power transient to die */
			while(actPosition > desPosition) {	/* read pot until we get there */
				actPosition = AtoDReadAvg(POT_POS, NUMSAMPS);
				if(!Pin(E, 0)) {			/* check for overcurrent trip */
					fault = TRUE;
					break;
				} /* end if */
				if(kbhit()) {				/* check for operator abort */
					abort = TRUE;
					break;
				} /* end if */
			} /* end while */
		} /* end if */
		TPUSetPin(MTR_RUN, OFF);			/* stop motor */
		DisDCDrive();						/* power down the motor driver */
		actPosition = ((long)actPosition - LOLIM) * 100 / RANGE; /* convert count to percent */
		if(fault) printf("OVERCURRENT TRIP at %d percent\n", actPosition);
		if(abort) printf("OPERATOR ABORT at %d percent\n", actPosition);
	} else {
		printf("Position must be in range 0 to 100\n");
	} /* end if */

} /* end function SetEngPos() */


/* Read the engine position */
void ReadEngPos(void)
{
	short	potPosition;
	
	potPosition = AtoDReadAvg(POT_POS, NUMSAMPS);	/* read pot position count */
	potPosition = ((long)potPosition - LOLIM) * 100 / RANGE; /* convert count to percent */
	printf("Engine position is %d percent\n", potPosition);
	
} /* end function ReadEngPos() */


/* Set the real-time clock */
void SetClkTime(void)
{
	printf("\nSet Current Date and Time MM/DD/YY HH:MM:SS");
	if (! QueryDateTime("\n<return> for default", TRUE, &gTime)) {
		printf("Invalid Date or Time\n");
		return;
	} /* end if */
	SetTimeTM(&gTime, NULL);

} /* end function SetClkTime() */



/* Read the real-time clock */
void ReadClkTime(void)
{
	printf("Read clock time not yet implemented\n");
//	printf("Strike any key to exit\n");
//	while(!kbhit()) {
//		curTime = 
	
//	} /* end while */
	
} /* end function ReadClkTime() */



/* Enable (power on) the DC Drive module */
void EnaDCDrive(void)
{

	PConfOutp(E, 0);				/* config Port E run/sense pin as output */
	PSet(E, 0);						/* set run/sense hi */
	DelayMilliSecs(2L);				/* delay for 2 ms to latch run/sense */
	PConfInp(E, 0);					/* config run/sense pin as input */

} /* end function EnaDCDrive() */


/* Disable (power off) the DC Drive module */
void DisDCDrive(void)
{

	PConfOutp(E, 0);				/* config Port E run/sense pin as output */
	PClear(E, 0);					/* set run/sense lo */

} /* end function DisDCDrive() */


/* Print the help message */
void Help(void)
{
	short	i;
	
	printf("Commands are:\n");
	for(i = 0; i < NUMCOMMANDS; i++) {
		printf(commands[i].theCommand);
		if(commands[i].theExplanation) {
			printf(commands[i].theExplanation);
		} /* end if */
		printf("\n");
	} /* end for */
	
} /* end function Help() */


/* Read the A/D chan numSamps times and average the results */
short AtoDReadAvg(short chan, short numSamps)
{
	unsigned short i, sum = 0;

	if(numSamps > 16) numSamps = 16;		/* limit max samples to prevent math overflow */
	for(i = 0; i < numSamps; i++) {
		sum += AtoDReadWord(chan) / 8;		/* right-justify 12-bit result, and sum */
	} /* end for */
	return sum / numSamps;

} /* end function AtoDReadAvg() */


/* Parse the string in the command buffer */
short ParseCommand(void)
{
	short   i, j, cmdLen;
	char    *p;
	short   returnValue;
	
	returnValue = kUnknown;
	for(i = 0; i < MXARGS; i++) {
		cmdArg[i] = 32767;				/* set to invalid value */
    } /* end for */

	if(!cmdBuffer[0]) {
		returnValue = kEmpty;            /* Empty buffer */
	} else {
		for(i = j = 0; i < NUMCOMMANDS; i++) {
			cmdLen = strlen(commands[i].theCommand);
			if(strncmp(cmdBuffer, commands[i].theCommand, cmdLen) == 0) {
				returnValue = commands[i].theNumber;
				p = cmdBuffer + cmdLen;
				while(*p && j < MXARGS) {
					while(*p && isspace(*p)) p++; /* skip spaces before arg */
					sscanf(p, "%d", &cmdArg[j++]); /* read the argument */
					while(*p && !isspace(*p)) p++; /* skip to next arg */
                } /* end while */
				if(*(p-1) == '*') loopMode = TRUE;
				break;
			} /* end if */
		} /* end for */
	} /* end if */

	return returnValue;

} /* end function ParseCommand */


/* Convert a string to upper case */
void MakeWordUpper(char *p)
{
	for( ; *p && !isspace(*p); p++) *p = toupper(*p);
} /* end function MakeWordUpper */
