//=========================================================================
// Summary  : */
// Filename : SerialDevice.h
// Author   : */
// Project  : */
// Revision : 1
// Created  : 2000/08/19
// Modified : 2000/08/19
//=========================================================================
// Description :
//=========================================================================
#ifndef _SERIALDEVICE_H
#define _SERIALDEVICE_H


#include "DeviceInterface.h"

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <errno.h>

#include "DeviceInterface.h"
#include "Exception.h"

#define ERROR -1
#define OK     0

/*
CLASS
SerialDevice

DESCRIPTION
SerialDevice DeviceInterface performs I/O through a serial"port"

AUTHOR
Andrew Pearce

*/

class SerialDevice : public DeviceInterface
{
public:

  class TimedOut : public Exception {

  public:

    TimedOut(int nBytesRead);

    int nBytesRead();

  protected:

    // Number of bytes read before timeout occurred
    int _nBytes;
  };

  class CommsFailure : public Exception {
  public:
      CommsFailure();
  };

  class BufferFull : public Exception {

  public:

    BufferFull();

  };

  class BadSystemCall : public Exception {

  public:

    BadSystemCall(char *systemCall);

  };


  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] ttyName: /dev/name for serial device
  SerialDevice(const char *ttyName);

  virtual ~SerialDevice();

  ///////////////////////////////////////////////////////////////////
  // getFd - Returns file descriptor for tty device
  int getFd();

  ///////////////////////////////////////////////////////////////////
  // devName - Returns device name for tty device
  const char* devName();

  ///////////////////////////////////////////////////////////////////
  // nonBlocking - Sets device to non-blocking mode
  int nonBlocking();

  ///////////////////////////////////////////////////////////////////
  // blocking - Sets device to blocking mode
  int blocking();

  ///////////////////////////////////////////////////////////////////
  // raw - Sets device to a "raw" input mode
  int raw();

  ///////////////////////////////////////////////////////////////////
  // nonRaw - Sets device to a "cooked" input mode
  int nonRaw();

  ///////////////////////////////////////////////////////////////////
  // sendBreak - Sends a break to the device
  int sendBreak();

  ///////////////////////////////////////////////////////////////////
  // sendBreak - Send break of user specified duration to device
  int sendBreak(int milliseconds);

  ///////////////////////////////////////////////////////////////////
  // read - reads chars from port into the string reply until a
  // termination character is received or until timeout (in millisecs)
  // elapses. A timeout value of 0 performs a blocking read
  // assumes memory already allocated for reply.
  // log diagnostics if enable by CommDebugMode
  virtual int readNChars( char *buf, int count, int timeout );

  virtual int read(char *buf, int maxBytes, int timeout)
    throw (TimedOut, BadSystemCall);


  ///////////////////////////////////////////////////////////////////
  // writeData - clear read buffer, then send message to port,
  // log diagnostics if enable by CommDebugMode
  virtual int write(const char *buf, int nBytes);
  virtual int writeRepeat( const char *buf, int nBytes, int reps );

  // calls write, then fflush
  virtual int writeFlush(const char *buf, int nBytes);

  ///////////////////////////////////////////////////////////////////
  // Reset device
  virtual void reset();

  enum CommsDebugMode {
    DebugOn, DebugOff
  };

  ///////////////////////////////////////////////////////////////////
  // commsDebugMode - Sets Communications Debug Mode (Default is off)
  void commsDebugMode(CommsDebugMode mode);

  ///////////////////////////////////////////////////////////////////
  struct lineFormat {
       speed_t baud;
       int data, stop;
       const char *parity;
  };

  ///////////////////////////////////////////////////////////////////
  // SetLineFormat
  // [input] baud: baud rate
  // [input] data: data bits
  // [input] stop: stop bits (1 or 2)
  // [input] parity: parity setting (NONE, EVEN, ODD)
  int setLineFormat(speed_t baud, int data, int stop, const char *parity);
  inline int setLineFormat( lineFormat *inFmt )
    { return setLineFormat( inFmt->baud, inFmt->data,
			    inFmt->stop, inFmt->parity ); };

  ///////////////////////////////////////////////////////////////////
  // nRecvdBytes - Returns number of bytes in the receive buffer
  int nRecvdBytes();

  void clearPort();

  ///////////////////////////////////////////////////////////////////
  // flushReceiveBuf - checks to see if there are any chars to read from port,
  // and if so it reads and discards them.
  int flushReceiveBuf();

  ///////////////////////////////////////////////////////////////////
  // reads characters into buffer until string is received from device
  int readUntil(char *buf, int maxBytes, char *term, int timeout)
    throw (TimedOut, BufferFull, BadSystemCall, CommsFailure);

  ///////////////////////////////////////////////////////////////////
  // Confirm that a string was received from device
  int readUntil(char *term, int timeout)
    throw (TimedOut, BadSystemCall, CommsFailure);

  ///////////////////////////////////////////////////////////////////
  // Confirm that a string was received from device
  int confirm(char *term, int timeout);

  void clearPort();

  void printTermios();

protected:

  int NonBlocking();
  int Blocking();
  int sendBreak();

private:

  FILE *_dev;
  int _fd;

  struct termios orig_termios_p;

  CommsDebugMode  _commsDebugMode;

  int csetStopBits(struct termios *termios_p, int stopBits );
  int csetDataBits(struct termios *termios_p, int dataBits );
  int csetParityBits(struct termios *termios_p, const char *parity);
};

#endif


