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

#define HvAdjusting "HV adj"
//maximum record length is as follows:
//record number 6 bytes
//cal string    9 bytes
//pump rpm      6 bytes
//flow rpm      6 bytes
//humidity      4 bytes
//temp          4 bytes
//raw(8*60 vals)480 bytes
//trailers      3 bytes
//total         398 bytes
#define MaxRecordBytes 1024 
#define ReadTimeout 10000
#define InvalidPmt -9999999.

#define PumpOnCmd "g"
#define PMTOnCmd "o"
#define StartCmd "P"
#define StopCmd "O"
#define YesCmd "Y"

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

BiolumeLog::BiolumeLog(DataLog::FileFormat fileFormat) 
  : DataLogWriter(BiolumeLogName, fileFormat, AutoTimeStamp)
{
char name[20];

  //default long name, UNKNOWN units
  addField(_RecordNum = new IntegerData("rrr"));

  //default long name, UNKNOWN units
  addField(_CalString = new FloatData("cal_striing"));

  //average bioluminescence, photons s^-1
  addField(_AvgBiolume = new FloatData("avg_biolume"));
  _AvgBiolume->setUnits("photons s^-1");
 
  //default long name, RPM units
  addField(_PumpRPM = new IntegerData("pump"));
  _PumpRPM->setUnits("RPM");

  //System Voltage, volts
  addField(_SystemVoltage = new FloatData("system_voltage"));
  _SystemVoltage->setUnits("volts");

  //default long name, RPM units
  addField(_FlowRPM = new IntegerData("flow"));
  _FlowRPM->setUnits("RPM");

  addField(_HV_Step = new FloatData("HV step"));
  _HV_Step->setUnits("volts");

  addField(_reserved1 = new IntegerData("reserved 1"));
  addField(_reserved2 = new FloatData("reserved 2"));

  //raw fields
  for (int i=0; i < 60; i++) {
    sprintf(name,"raw_%d\0",i);
    addField(_Raw[i] = new IntegerData(name));
    _Raw[i]->setUnits("UNCALIBRATED");
  }
}


BiolumeLog::~BiolumeLog()
{

  delete _RecordNum;
  delete _CalString;
  delete _AvgBiolume;
  delete _PumpRPM;
  delete _SystemVoltage;
  delete _FlowRPM;
  delete _HV_Step;
  delete _reserved1;
  delete _reserved2;
  for (int i = 0; i < 60; i++)
    delete _Raw[i];
}


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, "\xa", 
		       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;
    }

    strcpy(cmd,PMTOnCmd);
    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;
  char *val;
  int ntokens = 0;

  record[nRecordBytes] = 0x0;  
  dprintf("BiolumeDriver::processRecord - record=%s", record);

  //skip over UBAT serial number
  val = strtok((char *)record,",");

  //read in the actual data
  if ((val = strtok(NULL,","))){
    _log->_RecordNum->setValue(atoi(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_CalString->setValue(atof(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_AvgBiolume->setValue(atof(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_PumpRPM->setValue(atoi(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_SystemVoltage->setValue(atof(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_FlowRPM->setValue(atoi(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_HV_Step->setValue(atof(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_reserved1->setValue(atoi(val));
    ntokens++;
  }

  if ((val = strtok(NULL,","))){
    _log->_reserved2->setValue(atof(val));
    ntokens++;
  }

  for (int i=0; i<60; i++) {
    if ((val = strtok(NULL,","))) {
      _log->_Raw[i]->setValue(atoi(val));
      ntokens++;
    }
  }

  if (ntokens != 69) {
    Syslog::write("BiolumeDriver::processRecord() - parse error %d", ntokens);
    return DeviceIF::Error;
  } else {
    _log->write();
  }

  return DeviceIF::Ok;
}

