#include "OCR507.h"
#include "Syslog.h"
#include <sys/socket.h>
#include <sys/inline.h>

#define MaxRecordBytes 60 
#define ReadTimeout 10000
#define InvalidPmt -9999999.

// Serial parameters
#define Baud 19200
#define DataBits 8
#define StopBits 1
#define Parity "NONE"
extern char *memstr(char *haystack, char *needle, int size);

OCR507Log::OCR507Log(const char *filename, DataLog::FileFormat fileFormat) 
  : DataLogWriter(filename, fileFormat, AutoTimeStamp)
{
char name[20];

  for (int i = 0; i < NUM_OCR_CHANNELS; i++) {
    sprintf(name, "Channel%d", i);
    addField(_ChannelData[i] = new IntegerData(name));
    _ChannelData[i]->setUnits("counts");
  }

  addField(_VinSense = new IntegerData("VinSense"));
  _VinSense->setUnits("volts");

  addField(_IntTemp = new IntegerData("IntTemp"));
  _IntTemp->setUnits("degrees_Celsius");

  addField(_frameCounter = new IntegerData("FrameCounter"));
  _frameCounter->setUnits("cycles");

}


OCR507Log::~OCR507Log()
{

  for (int i = 0; i < NUM_OCR_CHANNELS; i++) delete _ChannelData[i];
  delete _VinSense;
  delete _IntTemp;
  delete _frameCounter;
}


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



OCR507Driver::OCR507Driver(SerialDevice *device, Boolean verbose)
  : StreamSerialDriver("OCR507Driver", device, MaxRecordBytes, "\xd\xa", 
		       ReadTimeout)
{
  _device = device;
  _verbose = verbose;
  _log = NULL;
}



OCR507Driver::~OCR507Driver()
{
  if (_log) delete _log;
}


DeviceIF::Status OCR507Driver::initialize()
{
  _device->raw();
  return DeviceIF::Ok;
}


DeviceIF::Status OCR507Driver::readRecord(unsigned char *record,
					  int maxRecordBytes,
					  const char *recordTerminator,
					  unsigned readTimeout,
					  int *nBytesRead)
{
char buf[61];
char *position;
int discardBytes;

    buf[60] = 0x0; //null terminate

    try{_device->selectTimeout(1000);}
    catch (...) {return DeviceIF::Error;}

    int bytesRead = recv(_device->getFd(), buf, 61, MSG_PEEK);

    if (position = memstr((char *)buf, "SATDI70061", bytesRead)) {
	discardBytes = position - (char *)buf; 
        read(_device->getFd(), buf, discardBytes);
        *nBytesRead = read(_device->getFd(), record, 56);
        return DeviceIF::Ok;
    }
    return DeviceIF::Error;
}
	
DeviceIF::Status OCR507Driver::processRecord(unsigned char *record, 
					      int nRecordBytes)
{
  Boolean debug = _verbose;
  char *val;
  int ntokens = 0;
  char instrumentName[11];
  unsigned short usval;
  unsigned long ulval;
  int i;

  if (nRecordBytes != 56) {
	return DeviceIF::Error;
   }
  if (record[nRecordBytes-1] != 0xa) {
//        printf("trailer is wrong\n");
//        printf("value is 0x%x\n", record[nRecordBytes-1]);
 	return DeviceIF::Error;
  }

  //printf("OCR507Driver::processRecord - record=%s", record);
  memcpy(instrumentName, record, 10);
  instrumentName[10] = 0;
  if (!_log) {
      if (!strncmp("SATD", instrumentName, 4)) {
	_log = new OCR507Log(instrumentName, DataLog::BinaryFormat);
      }
  } 
  for (i = 0; i < 7; i++) {
	memcpy(&ulval, record+22+i*4, 4);
   	ulval = swapl(ulval);
     	_log->_ChannelData[i]->setValue(ulval);
//	printf("channel %d: %d(0x%x)\n", i, ulval, ulval);
  }
  memcpy(&usval, record+50, 2); usval = swapw(usval);
  _log->_VinSense->setValue(usval);
 // printf("Vin Sense: %d(0x%x)\n", usval, usval);
  memcpy(&usval, record+52, 2); usval = swapw(usval);
  _log->_IntTemp->setValue(usval);
 // printf("Int Temp: %d(0x%x)\n", usval, usval);
  _log->_frameCounter->setValue(record[19]);
//  printf("frame counter is %d\n", record[19]);

  _log->write();
  return DeviceIF::Ok;
}

