/****************************************************************************/
/* Copyright 2005-2016 MBARI.												*/
/* MBARI Proprietary Information. All rights reserved.						*/
/****************************************************************************/
#include <mbariTypes.h>		/* MBARI type definitions			*/
#include <mbariConst.h>		/* MBARI constants					*/
#include <oasis.h>			/* OASIS controller definitions		*/
#include <fatFs/ff.h>		/* FatFs file system defns			*/
#include <file.h>			/* OASIS File I/O Routines			*/
#include <drvr.h>			/* OASIS driver functions			*/
#include <dig_io.h>			/* OASIS digital I/O				*/
#include <utils.h>			/* OASIS Utility routines			*/
#include <sysLog.h>
#include <adc.h>			/* A/D conversion					*/
#include <timer.h>			/* clkTime()						*/
#include <env.h>			/* This module						*/

#include <stdio.h>			/* Standard I/O functions			*/
#include <stdlib.h>
#include <string.h>


#define DATA_FILE		"ENV.TXT"	/* log file for enviornmental data	*/

#define VOLTAGE_SAMPLES 100			/* Number of samples to average		*/

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

Extern Nat32 lowVoltLimit;			/* Contoller low voltage reset */


/********************************/
/*	Forward Declarations		*/
/********************************/

CmdRtn	lastEnvSample(Driver *dp);


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

/* envBuf can be static, because it's only used when we own fileSem, */
/* which thus acts as a mutex for this buffer, too.  Note this means */
/* that if you modify this file, you must make sure to use this ONLY */
/* when you own the semaphore										 */

MLocal char			envBuf[128];


/****************************************************/
/*	Drive Descriptors for Drivers in this module	*/
/****************************************************/

const char *envParmDesc[] = 
	{"Subsample divisor", NULL, NULL, NULL, NULL, NULL, NULL, NULL};

const DrvDesc envDrvDesc =
	{ "env", envDrv, nullWakeFunc, lastEnvSample, envParmDesc,
	  600, NO_SERIAL, 0, 0, 0, LOG_BIN, 0, 0, 0, 0, 0};


/************************************************************************/
/* Function	   : logEnvData												*/
/* Purpose	   : log contents of environmental cample to a data file	*/
/* Inputs	   : Environmental sample									*/
/* Outputs	   : None													*/
/************************************************************************/
MLocal void logEnvData(Driver *dp, EnvSample* sample)
{
	struct tm	*tm_struct;
	FIL			fp;
 
	/* convert the time stamp to a time structure */
	tm_struct = localtime(&sample->time_stamp);

	takeFileSem();				/* grab the semaphore for the data file */

	/* create the time stamp string "mm/dd/yyyy hh:mm:ss" for the log file */
	strftime(envBuf, sizeof(envBuf), "%m/%d/%Y %H:%M:%S", tm_struct);
  
	if (f_open(&fp, DATA_FILE, (BYTE)(FA_WRITE | FA_OPEN_APPEND)) == FR_OK)
	{
		dp->drv_lastlog = f_tell(&fp);

		sprintf(envBuf + strlen(envBuf), ", %6.2f, %6.2f, %6.2f\r\n",
				sample->volt, sample->temp, sample->pres);

		f_puts(envBuf, &fp);
		f_close(&fp);
	}
	else
		dprintf("Can't open %s\n", DATA_FILE);
	
	giveFileSem();				/* release the file semaphore			*/
}


/************************************************************************/
/* Function	   : lastEnvSample											*/
/* Purpose	   : get the last environmental sample						*/
/* Inputs	   : Driver pointer											*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
CmdRtn lastEnvSample(Driver* dp)
{
	CmdRtn		rtn = OK;
	FIL			fp;

	if (dp->drv_lastlog != -1)
	{
		memset(envBuf, 0, sizeof(envBuf));
		takeFileSem();

		if (f_open(&fp, DATA_FILE, (BYTE)(FA_READ | FA_OPEN_EXISTING)) == FR_OK)
		{
			f_lseek(&fp, dp->drv_lastlog);
			f_gets(envBuf, sizeof(envBuf), &fp);
			f_close(&fp);
			xprintf("%s\t(time, batt, temp, press)\n", envBuf);
		}
		else
		{
			xprintf("Can't open %s\n", DATA_FILE);
			rtn = ERROR;
		}

		giveFileSem();				/* release the file semaphore			*/
	}
	else
		xprintf("No samples taken\n");
	
	return(rtn);
}


/************************************************************************/
/* Function	   : sampleEnv												*/
/* Purpose	   : Sample BRS environmental sensors						*/
/* Inputs	   : Driver pointer, EnvSample pointer						*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
MLocal Errno sampleEnv(Driver* dp, EnvSample* sample)
{
	Nat16		data[4];
	AnalogDesc	*baseAdp, *adp;

	sample->time_stamp = clkTime();				/* time stamp the sample */
	
	adcConvertChans(ADC_PRESS, 4, 64, data);	/* read batt, pressure, temp*/
	baseAdp = getAnalogDesc();

	adp = baseAdp + ADC_BATT;
	sample->volt =  (AdcVolts(data[ADC_BATT]) * adp->mult) + adp->offset;

	adp = baseAdp + ADC_TEMP;
	sample->temp =  (AdcVolts(data[ADC_TEMP]) * adp->mult) + adp->offset;

	adp = baseAdp + ADC_PRESS;
	sample->pres =  (AdcVolts(data[ADC_PRESS]) * adp->mult) + adp->offset;

	return(OK);
}

/************************************************************************/
/* Function	   : checkBatteryVolts										*/
/* Purpose	   : Read analog channel to check battery voltage break to	*/
/*				 Picodos if below threshold								*/
/* Inputs	   : None													*/
/* Outputs	   : None													*/
/************************************************************************/
MLocal void checkBatteryVolts()
{
	Nat16 volts; 
	
	/* Read Analog Batery Voltage */
	adcConvertChans(ADC_BATT, 1, VOLTAGE_SAMPLES, &volts);
	
	/* If Battery volts is lower than 12.5v */
	if ( volts < ((Nat16)lowVoltLimit) ) 
	{
		sysLogPrintf("env driver shutting down system, battery count = %d\n",
					 volts);
		dprintf("counts = %d\n", volts);
		digPwrAllOff();
		picSoftReset();
	}  
}

/************************************************************************/
/* Function	   : envDrv													*/
/* Purpose	   : Driver BRS environmental sensors temp, battery, and	*/
/*				 pressure												*/
/* Inputs	   : Driver Pointer											*/
/* Outputs	   : None													*/
/************************************************************************/
void envDrv(Driver *dp)
{
	EnvSample sample;

	if (dp->drv_runflags & DO_SYNC)
		dp->drv_cnt = 0;

	checkBatteryVolts();   
	sampleEnv(dp, &sample);
	
	/* if PARM0 is set use subsampling */
	if ( dp->drv_parms[PARM0] > 0 )
	{
		if ((dp->drv_cnt % dp->drv_parms[PARM0]) == 0)
			logEnvData(dp, &sample);
	}
	else
	{
		logEnvData(dp, &sample);
	}

	/* increment cycle counter */
	++dp->drv_cnt;
}
