#include "BiolumeDriver.h"
#include "Syslog.h"

#define HvAdjusting "HV adj"
#define MaxRecordBytes 256
#define ReadTimeout 10000
#define InvalidPmt -9999999.

#define PumpOnCmd "E"
#define StartCmd "J"
#define StopCmd "K"

// Serial parameters
#define Baud 9600
#define DataBits 8
#define StopBits 1
#define Parity "NONE"

BiolumeLog::Data::Data()
  : depth("depth"),
    pmt("biolum"),
    flowRate("flow"),
    temperature("temp")
{
}


BiolumeLog::BiolumeLog(DataLog::FileFormat fileFormat) 
  : DataLogWriter(BiolumeLogName, fileFormat, AutoTimeStamp)
{
  addField(&data.depth);
  addField(&data.pmt);
  addField(&data.flowRate);
  addField(&data.temperature);
}


BiolumeLog::~BiolumeLog()
{
}


void BiolumeLog::setFields()
{
  // Doesn't need to do anything, as BiolumeDriver::processRecord() fills
  // field values directly.
}



BiolumeDriver::BiolumeDriver(SerialDevice *device, Boolean verbose)
  : StreamSerialDriver("biolumeDriver", device, MaxRecordBytes, "\n", 
		       ReadTimeout)
{
  _verbose = verbose;
  _log = new BiolumeLog(DataLog::BinaryFormat);
}



BiolumeDriver::~BiolumeDriver()
{
  // Stop data, pump, etc
  if (_device->write(StopCmd, strlen(StopCmd)) == -1) {
      Syslog::write("BiolumeDriver::~BiolumeDriver() - "
		    "device->write() failed");
  }

  delete _log;
}


DeviceIF::Status BiolumeDriver::initialize()
{
  // Initialize serial port
  _device->setLineFormat(Baud, DataBits, StopBits, Parity);

  char cmd[10];

  try {

    // Turn on pump
    strcpy(cmd, PumpOnCmd);
    if (_device->write(cmd, strlen(cmd)) == -1) {
      Syslog::write("BiolumeDriver::initialize() - device->write() failed");
      return DeviceIF::Error;
    }

    // Reset record number and start data streaming
    strcpy(cmd, StartCmd);
    if (_device->write(cmd, strlen(cmd)) == -1) {
      Syslog::write("BiolumeDriver::initialize() - device->write() failed");
      return DeviceIF::Error;
    }
  }

  catch (Exception e) {
    Syslog::write("BiolumeDriver::initialize() - caught exception: %s",
		  e.msg);

    return DeviceIF::Error;
  }

  return DeviceIF::Ok;
}



DeviceIF::Status BiolumeDriver::processRecord(unsigned char *record, 
					      int nRecordBytes)
{
  Boolean debug = _verbose;

  dprintf("BiolumeDriver::processRecord - record=%s", record);

  enum {
    Day, TimeTag, Depth, PMT, FlowRate, Temperature, 

    // This must be last value in enumeration!
    NTokens
  };

  char *token;
  char *ptr = (char *)record;
  int nToken = 0;
  Boolean done = False;

  while ((token = strtok(ptr, ",")) != 0 && !done) {
    ptr = 0;

    switch (nToken) {

    case Day:
      // Ignore; we add our own time-tag
      break;

    case TimeTag:
      // Ignore; we add our own time-tag
      break;

    case Depth:
      _log->data.depth.setValue(atof(token));
      break;

    case PMT:
      if (!strcmp(token, HvAdjusting)) {
	// PMT is not valid during HV adjust
	_log->data.pmt.setValue(InvalidPmt);
      }
      else
	_log->data.pmt.setValue(atof(token));

      break;

    case FlowRate:
      _log->data.flowRate.setValue(atoi(token));
      break;

    case Temperature:
      _log->data.temperature.setValue(atof(token));

      // Temperature is last field we are interested in
      done = True;
      break;

    default:
      Syslog::write("BiolumeDriver::processRecord() - too many tokens?");
      return DeviceIF::Error;
    }
    nToken++;
  }

  if (nToken < NTokens) {
    Syslog::write("BiolumeDriver::processRecord() - parse error");
    return DeviceIF::Error;
  }

  _log->write();

  return DeviceIF::Ok;
}

