/************************************************************************/
/* Copyright 2003-2012 MBARI											*/
/************************************************************************/
/* Summary	: Definitions for Utility library for BEDS					*/
/* Filename : utils.c													*/
/* Author	: Robert Herlien (rah)										*/
/* Project	: Benthic Event Detection System (BEDS)						*/
/* Revision: 1.0														*/
/* Created	: 09/28/2012 from OASIS utils.h								*/
/*																			*/
/* MBARI provides this documentation and code "as is", with no warranty,	*/
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium	*/
/* Research Institute to assist in its use, correction, modification, or	*/
/* enhancement. This information should not be published or distributed to	*/
/* third parties without specific written permission from MBARI.			*/
/*																			*/
/************************************************************************/
/* Modification History:												*/
/* 28sep2012 rah - created from OASIS utils.c							*/
/* $Log$
 */
/************************************************************************/

#include <mbariTypes.h>					/* MBARI type definitions			*/
#include <beds.h>						/* BEDS controller definitions		*/
#include <dig_io.h>						/* BEDS digital I/O definitions		*/
#include <clock.h>						/* BEDS Clock module				*/
#include <serial.h>						/* BEDS Serial I/O					*/
#include <utils.h>						/* BEDS Utility routines			*/
#include <fatFs/ff.h>					/* FatFs definitions				*/

#include <stdio.h>						/* Standard I/O library				*/
#include <stdarg.h>						/* vararg stuff						*/
#include <stdlib.h>						/* Standard C library				*/
#include <string.h>						/* String library functions			*/
#include <ctype.h>						/* Standard ctype.h defs			*/
#include <time.h>


/****************************************/
/*		External Data					*/
/****************************************/

Extern Int32	usrTmout;				/* Timeout on user I/F (secs)		*/
Extern MBool	localEcho;				/* Echo command line				*/
Extern MBool	wdtOn;					/* Use watchdog timer			*/
Extern Int32	wdtSecs;				/* Rate to ping WDT in seconds	*/


/****************************************/
/*		Global Data						*/
/****************************************/

Global char		*timespecErr = NULL;


/****************************************/
/*		Module Local Data				*/
/****************************************/

MLocal char		*okStr = "OK";
MLocal char		*dateErr = "Error in date string";
MLocal char		*timeErr = "Error in time string";
MLocal char		*unkErr = "Unknown time/date string";


/************************************************************************/
/* Function	   : delimit												*/
/* Purpose	   : Determine if character is a delimiter					*/
/* Inputs	   : Character												*/
/* Outputs	   : TRUE if character is ',', NULL, or space				*/
/************************************************************************/
MBool delimit( Reg char c )
{
	return( isspace(c) || (c == '\0') || (c == ',') );

} /* delimit() */


/************************************************************************/
/* Function	   : newline												*/
/* Purpose	   : Print newline (\r\n) to serial output					*/
/* Inputs	   : None													*/
/* Outputs	   : None													*/
/************************************************************************/
void newline(void)
{
	printf("\r\n");
}


/************************************************************************/
/* Function	   : removeNewline											*/
/* Purpose	   : Remove line terminator of \n or \r						*/
/* Inputs	   : String ptr												*/
/* Outputs	   : None													*/
/************************************************************************/
void removeNewline(char *s)
{
	char *p;

	if ((p = strchr(s, '\n')) != NULL)
		*p = '\0';

	if ((p = strchr(s, '\r')) != NULL)
		*p = '\0';

} /* removeNewline() */


/************************************************************************/
/* Function	   : readWord												*/
/* Purpose	   : Get 16 bit word from input stream						*/
/* Inputs	   : FIL Ptr												*/
/* Outputs	   : 16 bit value											*/
/************************************************************************/
Nat16 readWord(FIL *fp)
{
	Nat32	br;
	Byte	wrd[2];

	f_read(fp, wrd, sizeof(wrd), &br);
	return((Nat16)((wrd[0]<<8) | (wrd[1]&0xff)));
}


/************************************************************************/
/* Function	   : readLong												*/
/* Purpose	   : Get 32 bit long from input stream						*/
/* Inputs	   : FIL Ptr												*/
/* Outputs	   : 32 bit value											*/
/************************************************************************/
Nat32 readLong(FIL *fp)
{
	Nat32	br;
	Byte	lng[4];

	f_read(fp, lng, sizeof(lng), &br);
	return((Nat32)((lng[0]<<24) | (lng[1]<<16) | (lng[2]<<8) | (lng[3]&0xff)));
}


/************************************************************************/
/* Function	   : gets_lpt												*/
/* Purpose	   : gets in low power and timeout							*/
/* Inputs	   : line buffer ptr, length of buffer						*/
/* Outputs	   : Length of string or TMOUT								*/
/************************************************************************/
int gets_lpt(char *linebuf, int len)
{
	char		*p;
	SerPort		port;
	int			got, ch;
	time_t		endTime;

	endTime = clkTime() + usrTmout;
	port = getConsole();

	for (p = linebuf, got = 0; got < len-1; )
	{
		if ((ch = ser_getc(port)) != ERROR)
		{
			switch(ch)
			{
			  case '\n':
			  case '\r':
				  *p = '\0';
				  return(got);

			  case '\b':
				  if (got > 0)
				  {
					  if (localEcho)
						  printf("\b \b");
					  got--;
					  *--p = '\0';
				  }
				  break;

			  default:
				  *p++ = ch;
				  got++;
				  if (localEcho)
					  ser_putc(port, (Byte)ch);
				  break;
			}

			endTime = clkTime() + usrTmout;
		}

		if (clkTime() >= endTime)
			return(TMOUT);

//		checkModemBatt();						/* Check modem batt, if time */
//		clkIdle(TICKS_PER_SECOND/10);			/* Idle for .1 sec or until char */

		if (wdtOn)
			wdtPing();							/* Keep watchdog running */
	}

	return(got);

} /* gets_lpt() */


/************************************************************************/
/* Function	   : getDuration											*/
/* Purpose	   : Parse string for a duration in seconds					*/
/* Inputs	   : Duration string										*/
/* Outputs	   : Duration in seconds, or ERROR							*/
/* Comment	   : Trailing s/m/h/d denotes seconds/minutes/hours/days	*/
/************************************************************************/
Int32 getDuration(char *spec)
{
	char		c;
	Int32		len = -1;
	int			numItems;

	numItems = sscanf(spec, " %d%c", &len, &c);

	if ((numItems < 1) || (len <= 0))
		return(ERROR);

	if (numItems == 1)
		return(len);

	switch(toupper(c))
	{
	  case 'D':
		  if (len <= 0x7fffffff/(24*3600))
			  return(24 * 3600 * len);
		  break;

	  case 'H':
		  if (len <= 0x7fffffff/3600)
			  return(3600 * len);
		  break;
		  
	  case 'M':
		  if (len <= 0x7fffffff/60)
			  return(60 * len);
		  break;

	  case 'S':
	  default:
		  return(len);
	}

	return(ERROR);

} /* getDuration() */


/************************************************************************/
/* Function	   : getTimespec											*/
/* Purpose	   : Parse command-line spec for time and date				*/
/* Inputs	   : Time string, as yyyy/mm/ddThh:mm:ss					*/
/* Outputs	   : time_t corresponding to timspec, or 0 if error			*/
/************************************************************************/
time_t getTimespec(char *spec)
{
	char		*p, *curp;
	time_t		when;
	struct tm	spectm, *tmp;
	Int32		len, hour, min, sec, year;
	int			numD, numT;

	timespecErr = okStr;
	memset(&spectm, 0, sizeof(spectm));
	when = clkTime();
	tmp = gmtime(&when);
	memcpy(&spectm, tmp, sizeof(struct tm));
	spectm.tm_hour = 0;
	spectm.tm_min = 0;
	spectm.tm_sec = 0;
	curp = spec;
	numD = 0;

	if ((p = strchr(spec, '/')) != NULL)
	{
		if ((p = strchr(p+1, '/')) != NULL)
		{								/* Got mm/dd/yyyy				*/
			if (sscanf(spec, " %d/%d/%d%n",
					   &spectm.tm_mon, &spectm.tm_mday, &spectm.tm_year, &len) < 3)
				return(0);
			if ((spectm.tm_mon > 12) && (spectm.tm_year <= 31))
			{							/* Perhaps they entered yyyy/mm/dd ? */
				year = spectm.tm_year;
				spectm.tm_year = spectm.tm_mon;
				spectm.tm_mon = spectm.tm_mday;
				spectm.tm_mday = year;
			}
			spectm.tm_year -= 1900;
			spectm.tm_mon -= 1;
			curp = spec + len;
			numD = 3;
		}
		else							/* Got mm/dd					*/
		{
			if (sscanf(spec, " %d/%d%n", &spectm.tm_mon, &spectm.tm_mday, &len) < 2)
				return(0);
			spectm.tm_mon -= 1;
			curp = spec + len;
			numD = 2;
		}

		if ((spectm.tm_year < 70) || (spectm.tm_year > 200) ||
			(spectm.tm_mon < 0) || (spectm.tm_mon > 11) ||
			(spectm.tm_mday < 1) || (spectm.tm_mday > 31))
		{
			timespecErr = dateErr;
			return(0);
		}

		if (isspace(*curp))
			deblank(curp);
		else if (*curp)
			curp++;
	}

	numT = sscanf(curp, " %d:%d:%d", &hour, &min, &sec);

	if ((numD <= 0) && (numT < 2))
	{
		timespecErr = unkErr;
		return(0);
	}

	if (numT >= 2)
	{
		spectm.tm_hour = hour;
		spectm.tm_min = min;
	}
	if (numT >= 3)
		spectm.tm_sec = sec;

	if ((spectm.tm_hour < 0) || (spectm.tm_hour > 23) ||
		(spectm.tm_min < 0) || (spectm.tm_min > 59) ||
		(spectm.tm_sec < 0) || (spectm.tm_sec > 59))
	{
		timespecErr = timeErr;
		return(0);
	}

	return(mktime(&spectm));

} /* getTimespec() */


/************************************************************************/
/* Function	   : printTimespec											*/
/* Purpose	   : Print explanation of timespec							*/
/* Inputs	   : None													*/
/* Outputs	   : None													*/
/************************************************************************/
void printTimespec(MBool lng)
{
	printf("\n\tTimespec is of form: mm/dd/yyyyThh:mm:ss\n");
	if (lng)
	{
		printf("\t\tEither date portion or time portion may be omitted\n");
		printf("\t\tDate portion may omit year, time portion may omit seconds\n");
	}
}
