text: /****************************************************************************
  ** Copyright (c) 2000-2003 Wayne Roth
  ** Copyright (c) 2004-2007 Stefan Sander
  ** Copyright (c) 2007 Michal Policht
  ** Copyright (c) 2008 Brandon Fosdick
  ** Copyright (c) 2009-2010 Liam Staskawicz
  ** Copyright (c) 2011 Debao Zhang
  ** All right reserved.
  ** Web: http://code.google.com/p/qextserialport/
  **
  ** Permission is hereby granted, free of charge, to any person obtaining
  ** a copy of this software and associated documentation files (the
  ** "Software"), to deal in the Software without restriction, including
  ** without limitation the rights to use, copy, modify, merge, publish,
  ** distribute, sublicense, and/or sell copies of the Software, and to
  ** permit persons to whom the Software is furnished to do so, subject to
  ** the following conditions:
  **
  ** The above copyright notice and this permission notice shall be
  ** included in all copies or substantial portions of the Software.
  **
  ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  **
  ****************************************************************************/
  
  #ifndef _QEXTSERIALPORT_P_H_
  #define _QEXTSERIALPORT_P_H_
  
  //
  //  W A R N I N G
  //  -------------
  //
  // This file is not part of the QESP API.  It exists for the convenience
  // of other QESP classes.  This header file may change from version to
  // version without notice, or even be removed.
  //
  // We mean it.
  //
  
  #include "qextserialport.h"
  #include <QtCore/QReadWriteLock>
  #ifdef Q_OS_UNIX
  #  include <termios.h>
  #elif (defined Q_OS_WIN)
  #  include <QtCore/qt_windows.h>
  #endif
  #include <stdlib.h>
  
  // This is QextSerialPort's read buffer, needed by posix system.
  // ref: QRingBuffer & QIODevicePrivateLinearBuffer
  class QextReadBuffer
  {
  public:
      inline QextReadBuffer(size_t growth=4096)
          : len(0), first(0), buf(0), capacity(0), basicBlockSize(growth) {
      }
  
      ~QextReadBuffer() {
          delete [] buf;
      }
  
      inline void clear() {
          first = buf;
          len = 0;
      }
  
      inline int size() const {
          return len;
      }
  
      inline bool isEmpty() const {
          return len == 0;
      }
  
      inline int read(char *target, int size) {
          int r = qMin(size, len);
          if (r == 1) {
              *target = *first;
              --len;
              ++first;
          } else {
              memcpy(target, first, r);
              len -= r;
              first += r;
          }
          return r;
      }
  
      inline char *reserve(size_t size) {
          if ((first - buf) + len + size > capacity) {
              size_t newCapacity = qMax(capacity, basicBlockSize);
              while (newCapacity < len + size)
                  newCapacity *= 2;
              if (newCapacity > capacity) {
                  // allocate more space
                  char *newBuf = new char[newCapacity];
                  memmove(newBuf, first, len);
                  delete [] buf;
                  buf = newBuf;
                  capacity = newCapacity;
              } else {
                  // shift any existing data to make space
                  memmove(buf, first, len);
              }
              first = buf;
          }
          char *writePtr = first + len;
          len += (int)size;
          return writePtr;
      }
  
      inline void chop(int size) {
          if (size >= len) {
              clear();
          } else {
              len -= size;
          }
      }
  
      inline void squeeze() {
          if (first != buf) {
              memmove(buf, first, len);
              first = buf;
          }
          size_t newCapacity = basicBlockSize;
          while (newCapacity < size_t(len))
              newCapacity *= 2;
          if (newCapacity < capacity) {
              char *tmp = static_cast<char *>(realloc(buf, newCapacity));
              if (tmp) {
                  buf = tmp;
                  capacity = newCapacity;
              }
          }
      }
  
      inline QByteArray readAll() {
          char *f = first;
          int l = len;
          clear();
          return QByteArray(f, l);
      }
  
      inline int readLine(char *target, int size) {
          int r = qMin(size, len);
          char *eol = static_cast<char *>(memchr(first, '\n', r));
          if (eol)
              r = 1+(eol-first);
          memcpy(target, first, r);
          len -= r;
          first += r;
          return int(r);
      }
  
      inline bool canReadLine() const {
          return memchr(first, '\n', len);
      }
  
  private:
      int len;
      char *first;
      char *buf;
      size_t capacity;
      size_t basicBlockSize;
  };
  
  class QWinEventNotifier;
  class QReadWriteLock;
  class QSocketNotifier;
  
  class QextSerialPortPrivate
  {
      Q_DECLARE_PUBLIC(QextSerialPort)
  public:
      QextSerialPortPrivate(QextSerialPort *q);
      ~QextSerialPortPrivate();
      enum DirtyFlagEnum
      {
          DFE_BaudRate = 0x0001,
          DFE_Parity = 0x0002,
          DFE_StopBits = 0x0004,
          DFE_DataBits = 0x0008,
          DFE_Flow = 0x0010,
          DFE_TimeOut = 0x0100,
          DFE_ALL = 0x0fff,
          DFE_Settings_Mask = 0x00ff //without TimeOut
      };
      mutable QReadWriteLock lock;
      QString port;
      PortSettings settings;
      QextReadBuffer readBuffer;
      int settingsDirtyFlags;
      ulong lastErr;
      QextSerialPort::QueryMode queryMode;
  
      // platform specific members
  #ifdef Q_OS_UNIX
      int fd;
      QSocketNotifier *readNotifier;
      struct termios currentTermios;
      struct termios oldTermios;
  #elif (defined Q_OS_WIN)
      HANDLE handle;
      OVERLAPPED overlap;
      COMMCONFIG commConfig;
      COMMTIMEOUTS commTimeouts;
      QWinEventNotifier *winEventNotifier;
      DWORD eventMask;
      QList<OVERLAPPED *> pendingWrites;
      QReadWriteLock *bytesToWriteLock;
  #endif
  
      /*fill PortSettings*/
      void setBaudRate(BaudRateType baudRate, bool update=true);
      void setDataBits(DataBitsType dataBits, bool update=true);
      void setParity(ParityType parity, bool update=true);
      void setStopBits(StopBitsType stopbits, bool update=true);
      void setFlowControl(FlowType flow, bool update=true);
      void setTimeout(long millisec, bool update=true);
      void setPortSettings(const PortSettings &settings, bool update=true);
  
      void platformSpecificDestruct();
      void platformSpecificInit();
      void translateError(ulong error);
      void updatePortSettings();
  
      qint64 readData_sys(char *data, qint64 maxSize);
      qint64 writeData_sys(const char *data, qint64 maxSize);
      void setDtr_sys(bool set=true);
      void setRts_sys(bool set=true);
      bool open_sys(QIODevice::OpenMode mode);
      bool close_sys();
      bool flush_sys();
      ulong lineStatus_sys();
      qint64 bytesAvailable_sys() const;
  
  #ifdef Q_OS_WIN
      void _q_onWinEvent(HANDLE h);
  #endif
      void _q_canRead();
  
      QextSerialPort *q_ptr;
  };
  
  #endif //_QEXTSERIALPORT_P_H_
  