//=========================================================================
// Summary  : */
// Filename : StreamSerialDriver.cc
// Author   : */
// Project  : */
// Revision : 1
// Created  : 2000/08/19
// Modified : 2000/08/19
//=========================================================================
// Description :
//=========================================================================
#include <string.h>
#include "StreamSerialDriver.h"
#include "Exception.h"
#include "Syslog.h"

StreamSerialDriver::StreamSerialDriver(const char *name,
				       SerialDevice *serialDevice,
				       unsigned maxRecordBytes,
				       const char *recordTerminator,
				       unsigned readTimeout,
				       unsigned maxInitTries)
  : DeviceDriver(name)
{
  char errorBuf[512];

  _device = NULL;
  _device = serialDevice;

  _recordTerminator = strdup(recordTerminator);
  _maxRecordBytes = maxRecordBytes;

  _readTimeout = readTimeout;

  _state = DeviceIF::Initializing;

  _maxInitTries = maxInitTries;

  _timeOutCount = 0;

  // Driver defaults to maximum verbosity (assume all errors are worth
  // knowing about (this isn't always the case)
  verbose();

  // Allocate record buffer
  if ((_record = (unsigned char *)malloc(_maxRecordBytes)) == 0) {
    sprintf(errorBuf, 
	    "StreamSerialDriver::StreamSerialDriver() for %s - "
	    "malloc() of %d bytes failed", name, _maxRecordBytes);

    throw Exception(errorBuf);
  }
}


StreamSerialDriver::~StreamSerialDriver()
{
  free((void *)_recordTerminator);
  free((void *)_record);
}

//=========================================================================
void StreamSerialDriver::verbose()
{
    _showTimedOut = _showBufferFull = _showMiscException = True;
}

void StreamSerialDriver::silent()
{
    _showTimedOut = _showBufferFull = _showMiscException = False;
}

//=========================================================================

unsigned StreamSerialDriver::readTimeout()
{
    return _readTimeout;
}


void StreamSerialDriver::setReadTimeout(unsigned timeout)
{
    _readTimeout = timeout;
}


void StreamSerialDriver::run()
{
  Boolean debug = False;
  char errorBuf[512];
  DeviceIF::Status newState;

  dprintf("StreamSerialDriver::initialize()");
  // Try to initialize device
  for (int i = 0; i < _maxInitTries; i++) {
    // Initialize device; pure virtual method
    if ((newState = initialize()) == DeviceIF::Ok)
      break;
  }

  setState(newState);

  if (state() != DeviceIF::Ok) {
    // initialize() failed
    sprintf(errorBuf, "%s::initialize() failed after %d tries", 
	    name(), _maxInitTries);
    
    onFailedInit();

    //    throw Exception(errorBuf);
  }

  if( _device ) {
       try {
	    _device->flushReceiveBuf();
       }
       catch (...) {
	    setState(DeviceIF::Error);
       }
  } 
  else {
       Syslog::write("StreamSerialDriver: run -- Serial Device is not defined!");
       Syslog::write("StreamSerialDriver: Are you sure you setSerialDevice'ed in my child?\n");
  }

  Boolean readError;
  int nBytesRead;

  dprintf("StreamSerialDriver::run() - start main loop");

  while (True) {

    nBytesRead = 0;

    // Prepare for data acquisition, etc
    newState = beginCycle();
    setState(newState);

    dprintf("StreamSerialDriver::run() - call readRecord()");

    // Read data record from device
    newState = readRecord(_record, _maxRecordBytes, _recordTerminator,
			  _readTimeout, &nBytesRead);

    setState(newState);

    if (newState == DeviceIF::Ok) {
      // Process device data record; pure virtual method
      newState = processRecord(_record, nBytesRead);
      setState(newState);
    }

    // Check for command, then process it
    if (!(_Child_Processes_Own_Commands))
      processCommand();
    setState(newState);
  }
}



Boolean StreamSerialDriver::setState(DeviceIF::Status newState)
{

  if (newState == _state) {
    // No change in state
    return False;
  }
  
  _state = newState;

  // Trigger event for subscribers
  triggerEvent(newState);

  // State changed
  return True;
}


DeviceIF::Status StreamSerialDriver::state()
{
  return _state;
}


DeviceIF::Status StreamSerialDriver::readRecord(unsigned char *record,
						int maxRecordBytes,
						const char *recordTerminator,
						unsigned readTimeout,
						int *nBytesRead)
{
  Boolean debug = False;
  dprintf("StreamSerialDriver::readRecord()");
  Boolean readError = False;
  
  if( _device ) {
       try {
	    
	    // Read data record from device
	    *nBytesRead = _device->readUntil((char *)record, maxRecordBytes, 
					     (char *)recordTerminator, 
					     readTimeout);

	    if(*nBytesRead == -1) { 
		onError();
		readError = -1;
	    } else {
		//we've gotten some stuff, so it's all good
		_timeOutCount = 0;
	    }
       }
       catch (SerialDevice::TimedOut) {
	    readError = True;
	    
	    if( _showTimedOut )
		 Syslog::write("%s::readRecord() - serial device timed out", name());
	    
	    onError();
       }
       catch (SerialDevice::CommsFailure) {
	   readError = True;
	
	   fprintf(stdout, "Name ok: %s\n", name());

	   Syslog::write("%s::readRecord() - serial device comms failure", name());
   
	   onError();
       }
       catch (SerialDevice::BufferFull) {
	    readError = True;
	    
	    if( _showBufferFull )
		 Syslog::write("%s::readRecord() - serial device buffer full", name());
	    
	    onBufferFull();
       }
       catch (Exception e) {
	    readError = True;
	    
	    if( _showMiscException )
		 Syslog::write("%s::readRecord() - caught exception:  abort", name());
	    
	    onException();
	    throw;
       }
  }
  else
       Syslog::write("%s::readRecord -- Serial device not defined");

  dprintf("StreamSerialDriver::readRecord() - done");

  if (readError)
    return DeviceIF::Error;
  else
    return DeviceIF::Ok;
}

void StreamSerialDriver::onError()
{
    if(++_timeOutCount < _timeOutLimit) {
	errorState();
    } else {
	failureState();
    }
}

void StreamSerialDriver::onBufferFull()
{
    Syslog::write("%s::onBufferFull() - the buffer of this device is full.  Deal.");
}

DeviceIF::Status StreamSerialDriver::beginCycle()
{
  Boolean debug = False;
  dprintf("StreamSerialDriver::beginCycle()");
  return DeviceIF::Ok;
}




