////////////////////////////////////////////////////////////////////////////////
//
// PURPOSE:  Dvl Driver Class.
// AUTHOR:   Rob McEwen, based on  O'Reilly's methane sensor.
// DATE:     01/3/9
// COMMENTS:
//
////////////////////////////////////////////////////////////////////////////////
//
#ifndef _DVL_H
#define _DVL_H

#define BAUD_RATE 9600
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY "NONE"

#define NBYTES              2           /* number of bytes                    */
#define MM_TO_METRES        0.001       /* mm to meters conversion            */
#define RAD_TO_DEG          (180.0/PI)  /* radians to degrees converion       */
#define EPSILON             0.00001     /* floating point zero                */
#define DOPPLER_LSB         0           /* least significant byte             */
#define DOPPLER_MSB         1           /* most significant byte              */
#define NUM_BEAMS           4           /* number of beams                    */
#define BEAM_OK                     0   /* beam status ok                     */
#define BOTTOM_BEAM1_CORRELATION    1   /* bottom-referenced correlation and  */
#define BOTTOM_BEAM1_ECHO_AMPLITUDE 2   /* echo amplitude status              */
#define BOTTOM_BEAM2_CORRELATION    4
#define BOTTOM_BEAM2_ECHO_AMPLITUDE 8
#define BOTTOM_BEAM3_CORRELATION    16
#define BOTTOM_BEAM3_ECHO_AMPLITUDE 32
#define BOTTOM_BEAM4_CORRELATION    64
#define BOTTOM_BEAM4_ECHO_AMPLITUDE 128
#define WATER_BEAM1_CORRELATION     1   /* water-referenced depth and         */
#define WATER_BEAM2_CORRELATION     4   /* correlation status                 */
#define WATER_BEAM3_CORRELATION     8
#define WATER_BEAM4_CORRELATION     16
#define ALTITUDE_TOO_SHALLOW        32

#define DVL_INBUF_SIZE              128
#define DVL_OUTBUF_SIZE             1024

                                        /* bad velocity value returned        */
#define BAD_VELOCITY                -32768

                                        /* dvlDataStatus & SerialStatus flags */
#define DVL_DATA_GOOD               0   /* Good data received from DVL        */
#define BAD_BOTTOM_TRACK_VELOCITY   1   /* bad bottom track velocity          */
#define BAD_WATER_MASS_VELOCITY     2   /* bad water track velocity           */
#define NO_DVL_RESPONSE             4   /* No response from DVL serial line   */
#define BAD_SERIAL_READ             8   /* Problem reading serial line        */
#define CHECKSUM_WRONG              16  /* Incorrect checksum from serial     */
#define BAD_BEAM_RANGE              0   /* Dvl returns 0 for a bad beam readg */

#define CM_TO_METRES        0.01        /* cm to meters conversion            */
#define cos30 0.86602540378444

enum beamIndx {BM1, BM2, BM3, BM4};     /* for indexing the 4 beams in rawRange*/
enum timeIndx {HRS, MIN, SEC, CENTISEC};/* For indexing the time bytes        */
                                        /* cartesian degrees of freedom       */
typedef enum { X_INDEX, Y_INDEX, Z_INDEX, E_INDEX } cartDof;

#include "SerialDeviceDriver.h"
#include "DvlLog.h"
#include "DvlOutput.h"
#include "DataLogWriter.h"
#include "IntegerData.h"
#include "ShortData.h"

class Dvl : public SerialDeviceDriver {

friend class DvlLog;

public:

  ////////////////////////////////////////////////////////////////////
  // Constructor
  // [input] serialDevice: Associated SerialDevice
  Dvl(SerialDevice *serialDevice, Boolean verbose);
  virtual ~Dvl();

  ////////////////////////////////////////////////////////////////////
  // Initialize device. Returned DeviceIF::Status
  // will be propagated to subscribers in other tasks.
  virtual DeviceIF::Status initialize();

  ////////////////////////////////////////////////////////////////////
  // Read a fixed-length record
  virtual DeviceIF::Status readRecord(unsigned char *record,
                                      int maxRecordBytes,
                                      const char *recordTerminator,
                                      unsigned readTimeout,
                                      int *nBytesRead);

  ////////////////////////////////////////////////////////////////////
  // Process device data record. Returned DeviceIF::Status
  // will be propagated to subscribers in other tasks.
  // [input] record: Record from device
  // [input] nRecordBytes: Bytes in record
  virtual DeviceIF::Status processRecord(unsigned char *record,
                                         int nRecordBytes);
  //
  // Convert the raw readings from the 4 beams into distance in Engineering
  // units.  *beamRange is a pointer to beamRange[NUM_BEAMS].
  //
  Boolean cvtRange(long rawRange[NUM_BEAMS][NBYTES], 
		   double *beamRange, double *dvlAltitude,
		   Boolean useMinBeam );

protected:

  //
  // Bring the DVL to life.
  //
  DeviceIF::Status wakeupDvl();
  //
  // Convert the raw velocity reading into distance in Engineering units.
  //
  Boolean mmToMetres(long xVelocity[NBYTES], long yVelocity[NBYTES],
                     long zVelocity[NBYTES], long eVelocity[NBYTES],
                     double velocity[NXE]);
  ////////////////////////////////////////////////////////////////////////////
  //
  // PURPOSE: Write a variable-length Ascii string to the Dvl.
  //
  //          The string must be shorter than DVL_INBUF_SIZE-2, and include a
  //          terminating null.
  //
  //          This routine will add the terminating '\r' that the Dvl expects.
  //
  // INPUTS:  buf   - The usual null-terminated character string.
  //
  // RETURNS: Ok    - All characters successfully sent.
  //          Error - Some problem with _device->write???
  //
  ////////////////////////////////////////////////////////////////////////////
  //
  DeviceIF::Status writeAscii( char *buf );


  ////////////////////////////////////////////////////////////////////////////
  //
  // PURPOSE: Read a variable-length record.  It reads until either it
  //          receives the Dvl's terminating Ascii character ">", or
  //          it times out.
  //
  // INPUTS:  buf          - Pointer to a character array.  The routine will
  //                         place the record here, so buf must be larger
  //                         than the largest record expected.
  //          bufSize      - sizeof(buf);
  //          readTimeOut  - Exit with an error if no characters have been
  //                         received after this time, and the terminating
  //                         sequence has not been received.  In Milliseconds.
  //
  // OUTPUTS: buf          - Now contains a null-terminated Ascii string.
  //
  // RETURNS: Error or Ok.
  //
  ////////////////////////////////////////////////////////////////////////////
  //
  DeviceIF::Status   Dvl::readAscii( char *buf, int bufSize, int readTimeOut );


  ////////////////////////////////////////////////////////////////////////////
  //
  // PURPOSE: Write a variable-length Ascii string to the Dvl using
  //          the writeAscii() member function above.  Then, read the
  //          response using the readAscii() member function also above,
  //          and print the response to Syslog if m_verbose is true.
  //
  //          Read the descriptions of these two functions for more details.
  //
  // INPUTS:  cmd          - The usual null-terminated character string.
  //          readTimeOut  - Exit with an error if no characters have been
  //                         received after this time, and the terminating
  //                         sequence has not been received.  In Milliseconds.
  //
  // RETURNS: Ok    - All characters successfully sent.  Response successfully
  //                  received.
  //          Error - Error.
  //
  ////////////////////////////////////////////////////////////////////////////
  //
  DeviceIF::Status   Dvl::writeReadAscii( char *cmd, int readTimeOut );
  char m_buf[DVL_OUTBUF_SIZE];
  int m_bufSize;

  //
  ////////////////////////////////////////////////////////////////////////////
  //
  // PURPOSE: Set the member variable "Format" to the value in the "cmd" string.
  //
  // INPUTS:  cmd - The usual null-terminated character string.  It must
  //                be "PD0" or "PD5".
  //
  ////////////////////////////////////////////////////////////////////////////
  //
  void Dvl::setFormat( char *cmd );

  //
  ////////////////////////////////////////////////////////////////////////////
  //
  // PURPOSE: Convert a null-terminated character string to binary.
  //
  // INPUTS:  ascbuf  - The usual null-terminated character string.  
  //          binbuf  - Binary equivalent
  //                
  // OUTPUTS: int     - 0 if successful, nonzero if failed.
  //
  ////////////////////////////////////////////////////////////////////////////
  //
  int Dvl::cvt2bin( char *ascbuf, unsigned char *binbuf );

  unsigned char *binRecord;


  DvlLog *m_log;
  FILE *fpAsc, *fpCfg;
  int fdescBin;
  char AscFileName[128], ConfigFileName[128], BinFileName[128];
  Boolean m_verbose;
  int m_timeout;
  DvlOutput *m_output;
  int m_sos;

  unsigned char  bottomTrackVelocityStatus;     /* velocity status            */
  unsigned char  waterMassVelocityStatus;
  long xBottomTrackVelocity[NBYTES];            /* velocity                 */
  long yBottomTrackVelocity[NBYTES];
  long zBottomTrackVelocity[NBYTES];
  long eBottomTrackVelocity[NBYTES];
  long xWaterMassVelocity[NBYTES];
  long yWaterMassVelocity[NBYTES];
  long zWaterMassVelocity[NBYTES];
  long eWaterMassVelocity[NBYTES];
  long hour;
  long min;
  long sec;
  long centisec;
  long rawRange[NUM_BEAMS][NBYTES];             /* raw DVL range in centimetrs*/
  long rawTemp[NBYTES];                         /* temperature, .01 Deg C/bit */
  long rawPitch[NBYTES];                        /* Pitch tilt .01 Deg/count   */
  long rawRoll[NBYTES];                         /* Roll  tilt .01 Deg/count   */
  long rawHeading[NBYTES];                      /* Magnetic Heading, .01 Deg/c*/
  short dof;                                    /* dof counter                */
  Boolean m_status;                             /* General function call status*/
  //
  // The following pointers must be initialized to point to the "data" structure
  // defined in DvlOutput.h (which comes from DvlIF.idl).
  //
  long waterStatus[1];                         /* Init this to the output array*/
  long bottomStatus[1];                        /* Init this to the output array*/
  Boolean bottomDetectStatus[1];
  Boolean _lastBottomDetectStatus;
  double bottomTrackVelocity[NXE];             /* 4 element vector           */
  double waterMassVelocity[NXE];               /* 4 element vector           */
  double dvlPingTime[1];
  double dvlRange[1];
  double beamRange[NUM_BEAMS];                 /* The four ranges in meters  */
  double dvlTemp[1];
  double dvlPitch[1];
  double dvlRoll[1];
  double dvlHeading[1];
  unsigned char dvlDataStatus[1];
  unsigned char dvlSerialStatus;                /* Status of DVL serial comms */
  //
  // m_badComms is a long to be consistant with the idl types.  It need only
  // be a bool.
  //
  long m_badComms;
  //
  // For PD5, the output format still will match Figure D-12 & 13 on
  // pp. D-12 & 13 of the manual, except there will be twice as many bytes,
  // because each hex char is a byte.  See also p D-24, and note the
  // first column.
  //
  // Size of the record in bytes, not counting the checksum.
  //
  short recordBytes;
  //
  // Size of the record in ASCII chars = 2* above, plus the two byte checksum.
  //
  short recordSize;
  enum FormatEnum {PD0, PD1, PD2, PD3, PD4, PD5, PD6};
  enum FormatEnum Format;

  //
  // For header byte patterns
  //
  char *PD5Header;
  char PD0Header[10];
  char *Header;
  //
  // Number of Dvl data types, set by the WD command.  It apparently defaults
  // to 7.
  //
  short numDataTypes;
  //
  // Number of water layer cells, set by the WN command.  The default is 30.
  //
  short numCells;
  //
  // Numerical value of evaluation parameters.  For PD0 only.
  //
  short bottomTrackCor[NUM_BEAMS];
  short bottomTrackAmp[NUM_BEAMS];
  short waterMassCor[NUM_BEAMS];
  short bottomTrackCorMin;
  short bottomTrackAmpMin;
  short waterMassCorMin;
};

#endif
