/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : Seabird25p.cc                                                 */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 0.1                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified : 09/08/2014                                                    */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* 09/08/2014 Renamed file from original Seabird.cc, and began refactoring  */
/*            so that this driver can support the seabird 25plus system.    */
/****************************************************************************/
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <fcntl.h>
#include <ioctl.h>
#include <errno.h>
#include <math.h>

//#include <iostream.h>
#include <time.h>
#include <TimeP.h>
#include <math.h>
#include <string.h>
#include "Seabird25p.h"
#include "Seabird25pTask.h"
#include "Syslog.h"
#include "Seabird25pIF.h"
#include "System.h"

// keep these here to obfuscate them
#define BAUD 9600
#define PARITY "NONE"
#define STOP_BITS 1
#define DATA_BITS 8
#define READ_TIMEOUT 5000
#define CTDPERIOD 1000
#define SHORT_WAIT 4000
#define LONG_WAIT 8000


// The instName parameter should be a unique name for each instance
// of the seabird server/driver. The name "ctdDriver" is recognized by
// the rest of the system as the "main" source of CTD data and
// therefore should always be used as one of the instance names.
//
Seabird25pTask::Seabird25pTask(SerialDevice *serialDevice, char *configFile, char *instName )
: StreamSerialDriver(instName, serialDevice, MaxRecordBytes, "\xa",
		READ_TIMEOUT)
{

	Syslog::write("Seabird25pTask/%s::Seabird25pTask() - create interface to depth sensor...",
			instName);

	_lastFlush = time((long*)0);
	_flushInterval = (time_t)300;      // flush log every 5 minutes
	_nBytes = 0;

	_sbe25p = new Seabird25p(configFile, instName);

	Syslog::write("Seabird25pTask/%s -- constructor succeeded\n", instName);
}

Seabird25pTask::~Seabird25pTask()
{
	// Send command to stop logging
	//
	char buf[30];
	sprintf(buf,"Stop\r\n");
	_device->write(buf,strlen(buf));

	delete _sbe25p ;
}


DeviceIF::Status Seabird25pTask::initialize()
{
	char buf[30];
	int i;

	_device->commsDebugMode(SerialDevice::DebugOff);

	Syslog::write("Seabird25pTask/%s:initializing Seabird...\n", name());

	// initialize serial port
	_device->setLineFormat(BAUD, DATA_BITS, STOP_BITS, PARITY);
	_device->printTermios();

	// clear serial port
	_device->clearPort();
	_device->flushReceiveBuf();

	/* First send a return & see if we get back S>, then it isn't in the
     initialized state.  */

	sprintf(buf,"\r\n");
	_device->write(buf,strlen(buf));

	if (_device->confirm("S>",SHORT_WAIT) == -1) {
		Syslog::write("Seabird25pTask/%s::initialize() - confirm() timed out; sleep a bit",
				name());
		sleep(5);
	}

	_device->write(buf, strlen(buf));

	if (_device->confirm("S>",LONG_WAIT) == -1) {
		Syslog::write("Seabird25pTask/%s::initialize() - "
				"confirm() timed out again, send multiple newlines", name());

		/* sending lots of returns to get past the
       	   part where it wants you to set the date */

		sprintf(buf,"\r\n");
		_device->write(buf,strlen(buf));

		Syslog::write("Seabird25pTask/%s: first CR  sent...\n", name());

		if (_device->confirm("S>",LONG_WAIT) == -1) {
			i = _device->confirm("S>", 4000 );
			if (i) {
				Syslog::write("Seabird25pTask/%s: confirmed power on returns: %d\n",name(), i);
			}
			if (i==-1) {
				Syslog::write("Seabird25pTask/%s: no power on detected yet...\n", name());
				sprintf(buf,"\r\n\r\n\r\n");
				_device->write(buf, strlen(buf));
				i = _device->confirm("S>", 4000);

				if (i==-1) {
					Syslog::write("Seabird25pTask/%s: no power on detected yet...\n", name());
					sprintf(buf,"\r\n\r\n\r\n");
					_device->write(buf, strlen(buf));

					i = _device->confirm("S>", 8000);

					_device->clearPort();
					if (i==-1) {
						//	    fprintf(stderr, "%s",error.msg);
						return DeviceIF::Error;
						//throw Exception("Seabird: no power on detected..bailing!\n");
					}
				}
			}
		}
	}


	Syslog::write("Seabird25pTask/%s::initialize() - starting logging...\n", name());

	// Start logging
	sprintf(buf,  "StartNow\r\n" );
	_device->write(buf, strlen(buf));

	if (_device->confirm("StartNow",LONG_WAIT))
		Syslog::write("Ctd/%s:initialize() - Logging Started...\n", name());

	Syslog::write("Ctd/%s:initialize() - ready!", name());

	return DeviceIF::Ok;
}

#if 1
///////////////////////////////////////////////////////////////////////
// readRecord() for socket implementations only!
///////////////////////////////////////////////////////////////////////
DeviceIF::Status Seabird25pTask::readRecord(unsigned char *record,
		int maxRecordBytes,
		const char *recordTerminator,
		unsigned readTimeout,
		int *nBytesRead)
{
	Boolean debug = False;
	Boolean readError = False;
	Boolean noRecord = True;
	char* eor = NULL;
	int nBytes = 0;

	// Keep track of time spent in this method
	//
	long t0, t1;
	t0 = t1 = Time::milliseconds();

	while (noRecord) {
		nBytes = read(_device->getFd(), _nBytes + ((char *)(_recordBuf)), ExpectedRecordBytes);
		_nBytes += nBytes;
		if (_nBytes< ExpectedRecordBytes) {
			continue;
		}
		int i;
		for (i = 0; i < _nBytes; i++) {
			if (_recordBuf[i] == *recordTerminator) {
				eor = _recordBuf+i;
				dprintf("Got Terminator\n");
			}
		}

		if (eor != (char *)NULL)
		{
			// Got a complete record
			//
	    	dprintf("Seabird/%s::readRecord() - got complete record\n", name());
			noRecord = False;
			readError = False;
			long readTime = Time::milliseconds() - t0;
		}

		else if (_nBytes == (maxRecordBytes-1))
		{
			// Not a record yet, make sure we didn't reach the end
			// of the buffer. If we have, then nothing to do except
			// start recv()ing at the beginning of the buffer again.
			//
			dprintf("SerialDevice::Buffer full!");
			readError = True;
			nBytes = 0;
			ioctl(_device->getFd(), TIOCFLUSH, 0);
		}

		// Time is up, break out of the while loop
		//
		t1 = Time::milliseconds();
		if (noRecord && (t0 + readTimeout) <= t1)
		{
			readError = True;
			dprintf("Timed out\n");
			break;
		}

	}

	// No record yet and were done. Return Error so that processRecord
	// isn't called with a bad record.
	//
	if (readError || noRecord)
	{
		dprintf("No record yet\n");
		return DeviceIF::Error;
	}
	else
	{
		// Record terminator reached, so copy _nBytes from recordBuf
		// to record, report the number of bytes read, and return.
		//
		*nBytesRead = (eor-_recordBuf+strlen(recordTerminator));
		memcpy(record, _recordBuf, *nBytesRead);
		record[*nBytesRead] = '\0';

		_nBytes = _nBytes - *nBytesRead;

		// Copy any remaining bytes in the recordBuf from the "end" to
		// the start so we don't lose them.
		//
		if (_nBytes > 0)
		{
			memcpy(_recordBuf, _recordBuf+*nBytesRead, _nBytes);
			dprintf("Seabird/%s::readRecord: copied %d bytes to start of recordBuf",
					name(), _nBytes);
		}

		return DeviceIF::Ok;
	}
}

#endif

DeviceIF::Status Seabird25pTask::processRecord(unsigned char *record, int nBytes)
{
	_sbe25p->processRecord(record, nBytes);

	return DeviceIF::Ok;

}

void Seabird25pTask::standby(void)
{
	char buf[10];
	sprintf(buf,  "\r\n" );
	_device->write(buf, strlen(buf));
}

void Seabird25pTask::halt(void)
{
	char buf[10];
	sprintf(buf,  "\x1a" );
	_device->write(buf, strlen(buf));
}

