/****************************************************************************/
/* Copyright 1995-2010 MBARI												*/
/****************************************************************************/
/* $Header: /home/cvs/oasis4/src/controller/drivers/li820.c,v 1.1 2011/10/25 22:39:21 bobh Exp $			*/
/* Summary	: Driver Routines for LiCor pCO2 Analyzer on OASIS mooring		*/
/* Filename : licor.c														*/
/* Author	: Robert Herlien (rah)											*/
/* Project	: OASIS Mooring													*/
/* $Revision: 1.1 $															*/
/* Created	: 17may2010 from co2.c and SOON version of li820.c				*/
/*																			*/
/* 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:													*/
/* 17may2010 rah - created from co2.c and SOON version of li820.c			*/
/* $Log: li820.c,v $
/* Revision 1.1	 2011/10/25 22:39:21  bobh
/* Initial oasis4 revision
/*
/* Revision 1.2	 2011/02/24 00:00:11  bobh
/* Changes to: support calling drivers from scripts, better diagnostics for scripts, driver mods
/*
/* Revision 1.1	 2010/05/20 18:27:28  bobh
/* Added Licor820 driver for Gernot
/*
 */
/****************************************************************************/

#include <mbariTypes.h>					/* MBARI type definitions			*/
#include <mbariConst.h>					/* MBARI constants					*/
#include <oasis.h>						/* OASIS controller definitions		*/
#include <io.h>							/* OASIS I/O definitions			*/
#include <log.h>						/* Log record definitions			*/
#include <custom.h>						/* Customizations for implementation*/
#include <list.h>						/* OASIS Linked List library		*/
#include <sem.h>						/* OASIS Semaphore library			*/
#include <task.h>						/* OASIS Multitasking definitions	*/
#include <drvr.h>						/* OASIS driver functions			*/
#include <file.h>						/* OASIS File I/O Routines			*/
#include <utils.h>						/* OASIS Utility routines			*/
#include <remote.h>						/* Remote I/O library				*/
#include <li820.h>						/* Licor 820 include file			*/
#include <debug.h>

#include <stdio.h>						/* Standard I/O functions			*/
#include <string.h>						/* Standard string functions		*/
#include <time.h>

#define LICOR


/************************************************/
/* Parameters used:								*/
/* PARM0:  Pwr bit number for pump				*/
/* PARM1:  I/O bit number for first valve		*/
/* PARM2:  Retry count							*/
/************************************************/

/********************************/
/*		Global Data				*/
/********************************/

Global MBool	licorDebug = FALSE;


/********************************/
/*		Module Local Data		*/
/********************************/

MLocal char		*licorFile = "LICOR.TXT";


/************************************************************************/
/* Function	   : li820_wake												*/
/* Purpose	   : Licor serial wakeup function							*/ 
/* Inputs	   : Driver ptr, MBool (TRUE for on, FALSE for off)			*/
/* Outputs	   : TRUE													*/
/************************************************************************/
MBool li820_wake(Driver *dp, MBool on)
{
	if ( on )
		xputs("<LI820><ACK>TRUE</ACK></LI820>\n");
	else
		drv_pwroff( dp );

	return( TRUE );

} /* pco2_wake() */


/************************************************************************/
/* Function	   : pulseValve												*/
/* Purpose	   : Pulse a valve											*/
/* Inputs	   : Output bit number										*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
MLocal Void pulseValve(Nat32 valveBit)
{
	remOutput(valveBit, TRUE);
	task_delay(VALVE_TIME);
	remOutput(valveBit, FALSE);

} /* pulseValve() */


/************************************************************************/
/* Function	   : initLI820												*/
/* Purpose	   : Function to initialize LI820 when system first comes up*/
/* Inputs	   : None													*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
MLocal Errno initLI820(Driver *dp, MBool doValves)
{
	Nat32		tmout, firstValve;
	char		buf[LI_BUFSIZE];

	if (doValves)
	{
		firstValve = dp->drv_parms[PARM1];
		pwrBitOff(dp->drv_parms[PARM0]);
		pulseValve(VALVE_A1(firstValve));
		pulseValve(VALVE_B1(firstValve));
		pulseValve(VALVE_C2(firstValve));
		pulseValve(VALVE_D1(firstValve));
	}

	li820_wake(dp, TRUE);				/* Send dummy command for wakeup*/
	xflush_ser(TICKS_PER_SECOND);

	tmout = dp->drv_parms[TIMEOUT];
	xputs("<LI820><RS232><STRIP>TRUE</STRIP></RS232></LI820>");
	xgets_tmout(buf, LI_BUFSIZE, tmout);
	xflush_ser(TICKS_PER_SECOND);

	xputs("<LI820><CFG><OUTRATE>0</OUTRATE><HEATER>FALSE</HEATER><FILTER>3</FILTER></CFG></LI820>");
	xgets_tmout(buf, LI_BUFSIZE, tmout);
	xflush_ser(TICKS_PER_SECOND);

	xputs("<LI820><CFG><ALARMS><ENABLED>FALSE</ENABLED></ALARMS></CFG></LI820>");
	xgets_tmout(buf, LI_BUFSIZE, tmout);
	xflush_ser(TICKS_PER_SECOND);

	delay_secs(10L);

	takeFileSem();
	remove(licorFile);
	giveFileSem();

	return( OK );

} /* initLI820() */


/************************************************************************/
/* Function	   : getLI820Data											*/
/* Purpose	   : Function to get the LI820 data							*/
/* Inputs	   : Ptr to where to put data								*/
/* Outputs	   : None													*/
/************************************************************************/
MLocal Errno getLI820Data(Driver *dp, Int16 mode)
{
	Nat16		i;
	Flt32		temp, press, co2, co2abs, batt;
	Int16		itemp, ipress, ico2, ibatt;
	FILE		*fp;
	ulong		tm;
	struct tm	*tmptr;
	char		buf[LI_BUFSIZE];

	if (licorDebug)
		printf("getLI820Data, mode = %hd\n", mode);

	for ( i = 0; i < dp->drv_parms[PARM2]; i++ )
	{
		xprintf("<LI820><DATA>?</DATA></LI820>\n");
		if (xgetn_tmout(buf, LI_BUFSIZE, dp->drv_parms[TIMEOUT]) < 1)
		{
			if (licorDebug)
				printf("LI820 - No reply\n");
		}

		else if ((i = sscanf(buf, "%f %f %f %f %f", &temp, &press,&co2,&co2abs,&batt)) < 5)
		{
			if (licorDebug)
				printf("LI820 - Got %d values, expected 5: %s\n", i, buf);
		}
		else
		{
			ico2 = (int)(co2 * 10.0);
			itemp = (int)(temp * 10.0);
			ibatt = (int)(batt * 10.0);
			ipress = (int)(press *100.0);

			i = strcspn(buf, "\r\n");
			sprintf(buf + i, " %d", mode);
			drvLog(dp, buf, strlen(buf));

			takeFileSem();
			if ((fp = fopen(licorFile, "a")) != NULL)
			{
				if (mode == 1)
				{
					time(&tm);
					tmptr = gmtime(&tm);
					fprintf(fp, "%04d/%02d/%02d %02d:%02d:%02d %d %d %d %d ",
							tmptr->tm_year + 1900, tmptr->tm_mon+1,
							tmptr->tm_mday, tmptr-> tm_hour,
							tmptr->tm_min, tmptr->tm_sec,
							ico2, itemp, ipress, ibatt);
				}
				else
					fprintf(fp, "%d %d ",ico2, ipress);
				if (mode >= 6)
					fprintf(fp, "\r\n");
				fclose(fp);
			}
			giveFileSem();

			return(OK);
		}

		task_delay(TICKS_PER_SECOND);
	}

	return(ERROR);

} /* getLI820Data() */


/************************************************************************/
/* Function	   : li820_drv												*/
/* Purpose	   : Licor 820 pCO2 Sensor driver							*/
/* Inputs	   : Driver Pointer											*/
/* Outputs	   : None													*/
/************************************************************************/
Void li820_drv(Driver *dp)
{
	Nat32		pumpPwr, firstValve;	/* Pump pwr bit, first valve bit*/

	drv_ser_port(dp);					/* Get ser port and turn on pwr */

	if (dp->drv_flags & DO_INIT)		/* do init if DO_INIT flag		*/
		initLI820(dp, TRUE);

	pumpPwr = dp->drv_parms[PARM0];
	firstValve = dp->drv_parms[PARM1];

	pulseValve(VALVE_A2(firstValve));
	pulseValve(VALVE_B1(firstValve));
	pulseValve(VALVE_C1(firstValve));
	pulseValve(VALVE_D2(firstValve));

	pwrBitOn(pumpPwr);					/* Turn on pump					*/
	delay_secs(INIT_LI_TIME);			/* Wait for pump				*/

	getLI820Data(dp, 1);				/* Get sample for mode 1		*/

	pwrBitOff(pumpPwr);					/* Turn off pump				*/
	delay_secs(PUMP_OFF_TIME);			
	getLI820Data(dp, 2);				/* Get sample for mode 2		*/

	pulseValve(VALVE_A2(firstValve));
	pulseValve(VALVE_B2(firstValve));
	pulseValve(VALVE_C2(firstValve));
	pulseValve(VALVE_D2(firstValve));

	pwrBitOn(pumpPwr);					/* Turn on pump					*/
	delay_secs(LI_TIME);
	getLI820Data(dp, 3);				/* Get sample for mode 3		*/

	pwrBitOff(pumpPwr);					/* Turn off pump				*/
	delay_secs(PUMP_OFF_TIME);			
	getLI820Data(dp, 4);				/* Get sample for mode 4		*/

	pulseValve(VALVE_A1(firstValve));
	pulseValve(VALVE_B2(firstValve));
	pulseValve(VALVE_C2(firstValve));
	pulseValve(VALVE_D1(firstValve));

	pwrBitOn(pumpPwr);					/* Turn on pump					*/
	delay_secs(LI_TIME);
	getLI820Data(dp, 5);				/* Get sample for mode 5		*/

	pwrBitOff(pumpPwr);					/* Turn off pump				*/
	delay_secs(PUMP_OFF_TIME);			
	getLI820Data(dp, 6);				/* Get sample for mode 6		*/

	pulseValve(VALVE_A1(firstValve));
	pulseValve(VALVE_B1(firstValve));
	pulseValve(VALVE_C2(firstValve));
	pulseValve(VALVE_D1(firstValve));

	drv_pwroff(dp);						/* Turn off pco2 power			*/
	drv_ser_release(dp);				/* Release serial port			*/

} /* li820_drv() */


/************************************************************************/
/* Function	   : li820_single_drv										*/
/* Purpose	   : Licor 820 single-pass driver							*/
/* Inputs	   : Driver Pointer											*/
/* Outputs	   : None													*/
/* Comments	   : This version is intended to be called from a script, in*/
/*				 which the valve control and looping is done by the script*/
/************************************************************************/
Void li820_single_drv(Driver *dp)
{
	drv_ser_port(dp);					/* Get ser port and turn on pwr */

	if (dp->drv_flags & DO_INIT)		/* do init if DO_INIT flag		*/
		initLI820(dp, FALSE);

	getLI820Data(dp, dp->drv_usrparm);	/* Mode is passed in usrparm	*/

										/* Note - no power off, done by script*/
	drv_ser_release(dp);				/* Release serial port			*/

} /* li820_single_drv() */
