/****************************************************************************/
/* Copyright 2011 MBARI														*/
/****************************************************************************/
/* $Header: /home/cvs/oasis4/src/controller/drivers/serialAtoD.c,v 1.2 2011/11/09 18:45:16 bobh Exp $ */
/* Summary	: Driver Routines for Measurement Computing CB-7012 serial A/D	*/
/* Filename : serialAtoD.c													*/
/* Author	: Robert Herlien (rah)											*/
/* Project	: OASIS Mooring													*/
/* $Revision: 1.2 $															*/
/* Created	: 02/10/2011													*/
/*																			*/
/* 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:													*/
/* 11feb2011 rah - created													*/
/* $Log: serialAtoD.c,v $
/* Revision 1.2	 2011/11/09 18:45:16  bobh
/* Changes for WaveGlider
/*
/* Revision 1.1	 2011/10/25 22:39:21  bobh
/* Initial oasis4 revision
/*
/* Revision 1.2	 2011/08/25 23:02:37  bobh
/* Retry each channel
/*
/* Revision 1.1	 2011/02/22 17:08:24  bobh
/* Added serialAtoD driver
/*
 * 
*/
/****************************************************************************/

#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 <drvr.h>						/* OASIS driver functions			*/
#include <custom.h>						/* CTD_TS definition				*/
#include <task.h>						/* OASIS Multitasking definitions	*/
#include <spi.h>						/* OASIS SPI I/O definitions	*/
#include <utils.h>						/* OASIS Utility routines			*/
#include <parse.h>						/* Parse routines					*/
#include <cfxpico.h>					/* Persistor PicoDOS definitions*/
#include <stdio.h>						/* Standard I/O functions			*/
#include <string.h>						/* Standard String functions		*/

#define BUFSIZE			128 


/************************************************/
/* Parameters used:								*/
/* PARM0:  Unit's address						*/
/* PARM1:  Retry count							*/
/* PARM2:  Input range - see doc				*/
/* PARM3:  Channel bit vector bit 0 = chan 0, etc*/
/* PARM4:  Output format, see doc. Dflt is 00	*/
/************************************************/
/* Note - this device can be RS-232 or RS-485	*/
/* This driver implements the code for each		*/
/************************************************/

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

Global MBool	adDebug = FALSE;


/********************************/
/*		Function Prototypes		*/
/********************************/

Void	serialAtoD_drv(Driver *dp);


/************************************************************************/
/* Function	   : serTransact											*/
/* Purpose	   : Do one serial transaction								*/
/* Inputs	   : Serial port, buffer, buffer len, is485 bool, usecs for line*/
/* Outputs	   : Number of bytes received from A/D, or ERROR			*/
/************************************************************************/
MLocal Int16 serTransact(Nat16 serport, Nat16 tmout, char *buf, Int16 buflen,
						 MBool is485, Nat32 turnaroundUSecs)
{
	Int32		rtn, sndLen = strlen(buf);

	if (adDebug)
		printf("Serial A/D Sending: %s", buf);

	if (is485)
	{
		io_serEnable(serport, SEND485);
		Delay10us();

		rtn = ser_write(serport, buf, sndLen, TICKS_PER_SECOND);

		ser_iflush(serport);
		ser_waitSend(serport);					/* Busy wait for sent to complete */
		RTCDelayMicroSeconds(turnaroundUSecs);
		spiSetPIOBit(GPIO_CHIP, DE_485(serport), 0);
	}
	else		/* RS-232 Mode	*/
		rtn = ser_write(serport, buf, sndLen, TICKS_PER_SECOND);

	if (rtn != sndLen)
		return(ERROR);

	rtn = xgets_tmout(buf, buflen, tmout);
	if (adDebug)
		printf("Serial A/D Rcv: %s\n", buf);

	return(rtn);

} /* serTransact() */


/************************************************************************/
/* Function	   : getAtoD												*/
/* Purpose	   : Make one attempt to get serial A/d data				*/
/* Inputs	   : Driver pointer, buffer									*/
/* Outputs	   : Number of bytes received from A/D, or ERROR			*/
/************************************************************************/
MLocal Int16 getAtoD(Driver *dp, char *buf, Int16 buflen)
{
	Nat16		modAddr = dp->drv_parms[PARM0];
	Nat16		tmout = dp->drv_parms[TIMEOUT];
	Nat16		port, i, j;
	Int16		rtn;
	MBool		is485 = TRUE, gotit = FALSE;
	Nat32		turnaroundUSecs = 1000;
	char		expectedResp[8];
	char		transBuf[64];

	port = dp->drv_parms[SER_PORT];
	is485 = spiReadPIOBit(GPIO_CHIP, SENSE_485(port)) ? TRUE : FALSE;
	if (dp->drv_parms[SER_BAUD] > 0)
		turnaroundUSecs = 20000000/dp->drv_parms[SER_BAUD] + 250;
	else
		turnaroundUSecs = 3000;

	/* Set up expected response to config commands */
	sprintf(expectedResp, "!%02x", modAddr);

	/* Set up data format, input range	*/
	sprintf(transBuf, "%%%02hX%02hX%02lX06%02lX\r", modAddr, modAddr, 
			dp->drv_parms[PARM2], dp->drv_parms[PARM4]);

	if ((serTransact(port, tmout, transBuf, sizeof(transBuf), is485, turnaroundUSecs) <= 0)
		|| (strncasecmp(transBuf, expectedResp, 3) != 0))
		return(ERROR);

	for (i = 0; i < 8; i++)				/* Sample subset of 8 channels	*/
		if (dp->drv_parms[PARM3] & (1 << i))
		{
			gotit = FALSE;
			for (j = 0; j < dp->drv_parms[PARM1]; j++)
			{
				sprintf(transBuf, "#%02X%01X\r", modAddr, i);
				if ((rtn = serTransact(port, tmout, transBuf, sizeof(transBuf),
									   is485, turnaroundUSecs)) > 0)
				{
					gotit = TRUE;
					if (transBuf[0] == '>')
						transBuf[0] = ' ';
					strncat(buf, transBuf, (buflen - strlen(buf) - 2));
					break;
				}
			}
			if (!gotit)
				strcat(buf, "<tmout> ");
		}

	return(strlen(buf));

} /* getAtoD() */


/************************************************************************/
/* Function	   : serialAtoD_drv											*/
/* Purpose	   : Driver for serial A/D converter						*/
/* Inputs	   : Driver Pointer											*/
/* Outputs	   : None													*/
/************************************************************************/
Void serialAtoD_drv(Driver *dp)
{
	Int16		len;
	char		buf[BUFSIZE];			/* Buffer for rcvd data			*/
	
	drv_ser_port( dp );					/* Get serial port				*/
	delay_secs(2);						/* Wait for power up			*/
	memset(buf, 0, sizeof(buf));

	len = getAtoD(dp, buf, sizeof(buf));
	
	drv_ser_release( dp );				/* Release serial port			*/

	if ( len > 0 )
		drvLog(dp, buf, len );			/* Log A/D data					*/
	else
		drvLogError(dp, NO_DATA);

	drv_pwroff( dp );					/* Turn off power				*/

} /* serialAtoD_drv() */

