summaryrefslogtreecommitdiff
path: root/src/serialport
diff options
context:
space:
mode:
Diffstat (limited to 'src/serialport')
-rw-r--r--src/serialport/qt4support/install-helper.pri25
-rw-r--r--src/serialport/qt4support/qringbuffer_p.h451
-rw-r--r--src/serialport/qt4support/qwineventnotifier_p.h94
-rw-r--r--src/serialport/qt4support/serialport.prf29
-rw-r--r--src/serialport/serialport-global.h71
-rw-r--r--src/serialport/serialport-lib.pri80
-rw-r--r--src/serialport/serialport.cpp1086
-rw-r--r--src/serialport/serialport.h242
-rw-r--r--src/serialport/serialport.pro18
-rw-r--r--src/serialport/serialport_p.h87
-rw-r--r--src/serialport/serialport_symbian.cpp645
-rw-r--r--src/serialport/serialport_symbian_p.h116
-rw-r--r--src/serialport/serialport_unix.cpp1327
-rw-r--r--src/serialport/serialport_unix_p.h153
-rw-r--r--src/serialport/serialport_win.cpp1091
-rw-r--r--src/serialport/serialport_win_p.h163
-rw-r--r--src/serialport/serialport_wince.cpp475
-rw-r--r--src/serialport/serialportinfo.cpp242
-rw-r--r--src/serialport/serialportinfo.h93
-rw-r--r--src/serialport/serialportinfo_mac.cpp264
-rw-r--r--src/serialport/serialportinfo_p.h77
-rw-r--r--src/serialport/serialportinfo_symbian.cpp253
-rw-r--r--src/serialport/serialportinfo_unix.cpp264
-rw-r--r--src/serialport/serialportinfo_win.cpp222
-rw-r--r--src/serialport/serialportinfo_wince.cpp136
-rw-r--r--src/serialport/ttylocker_unix.cpp178
-rw-r--r--src/serialport/ttylocker_unix_p.h59
27 files changed, 7941 insertions, 0 deletions
diff --git a/src/serialport/qt4support/install-helper.pri b/src/serialport/qt4support/install-helper.pri
new file mode 100644
index 0000000..657dbd6
--- /dev/null
+++ b/src/serialport/qt4support/install-helper.pri
@@ -0,0 +1,25 @@
+SERIALPORT_PROJECT_INCLUDEDIR = $$SERIALPORT_BUILD_ROOT/include/QtAddOnSerialPort
+SERIALPORT_PROJECT_INCLUDEDIR ~=s,/,$$QMAKE_DIR_SEP,
+
+system("$$QMAKE_MKDIR $$SERIALPORT_PROJECT_INCLUDEDIR")
+
+for(header_file, PUBLIC_HEADERS) {
+ header_file ~=s,/,$$QMAKE_DIR_SEP,
+ system("$$QMAKE_COPY $${header_file} $$SERIALPORT_PROJECT_INCLUDEDIR")
+}
+
+target_headers.files = $$PUBLIC_HEADERS
+target_headers.path = $$[QT_INSTALL_PREFIX]/include/QtAddOnSerialPort
+INSTALLS += target_headers
+
+mkspecs_features.files = $$SERIALPORT_PROJECT_ROOT/src/serialport/qt4support/serialport.prf
+mkspecs_features.path = $$[QT_INSTALL_DATA]/mkspecs/features
+INSTALLS += mkspecs_features
+
+win32 {
+ dlltarget.path = $$[QT_INSTALL_BINS]
+ INSTALLS += dlltarget
+}
+
+target.path = $$[QT_INSTALL_LIBS]
+INSTALLS += target
diff --git a/src/serialport/qt4support/qringbuffer_p.h b/src/serialport/qt4support/qringbuffer_p.h
new file mode 100644
index 0000000..65eb8d7
--- /dev/null
+++ b/src/serialport/qt4support/qringbuffer_p.h
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRINGBUFFER_P_H
+#define QRINGBUFFER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRingBuffer
+{
+public:
+ explicit inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) {
+ buffers << QByteArray();
+ clear();
+ }
+
+ inline int nextDataBlockSize() const {
+ return (tailBuffer == 0 ? tail : buffers.first().size()) - head;
+ }
+
+ inline const char *readPointer() const {
+ return buffers.isEmpty() ? 0 : (buffers.first().constData() + head);
+ }
+
+ // access the bytes at a specified position
+ // the out-variable length will contain the amount of bytes readable
+ // from there, e.g. the amount still the same QByteArray
+ inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const {
+ if (buffers.isEmpty()) {
+ length = 0;
+ return 0;
+ }
+
+ if (pos >= bufferSize) {
+ length = 0;
+ return 0;
+ }
+
+ // special case: it is in the first buffer
+ int nextDataBlockSizeValue = nextDataBlockSize();
+ if (pos - head < nextDataBlockSizeValue) {
+ length = nextDataBlockSizeValue - pos;
+ return buffers.at(0).constData() + head + pos;
+ }
+
+ // special case: we only had one buffer and tried to read over it
+ if (buffers.length() == 1) {
+ length = 0;
+ return 0;
+ }
+
+ // skip the first
+ pos -= nextDataBlockSizeValue;
+
+ // normal case: it is somewhere in the second to the-one-before-the-tailBuffer
+ for (int i = 1; i < tailBuffer; i++) {
+ if (pos >= buffers[i].size()) {
+ pos -= buffers[i].size();
+ continue;
+ }
+
+ length = buffers[i].length() - pos;
+ return buffers[i].constData() + pos;
+ }
+
+ // it is in the tail buffer
+ length = tail - pos;
+ return buffers[tailBuffer].constData() + pos;
+ }
+
+ inline void free(int bytes) {
+ bufferSize -= bytes;
+ if (bufferSize < 0)
+ bufferSize = 0;
+
+ for (;;) {
+ int nextBlockSize = nextDataBlockSize();
+ if (bytes < nextBlockSize) {
+ head += bytes;
+ if (head == tail && tailBuffer == 0)
+ head = tail = 0;
+ break;
+ }
+
+ bytes -= nextBlockSize;
+ if (buffers.count() == 1) {
+ if (buffers.at(0).size() != basicBlockSize)
+ buffers[0].resize(basicBlockSize);
+ head = tail = 0;
+ tailBuffer = 0;
+ break;
+ }
+
+ buffers.removeAt(0);
+ --tailBuffer;
+ head = 0;
+ }
+
+ if (isEmpty())
+ clear(); // try to minify/squeeze us
+ }
+
+ inline char *reserve(int bytes) {
+ // if this is a fresh empty QRingBuffer
+ if (bufferSize == 0) {
+ buffers[0].resize(qMax(basicBlockSize, bytes));
+ bufferSize += bytes;
+ tail = bytes;
+ return buffers[tailBuffer].data();
+ }
+
+ bufferSize += bytes;
+
+ // if there is already enough space, simply return.
+ if (tail + bytes <= buffers.at(tailBuffer).size()) {
+ char *writePtr = buffers[tailBuffer].data() + tail;
+ tail += bytes;
+ return writePtr;
+ }
+
+ // if our buffer isn't half full yet, simply resize it.
+ if (tail < buffers.at(tailBuffer).size() / 2) {
+ buffers[tailBuffer].resize(tail + bytes);
+ char *writePtr = buffers[tailBuffer].data() + tail;
+ tail += bytes;
+ return writePtr;
+ }
+
+ // shrink this buffer to its current size
+ buffers[tailBuffer].resize(tail);
+
+ // create a new QByteArray with the right size
+ buffers << QByteArray();
+ ++tailBuffer;
+ buffers[tailBuffer].resize(qMax(basicBlockSize, bytes));
+ tail = bytes;
+ return buffers[tailBuffer].data();
+ }
+
+ inline void truncate(int pos) {
+ if (pos < size())
+ chop(size() - pos);
+ }
+
+ inline void chop(int bytes) {
+ bufferSize -= bytes;
+ if (bufferSize < 0)
+ bufferSize = 0;
+
+ for (;;) {
+ // special case: head and tail are in the same buffer
+ if (tailBuffer == 0) {
+ tail -= bytes;
+ if (tail <= head)
+ tail = head = 0;
+ return;
+ }
+
+ if (bytes <= tail) {
+ tail -= bytes;
+ return;
+ }
+
+ bytes -= tail;
+ buffers.removeAt(tailBuffer);
+
+ --tailBuffer;
+ tail = buffers.at(tailBuffer).size();
+ }
+
+ if (isEmpty())
+ clear(); // try to minify/squeeze us
+ }
+
+ inline bool isEmpty() const {
+ return tailBuffer == 0 && tail == 0;
+ }
+
+ inline int getChar() {
+ if (isEmpty())
+ return -1;
+ char c = *readPointer();
+ free(1);
+ return int(uchar(c));
+ }
+
+ inline void putChar(char c) {
+ char *ptr = reserve(1);
+ *ptr = c;
+ }
+
+ inline void ungetChar(char c) {
+ --head;
+ if (head < 0) {
+ buffers.prepend(QByteArray());
+ buffers[0].resize(basicBlockSize);
+ head = basicBlockSize - 1;
+ ++tailBuffer;
+ }
+ buffers[0][head] = c;
+ ++bufferSize;
+ }
+
+ inline int size() const {
+ return bufferSize;
+ }
+
+ inline void clear() {
+ buffers.erase(buffers.begin() + 1, buffers.end());
+ buffers[0].resize(0);
+ buffers[0].squeeze();
+
+ head = tail = 0;
+ tailBuffer = 0;
+ bufferSize = 0;
+ }
+
+ inline int indexOf(char c) const {
+ int index = 0;
+ for (int i = 0; i < buffers.size(); ++i) {
+ int start = 0;
+ int end = buffers.at(i).size();
+
+ if (i == 0)
+ start = head;
+ if (i == tailBuffer)
+ end = tail;
+ const char *ptr = buffers.at(i).data() + start;
+ for (int j = start; j < end; ++j) {
+ if (*ptr++ == c)
+ return index;
+ ++index;
+ }
+ }
+ return -1;
+ }
+
+ inline int indexOf(char c, int maxLength) const {
+ int index = 0;
+ int remain = qMin(size(), maxLength);
+ for (int i = 0; remain && i < buffers.size(); ++i) {
+ int start = 0;
+ int end = buffers.at(i).size();
+
+ if (i == 0)
+ start = head;
+ if (i == tailBuffer)
+ end = tail;
+ if (remain < end - start) {
+ end = start + remain;
+ remain = 0;
+ } else {
+ remain -= end - start;
+ }
+ const char *ptr = buffers.at(i).data() + start;
+ for (int j = start; j < end; ++j) {
+ if (*ptr++ == c)
+ return index;
+ ++index;
+ }
+ }
+ return -1;
+ }
+
+ inline int read(char *data, int maxLength) {
+ int bytesToRead = qMin(size(), maxLength);
+ int readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = readPointer();
+ int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize());
+ if (data)
+ memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ free(bytesToReadFromThisBlock);
+ }
+ return readSoFar;
+ }
+
+ inline QByteArray read(int maxLength) {
+ QByteArray tmp;
+ tmp.resize(qMin(maxLength, size()));
+ read(tmp.data(), tmp.size());
+ return tmp;
+ }
+
+ inline QByteArray readAll() {
+ return read(size());
+ }
+
+ // read an unspecified amount (will read the first buffer)
+ inline QByteArray read() {
+ if (bufferSize == 0)
+ return QByteArray();
+
+ // multiple buffers, just take the first one
+ if (head == 0 && tailBuffer != 0) {
+ QByteArray qba = buffers.takeFirst();
+ --tailBuffer;
+ bufferSize -= qba.length();
+ return qba;
+ }
+
+ // one buffer with good value for head. Just take it.
+ if (head == 0 && tailBuffer == 0) {
+ QByteArray qba = buffers.takeFirst();
+ qba.resize(tail);
+ buffers << QByteArray();
+ bufferSize = 0;
+ tail = 0;
+ return qba;
+ }
+
+ // Bad case: We have to memcpy.
+ // We can avoid by initializing the QRingBuffer with basicBlockSize of 0
+ // and only using this read() function.
+ QByteArray qba(readPointer(), nextDataBlockSize());
+ buffers.removeFirst();
+ head = 0;
+ if (tailBuffer == 0) {
+ buffers << QByteArray();
+ tail = 0;
+ } else {
+ --tailBuffer;
+ }
+ bufferSize -= qba.length();
+ return qba;
+ }
+
+ // append a new buffer to the end
+ inline void append(const QByteArray &qba) {
+ buffers[tailBuffer].resize(tail);
+ buffers << qba;
+ ++tailBuffer;
+ tail = qba.length();
+ bufferSize += qba.length();
+ }
+
+ inline QByteArray peek(int maxLength) const {
+ int bytesToRead = qMin(size(), maxLength);
+ if (maxLength <= 0)
+ return QByteArray();
+ QByteArray ret;
+ ret.resize(bytesToRead);
+ int readSoFar = 0;
+ for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) {
+ int start = 0;
+ int end = buffers.at(i).size();
+ if (i == 0)
+ start = head;
+ if (i == tailBuffer)
+ end = tail;
+ const int len = qMin(ret.size()-readSoFar, end-start);
+ memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len);
+ readSoFar += len;
+ }
+ Q_ASSERT(readSoFar == ret.size());
+ return ret;
+ }
+
+ inline int skip(int length) {
+ return read(0, length);
+ }
+
+ inline int readLine(char *data, int maxLength) {
+ int index = indexOf('\n');
+ if (index == -1)
+ return read(data, maxLength);
+ if (maxLength <= 0)
+ return -1;
+
+ int readSoFar = 0;
+ while (readSoFar < index + 1 && readSoFar < maxLength - 1) {
+ int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize());
+ bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar);
+ memcpy(data + readSoFar, readPointer(), bytesToRead);
+ readSoFar += bytesToRead;
+ free(bytesToRead);
+ }
+
+ // Terminate it.
+ data[readSoFar] = '\0';
+ return readSoFar;
+ }
+
+ inline bool canReadLine() const {
+ return indexOf('\n') != -1;
+ }
+
+private:
+ QList<QByteArray> buffers;
+ int head, tail;
+ int tailBuffer; // always buffers.size() - 1
+ int basicBlockSize;
+ int bufferSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QRINGBUFFER_P_H
diff --git a/src/serialport/qt4support/qwineventnotifier_p.h b/src/serialport/qt4support/qwineventnotifier_p.h
new file mode 100644
index 0000000..a87994d
--- /dev/null
+++ b/src/serialport/qt4support/qwineventnotifier_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINEVENTNOTIFIER_P_H
+#define QWINEVENTNOTIFIER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qobject.h"
+#include "QtCore/qt_windows.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_CORE_EXPORT QWinEventNotifier : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QObject)
+
+public:
+ explicit QWinEventNotifier(QObject *parent = 0);
+ explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0);
+ ~QWinEventNotifier();
+
+ void setHandle(HANDLE hEvent);
+ HANDLE handle() const;
+
+ bool isEnabled() const;
+
+public Q_SLOTS:
+ void setEnabled(bool enable);
+
+Q_SIGNALS:
+ void activated(HANDLE hEvent);
+
+protected:
+ bool event(QEvent * e);
+
+private:
+ Q_DISABLE_COPY(QWinEventNotifier)
+
+ HANDLE handleToEvent;
+ bool enabled;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINEVENTNOTIFIER_P_H
diff --git a/src/serialport/qt4support/serialport.prf b/src/serialport/qt4support/serialport.prf
new file mode 100644
index 0000000..489acb5
--- /dev/null
+++ b/src/serialport/qt4support/serialport.prf
@@ -0,0 +1,29 @@
+!exists($$[QT_INSTALL_HEADERS]/QtAddOnSerialPort) {
+ INCLUDEPATH += $$SERIALPORT_BUILD_ROOT/include $$SERIALPORT_BUILD_ROOT/include/QtAddOnSerialPort
+
+ SERIALPORT_BUILD_SUBDIR = src/serialport
+ win32 {
+ CONFIG(debug, debug|release) {
+ SERIALPORT_BUILD_SUBDIR = $$SERIALPORT_BUILD_SUBDIR/debug
+ } else {
+ SERIALPORT_BUILD_SUBDIR = $$SERIALPORT_BUILD_SUBDIR/release
+ }
+ }
+
+ LIBS += -L$$SERIALPORT_BUILD_ROOT/$$SERIALPORT_BUILD_SUBDIR
+}
+
+qtAddLibrary(SerialPort)
+
+mac {
+ LIBS -= -framework SerialPort$${QT_LIBINFIX}
+
+ if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
+ LIBS += -lSerialPort$${QT_LIBINFIX}_debug
+ } else {
+ LIBS += -lSerialPort$${QT_LIBINFIX}
+ }
+}
+
+INCLUDEPATH -= $$[QT_INSTALL_HEADERS]/SerialPort
+INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtAddOnSerialPort
diff --git a/src/serialport/serialport-global.h b/src/serialport/serialport-global.h
new file mode 100644
index 0000000..d0f7680
--- /dev/null
+++ b/src/serialport/serialport-global.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_GLOBAL_H
+#define SERIALPORT_GLOBAL_H
+
+#include "qglobal.h"
+
+#if defined(QT_SERIALPORT_LIB)
+# define Q_SERIALPORT_EXPORT Q_DECL_EXPORT
+#else
+# define Q_SERIALPORT_EXPORT Q_DECL_IMPORT
+#endif
+
+#if defined(QT_NAMESPACE)
+# define QT_BEGIN_NAMESPACE_SERIALPORT namespace QT_NAMESPACE { namespace QtAddOn { namespace SerialPort {
+# define QT_END_NAMESPACE_SERIALPORT } } }
+# define QT_USE_NAMESPACE_SERIALPORT using namespace QT_NAMESPACE::QtAddOn::SerialPort;
+# define QT_PREPEND_NAMESPACE_SERIALPORT(name) ::QT_NAMESPACE::QtAddOn::SerialPort::name
+#else
+# define QT_BEGIN_NAMESPACE_SERIALPORT namespace QtAddOn { namespace SerialPort {
+# define QT_END_NAMESPACE_SERIALPORT } }
+# define QT_USE_NAMESPACE_SERIALPORT using namespace QtAddOn::SerialPort;
+# define QT_PREPEND_NAMESPACE_SERIALPORT(name) ::QtAddOn::SerialPort::name
+#endif
+
+// a workaround for moc - if there is a header file that doesn't use serialport
+// namespace, we still force moc to do "using namespace" but the namespace have to
+// be defined, so let's define an empty namespace here
+QT_BEGIN_NAMESPACE_SERIALPORT
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_GLOBAL_H
diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri
new file mode 100644
index 0000000..3d946c1
--- /dev/null
+++ b/src/serialport/serialport-lib.pri
@@ -0,0 +1,80 @@
+INCLUDEPATH += $$PWD
+
+linux*:DEFINES += HAVE_LIBUDEV
+
+PUBLIC_HEADERS += \
+ $$PWD/serialport-global.h \
+ $$PWD/serialport.h \
+ $$PWD/serialportinfo.h
+
+PRIVATE_HEADERS += \
+ $$PWD/serialport_p.h \
+ $$PWD/serialportinfo_p.h
+
+SOURCES += \
+ $$PWD/serialport.cpp \
+ $$PWD/serialportinfo.cpp
+
+win32 {
+ PRIVATE_HEADERS += \
+ $$PWD/serialport_win_p.h
+
+ SOURCES += \
+ $$PWD/serialport_win.cpp \
+ $$PWD/serialportinfo_win.cpp
+
+ !wince*: {
+ LIBS += -lsetupapi -ladvapi32
+ } else {
+ SOURCES += \
+ $$PWD/serialport_wince.cpp \
+ $$PWD/serialportinfo_wince.cpp
+ }
+}
+
+symbian {
+ MMP_RULES += EXPORTUNFROZEN
+ #MMP_RULES += DEBUGGABLE_UDEBONLY
+ TARGET.UID3 = 0xE7E62DFD
+ TARGET.CAPABILITY =
+ TARGET.EPOCALLOWDLLDATA = 1
+ addFiles.sources = SerialPort.dll
+ addFiles.path = !:/sys/bin
+ DEPLOYMENT += addFiles
+
+ # FIXME !!!
+ #INCLUDEPATH += c:/Nokia/devices/Nokia_Symbian3_SDK_v1.0/epoc32/include/platform
+ INCLUDEPATH += c:/QtSDK/Symbian/SDKs/Symbian3Qt473/epoc32/include/platform
+
+ PRIVATE_HEADERS += \
+ $$PWD/serialport_symbian_p.h
+
+ SOURCES += \
+ $$PWD/serialport_symbian.cpp \
+ $$PWD/serialportinfo_symbian.cpp
+
+ LIBS += -leuser -lefsrv -lc32
+}
+
+unix:!symbian {
+ PRIVATE_HEADERS += \
+ $$PWD/ttylocker_unix_p.h \
+ $$PWD/serialport_unix_p.h
+
+ SOURCES += \
+ $$PWD/ttylocker_unix.cpp \
+ $$PWD/serialport_unix.cpp \
+ $$PWD/serialportinfo_unix.cpp
+
+ macx {
+ SOURCES += $$PWD/serialportinfo_mac.cpp
+
+ LIBS += -framework IOKit -framework CoreFoundation
+ } else {
+ linux*:contains( DEFINES, HAVE_LIBUDEV ) {
+ LIBS += -ludev
+ }
+ }
+}
+
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
diff --git a/src/serialport/serialport.cpp b/src/serialport/serialport.cpp
new file mode 100644
index 0000000..178a835
--- /dev/null
+++ b/src/serialport/serialport.cpp
@@ -0,0 +1,1086 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialport.h"
+#include "serialportinfo.h"
+
+#ifdef Q_OS_WIN
+#include "serialport_win_p.h"
+#elif defined (Q_OS_SYMBIAN)
+#include "serialport_symbian_p.h"
+#elif defined (Q_OS_UNIX)
+#include "serialport_unix_p.h"
+#else
+#error Unsupported OS
+#endif
+
+#ifndef SERIALPORT_BUFFERSIZE
+# define SERIALPORT_BUFFERSIZE 16384
+#endif
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+SerialPortPrivateData::SerialPortPrivateData(SerialPort *q)
+ : readBufferMaxSize(0)
+ , readBuffer(SERIALPORT_BUFFERSIZE)
+ , writeBuffer(SERIALPORT_BUFFERSIZE)
+ , portError(SerialPort::NoError)
+ , inputRate(0)
+ , outputRate(0)
+ , dataBits(SerialPort::UnknownDataBits)
+ , parity(SerialPort::UnknownParity)
+ , stopBits(SerialPort::UnknownStopBits)
+ , flow(SerialPort::UnknownFlowControl)
+ , restoreSettingsOnClose(true)
+ , q_ptr(q)
+{
+}
+
+int SerialPortPrivateData::timeoutValue(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return msecs;
+ msecs -= elapsed;
+ return qMax(msecs, 0);
+}
+
+/*!
+ \class SerialPort
+
+ \brief The SerialPort class provides functions to access
+ serial ports.
+
+ \reentrant
+ \ingroup serialport-main
+ \inmodule QtAddOnSerialPort
+ \since 5.0
+
+ This class resembles the functionality and behavior of the QAbstractSocket
+ class in many aspects, for instance the I/O operations, the implementation
+ of the wait methods, the internal architecture and so forth. Certain
+ SerialPort method implementations were taken directly from QAbstractSocket
+ with only minor changes.
+
+ The features of the implementation and the conduct of the class are
+ listed below:
+
+ \list
+ \o Provides only common functionality which includes
+ configuring, I/O data stream, get and set control signals of the
+ RS-232 lines.
+ \o Does not support for terminal features as echo, control CR/LF and so
+ forth.
+ \o Always works in binary mode.
+ \o Does not support the native ability for configuring timeouts
+ and delays while reading.
+ \o Does not provide tracking and notification when the state
+ of RS-232 lines was changed.
+ \endlist
+
+ To get started with the SerialPort class, first create an object of
+ that.
+
+ Then, call the setPort() method in order to assign the object with the name
+ of the desired serial port (which has to be present in the system).
+ The name has to follow a certain format, which is platform dependent.
+
+ The helper class SerialPortInfo allows the enumeration of all the serial
+ ports in the system. This is useful to obtain the correct serial port name.
+
+ The SerialPortInfo class can also be used as an input parameter for the
+ setPort() method (to retrieve the currently assigned name, use the
+ portName() method).
+
+ After that, the serial port can be opened in read-only (r/o), write-only
+ (w/o) or read-write (r/w) mode using the open() method.
+
+ Note: The serial port is always opened with exclusive access
+ (i.e. no other process or thread can access an already opened serial port).
+
+ Having successfully opened, the SerialPort determines its current
+ configuration and initializes itself to that. To access the current
+ configuration use the rate(), dataBits(), parity(), stopBits(), and
+ flowControl() methods.
+
+ If these settings are satisfying, the I/O operation can be proceed with.
+ Otherwise the port can be reconfigured to the desired setting using the
+ setRate(), setDataBits(), setParity(), setStopBits(), and setFlowControl()
+ methods.
+
+ Read or write the data by calling read() or write(). Alternatively the
+ readLine() and readAll() convenience methods can also be invoked. The
+ SerialPort class also inherits the getChar(), putChar(), and ungetChar()
+ methods from the QIODevice class. Those methods work on single bytes. The
+ bytesWritten() signal is emitted when data has been written to the serial
+ port. Note that, Qt does not limit the write buffer size, which can be
+ monitored by listening to this signal.
+
+ The readyRead() signal is emitted every time a new chunk of data
+ has arrived. The bytesAvailable() method then returns the number of bytes
+ that are available for reading. Typically, the readyRead() signal would be
+ connected to a slot and all data available could be read in there.
+
+ If not all the data is read at once, the remaining data will
+ still be available later. Any new incoming data will be
+ appended to the SerialPort's internal read buffer. In order to limit the
+ size of the read buffer, call setReadBufferSize().
+
+ The status of the control lines is determined with the dtr(), rts(), and
+ lines() methods. To change the control line status, use the setDtr(), and
+ setRts() methods.
+
+ To close the serial port, call the close() method. After all the pending data
+ has been written to the serial port, the SerialPort class actually closes
+ the descriptor.
+
+ SerialPort provides a set of functions that suspend the calling
+ thread until certain signals are emitted. These functions can be
+ used to implement blocking serial ports:
+
+ \list
+ \o waitForReadyRead() blocks until new data is available for
+ reading.
+
+ \o waitForBytesWritten() blocks until one payload of data has been
+ written to the serial port.
+ \endlist
+
+ See the following example:
+
+ \code
+ int numRead = 0, numReadTotal = 0;
+ char buffer[50];
+
+ forever {
+ numRead = serial.read(buffer, 50);
+
+ // Do whatever with the array
+
+ numReadTotal += numRead;
+ if (numRead == 0 && !serial.waitForReadyRead())
+ break;
+ }
+ \endcode
+
+ If \l{QIODevice::}{waitForReadyRead()} returns false, the
+ connection has been closed or an error has occurred.
+
+ Programming with a blocking serial port is radically different from
+ programming with a non-blocking serial port. A blocking serial port
+ does not require an event loop and typically leads to simpler code.
+ However, in a GUI application, blocking serial port should only be
+ used in non-GUI threads, to avoid freezing the user interface.
+
+ See the \l examples/terminal and \l examples/blockingterminal
+ examples for an overview of both approaches.
+
+ The use of blocking functions is discouraged together with signals. One of
+ the two possibilities should be used.
+
+ The SerialPort class can be used with QTextStream and QDataStream's stream
+ operators (operator<<() and operator>>()). There is one issue to be aware
+ of, though: make sure that enough data is available before attempting to
+ read by using the operator>>() overloaded operator.
+
+ \sa SerialPortInfo
+*/
+
+/*!
+ \enum SerialPort::Direction
+
+ This enum describes the possible directions of the data transmission.
+ Note: This enumeration is used for setting the baud rate of the device
+ separately for each direction in case some operating systems (i.e. POSIX-like).
+
+ \value Input Input direction.
+ \value Output Output direction.
+ \value AllDirections Simultaneously in two directions.
+*/
+
+/*!
+ \enum SerialPort::Rate
+
+ This enum describes the baud rate which the communication device operates
+ with. Note: only the most common standard rates are listed in this enum.
+
+ \value Rate1200 1200 baud.
+ \value Rate2400 2400 baud.
+ \value Rate4800 4800 baud.
+ \value Rate9600 9600 baud.
+ \value Rate19200 19200 baud.
+ \value Rate38400 38400 baud.
+ \value Rate57600 57600 baud.
+ \value Rate115200 115200 baud.
+ \value UnknownRate Unknown baud.
+
+ \sa setRate(), rate()
+*/
+
+/*!
+ \enum SerialPort::DataBits
+
+ This enum describes the number of data bits used.
+
+ \value Data5 Five bits.
+ \value Data6 Six bits.
+ \value Data7 Seven bits
+ \value Data8 Eight bits.
+ \value UnknownDataBits Unknown number of bits.
+
+ \sa setDataBits(), dataBits()
+*/
+
+/*!
+ \enum SerialPort::Parity
+
+ This enum describes the parity scheme used.
+
+ \Value NoParity No parity.
+ \value EvenParity Even parity.
+ \value OddParity Odd parity.
+ \value SpaceParity Space parity.
+ \value MarkParity Mark parity.
+ \value UnknownParity Unknown parity.
+
+ \sa setParity(), parity()
+*/
+
+/*!
+ \enum SerialPort::StopBits
+
+ This enum describes the number of stop bits used.
+
+ \value OneStop 1 stop bit.
+ \value OneAndHalfStop 1.5 stop bits.
+ \value TwoStop 2 stop bits.
+ \value UnknownStopBits Unknown number of stop bit.
+
+ \sa setStopBits(), stopBits()
+*/
+
+/*!
+ \enum SerialPort::FlowControl
+
+ This enum describes the flow control used.
+
+ \value NoFlowControl No flow control.
+ \value HardwareControl Hardware flow control (RTS/CTS).
+ \value SoftwareControl Software flow control (XON/XOFF).
+ \value UnknownFlowControl Unknown flow control.
+
+ \sa setFlowControl(), flowControl()
+*/
+
+/*!
+ \enum SerialPort::Line
+
+ This enum describes the possible RS-232 pinout signals.
+
+ \value Le DSR (data set ready/line enable).
+ \value Dtr DTR (data terminal ready).
+ \value Rts RTS (request to send).
+ \value St Secondary TXD (transmit).
+ \value Sr Secondary RXD (receive).
+ \value Cts CTS (clear to send).
+ \value Dcd DCD (data carrier detect).
+ \value Ri RNG (ring).
+ \value Dsr DSR (data set ready).
+
+ \sa lines(), setDtr(), setRts(), dtr(), rts()
+*/
+
+/*!
+ \enum SerialPort::DataErrorPolicy
+
+ This enum describes the policies for the received symbols
+ while parity errors were detected.
+
+ \value SkipPolicy Skips the bad character.
+ \value PassZeroPolicy Replaces bad character to zero.
+ \value IgnorePolicy Ignores the error for a bad character.
+ \value StopReceivingPolicy Stops data reception on error.
+ \value UnknownPolicy Unknown policy.
+
+ \sa setDataErrorPolicy(), dataErrorPolicy()
+*/
+
+/*!
+ \enum SerialPort::PortError
+
+ This enum describes the errors that may be returned by the error()
+ method.
+
+ \value NoError No error occurred.
+ \value NoSuchDeviceError An error occurred while attempting to
+ open an non-existing device.
+ \value PermissionDeniedError An error occurred while attempting to
+ open an already opened device by another process or a user not
+ having enough permission and credentials to open.
+ \value DeviceAlreadyOpenedError An error occurred while attempting to
+ open an already opened device in this object.
+ \value DeviceIsNotOpenedError An error occurred while attempting to
+ control a device still closed.
+ \value ParityError Parity error detected by the hardware while reading data.
+ \value FramingError Framing error detected by the hardware while reading data.
+ \value BreakConditionError Break condition detected by the hardware on
+ the input line.
+ \value IoError An I/O error occurred while reading or writing the data.
+ \value UnsupportedPortOperationError The requested device operation is
+ not supported or prohibited by the running operating system.
+ \value UnknownPortError An unidentified error occurred.
+
+ \sa error(), unsetError()
+*/
+
+
+
+/*!
+ Constructs a new serial port object with the given \a parent.
+*/
+SerialPort::SerialPort(QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new SerialPortPrivate(this))
+{}
+
+/*!
+ Constructs a new serial port object with the given \a parent
+ to represent the serial port with the specified \a name.
+
+ The name should have a specific format; see the setPort() method.
+*/
+SerialPort::SerialPort(const QString &name, QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new SerialPortPrivate(this))
+{
+ setPort(name);
+}
+
+/*!
+ Constructs a new serial port object with the given \a parent
+ to represent the serial port with the specified a helper
+ class \a info.
+*/
+SerialPort::SerialPort(const SerialPortInfo &info, QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new SerialPortPrivate(this))
+{
+ setPort(info);
+}
+
+/*!
+ Closes the serial port, if neccessary, and then destroys object.
+*/
+SerialPort::~SerialPort()
+{
+ /**/
+ close();
+ delete d_ptr;
+}
+
+/*!
+ Sets the \a name of the port. The name may be in any format;
+ either short, or also as system location (with all the prefixes and
+ postfixed). As a result, this name will be automatically written
+ and converted into an internal variable as system location.
+
+ \sa portName(), SerialPortInfo
+*/
+void SerialPort::setPort(const QString &name)
+{
+ Q_D(SerialPort);
+ d->systemLocation = SerialPortPrivate::portNameToSystemLocation(name);
+}
+
+/*!
+ Sets the port stored in the serial port info instance \a info.
+
+ \sa portName(), SerialPortInfo
+*/
+void SerialPort::setPort(const SerialPortInfo &info)
+{
+ Q_D(SerialPort);
+ d->systemLocation = SerialPortPrivate::portNameToSystemLocation(info.systemLocation());
+}
+
+/*!
+ Returns the name set by setPort() or to the SerialPort constructors.
+ This name is short, i.e. it extract and convert out from the internal
+ variable system location of the device. Conversion algorithm is
+ platform specific:
+ \table
+ \header
+ \o Platform
+ \o Brief Description
+ \row
+ \o Windows
+ \o Removes the prefix "\\\\.\\" from the system location
+ and returns the remainder of the string.
+ \row
+ \o Windows CE
+ \o Removes the postfix ":" from the system location
+ and returns the remainder of the string.
+ \row
+ \o Symbian
+ \o Returns the system location as it is,
+ as it is equivalent to the port name.
+ \row
+ \o GNU/Linux
+ \o Removes the prefix "/dev/" from the system location
+ and returns the remainder of the string.
+ \row
+ \o Mac OSX
+ \o Removes the prefix "/dev/cu." and "/dev/tty." from the
+ system location and returns the remainder of the string.
+ \row
+ \o Other *nix
+ \o The same as for GNU/Linux.
+ \endtable
+
+ \sa setPort(), SerialPortInfo::portName()
+*/
+QString SerialPort::portName() const
+{
+ Q_D(const SerialPort);
+ return SerialPortPrivate::portNameFromSystemLocation(d->systemLocation);
+}
+
+/*! \reimp
+ Opens the serial port using OpenMode \a mode, and then returns true if
+ successful; otherwise returns false with and sets an error code which can be
+ obtained by calling the error() method.
+
+ \warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly,
+ or QIODevice::ReadWrite. This may also have additional flags, such as
+ QIODevice::Unbuffered. Other modes are unsupported.
+
+ \sa QIODevice::OpenMode, setPort()
+*/
+bool SerialPort::open(OpenMode mode)
+{
+ Q_D(SerialPort);
+
+ if (isOpen()) {
+ d->portError = SerialPort::DeviceAlreadyOpenedError;
+ return false;
+ }
+
+ // Define while not supported modes.
+ static const OpenMode unsupportedModes = Append | Truncate | Text | Unbuffered;
+ if ((mode & unsupportedModes) || mode == NotOpen) {
+ d->portError = SerialPort::UnsupportedPortOperationError;
+ return false;
+ }
+
+ unsetError();
+ if (d->open(mode)) {
+ QIODevice::open(mode);
+ return true;
+ }
+ return false;
+}
+
+/*! \reimp
+ Calls SerialPort::flush() and closes the serial port.
+ Errors from flush are ignored.
+
+ \sa QIODevice::close()
+*/
+void SerialPort::close()
+{
+ Q_D(SerialPort);
+ if (!isOpen()) {
+ d->portError = SerialPort::DeviceIsNotOpenedError;
+ return;
+ }
+
+ QIODevice::close();
+ d->close();
+}
+
+/*!
+ Sets or clears the flag \a restore, which allows to restore the
+ previous settings while closing the serial port. If this flag
+ is true, the settings will be restored; otherwise not.
+ The default state of the SerialPort class is configured to restore the
+ settings.
+
+ \sa restoreSettingsOnClose()
+*/
+void SerialPort::setRestoreSettingsOnClose(bool restore)
+{
+ Q_D( SerialPort);
+ d->restoreSettingsOnClose = restore;
+}
+
+/*!
+ Returns the current status of the restore flag settings on
+ closing the port. The default SerialPort is configured to
+ restore the settings.
+
+ \sa setRestoreSettingsOnClose()
+*/
+bool SerialPort::restoreSettingsOnClose() const
+{
+ Q_D(const SerialPort);
+ return d->restoreSettingsOnClose;
+}
+
+/*!
+ Sets the desired data rate \a rate for a given direction \a dir. If
+ successful, returns true; otherwise returns false and sets an error code
+ which can be obtained by calling error(). To set the baud rate, use the
+ enumeration SerialPort::Rate or any positive qint32 value.
+
+ \warning For OS Windows, Windows CE, Symbian supported only
+ AllDirections flag.
+
+ \sa rate()
+*/
+bool SerialPort::setRate(qint32 rate, Directions dir)
+{
+ Q_D(SerialPort);
+ if (d->setRate(rate, dir)) {
+ if (dir & SerialPort::Input)
+ d->inputRate = rate;
+ if (dir & SerialPort::Output)
+ d->outputRate = rate;
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current baud rate of the chosen direction \a dir.
+
+ \warning Returns equal rate in any direction for Operating Systems as
+ Windows, Windows CE, and Symbian.
+
+ \sa setRate()
+*/
+qint32 SerialPort::rate(Directions dir) const
+{
+ Q_D(const SerialPort);
+ if (dir == SerialPort::AllDirections)
+ return d->inputRate == d->outputRate ?
+ d->inputRate : SerialPort::UnknownRate;
+ return dir & SerialPort::Input ? d->inputRate : d->outputRate;
+}
+
+/*!
+ Sets the desired number of data bits \a dataBits in a frame.
+ If successful, returns true; otherwise returns false and sets an error
+ code which can be obtained by calling the error() method.
+
+ \sa dataBits()
+*/
+bool SerialPort::setDataBits(DataBits dataBits)
+{
+ Q_D(SerialPort);
+ if (d->setDataBits(dataBits)) {
+ d->dataBits = dataBits;
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current number of data bits in a frame.
+
+ \sa setDataBits()
+*/
+SerialPort::DataBits SerialPort::dataBits() const
+{
+ Q_D(const SerialPort);
+ return d->dataBits;
+}
+
+/*!
+ Sets the desired parity \a parity checking mode.
+ If successful, returns true; otherwise returns false and sets an error
+ code which can be obtained by calling the error() method.
+
+ \sa parity()
+*/
+bool SerialPort::setParity(Parity parity)
+{
+ Q_D(SerialPort);
+ if (d->setParity(parity)) {
+ d->parity = parity;
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current parity checking mode.
+
+ \sa setParity()
+*/
+SerialPort::Parity SerialPort::parity() const
+{
+ Q_D(const SerialPort);
+ return d->parity;
+}
+
+/*!
+ Sets the desired number of stop bits \a stopBits in a frame. If successful,
+ returns true; otherwise returns false and sets an error code which can be
+ obtained by calling the error() method.
+
+ \sa stopBits()
+*/
+bool SerialPort::setStopBits(StopBits stopBits)
+{
+ Q_D(SerialPort);
+ if (d->setStopBits(stopBits)) {
+ d->stopBits = stopBits;
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current number of stop bits.
+
+ \sa setStopBits()
+*/
+SerialPort::StopBits SerialPort::stopBits() const
+{
+ Q_D(const SerialPort);
+ return d->stopBits;
+}
+
+/*!
+ Sets the desired number flow control mode \a flow.
+ If successful, returns true; otherwise returns false and sets an error
+ code which can be obtained by calling the error() method.
+
+ \sa flowControl()
+*/
+bool SerialPort::setFlowControl(FlowControl flow)
+{
+ Q_D(SerialPort);
+ if (d->setFlowControl(flow)) {
+ d->flow = flow;
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current flow control mode.
+
+ \sa setFlowControl()
+*/
+SerialPort::FlowControl SerialPort::flowControl() const
+{
+ Q_D(const SerialPort);
+ return d->flow;
+}
+
+/*!
+ Returns the current state of the line signal DTR.
+ If the signal state high, the return true; otherwise returns false;
+
+ \sa lines()
+*/
+bool SerialPort::dtr() const
+{
+ Q_D(const SerialPort);
+ return d->lines() & SerialPort::Dtr;
+}
+
+/*!
+ Returns the current state of the line signal RTS.
+ If the signal state high, the return true; otherwise returns false;
+
+ \sa lines()
+*/
+bool SerialPort::rts() const
+{
+ Q_D(const SerialPort);
+ return d->lines() & SerialPort::Rts;
+}
+
+/*!
+ Returns the bitmap states of the line signals.
+ From this result, it is possible to allocate the state of the
+ desired signal by applying a mask "AND", where the mask is
+ the desired enumeration value from SerialPort::Lines.
+
+ \sa dtr(), rts(), setDtr(), setRts()
+*/
+SerialPort::Lines SerialPort::lines() const
+{
+ Q_D(const SerialPort);
+ return d->lines();
+}
+
+/*!
+ This function writes as much as possible from the internal write
+ buffer to the underlying serial port without blocking. If any data
+ was written, this function returns true; otherwise returns false.
+
+ Call this function for sending the buffered data immediately to the serial
+ port. The number of bytes successfully written depends on the operating
+ system. In most cases, this function does not need to be called, because the
+ SerialPort class will start sending data automatically once control is
+ returned to the event loop. In the absence of an event loop, call
+ waitForBytesWritten() instead.
+
+ \sa write(), waitForBytesWritten()
+*/
+bool SerialPort::flush()
+{
+ Q_D(SerialPort);
+ return d->flush();
+}
+
+/*!
+ Discards all characters from the output or input buffer, depending on
+ a given direction \a dir. Including clear an internal class buffers and
+ the UART (driver) buffers. Also terminate pending read or write operations.
+ If successful, returns true; otherwise returns false.
+*/
+bool SerialPort::clear(Directions dir)
+{
+ Q_D(SerialPort);
+ if (dir & Input)
+ d->readBuffer.clear();
+ if (dir & Output)
+ d->writeBuffer.clear();
+ return d->clear(dir);
+}
+
+/*! \reimp
+
+ Returns true if no more data is currently available for reading; otherwise
+ returns false.
+
+ This function is most commonly used when reading data from the
+ serial port in a loop. For example:
+
+ \code
+ // This slot is connected to SerialPort::readyRead()
+ void SerialPortClass::readyReadSlot()
+ {
+ while (!port.atEnd()) {
+ QByteArray data = port.read(100);
+ ....
+ }
+ }
+ \endcode
+
+ \sa bytesAvailable(), readyRead()
+ */
+bool SerialPort::atEnd() const
+{
+ Q_D(const SerialPort);
+ return QIODevice::atEnd() && (!isOpen() || d->readBuffer.isEmpty());
+}
+
+/*!
+ Sets the error policy \a policy process received character in
+ the case of parity error detection. If successful, returns
+ true; otherwise returns false. The default policy set is IgnorePolicy.
+
+ \sa dataErrorPolicy()
+*/
+bool SerialPort::setDataErrorPolicy(DataErrorPolicy policy)
+{
+ Q_D(SerialPort);
+ const bool ret = d->policy == policy || d->setDataErrorPolicy(policy);
+ if (ret)
+ d->policy = policy;
+ return ret;
+}
+
+/*!
+ Returns current error policy.
+
+ \sa setDataErrorPolicy()
+*/
+SerialPort::DataErrorPolicy SerialPort::dataErrorPolicy() const
+{
+ Q_D(const SerialPort);
+ return d->policy;
+}
+
+/*!
+ Returns the serial port's error status.
+
+ The I/O device status returns an error code. For example, if open()
+ returns false, or a read/write operation returns -1, this function can
+ be called to find out the reason why the operation failed.
+
+ \sa unsetError()
+*/
+SerialPort::PortError SerialPort::error() const
+{
+ Q_D(const SerialPort);
+ return d->portError;
+}
+
+/*!
+ Clears the error code to SerialPort::NoError.
+
+ \sa error()
+*/
+void SerialPort::unsetError()
+{
+ Q_D(SerialPort);
+ d->portError = SerialPort::NoError;
+}
+
+/*!
+ Returns the size of the internal read buffer. This limits the
+ amount of data that the client can receive before calling the read()
+ or readAll() methods.
+
+ A read buffer size of 0 (the default) means that the buffer has
+ no size limit, ensuring that no data is lost.
+
+ \sa setReadBufferSize(), read()
+*/
+qint64 SerialPort::readBufferSize() const
+{
+ Q_D(const SerialPort);
+ return d->readBufferMaxSize;
+}
+
+/*!
+ Sets the size of SerialPort's internal read buffer to be \a
+ size bytes.
+
+ If the buffer size is limited to a certain size, SerialPort
+ will not buffer more than this size of data. Exceptionally, a buffer
+ size of 0 means that the read buffer is unlimited and all
+ incoming data is buffered. This is the default.
+
+ This option is useful if the data is only read at certain points
+ in time (for instance in a real-time streaming application) or if the serial
+ port should be protected against receiving too much data, which may
+ eventually causes that the application runs out of memory.
+
+ \sa readBufferSize(), read()
+*/
+void SerialPort::setReadBufferSize(qint64 size)
+{
+ Q_D(SerialPort);
+
+ if (d->readBufferMaxSize == size)
+ return;
+ d->readBufferMaxSize = size;
+}
+
+/*! \reimp
+ Always returns true. The serial port is a sequential device.
+*/
+bool SerialPort::isSequential() const
+{
+ return true;
+}
+
+/*! \reimp
+ Returns the number of incoming bytes that are waiting to be read.
+
+ \sa bytesToWrite(), read()
+*/
+qint64 SerialPort::bytesAvailable() const
+{
+ Q_D(const SerialPort);
+ return d->readBuffer.size() + QIODevice::bytesAvailable();
+}
+
+/*! \reimp
+ Returns the number of bytes that are waiting to be written. The
+ bytes are written when control goes back to the event loop or
+ when flush() is called.
+
+ \sa bytesAvailable(), flush()
+*/
+qint64 SerialPort::bytesToWrite() const
+{
+ Q_D(const SerialPort);
+ return d->writeBuffer.size() + QIODevice::bytesToWrite();
+}
+
+/*! \reimp
+ Returns true if a line of data can be read from the serial port;
+ otherwise returns false.
+
+ \sa readLine()
+*/
+bool SerialPort::canReadLine() const
+{
+ Q_D(const SerialPort);
+ const bool hasLine = d->readBuffer.canReadLine();
+ return hasLine || QIODevice::canReadLine();
+}
+
+/*! \reimp
+ This function blocks until new data is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+
+ \sa waitForBytesWritten()
+*/
+bool SerialPort::waitForReadyRead(int msecs)
+{
+ Q_D(SerialPort);
+ return d->waitForReadyRead(msecs);
+}
+
+/*! \reimp
+*/
+bool SerialPort::waitForBytesWritten(int msecs)
+{
+ Q_D(SerialPort);
+ return d->waitForBytesWritten(msecs);
+}
+
+/*!
+ Sets the desired state of the line signal DTR,
+ depending on the flag \a set. If successful, returns true;
+ otherwise returns false.
+
+ If the flag is true then the DTR signal is set to high; otherwise low.
+
+ \sa lines(), dtr()
+*/
+bool SerialPort::setDtr(bool set)
+{
+ Q_D(SerialPort);
+ return d->setDtr(set);
+}
+
+/*!
+ Sets the desired state of the line signal RTS,
+ depending on the flag \a set. If successful, returns true;
+ otherwise returns false.
+
+ If the flag is true then the RTS signal is set to high; otherwise low.
+
+ \sa lines(), rts()
+*/
+bool SerialPort::setRts(bool set)
+{
+ Q_D(SerialPort);
+ return d->setRts(set);
+}
+
+/*!
+ Sends a continuous stream of zero bits during a specified period
+ of time \a duration in msec if the terminal is using asynchronous
+ serial data. If successful, returns true; otherwise returns false.
+
+ If the duration is zero then zero bits are transmitted by at least
+ 0.25 seconds, but no more than 0.5 seconds.
+
+ If the duration is non zero then zero bits are transmitted within a certain
+ period of time depending on the implementation.
+
+ \sa setBreak(), clearBreak()
+*/
+bool SerialPort::sendBreak(int duration)
+{
+ Q_D(SerialPort);
+ return d->sendBreak(duration);
+}
+
+/*!
+ Controls the signal break, depending on the flag \a set.
+ If successful, returns true; otherwise returns false.
+
+ If \a set is true then enables the break transmission; otherwise disables.
+
+ \sa clearBreak(), sendBreak()
+*/
+bool SerialPort::setBreak(bool set)
+{
+ Q_D(SerialPort);
+ return d->setBreak(set);
+}
+
+/*! \reimp
+*/
+qint64 SerialPort::readData(char *data, qint64 maxSize)
+{
+ Q_D(SerialPort);
+ return d->readFromBuffer(data, maxSize);
+}
+
+/*! \reimp
+*/
+qint64 SerialPort::readLineData(char *data, qint64 maxSize)
+{
+ return QIODevice::readLineData(data, maxSize);
+}
+
+/*! \reimp
+*/
+qint64 SerialPort::writeData(const char *data, qint64 maxSize)
+{
+ Q_D(SerialPort);
+ return d->writeToBuffer(data, maxSize);
+}
+
+/*!
+ \fn bool SerialPort::clearBreak(bool clear)
+
+ Controls the signal break, depending on the flag \a clear.
+ If successful, returns true; otherwise returns false.
+
+ If clear is false then enables the break transmission; otherwise disables.
+
+ \sa setBreak(), sendBreak()
+*/
+
+#include "moc_serialport.cpp"
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialport.h b/src/serialport/serialport.h
new file mode 100644
index 0000000..769ecfb
--- /dev/null
+++ b/src/serialport/serialport.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig2@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_H
+#define SERIALPORT_H
+
+#include <QtCore/qiodevice.h>
+
+#include "serialport-global.h"
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortInfo;
+class SerialPortPrivate;
+
+class Q_SERIALPORT_EXPORT SerialPort : public QIODevice
+{
+ Q_OBJECT
+
+ //Q_PROPERTY(qint32 rate READ rate WRITE setRate)
+ //Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits)
+ //Q_PROPERTY(Parity parity READ parity WRITE setParity)
+ //Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits)
+ //Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl)
+ //Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy)
+ //Q_PROPERTY(bool dtr READ dtr WRITE setDtr)
+ //Q_PROPERTY(bool rts READ rts WRITE setRts)
+ //Q_PROPERTY(PortError error READ error RESET unsetError)
+ //Q_PROPERTY(bool restoreSettingsOnClose READ restoreSettingsOnClose WRITE setRestoreSettingsOnClose)
+
+ Q_ENUMS( Directions Rate DataBits Parity StopBits FlowControl Lines DataErrorPolicy PortError )
+
+public:
+
+ enum Direction {
+ Input = 1,
+ Output = 2,
+ AllDirections = Input | Output
+ };
+ Q_DECLARE_FLAGS(Directions, Direction)
+
+ enum Rate {
+ Rate1200 = 1200,
+ Rate2400 = 2400,
+ Rate4800 = 4800,
+ Rate9600 = 9600,
+ Rate19200 = 19200,
+ Rate38400 = 38400,
+ Rate57600 = 57600,
+ Rate115200 = 115200,
+ UnknownRate = -1
+ };
+
+ enum DataBits {
+ Data5 = 5,
+ Data6 = 6,
+ Data7 = 7,
+ Data8 = 8,
+ UnknownDataBits = -1
+ };
+
+ enum Parity {
+ NoParity = 0,
+ EvenParity = 2,
+ OddParity = 3,
+ SpaceParity = 4,
+ MarkParity = 5,
+ UnknownParity = -1
+ };
+
+ enum StopBits {
+ OneStop = 1,
+ OneAndHalfStop = 3,
+ TwoStop = 2,
+ UnknownStopBits = -1
+ };
+
+ enum FlowControl {
+ NoFlowControl,
+ HardwareControl,
+ SoftwareControl,
+ UnknownFlowControl = -1
+ };
+
+ enum Line {
+ Le = 0x01,
+ Dtr = 0x02,
+ Rts = 0x04,
+ St = 0x08,
+ Sr = 0x10,
+ Cts = 0x20,
+ Dcd = 0x40,
+ Ri = 0x80,
+ Dsr = Le
+ };
+ Q_DECLARE_FLAGS(Lines, Line)
+
+ enum DataErrorPolicy {
+ SkipPolicy,
+ PassZeroPolicy,
+ IgnorePolicy,
+ StopReceivingPolicy,
+ UnknownPolicy = -1
+ };
+
+ enum PortError {
+ NoError,
+ NoSuchDeviceError,
+ PermissionDeniedError,
+ DeviceAlreadyOpenedError,
+ DeviceIsNotOpenedError,
+ ParityError,
+ FramingError,
+ BreakConditionError,
+ IoError,
+ UnsupportedPortOperationError,
+ UnknownPortError
+ };
+
+ explicit SerialPort(QObject *parent = 0);
+ explicit SerialPort(const QString &name, QObject *parent = 0);
+ explicit SerialPort(const SerialPortInfo &info, QObject *parent = 0);
+ virtual ~SerialPort();
+
+ void setPort(const QString &port);
+ void setPort(const SerialPortInfo &info);
+ QString portName() const;
+
+ virtual bool open(OpenMode mode);
+ virtual void close();
+
+ void setRestoreSettingsOnClose(bool restore);
+ bool restoreSettingsOnClose() const;
+
+ bool setRate(qint32 rate, Directions dir = AllDirections);
+ qint32 rate(Directions dir = AllDirections) const;
+
+ bool setDataBits(DataBits dataBits);
+ DataBits dataBits() const;
+
+ bool setParity(Parity parity);
+ Parity parity() const;
+
+ bool setStopBits(StopBits stopBits);
+ StopBits stopBits() const;
+
+ bool setFlowControl(FlowControl flow);
+ FlowControl flowControl() const;
+
+ bool dtr() const;
+ bool rts() const;
+
+ Lines lines() const;
+
+ bool flush();
+ bool clear(Directions dir = AllDirections);
+ virtual bool atEnd() const;
+
+ bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy);
+ DataErrorPolicy dataErrorPolicy() const;
+
+ PortError error() const;
+ void unsetError();
+
+ qint64 readBufferSize() const;
+ void setReadBufferSize(qint64 size);
+
+ virtual bool isSequential() const;
+
+ virtual qint64 bytesAvailable() const;
+ virtual qint64 bytesToWrite() const;
+ virtual bool canReadLine() const;
+
+ virtual bool waitForReadyRead(int msecs);
+ virtual bool waitForBytesWritten(int msecs);
+
+public Q_SLOTS:
+ bool setDtr(bool set);
+ bool setRts(bool set);
+ bool sendBreak(int duration = 0);
+ bool setBreak(bool set = true);
+ bool clearBreak(bool clear = true);
+
+protected:
+ virtual qint64 readData(char *data, qint64 maxSize);
+ virtual qint64 readLineData(char *data, qint64 maxSize);
+ virtual qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+ SerialPortPrivate * const d_ptr;
+
+ Q_DECLARE_PRIVATE(SerialPort)
+ Q_DISABLE_COPY(SerialPort)
+};
+
+inline bool SerialPort::clearBreak(bool clear)
+{ return setBreak(!clear); }
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(SerialPort::Directions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(SerialPort::Lines)
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_H
diff --git a/src/serialport/serialport.pro b/src/serialport/serialport.pro
new file mode 100644
index 0000000..5fdec9f
--- /dev/null
+++ b/src/serialport/serialport.pro
@@ -0,0 +1,18 @@
+QT = core
+DEFINES += QT_SERIALPORT_LIB
+VERSION = 1.0.0
+
+include($$PWD/serialport-lib.pri)
+
+greaterThan(QT_MAJOR_VERSION, 4) {
+ load(qt_build_config)
+ QT += core-private
+ TARGET = QtAddOnSerialPort
+ load(qt_module)
+} else {
+ TEMPLATE = lib
+ TARGET = $$qtLibraryTarget(SerialPort$$QT_LIBINFIX)
+ include($$PWD/qt4support/install-helper.pri)
+ CONFIG += module create_prl
+ mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET
+}
diff --git a/src/serialport/serialport_p.h b/src/serialport/serialport_p.h
new file mode 100644
index 0000000..852e7f5
--- /dev/null
+++ b/src/serialport/serialport_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_P_H
+#define SERIALPORT_P_H
+
+#include "serialport.h"
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <private/qringbuffer_p.h>
+#else
+#include "qt4support/qringbuffer_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortPrivateData
+{
+ Q_DECLARE_PUBLIC(SerialPort)
+public:
+ enum IoConstants {
+ ReadChunkSize = 512,
+ WriteChunkSize = 512
+ };
+
+ SerialPortPrivateData(SerialPort *q);
+ int timeoutValue(int msecs, int elapsed);
+
+ qint64 readBufferMaxSize;
+ QRingBuffer readBuffer;
+ QRingBuffer writeBuffer;
+ SerialPort::PortError portError;
+ QString systemLocation;
+ qint32 inputRate;
+ qint32 outputRate;
+ SerialPort::DataBits dataBits;
+ SerialPort::Parity parity;
+ SerialPort::StopBits stopBits;
+ SerialPort::FlowControl flow;
+ SerialPort::DataErrorPolicy policy;
+ bool restoreSettingsOnClose;
+ SerialPort * const q_ptr;
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_P_H
diff --git a/src/serialport/serialport_symbian.cpp b/src/serialport/serialport_symbian.cpp
new file mode 100644
index 0000000..c2542fd
--- /dev/null
+++ b/src/serialport/serialport_symbian.cpp
@@ -0,0 +1,645 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialport_symbian_p.h"
+
+#include <e32base.h>
+//#include <e32test.h>
+#include <f32file.h>
+
+#include <QtCore/qregexp.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+// Physical device driver.
+#ifdef __WINS__
+_LIT(KPddName, "ECDRV");
+#else // defined (__EPOC32__)
+_LIT(KPddName, "EUART");
+#endif
+
+// Logical device driver.
+_LIT(KLddName,"ECOMM");
+
+// Modules names.
+_LIT(KRS232ModuleName, "ECUART");
+_LIT(KBluetoothModuleName, "BTCOMM");
+_LIT(KInfraRedModuleName, "IRCOMM");
+_LIT(KACMModuleName, "ECACM");
+
+// Return false on error load.
+static bool loadDevices()
+{
+ TInt r = KErrNone;
+#ifdef __WINS__
+ RFs fileServer;
+ r = User::LeaveIfError(fileServer.Connect());
+ if (r != KErrNone)
+ return false;
+ fileServer.Close ();
+#endif
+
+ r = User::LoadPhysicalDevice(KPddName);
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+
+ r = User::LoadLogicalDevice(KLddName);
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+
+#ifndef __WINS__
+ r = StartC32();
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+#endif
+
+ return true;
+}
+
+SerialPortPrivate::SerialPortPrivate(SerialPort *q)
+ : SerialPortPrivateData(q)
+ , errnum(KErrNone)
+{
+}
+
+bool SerialPortPrivate::open(QIODevice::OpenMode mode)
+{
+ // FIXME: Maybe need added check an ReadWrite open mode?
+ Q_UNUSED(mode)
+
+ if (!loadDevices()) {
+ portError = SerialPort::UnknownPortError;
+ return false;
+ }
+
+ RCommServ server;
+ errnum = server.Connect();
+ if (errnum != KErrNone) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ if (systemLocation.contains("BTCOMM"))
+ errnum = server.LoadCommModule(KBluetoothModuleName);
+ else if (systemLocation.contains("IRCOMM"))
+ errnum = server.LoadCommModule(KInfraRedModuleName);
+ else if (systemLocation.contains("ACM"))
+ errnum = server.LoadCommModule(KACMModuleName);
+ else
+ errnum = server.LoadCommModule(KRS232ModuleName);
+
+ if (errnum != KErrNone) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ // In Symbian OS port opening only in R/W mode?
+ TPtrC portName(static_cast<const TUint16*>(systemLocation.utf16()), systemLocation.length());
+ errnum = descriptor.Open(server, portName, ECommExclusive);
+
+ if (errnum != KErrNone) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ // Save current port settings.
+ errnum = descriptor.Config(restoredSettings);
+ if (errnum != KErrNone) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ detectDefaultSettings();
+ return true;
+}
+
+void SerialPortPrivate::close()
+{
+ if (restoreSettingsOnClose)
+ descriptor.SetConfig(restoredSettings);
+ descriptor.Close();
+}
+
+SerialPort::Lines SerialPortPrivate::lines() const
+{
+ SerialPort::Lines ret = 0;
+
+ TUint signalMask = 0;
+ descriptor.Signals(signalMask);
+
+ if (signalMask & KSignalCTS)
+ ret |= SerialPort::Cts;
+ if (signalMask & KSignalDSR)
+ ret |= SerialPort::Dsr;
+ if (signalMask & KSignalDCD)
+ ret |= SerialPort::Dcd;
+ if (signalMask & KSignalRNG)
+ ret |= SerialPort::Ri;
+ if (signalMask & KSignalRTS)
+ ret |= SerialPort::Rts;
+ if (signalMask & KSignalDTR)
+ ret |= SerialPort::Dtr;
+
+ //if (signalMask & KSignalBreak)
+ // ret |=
+ return ret;
+}
+
+bool SerialPortPrivate::setDtr(bool set)
+{
+ TInt r;
+ if (set)
+ r = descriptor.SetSignalsToMark(KSignalDTR);
+ else
+ r = descriptor.SetSignalsToSpace(KSignalDTR);
+
+ return r == KErrNone;
+}
+
+bool SerialPortPrivate::setRts(bool set)
+{
+ TInt r;
+ if (set)
+ r = descriptor.SetSignalsToMark(KSignalRTS);
+ else
+ r = descriptor.SetSignalsToSpace(KSignalRTS);
+
+ return r == KErrNone;
+}
+
+bool SerialPortPrivate::flush()
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::clear(SerialPort::Directions dir)
+{
+ TUint flags = 0;
+ if (dir & SerialPort::Input)
+ flags |= KCommResetRx;
+ if (dir & SerialPort::Output)
+ flags |= KCommResetTx;
+ TInt r = descriptor.ResetBuffers(flags);
+ return r == KErrNone;
+}
+
+bool SerialPortPrivate::sendBreak(int duration)
+{
+ TRequestStatus status;
+ descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000));
+ return false;
+}
+
+bool SerialPortPrivate::setBreak(bool set)
+{
+ // TODO: Implement me
+ return false;
+}
+
+qint64 SerialPortPrivate::bytesAvailable() const
+{
+ return descriptor.QueryReceiveBuffer();
+}
+
+qint64 SerialPortPrivate::bytesToWrite() const
+{
+ // TODO: Implement me
+ return 0;
+}
+
+qint64 SerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
+{
+ // TODO: Implement me
+ return -1;
+}
+
+qint64 SerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
+{
+ // TODO: Implement me
+ return -1;
+}
+
+bool SerialPortPrivate::waitForReadyRead(int msec)
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::waitForBytesWritten(int msec)
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::setRate(qint32 rate, SerialPort::Directions dir)
+{
+ if (dir != SerialPort::AllDirections) {
+ portError = SerialPort::UnsupportedPortOperationError;
+ return false;
+ }
+
+ rate = settingFromRate(rate);
+ if (rate)
+ currentSettings().iRate = static_cast<TBps>(rate);
+ else {
+ portError = SerialPort::UnsupportedPortOperationError;
+ return false;
+ }
+
+ return updateCommConfig();
+}
+
+bool SerialPortPrivate::setDataBits(SerialPort::DataBits dataBits)
+{
+ switch (dataBits) {
+ case SerialPort::Data5:
+ currentSettings().iDataBits = EData5;
+ break;
+ case SerialPort::Data6:
+ currentSettings().iDataBits = EData6;
+ break;
+ case SerialPort::Data7:
+ currentSettings().iDataBits = EData7;
+ break;
+ case SerialPort::Data8:
+ currentSettings().iDataBits = EData8;
+ break;
+ default:
+ currentSettings().iDataBits = EData8;
+ break;
+ }
+
+ return updateCommConfig();
+}
+
+bool SerialPortPrivate::setParity(SerialPort::Parity parity)
+{
+ switch (parity) {
+ case SerialPort::NoParity:
+ currentSettings().iParity = EParityNone;
+ break;
+ case SerialPort::EvenParity:
+ currentSettings().iParity = EParityEven;
+ break;
+ case SerialPort::OddParity:
+ currentSettings().iParity = EParityOdd;
+ break;
+ case SerialPort::MarkParity:
+ currentSettings().iParity = EParityMark;
+ break;
+ case SerialPort::SpaceParity:
+ currentSettings().iParity = EParitySpace;
+ break;
+ default:
+ currentSettings().iParity = EParityNone;
+ break;
+ }
+
+ return updateCommConfig();
+}
+
+bool SerialPortPrivate::setStopBits(SerialPort::StopBits stopBits)
+{
+ switch (stopBits) {
+ case SerialPort::OneStop:
+ currentSettings().iStopBits = EStop1;
+ break;
+ case SerialPort::TwoStop:
+ currentSettings().iStopBits = EStop2;
+ break;
+ default:
+ currentSettings().iStopBits = EStop1;
+ break;
+ }
+
+ return updateCommConfig();
+}
+
+bool SerialPortPrivate::setFlowControl(SerialPort::FlowControl flow)
+{
+ switch (flow) {
+ case SerialPort::NoFlowControl:
+ currentSettings().iHandshake = KConfigFailDSR;
+ break;
+ case SerialPort::HardwareControl:
+ currentSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS;
+ break;
+ case SerialPort::SoftwareControl:
+ currentSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff;
+ break;
+ default:
+ currentSettings().iHandshake = KConfigFailDSR;
+ break;
+ }
+
+ return updateCommConfig();
+}
+
+bool SerialPortPrivate::setDataErrorPolicy(SerialPort::DataErrorPolicy policy)
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::notifyRead()
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::notifyWrite()
+{
+ // TODO: Implement me
+ return false;
+}
+
+bool SerialPortPrivate::updateCommConfig()
+{
+ if (descriptor.SetConfig(currentSettings) != KErrNone) {
+ portError = SerialPort::UnsupportedPortOperationError;
+ return false;
+ }
+ return true;
+}
+
+void SerialPortPrivate::detectDefaultSettings()
+{
+ // Detect rate.
+ inputRate = rateFromSetting(currentSettings().iRate);
+ outputRate = inputRate;
+
+ // Detect databits.
+ switch (currentSettings().iDataBits) {
+ case EData5:
+ dataBits = SerialPort::Data5;
+ break;
+ case EData6:
+ dataBits = SerialPort::Data6;
+ break;
+ case EData7:
+ dataBits = SerialPort::Data7;
+ break;
+ case EData8:
+ dataBits = SerialPort::Data8;
+ break;
+ default:
+ dataBits = SerialPort::UnknownDataBits;
+ break;
+ }
+
+ // Detect parity.
+ switch (currentSettings().iParity) {
+ case EParityNone:
+ parity = SerialPort::NoParity;
+ break;
+ case EParityEven:
+ parity = SerialPort::EvenParity;
+ break;
+ case EParityOdd:
+ parity = SerialPort::OddParity;
+ break;
+ case EParityMark:
+ parity = SerialPort::MarkParity;
+ break;
+ case EParitySpace:
+ parity = SerialPort::SpaceParity;
+ break;
+ default:
+ parity = SerialPort::UnknownParity;
+ break;
+ }
+
+ // Detect stopbits.
+ switch (currentSettings().iStopBits) {
+ case EStop1:
+ stopBits = SerialPort::OneStop;
+ break;
+ case EStop2:
+ stopBits = SerialPort::TwoStop;
+ break;
+ default:
+ stopBits = SerialPort::UnknownStopBits;
+ break;
+ }
+
+ // Detect flow control.
+ if ((currentSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff))
+ == (KConfigObeyXoff | KConfigSendXoff))
+ flow = SerialPort::SoftwareControl;
+ else if ((currentSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS))
+ == (KConfigObeyCTS | KConfigFreeRTS))
+ flow = SerialPort::HardwareControl;
+ else if (currentSettings().iHandshake & KConfigFailDSR)
+ flow = SerialPort::NoFlowControl;
+ else
+ flow = SerialPort::UnknownFlowControl;
+}
+
+SerialPort::PortError SerialPortPrivate::decodeSystemError() const
+{
+ SerialPort::PortError error;
+ switch (errnum) {
+ case KErrPermissionDenied:
+ error = SerialPort::NoSuchDeviceError;
+ break;
+ case KErrLocked:
+ error = SerialPort::PermissionDeniedError;
+ break;
+ case KErrAccessDenied:
+ error = SerialPort::PermissionDeniedError;
+ break;
+ default:
+ error = SerialPort::UnknownPortError;
+ break;
+ }
+ return error;
+}
+
+bool SerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+
+ // FIXME: I'm not sure in implementation this method.
+ // Someone needs to check and correct.
+
+ TRequestStatus timerStatus;
+ TRequestStatus readStatus;
+ TRequestStatus writeStatus;
+
+ if (msecs > 0) {
+ if (!selectTimer.Handle()) {
+ if (selectTimer.CreateLocal() != KErrNone)
+ return false;
+ }
+ selectTimer.HighRes(timerStatus, msecs * 1000);
+ }
+
+ if (checkRead)
+ descriptor.NotifyDataAvailable(readStatus);
+
+ if (checkWrite)
+ descriptor.NotifyOutputEmpty(writeStatus);
+
+ enum { STATUSES_COUNT = 3 };
+ TRequestStatus *statuses[STATUSES_COUNT];
+ TInt num = 0;
+ statuses[num++] = &timerStatus;
+ statuses[num++] = &readStatus;
+ statuses[num++] = &writeStatus;
+
+ User::WaitForNRequest(statuses, num);
+
+ bool result = false;
+
+ // By timeout?
+ if (timerStatus != KRequestPending) {
+ Q_ASSERT(selectForRead);
+ *selectForRead = false;
+ Q_ASSERT(selectForWrite);
+ *selectForWrite = false;
+ } else {
+ selectTimer.Cancel();
+ User::WaitForRequest(timerStatus);
+
+ // By read?
+ if (readStatus != KRequestPending) {
+ Q_ASSERT(selectForRead);
+ *selectForRead = true;
+ }
+
+ // By write?
+ if (writeStatus != KRequestPending) {
+ Q_ASSERT(selectForWrite);
+ *selectForWrite = true;
+ }
+
+ if (checkRead)
+ descriptor.NotifyDataAvailableCancel();
+ if (checkWrite)
+ descriptor.NotifyOutputEmptyCancel();
+
+ result = true;
+ }
+ return result;
+}
+
+QString SerialPortPrivate::portNameToSystemLocation(const QString &port)
+{
+ // Port name is equval to port systemLocation.
+ return port;
+}
+
+QString SerialPortPrivate::portNameFromSystemLocation(const QString &location)
+{
+ // Port name is equval to port systemLocation.
+ return location;
+}
+
+struct RatePair
+{
+ qint32 rate; // The numerical value of baud rate.
+ qint32 setting; // The OS-specific code of baud rate.
+ bool operator<(const RatePair &other) const { return rate < other.rate; }
+ bool operator==(const RatePair &other) const { return setting == other.setting; }
+};
+
+// This table contains correspondences standard pairs values of
+// baud rates that are defined in files
+// - d32comm.h for Symbian^3
+// - d32public.h for Symbian SR1
+static const RatePair standardRatesTable[] =
+{
+ { 50, EBps50 },
+ { 75, EBps75 },
+ { 110, EBps110},
+ { 134, EBps134 },
+ { 150, EBps150 },
+ { 300, EBps300 },
+ { 600, EBps600 },
+ { 1200, EBps1200 },
+ { 1800, EBps1800 },
+ { 2000, EBps2000 },
+ { 2400, EBps2400 },
+ { 3600, EBps3600 },
+ { 4800, EBps4800 },
+ { 7200, EBps7200 },
+ { 9600, EBps9600 },
+ { 19200, EBps19200 },
+ { 38400, EBps38400 },
+ { 57600, EBps57600 },
+ { 115200, EBps115200 },
+ { 230400, EBps230400 },
+ { 460800, EBps460800 },
+ { 576000, EBps576000 },
+ { 921600, EBps921600 },
+ { 1152000, EBps1152000 },
+ //{ 1843200, EBps1843200 }, only for Symbian SR1
+ { 4000000, EBps4000000 }
+};
+
+static const RatePair *standardRatesTable_end =
+ standardRatesTable + sizeof(standardRatesTable)/sizeof(*standardRatesTable);
+
+qint32 SerialPortPrivate::rateFromSetting(qint32 setting)
+{
+ const RatePair rp = { 0, setting };
+ const RatePair *ret = qFind(standardRatesTable, standardRatesTable_end, rp);
+ return ret != standardRatesTable_end ? ret->rate : 0;
+}
+
+qint32 SerialPortPrivate::settingFromRate(qint32 rate)
+{
+ const RatePair rp = { rate, 0 };
+ const RatePair *ret = qBinaryFind(standardRatesTable, standardRatesTable_end, rp);
+ return ret != standardRatesTable_end ? ret->setting : 0;
+}
+
+QList<qint32> SerialPortPrivate::standardRates()
+{
+ QList<qint32> ret;
+ for (const RatePair *it = standardRatesTable; it != standardRatesTable_end; ++it)
+ ret.append(it->rate);
+ return ret;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialport_symbian_p.h b/src/serialport/serialport_symbian_p.h
new file mode 100644
index 0000000..647585c
--- /dev/null
+++ b/src/serialport/serialport_symbian_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig2@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_SYMBIAN_P_H
+#define SERIALPORT_SYMBIAN_P_H
+
+#include "serialport_p.h"
+
+#include <c32comm.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortPrivate : public SerialPortPrivateData
+{
+public:
+ SerialPortPrivate(SerialPort *q);
+
+ bool open(QIODevice::OpenMode mode);
+ void close();
+
+ SerialPort::Lines lines() const;
+
+ bool setDtr(bool set);
+ bool setRts(bool set);
+
+ bool flush();
+ bool clear(SerialPort::Directions dir);
+
+ bool sendBreak(int duration);
+ bool setBreak(bool set);
+
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+
+ qint64 readFromBuffer(char *data, qint64 maxSize);
+ qint64 writeToBuffer(const char *data, qint64 maxSize);
+
+ bool waitForReadyRead(int msec);
+ bool waitForBytesWritten(int msec);
+
+ bool setRate(qint32 rate, SerialPort::Directions dir);
+ bool setDataBits(SerialPort::DataBits dataBits);
+ bool setParity(SerialPort::Parity parity);
+ bool setStopBits(SerialPort::StopBits stopBits);
+ bool setFlowControl(SerialPort::FlowControl flowControl);
+ bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy);
+
+ bool notifyRead();
+ bool notifyWrite();
+
+ static QString portNameToSystemLocation(const QString &port);
+ static QString portNameFromSystemLocation(const QString &location);
+
+ static qint32 rateFromSetting(qint32 setting);
+ static qint32 settingFromRate(qint32 rate);
+
+ static QList<qint32> standardRates();
+
+ TCommConfig currentSettings;
+ TCommConfig restoredSettings;
+ RComm descriptor;
+ mutable RTimer selectTimer;
+ TInt errnum;
+
+private:
+ bool updateCommConfig();
+
+ void detectDefaultSettings();
+ SerialPort::PortError decodeSystemError() const;
+
+ bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut);
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_SYMBIAN_P_H
diff --git a/src/serialport/serialport_unix.cpp b/src/serialport/serialport_unix.cpp
new file mode 100644
index 0000000..4bb314b
--- /dev/null
+++ b/src/serialport/serialport_unix.cpp
@@ -0,0 +1,1327 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialport_unix_p.h"
+#include "ttylocker_unix_p.h"
+
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef Q_OS_MAC
+#if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
+#include <IOKit/serial/ioss.h>
+#endif
+#endif
+
+#include <QtCore/qelapsedtimer.h>
+
+#include <QtCore/qsocketnotifier.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class ReadNotifier : public QSocketNotifier
+{
+public:
+ ReadNotifier(SerialPortPrivate *d, QObject *parent)
+ : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
+ , dptr(d)
+ {}
+
+protected:
+ virtual bool event(QEvent *e) {
+ bool ret = QSocketNotifier::event(e);
+ if (ret)
+ dptr->readNotification();
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+class WriteNotifier : public QSocketNotifier
+{
+public:
+ WriteNotifier(SerialPortPrivate *d, QObject *parent)
+ : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
+ , dptr(d)
+ {}
+
+protected:
+ virtual bool event(QEvent *e) {
+ bool ret = QSocketNotifier::event(e);
+ if (ret)
+ dptr->writeNotification(SerialPortPrivateData::WriteChunkSize);
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+class ExceptionNotifier : public QSocketNotifier
+{
+public:
+ ExceptionNotifier(SerialPortPrivate *d, QObject *parent)
+ : QSocketNotifier(d->descriptor, QSocketNotifier::Exception, parent)
+ , dptr(d)
+ {}
+
+protected:
+ virtual bool event(QEvent *e) {
+ bool ret = QSocketNotifier::event(e);
+ if (ret)
+ dptr->exceptionNotification();
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+SerialPortPrivate::SerialPortPrivate(SerialPort *q)
+ : SerialPortPrivateData(q)
+ , descriptor(-1)
+ , isCustomRateSupported(false)
+ , readNotifier(0)
+ , writeNotifier(0)
+ , exceptionNotifier(0)
+ , readPortNotifierCalled(false)
+ , readPortNotifierState(false)
+ , readPortNotifierStateSet(false)
+ , emittedReadyRead(false)
+ , emittedBytesWritten(false)
+{
+}
+
+bool SerialPortPrivate::open(QIODevice::OpenMode mode)
+{
+ QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit();
+ const char *ptr = portName.constData();
+
+ bool byCurrPid = false;
+ if (TtyLocker::isLocked(ptr, &byCurrPid)) {
+ portError = SerialPort::PermissionDeniedError;
+ return false;
+ }
+
+ int flags = O_NOCTTY | O_NONBLOCK;
+
+ switch (mode & QIODevice::ReadWrite) {
+ case QIODevice::WriteOnly:
+ flags |= O_WRONLY;
+ break;
+ case QIODevice::ReadWrite:
+ flags |= O_RDWR;
+ break;
+ default:
+ flags |= O_RDONLY;
+ break;
+ }
+
+ descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags);
+
+ if (descriptor == -1) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ ::fcntl(descriptor, F_SETFL, FNDELAY);
+
+ TtyLocker::lock(ptr);
+ if (!TtyLocker::isLocked(ptr, &byCurrPid)) {
+ portError = SerialPort::PermissionDeniedError;
+ return false;
+ }
+
+#ifdef TIOCEXCL
+ ::ioctl(descriptor, TIOCEXCL);
+#endif
+
+ if (::tcgetattr(descriptor, &restoredTermios) == -1) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ ::memset(&currentTermios, 0, sizeof(currentTermios));
+ ::cfmakeraw(&currentTermios);
+ currentTermios.c_cflag |= CLOCAL;
+ currentTermios.c_cc[VTIME] = 0;
+ currentTermios.c_cc[VMIN] = 0;
+
+ if (mode & QIODevice::ReadOnly)
+ currentTermios.c_cflag |= CREAD;
+
+ if (!updateTermios())
+ return false;
+
+ setExceptionNotificationEnabled(true);
+
+ if ((flags & O_WRONLY) == 0)
+ setReadNotificationEnabled(true);
+
+ detectDefaultSettings();
+ return true;
+}
+
+void SerialPortPrivate::close()
+{
+ if (restoreSettingsOnClose) {
+ ::tcsetattr(descriptor, TCSANOW, &restoredTermios);
+#ifdef Q_OS_LINUX
+ if (isCustomRateSupported)
+ ::ioctl(descriptor, TIOCSSERIAL, &restoredSerialInfo);
+#endif
+ }
+
+#ifdef TIOCNXCL
+ ::ioctl(descriptor, TIOCNXCL);
+#endif
+
+ if (readNotifier) {
+ readNotifier->setEnabled(false);
+ readNotifier->deleteLater();
+ readNotifier = 0;
+ }
+
+ if (writeNotifier) {
+ writeNotifier->setEnabled(false);
+ writeNotifier->deleteLater();
+ writeNotifier = 0;
+ }
+
+ if (exceptionNotifier) {
+ exceptionNotifier->setEnabled(false);
+ exceptionNotifier->deleteLater();
+ exceptionNotifier = 0;
+ }
+
+ ::close(descriptor);
+
+ QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit();
+ const char *ptr = portName.constData();
+
+ bool byCurrPid = false;
+ if (TtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid)
+ TtyLocker::unlock(ptr);
+
+ descriptor = -1;
+ isCustomRateSupported = false;
+}
+
+SerialPort::Lines SerialPortPrivate::lines() const
+{
+ int arg = 0;
+ SerialPort::Lines ret = 0;
+
+ if (::ioctl(descriptor, TIOCMGET, &arg) == -1)
+ return ret;
+
+#ifdef TIOCM_LE
+ if (arg & TIOCM_LE)
+ ret |= SerialPort::Le;
+#endif
+#ifdef TIOCM_DTR
+ if (arg & TIOCM_DTR)
+ ret |= SerialPort::Dtr;
+#endif
+#ifdef TIOCM_RTS
+ if (arg & TIOCM_RTS)
+ ret |= SerialPort::Rts;
+#endif
+#ifdef TIOCM_ST
+ if (arg & TIOCM_ST)
+ ret |= SerialPort::St;
+#endif
+#ifdef TIOCM_SR
+ if (arg & TIOCM_SR)
+ ret |= SerialPort::Sr;
+#endif
+#ifdef TIOCM_CTS
+ if (arg & TIOCM_CTS)
+ ret |= SerialPort::Cts;
+#endif
+#ifdef TIOCM_CAR
+ if (arg & TIOCM_CAR)
+ ret |= SerialPort::Dcd;
+#elif defined TIOCM_CD
+ if (arg & TIOCM_CD)
+ ret |= SerialPort::Dcd;
+#endif
+#ifdef TIOCM_RNG
+ if (arg & TIOCM_RNG)
+ ret |= SerialPort::Ri;
+#elif defined TIOCM_RI
+ if (arg & TIOCM_RI)
+ ret |= SerialPort::Ri;
+#endif
+#ifdef TIOCM_DSR
+ if (arg & TIOCM_DSR)
+ ret |= SerialPort::Dsr;
+#endif
+
+ return ret;
+}
+
+bool SerialPortPrivate::setDtr(bool set)
+{
+ int status = TIOCM_DTR;
+ return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1;
+}
+
+bool SerialPortPrivate::setRts(bool set)
+{
+ int status = TIOCM_RTS;
+ return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1;
+}
+
+bool SerialPortPrivate::flush()
+{
+ return writeNotification() && (::tcdrain(descriptor) != -1);
+}
+
+bool SerialPortPrivate::clear(SerialPort::Directions dir)
+{
+ return ::tcflush(descriptor, (dir == SerialPort::AllDirections)
+ ? TCIOFLUSH : (dir & SerialPort::Input) ? TCIFLUSH : TCOFLUSH) != -1;
+}
+
+bool SerialPortPrivate::sendBreak(int duration)
+{
+ return ::tcsendbreak(descriptor, duration) != -1;
+}
+
+bool SerialPortPrivate::setBreak(bool set)
+{
+ return ::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) != -1;
+}
+
+qint64 SerialPortPrivate::bytesAvailable() const
+{
+ int nbytes = 0;
+#ifdef TIOCINQ
+ if (::ioctl(descriptor, TIOCINQ, &nbytes) == -1)
+ return -1;
+#endif
+ return nbytes;
+}
+
+qint64 SerialPortPrivate::bytesToWrite() const
+{
+ int nbytes = 0;
+#ifdef TIOCOUTQ
+ if (::ioctl(descriptor, TIOCOUTQ, &nbytes) == -1)
+ return -1;
+#endif
+ return nbytes;
+}
+
+qint64 SerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
+{
+ if (readBuffer.isEmpty())
+ return 0;
+
+ if (maxSize == 1) {
+ *data = readBuffer.getChar();
+ if (readBuffer.isEmpty())
+ setReadNotificationEnabled(true);
+ return 1;
+ }
+
+ const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize);
+ qint64 readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = readBuffer.readPointer();
+ const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
+ readBuffer.nextDataBlockSize());
+ ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ readBuffer.free(bytesToReadFromThisBlock);
+ }
+
+ if (!isReadNotificationEnabled())
+ setReadNotificationEnabled(true);
+
+ if (readSoFar > 0) {
+ if (readBuffer.isEmpty())
+ setReadNotificationEnabled(true);
+ return readSoFar;
+ }
+
+ return readSoFar;
+}
+
+qint64 SerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
+{
+ char *ptr = writeBuffer.reserve(maxSize);
+ if (maxSize == 1)
+ *ptr = *data;
+ else
+ ::memcpy(ptr, data, maxSize);
+
+ const qint64 written = maxSize;
+
+ if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
+ setWriteNotificationEnabled(true);
+
+ return written;
+}
+
+bool SerialPortPrivate::waitForReadyRead(int msecs)
+{
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ do {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
+ timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
+ // TODO: set error ?
+ return false;
+ }
+
+ if (readyToRead) {
+ if (readNotification())
+ return true;
+ }
+
+ if (readyToWrite)
+ writeNotification(WriteChunkSize);
+
+ } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0);
+ return false;
+}
+
+bool SerialPortPrivate::waitForBytesWritten(int msecs)
+{
+ if (writeBuffer.isEmpty())
+ return false;
+
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
+ timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
+ // TODO: set error ?
+ return false;
+ }
+
+ if (readyToRead && !readNotification())
+ return false;
+
+ if (readyToWrite && writeNotification(WriteChunkSize))
+ return true;
+ }
+ return false;
+}
+
+bool SerialPortPrivate::setRate(qint32 rate, SerialPort::Directions dir)
+{
+ bool ret = rate > 0;
+
+ // prepare section
+
+ if (ret) {
+ const qint32 unixRate = SerialPortPrivate::settingFromRate(rate);
+ if (unixRate > 0) {
+ // try prepate to set standard baud rate
+#ifdef Q_OS_LINUX
+ // prepare to forcefully reset the custom mode
+ if (isCustomRateSupported) {
+ //currentSerialInfo.flags |= ASYNC_SPD_MASK;
+ currentSerialInfo.flags &= ~(ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
+ currentSerialInfo.custom_divisor = 0;
+ }
+#endif
+ // prepare to set standard rate
+ ret = !(((dir & SerialPort::Input) && ::cfsetispeed(&currentTermios, unixRate) < 0)
+ || ((dir & SerialPort::Output) && ::cfsetospeed(&currentTermios, unixRate) < 0));
+ } else {
+ // try prepate to set custom baud rate
+#ifdef Q_OS_LINUX
+ // prepare to forcefully set the custom mode
+ if (isCustomRateSupported) {
+ currentSerialInfo.flags &= ~ASYNC_SPD_MASK;
+ currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
+ currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / rate;
+ if (currentSerialInfo.custom_divisor == 0)
+ currentSerialInfo.custom_divisor = 1;
+ // for custom mode needed prepare to set B38400 rate
+ ret = (::cfsetspeed(&currentTermios, B38400) != -1);
+ } else {
+ ret = false;
+ }
+#elif defined(Q_OS_MAC)
+
+# if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
+ // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
+ // other than those specified by POSIX. The driver for the underlying serial hardware
+ // ultimately determines which baud rates can be used. This ioctl sets both the input
+ // and output speed.
+ ret = ::ioctl(descriptor, IOSSIOSPEED, &rate) != -1;
+# else
+ // others MacOSX version, can't prepare to set custom rate
+ ret = false;
+# endif
+
+#else
+ // others *nix OS, can't prepare to set custom rate
+ ret = false;
+#endif
+ }
+ }
+
+ // finally section
+
+#ifdef Q_OS_LINUX
+ if (ret && isCustomRateSupported) // finally, set or reset the custom mode
+ ret = ::ioctl(descriptor, TIOCSSERIAL, &currentSerialInfo) != -1;
+#endif
+
+ if (ret) // finally, set rate
+ ret = updateTermios();
+ else
+ portError = decodeSystemError();
+ return ret;
+}
+
+bool SerialPortPrivate::setDataBits(SerialPort::DataBits dataBits)
+{
+ currentTermios.c_cflag &= ~CSIZE;
+ switch (dataBits) {
+ case SerialPort::Data5:
+ currentTermios.c_cflag |= CS5;
+ break;
+ case SerialPort::Data6:
+ currentTermios.c_cflag |= CS6;
+ break;
+ case SerialPort::Data7:
+ currentTermios.c_cflag |= CS7;
+ break;
+ case SerialPort::Data8:
+ currentTermios.c_cflag |= CS8;
+ break;
+ default:
+ currentTermios.c_cflag |= CS8;
+ break;
+ }
+ return updateTermios();
+}
+
+bool SerialPortPrivate::setParity(SerialPort::Parity parity)
+{
+ currentTermios.c_iflag &= ~(PARMRK | INPCK);
+ currentTermios.c_iflag |= IGNPAR;
+
+ switch (parity) {
+
+#ifdef CMSPAR
+ // Here Installation parity only for GNU/Linux where the macro CMSPAR.
+ case SerialPort::SpaceParity:
+ currentTermios.c_cflag &= ~PARODD;
+ currentTermios.c_cflag |= PARENB | CMSPAR;
+ break;
+ case SerialPort::MarkParity:
+ currentTermios.c_cflag |= PARENB | CMSPAR | PARODD;
+ break;
+#endif
+ case SerialPort::NoParity:
+ currentTermios.c_cflag &= ~PARENB;
+ break;
+ case SerialPort::EvenParity:
+ currentTermios.c_cflag &= ~PARODD;
+ currentTermios.c_cflag |= PARENB;
+ break;
+ case SerialPort::OddParity:
+ currentTermios.c_cflag |= PARENB | PARODD;
+ break;
+ default:
+ currentTermios.c_cflag |= PARENB;
+ currentTermios.c_iflag |= PARMRK | INPCK;
+ currentTermios.c_iflag &= ~IGNPAR;
+ break;
+ }
+
+ return updateTermios();
+}
+
+bool SerialPortPrivate::setStopBits(SerialPort::StopBits stopBits)
+{
+ switch (stopBits) {
+ case SerialPort::OneStop:
+ currentTermios.c_cflag &= ~CSTOPB;
+ break;
+ case SerialPort::TwoStop:
+ currentTermios.c_cflag |= CSTOPB;
+ break;
+ default:
+ currentTermios.c_cflag &= ~CSTOPB;
+ break;
+ }
+ return updateTermios();
+}
+
+bool SerialPortPrivate::setFlowControl(SerialPort::FlowControl flow)
+{
+ switch (flow) {
+ case SerialPort::NoFlowControl:
+ currentTermios.c_cflag &= ~CRTSCTS;
+ currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ break;
+ case SerialPort::HardwareControl:
+ currentTermios.c_cflag |= CRTSCTS;
+ currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ break;
+ case SerialPort::SoftwareControl:
+ currentTermios.c_cflag &= ~CRTSCTS;
+ currentTermios.c_iflag |= IXON | IXOFF | IXANY;
+ break;
+ default:
+ currentTermios.c_cflag &= ~CRTSCTS;
+ currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ break;
+ }
+ return updateTermios();
+}
+
+bool SerialPortPrivate::setDataErrorPolicy(SerialPort::DataErrorPolicy policy)
+{
+ tcflag_t parmrkMask = PARMRK;
+#ifndef CMSPAR
+ // in space/mark parity emulation also used PARMRK flag
+ if (parity == SerialPort::SpaceParity
+ || parity == SerialPort::MarkParity) {
+ parmrkMask = 0;
+ }
+#endif //CMSPAR
+ switch (policy) {
+ case SerialPort::SkipPolicy:
+ currentTermios.c_iflag &= ~parmrkMask;
+ currentTermios.c_iflag |= IGNPAR | INPCK;
+ break;
+ case SerialPort::PassZeroPolicy:
+ currentTermios.c_iflag &= ~(IGNPAR | parmrkMask);
+ currentTermios.c_iflag |= INPCK;
+ break;
+ case SerialPort::IgnorePolicy:
+ currentTermios.c_iflag &= ~INPCK;
+ break;
+ case SerialPort::StopReceivingPolicy:
+ currentTermios.c_iflag &= ~IGNPAR;
+ currentTermios.c_iflag |= parmrkMask | INPCK;
+ break;
+ default:
+ currentTermios.c_iflag &= ~INPCK;
+ break;
+ }
+ return updateTermios();
+}
+
+bool SerialPortPrivate::readNotification()
+{
+ // Prevent recursive calls
+ if (readPortNotifierCalled) {
+ if (!readPortNotifierStateSet) {
+ readPortNotifierStateSet = true;
+ readPortNotifierState = isReadNotificationEnabled();
+ setReadNotificationEnabled(false);
+ }
+ }
+
+ readPortNotifierCalled = true;
+
+ // Always buffered, read data from the port into the read buffer
+ qint64 newBytes = readBuffer.size();
+ qint64 bytesToRead = policy == SerialPort::IgnorePolicy ? ReadChunkSize : 1;
+
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (bytesToRead == 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the port.
+ return false;
+ }
+ }
+
+ char *ptr = readBuffer.reserve(bytesToRead);
+ const qint64 readBytes = readFromPort(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ readBuffer.chop(bytesToRead);
+ return true;
+ }
+ readBuffer.chop(bytesToRead - qMax(readBytes, qint64(0)));
+
+ newBytes = readBuffer.size() - newBytes;
+
+ // If read buffer is full, disable the read port notifier.
+ if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize)
+ setReadNotificationEnabled(false);
+
+ // only emit readyRead() when not recursing, and only if there is data available
+ const bool hasData = newBytes > 0;
+
+ if (!emittedReadyRead && hasData) {
+ emittedReadyRead = true;
+ emit q_ptr->readyRead();
+ emittedReadyRead = false;
+ }
+
+ if (!hasData)
+ setReadNotificationEnabled(true);
+
+ // reset the read port notifier state if we reentered inside the
+ // readyRead() connected slot.
+ if (readPortNotifierStateSet
+ && readPortNotifierState != isReadNotificationEnabled()) {
+ setReadNotificationEnabled(readPortNotifierState);
+ readPortNotifierStateSet = false;
+ }
+ return true;
+}
+
+bool SerialPortPrivate::writeNotification(int maxSize)
+{
+ const int tmp = writeBuffer.size();
+
+ if (writeBuffer.isEmpty()) {
+ setWriteNotificationEnabled(false);
+ return false;
+ }
+
+ int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize);
+
+ const char *ptr = writeBuffer.readPointer();
+
+ // Attempt to write it chunk.
+ qint64 written = writeToPort(ptr, nextSize);
+ if (written < 0) {
+ // TODO: set error?
+ return false;
+ }
+
+ // Remove what we wrote so far.
+ writeBuffer.free(written);
+ if (written > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q_ptr->bytesWritten(written);
+ emittedBytesWritten = false;
+ }
+ }
+
+ if (writeBuffer.isEmpty())
+ setWriteNotificationEnabled(false);
+
+ return (writeBuffer.size() < tmp);
+}
+
+bool SerialPortPrivate::exceptionNotification()
+{
+ // FIXME:
+ return false;
+}
+
+bool SerialPortPrivate::updateTermios()
+{
+ if (::tcsetattr(descriptor, TCSANOW, &currentTermios) == -1) {
+ portError = decodeSystemError();
+ return false;
+ }
+ return true;
+}
+
+void SerialPortPrivate::detectDefaultSettings()
+{
+ // Detect rate.
+ const speed_t inputUnixRate = ::cfgetispeed(&currentTermios);
+ const speed_t outputUnixRate = ::cfgetospeed(&currentTermios);
+ bool isCustomRateCurrentSet = false;
+
+#ifdef Q_OS_LINUX
+ // try detect the ability to support custom rate
+ isCustomRateSupported = ::ioctl(descriptor, TIOCGSERIAL, &currentSerialInfo) != -1
+ && ::ioctl(descriptor, TIOCSSERIAL, &currentSerialInfo) != -1;
+
+ if (isCustomRateSupported) {
+ restoredSerialInfo = currentSerialInfo;
+
+ // assume that the baud rate is a custom
+ isCustomRateCurrentSet = inputUnixRate == B38400 && outputUnixRate == B38400;
+
+ if (isCustomRateCurrentSet) {
+ if ((currentSerialInfo.flags & ASYNC_SPD_CUST)
+ && currentSerialInfo.custom_divisor > 0) {
+
+ // yes, speed is really custom
+ inputRate = currentSerialInfo.baud_base / currentSerialInfo.custom_divisor;
+ outputRate = inputRate;
+ } else {
+ // no, we were wrong and the speed is a standard 38400 baud
+ isCustomRateCurrentSet = false;
+ }
+ }
+ }
+#else
+ // other *nix
+#endif
+ if (!isCustomRateSupported || !isCustomRateCurrentSet) {
+ inputRate = SerialPortPrivate::rateFromSetting(inputUnixRate);
+ outputRate = SerialPortPrivate::rateFromSetting(outputUnixRate);
+ }
+
+ // Detect databits.
+ switch (currentTermios.c_cflag & CSIZE) {
+ case CS5:
+ dataBits = SerialPort::Data5;
+ break;
+ case CS6:
+ dataBits = SerialPort::Data6;
+ break;
+ case CS7:
+ dataBits = SerialPort::Data7;
+ break;
+ case CS8:
+ dataBits = SerialPort::Data8;
+ break;
+ default:
+ dataBits = SerialPort::UnknownDataBits;
+ break;
+ }
+
+ // Detect parity.
+#ifdef CMSPAR
+ if (currentTermios.c_cflag & CMSPAR) {
+ parity = currentTermios.c_cflag & PARODD ?
+ SerialPort::MarkParity : SerialPort::SpaceParity;
+ } else {
+#endif
+ if (currentTermios.c_cflag & PARENB) {
+ parity = currentTermios.c_cflag & PARODD ?
+ SerialPort::OddParity : SerialPort::EvenParity;
+ } else {
+ parity = SerialPort::NoParity;
+ }
+#ifdef CMSPAR
+ }
+#endif
+
+ // Detect stopbits.
+ stopBits = currentTermios.c_cflag & CSTOPB ?
+ SerialPort::TwoStop : SerialPort::OneStop;
+
+ // Detect flow control.
+ if ((!(currentTermios.c_cflag & CRTSCTS)) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY))))
+ flow = SerialPort::NoFlowControl;
+ else if ((!(currentTermios.c_cflag & CRTSCTS)) && (currentTermios.c_iflag & (IXON | IXOFF | IXANY)))
+ flow = SerialPort::SoftwareControl;
+ else if ((currentTermios.c_cflag & CRTSCTS) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY))))
+ flow = SerialPort::HardwareControl;
+ else
+ flow = SerialPort::UnknownFlowControl;
+}
+
+SerialPort::PortError SerialPortPrivate::decodeSystemError() const
+{
+ SerialPort::PortError error;
+ switch (errno) {
+ case ENODEV:
+ error = SerialPort::NoSuchDeviceError;
+ break;
+ case EACCES:
+ error = SerialPort::PermissionDeniedError;
+ break;
+ case EBUSY:
+ error = SerialPort::PermissionDeniedError;
+ break;
+ case ENOTTY:
+ error = SerialPort::IoError;
+ break;
+ default:
+ error = SerialPort::UnknownPortError;
+ break;
+ }
+ return error;
+}
+
+bool SerialPortPrivate::isReadNotificationEnabled() const
+{
+ return readNotifier && readNotifier->isEnabled();
+}
+
+void SerialPortPrivate::setReadNotificationEnabled(bool enable)
+{
+ if (readNotifier) {
+ readNotifier->setEnabled(enable);
+ } else if (enable) {
+ readNotifier = new ReadNotifier(this, q_ptr);
+ readNotifier->setEnabled(true);
+ }
+}
+
+bool SerialPortPrivate::isWriteNotificationEnabled() const
+{
+ return writeNotifier && writeNotifier->isEnabled();
+}
+
+void SerialPortPrivate::setWriteNotificationEnabled(bool enable)
+{
+ if (writeNotifier) {
+ writeNotifier->setEnabled(enable);
+ } else if (enable) {
+ writeNotifier = new WriteNotifier(this, q_ptr);
+ writeNotifier->setEnabled(true);
+ }
+}
+
+bool SerialPortPrivate::isExceptionNotificationEnabled() const
+{
+ return exceptionNotifier && exceptionNotifier->isEnabled();
+}
+
+void SerialPortPrivate::setExceptionNotificationEnabled(bool enable)
+{
+ if (exceptionNotifier) {
+ exceptionNotifier->setEnabled(enable);
+ } else if (enable) {
+ exceptionNotifier = new ExceptionNotifier(this, q_ptr);
+ exceptionNotifier->setEnabled(true);
+ }
+}
+
+bool SerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_ASSERT(selectForRead);
+ Q_ASSERT(selectForWrite);
+ Q_ASSERT(timedOut);
+
+ fd_set fdread;
+ FD_ZERO(&fdread);
+ if (checkRead)
+ FD_SET(descriptor, &fdread);
+
+ fd_set fdwrite;
+ FD_ZERO(&fdwrite);
+ if (checkWrite)
+ FD_SET(descriptor, &fdwrite);
+
+ struct timeval tv;
+ tv.tv_sec = msecs / 1000;
+ tv.tv_usec = (msecs % 1000) * 1000;
+
+ int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv);
+ if (ret < 0)
+ return false;
+ if (ret == 0) {
+ *timedOut = true;
+ return false;
+ }
+
+ *selectForRead = FD_ISSET(descriptor, &fdread);
+ *selectForWrite = FD_ISSET(descriptor, &fdwrite);
+
+ return ret;
+}
+
+qint64 SerialPortPrivate::readFromPort(char *data, qint64 maxSize)
+{
+ qint64 bytesRead = 0;
+#if defined (CMSPAR)
+ if (parity == SerialPort::NoParity
+ || policy != SerialPort::StopReceivingPolicy) {
+#else
+ if (parity != SerialPort::MarkParity
+ && parity != SerialPort::SpaceParity) {
+#endif
+ bytesRead = ::read(descriptor, data, maxSize);
+ } else {// Perform parity emulation.
+ bytesRead = readPerChar(data, maxSize);
+ }
+
+ // FIXME: Here 'errno' codes for sockets.
+ // You need to replace the codes for the serial port.
+ if (bytesRead < 0) {
+ bytesRead = -1;
+ switch (errno) {
+#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+ // No data was available for reading.
+ bytesRead = -2;
+ break;
+ case EBADF:
+ case EINVAL:
+ case EIO:
+ break;
+ case ECONNRESET:
+ bytesRead = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ return bytesRead;
+}
+
+qint64 SerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
+{
+ qint64 bytesWritten = 0;
+#if defined (CMSPAR)
+ bytesWritten = ::write(descriptor, data, maxSize);
+#else
+ if (parity != SerialPort::MarkParity
+ && parity != SerialPort::SpaceParity) {
+ bytesWritten = ::write(descriptor, data, maxSize);
+ } else {// Perform parity emulation.
+ bytesWritten = writePerChar(data, maxSize);
+ }
+#endif
+
+ // FIXME: Here 'errno' codes for sockets.
+ // You need to replace the codes for the serial port.
+ if (bytesWritten < 0) {
+ switch (errno) {
+ case EPIPE:
+ case ECONNRESET:
+ bytesWritten = -1;
+ break;
+ case EAGAIN:
+ bytesWritten = 0;
+ break;
+ case EMSGSIZE:
+ break;
+ default:
+ break;
+ }
+ }
+ return bytesWritten;
+}
+
+static inline bool evenParity(quint8 c)
+{
+ c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0)
+ c ^= c >> 2; //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)]
+ c ^= c >> 1;
+ return c & 1; //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0)
+}
+
+#ifndef CMSPAR
+
+qint64 SerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
+{
+ qint64 ret = 0;
+ quint8 const charMask = (0xFF >> (8 - dataBits));
+
+ while (ret < maxSize) {
+
+ bool par = evenParity(*data & charMask);
+ // False if need EVEN, true if need ODD.
+ par ^= parity == SerialPort::MarkParity;
+ if (par ^ (currentTermios.c_cflag & PARODD)) { // Need switch parity mode?
+ currentTermios.c_cflag ^= PARODD;
+ flush(); //force sending already buffered data, because updateTermios() cleares buffers
+ //todo: add receiving buffered data!!!
+ if (!updateTermios())
+ break;
+ }
+
+ int r = ::write(descriptor, data, 1);
+ if (r < 0)
+ return -1;
+ if (r > 0) {
+ data += r;
+ ret += r;
+ }
+ }
+ return ret;
+}
+
+#endif //CMSPAR
+
+qint64 SerialPortPrivate::readPerChar(char *data, qint64 maxSize)
+{
+ qint64 ret = 0;
+ quint8 const charMask = (0xFF >> (8 - dataBits));
+
+ // 0 - prefix not started,
+ // 1 - received 0xFF,
+ // 2 - received 0xFF and 0x00
+ int prefix = 0;
+ while (ret < maxSize) {
+
+ qint64 r = ::read(descriptor, data, 1);
+ if (r < 0) {
+ if (errno == EAGAIN) // It is ok for nonblocking mode.
+ break;
+ return -1;
+ }
+ if (r == 0)
+ break;
+
+ bool par = true;
+ switch (prefix) {
+ case 2: // Previously received both 0377 and 0.
+ par = false;
+ prefix = 0;
+ break;
+ case 1: // Previously received 0377.
+ if (*data == '\0') {
+ ++prefix;
+ continue;
+ }
+ prefix = 0;
+ break;
+ default:
+ if (*data == '\377') {
+ prefix = 1;
+ continue;
+ }
+ break;
+ }
+ // Now: par contains parity ok or error, *data contains received character
+ par ^= evenParity(*data & charMask); //par contains parity bit value for EVEN mode
+ par ^= (currentTermios.c_cflag & PARODD); //par contains parity bit value for current mode
+ if (par ^ (parity == SerialPort::SpaceParity)) { //if parity error
+ switch (policy) {
+ case SerialPort::SkipPolicy:
+ continue; //ignore received character
+ case SerialPort::StopReceivingPolicy:
+ if (parity != SerialPort::NoParity)
+ portError = SerialPort::ParityError;
+ else
+ portError = *data == '\0' ?
+ SerialPort::BreakConditionError : SerialPort::FramingError;
+ return ++ret; //abort receiving
+ break;
+ case SerialPort::UnknownPolicy:
+ // Unknown error policy is used! Falling back to PassZeroPolicy
+ case SerialPort::PassZeroPolicy:
+ *data = '\0'; //replace received character by zero
+ break;
+ case SerialPort::IgnorePolicy:
+ break; //ignore error and pass received character
+ }
+ }
+ ++data;
+ ++ret;
+ }
+ return ret;
+}
+
+#ifdef Q_OS_MAC
+static const QLatin1String defaultPathPrefix("/dev/cu.");
+static const QLatin1String notUsedPathPrefix("/dev/tty.");
+#else
+static const QLatin1String defaultPathPrefix("/dev/");
+#endif
+
+QString SerialPortPrivate::portNameToSystemLocation(const QString &port)
+{
+ QString ret = port;
+
+#ifdef Q_OS_MAC
+ ret.remove(notUsedPathPrefix);
+#endif
+
+ if (!ret.contains(defaultPathPrefix))
+ ret.prepend(defaultPathPrefix);
+ return ret;
+}
+
+QString SerialPortPrivate::portNameFromSystemLocation(const QString &location)
+{
+ QString ret = location;
+
+#ifdef Q_OS_MAC
+ ret.remove(notUsedPathPrefix);
+#endif
+
+ ret.remove(defaultPathPrefix);
+ return ret;
+}
+
+struct RatePair
+{
+ qint32 rate; // The numerical value of baud rate.
+ qint32 setting; // The OS-specific code of baud rate.
+ bool operator<(const RatePair &other) const { return rate < other.rate; }
+ bool operator==(const RatePair &other) const { return setting == other.setting; }
+};
+
+// This table contains correspondences standard pairs values of
+// baud rates that are defined in file termios.h
+static const RatePair standardRatesTable[] =
+{
+ #ifdef B50
+ { 50, B50 },
+ #endif
+ #ifdef B75
+ { 75, B75 },
+ #endif
+ #ifdef B110
+ { 110, B110 },
+ #endif
+ #ifdef B134
+ { 134, B134 },
+ #endif
+ #ifdef B150
+ { 150, B150 },
+ #endif
+ #ifdef B200
+ { 200, B200 },
+ #endif
+ #ifdef B300
+ { 300, B300 },
+ #endif
+ #ifdef B600
+ { 600, B600 },
+ #endif
+ #ifdef B1200
+ { 1200, B1200 },
+ #endif
+ #ifdef B1800
+ { 1800, B1800 },
+ #endif
+ #ifdef B2400
+ { 2400, B2400 },
+ #endif
+ #ifdef B4800
+ { 4800, B4800 },
+ #endif
+ #ifdef B9600
+ { 9600, B9600 },
+ #endif
+ #ifdef B19200
+ { 19200, B19200 },
+ #endif
+ #ifdef B38400
+ { 38400, B38400 },
+ #endif
+ #ifdef B57600
+ { 57600, B57600 },
+ #endif
+ #ifdef B115200
+ { 115200, B115200 },
+ #endif
+ #ifdef B230400
+ { 230400, B230400 },
+ #endif
+ #ifdef B460800
+ { 460800, B460800 },
+ #endif
+ #ifdef B500000
+ { 500000, B500000 },
+ #endif
+ #ifdef B576000
+ { 576000, B576000 },
+ #endif
+ #ifdef B921600
+ { 921600, B921600 },
+ #endif
+ #ifdef B1000000
+ { 1000000, B1000000 },
+ #endif
+ #ifdef B1152000
+ { 1152000, B1152000 },
+ #endif
+ #ifdef B1500000
+ { 1500000, B1500000 },
+ #endif
+ #ifdef B2000000
+ { 2000000, B2000000},
+ #endif
+ #ifdef B2500000
+ { 2500000, B2500000 },
+ #endif
+ #ifdef B3000000
+ { 3000000, B3000000 },
+ #endif
+ #ifdef B3500000
+ { 3500000, B3500000 },
+ #endif
+ #ifdef B4000000
+ { 4000000, B4000000 }
+ #endif
+};
+
+static const RatePair *standardRatesTable_end =
+ standardRatesTable + sizeof(standardRatesTable)/sizeof(*standardRatesTable);
+
+qint32 SerialPortPrivate::rateFromSetting(qint32 setting)
+{
+ const RatePair rp = { 0, setting };
+ const RatePair *ret = qFind(standardRatesTable, standardRatesTable_end, rp);
+ return ret != standardRatesTable_end ? ret->rate : 0;
+}
+
+qint32 SerialPortPrivate::settingFromRate(qint32 rate)
+{
+ const RatePair rp = { rate, 0 };
+ const RatePair *ret = qBinaryFind(standardRatesTable, standardRatesTable_end, rp);
+ return ret != standardRatesTable_end ? ret->setting : 0;
+}
+
+QList<qint32> SerialPortPrivate::standardRates()
+{
+ QList<qint32> ret;
+ for (const RatePair *it = standardRatesTable; it != standardRatesTable_end; ++it)
+ ret.append(it->rate);
+ return ret;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialport_unix_p.h b/src/serialport/serialport_unix_p.h
new file mode 100644
index 0000000..76a6494
--- /dev/null
+++ b/src/serialport/serialport_unix_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_UNIX_P_H
+#define SERIALPORT_UNIX_P_H
+
+#include "serialport_p.h"
+
+#include <termios.h>
+#ifdef Q_OS_LINUX
+# include <linux/serial.h>
+#endif
+
+class QSocketNotifier;
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortPrivate : public SerialPortPrivateData
+{
+public:
+ SerialPortPrivate(SerialPort *q);
+
+ bool open(QIODevice::OpenMode mode);
+ void close();
+
+ SerialPort::Lines lines() const;
+
+ bool setDtr(bool set);
+ bool setRts(bool set);
+
+ bool flush();
+ bool clear(SerialPort::Directions dir);
+
+ bool sendBreak(int duration);
+ bool setBreak(bool set);
+
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+
+ qint64 readFromBuffer(char *data, qint64 maxSize);
+ qint64 writeToBuffer(const char *data, qint64 maxSize);
+
+ bool waitForReadyRead(int msecs);
+ bool waitForBytesWritten(int msecs);
+
+ bool setRate(qint32 rate, SerialPort::Directions dir);
+ bool setDataBits(SerialPort::DataBits dataBits);
+ bool setParity(SerialPort::Parity parity);
+ bool setStopBits(SerialPort::StopBits stopBits);
+ bool setFlowControl(SerialPort::FlowControl flow);
+ bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy);
+
+ bool readNotification();
+ bool writeNotification(int maxSize = INT_MAX);
+ bool exceptionNotification();
+
+ static QString portNameToSystemLocation(const QString &port);
+ static QString portNameFromSystemLocation(const QString &location);
+
+ static qint32 rateFromSetting(qint32 setting);
+ static qint32 settingFromRate(qint32 rate);
+
+ static QList<qint32> standardRates();
+
+ struct termios currentTermios;
+ struct termios restoredTermios;
+#ifdef Q_OS_LINUX
+ struct serial_struct currentSerialInfo;
+ struct serial_struct restoredSerialInfo;
+#endif
+ int descriptor;
+ bool isCustomRateSupported;
+
+ QSocketNotifier *readNotifier;
+ QSocketNotifier *writeNotifier;
+ QSocketNotifier *exceptionNotifier;
+
+ bool readPortNotifierCalled;
+ bool readPortNotifierState;
+ bool readPortNotifierStateSet;
+
+ bool emittedReadyRead;
+ bool emittedBytesWritten;
+
+private:
+ bool updateTermios();
+
+ void detectDefaultSettings();
+ SerialPort::PortError decodeSystemError() const;
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+ bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut);
+
+ qint64 readFromPort(char *data, qint64 maxSize);
+ qint64 writeToPort(const char *data, qint64 maxSize);
+
+#ifndef CMSPAR
+ qint64 writePerChar(const char *data, qint64 maxSize);
+#endif
+ qint64 readPerChar(char *data, qint64 maxSize);
+
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_UNIX_P_H
diff --git a/src/serialport/serialport_win.cpp b/src/serialport/serialport_win.cpp
new file mode 100644
index 0000000..af43f79
--- /dev/null
+++ b/src/serialport/serialport_win.cpp
@@ -0,0 +1,1091 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialport_win_p.h"
+
+#include <QtCore/qelapsedtimer.h>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtCore/qwineventnotifier.h>
+#else
+#include "qt4support/qwineventnotifier_p.h"
+#endif
+
+#include <QDebug>
+
+#ifndef CTL_CODE
+# define CTL_CODE(DeviceType, Function, Method, Access) ( \
+ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+ )
+#endif
+
+#ifndef FILE_DEVICE_SERIAL_PORT
+# define FILE_DEVICE_SERIAL_PORT 27
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0x00000000
+#endif
+
+#ifndef IOCTL_SERIAL_GET_DTRRTS
+# define IOCTL_SERIAL_GET_DTRRTS \
+ CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif
+
+#ifndef SERIAL_DTR_STATE
+# define SERIAL_DTR_STATE 0x00000001
+#endif
+
+#ifndef SERIAL_RTS_STATE
+# define SERIAL_RTS_STATE 0x00000002
+#endif
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+#ifndef Q_OS_WINCE
+
+class CommEventNotifier : public QWinEventNotifier
+{
+public:
+ CommEventNotifier(SerialPortPrivate *d, QObject *parent)
+ : QWinEventNotifier(d->eventOverlapped.hEvent, parent)
+ , dptr(d)
+ {
+ }
+
+protected:
+ virtual bool event(QEvent *e) {
+ const bool ret = QWinEventNotifier::event(e);
+ if (ret) {
+ if (EV_ERR & dptr->eventMask)
+ dptr->processIoErrors();
+ if (EV_RXCHAR & dptr->eventMask) {
+ if (!dptr->readSequenceStarted)
+ dptr->startAsyncRead();
+ }
+ ::WaitCommEvent(dptr->descriptor, &dptr->eventMask, &dptr->eventOverlapped);
+ }
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+class ReadCompletionNotifier : public QWinEventNotifier
+{
+public:
+ ReadCompletionNotifier(SerialPortPrivate *d, QObject *parent)
+ : QWinEventNotifier(d->readOverlapped.hEvent, parent)
+ , dptr(d)
+ {}
+
+protected:
+ virtual bool event(QEvent *e) {
+ bool ret = QWinEventNotifier::event(e);
+ if (ret) {
+ DWORD numberOfBytesTransferred = 0;
+ BOOL success = ::GetOverlappedResult(dptr->descriptor,
+ &dptr->readOverlapped,
+ &numberOfBytesTransferred,
+ FALSE);
+ if (success)
+ dptr->completeAsyncRead(numberOfBytesTransferred);
+ }
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+class WriteCompletionNotifier : public QWinEventNotifier
+{
+public:
+ WriteCompletionNotifier(SerialPortPrivate *d, QObject *parent)
+ : QWinEventNotifier(d->writeOverlapped.hEvent, parent)
+ , dptr(d)
+ {}
+
+protected:
+ virtual bool event(QEvent *e) {
+ bool ret = QWinEventNotifier::event(e);
+ if (ret) {
+ DWORD numberOfBytesTransferred = 0;
+ BOOL success = ::GetOverlappedResult(dptr->descriptor,
+ &dptr->writeOverlapped,
+ &numberOfBytesTransferred,
+ FALSE);
+ if (success)
+ dptr->completeAsyncWrite(numberOfBytesTransferred);
+ }
+ return ret;
+ }
+
+private:
+ SerialPortPrivate *dptr;
+};
+
+SerialPortPrivate::SerialPortPrivate(SerialPort *q)
+ : SerialPortPrivateData(q)
+ , descriptor(INVALID_HANDLE_VALUE)
+ , flagErrorFromCommEvent(false)
+ , eventMask(EV_ERR)
+ , eventNotifier(0)
+ , readCompletionNotifier(0)
+ , writeCompletionNotifier(0)
+ , actualReadBufferSize(0)
+ , actualWriteBufferSize(0)
+ , readyReadEmitted(0)
+ , readSequenceStarted(false)
+ , writeSequenceStarted(false)
+{
+}
+
+bool SerialPortPrivate::open(QIODevice::OpenMode mode)
+{
+ DWORD desiredAccess = 0;
+ eventMask = EV_ERR;
+
+ if (mode & QIODevice::ReadOnly) {
+ desiredAccess |= GENERIC_READ;
+ eventMask |= EV_RXCHAR;
+ }
+ if (mode & QIODevice::WriteOnly) {
+ desiredAccess |= GENERIC_WRITE;
+ eventMask |= EV_TXEMPTY;
+ }
+
+ descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
+ desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+
+ if (descriptor == INVALID_HANDLE_VALUE) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ if (!::GetCommState(descriptor, &restoredDcb)) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ currentDcb = restoredDcb;
+ currentDcb.fBinary = TRUE;
+ currentDcb.fInX = FALSE;
+ currentDcb.fOutX = FALSE;
+ currentDcb.fAbortOnError = FALSE;
+ currentDcb.fNull = FALSE;
+ currentDcb.fErrorChar = FALSE;
+
+ if (!updateDcb())
+ return false;
+
+ if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ ::memset(&currentCommTimeouts, 0, sizeof(currentCommTimeouts));
+ currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
+
+ if (!updateCommTimeouts())
+ return false;
+
+ ::memset(&selectOverlapped, 0, sizeof(selectOverlapped));
+ selectOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (eventMask & EV_RXCHAR) {
+ ::memset(&readOverlapped, 0, sizeof(readOverlapped));
+ readOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ readCompletionNotifier = new ReadCompletionNotifier(this, q_ptr);
+ readCompletionNotifier->setEnabled(true);
+ }
+
+ if (eventMask & EV_TXEMPTY) {
+ // Disable EV_TXEMPTY for CommEventNotifier because not all serial ports
+ // (such as from Bluetooth stack of Microsoft) supported this feature.
+ // I.e. now do not use this event to write to the port.
+ eventMask &= ~EV_TXEMPTY;
+ ::memset(&writeOverlapped, 0, sizeof(writeOverlapped));
+ writeOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ writeCompletionNotifier = new WriteCompletionNotifier(this, q_ptr);
+ writeCompletionNotifier->setEnabled(true);
+ }
+
+ ::SetCommMask(descriptor, eventMask);
+ ::memset(&eventOverlapped, 0, sizeof(eventOverlapped));
+ eventOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ eventNotifier = new CommEventNotifier(this, q_ptr);
+ eventNotifier->setEnabled(true);
+ ::WaitCommEvent(descriptor, &eventMask, &eventOverlapped);
+
+ detectDefaultSettings();
+ return true;
+}
+
+void SerialPortPrivate::close()
+{
+ ::CancelIo(descriptor);
+
+ if (eventNotifier) {
+ eventNotifier->setEnabled(false);
+ ::CancelIo(eventOverlapped.hEvent);
+ ::CloseHandle(eventOverlapped.hEvent);
+ eventNotifier->deleteLater();
+ eventNotifier = 0;
+ }
+
+ if (readCompletionNotifier) {
+ readCompletionNotifier->setEnabled(false);
+ ::CancelIo(readOverlapped.hEvent);
+ ::CloseHandle(readOverlapped.hEvent);
+ readCompletionNotifier->deleteLater();
+ readCompletionNotifier = 0;
+ }
+
+ if (readSequenceStarted)
+ readSequenceStarted = false;
+
+ readBuffer.clear();
+ actualReadBufferSize = 0;
+
+ if (writeCompletionNotifier) {
+ writeCompletionNotifier->setEnabled(false);
+ ::CancelIo(writeOverlapped.hEvent);
+ ::CloseHandle(writeOverlapped.hEvent);
+ writeCompletionNotifier->deleteLater();
+ writeCompletionNotifier = 0;
+ }
+
+ if (writeSequenceStarted)
+ writeSequenceStarted = false;
+
+ writeBuffer.clear();
+ actualWriteBufferSize = 0;
+
+ readyReadEmitted = false;
+ flagErrorFromCommEvent = false;
+
+ if (restoreSettingsOnClose) {
+ ::SetCommState(descriptor, &restoredDcb);
+ ::SetCommTimeouts(descriptor, &restoredCommTimeouts);
+ }
+
+ ::CloseHandle(descriptor);
+ descriptor = INVALID_HANDLE_VALUE;
+}
+
+#endif // #ifndef Q_OS_WINCE
+
+SerialPort::Lines SerialPortPrivate::lines() const
+{
+ DWORD modemStat = 0;
+ SerialPort::Lines ret = 0;
+
+ if (!::GetCommModemStatus(descriptor, &modemStat))
+ return ret;
+
+ if (modemStat & MS_CTS_ON)
+ ret |= SerialPort::Cts;
+ if (modemStat & MS_DSR_ON)
+ ret |= SerialPort::Dsr;
+ if (modemStat & MS_RING_ON)
+ ret |= SerialPort::Ri;
+ if (modemStat & MS_RLSD_ON)
+ ret |= SerialPort::Dcd;
+
+ DWORD bytesReturned = 0;
+ if (::DeviceIoControl(descriptor, IOCTL_SERIAL_GET_DTRRTS, NULL, 0,
+ &modemStat, sizeof(modemStat),
+ &bytesReturned, NULL)) {
+
+ if (modemStat & SERIAL_DTR_STATE)
+ ret |= SerialPort::Dtr;
+ if (modemStat & SERIAL_RTS_STATE)
+ ret |= SerialPort::Rts;
+ }
+
+ return ret;
+}
+
+bool SerialPortPrivate::setDtr(bool set)
+{
+ return ::EscapeCommFunction(descriptor, set ? SETDTR : CLRDTR);
+}
+
+bool SerialPortPrivate::setRts(bool set)
+{
+ return ::EscapeCommFunction(descriptor, set ? SETRTS : CLRRTS);
+}
+
+#ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::flush()
+{
+ return startAsyncWrite() && ::FlushFileBuffers(descriptor);
+}
+
+#endif
+
+bool SerialPortPrivate::clear(SerialPort::Directions dir)
+{
+ DWORD flags = 0;
+ if (dir & SerialPort::Input)
+ flags |= PURGE_RXABORT | PURGE_RXCLEAR;
+ if (dir & SerialPort::Output)
+ flags |= PURGE_TXABORT | PURGE_TXCLEAR;
+ return ::PurgeComm(descriptor, flags);
+}
+
+bool SerialPortPrivate::sendBreak(int duration)
+{
+ // FIXME:
+ if (setBreak(true)) {
+ ::Sleep(duration);
+ if (setBreak(false))
+ return true;
+ }
+ return false;
+}
+
+bool SerialPortPrivate::setBreak(bool set)
+{
+ if (set)
+ return ::SetCommBreak(descriptor);
+ return ::ClearCommBreak(descriptor);
+}
+
+qint64 SerialPortPrivate::bytesAvailable() const
+{
+ COMSTAT cs;
+ ::memset(&cs, 0, sizeof(cs));
+ if (!::ClearCommError(descriptor, NULL, &cs))
+ return -1;
+ return cs.cbInQue;
+}
+
+qint64 SerialPortPrivate::bytesToWrite() const
+{
+ COMSTAT cs;
+ ::memset(&cs, 0, sizeof(cs));
+ if (!::ClearCommError(descriptor, NULL, &cs))
+ return -1;
+ return cs.cbOutQue;
+}
+
+#ifndef Q_OS_WINCE
+
+qint64 SerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
+{
+ if (actualReadBufferSize == 0)
+ return 0;
+
+ qint64 readSoFar = -1;
+ if (maxSize == 1 && actualReadBufferSize > 0) {
+ *data = readBuffer.getChar();
+ actualReadBufferSize--;
+ readSoFar = 1;
+ } else {
+ const qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxSize);
+ readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = readBuffer.readPointer();
+ const int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ qint64(readBuffer.nextDataBlockSize()));
+ ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ readBuffer.free(bytesToReadFromThisBlock);
+ actualReadBufferSize -= bytesToReadFromThisBlock;
+ }
+ }
+
+ if (!readSequenceStarted)
+ startAsyncRead();
+
+ return readSoFar;
+}
+
+qint64 SerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
+{
+ char *ptr = writeBuffer.reserve(maxSize);
+ if (maxSize == 1) {
+ *ptr = *data;
+ actualWriteBufferSize++;
+ } else {
+ ::memcpy(ptr, data, maxSize);
+ actualWriteBufferSize += maxSize;
+ }
+
+ if (!writeSequenceStarted)
+ startAsyncWrite(WriteChunkSize);
+
+ return maxSize;
+}
+
+bool SerialPortPrivate::waitForReadyRead(int msecs)
+{
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ do {
+ bool readyToStartRead = false;
+ bool readyToStartWrite = false;
+ bool readyToCompleteRead = false;
+ bool readyToCompleteWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToStartRead, &readyToStartWrite,
+ &readyToCompleteRead, &readyToCompleteWrite,
+ true, !writeBuffer.isEmpty(),
+ timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
+ // This is occur timeout or another error
+ // TODO: set error ?
+ return false;
+ }
+
+ if (readyToStartRead) {
+ if (!startAsyncRead())
+ return false;
+ }
+
+ if (readyToStartWrite) {
+ if (!startAsyncWrite(WriteChunkSize))
+ return false;
+ }
+
+ DWORD bytesTransferred = 0;
+
+ if (readyToCompleteRead) {
+ if (!::GetOverlappedResult(descriptor, &readOverlapped,
+ &bytesTransferred, FALSE)) {
+ return false;
+ }
+ return completeAsyncRead(bytesTransferred);
+ }
+
+ if (readyToCompleteWrite) {
+ if (::GetOverlappedResult(descriptor, &readOverlapped,
+ &bytesTransferred, FALSE)) {
+ completeAsyncWrite(bytesTransferred);
+ }
+ }
+
+ } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0);
+ return false;
+}
+
+bool SerialPortPrivate::waitForBytesWritten(int msecs)
+{
+ if (writeBuffer.isEmpty())
+ return false;
+
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ forever {
+ bool readyToStartRead = false;
+ bool readyToStartWrite = false;
+ bool readyToCompleteRead = false;
+ bool readyToCompleteWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToStartRead, &readyToStartWrite,
+ &readyToCompleteRead, &readyToCompleteWrite,
+ true, !writeBuffer.isEmpty(),
+ timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
+ // This is occur timeout or another error
+ // TODO: set error ?
+ return false;
+ }
+
+ if (readyToStartRead) {
+ if (!startAsyncRead())
+ return false;
+ }
+
+ if (readyToStartWrite) {
+ startAsyncWrite(WriteChunkSize);
+ }
+
+ DWORD bytesTransferred = 0;
+
+ if (readyToCompleteRead) {
+ if (!::GetOverlappedResult(descriptor, &readOverlapped,
+ &bytesTransferred, FALSE)) {
+ return false;
+ }
+ if (!completeAsyncRead(bytesTransferred))
+ return false;
+ }
+
+ if (readyToCompleteWrite) {
+ if (::GetOverlappedResult(descriptor, &readOverlapped,
+ &bytesTransferred, FALSE)) {
+ if (completeAsyncWrite(bytesTransferred))
+ return true;
+ }
+ }
+
+ }
+ return false;
+}
+
+#endif // #ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::setRate(qint32 rate, SerialPort::Directions dir)
+{
+ if (dir != SerialPort::AllDirections) {
+ portError = SerialPort::UnsupportedPortOperationError;
+ return false;
+ }
+ currentDcb.BaudRate = rate;
+ return updateDcb();
+}
+
+bool SerialPortPrivate::setDataBits(SerialPort::DataBits dataBits)
+{
+ currentDcb.ByteSize = dataBits;
+ return updateDcb();
+}
+
+bool SerialPortPrivate::setParity(SerialPort::Parity parity)
+{
+ currentDcb.fParity = TRUE;
+ switch (parity) {
+ case SerialPort::NoParity:
+ currentDcb.Parity = NOPARITY;
+ currentDcb.fParity = FALSE;
+ break;
+ case SerialPort::OddParity:
+ currentDcb.Parity = ODDPARITY;
+ break;
+ case SerialPort::EvenParity:
+ currentDcb.Parity = EVENPARITY;
+ break;
+ case SerialPort::MarkParity:
+ currentDcb.Parity = MARKPARITY;
+ break;
+ case SerialPort::SpaceParity:
+ currentDcb.Parity = SPACEPARITY;
+ break;
+ default:
+ currentDcb.Parity = NOPARITY;
+ currentDcb.fParity = FALSE;
+ break;
+ }
+ return updateDcb();
+}
+
+bool SerialPortPrivate::setStopBits(SerialPort::StopBits stopBits)
+{
+ switch (stopBits) {
+ case SerialPort::OneStop:
+ currentDcb.StopBits = ONESTOPBIT;
+ break;
+ case SerialPort::OneAndHalfStop:
+ currentDcb.StopBits = ONE5STOPBITS;
+ break;
+ case SerialPort::TwoStop:
+ currentDcb.StopBits = TWOSTOPBITS;
+ break;
+ default:
+ currentDcb.StopBits = ONESTOPBIT;
+ break;
+ }
+ return updateDcb();
+}
+
+bool SerialPortPrivate::setFlowControl(SerialPort::FlowControl flow)
+{
+ currentDcb.fInX = FALSE;
+ currentDcb.fOutX = FALSE;
+ currentDcb.fOutxCtsFlow = FALSE;
+ currentDcb.fRtsControl = RTS_CONTROL_DISABLE;
+ switch (flow) {
+ case SerialPort::NoFlowControl:
+ break;
+ case SerialPort::SoftwareControl:
+ currentDcb.fInX = TRUE;
+ currentDcb.fOutX = TRUE;
+ break;
+ case SerialPort::HardwareControl:
+ currentDcb.fOutxCtsFlow = TRUE;
+ currentDcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+ break;
+ default:
+ break;
+ }
+ return updateDcb();
+}
+
+bool SerialPortPrivate::setDataErrorPolicy(SerialPort::DataErrorPolicy policy)
+{
+ policy = policy;
+ return true;
+}
+
+#ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::startAsyncRead()
+{
+ DWORD bytesToRead = policy == SerialPort::IgnorePolicy ? ReadChunkSize : 1;
+
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (bytesToRead == 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the port.
+ return false;
+ }
+ }
+
+ char *ptr = readBuffer.reserve(bytesToRead);
+
+ readSequenceStarted = true;
+ if (::ReadFile(descriptor, ptr, bytesToRead, NULL, &readOverlapped))
+ return true;
+
+ switch (::GetLastError()) {
+ case ERROR_IO_PENDING:
+ // This is not an error. We're getting notified, when data arrives.
+ return true;
+ case ERROR_MORE_DATA:
+ // This is not an error. The synchronous read succeeded.
+ break;
+ default:
+ // error
+ readSequenceStarted = false;
+ return false;
+ }
+
+ return true;
+}
+
+bool SerialPortPrivate::startAsyncWrite(int maxSize)
+{
+ writeSequenceStarted = true;
+
+ int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize);
+
+ const char *ptr = writeBuffer.readPointer();
+
+ if (::WriteFile(descriptor, ptr, nextSize, NULL, &writeOverlapped))
+ return true;
+
+ switch (::GetLastError()) {
+ case ERROR_IO_PENDING:
+ // This is not an error. We're getting notified, when data arrives.
+ return true;
+ case ERROR_MORE_DATA:
+ // This is not an error. The synchronous read succeeded.
+ break;
+ default:
+ // error
+ writeSequenceStarted = false;
+ return false;
+ }
+ return true;
+}
+
+#endif // #ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::processIoErrors()
+{
+ DWORD error = 0;
+ const bool ret = ::ClearCommError(descriptor, &error, FALSE);
+ if (ret && error) {
+ if (error & CE_FRAME)
+ portError = SerialPort::FramingError;
+ else if (error & CE_RXPARITY)
+ portError = SerialPort::ParityError;
+ else if (error & CE_BREAK)
+ portError = SerialPort::BreakConditionError;
+ else
+ portError = SerialPort::UnknownPortError;
+
+ flagErrorFromCommEvent = true;
+ }
+ return ret;
+}
+
+#ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::completeAsyncRead(DWORD numberOfBytes)
+{
+ actualReadBufferSize += qint64(numberOfBytes);
+ readBuffer.truncate(actualReadBufferSize);
+
+ if (numberOfBytes > 0) {
+
+ // Process emulate policy.
+ if (flagErrorFromCommEvent) {
+
+ flagErrorFromCommEvent = false;
+
+ // Ignore received character, remove it from buffer
+ if (policy == SerialPort::SkipPolicy) {
+ readSequenceStarted = false;
+ readBuffer.getChar();
+ startAsyncRead();
+ return true;
+ }
+
+ // Abort receiving
+ if (policy == SerialPort::StopReceivingPolicy) {
+ readSequenceStarted = false;
+ readyReadEmitted = true;
+ emit q_ptr->readyRead();
+ return true;
+ }
+
+ // Replace received character by zero
+ if (policy == SerialPort::PassZeroPolicy) {
+ readBuffer.getChar();
+ readBuffer.putChar('\0');
+ }
+
+ }
+
+ readyReadEmitted = true;
+ emit q_ptr->readyRead();
+ startAsyncRead();
+ } else {
+ readSequenceStarted = false;
+ }
+ return true;
+}
+
+bool SerialPortPrivate::completeAsyncWrite(DWORD numberOfBytes)
+{
+ writeBuffer.free(numberOfBytes);
+ actualWriteBufferSize -= qint64(numberOfBytes);
+
+ if (numberOfBytes > 0)
+ emit q_ptr->bytesWritten(numberOfBytes);
+
+ if (writeBuffer.isEmpty())
+ writeSequenceStarted = false;
+ else
+ startAsyncWrite(WriteChunkSize);
+
+ return true;
+}
+
+bool SerialPortPrivate::updateDcb()
+{
+ if (!::SetCommState(descriptor, &currentDcb)) {
+ portError = decodeSystemError();
+ return false;
+ }
+ return true;
+}
+
+bool SerialPortPrivate::updateCommTimeouts()
+{
+ if (!::SetCommTimeouts(descriptor, &currentCommTimeouts)) {
+ portError = decodeSystemError();
+ return false;
+ }
+ return true;
+}
+
+#endif // #ifndef Q_OS_WINCE
+
+void SerialPortPrivate::detectDefaultSettings()
+{
+ // Detect rate.
+ inputRate = quint32(currentDcb.BaudRate);
+ outputRate = inputRate;
+
+ // Detect databits.
+ switch (currentDcb.ByteSize) {
+ case 5:
+ dataBits = SerialPort::Data5;
+ break;
+ case 6:
+ dataBits = SerialPort::Data6;
+ break;
+ case 7:
+ dataBits = SerialPort::Data7;
+ break;
+ case 8:
+ dataBits = SerialPort::Data8;
+ break;
+ default:
+ dataBits = SerialPort::UnknownDataBits;
+ break;
+ }
+
+ // Detect parity.
+ if ((currentDcb.Parity == NOPARITY) && !currentDcb.fParity)
+ parity = SerialPort::NoParity;
+ else if ((currentDcb.Parity == SPACEPARITY) && currentDcb.fParity)
+ parity = SerialPort::SpaceParity;
+ else if ((currentDcb.Parity == MARKPARITY) && currentDcb.fParity)
+ parity = SerialPort::MarkParity;
+ else if ((currentDcb.Parity == EVENPARITY) && currentDcb.fParity)
+ parity = SerialPort::EvenParity;
+ else if ((currentDcb.Parity == ODDPARITY) && currentDcb.fParity)
+ parity = SerialPort::OddParity;
+ else
+ parity = SerialPort::UnknownParity;
+
+ // Detect stopbits.
+ switch (currentDcb.StopBits) {
+ case ONESTOPBIT:
+ stopBits = SerialPort::OneStop;
+ break;
+ case ONE5STOPBITS:
+ stopBits = SerialPort::OneAndHalfStop;
+ break;
+ case TWOSTOPBITS:
+ stopBits = SerialPort::TwoStop;
+ break;
+ default:
+ stopBits = SerialPort::UnknownStopBits;
+ break;
+ }
+
+ // Detect flow control.
+ if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE)
+ && !currentDcb.fInX && !currentDcb.fOutX) {
+ flow = SerialPort::NoFlowControl;
+ } else if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE)
+ && currentDcb.fInX && currentDcb.fOutX) {
+ flow = SerialPort::SoftwareControl;
+ } else if (currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_HANDSHAKE)
+ && !currentDcb.fInX && !currentDcb.fOutX) {
+ flow = SerialPort::HardwareControl;
+ } else
+ flow = SerialPort::UnknownFlowControl;
+}
+
+SerialPort::PortError SerialPortPrivate::decodeSystemError() const
+{
+ SerialPort::PortError error;
+ switch (::GetLastError()) {
+ case ERROR_FILE_NOT_FOUND:
+ error = SerialPort::NoSuchDeviceError;
+ break;
+ case ERROR_ACCESS_DENIED:
+ error = SerialPort::PermissionDeniedError;
+ break;
+ case ERROR_INVALID_HANDLE:
+ error = SerialPort::DeviceIsNotOpenedError;
+ break;
+ case ERROR_INVALID_PARAMETER:
+ error = SerialPort::UnsupportedPortOperationError;
+ break;
+ default:
+ error = SerialPort::UnknownPortError;
+ break;
+ }
+ return error;
+}
+
+#ifndef Q_OS_WINCE
+
+bool SerialPortPrivate::waitForReadOrWrite(bool *selectForStartRead, bool *selectForStartWrite,
+ bool *selectForCompleteRead, bool *selectForCompleteWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_ASSERT(selectForStartRead);
+ Q_ASSERT(selectForStartWrite);
+ Q_ASSERT(selectForCompleteRead);
+ Q_ASSERT(selectForCompleteWrite);
+
+ DWORD eventMask = 0;
+
+ if (!::WaitCommEvent(descriptor, &eventMask, &selectOverlapped)
+ && ::GetLastError() != ERROR_IO_PENDING) {
+ return false;
+ }
+
+ enum {
+ SelectEventIndex = 0,
+ ReadEventIndex = 1,
+ WriteEventIndex = 2,
+ NumberOfEvents = 3
+ };
+
+ HANDLE events[NumberOfEvents] = {
+ selectOverlapped.hEvent,
+ readOverlapped.hEvent,
+ writeOverlapped.hEvent
+ };
+
+ DWORD waitResult = ::WaitForMultipleObjects(NumberOfEvents,
+ events,
+ FALSE, // wait any event
+ qMax(msecs, 0));
+
+ switch (waitResult) {
+ case WAIT_OBJECT_0 + SelectEventIndex: {
+ if (checkRead && (eventMask == EV_RXCHAR))
+ *selectForStartRead = true;
+ if (checkWrite && (eventMask == EV_TXEMPTY))
+ *selectForStartWrite = true;
+ }
+ break;
+ case WAIT_OBJECT_0 + ReadEventIndex: {
+ if (checkRead)
+ *selectForCompleteRead = true;
+ }
+ break;
+ case WAIT_OBJECT_0 + WriteEventIndex: {
+ if (checkWrite)
+ *selectForCompleteWrite = true;
+ }
+ break;
+ case WAIT_OBJECT_0 + WAIT_TIMEOUT: {
+ *timedOut = true;
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static const QLatin1String defaultPathPrefix("\\\\.\\");
+
+QString SerialPortPrivate::portNameToSystemLocation(const QString &port)
+{
+ QString ret = port;
+ if (!ret.contains(defaultPathPrefix))
+ ret.prepend(defaultPathPrefix);
+ return ret;
+}
+
+QString SerialPortPrivate::portNameFromSystemLocation(const QString &location)
+{
+ QString ret = location;
+ if (ret.contains(defaultPathPrefix))
+ ret.remove(defaultPathPrefix);
+ return ret;
+}
+
+#endif // #ifndef Q_OS_WINCE
+
+// This table contains standard values of baud rates that
+// are defined in MSDN and/or in Win SDK file winbase.h
+static const qint32 standardRatesTable[] =
+{
+ #ifdef CBR_110
+ CBR_110,
+ #endif
+ #ifdef CBR_300
+ CBR_300,
+ #endif
+ #ifdef CBR_600
+ CBR_600,
+ #endif
+ #ifdef CBR_1200
+ CBR_1200,
+ #endif
+ #ifdef CBR_2400
+ CBR_2400,
+ #endif
+ #ifdef CBR_4800
+ CBR_4800,
+ #endif
+ #ifdef CBR_9600
+ CBR_9600,
+ #endif
+ #ifdef CBR_14400
+ CBR_14400,
+ #endif
+ #ifdef CBR_19200
+ CBR_19200,
+ #endif
+ #ifdef CBR_38400
+ CBR_38400,
+ #endif
+ #ifdef CBR_56000
+ CBR_56000,
+ #endif
+ #ifdef CBR_57600
+ CBR_57600,
+ #endif
+ #ifdef CBR_115200
+ CBR_115200,
+ #endif
+ #ifdef CBR_128000
+ CBR_128000,
+ #endif
+ #ifdef CBR_256000
+ CBR_256000
+ #endif
+};
+
+static const qint32 *standardRatesTable_end =
+ standardRatesTable + sizeof(standardRatesTable)/sizeof(*standardRatesTable);
+
+qint32 SerialPortPrivate::rateFromSetting(qint32 setting)
+{
+ const qint32 *ret = qFind(standardRatesTable, standardRatesTable_end, setting);
+ return ret != standardRatesTable_end ? *ret : 0;
+}
+
+qint32 SerialPortPrivate::settingFromRate(qint32 rate)
+{
+ const qint32 *ret = qBinaryFind(standardRatesTable, standardRatesTable_end, rate);
+ return ret != standardRatesTable_end ? *ret : 0;
+}
+
+QList<qint32> SerialPortPrivate::standardRates()
+{
+ QList<qint32> l;
+ for (const qint32 *it = standardRatesTable; it != standardRatesTable_end; ++it)
+ l.append(*it);
+ return l;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialport_win_p.h b/src/serialport/serialport_win_p.h
new file mode 100644
index 0000000..171f2cb
--- /dev/null
+++ b/src/serialport/serialport_win_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORT_WIN_P_H
+#define SERIALPORT_WIN_P_H
+
+#include "serialport_p.h"
+
+#include <qt_windows.h>
+
+#ifndef Q_OS_WINCE
+class QWinEventNotifier;
+#else
+class QThread;
+#include <QtCore/qmutex.h>
+#endif
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortPrivate : public SerialPortPrivateData
+{
+public:
+ SerialPortPrivate(SerialPort *q);
+
+ bool open(QIODevice::OpenMode mode);
+ void close();
+
+ SerialPort::Lines lines() const;
+
+ bool setDtr(bool set);
+ bool setRts(bool set);
+
+ bool flush();
+ bool clear(SerialPort::Directions dir);
+
+ bool sendBreak(int duration);
+ bool setBreak(bool set);
+
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+
+ qint64 readFromBuffer(char *data, qint64 maxSize);
+ qint64 writeToBuffer(const char *data, qint64 maxSize);
+
+ bool waitForReadyRead(int msec);
+ bool waitForBytesWritten(int msec);
+
+ bool setRate(qint32 rate, SerialPort::Directions dir);
+ bool setDataBits(SerialPort::DataBits dataBits);
+ bool setParity(SerialPort::Parity parity);
+ bool setStopBits(SerialPort::StopBits stopBits);
+ bool setFlowControl(SerialPort::FlowControl flowControl);
+ bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy);
+
+ bool processIoErrors();
+#ifndef Q_OS_WINCE
+ bool startAsyncRead();
+ bool startAsyncWrite(int maxSize = INT_MAX);
+ bool completeAsyncRead(DWORD numberOfBytes);
+ bool completeAsyncWrite(DWORD numberOfBytes);
+#else
+ bool notifyRead();
+ bool notifyWrite(int maxSize = INT_MAX);
+#endif
+
+ static QString portNameToSystemLocation(const QString &port);
+ static QString portNameFromSystemLocation(const QString &location);
+
+ static qint32 rateFromSetting(qint32 setting);
+ static qint32 settingFromRate(qint32 rate);
+
+ static QList<qint32> standardRates();
+
+ DCB currentDcb;
+ DCB restoredDcb;
+ COMMTIMEOUTS currentCommTimeouts;
+ COMMTIMEOUTS restoredCommTimeouts;
+ HANDLE descriptor;
+ bool flagErrorFromCommEvent;
+ DWORD eventMask;
+
+#ifndef Q_OS_WINCE
+ OVERLAPPED eventOverlapped;
+ OVERLAPPED readOverlapped;
+ OVERLAPPED writeOverlapped;
+ OVERLAPPED selectOverlapped;
+
+ QWinEventNotifier *eventNotifier;
+ QWinEventNotifier *readCompletionNotifier;
+ QWinEventNotifier *writeCompletionNotifier;
+
+ qint64 actualReadBufferSize;
+ qint64 actualWriteBufferSize;
+ bool readyReadEmitted;
+ bool readSequenceStarted;
+ bool writeSequenceStarted;
+#else
+ QThread *eventNotifier;
+ QMutex settingsChangeMutex;
+#endif
+
+private:
+ bool updateDcb();
+ bool updateCommTimeouts();
+
+ void detectDefaultSettings();
+ SerialPort::PortError decodeSystemError() const;
+
+#ifndef Q_OS_WINCE
+ bool waitForReadOrWrite(bool *selectForStartRead, bool *selectForStartWrite,
+ bool *selectForCompleteRead, bool *selectForCompleteWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut);
+#else
+ bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut);
+#endif
+
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORT_WIN_P_H
diff --git a/src/serialport/serialport_wince.cpp b/src/serialport/serialport_wince.cpp
new file mode 100644
index 0000000..7489747
--- /dev/null
+++ b/src/serialport/serialport_wince.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialport_win_p.h"
+
+#include <QtCore/qelapsedtimer.h>
+
+#include <QtCore/qthread.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortPrivate;
+
+class CommEventNotifier : public QThread
+{
+ Q_OBJECT
+signals:
+ void eventMask(quint32 mask);
+
+public:
+ CommEventNotifier(DWORD mask, SerialPortPrivate *d, QObject *parent)
+ : QThread(parent), dptr(d), running(true) {
+ connect(this, SIGNAL(eventMask(quint32)), this, SLOT(processNotification(quint32)));
+ ::SetCommMask(dptr->descriptor, mask);
+ }
+
+ virtual ~CommEventNotifier() {
+ running = false;
+ ::SetCommMask(dptr->descriptor, 0);
+ wait();
+ }
+
+protected:
+ virtual void run() {
+ DWORD mask = 0;
+ while (running) {
+ if (::WaitCommEvent(dptr->descriptor, &mask, FALSE)) {
+ // Wait until complete the operation changes the port settings,
+ // see updateDcb().
+ dptr->settingsChangeMutex.lock();
+ dptr->settingsChangeMutex.unlock();
+ emit eventMask(quint32(mask));
+ }
+ }
+ }
+
+private slots:
+ void processNotification(quint32 eventMask) {
+ if (EV_ERR & eventMask)
+ dptr->processIoErrors();
+ if (EV_RXCHAR &eventMask)
+ dptr->notifyRead();
+ if (EV_TXEMPTY & eventMask)
+ dptr->notifyWrite(SerialPortPrivateData::WriteChunkSize);
+ }
+
+private:
+ SerialPortPrivate *dptr;
+ mutable bool running;
+};
+
+class WaitCommEventBreaker : public QThread
+{
+ Q_OBJECT
+public:
+ WaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0)
+ : QThread(parent), descriptor(descriptor), timeout(timeout), worked(false) {
+ start();
+ }
+
+ virtual ~WaitCommEventBreaker() {
+ stop();
+ wait();
+ }
+
+ void stop() {
+ exit(0);
+ }
+
+ bool isWorked() const {
+ return worked;
+ }
+
+protected:
+ void run() {
+ QTimer timer;
+ QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(processTimeout()), Qt::DirectConnection);
+ timer.start(timeout);
+ exec();
+ worked = true;
+ }
+
+private slots:
+ void processTimeout() {
+ ::SetCommMask(descriptor, 0);
+ stop();
+ }
+
+private:
+ HANDLE descriptor;
+ int timeout;
+ mutable bool worked;
+};
+
+SerialPortPrivate::SerialPortPrivate(SerialPort *q)
+ : SerialPortPrivateData(q)
+ , descriptor(INVALID_HANDLE_VALUE)
+ , flagErrorFromCommEvent(0)
+ , eventNotifier(0)
+{
+}
+
+bool SerialPortPrivate::open(QIODevice::OpenMode mode)
+{
+ DWORD desiredAccess = 0;
+ DWORD eventMask = EV_ERR;
+
+ if (mode & QIODevice::ReadOnly) {
+ desiredAccess |= GENERIC_READ;
+ eventMask |= EV_RXCHAR;
+ }
+ if (mode & QIODevice::WriteOnly) {
+ desiredAccess |= GENERIC_WRITE;
+ eventMask |= EV_TXEMPTY;
+ }
+
+ descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
+ desiredAccess, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (descriptor == INVALID_HANDLE_VALUE) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ if (!::GetCommState(descriptor, &restoredDcb)) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ currentDcb = restoredDcb;
+ currentDcb.fBinary = true;
+ currentDcb.fInX = false;
+ currentDcb.fOutX = false;
+ currentDcb.fAbortOnError = false;
+ currentDcb.fNull = false;
+ currentDcb.fErrorChar = false;
+
+ if (!updateDcb())
+ return false;
+
+ if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) {
+ portError = decodeSystemError();
+ return false;
+ }
+
+ ::memset(&currentCommTimeouts, 0, sizeof(currentCommTimeouts));
+ currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
+
+ if (!updateCommTimeouts())
+ return false;
+
+ eventNotifier = new QtAddOn::SerialPort::CommEventNotifier(eventMask, this, q_ptr);
+ eventNotifier->start();
+
+ detectDefaultSettings();
+ return true;
+}
+
+void SerialPortPrivate::close()
+{
+ if (eventNotifier) {
+ eventNotifier->deleteLater();
+ eventNotifier = 0;
+ }
+
+ if (restoreSettingsOnClose) {
+ ::SetCommState(descriptor, &restoredDcb);
+ ::SetCommTimeouts(descriptor, &restoredCommTimeouts);
+ }
+
+ ::CloseHandle(descriptor);
+ descriptor = INVALID_HANDLE_VALUE;
+}
+
+bool SerialPortPrivate::flush()
+{
+ return notifyWrite() && ::FlushFileBuffers(descriptor);
+}
+
+qint64 SerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
+{
+ if (readBuffer.isEmpty())
+ return 0;
+
+ if (maxSize == 1) {
+ *data = readBuffer.getChar();
+ return 1;
+ }
+
+ const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize);
+ qint64 readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = readBuffer.readPointer();
+ const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
+ readBuffer.nextDataBlockSize());
+ ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ readBuffer.free(bytesToReadFromThisBlock);
+ }
+
+ return readSoFar;
+}
+
+qint64 SerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
+{
+ char *ptr = writeBuffer.reserve(maxSize);
+ if (maxSize == 1)
+ *ptr = *data;
+ else
+ ::memcpy(ptr, data, maxSize);
+
+ return maxSize;
+}
+
+bool SerialPortPrivate::waitForReadyRead(int msec)
+{
+ if (!readBuffer.isEmpty())
+ return true;
+
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToRead, &readyToWrite,
+ true, !writeBuffer.isEmpty(),
+ timeoutValue(msec, stopWatch.elapsed()),
+ &timedOut)) {
+ return false;
+ }
+ if (readyToRead) {
+ if (notifyRead())
+ return true;
+ }
+ if (readyToWrite)
+ notifyWrite(WriteChunkSize);
+ }
+ return false;
+}
+
+bool SerialPortPrivate::waitForBytesWritten(int msec)
+{
+ if (writeBuffer.isEmpty())
+ return false;
+
+ QElapsedTimer stopWatch;
+
+ stopWatch.start();
+
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ bool timedOut = false;
+ if (!waitForReadOrWrite(&readyToRead, &readyToWrite,
+ true, !writeBuffer.isEmpty(),
+ timeoutValue(msec, stopWatch.elapsed()),
+ &timedOut)) {
+ return false;
+ }
+ if (readyToRead) {
+ if (!notifyRead())
+ return false;
+ }
+ if (readyToWrite) {
+ if (notifyWrite(WriteChunkSize))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SerialPortPrivate::notifyRead()
+{
+ DWORD bytesToRead = (policy == SerialPort::IgnorePolicy) ? ReadChunkSize : 1;
+
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (bytesToRead == 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the port.
+ return false;
+ }
+ }
+
+ char *ptr = readBuffer.reserve(bytesToRead);
+
+ DWORD readBytes = 0;
+ BOOL sucessResult = ::ReadFile(descriptor, ptr, bytesToRead, &readBytes, NULL);
+
+ if (!sucessResult) {
+ readBuffer.truncate(bytesToRead);
+ return false;
+ }
+
+ readBuffer.truncate(readBytes);
+
+ // Process emulate policy.
+ if (flagErrorFromCommEvent) {
+ flagErrorFromCommEvent = false;
+
+ switch (policy) {
+ case SerialPort::SkipPolicy:
+ readBuffer.getChar();
+ return true;
+ case SerialPort::PassZeroPolicy:
+ readBuffer.getChar();
+ readBuffer.putChar('\0');
+ break;
+ case SerialPort::StopReceivingPolicy:
+ // FIXME: Maybe need disable read notifier?
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (readBytes > 0)
+ emit q_ptr->readyRead();
+
+ return true;
+}
+
+bool SerialPortPrivate::notifyWrite(int maxSize)
+{
+ int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize);
+
+ const char *ptr = writeBuffer.readPointer();
+
+ DWORD bytesWritten = 0;
+ if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL))
+ return false;
+
+ writeBuffer.free(bytesWritten);
+
+ if (bytesWritten > 0)
+ emit q_ptr->bytesWritten(bytesWritten);
+
+ return true;
+}
+
+bool SerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ // FIXME: Here the situation is not properly handled with zero timeout:
+ // breaker can work out before you call a method WaitCommEvent()
+ // and so it will loop forever!
+ WaitCommEventBreaker breaker(descriptor, qMax(msecs, 0));
+ ::WaitCommEvent(descriptor, &eventMask, NULL);
+ breaker.stop();
+
+ if (breaker.isWorked())
+ *timedOut = true;
+
+ if (!breaker.isWorked()) {
+ if (checkRead) {
+ Q_ASSERT(selectForRead);
+ *selectForRead = eventMask & EV_RXCHAR;
+ }
+ if (checkWrite) {
+ Q_ASSERT(selectForWrite);
+ *selectForWrite = eventMask & EV_TXEMPTY;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SerialPortPrivate::updateDcb()
+{
+ QMutexLocker locker(&settingsChangeMutex);
+
+ DWORD eventMask = 0;
+ // Save the event mask
+ if (!::GetCommMask(descriptor, &eventMask))
+ return false;
+
+ // Break event notifier from WaitCommEvent
+ ::SetCommMask(descriptor, 0);
+ // Change parameters
+ bool ret = ::SetCommState(descriptor, &currentDcb);
+ if (!ret)
+ portError = decodeSystemError();
+ // Restore the event mask
+ ::SetCommMask(descriptor, eventMask);
+
+ return ret;
+}
+
+bool SerialPortPrivate::updateCommTimeouts()
+{
+ if (!::SetCommTimeouts(descriptor, &currentCommTimeouts)) {
+ portError = decodeSystemError();
+ return false;
+ }
+ return true;
+}
+
+static const QLatin1String defaultPathPostfix(":");
+
+QString SerialPortPrivate::portNameToSystemLocation(const QString &port)
+{
+ QString ret = port;
+ if (!ret.contains(defaultPathPostfix))
+ ret.append(defaultPathPostfix);
+ return ret;
+}
+
+QString SerialPortPrivate::portNameFromSystemLocation(const QString &location)
+{
+ QString ret = location;
+ if (ret.contains(defaultPathPostfix))
+ ret.remove(defaultPathPostfix);
+ return ret;
+}
+
+#include "serialport_wince.moc"
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo.cpp b/src/serialport/serialportinfo.cpp
new file mode 100644
index 0000000..82d927a
--- /dev/null
+++ b/src/serialport/serialportinfo.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+#include "serialport.h"
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+
+/*!
+ \class SerialPortInfo
+
+ \brief The SerialPortInfo class provides information about
+ existing serial ports.
+
+ \ingroup serialport-main
+ \inmodule QtAddOnSerialPort
+ \since 5.0
+
+ Use the static functions to generate a list of SerialPortInfo
+ objects. Each SerialPortInfo object in the list represents a single
+ serial port and can be queried for the port name, system location,
+ description, and manufacturer. The SerialPortInfo class can also be
+ used as an input parameter for the setPort() method of the SerialPort
+ class.
+
+ \sa SerialPort
+*/
+
+/*!
+ Constructs an empty SerialPortInfo object.
+
+ \sa isNull()
+*/
+SerialPortInfo::SerialPortInfo()
+ : d_ptr(new SerialPortInfoPrivate)
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+SerialPortInfo::SerialPortInfo(const SerialPortInfo &other)
+ : d_ptr(other.d_ptr ? new SerialPortInfoPrivate(*other.d_ptr) : 0)
+{
+}
+
+/*!
+ Constructs a SerialPortInfo object from serial \a port.
+*/
+SerialPortInfo::SerialPortInfo(const SerialPort &port)
+ : d_ptr(new SerialPortInfoPrivate)
+{
+ foreach (const SerialPortInfo &info, availablePorts()) {
+ if (port.portName() == info.portName()) {
+ *this = info;
+ break;
+ }
+ }
+}
+
+/*!
+ Constructs a SerialPortInfo object from serial port \a name.
+
+ This constructor finds the relevant serial port among the available ones
+ according to the port name \a name, and constructs the serial port info
+ instance for that port.
+*/
+SerialPortInfo::SerialPortInfo(const QString &name)
+ : d_ptr(new SerialPortInfoPrivate)
+{
+ foreach (const SerialPortInfo &info, availablePorts()) {
+ if (name == info.portName()) {
+ *this = info;
+ break;
+ }
+ }
+}
+
+/*!
+ Destroys the SerialPortInfo object. References to the values in the
+ object become invalid.
+*/
+SerialPortInfo::~SerialPortInfo()
+{
+}
+
+/*! \fn void SerialPortInfo::swap(SerialPortInfo &other)
+
+ Swaps SerialPortInfo \a other with this SerialPortInfo. This operation is
+ very fast and never fails.
+*/
+void SerialPortInfo::swap(SerialPortInfo &other)
+{
+ d_ptr.swap(other.d_ptr);
+}
+
+/*!
+ Sets the SerialPortInfo object to be equal to \a other.
+*/
+SerialPortInfo& SerialPortInfo::operator=(const SerialPortInfo &other)
+{
+ SerialPortInfo(other).swap(*this);
+ return *this;
+}
+
+/*!
+ Returns the name of the serial port.
+*/
+QString SerialPortInfo::portName() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->portName;
+}
+
+/*!
+ Returns the system location of the serial port.
+*/
+QString SerialPortInfo::systemLocation() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->device;
+}
+
+/*!
+ Returns the description string of the serial port,
+ if available; otherwise returns an empty string.
+*/
+QString SerialPortInfo::description() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->description;
+}
+
+/*!
+ Returns the manufacturer string of the serial port,
+ if available; otherwise returns an empty string.
+*/
+QString SerialPortInfo::manufacturer() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->manufacturer;
+}
+
+/*!
+ Returns the vendor identifier string of the serial
+ port in hexadecimal format, if available; otherwise
+ returns an empty string.
+*/
+QString SerialPortInfo::vendorIdentifier() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->vendorIdentifier;
+}
+
+/*!
+ Returns the product identifier string of the serial
+ port in hexadecimal format, if available; otherwise
+ returns an empty string.
+*/
+QString SerialPortInfo::productIdentifier() const
+{
+ Q_D(const SerialPortInfo);
+ return !d ? QString() : d->productIdentifier;
+}
+
+/*!
+ \fn bool SerialPortInfo::isNull() const
+
+ Returns whether this SerialPortInfo object holds a
+ serial port definition.
+*/
+
+/*!
+ \fn bool SerialPortInfo::isBusy() const
+
+ Returns true if serial port is busy;
+ otherwise returns false.
+*/
+
+/*!
+ \fn bool SerialPortInfo::isValid() const
+
+ Returns true if serial port is present on system;
+ otherwise returns false.
+*/
+
+/*!
+ \fn QList<qint32> SerialPortInfo::standardRates()
+
+ Returns a list of available standard baud rates supported by
+ the current serial port.
+*/
+
+/*!
+ \fn QList<SerialPortInfo> SerialPortInfo::availablePorts()
+
+ Returns a list of available serial ports on the system.
+*/
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo.h b/src/serialport/serialportinfo.h
new file mode 100644
index 0000000..049a468
--- /dev/null
+++ b/src/serialport/serialportinfo.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORTINFO_H
+#define SERIALPORTINFO_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qscopedpointer.h>
+
+#include "serialport-global.h"
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPort;
+class SerialPortInfoPrivate;
+class SerialInfoPrivateDeleter;
+
+class Q_SERIALPORT_EXPORT SerialPortInfo
+{
+ Q_DECLARE_PRIVATE(SerialPortInfo)
+public:
+ SerialPortInfo();
+ SerialPortInfo(const SerialPortInfo &other);
+ SerialPortInfo(const SerialPort &port);
+ SerialPortInfo(const QString &name);
+ ~SerialPortInfo();
+
+ SerialPortInfo& operator=(const SerialPortInfo &other);
+ void swap(SerialPortInfo &other);
+
+ QString portName() const;
+ QString systemLocation() const;
+ QString description() const;
+ QString manufacturer() const;
+ QString vendorIdentifier() const;
+ QString productIdentifier() const;
+
+ bool isNull() const;
+ bool isBusy() const;
+ bool isValid() const;
+
+ static QList<qint32> standardRates();
+ static QList<SerialPortInfo> availablePorts();
+
+private:
+ QScopedPointer<SerialPortInfoPrivate, SerialInfoPrivateDeleter> d_ptr;
+};
+
+inline bool SerialPortInfo::isNull() const
+{ return !d_ptr; }
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORTINFO_H
diff --git a/src/serialport/serialportinfo_mac.cpp b/src/serialport/serialportinfo_mac.cpp
new file mode 100644
index 0000000..6672a84
--- /dev/null
+++ b/src/serialport/serialportinfo_mac.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+
+#include <sys/param.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+
+#include <IOKit/serial/IOSerialKeys.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h> // for kIOPropertyProductNameKey
+#include <IOKit/usb/USB.h>
+#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
+# include <IOKit/serial/ioss.h>
+#endif
+#include <IOKit/IOBSD.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+enum { MATCHING_PROPERTIES_COUNT = 6 };
+
+QList<SerialPortInfo> SerialPortInfo::availablePorts()
+{
+ QList<SerialPortInfo> ports;
+
+ int matchingPropertiesCounter = 0;
+
+
+ ::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue);
+
+ ::CFDictionaryAddValue(matching,
+ CFSTR(kIOSerialBSDTypeKey),
+ CFSTR(kIOSerialBSDAllTypes));
+
+ io_iterator_t iter = 0;
+ kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault,
+ matching,
+ &iter);
+
+ if (kr != kIOReturnSuccess)
+ return ports;
+
+ io_registry_entry_t service;
+
+ while ((service = ::IOIteratorNext(iter))) {
+
+ ::CFTypeRef device = 0;
+ ::CFTypeRef portName = 0;
+ ::CFTypeRef description = 0;
+ ::CFTypeRef manufacturer = 0;
+ ::CFTypeRef vendorIdentifier = 0;
+ ::CFTypeRef productIdentifier = 0;
+
+ io_registry_entry_t entry = service;
+
+ // Find MacOSX-specific properties names.
+ do {
+
+ if (!device) {
+ device =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kIOCalloutDeviceKey),
+ kCFAllocatorDefault,
+ 0);
+ if (device)
+ ++matchingPropertiesCounter;
+ }
+
+ if (!portName) {
+ portName =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kIOTTYDeviceKey),
+ kCFAllocatorDefault,
+ 0);
+ if (portName)
+ ++matchingPropertiesCounter;
+ }
+
+ if (!description) {
+ description =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kIOPropertyProductNameKey),
+ kCFAllocatorDefault,
+ 0);
+ if (!description)
+ description =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kUSBProductString),
+ kCFAllocatorDefault,
+ 0);
+ if (description)
+ ++matchingPropertiesCounter;
+ }
+
+ if (!manufacturer) {
+ manufacturer =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kUSBVendorString),
+ kCFAllocatorDefault,
+ 0);
+ if (manufacturer)
+ ++matchingPropertiesCounter;
+
+ }
+
+ if (!vendorIdentifier) {
+ vendorIdentifier =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kUSBVendorID),
+ kCFAllocatorDefault,
+ 0);
+ if (vendorIdentifier)
+ ++matchingPropertiesCounter;
+
+ }
+
+ if (!productIdentifier) {
+ productIdentifier =
+ ::IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kUSBProductID),
+ kCFAllocatorDefault,
+ 0);
+ if (productIdentifier)
+ ++matchingPropertiesCounter;
+
+ }
+
+ // If all matching properties is found, then force break loop.
+ if (matchingPropertiesCounter == MATCHING_PROPERTIES_COUNT)
+ break;
+
+ kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry);
+
+ } while (kr == kIOReturnSuccess);
+
+ (void) ::IOObjectRelease(entry);
+
+ // Convert from MacOSX-specific properties to Qt4-specific.
+ if (matchingPropertiesCounter > 0) {
+
+ SerialPortInfo info;
+ QByteArray buffer(MAXPATHLEN, 0);
+
+ if (device) {
+ if (::CFStringGetCString(CFStringRef(device),
+ buffer.data(),
+ buffer.size(),
+ kCFStringEncodingUTF8)) {
+ info.d_ptr->device = QString(buffer);
+ }
+ ::CFRelease(device);
+ }
+
+ if (portName) {
+ if (::CFStringGetCString(CFStringRef(portName),
+ buffer.data(),
+ buffer.size(),
+ kCFStringEncodingUTF8)) {
+ info.d_ptr->portName = QString(buffer);
+ }
+ ::CFRelease(portName);
+ }
+
+ if (description) {
+ ::CFStringGetCString(CFStringRef(description),
+ buffer.data(),
+ buffer.size(),
+ kCFStringEncodingUTF8);
+
+ info.d_ptr->description = QString(buffer);
+ ::CFRelease(description);
+ }
+
+ if (manufacturer) {
+ ::CFStringGetCString(CFStringRef(manufacturer),
+ buffer.data(),
+ buffer.size(),
+ kCFStringEncodingUTF8);
+
+ info.d_ptr->manufacturer = QString(buffer);
+ ::CFRelease(manufacturer);
+ }
+
+ int value = 0;
+
+ if (vendorIdentifier) {
+ ::CFNumberGetValue(CFNumberRef(vendorIdentifier),
+ kCFNumberIntType,
+ &value);
+
+ info.d_ptr->vendorIdentifier = QString::number(value, 16);
+ ::CFRelease(vendorIdentifier);
+ }
+
+ if (productIdentifier) {
+ ::CFNumberGetValue(CFNumberRef(productIdentifier),
+ kCFNumberIntType,
+ &value);
+
+ info.d_ptr->productIdentifier = QString::number(value, 16);
+ ::CFRelease(productIdentifier);
+ }
+
+ ports.append(info);
+ }
+
+ (void) ::IOObjectRelease(service);
+ }
+
+ (void) ::IOObjectRelease(iter);
+
+ return ports;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo_p.h b/src/serialport/serialportinfo_p.h
new file mode 100644
index 0000000..262efa8
--- /dev/null
+++ b/src/serialport/serialportinfo_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERIALPORTINFO_P_H
+#define SERIALPORTINFO_P_H
+
+#include "serialport-global.h"
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class SerialPortInfoPrivate
+{
+public:
+ SerialPortInfoPrivate() {}
+ ~SerialPortInfoPrivate() {}
+
+ QString portName;
+ QString device;
+ QString description;
+ QString manufacturer;
+ QString vendorIdentifier;
+ QString productIdentifier;
+};
+
+class SerialInfoPrivateDeleter
+{
+public:
+ static void cleanup(SerialPortInfoPrivate *p) {
+ delete p;
+ }
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // SERIALPORTINFO_P_H
diff --git a/src/serialport/serialportinfo_symbian.cpp b/src/serialport/serialportinfo_symbian.cpp
new file mode 100644
index 0000000..057c760
--- /dev/null
+++ b/src/serialport/serialportinfo_symbian.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+#include "serialport_symbian_p.h"
+
+#include <e32base.h>
+//#include <e32test.h>
+#include <c32comm.h>
+#include <f32file.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+// Physical device driver.
+#ifdef __WINS__
+_LIT(KPddName, "ECDRV");
+#else // defined (__EPOC32__)
+_LIT(KPddName, "EUART");
+#endif
+
+// Logical native device driver.
+_LIT(KLddName,"ECOMM");
+
+// Modules names.
+_LIT(KRS232ModuleName , "ECUART");
+_LIT(KBluetoothModuleName , "BTCOMM");
+_LIT(KInfraRedModuleName , "IRCOMM");
+_LIT(KACMModuleName, "ECACM");
+
+// Return false on error load.
+static bool loadDevices()
+{
+ TInt r = KErrNone;
+#ifdef __WINS__
+ RFs fileServer;
+ r = User::LeaveIfError(fileServer.Connect());
+ if (r != KErrNone)
+ return false;
+ fileServer.Close ();
+#endif
+
+ r = User::LoadPhysicalDevice(KPddName);
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+
+ r = User::LoadLogicalDevice(KLddName);
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+
+#ifndef __WINS__
+ r = StartC32();
+ if (r != KErrNone && r != KErrAlreadyExists)
+ return false; //User::Leave(r);
+#endif
+
+ return true;
+}
+
+QList<SerialPortInfo> SerialPortInfo::availablePorts()
+{
+ QList<SerialPortInfo> ports;
+
+ if (!loadDevices())
+ return ports;
+
+ RCommServ server;
+ TInt r = server.Connect();
+ if (r != KErrNone)
+ return ports; //User::LeaveIfError(r);
+
+ TSerialInfo nativeInfo; // Native Symbian OS port info class.
+ QString s("%1::%2");
+
+ // FIXME: Get info about RS232 ports.
+ r = server.LoadCommModule(KRS232ModuleName);
+ //User::LeaveIfError(r);
+ if (r == KErrNone) {
+ r = server.GetPortInfo(KRS232ModuleName, nativeInfo);
+ if (r == KErrNone) {
+ //
+ for (quint32 i = nativeInfo.iLowUnit; i < nativeInfo.iHighUnit + 1; ++i) {
+
+ SerialPortInfo info; // My (desired) info class.
+
+ info.d_ptr->device = s
+ .arg(QString::fromUtf16(nativeInfo.iName.Ptr(), nativeInfo.iName.Length()))
+ .arg(i);
+ info.d_ptr->portName = info.d_ptr->device;
+ info.d_ptr->description =
+ QString::fromUtf16(nativeInfo.iDescription.Ptr(), nativeInfo.iDescription.Length());
+ info.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
+ ports.append(info);
+ }
+ }
+ }
+
+ // FIXME: Get info about Bluetooth ports.
+ r = server.LoadCommModule(KBluetoothModuleName);
+ //User::LeaveIfError(r);
+ if (r == KErrNone) {
+ r = server.GetPortInfo(KBluetoothModuleName, nativeInfo);
+ if (r == KErrNone) {
+ //
+ for (quint32 i = nativeInfo.iLowUnit; i < nativeInfo.iHighUnit + 1; ++i) {
+
+ SerialPortInfo info; // My (desired) info class.
+
+ info.d_ptr->device = s
+ .arg(QString::fromUtf16(nativeInfo.iName.Ptr(), nativeInfo.iName.Length()))
+ .arg(i);
+ info.d_ptr->portName = info.d_ptr->device;
+ info.d_ptr->description =
+ QString::fromUtf16(nativeInfo.iDescription.Ptr(), nativeInfo.iDescription.Length());
+ info.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
+ ports.append(info);
+ }
+ }
+ }
+
+ // FIXME: Get info about InfraRed ports.
+ r = server.LoadCommModule(KInfraRedModuleName);
+ //User::LeaveIfError(r);
+ if (r == KErrNone) {
+ r = server.GetPortInfo(KInfraRedModuleName, nativeInfo);
+ if (r == KErrNone) {
+ //
+ for (quint32 i = nativeInfo.iLowUnit; i < nativeInfo.iHighUnit + 1; ++i) {
+
+ SerialPortInfo info; // My (desired) info class.
+
+ info.d_ptr->device = s
+ .arg(QString::fromUtf16(nativeInfo.iName.Ptr(), nativeInfo.iName.Length()))
+ .arg(i);
+ info.d_ptr->portName = info.d_ptr->device;
+ info.d_ptr->description =
+ QString::fromUtf16(nativeInfo.iDescription.Ptr(), nativeInfo.iDescription.Length());
+ info.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
+ ports.append(info);
+ }
+ }
+ }
+
+ // FIXME: Get info about ACM ports.
+ r = server.LoadCommModule(KACMModuleName);
+ //User::LeaveIfError(r);
+ if (r == KErrNone) {
+ r = server.GetPortInfo(KACMModuleName, nativeInfo);
+ if (r == KErrNone) {
+ //
+ for (quint32 i = nativeInfo.iLowUnit; i < nativeInfo.iHighUnit + 1; ++i) {
+
+ SerialPortInfo info; // My (desired) info class.
+
+ info.d_ptr->device = s
+ .arg(QString::fromUtf16(nativeInfo.iName.Ptr(), nativeInfo.iName.Length()))
+ .arg(i);
+ info.d_ptr->portName = SerialPortPrivate::portNameFromSystemLocation(info.d_ptr->device);
+ info.d_ptr->description =
+ QString::fromUtf16(nativeInfo.iDescription.Ptr(), nativeInfo.iDescription.Length());
+ info.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
+ ports.append(info);
+ }
+ }
+ }
+
+ return ports;
+}
+
+QList<qint32> SerialPortInfo::standardRates()
+{
+ return SerialPortPrivate::standardRates();
+}
+
+bool SerialPortInfo::isBusy() const
+{
+ if (!loadDevices())
+ return false;
+
+ RCommServ server;
+ TInt r = server.Connect();
+ if (r != KErrNone)
+ return false;
+
+ RComm port;
+ TPtrC portName(static_cast<const TUint16*>(systemLocation().utf16()), systemLocation().length());
+ r = port.Open(server, portName, ECommExclusive);
+ if (r == KErrNone)
+ port.Close();
+ return r == KErrLocked;
+}
+
+bool SerialPortInfo::isValid() const
+{
+ if (!loadDevices())
+ return false;
+
+ RCommServ server;
+ TInt r = server.Connect();
+ if (r != KErrNone)
+ return false;
+
+ RComm port;
+ TPtrC portName(static_cast<const TUint16*>(systemLocation().utf16()), systemLocation().length());
+ r = port.Open(server, portName, ECommExclusive);
+ if (r == KErrNone)
+ port.Close();
+ return r == KErrNone || r == KErrLocked;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo_unix.cpp b/src/serialport/serialportinfo_unix.cpp
new file mode 100644
index 0000000..2869d44
--- /dev/null
+++ b/src/serialport/serialportinfo_unix.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+#include "ttylocker_unix_p.h"
+#include "serialport_unix_p.h"
+#include <QtCore/qfile.h>
+
+#ifndef Q_OS_MAC
+
+#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
+extern "C"
+{
+#include <libudev.h>
+}
+#else
+#include <QtCore/qdir.h>
+#include <QtCore/qstringlist.h>
+#endif
+
+#endif // Q_OS_MAC
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+#ifndef Q_OS_MAC
+
+#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
+
+// White list for devices without a parent
+static const QString rfcommDeviceName(QLatin1String("rfcomm"));
+
+#else
+
+static QStringList generateFiltersOfDevices()
+{
+ QStringList l;
+
+# ifdef Q_OS_LINUX
+ l << QLatin1String("ttyS*") // Standart UART 8250 and etc.
+ << QLatin1String("ttyUSB*") // Usb/serial converters PL2303 and etc.
+ << QLatin1String("ttyACM*") // CDC_ACM converters (i.e. Mobile Phones).
+ << QLatin1String("ttyGS*") // Gadget serial device (i.e. Mobile Phones with gadget serial driver).
+ << QLatin1String("ttyMI*") // MOXA pci/serial converters.
+ << QLatin1String("rfcomm*"); // Bluetooth serial device.
+# elif defined (Q_OS_FREEBSD)
+ l << QLatin1String("cu*");
+# else
+ // Here for other *nix OS.
+# endif
+
+ return l;
+}
+
+inline QStringList& filtersOfDevices()
+{
+ static QStringList l = generateFiltersOfDevices();
+ return l;
+}
+
+#endif
+
+QList<SerialPortInfo> SerialPortInfo::availablePorts()
+{
+ QList<SerialPortInfo> ports;
+
+#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
+
+ struct ::udev *udev = ::udev_new();
+ if (udev) {
+
+ struct ::udev_enumerate *enumerate =
+ ::udev_enumerate_new(udev);
+
+ if (enumerate) {
+
+ ::udev_enumerate_add_match_subsystem(enumerate, "tty");
+ ::udev_enumerate_scan_devices(enumerate);
+
+ struct ::udev_list_entry *devices =
+ ::udev_enumerate_get_list_entry(enumerate);
+
+ struct ::udev_list_entry *dev_list_entry;
+ udev_list_entry_foreach(dev_list_entry, devices) {
+
+ struct ::udev_device *dev =
+ ::udev_device_new_from_syspath(udev,
+ ::udev_list_entry_get_name(dev_list_entry));
+
+ if (dev) {
+
+ SerialPortInfo info;
+
+ info.d_ptr->device =
+ QLatin1String(::udev_device_get_devnode(dev));
+ info.d_ptr->portName =
+ QLatin1String(::udev_device_get_sysname(dev));
+
+ struct ::udev_device *parentdev = ::udev_device_get_parent(dev);
+
+ bool canAppendToList = true;
+
+ if (parentdev) {
+
+ QLatin1String subsys(::udev_device_get_subsystem(parentdev));
+
+ if (subsys == QLatin1String("usb-serial")
+ || subsys == QLatin1String("usb")) { // USB bus type
+ // Append this devices and try get additional information about them.
+ info.d_ptr->description = QString(
+ QLatin1String(::udev_device_get_property_value(dev,
+ "ID_MODEL"))).replace('_', ' ');
+ info.d_ptr->manufacturer = QString(
+ QLatin1String(::udev_device_get_property_value(dev,
+ "ID_VENDOR"))).replace('_', ' ');
+ info.d_ptr->vendorIdentifier =
+ QLatin1String(::udev_device_get_property_value(dev,
+ "ID_VENDOR_ID"));
+ info.d_ptr->productIdentifier =
+ QLatin1String(::udev_device_get_property_value(dev,
+ "ID_MODEL_ID"));
+ } else if (subsys == QLatin1String("pnp")) { // PNP bus type
+ // Append this device.
+ // FIXME: How to get additional information about serial devices
+ // with this subsystem?
+ } else if (subsys == QLatin1String("platform")) { // Platform 'pseudo' bus for legacy device.
+ // Skip this devices because this type of subsystem does
+ // not include a real physical serial device.
+ canAppendToList = false;
+ } else { // Others types of subsystems.
+ // Append this devices because we believe that any other types of
+ // subsystems provide a real serial devices. For example, for devices
+ // such as ttyGSx, its driver provide an empty subsystem name, but it
+ // devices is a real physical serial devices.
+ // FIXME: How to get additional information about serial devices
+ // with this subsystems?
+ }
+ } else { // Devices without a parent
+ if (info.d_ptr->portName.startsWith(rfcommDeviceName)) { // Bluetooth device
+ bool ok;
+ // Check for an unsigned decimal integer at the end of the device name: "rfcomm0", "rfcomm15"
+ // devices with negative and invalid numbers in the name are rejected
+ int portNumber = info.d_ptr->portName.mid(rfcommDeviceName.length()).toInt(&ok);
+
+ if (!ok || (portNumber < 0) || (portNumber > 255)) {
+ canAppendToList = false;
+ }
+ } else {
+ canAppendToList = false;
+ }
+ }
+
+ if (canAppendToList)
+ ports.append(info);
+
+ ::udev_device_unref(dev);
+ }
+
+ }
+
+ ::udev_enumerate_unref(enumerate);
+ }
+
+ ::udev_unref(udev);
+ }
+
+#elif defined (Q_OS_FREEBSD) && defined (HAVE_LIBUSB)
+ // TODO: Implement me.
+#else
+
+ QDir devDir(QLatin1String("/dev"));
+ if (devDir.exists()) {
+
+ devDir.setNameFilters(filtersOfDevices());
+ devDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks);
+
+ QStringList foundDevices; // Found devices list.
+
+ foreach (const QFileInfo &fi, devDir.entryInfoList()) {
+ QString s = fi.absoluteFilePath();
+ if (!foundDevices.contains(s)) {
+ foundDevices.append(s);
+
+ SerialPortInfo info;
+
+ info.d_ptr->device = s;
+ info.d_ptr->portName = SerialPortPrivate::portNameFromSystemLocation(s);
+
+ // Get description, manufacturer, vendor identifier, product
+ // identifier are not supported.
+
+ ports.append(info);
+
+ }
+ }
+ }
+
+#endif
+
+ return ports;
+}
+
+#endif // Q_OS_MAC
+
+// common part
+
+QList<qint32> SerialPortInfo::standardRates()
+{
+ return SerialPortPrivate::standardRates();
+}
+
+bool SerialPortInfo::isBusy() const
+{
+ bool currentPid = false;
+ return TtyLocker::isLocked(portName().toLocal8Bit().constData(), &currentPid);
+}
+
+bool SerialPortInfo::isValid() const
+{
+ QFile f(systemLocation());
+ return f.exists();
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo_win.cpp b/src/serialport/serialportinfo_win.cpp
new file mode 100644
index 0000000..a0e4c73
--- /dev/null
+++ b/src/serialport/serialportinfo_win.cpp
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+#include "serialport_win_p.h"
+
+#include <qt_windows.h>
+
+#ifndef Q_OS_WINCE
+#include <initguid.h>
+#include <setupapi.h>
+#endif
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+#ifndef Q_OS_WINCE
+
+static const GUID guidsArray[] =
+{
+ // Windows Ports Class GUID
+ { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
+ // Virtual Ports Class GUID (i.e. com0com and etc)
+ { 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } },
+ // Windows Modems Class GUID
+ { 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
+ // Eltima Virtual Serial Port Driver v4 GUID
+ { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } },
+ // Advanced Virtual COM Port GUID
+ { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } },
+};
+
+static const wchar_t portKeyName[] = L"PortName";
+
+static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet,
+ PSP_DEVINFO_DATA deviceInfoData,
+ DWORD property)
+{
+ DWORD dataType = 0;
+ DWORD dataSize = 0;
+ ::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData,
+ property, &dataType, NULL, 0, &dataSize);
+ QByteArray data(dataSize, 0);
+ if (!::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, NULL,
+ reinterpret_cast<unsigned char*>(data.data()),
+ dataSize, NULL)
+ || !dataSize) {
+ return QVariant();
+ }
+
+ switch (dataType) {
+
+ case REG_EXPAND_SZ:
+ case REG_SZ: {
+ return QVariant(QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData())));
+ }
+
+ case REG_MULTI_SZ: {
+ QStringList list;
+ int i = 0;
+ forever {
+ QString s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()) + i);
+ i += s.length() + 1;
+ if (s.isEmpty())
+ break;
+ list.append(s);
+ }
+ return QVariant(list);
+ }
+
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData)
+{
+ const HKEY key = ::SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL,
+ 0, DIREG_DEV, KEY_READ);
+ if (key == INVALID_HANDLE_VALUE)
+ return QString();
+
+ DWORD dataSize;
+ if (::RegQueryValueEx(key, portKeyName, NULL, NULL, NULL, &dataSize) != ERROR_SUCCESS) {
+ ::RegCloseKey(key);
+ return QString();
+ }
+
+ QByteArray data(dataSize, 0);
+
+ if (::RegQueryValueEx(key, portKeyName, NULL, NULL,
+ reinterpret_cast<unsigned char *>(data.data()), &dataSize) != ERROR_SUCCESS) {
+ ::RegCloseKey(key);
+ return QString();
+ }
+ ::RegCloseKey(key);
+ return QString::fromWCharArray(((const wchar_t *)data.constData()));
+}
+
+QList<SerialPortInfo> SerialPortInfo::availablePorts()
+{
+ QList<SerialPortInfo> ports;
+ static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]);
+
+ for (int i = 0; i < guidCount; ++i) {
+ const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT);
+ if (deviceInfoSet == INVALID_HANDLE_VALUE)
+ return ports;
+
+ SP_DEVINFO_DATA deviceInfoData;
+ ::memset(&deviceInfoData, 0, sizeof(deviceInfoData));
+ deviceInfoData.cbSize = sizeof(deviceInfoData);
+
+ DWORD index = 0;
+ while (::SetupDiEnumDeviceInfo(deviceInfoSet, index++, &deviceInfoData)) {
+ SerialPortInfo info;
+
+ QString s = devicePortName(deviceInfoSet, &deviceInfoData);
+ if (s.isEmpty() || s.contains(QLatin1String("LPT")))
+ continue;
+
+ info.d_ptr->portName = s;
+ info.d_ptr->device = SerialPortPrivate::portNameToSystemLocation(s);
+ info.d_ptr->description =
+ deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC).toString();
+ info.d_ptr->manufacturer =
+ deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG).toString();
+
+ s = deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID).toStringList().at(0).toUpper();
+ info.d_ptr->vendorIdentifier = s.mid(s.indexOf(QLatin1String("VID_")) + 4, 4);
+ info.d_ptr->productIdentifier = s.mid(s.indexOf(QLatin1String("PID_")) + 4, 4);
+
+ ports.append(info);
+ }
+ ::SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ return ports;
+}
+
+#endif
+
+// common part
+
+QList<qint32> SerialPortInfo::standardRates()
+{
+ return SerialPortPrivate::standardRates();
+}
+
+bool SerialPortInfo::isBusy() const
+{
+ const HANDLE descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()),
+ GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (descriptor == INVALID_HANDLE_VALUE) {
+ if (::GetLastError() == ERROR_ACCESS_DENIED)
+ return true;
+ } else {
+ ::CloseHandle(descriptor);
+ }
+ return false;
+}
+
+bool SerialPortInfo::isValid() const
+{
+ const HANDLE descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()),
+ GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (descriptor == INVALID_HANDLE_VALUE) {
+ if (::GetLastError() != ERROR_ACCESS_DENIED)
+ return false;
+ } else {
+ ::CloseHandle(descriptor);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/serialportinfo_wince.cpp b/src/serialport/serialportinfo_wince.cpp
new file mode 100644
index 0000000..1fbbd86
--- /dev/null
+++ b/src/serialport/serialportinfo_wince.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <scapig2@yandex.ru>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "serialportinfo.h"
+#include "serialportinfo_p.h"
+#include "serialport_win_p.h"
+
+#include <qt_windows.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+const static QString valueName(QLatin1String("FriendlyName"));
+static QString findDescription(HKEY parentKeyHandle, const QString &subKey)
+{
+ QString result;
+ HKEY hSubKey = 0;
+ LONG res = ::RegOpenKeyEx(parentKeyHandle, reinterpret_cast<const wchar_t *>(subKey.utf16()),
+ 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hSubKey);
+
+ if (res == ERROR_SUCCESS) {
+
+ DWORD dataType = 0;
+ DWORD dataSize = 0;
+ res = ::RegQueryValueEx(hSubKey, reinterpret_cast<const wchar_t *>(valueName.utf16()),
+ NULL, &dataType, NULL, &dataSize);
+
+ if (res == ERROR_SUCCESS) {
+ QByteArray data(dataSize, 0);
+ res = ::RegQueryValueEx(hSubKey, reinterpret_cast<const wchar_t *>(valueName.utf16()),
+ NULL, NULL,
+ reinterpret_cast<unsigned char *>(data.data()),
+ &dataSize);
+
+ if (res == ERROR_SUCCESS) {
+ switch (dataType) {
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+ if (dataSize)
+ result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ DWORD index = 0;
+ dataSize = 255; // Max. key length (see MSDN).
+ QByteArray data(dataSize, 0);
+ while (::RegEnumKeyEx(hSubKey, index++,
+ reinterpret_cast<wchar_t *>(data.data()), &dataSize,
+ NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
+
+ result = findDescription(hSubKey,
+ QString::fromUtf16(reinterpret_cast<ushort *>(data.data()), dataSize));
+ if (!result.isEmpty())
+ break;
+ }
+ }
+ ::RegCloseKey(hSubKey);
+ }
+ return result;
+}
+
+QList<SerialPortInfo> SerialPortInfo::availablePorts()
+{
+ QList<SerialPortInfo> ports;
+
+ DEVMGR_DEVICE_INFORMATION di;
+ di.dwSize = sizeof(di);
+ const HANDLE hSearch = ::FindFirstDevice(DeviceSearchByLegacyName,
+ L"COM*",
+ &di);
+ if (hSearch != INVALID_HANDLE_VALUE) {
+ do {
+ SerialPortInfo info;
+ info.d_ptr->device = QString::fromWCharArray(di.szLegacyName);
+ info.d_ptr->portName = SerialPortPrivate::portNameFromSystemLocation(info.d_ptr->device);
+ info.d_ptr->description = findDescription(HKEY_LOCAL_MACHINE,
+ QString::fromWCharArray(di.szDeviceKey));
+
+ // Get manufacturer, vendor identifier, product identifier are not
+ // possible.
+
+ ports.append(info);
+
+ } while (::FindNextDevice(hSearch, &di));
+ ::FindClose(hSearch);
+ }
+
+ return ports;
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/ttylocker_unix.cpp b/src/serialport/ttylocker_unix.cpp
new file mode 100644
index 0000000..3e36d67
--- /dev/null
+++ b/src/serialport/ttylocker_unix.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ttylocker_unix_p.h"
+
+#ifdef HAVE_BAUDBOY_H
+# include <baudboy.h>
+# include <cstdlib>
+#elif defined (HAVE_LOCKDEV_H)
+# include <lockdev.h>
+# include <unistd.h>
+#else
+# include <signal.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <sys/stat.h>
+# include <unistd.h>
+# include <QtCore/qfile.h>
+# include <QtCore/qdir.h>
+# include <QtCore/qstringlist.h>
+#endif // defined (HAVE_BAUDBOY_H)
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H))
+
+static
+const char * const entryLockDirectoryList[] = {
+ "/var/lock",
+ "/etc/locks",
+ "/var/spool/locks",
+ "/var/spool/uucp",
+ "/tmp",
+ 0
+};
+
+// Returns the full path first found in the directory where you can create a lock file
+// (ie a directory with access to the read/write).
+// Verification of directories is of the order in accordance with the order
+// of records in the variable lockDirList.
+static
+QString lookupFirstSharedLockDir()
+{
+ for (int i = 0; entryLockDirectoryList[i] != 0; ++i) {
+ if (::access(entryLockDirectoryList[i], R_OK | W_OK) == 0)
+ return QLatin1String(entryLockDirectoryList[i]);
+ }
+ return QString();
+}
+
+// Returns the name of the lock file which is tied to the
+// device name, eg "LCK..ttyS0", etc.
+static
+QString generateLockFileNameAsNamedForm(const char *portName)
+{
+ QString result(lookupFirstSharedLockDir());
+ if (!result.isEmpty())
+ result.append(QLatin1String("/LCK..") + QLatin1String(portName));
+ return result;
+}
+
+#endif //!(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H))
+
+// Try lock serial device. However, other processes can not access it.
+bool TtyLocker::lock(const char *portName)
+{
+#ifdef HAVE_BAUDBOY_H
+ if (::ttylock(portName)
+ ::ttywait(portName);
+ return ::ttylock(portName) != -1;
+#elif defined (HAVE_LOCKDEV_H)
+ return ::dev_lock(portName) != -1;
+#else
+ QFile f(generateLockFileNameAsNamedForm(portName));
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ QString content(QLatin1String(" %1 %2\x0A"));
+ content = content.arg(::getpid()).arg(::getuid());
+ if (f.write(content.toLocal8Bit()) > 0) {
+ f.close();
+ return true;
+ }
+ f.close();
+ }
+ return false;
+#endif
+}
+
+// Try unlock serial device. However, other processes can access it.
+bool TtyLocker::unlock(const char *portName)
+{
+#ifdef HAVE_BAUDBOY_H
+ return ::ttyunlock(portName != -1;
+#elif defined (HAVE_LOCKDEV_H)
+ return ::dev_unlock(portName, ::getpid()) != -1;
+#else
+ QFile f(generateLockFileNameAsNamedForm(portName));
+ return f.remove();
+#endif
+}
+
+// Verifies the device is locked or not.
+// If returned currentPid = true - this means that the device is locked the current process.
+bool TtyLocker::isLocked(const char *portName, bool *currentPid)
+{
+ if (!currentPid)
+ return true;
+
+ *currentPid = false;
+
+#ifdef HAVE_BAUDBOY_H
+ return ::ttylocked(portName) != -1;
+#elif defined (HAVE_LOCKDEV_H)
+ return ::dev_testlock(portName) != -1;
+#else
+
+ QFile f(generateLockFileNameAsNamedForm(portName));
+ if (!f.exists())
+ return false;
+ if (!f.open(QIODevice::ReadOnly))
+ return true;
+
+ QString content(QLatin1String(f.readAll()));
+ f.close();
+
+ const pid_t pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt();
+
+ if (::kill(pid, 0) == -1) {
+ if (errno == ESRCH) // Process does not exists
+ return false;
+ } else {
+ if (::getpid() == pid) // Process exists and it is "their", i.e current
+ *currentPid = true;
+ }
+
+ return true;
+
+#endif
+}
+
+QT_END_NAMESPACE_SERIALPORT
diff --git a/src/serialport/ttylocker_unix_p.h b/src/serialport/ttylocker_unix_p.h
new file mode 100644
index 0000000..ed93fb1
--- /dev/null
+++ b/src/serialport/ttylocker_unix_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov <scapig@yandex.ru>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TTYLOCKER_UNIX_P_H
+#define TTYLOCKER_UNIX_P_H
+
+#include "serialport-global.h"
+
+QT_BEGIN_NAMESPACE_SERIALPORT
+
+class TtyLocker
+{
+public:
+ static bool lock(const char *portName);
+ static bool unlock(const char *portName);
+ static bool isLocked(const char *portName, bool *currentPid);
+};
+
+QT_END_NAMESPACE_SERIALPORT
+
+#endif // TTYLOCKER_UNIX_P_H