/****************************************************************************/
/* 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 <ioctl.h>
#include <errno.h>
//#include <iostream.h>
#include <time.h>
#include <TimeP.h>
#include <math.h>
#include <string.h>
#include <FloatAttribute.h>
#include <AttributeParser.h>
#include <StringAttribute.h>
#include <IntegerAttribute.h>
#include "Seabird.h"
#include "Syslog.h"
#include "CtdIF.h"
#include "System.h"

// keep these here to obfuscate them
#define BAUD 4800
#define PARITY "EVEN"
#define STOP_BITS 1
#define DATA_BITS 7
#define READ_TIMEOUT 1000
#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 );
  //added copy of config file to log directory 6/3/03 dg

  System::copyToLogDir( 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 ) );

     attributes.add( new FloatAttribute("SOc","SOc", &SOc ) );
     attributes.add( new FloatAttribute("BOc","BOc", &BOc ) );
     attributes.add( new FloatAttribute("Voff","Voff", &Voff ) );
     attributes.add( new FloatAttribute("TCor","TCor", &TCor ) );
     attributes.add( new FloatAttribute("PCor","PCor", &PCor ) );

     attributes.add( new IntegerAttribute("ScaleFactor", "ScaleFactor", &ScaleFactor, 0) );
     attributes.add( new FloatAttribute("DarkCounts", "DarkCounts", &DarkCounts, 0.0) );
     /*
     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") );
     attributes.add( new StringAttribute("PressureConfig", "PressureConfig", &_pressConfigFlag) );
		     
}

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\n"
		   "\tSOc  = %7.6le\n"
		   "\tBOc  = %7.6le\n"
		   "\tVoff = %7.6le\n"
		   "\tTCor = %7.6le\n"
		   "\tPCor = %7.6le\n",
		   name(),
		   T_A, T_B, T_C, T_D, T_F0,
		   C_A, C_B, C_C, C_D, C_M, EPS,
		   SOc, BOc, Voff, TCor, PCor);
}

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
  if (_device->confirm("pressure sensor range", SHORT_WAIT) == OK) {
        Syslog::write("%s:setting pressure sensor range", name());
	sprintf(buf,"0\xd");
	_device->write(buf, strlen(buf));
  }
  if (_device->confirm("pressure temperature compensation", SHORT_WAIT)==OK) {
 	Syslog::write("%s:setting pressure temperature comp value",name());	
	sprintf(buf,"0\xd");
	_device->write(buf, strlen(buf));
  }

/*
  if (!strcmp(_pressConfigFlag, "Y")) {
     printf("sending pressure config cmds\n");
     sprintf(buf, "1500\xd"); 
     _device->write(buf, strlen(buf));
     _device->confirm("new value = ", SHORT_WAIT);
     sprintf(buf, "1500\xd");
     _device->write(buf, strlen(buf));
  }
*/

  /* min freq for pump turn on */
  Syslog::write("Seabird/%s: setting pump freq...\n", name());
  sprintf(buf,  "1500\xd" );   
  // LOW ENOUGH SO THAT PUMP IS ALWAYS ON
  //JR and Jim B. 1-18-00  changed from 3500 to 1500 dg 4-26-03 
  _device->write(buf, strlen(buf));
  
  if (_device->confirm("stop CTD on upcast", SHORT_WAIT) == OK) {
  	Syslog::write("Seabird/%s: setting upcast...\n", name());
  	sprintf(buf,  "n\xd" );
  	_device->write(buf, strlen(buf));
  } else {
	return DeviceIF::Error;
  }
      
  if (_device->confirm("battery type", SHORT_WAIT) == OK) {
	Syslog::write("Seabird/%s: setting battery type...\n", name());
  	sprintf(buf,  "A\xd" );
  	_device->write(buf, strlen(buf));
  } else {
	return DeviceIF::Error;
  }

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

  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;
}
 
#if 1
///////////////////////////////////////////////////////////////////////
// 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;
  int nBytes = 0;

  // 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
    // Data was recv()ed from the device
    //
    nBytes += recv(_device->getFd(), (char*)(_recordBuf+nBytes),
                    (maxRecordBytes - nBytes - 1), MSG_PEEK);

      // 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);
      for (i = 0; i < nBytes; i++) {
        dprintf("%d ", _recordBuf[i]);
	if (_recordBuf[i] == *recordTerminator) {
	  eor = _recordBuf+i;
	  break;
        }
      }
      dprintf("\n");

      if (eor != (char *)NULL)
      {
	// Got a complete record
	//
	dprintf("Seabird/%s::readRecord() - got complete record\n", name);
	noRecord = False;
	readError = False;
	read(_device->getFd(), (char *)(_recordBuf), nBytes);
	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;
	ioctl(_device->getFd(), TIOCFLUSH, 0);
      }

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

  }

  // 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';

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

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

  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);
    //
    // rsm 28 Mar 07: Compute salinity from conductivity, temperature and
    // presssure:
    cndr      = 10.*read_cond/sw_c3515();
    salinity  = sw_salt( cndr, 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());
      Syslog::write("Seabird: reply is %s\n", reply);
      dprintf("Seabird/%s: error reading voltages\n", name());
      errorFlag = True;
    }
    offset+=3;
  }
  if (errorFlag) return DeviceIF::Error;
 
  clock_gettime(CLOCK_REALTIME,&cond_readtime);
  
  _output->data.conductivity = read_cond;
  _output->data.temperature  = read_temp;
  _output->data.salinity     = salinity;
  _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;
  
}
//
// The following routines are ported from the CSIRO repository:
// http://www.marine.csiro.au/datacentre/ext_docs/CSIRO_MatLAB_Seawater_Library.pdf
//
double Seabird::sw_salt(double cndr, double T, double P)
{
// SW_SALT    Salinity from cndr, T, P
//=========================================================================
// SW_SALT  $Id: Seabird.cc,v 1.22 2009/09/22 20:34:27 rob Exp $
//          Copyright (C) CSIRO, Phil Morgan 1993.
//
// USAGE: S = sw_salt(cndr,T,P)
//
// DESCRIPTION:
//   Calculates Salinity from conductivity ratio. UNESCO 1983 polynomial.
//
// INPUT:
//   cndr = Conductivity ratio     R =  C(S,T,P)/C(35,15(IPTS-68),0) [no units]
//   T    = temperature [degree C (ITS-90)]
//   P    = pressure    [db]
//
// OUTPUT:
//   S    = salinity    [psu      (PSS-78)]
//
// AUTHOR:  Phil Morgan 93-04-17, Lindsay Pender (Lindsay.Pender@csiro.au)
//
// DISCLAIMER:
//   This software is provided "as is" without warranty of any kind.
//   See the file sw_copy.m for conditions of use and licence.
//
// REFERENCES:
//    Fofonoff, P. and Millard, R.C. Jr
//    Unesco 1983. Algorithms for computation of fundamental properties of
//    seawater, 1983. _Unesco Tech. Pap. in Mar. Sci._, No. 44, 53 pp.
//=========================================================================

// Modifications
// 03-12-12. Lindsay Pender, Converted to ITS-90.

// CALLER: general purpose
// CALLEE: sw_sals.m sw_salrt.m sw_salrp.m


//----------------------------------
// rsm 27 Mar 07 This version takes only scalar inputs.
//----------------------------------
//


//-------
// BEGIN
//-------
   double R, rt, Rp, Rt, S;
   R  = cndr;
   rt = sw_salrt(T);
   Rp = sw_salrp(R,T,P);
   Rt = R/(Rp*rt);
   if( Rt <= 0. ) return 0.;
   S  = sw_sals(Rt,T);
   return S;
}

double Seabird::sw_salrt( double T)
{
// SW_SALRT   Conductivity ratio   rt(T)     = C(35,T,0)/C(35,15,0)
//=========================================================================
// SW_SALRT  $Id: Seabird.cc,v 1.22 2009/09/22 20:34:27 rob Exp $
//           Copyright (C) CSIRO, Phil Morgan 1993.
//
// USAGE:  rt = sw_salrt(T)
//
// DESCRIPTION:
//    Equation rt(T) = C(35,T,0)/C(35,15(IPTS-68),0) used in calculating
//       salinity.
//    UNESCO 1983 polynomial.
//
// INPUT:
//   T = temperature [degree C (ITS-90)]
//
// OUTPUT:
//   rt = conductivity ratio  [no units]
//
// AUTHOR:  Phil Morgan 93-04-17, Lindsay Pender (Lindsay.Pender@csiro.au)
//
// DISCLAIMER:
//   This software is provided "as is" without warranty of any kind.
//   See the file sw_copy.m for conditions of use and licence.
//
// REFERENCES:
//    Fofonoff, P. and Millard, R.C. Jr
//    Unesco 1983. Algorithms for computation of fundamental properties of
//    seawater, 1983. _Unesco Tech. Pap. in Mar. Sci._, No. 44, 53 pp.
//=========================================================================

// Modifications
// 03-12-12. Lindsay Pender, Converted to ITS-90.

// CALLER: sw_salt
// CALLEE: none

// rt = rt(T) = C(35,T,0)/C(35,15,0)
// Eqn (3) p.7 Unesco.

   double T68, c0, c1, c2, c3, c4, rt;

   T68 = T * 1.00024;

   c0 =  0.6766097;
   c1 =  2.00564e-2;
   c2 =  1.104259e-4;
   c3 = -6.9698e-7;
   c4 =  1.0031e-9;

   rt = c0 + (c1 + (c2 + (c3 + c4*T68)*T68)*T68)*T68;

   return rt;
}


double Seabird::sw_salrp( double R, double T, double P)
{
// SW_SALRP   Conductivity ratio   Rp(S,T,P) = C(S,T,P)/C(S,T,0)
//=========================================================================
// SW_SALRP   $Id: Seabird.cc,v 1.22 2009/09/22 20:34:27 rob Exp $
//            Copyright (C) CSIRO, Phil Morgan 1993.
//
// USAGE:  Rp = sw_salrp(R,T,P)
//
// DESCRIPTION:
//    Equation Rp(S,T,P) = C(S,T,P)/C(S,T,0) used in calculating salinity.
//    UNESCO 1983 polynomial.
//
// INPUT: (All must have same shape)
//   R = Conductivity ratio  R =  C(S,T,P)/C(35,15(IPTS-68),0) [no units]
//   T = temperature [degree C (ITS-90)]
//   P = pressure    [db]
//
// OUTPUT:
//   Rp = conductivity ratio  Rp(S,T,P) = C(S,T,P)/C(S,T,0)  [no units]
//
// AUTHOR:  Phil Morgan 93-04-17, Lindsay Pender (Lindsay.Pender@csiro.au)
//
// DISCLAIMER:
//   This software is provided "as is" without warranty of any kind.
//   See the file sw_copy.m for conditions of use and licence.
//
// REFERENCES:
//    Fofonoff, P. and Millard, R.C. Jr
//    Unesco 1983. Algorithms for computation of fundamental properties of
//    seawater, 1983. _Unesco Tech. Pap. in Mar. Sci._, No. 44, 53 pp.
//=========================================================================

// Modifications
// 03-12-12. Lindsay Pender, Converted to ITS-90.

// CALLER: sw_salt
// CALLEE: none

//-------------------
// eqn (4) p.8 unesco.
//-------------------

   double T68,d1,d2,d3,d4,e1,e2,e3,Rp;

   T68 = T * 1.00024;

   d1 =  3.426e-2;
   d2 =  4.464e-4;
   d3 =  4.215e-1;
   d4 = -3.107e-3;

   e1 =  2.070e-5;
   e2 = -6.370e-10;
   e3 =  3.989e-15;

   Rp = 1 + ( P*(e1 + e2*P + e3*P*P) )/
       (1 + d1*T68 + d2*T68*T68 +(d3 + d4*T68)*R);

   return Rp;
}

double Seabird::sw_sals(double Rt, double T)
{
// SW_SALS    Salinity of sea water
//=========================================================================
// SW_SALS  $Id: Seabird.cc,v 1.22 2009/09/22 20:34:27 rob Exp $
//          Copyright (C) CSIRO, Phil Morgan 1993.
//
// USAGE:  S = sw_sals(Rt,T)
//
// DESCRIPTION:
//    Salinity of sea water as a function of Rt and T.
//    UNESCO 1983 polynomial.
//
// INPUT:
//   Rt = Rt(S,T) = C(S,T,0)/C(35,T(IPTS-68),0)
//   T  = temperature [degree C (ITS-90)]
//
// OUTPUT:
//   S  = salinity    [psu      (PSS-78)]
//
// AUTHOR:  Phil Morgan 93-04-17, Lindsay Pender (Lindsay.Pender@csiro.au)
//
// DISCLAIMER:
//   This software is provided "as is" without warranty of any kind.
//   See the file sw_copy.m for conditions of use and licence.
//
// REFERENCES:
//    Fofonoff, P. and Millard, R.C. Jr
//    Unesco 1983. Algorithms for computation of fundamental properties of
//    seawater, 1983. _Unesco Tech. Pap. in Mar. Sci._, No. 44, 53 pp.
//=========================================================================

// Modifications
// 03-12-12. Lindsay Pender, Converted to ITS-90.

// CALLER: sw_salt
// CALLEE: none

//--------------------------
// eqn (1) & (2) p6,7 unesco
//--------------------------

   double del_T68,a0,a1,a2,a3,a4,a5,b0,b1,b2,b3,b4,b5,k,Rtx,del_S,S;

   del_T68 = T * 1.00024 - 15;

   a0 =  0.0080;
   a1 = -0.1692;
   a2 = 25.3851;
   a3 = 14.0941;
   a4 = -7.0261;
   a5 =  2.7081;

   b0 =  0.0005;
   b1 = -0.0056;
   b2 = -0.0066;
   b3 = -0.0375;
   b4 =  0.0636;
   b5 = -0.0144;

   k  =  0.0162;

   Rtx   = sqrt(Rt);
   del_S = (del_T68 / (1+k*del_T68) ) * 
      ( b0 + (b1 + (b2+ (b3 + (b4 + b5*Rtx)*Rtx)*Rtx)*Rtx)*Rtx);

   S = a0 + (a1 + (a2 + (a3 + (a4 + a5*Rtx)*Rtx)*Rtx)*Rtx)*Rtx;

   S = S + del_S;

   return S;
}


double Seabird::sw_c3515(void)
{
// SW_C3515   Conductivity at (35,15,0)
//=========================================================================
// SW_c3515  $Id: Seabird.cc,v 1.22 2009/09/22 20:34:27 rob Exp $
//       //   Copyright (C) CSIRO, Phil Morgan 1993.
//
// USAGE:  c3515 = sw_c3515
//
// DESCRIPTION:
//   Returns conductivity at S=35 psu , T=15 C [ITPS 68] and P=0 db).
//
// INPUT: (none)
//
// OUTPUT:
//   c3515  = Conductivity   [mmho/cm == mS/cm]
//
// AUTHOR:  Phil Morgan 93-04-17  (morgan@ml.csiro.au)
//
// DISCLAIMER:
//   This software is provided "as is" without warranty of any kind.
//   See the file sw_copy.m for conditions of use and licence.
//
// REFERENCES:
//    R.C. Millard and K. Yang 1992.
//    "CTD Calibration and Processing Methods used by Woods Hole
//     Oceanographic Institution"  Draft April 14, 1992
//    (Personal communication)
//=========================================================================

// CALLER: none
// CALLEE: none
//

   return 42.914;

//-------------------------------------------------------------------------
}

 
#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
