/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : Seabird.cc                                                        */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#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 <errno.h>
#include <iostream.h>
#include <time.h>
#include <TimeP.h>
#include <math.h>
#include <FloatAttribute.h>
#include <AttributeParser.h>
#include <StringAttribute.h>
#include <IntegerAttribute.h>
#include "Seabird.h"
#include "Syslog.h"
#include "CtdIF.h"

// keep these here to obfuscate them
#define BAUD 4800
#define PARITY "EVEN"
#define STOP_BITS 1
#define DATA_BITS 7
#define READ_TIMEOUT 900
#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.
//
Seabird::Seabird(SerialDevice *serialDevice, char *configFile, char *instName )
     : StreamSerialDriver(instName, serialDevice, MaxRecordBytes, "\xa",
			  READ_TIMEOUT),
       attributes(instName)
{
  char seabirdOutputName[256];

  // Use the instance name to create a unique shared memory area
  //
  strcpy(seabirdOutputName, instName);
  strcat(seabirdOutputName, SeabirdOutputName);
  _output = new SeabirdOutput(seabirdOutputName, SharedData::ReadWrite);

  createCTDAttributes();
  loadCTDConfigFile( configFile );
  reportCTDAttributes();

  depthSensorRunning = False;

  Syslog::write("Seabird/%s::Seabird() - create interface to depth sensor...",
		instName);
  try {
       depthSensor = new DepthSensorIF("depthSensor");
       depthSensorRunning = True;
  } 
  catch(SharedObjectClient::MissingServer e) {
    depthSensor_pres = 10.1;
    depthSensorRunning = False;
    Syslog::write("Seabird/%s -- DepthSensor server is not running. "
		  "Using default pres of %lf", instName, depthSensor_pres);
  }
  
  Syslog::write("Seabird/%s -- constructing Log...\n", instName);
  try {
    _log = new SeabirdLog(this, instName);
  }
  catch ( ... ) {
    throw Exception("Seabird.cc - CtdLog constructor failed\n");
  }

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

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

void Seabird::createCTDAttributes()
{
     attributes.add( new FloatAttribute("t_a","t_a", &T_A ) );
     attributes.add( new FloatAttribute("t_b","t_b", &T_B ) );
     attributes.add( new FloatAttribute("t_c","t_c", &T_C ) );
     attributes.add( new FloatAttribute("t_d","t_d", &T_D ) );
     attributes.add( new FloatAttribute("t_f0","t_f0", &T_F0 ) );

     attributes.add( new FloatAttribute("c_a","c_a", &C_A ) );
     attributes.add( new FloatAttribute("c_b","c_b", &C_B ) );
     attributes.add( new FloatAttribute("c_c","c_c", &C_C ) );
     attributes.add( new FloatAttribute("c_d","c_d", &C_D ) );
     attributes.add( new FloatAttribute("c_m","c_m", &C_M ) );

     attributes.add( new FloatAttribute("eps","eps", &EPS ) );

     /*
     NUMVOLTAGES = 6;
     v1name = "v1";
     v2name = "v2";
     v3name = "v3";
     v4name = "v4";
     v5name = "v5";
     v6name = "v6";
     */
     
     attributes.add( new IntegerAttribute("NUMVOLTAGES","NUMVOLTAGES",(long *)&NUMVOLTAGES) );
    
     attributes.add( new StringAttribute("v1name","v1name",&_output->data.v1name,"v1") );
     attributes.add( new StringAttribute("v2name","v2name",&_output->data.v2name,"v2") );
     attributes.add( new StringAttribute("v3name","v3name",&_output->data.v3name,"v3") );
     attributes.add( new StringAttribute("v4name","v4name",&_output->data.v4name,"v4") );
     attributes.add( new StringAttribute("v5name","v5name",&_output->data.v5name,"v5") );
     attributes.add( new StringAttribute("v6name","v6name",&_output->data.v6name,"v6") );

		     
}

void Seabird::reportCTDAttributes()
{
     Syslog::write("CTD/%s -- Calibration constants:\n"
		   "\tT_a  = %7.6le\n"
		   "\tT_b  = %7.6le\n"
		   "\tT_c  = %7.6le\n"
		   "\tT_d  = %7.6le\n"
		   "\tT_f0 = %lf\n"
		   "\tC_a  = %7.6le\n"
		   "\tC_b  = %7.6le\n"
		   "\tC_c  = %lf\n"
		   "\tC_d  = %7.6le\n"
		   "\tC_m  = %4.3lf\n"
		   "\tEPS  = %7.6le", name(),
		   T_A, T_B, T_C, T_D, T_F0,
		   C_A, C_B, C_C, C_D, C_M, EPS );
}

void Seabird::loadCTDConfigFile( char *filename )
{
     Syslog::write("Seabird/%s -- Loading CTD constants from %s\n", 
		   name(), filename );
     AttributeParser::parse(filename, &attributes); 
     // check that numvoltages is between 0 and 6, inclusively
     if ((NUMVOLTAGES > 6)||(NUMVOLTAGES<0))
       {
	 Syslog::write("Seabird/%s::loadCTDConfigFile -- error in number of voltages",
		       name());
	 throw Exception("Seabird::loadCTDConfigFile -- error in number of voltages");
       }
     
}


Seabird::~Seabird()
{
  // Send a NULL character to stop logging
  //
  char buf[30];
  sprintf(buf,"\x1a\xd");
  _device->write(buf,strlen(buf));

  delete _output;
  delete depthSensor;
  delete _log ;
}


DeviceIF::Status Seabird::initialize()
{
  char buf[30];
  int i;
   
  _device->commsDebugMode(SerialDevice::DebugOff);
 
  Syslog::write("Seabird/%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.  Then, if not, send a Ctrl-Z in case we are data
     logging, then send a few returns to get past the set date part. */
  
  sprintf(buf,"\xd");
  _device->write(buf,strlen(buf));
  
  if (_device->confirm("S>",SHORT_WAIT) == -1) {
    Syslog::write("Seabird/%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("Seabird/%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,"\x1a\xd");
    _device->write(buf,strlen(buf));
    Syslog::write("Seabird/%s: first Ctrl-Z  sent...\n", name());
      
    if (_device->confirm("S>",LONG_WAIT) == -1) {
      i = _device->confirm("power on", 4000 );
      if (i) {
	Syslog::write("Seabird/%s: confirmed power on returns: %d\n",name(), i);
      } 
      if (i==-1) { 
	Syslog::write("Seabird/%s: no power on detected yet...\n", name());
	sprintf(buf,"\r\r\r");
	_device->write(buf, strlen(buf));
	i = _device->confirm("power on", 4000);
	  
	if (i==-1) {
	  Syslog::write("Seabird/%s: no power on detected yet...\n", name());
	  sprintf(buf,"\r\r\r");
	  _device->write(buf, strlen(buf));
	      
	  i = _device->confirm("power on", 8000);
	      
	  _device->clearPort(); 
	  if (i==-1) {
	    //	    fprintf(stderr, "%s",error.msg);
	    return DeviceIF::Error;
	    //throw Exception("Seabird: no power on detected..bailing!\n");
	  }
	}
      }
    }
  }
  
  
  /* configure */
  
  Syslog::write("Seabird/%s: sending configure commands...(%d)\n", name(), getppid());
  
  sprintf(buf,"CC\xd");
  _device->write(buf, strlen(buf));
  if ( _device->confirm("Y/N ? ", SHORT_WAIT) == -1 ) {
    return DeviceIF::Error;
    
    //    throw Exception("Seabird: bailout #1\n");
  }
  
  /* send yes to 1st prompt */
  
  sprintf(buf,  "Y\xd" );
  _device->write(buf, strlen(buf));
  
  if ( _device->confirm( "^Y/N ? ", SHORT_WAIT) == -1 ) {
    return DeviceIF::Error;
	    
    //    throw Exception("Seabird: bailout #2\n");
  }

  /* send Ctrl-Y (0x19, 25 dec) */
   
  sprintf(buf,  "\x19\xd" );
  _device->write(buf, strlen(buf));
 
  if ( _device->confirm( "new value = ", SHORT_WAIT) == -1 ) {
    // throw Exception("Seabird: init failed waiting for scans line\n");
    return DeviceIF::Error;
	    
  }
   
  /* average 1 scans */
  Syslog::write("Seabird/%s: setting scans...\n", name());
  sprintf(buf,  "1\xd" );
  _device->write(buf, strlen(buf));
   
  if ( _device->confirm( "new value = ", SHORT_WAIT) == -1 ) {
    //    throw Exception("Seabird: init failed waiting for pump freq msg \n");
    return DeviceIF::Error;
    
  }
   
   
  /*
    (from Odyssey Code)
     
    Discovered that one unit asks for the pressure range and temperature
    compensation values and one doesn't, hence the need to distinguish them
    during initialization sequence.  May need to pay more attention to this
    should it prove brittle. (BAM, 27-Jan-1998) */
   
  //#ifdef SBE_PRES_RANGE  // CURRENT TESTED CTD DOES NOT ASK FOR THIS 
  //JR - 12/9/99
   
  /* pressure sensor range */
   
   
  /* min freq for pump turn on */
  Syslog::write("Seabird/%s: setting pump freq...\n", name());
  sprintf(buf,  "3500\xd" );   
// LOW ENOUGH SO THAT PUMP IS ALWAYS ON
  //JR and Jim B. 1-18-00  
  _device->write(buf, strlen(buf));
   
  if ( _device->confirm( "new value = ", LONG_WAIT) == -1 ) {
    //throw Exception("Seabird::initialize() failed waiting for upcast msg\n");
    return DeviceIF::Error;

  }
				/* stop on upcast? */
  /* send a "n" instead of merely a carriage return,
     in case the CTD has pooped since last initialization */
  Syslog::write("Seabird/%s: setting upcast...\n", name());
  sprintf(buf,  "n\xd" );
  _device->write(buf, strlen(buf));
      
  if ( _device->confirm( "new", LONG_WAIT) == -1 ) {
    //    throw Exception("Seabird::initialize() failed while setting upcast\n");
    return DeviceIF::Error;

  }
				/* battery type */
  Syslog::write("Seabird/%s: setting battery type...\n", name());
  sprintf(buf,  "\xd" );
  _device->write(buf, strlen(buf));

  if ( _device->confirm( "new value = ", SHORT_WAIT) == -1 ) {
    //throw Exception("Seabird::initialize() failed setting battery type\n");
    return DeviceIF::Error;

  }
				/* external voltages */
  Syslog::write("Seabird/%s: setting external voltages to %d...(%d)\n",
		name(), NUMVOLTAGES, getppid());
  sprintf(buf,  "%d\xd",NUMVOLTAGES );
  _device->write(buf, strlen(buf));
     
  if ( _device->confirm( "new value =", SHORT_WAIT) == -1 ) {
    //     throw Exception("Seabird::initialize() failed setting external voltages\n");
    return DeviceIF::Error;
    
  }
  // now loop for all voltages
  for (i=1;i<=NUMVOLTAGES;i++)
    {
      Syslog::write("Seabird/%s::initialize() - confirming voltage...\n", name());
      sprintf(buf,  "Y\xd" );
      _device->write(buf, strlen(buf));
      
      if (i < NUMVOLTAGES)
	{
	  if (_device->confirm("new value =", SHORT_WAIT) == -1)
	    
	    {
	      Syslog::write("%s...failed on  %d\n", name(), i);
	      //      throw Exception("Seabird::initialize() failed on external voltage setup\n");
return DeviceIF::Error;

	    }
	}
    }
				/* voltage 1 */
  //  _device->commsDebugMode(SerialDevice::DebugOn);
  if ( _device->confirm( "S>", 5*LONG_WAIT) == -1 ) {
    Syslog::write("Seabird/%s: error reading S> prompt\n", name());
    //    throw Exception("Seabird::initialize() failed confirming voltage\n");
    return DeviceIF::Error;
 
  }
				/* disable switch */
  Syslog::write("Seabird/%s::initialize() - disabling switch...\n", name());
  sprintf(buf,  "SD\xd" );
  _device->write(buf, strlen(buf));

  if ( _device->confirm( "S>", SHORT_WAIT) == -1 ) {
    //throw Exception("Seabird::initialize() failed disabling switch\n");
    return DeviceIF::Error;

  }  
				/* DS to display setup into syslog */
  Syslog::write("Seabird/%s: sending DS command...\n", name());
  sprintf(buf,  "DS\xd" );
  _device->write(buf, strlen(buf));
     
  if ( _device->confirm( "S>", 5*LONG_WAIT) == -1 ) {       
    //    throw Exception("Seabird::initialize() failed on DS command\n");
    return DeviceIF::Error;

  }

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

  // Start logging
  sprintf(buf,  "GL\xd" );
  _device->write(buf, strlen(buf));

  // Are you Sure?
  if (_device->confirm("Y/N ? ",SHORT_WAIT) == -1) {
    //throw Exception("Seabird: failed waiting for yes/no prompt\n");
    return DeviceIF::Error;

  }

  sprintf(buf,  "Y\xd" );
  _device->write(buf, strlen(buf));
  // Cntrl-Y to confirm
  if (_device->confirm("^Y/N ? ",SHORT_WAIT) == -1) {
    //    throw Exception("Seabird: failed waiting for ctrl-yes/no prompt\n");
return DeviceIF::Error;

  }
  
  //\x19 is Ctrl-Y (!)
  sprintf(buf,  "\x19\xd" );
  _device->write(buf, strlen(buf));
      
  if (_device->confirm("S>",SHORT_WAIT) == -1) {
    //    throw Exception("Seabird: failed waiting for S> prompt\n");
    return DeviceIF::Error;

  }
  //done with init
  Syslog::write("Ctd/%s:initialize() - Logging Started...\n", name());

  _output->data.deviceReady = True;
  _output->write();
  Syslog::write("Ctd/%s:initialize() - ready!", name());

  return DeviceIF::Ok;
}
 
///////////////////////////////////////////////////////////////////////
// readRecord() for socket implementations only!
///////////////////////////////////////////////////////////////////////
DeviceIF::Status Seabird::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;

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

  // Set up for select() call
  //
  fd_set readFds;
  struct timeval timeout_tv;
  FD_ZERO(&readFds);
  FD_SET(_device->getFd(), &readFds);

  // Main loop
  //
  // Keep recv()ing until a complete record is read or
  // until my time has expired.
  //
  while (noRecord)
  {
    // Convert from milliseconds to timeval format
    timeout_tv.tv_sec  = (readTimeout-(t1-t0)) / 1000;
    timeout_tv.tv_usec = ((readTimeout-(t1-t0)) % 1000) * 1000;
    dprintf("Waiting on select() for %d ms\n", readTimeout);

    // Wait until data is available or my time is up
    //
    switch (select(_device->getFd() + 1, &readFds, 0, 0, &timeout_tv)) {
    case -1:
      Syslog::write("Seabird/%s::select() failed\n", name());
      readError = True;
      break;

    case 0:
      // My time has expired without a complete record
      //
      Syslog::write("Seabird/%s::select() timeout\n", name());
      break;

    default:
      // Data was recv()ed from the device
      //
      _nBytes += recv(_device->getFd(), (char*)(_recordBuf+_nBytes),
		      (maxRecordBytes - _nBytes - 1), 0);

      // Look for end-of-record marker in the buffer
      //
      _recordBuf[_nBytes] = '\0';
      dprintf("Seabird/%s::readRecord() - recv()ed %d bytes %s\n", name(),
	      _nBytes, _recordBuf);
      if (eor = strstr((char*)_recordBuf, recordTerminator))
      {
	// Got a complete record
	//
	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.
	//
	Syslog::write("SerialDevice::Buffer full!");
	readError = True;
	_nBytes = 0;
      }
      break;
    }

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

    // Continue recv()ing, but update the remaining time
    //
    readTimeout -= (t1 - t0);
  }

  // No record yet and were done. Return Error so that processRecord
  // isn't called with a bad record.
  //
  if (readError)
  {
    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';
    dprintf("Seabird/%s::readRecord(): got record %s from %d total bytes",
	    name(), record, _nBytes);

    _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;
  }
}

DeviceIF::Status Seabird::processRecord(unsigned char *record, int nBytes)
{
  Boolean debug = True;

  if (nBytes == 0)
  {
    dprintf("Seabird/%s: Null record", name());
    return DeviceIF::Ok;
  }

  char *reply = (char *)record;

  int val1, val2, val3, val4, nconv, nc;

  nconv = sscanf(reply, "%2x%2x%2x%n", &val1, &val2, &val3, &nc);

  if (nconv == 3 && nc == 6) {
    // value = val1*256+val2+val3/256
    read_tfreq = (val1*256) + val2 +((double)val3/256);
    read_temp = calculate_Temp(read_tfreq);
    // dprintf("Seabird: tfreq: %f, temp: %f\n",read_tfreq,read_temp);
    clock_gettime(CLOCK_REALTIME,&temp_readtime);
  }
  else {
    Syslog::write("Seabird/%s: error sscanfing %d bytes in reply: %s\n", 
		  name(), nBytes, reply);
  }
      
  nconv = sscanf(reply+6, "%2x%2x%2x%n",&val1,&val2,&val3,&nc);

  if (nconv == 3 && nc == 6) {

    // value = val1*256+val2+val3/256

    read_cfreq = (val1*256) + val2 +((double)val3/256);
    read_temp = calculate_Temp(read_tfreq);
	  
    // ??!????
	  
    TimeIF::TimeSpec t;
      
    if (depthSensorRunning) {
      depthSensor->pressure(&depthSensor_pres, &t);
      depthSensor_pres = 10*depthSensor_pres;
    }
    else {
      depthSensor_pres = 10.1 ; //in dbar -- just an assumption for now...
    }
    //pres = 10*sensor(M_PRESSURE);
      
    /* THIS IS CALCULATED ABOVE in  read_temp*/
      
    //temp = sensor(WATER_TEMP)  
	  
    read_cond = calculate_Cond(0.001*read_cfreq, read_temp, depthSensor_pres);

  }
  else
  {
    Syslog::write("Seabird/%s: error sscanf'ing conductivity data string\n",
		  name());
  }
  
  offset = 16;
  for (i=0;i< NUMVOLTAGES;i++)
  {
    //      Syslog::write("Seabird: scanning voltage %d...\n",i);

    if ((i == (NUMVOLTAGES - 1)) && ((NUMVOLTAGES/2) == ((NUMVOLTAGES-1)/2)))
      offset++;

    nconv = sscanf(reply+offset,"%3x%n",&val1,&nc);

    //      Syslog::write("Seabird: nconv: %d, val1: %3x, nc: %d\n",nconv,val1,nc);
      
    if ((nconv==1)&&(nc==3))
    {
      voltages[i] = ((double)val1)/819;
      //	  Syslog::write("Seabird: value of %d is: %f\n",i+1,voltages[i]);
      //  dprintf("Seabird: value of %d is: %f\n",i+1,voltages[i]);
    }
    else
    {
      Syslog::write("Seabird/%s: error reading voltages\n", name());
      dprintf("Seabird/%s: error reading voltages\n", name());
    }
    offset+=3;
  }
  
  clock_gettime(CLOCK_REALTIME,&cond_readtime);
  
  _output->data.conductivity = read_cond;
  _output->data.temperature = read_temp;
  _output->data.cfreq = read_cfreq;
  _output->data.tfreq = read_tfreq;
  _output->data.temp_updateTime.tv_sec = temp_readtime.tv_sec;
  _output->data.temp_updateTime.tv_nsec = temp_readtime.tv_nsec;
  _output->data.cond_updateTime.tv_sec = cond_readtime.tv_sec;
  _output->data.cond_updateTime.tv_nsec = cond_readtime.tv_nsec;
  for(i=0;i<NUMVOLTAGES;i++)
    {
      _output->data.voltages[i] = voltages[i];
    }


  // empty these up
  // free(_output->data.v1name);
  //free(_output->data.v2name);
  //free(_output->data.v3name);
  //free(_output->data.v4name);
  //free(_output->data.v5name);
  //free(_output->data.v6name);


  //and now copy them
  //_output->data.v1name = strdup(v1name);
  //_output->data.v2name = strdup(v2name);
  //_output->data.v3name = strdup(v3name);
  //_output->data.v4name = strdup(v4name);
  //_output->data.v5name = strdup(v5name);
  //_output->data.v6name = strdup(v6name);


  try
    {
      _output->write();
      
    }
  catch (SharedData::AccessError error)
    {
      fprintf(stderr, "%s",error.msg);
      exit(1);
    }
  // now write to log file
  _log->write();
  time_t now = time((long*)0);
  if ((now - _lastFlush) > _flushInterval)
  {
    _lastFlush = now;
    _log->flush();
  }
  
  
#if defined (FLBS_PORT) && defined (BS_HACK)
  nconv = sscanf(reply+16,"%4x%n",&val1,&nc);
  if (nconv == 1 && nc == 4) {
    read_m_bs_voltage = 5000*val1/4095;
    
  }  
#endif
  
  return DeviceIF::Ok;

}

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

void Seabird::halt(void)
{
  char buf[10];
  sprintf(buf,  "\x1a" );
  _device->write(buf, strlen(buf));
}
/*-----------------------------------------------------------------------*
  (from Odyssey Code)

  First do temp conversion:

      lf = log( f0 / f Hz )

       T = 1 / (a + b*lf + c*lf^2 + d*lf^3)  - 273.15

  Next conductivity (uses temperature)

      C (S/m) = (a*(c kHz)^m + b*(c kHz)^2 + c + d*T) /
                (10*(1 + eps*P))
      where P is dbar and T is deg C
 *-----------------------------------------------------------------------*/


double Seabird::calculate_Temp(double f)
{
  double T;

  f = ::log(T_F0/f);

  T = 1/(T_A + (T_B + (T_C + T_D*f)*f)*f) - 273.15;
  
  return T;
}

double Seabird::calculate_Cond(double f, double t, double p)
{
  double C;

  //  Syslog::write("Seabird debugging:\n");
  // Syslog::write("C_A = %f\n C_B = %f\nC_C = %f\nC_D = %f\nC_M = %f, EPS = %f\n", C_A, C_B, C_C, C_D, C_M, EPS);
  //Syslog::write("f  = %f, t = %f, p = %f\n",f,t,p);

  C = (C_A*pow(f,C_M) + C_B*f*f +C_C +C_D*t)/(10*(1+EPS*p));

  //Syslog::write("C = %f\n",C);
  return C;
  
}
 
#if 0
// Old correcting readRecord()
  try {
    // Read data record from device
    _nBytes += _device->readUntil((char *)(record + _nBytes),
				  (maxRecordBytes - _nBytes), 
				  (char *)recordTerminator, 
				  readTimeout);
  }
  catch (SerialDevice::TimedOut) {
    // OK, keep the bytes we've read and get the rest later
    // 
    readError = True;
    Syslog::write("Seabird/%s::readRecord() - timed out after %d bytes, %s",
		  name(), _nBytes, "correcting...");
    *nBytesRead = 0;
  }
  catch (SerialDevice::BufferFull) {
    readError = True;
    Syslog::write("%s::readRecord() - buf=", name(), _recordBuf);
    Syslog::write("%s::readRecord() - serial device buffer full", name());
    *nBytesRead = _nBytes = 0; // reset
  }
  catch (Exception e) {
    readError = True;
    Syslog::write("%s::readRecord() - caught exception:%s: abort",
		  e.msg, name());
    *nBytesRead = _nBytes = 0; // reset
    throw;
  }
#endif
