From b8af6f604cd86897c8a04825700892fd9970a616 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Sat, 11 Feb 2012 20:46:02 +0400 Subject: The first prepare QtSerialPort to the form of add-on, with the requirements of "Creating a new module or tool for Qt" Change-Id: I62bba3590a8873bfd03ed6836ac105e0a30d35ba Reviewed-by: Denis Shienkov --- .gitignore | 21 + CHANGES | 0 INSTALL | 0 LICENSE | 0 doc/EMPTYFILE | 0 doc/qserialdevice.qdocconf | 72 -- doc/src/serialportengine.qdoc | 1 - examples/consoleportinfo/consoleportinfo.pro | 27 - examples/consoleportinfo/main.cpp | 22 - examples/examples.pro | 2 - examples/guiportinfo/guiportinfo.pro | 28 - examples/guiportinfo/main.cpp | 11 - examples/guiportinfo/portinfodialog.cpp | 93 -- examples/guiportinfo/portinfodialog.h | 29 - examples/guiportinfo/portinfodialog.ui | 158 --- include/serialport.h | 213 ---- include/serialportinfo.h | 61 - modules/qt_serialport.pri | 16 + serialport.pro | 7 +- src/ringbuffer_p.h | 6 +- src/serialport-global.h | 34 + src/serialport.cpp | 6 +- src/serialport.h | 205 ++++ src/serialport_p.h | 5 +- src/serialportengine_p.h | 4 +- src/serialportengine_p_symbian.cpp | 981 ---------------- src/serialportengine_p_symbian.h | 78 -- src/serialportengine_p_unix.cpp | 1474 ------------------------ src/serialportengine_p_unix.h | 91 -- src/serialportengine_p_win.cpp | 1301 ---------------------- src/serialportengine_p_win.h | 162 --- src/serialportengine_symbian.cpp | 983 ++++++++++++++++ src/serialportengine_symbian_p.h | 78 ++ src/serialportengine_unix.cpp | 1478 +++++++++++++++++++++++++ src/serialportengine_unix_p.h | 91 ++ src/serialportengine_win.cpp | 1305 ++++++++++++++++++++++ src/serialportengine_win_p.h | 162 +++ src/serialportinfo.cpp | 4 +- src/serialportinfo.h | 53 + src/serialportinfo_mac.cpp | 4 +- src/serialportinfo_p.h | 4 +- src/serialportinfo_symbian.cpp | 4 +- src/serialportinfo_unix.cpp | 82 +- src/serialportinfo_win.cpp | 10 +- src/src-lib.pri | 79 ++ src/src.pri | 73 -- src/src.pro | 91 +- src/ttylocker_p_unix.cpp | 242 ---- src/ttylocker_p_unix.h | 24 - src/ttylocker_unix.cpp | 212 ++++ src/ttylocker_unix_p.h | 22 + sync.profile | 22 + tests/consolewaitreader/consolewaitreader.pro | 25 - tests/consolewaitreader/main.cpp | 89 -- tests/consolewriter/consolewriter.pro | 25 - tests/consolewriter/main.cpp | 81 -- tests/guiapp/guiapp.pro | 33 - tests/guiapp/main.cpp | 11 - tests/guiapp/maindialog.cpp | 173 --- tests/guiapp/maindialog.h | 48 - tests/guiapp/maindialog.ui | 275 ----- tests/guiapp/optionsdialog.cpp | 249 ----- tests/guiapp/optionsdialog.h | 39 - tests/guiapp/optionsdialog.ui | 91 -- tests/guiapp/tracedialog.cpp | 81 -- tests/guiapp/tracedialog.h | 34 - tests/guiapp/tracedialog.ui | 70 -- tests/guidevtest/guidevtest.pro | 45 - tests/guidevtest/main.cpp | 17 - tests/guidevtest/maindialog.cpp | 381 ------- tests/guidevtest/maindialog.h | 82 -- tests/guidevtest/maindialog.ui | 152 --- tests/guidevtest/unittestinfo.cpp | 64 -- tests/guidevtest/unittestio.cpp | 308 ------ tests/guidevtest/unittests.h | 168 --- tests/guidevtest/unittestsignals.cpp | 218 ---- tests/guidevtest/unittestwaitforx.cpp | 33 - 77 files changed, 4853 insertions(+), 8070 deletions(-) create mode 100644 .gitignore delete mode 100644 CHANGES delete mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 doc/EMPTYFILE delete mode 100644 doc/qserialdevice.qdocconf delete mode 100644 doc/src/serialportengine.qdoc delete mode 100644 examples/consoleportinfo/consoleportinfo.pro delete mode 100644 examples/consoleportinfo/main.cpp delete mode 100644 examples/examples.pro delete mode 100644 examples/guiportinfo/guiportinfo.pro delete mode 100644 examples/guiportinfo/main.cpp delete mode 100644 examples/guiportinfo/portinfodialog.cpp delete mode 100644 examples/guiportinfo/portinfodialog.h delete mode 100644 examples/guiportinfo/portinfodialog.ui delete mode 100644 include/serialport.h delete mode 100644 include/serialportinfo.h create mode 100644 modules/qt_serialport.pri create mode 100644 src/serialport-global.h create mode 100644 src/serialport.h delete mode 100644 src/serialportengine_p_symbian.cpp delete mode 100644 src/serialportengine_p_symbian.h delete mode 100644 src/serialportengine_p_unix.cpp delete mode 100644 src/serialportengine_p_unix.h delete mode 100644 src/serialportengine_p_win.cpp delete mode 100644 src/serialportengine_p_win.h create mode 100644 src/serialportengine_symbian.cpp create mode 100644 src/serialportengine_symbian_p.h create mode 100644 src/serialportengine_unix.cpp create mode 100644 src/serialportengine_unix_p.h create mode 100644 src/serialportengine_win.cpp create mode 100644 src/serialportengine_win_p.h create mode 100644 src/serialportinfo.h create mode 100644 src/src-lib.pri delete mode 100644 src/src.pri delete mode 100644 src/ttylocker_p_unix.cpp delete mode 100644 src/ttylocker_p_unix.h create mode 100644 src/ttylocker_unix.cpp create mode 100644 src/ttylocker_unix_p.h create mode 100644 sync.profile delete mode 100644 tests/consolewaitreader/consolewaitreader.pro delete mode 100644 tests/consolewaitreader/main.cpp delete mode 100644 tests/consolewriter/consolewriter.pro delete mode 100644 tests/consolewriter/main.cpp delete mode 100644 tests/guiapp/guiapp.pro delete mode 100644 tests/guiapp/main.cpp delete mode 100644 tests/guiapp/maindialog.cpp delete mode 100644 tests/guiapp/maindialog.h delete mode 100644 tests/guiapp/maindialog.ui delete mode 100644 tests/guiapp/optionsdialog.cpp delete mode 100644 tests/guiapp/optionsdialog.h delete mode 100644 tests/guiapp/optionsdialog.ui delete mode 100644 tests/guiapp/tracedialog.cpp delete mode 100644 tests/guiapp/tracedialog.h delete mode 100644 tests/guiapp/tracedialog.ui delete mode 100644 tests/guidevtest/guidevtest.pro delete mode 100644 tests/guidevtest/main.cpp delete mode 100644 tests/guidevtest/maindialog.cpp delete mode 100644 tests/guidevtest/maindialog.h delete mode 100644 tests/guidevtest/maindialog.ui delete mode 100644 tests/guidevtest/unittestinfo.cpp delete mode 100644 tests/guidevtest/unittestio.cpp delete mode 100644 tests/guidevtest/unittests.h delete mode 100644 tests/guidevtest/unittestsignals.cpp delete mode 100644 tests/guidevtest/unittestwaitforx.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c88ebd4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*~ +doc/html +Makefile +*.dylib +*.o +*.a +moc_*.cpp +*.pro.user +*.moc +lib*.so +lib*.so.* +.qmake.cache +include/QtAddOnSerialPort/* +lib/cmake/* +lib*.la +lib*.prl +module-paths/* +src/qtaddonserialportversion.h +lib/pkgconfig/* +Makefile.Debug +Makefile.Release diff --git a/CHANGES b/CHANGES deleted file mode 100644 index e69de29..0000000 diff --git a/INSTALL b/INSTALL deleted file mode 100644 index e69de29..0000000 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/doc/EMPTYFILE b/doc/EMPTYFILE new file mode 100644 index 0000000..e69de29 diff --git a/doc/qserialdevice.qdocconf b/doc/qserialdevice.qdocconf deleted file mode 100644 index ca2928e..0000000 --- a/doc/qserialdevice.qdocconf +++ /dev/null @@ -1,72 +0,0 @@ -#include(compat.qdocconf) -#include(macros.qdocconf) -#include(qt-cpp-ignore.qdocconf) -#include(qt-html-templates.qdocconf) -#include(qt-defines.qdocconf) - -project = QSerialDevice -versionsym = -version = 2.0 -description = QSerialDevice Reference Documentation -url = https://gitorious.org/qserialdevice - -###### - -#qhp.projects = QSerialDevice - -#qhp.QSerialDevice.file = qserialdevice.qhp -#qhp.QSerialDevice.namespace = com.gitorious.org.qserialdevice.20 -#qhp.QSerialDevice.virtualFolder = qdoc -#qhp.QSerialDevice.indexTitle = QSerialDevice Reference Documentation -#qhp.QSerialDevice.indexRoot = - -# Files not referenced in any qdoc file (last four are needed by qtdemo) -# See also extraimages.HTML -#qhp.QSerialDevice.extraFiles = classic.css - -#qhp.QSerialDevice.filterAttributes = qt 4.7.4 qtrefdoc -#qhp.QSerialDevice.customFilters.Qt.name = Qt 4.7.4 -#qhp.QSerialDevice.customFilters.Qt.filterAttributes = qt 4.7.4 -#qhp.QSerialDevice.subprojects = classes overviews examples -#qhp.QSerialDevice.subprojects.classes.title = Classes -#qhp.QSerialDevice.subprojects.classes.indexTitle = Qt's Classes -#qhp.QSerialDevice.subprojects.classes.selectors = class fake:headerfile -#qhp.QSerialDevice.subprojects.classes.sortPages = true -#qhp.QSerialDevice.subprojects.overviews.title = Overviews -#qhp.QSerialDevice.subprojects.overviews.indexTitle = All Overviews and HOWTOs -#qhp.QSerialDevice.subprojects.overviews.selectors = fake:page,group,module -#qhp.QSerialDevice.subprojects.examples.title = Tutorials and Examples -#qhp.QSerialDevice.subprojects.examples.indexTitle = Qt Examples -#qhp.QSerialDevice.subprojects.examples.selectors = fake:example - -language = Cpp - -Cpp.ignoretokens = SERIALPORT_EXPORT - -headers.fileextensions = "*.h" -sources.fileextensions = "*.cpp *.qdoc *.mm" -examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" - -headerdirs = $SERIALDEVICE_DIR/include \ - $SERIALDEVICE_DIR/src - -sourcedirs = $SERIALDEVICE_DIR/src \ - $SERIALDEVICE_DIR/doc/src - -exampledirs = $SERIALDEVICE_DIR/doc/src \ - $SERIALDEVICE_DIR/examples - -imagedirs = $SERIALDEVICE_DIR/doc/src/images \ - $SERIALDEVICE_DIR/examples - -outputdir = $SERIALDEVICE_DIR/doc/html - -tagfile = $SERIALDEVICE_DIR/doc/html/qt.tags - -base = file:$SERIALDEVICE_DIR/doc/html - - - - - - diff --git a/doc/src/serialportengine.qdoc b/doc/src/serialportengine.qdoc deleted file mode 100644 index e5a49f3..0000000 --- a/doc/src/serialportengine.qdoc +++ /dev/null @@ -1 +0,0 @@ -qqq \ No newline at end of file diff --git a/examples/consoleportinfo/consoleportinfo.pro b/examples/consoleportinfo/consoleportinfo.pro deleted file mode 100644 index 9bdd996..0000000 --- a/examples/consoleportinfo/consoleportinfo.pro +++ /dev/null @@ -1,27 +0,0 @@ -TEMPLATE = app -CONFIG += console -QT -= gui -OBJECTS_DIR = obj -MOC_DIR = moc - -linux*:DEFINES += HAVE_LIBUDEV - -INCLUDEPATH += \ - ../../include - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += main.cpp - -CONFIG(debug, debug|release) { - DESTDIR = debug - TARGET = consoleinfod -} else { - DESTDIR = release - TARGET = consoleinfo -} - diff --git a/examples/consoleportinfo/main.cpp b/examples/consoleportinfo/main.cpp deleted file mode 100644 index c1a3d56..0000000 --- a/examples/consoleportinfo/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -#include "serialportinfo.h" - -int main(int argc, char *argv[]) -{ - QCoreApplication a(argc, argv); - - QList list = SerialPortInfo::availablePorts(); - int item = 0; - foreach(SerialPortInfo info, list) { - qDebug() << "--> Item: " << item++; - qDebug() << "Port name : " << info.portName(); - qDebug() << "Port location : " << info.systemLocation(); - qDebug() << "Port description : " << info.description(); - qDebug() << "Port manufacturer: " << info.manufacturer(); - } - - return a.exec(); -} diff --git a/examples/examples.pro b/examples/examples.pro deleted file mode 100644 index 43c38e2..0000000 --- a/examples/examples.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += consoleportinfo diff --git a/examples/guiportinfo/guiportinfo.pro b/examples/guiportinfo/guiportinfo.pro deleted file mode 100644 index df2671e..0000000 --- a/examples/guiportinfo/guiportinfo.pro +++ /dev/null @@ -1,28 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2011-09-21T13:44:17 -# -#------------------------------------------------- - -QT += core gui - -TARGET = guiportinfo -TEMPLATE = app - -linux*:DEFINES += HAVE_LIBUDEV - -INCLUDEPATH += \ - ../../include - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += main.cpp\ - portinfodialog.cpp - -HEADERS += portinfodialog.h - -FORMS += portinfodialog.ui diff --git a/examples/guiportinfo/main.cpp b/examples/guiportinfo/main.cpp deleted file mode 100644 index 2bdf2fa..0000000 --- a/examples/guiportinfo/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "portinfodialog.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - Dialog w; - w.show(); - - return a.exec(); -} diff --git a/examples/guiportinfo/portinfodialog.cpp b/examples/guiportinfo/portinfodialog.cpp deleted file mode 100644 index 7954e43..0000000 --- a/examples/guiportinfo/portinfodialog.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "portinfodialog.h" -#include "ui_portinfodialog.h" - -#include "serialportinfo.h" - -#include - -Q_DECLARE_METATYPE(SerialPortInfo) - -Dialog::Dialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::Dialog) -{ - ui->setupUi(this); - procUpdateAvailablePorts(); - procItemPortChanged(0); - - connect(ui->updateButton, SIGNAL(clicked()), this, SLOT(procUpdateAvailablePorts())); - connect(ui->portsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(procItemPortChanged(int))); - connect(ui->busyButton, SIGNAL(clicked()), this, SLOT(procBusyButtonClick())); - connect(ui->validButton, SIGNAL(clicked()), this, SLOT(procValidButtonClick())); - connect(ui->ratesButton, SIGNAL(clicked()), this, SLOT(procRatesButtonClick())); -} - -Dialog::~Dialog() -{ - delete ui; -} - -void Dialog::procUpdateAvailablePorts() -{ - ui->portsComboBox->clear(); - foreach (SerialPortInfo info, SerialPortInfo::availablePorts()) { - QVariant v; - v.setValue(info); - ui->portsComboBox->addItem(info.portName(), v); - } -} - -void Dialog::procItemPortChanged(int idx) -{ - QVariant v = ui->portsComboBox->itemData(idx); - if (v.isValid()) { - SerialPortInfo info = v.value(); - - ui->locationValueLabel->setText(info.systemLocation()); - ui->descriptionValueLabel->setText(info.description()); - ui->manufacturerValueLabel->setText(info.manufacturer()); - - ui->busyLabel->setText("***"); - ui->validLabel->setText("***"); - ui->ratesComboBox->clear(); - } -} - -void Dialog::procBusyButtonClick() -{ - int idx = ui->portsComboBox->currentIndex(); - if (idx >= 0) { - QVariant v = ui->portsComboBox->itemData(idx); - if (v.isValid()) { - SerialPortInfo info = v.value(); - ui->busyLabel->setText(info.isBusy() ? tr("Busy") : tr("Free")); - } - } -} - -void Dialog::procValidButtonClick() -{ - int idx = ui->portsComboBox->currentIndex(); - if (idx >= 0) { - QVariant v = ui->portsComboBox->itemData(idx); - if (v.isValid()) { - SerialPortInfo info = v.value(); - ui->validLabel->setText(info.isValid() ? tr("Valid") : tr("Invalid")); - } - } -} - -void Dialog::procRatesButtonClick() -{ - ui->ratesComboBox->clear(); - int idx = ui->portsComboBox->currentIndex(); - if (idx >= 0) { - QVariant v = ui->portsComboBox->itemData(idx); - if (v.isValid()) { - SerialPortInfo info = v.value(); - - foreach (qint32 rate, info.standardRates()) - ui->ratesComboBox->addItem(QString::number(rate)); - } - } -} diff --git a/examples/guiportinfo/portinfodialog.h b/examples/guiportinfo/portinfodialog.h deleted file mode 100644 index 9032be7..0000000 --- a/examples/guiportinfo/portinfodialog.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef PORTINFODIALOG_H -#define PORTINFODIALOG_H - -#include - -namespace Ui { - class Dialog; -} - -class Dialog : public QDialog -{ - Q_OBJECT - -public: - explicit Dialog(QWidget *parent = 0); - ~Dialog(); - -private slots: - void procUpdateAvailablePorts(); - void procItemPortChanged(int idx); - void procBusyButtonClick(); - void procValidButtonClick(); - void procRatesButtonClick(); - -private: - Ui::Dialog *ui; -}; - -#endif // PORTINFODIALOG_H diff --git a/examples/guiportinfo/portinfodialog.ui b/examples/guiportinfo/portinfodialog.ui deleted file mode 100644 index abe58ec..0000000 --- a/examples/guiportinfo/portinfodialog.ui +++ /dev/null @@ -1,158 +0,0 @@ - - - Dialog - - - - 0 - 0 - 293 - 255 - - - - Simple port info application - - - - - - Available ports: - - - - - - Current port name: - - - - - - - - - - Update - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Current port info: - - - - - - - - Location: - - - - - - - *** - - - - - - - Description: - - - - - - - *** - - - - - - - Manufacturer: - - - - - - - *** - - - - - - - - - - - Check valid - - - - - - - *** - - - - - - - Check busy - - - - - - - *** - - - - - - - Get rates - - - - - - - - - - - - - - - - - diff --git a/include/serialport.h b/include/serialport.h deleted file mode 100644 index 2089b32..0000000 --- a/include/serialport.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - License... -*/ - -#ifndef SERIALPORT_H -#define SERIALPORT_H - -#include - -#ifdef SERIALPORT_SHARED -# ifdef SERIALPORT_BUILD -# define SERIALPORT_EXPORT Q_DECL_EXPORT -# else -# define SERIALPORT_EXPORT Q_DECL_IMPORT -# endif -#else -# define SERIALPORT_EXPORT -#endif - -QT_BEGIN_NAMESPACE - -class SerialPortInfo; -class SerialPortPrivate; - -class 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 - }; - - 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(); - virtual bool reset(); - 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 - -#endif // SERIALPORT_H diff --git a/include/serialportinfo.h b/include/serialportinfo.h deleted file mode 100644 index b197d52..0000000 --- a/include/serialportinfo.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - License... -*/ - -#ifndef SERIALPORTINFO_H -#define SERIALPORTINFO_H - -#include -#include - -#ifdef SERIALPORT_SHARED -# ifdef SERIALPORT_BUILD -# define SERIALPORT_EXPORT Q_DECL_EXPORT -# else -# define SERIALPORT_EXPORT Q_DECL_IMPORT -# endif -#else -# define SERIALPORT_EXPORT -#endif - -QT_BEGIN_NAMESPACE - -class SerialPort; -class SerialPortInfoPrivate; -class SerialInfoPrivateDeleter; - -class 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; - - bool isNull() const; - bool isBusy() const; - bool isValid() const; - - QList standardRates() const; - static QList availablePorts(); - -private: - QScopedPointer d_ptr; -}; - -inline bool SerialPortInfo::isNull() const -{ return !d_ptr; } - -QT_END_NAMESPACE - -#endif // SERIALPORTINFO_H diff --git a/modules/qt_serialport.pri b/modules/qt_serialport.pri new file mode 100644 index 0000000..0bd4768 --- /dev/null +++ b/modules/qt_serialport.pri @@ -0,0 +1,16 @@ +QT.serialport.VERSION = 1.0.0 +QT.serialport.MAJOR_VERSION = 1 +QT.serialport.MINOR_VERSION = 0 +QT.serialport.PATCH_VERSION = 0 + +QT.serialport.name = QtAddOnSerialPort +QT.serialport.bins = $$QT_MODULE_BIN_BASE +QT.serialport.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtAddOnSerialPort +QT.serialport.private_includes = $$QT_MODULE_INCLUDE_BASE/QtAddOnSerialPort/$$QT.serialport.VERSION +QT.serialport.sources = $$QT_MODULE_BASE/src +QT.serialport.libs = $$QT_MODULE_LIB_BASE +QT.serialport.plugins = $$QT_MODULE_PLUGIN_BASE +QT.serialport.imports = $$QT_MODULE_IMPORT_BASE +QT.serialport.depends = core + +QT_CONFIG += serialport diff --git a/serialport.pro b/serialport.pro index f5e0a59..27d0ba4 100644 --- a/serialport.pro +++ b/serialport.pro @@ -1,5 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = src -#examples - - +SUBDIRS = src #tests +CONFIG += ordered +#include(doc/doc.pri) diff --git a/src/ringbuffer_p.h b/src/ringbuffer_p.h index e99443f..8a2c3ed 100644 --- a/src/ringbuffer_p.h +++ b/src/ringbuffer_p.h @@ -4,7 +4,9 @@ #include #include -QT_BEGIN_NAMESPACE +#include "serialport-global.h" + +QT_BEGIN_NAMESPACE_SERIALPORT class RingBuffer { @@ -370,6 +372,6 @@ private: int bufferSize; }; -QT_END_NAMESPACE +QT_END_NAMESPACE_SERIALPORT #endif // RINGBUFFER_P_H diff --git a/src/serialport-global.h b/src/serialport-global.h new file mode 100644 index 0000000..85331aa --- /dev/null +++ b/src/serialport-global.h @@ -0,0 +1,34 @@ +/* + License... +*/ + +#ifndef SERIALPORT_GLOBAL_H +#define SERIALPORT_GLOBAL_H + +#include "qglobal.h" + +#if defined(QT_ADDON_SERIALPORT_LIB) +# define Q_ADDON_SERIALPORT_EXPORT Q_DECL_EXPORT +#else +# define Q_ADDON_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.cpp b/src/serialport.cpp index 308a461..3fe766b 100644 --- a/src/serialport.cpp +++ b/src/serialport.cpp @@ -17,7 +17,7 @@ # define SERIALPORT_BUFFERSIZE 16384 #endif -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT //---------------------------------------------------------------- @@ -1779,3 +1779,7 @@ qint64 SerialPort::writeData(const char *data, qint64 maxSize) \sa setBreak(), sendBreak() */ + +#include "moc_serialport.cpp" + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialport.h b/src/serialport.h new file mode 100644 index 0000000..1282468 --- /dev/null +++ b/src/serialport.h @@ -0,0 +1,205 @@ +/* + License... +*/ + +#ifndef SERIALPORT_H +#define SERIALPORT_H + +#include + +#include "serialport-global.h" + +QT_BEGIN_NAMESPACE_SERIALPORT + +class SerialPortInfo; +class SerialPortPrivate; + +class Q_ADDON_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 + }; + + 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(); + virtual bool reset(); + 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_p.h b/src/serialport_p.h index 4c376ca..3576d51 100644 --- a/src/serialport_p.h +++ b/src/serialport_p.h @@ -8,7 +8,7 @@ #include "serialport.h" #include "ringbuffer_p.h" -QT_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT class SerialPortEngine; @@ -70,7 +70,6 @@ public: bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite); - void clearBuffers(); bool readFromPort(); @@ -104,6 +103,6 @@ public: bool m_restoreSettingsOnClose; }; -QT_END_NAMESPACE +QT_END_NAMESPACE_SERIALPORT #endif // SERIALPORT_P_H diff --git a/src/serialportengine_p.h b/src/serialportengine_p.h index 4f122a8..e163342 100644 --- a/src/serialportengine_p.h +++ b/src/serialportengine_p.h @@ -8,7 +8,7 @@ #include "serialport.h" #include "serialport_p.h" -QT_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT class SerialPortEngine { @@ -79,6 +79,6 @@ protected: virtual void detectDefaultSettings() = 0; }; -QT_END_NAMESPACE +QT_END_NAMESPACE_SERIALPORT #endif // SERIALPORTENGINE_P_H diff --git a/src/serialportengine_p_symbian.cpp b/src/serialportengine_p_symbian.cpp deleted file mode 100644 index 6e7d916..0000000 --- a/src/serialportengine_p_symbian.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/* - License... -*/ - -/*! - \class SymbianSerialPortEngine - \internal - - \brief The SymbianSerialPortEngine class provides *nix OS - platform-specific low level access to a serial port. - - \reentrant - \ingroup serial - \inmodule QSerialDevice - - Currently the class supports all?? version of Symbian OS. - - SymbianSerialPortEngine (as well as other platform-dependent engines) - is a class with multiple inheritance, which on the one hand, - derives from a general abstract class interface SerialPortEngine, - on the other hand of a class inherited from QObject. - - From the abstract class SerialPortEngine, it inherits all virtual - interface methods that are common to all serial ports on any platform. - These methods, the class SymbianSerialPortEngine implements use - Symbian API. - - From QObject-like class ... - ... - ... - ... - - That is, as seen from the above, the functional SymbianSerialPortEngine - completely covers all the necessary tasks. -*/ - -#include "serialportengine_p_symbian.h" - -#include -//#include -#include - -#include -//#include - - -// Physical device driver. -#if defined (__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; -#if defined (__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); - -#if !defined (__WINS__) - r = StartC32(); - if ((r != KErrNone) && (r != KErrAlreadyExists)) - return false; //User::Leave(r); -#endif - - return true; -} - -QT_USE_NAMESPACE - -/* Public methods */ - -/*! - Constructs a SymbianSerialPortEngine with \a parent and - initializes all the internal variables of the initial values. - - A pointer \a parent to the object class SerialPortPrivate - is required for the recursive call some of its methods. -*/ -SymbianSerialPortEngine::SymbianSerialPortEngine(SerialPortPrivate *parent) -{ - Q_ASSERT(parent); - // Impl me - m_parent = parent; -} - -/*! - Destructs a SymbianSerialPortEngine, -*/ -SymbianSerialPortEngine::~SymbianSerialPortEngine() -{ - -} - -/*! - Tries to open the object desired serial port by \a location - in the given open \a mode. In the API of Symbian there is no flag - to open the port in r/o, w/o or r/w, most likely he always opens - as r/w. - - Since the port in the Symbian OS can be open in any access mode, - then this method forcibly puts a port in exclusive mode access. - In the process of discovery, always set a port in non-blocking - mode (when the read operation returns immediately) and tries to - determine its current configuration and install them. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) -{ - // Maybe need added check an ReadWrite open mode? - Q_UNUSED(mode) - - if (!loadDevices()) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - - RCommServ server; - TInt r = server.Connect(); - if (r != KErrNone) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - - if (location.contains("BTCOMM")) - r = server.LoadCommModule(KBluetoothModuleName); - else if (location.contains("IRCOMM")) - r = server.LoadCommModule(KInfraRedModuleName); - else if (location.contains("ACM")) - r = server.LoadCommModule(KACMModuleName); - else - r = server.LoadCommModule(KRS232ModuleName); - - if (r != KErrNone) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - - // In Symbian OS port opening only in R/W mode !? - TPtrC portName(static_cast(location.utf16()), location.length()); - r = m_descriptor.Open(server, portName, ECommExclusive); - - if (r != KErrNone) { - switch (r) { - case KErrPermissionDenied: - m_parent->setError(SerialPort::NoSuchDeviceError); break; - case KErrLocked: - case KErrAccessDenied: - m_parent->setError(SerialPort::PermissionDeniedError); break; - default: - m_parent->setError(SerialPort::UnknownPortError); - } - return false; - } - - // Save current port settings. - r = m_descriptor.Config(m_oldSettings); - if (r != KErrNone) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - - detectDefaultSettings(); - return true; -} - -/*! - Closes a serial port object. Before closing restore previous - serial port settings if necessary. -*/ -void SymbianSerialPortEngine::close(const QString &location) -{ - Q_UNUSED(location); - - if (m_parent->m_restoreSettingsOnClose) { - m_descriptor.SetConfig(m_oldSettings); - } - - m_descriptor.Close(); -} - -/*! - Returns a bitmap state of RS-232 line signals. On error, - bitmap will be empty (equal zero). - - Symbian API allows you to receive only the state of signals: - CTS, DSR, DCD, RING, RTS, DTR. Other signals are not available. -*/ -SerialPort::Lines SymbianSerialPortEngine::lines() const -{ - SerialPort::Lines ret = 0; - - TUint signalMask = 0; - m_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; -} - -/*! - Set DTR signal to state \a set. - - -*/ -bool SymbianSerialPortEngine::setDtr(bool set) -{ - TInt r; - if (set) - r = m_descriptor.SetSignalsToMark(KSignalDTR); - else - r = m_descriptor.SetSignalsToSpace(KSignalDTR); - - return (r == KErrNone); -} - -/*! - Set RTS signal to state \a set. - - -*/ -bool SymbianSerialPortEngine::setRts(bool set) -{ - TInt r; - if (set) - r = m_descriptor.SetSignalsToMark(KSignalRTS); - else - r = m_descriptor.SetSignalsToSpace(KSignalRTS); - - return (r == KErrNone); -} - -/*! - -*/ -bool SymbianSerialPortEngine::flush() -{ - // Impl me - return false; -} - -/*! - Resets the transmit and receive serial port buffers - independently. -*/ -bool SymbianSerialPortEngine::reset() -{ - TInt r = m_descriptor.ResetBuffers(KCommResetRx | KCommResetTx); - return (r == KErrNone); -} - -/*! - Sets a break condition for a specified time \a duration - in milliseconds. - - A break condition on a line is when a data line is held - permanently high for an indeterminate period which must be - greater than the time normally taken to transmit two characters. - It is sometimes used as an error signal between computers and - other devices attached to them over RS232 lines. - - Setting breaks is not supported on the integral ARM - serial hardware. EPOC has no support for detecting received - breaks. There is no way to detects whether setting a break is - supported using Caps(). -*/ -bool SymbianSerialPortEngine::sendBreak(int duration) -{ - TRequestStatus status; - m_descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000)); - return false; -} - -/*! - -*/ -bool SymbianSerialPortEngine::setBreak(bool set) -{ - // Impl me - return false; -} - -/*! - Gets the number of bytes currently waiting in the - driver's input buffer. A return value of zero means - the buffer is empty. -*/ -qint64 SymbianSerialPortEngine::bytesAvailable() const -{ - return qint64(m_descriptor.QueryReceiveBuffer()); -} - -/*! - - It is not possible to find out exactly how many bytes are - currently in the driver's output buffer waiting to be - transmitted. However, this is not an issue since it is easy - to ensure that the output buffer is empty. If the - KConfigWriteBufferedComplete bit (set via the TCommConfigV01 - structure's iHandshake field) is clear, then all write - requests will delay completion until the data has completely - cleared the driver's output buffer. - If the KConfigWriteBufferedComplete bit is set, a write of zero - bytes to a port which has data in the output buffer is guaranteed - to delay completion until the buffer has been fully drained. - -*/ -qint64 SymbianSerialPortEngine::bytesToWrite() const -{ - // Impl me - return 0; -} - -/*! - - Reads data from a serial port only if it arrives before a - specified time-out (zero). All reads from the serial device - use 8-bit descriptors as data buffers, even on a Unicode system. - - The length of the TDes8 is set to zero on entry, which means that - buffers can be reused without having to be zeroed first. - - The number of bytes to read is set to the maximum length of the - descriptor. - - If a read is issued with a data length of zero the Read() completes - immediately but with the side effect that the serial hardware is - powered up. - - When a Read() terminates with KErrTimedOut, different protocol - modules can show different behaviours. Some may write any data - received into the aDes buffer, while others may return just an - empty descriptor. In the case of a returned empty descriptor use - ReadOneOrMore() to read any data left in the buffer. - - The behaviour of this API after a call to NotifyDataAvailable() is - not prescribed and so different CSY's behave differently. IrComm - will allow a successful completion of this API after a call to - NotifyDataAvailable(), while ECUART and ECACM will complete the - request with KErrInUse. - -*/ -qint64 SymbianSerialPortEngine::read(char *data, qint64 len) -{ - TPtr8 buffer((TUint8 *)data, (int)len); - TRequestStatus status; - m_descriptor.Read(status, TTimeIntervalMicroSeconds32(0), buffer); - User::WaitForRequest(status); - TInt err = status.Int(); - if (err != KErrNone) { - m_parent->setError(SerialPort::IoError); - return qint64(-1); - } - return qint64(buffer.Length()); -} - -/*! - - Writes data to a serial port. All writes to the serial device - use 8-bit descriptors as data buffers, even on a Unicode system. - - The number of bytes to write is set to the maximum length of - the descriptor. - - When a Write() is issued with a data length of zero it cannot - complete until the current handshaking configuration and the - state of input control lines indicate that it is possible for - data to be immediately written to the serial line, even though no - data is to be written. This functionality is useful when - determining when serial devices come on line, and checking that - the output buffer is empty (if the KConfigWriteBufferedComplete - bit is set). - -*/ -qint64 SymbianSerialPortEngine::write(const char *data, qint64 len) -{ - TPtrC8 buffer((TUint8*)data, (int)len); - TRequestStatus status; - m_descriptor.Write(status, buffer); - User::WaitForRequest(status); - TInt err = status.Int(); - - if (err != KErrNone) { - m_parent->setError(SerialPort::IoError); - len = -1; - } - // FIXME: How to get the actual number of bytes written? - return qint64(len); -} - -/*! - -*/ -bool SymbianSerialPortEngine::select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) -{ - - // FIXME: I'm not sure in implementation this method. - // Someone needs to check and correct. - - TRequestStatus timerStatus; - TRequestStatus readStatus; - TRequestStatus writeStatus; - - if (timeout > 0) { - if (!m_selectTimer.Handle()) { - if (m_selectTimer.CreateLocal() != KErrNone) - return false; - } - m_selectTimer.HighRes(timerStatus, timeout * 1000); - } - - if (checkRead) - m_descriptor.NotifyDataAvailable(readStatus); - - if (checkWrite) - m_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 { - m_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) - m_descriptor.NotifyDataAvailableCancel(); - if (checkWrite) - m_descriptor.NotifyOutputEmptyCancel(); - - result = true; - } - return result; -} - -//static const QString defaultPathPostfix = ":"; - -/*! - Converts a platform specific \a port name to system location - and return result. - - Does not do anything because These concepts are equivalent. -*/ -QString SymbianSerialPortEngine::toSystemLocation(const QString &port) const -{ - // Port name is equval to port location. - return port; -} - -/*! - Converts a platform specific system \a location to port name - and return result. - - Does not do anything because These concepts are equivalent. -*/ -QString SymbianSerialPortEngine::fromSystemLocation(const QString &location) const -{ - // Port name is equval to port location. - return location; -} - -/*! - Set desired \a rate by given direction \a dir. - However, Symbian does not support separate directions, so the - method will return an error. Also it supports only the standard - set of speed. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) -{ - if (dir != SerialPort::AllDirections) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - switch (rate) { - case 50: - m_currSettings().iRate = EBps50; - break; - case 75: - m_currSettings().iRate = EBps75; - break; - case 110: - m_currSettings().iRate = EBps110; - break; - case 134: - m_currSettings().iRate = EBps134; - break; - case 150: - m_currSettings().iRate = EBps150; - break; - case 300: - m_currSettings().iRate = EBps300; - break; - case 600: - m_currSettings().iRate = EBps600; - break; - case 1200: - m_currSettings().iRate = EBps1200; - break; - case 1800: - m_currSettings().iRate = EBps1800; - break; - case 2000: - m_currSettings().iRate = EBps2000; - break; - case 2400: - m_currSettings().iRate = EBps2400; - break; - case 3600: - m_currSettings().iRate = EBps3600; - break; - case 4800: - m_currSettings().iRate = EBps4800; - break; - case 7200: - m_currSettings().iRate = EBps7200; - break; - case 9600: - m_currSettings().iRate = EBps9600; - break; - case 19200: - m_currSettings().iRate = EBps19200; - break; - case 38400: - m_currSettings().iRate = EBps38400; - break; - case 57600: - m_currSettings().iRate = EBps57600; - break; - case 115200: - m_currSettings().iRate = EBps115200; - break; - case 230400: - m_currSettings().iRate = EBps230400; - break; - case 460800: - m_currSettings().iRate = EBps460800; - break; - case 576000: - m_currSettings().iRate = EBps576000; - break; - case 1152000: - m_currSettings().iRate = EBps1152000; - break; - case 4000000: - m_currSettings().iRate = EBps4000000; - break; - case 921600: - m_currSettings().iRate = EBps921600; - break; - //case 1843200:; // Only for Symbian SR1 - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - return updateCommConfig(); -} - -/*! - Set desired number of data bits \a dataBits in byte. Symbian - native supported all present number of data bits 5, 6, 7, 8. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) -{ - switch (dataBits) { - case SerialPort::Data5: - m_currSettings().iDataBits = EData5; - break; - case SerialPort::Data6: - m_currSettings().iDataBits = EData6; - break; - case SerialPort::Data7: - m_currSettings().iDataBits = EData7; - break; - case SerialPort::Data8: - m_currSettings().iDataBits = EData8; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - return updateCommConfig(); -} - -/*! - Set desired \a parity control mode. Symbian native supported - all present parity types no parity, space, mark, even, odd. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::setParity(SerialPort::Parity parity) -{ - switch (parity) { - case SerialPort::NoParity: - m_currSettings().iParity = EParityNone; - break; - case SerialPort::EvenParity: - m_currSettings().iParity = EParityEven; - break; - case SerialPort::OddParity: - m_currSettings().iParity = EParityOdd; - break; - case SerialPort::MarkParity: - m_currSettings().iParity = EParityMark; - break; - case SerialPort::SpaceParity: - m_currSettings().iParity = EParitySpace; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - return updateCommConfig(); -} - -/*! - Set desired number of stop bits \a stopBits in frame. Symbian - native supported only 1, 2 number of stop bits. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) -{ - switch (stopBits) { - case SerialPort::OneStop: - m_currSettings().iStopBits = EStop1; - break; - case SerialPort::TwoStop: - m_currSettings().iStopBits = EStop2; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - return updateCommConfig(); -} - -/*! - Set desired \a flow control mode. Symbian native supported all - present flow control modes no control, hardware (RTS/CTS), - software (XON/XOFF). - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool SymbianSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) -{ - switch (flow) { - case SerialPort::NoFlowControl: - m_currSettings().iHandshake = KConfigFailDSR; - break; - case SerialPort::HardwareControl: - m_currSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS; - break; - case SerialPort::SoftwareControl: - m_currSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - - return updateCommConfig(); -} - -/*! - -*/ -bool SymbianSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) -{ - Q_UNUSED(policy) - // Impl me - return true; -} - -/*! - -*/ -bool SymbianSerialPortEngine::isReadNotificationEnabled() const -{ - // Impl me - return false; -} - -/*! - -*/ -void SymbianSerialPortEngine::setReadNotificationEnabled(bool enable) -{ - Q_UNUSED(enable) - // Impl me -} - -/*! - -*/ -bool SymbianSerialPortEngine::isWriteNotificationEnabled() const -{ - // Impl me - return false; -} - -/*! - -*/ -void SymbianSerialPortEngine::setWriteNotificationEnabled(bool enable) -{ - Q_UNUSED(enable) - // Impl me -} - -/*! - -*/ -bool SymbianSerialPortEngine::processIOErrors() -{ - // Impl me - return false; -} - -/// - -/* Protected methods */ - -/*! - Attempts to determine the current settings of the serial port, - wehn it opened. Used only in the method open(). -*/ -void SymbianSerialPortEngine::detectDefaultSettings() -{ - // Detect rate. - switch (m_currSettings().iRate) { - case EBps50: - m_parent->m_inRate = 50; - break; - case EBps75: - m_parent->m_inRate = 75; - break; - case EBps110: - m_parent->m_inRate = 110; - break; - case EBps134: - m_parent->m_inRate = 134; - break; - case EBps150: - m_parent->m_inRate = 150; - break; - case EBps300: - m_parent->m_inRate = 300; - break; - case EBps600: - m_parent->m_inRate = 600; - break; - case EBps1200: - m_parent->m_inRate = 1200; - break; - case EBps1800: - m_parent->m_inRate = 1800; - break; - case EBps2000: - m_parent->m_inRate = 2000; - break; - case EBps2400: - m_parent->m_inRate = 2400; - break; - case EBps3600: - m_parent->m_inRate = 3600; - break; - case EBps4800: - m_parent->m_inRate = 4800; - break; - case EBps7200: - m_parent->m_inRate = 7200; - break; - case EBps9600: - m_parent->m_inRate = 9600; - break; - case EBps19200: - m_parent->m_inRate = 19200; - break; - case EBps38400: - m_parent->m_inRate = 38400; - break; - case EBps57600: - m_parent->m_inRate = 57600; - break; - case EBps115200: - m_parent->m_inRate = 115200; - break; - case EBps230400: - m_parent->m_inRate = 230400; - break; - case EBps460800: - m_parent->m_inRate = 460800; - break; - case EBps576000: - m_parent->m_inRate = 576000; - break; - case EBps1152000: - m_parent->m_inRate = 1152000; - break; - case EBps4000000: - m_parent->m_inRate = 4000000; - break; - case EBps921600: - m_parent->m_inRate = 921600; - break; - //case EBps1843200: m_inRate = 1843200; break; - default: - m_parent->m_inRate = SerialPort::UnknownRate; - } - m_parent->m_outRate = m_parent->m_inRate; - - // Detect databits. - switch (m_currSettings().iDataBits) { - case EData5: - m_parent->m_dataBits = SerialPort::Data5; - break; - case EData6: - m_parent->m_dataBits = SerialPort::Data6; - break; - case EData7: - m_parent->m_dataBits = SerialPort::Data7; - break; - case EData8: - m_parent->m_dataBits = SerialPort::Data8; - break; - default: - m_parent->m_dataBits = SerialPort::UnknownDataBits; - } - - // Detect parity. - switch (m_currSettings().iParity) { - case EParityNone: - m_parent->m_parity = SerialPort::NoParity; - break; - case EParityEven: - m_parent->m_parity = SerialPort::EvenParity; - break; - case EParityOdd: - m_parent->m_parity = SerialPort::OddParity; - break; - case EParityMark: - m_parent->m_parity = SerialPort::MarkParity; - break; - case EParitySpace: - m_parent->m_parity = SerialPort::SpaceParity; - break; - default: - m_parent->m_parity = SerialPort::UnknownParity; - } - - // Detect stopbits. - switch (m_currSettings().iStopBits) { - case EStop1: - m_parent->m_stopBits = SerialPort::OneStop; - break; - case EStop2: - m_parent->m_stopBits = SerialPort::TwoStop; - break; - default: - m_parent->m_stopBits = SerialPort::UnknownStopBits; - } - - // Detect flow control. - if ((m_currSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff)) - == (KConfigObeyXoff | KConfigSendXoff)) - m_parent->m_flow = SerialPort::SoftwareControl; - else if ((m_currSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS)) - == (KConfigObeyCTS | KConfigFreeRTS)) - m_parent->m_flow = SerialPort::HardwareControl; - else if (m_currSettings().iHandshake & KConfigFailDSR) - m_parent->m_flow = SerialPort::NoFlowControl; - else - m_parent->m_flow = SerialPort::UnknownFlowControl; -} - -/* Private methods */ - -/*! - Updates the TCommConfig structure wehn changing of any the - parameters a serial port. - - If successful, returns true; otherwise false. -*/ -bool SymbianSerialPortEngine::updateCommConfig() -{ - if (m_descriptor.SetConfig(m_currSettings) != KErrNone) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return true; -} - -// From -SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) -{ - return new SymbianSerialPortEngine(parent); -} - - - - diff --git a/src/serialportengine_p_symbian.h b/src/serialportengine_p_symbian.h deleted file mode 100644 index 69f5ec4..0000000 --- a/src/serialportengine_p_symbian.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - License... -*/ - -#ifndef SERIALPORTENGINE_P_SYMBIAN_H -#define SERIALPORTENGINE_P_SYMBIAN_H - -#include "serialport.h" -#include "serialportengine_p.h" - -#include - -QT_BEGIN_NAMESPACE - -class SymbianSerialPortEngine : public QObject, public SerialPortEngine -{ - Q_OBJECT -public: - SymbianSerialPortEngine(SerialPortPrivate *parent); - virtual ~SymbianSerialPortEngine(); - - virtual bool open(const QString &location, QIODevice::OpenMode mode); - virtual void close(const QString &location); - - virtual SerialPort::Lines lines() const; - - virtual bool setDtr(bool set); - virtual bool setRts(bool set); - - virtual bool flush(); - virtual bool reset(); - - virtual bool sendBreak(int duration); - virtual bool setBreak(bool set); - - virtual qint64 bytesAvailable() const; - virtual qint64 bytesToWrite() const; - - virtual qint64 read(char *data, qint64 len); - virtual qint64 write(const char *data, qint64 len); - virtual bool select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite); - - virtual QString toSystemLocation(const QString &port) const; - virtual QString fromSystemLocation(const QString &location) const; - - virtual bool setRate(qint32 rate, SerialPort::Directions dir); - virtual bool setDataBits(SerialPort::DataBits dataBits); - virtual bool setParity(SerialPort::Parity parity); - virtual bool setStopBits(SerialPort::StopBits stopBits); - virtual bool setFlowControl(SerialPort::FlowControl flowControl); - - virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); - - virtual bool isReadNotificationEnabled() const; - virtual void setReadNotificationEnabled(bool enable); - virtual bool isWriteNotificationEnabled() const; - virtual void setWriteNotificationEnabled(bool enable); - - virtual bool processIOErrors(); - -protected: - virtual void detectDefaultSettings(); - //virtual bool eventFilter(QObject *obj, QEvent *e); - -private: - TCommConfig m_currSettings; - TCommConfig m_oldSettings; - RComm m_descriptor; - mutable RTimer m_selectTimer; - - bool updateCommConfig(); -}; - -QT_END_NAMESPACE - -#endif // SERIALPORTENGINE_P_SYMBIAN_H diff --git a/src/serialportengine_p_unix.cpp b/src/serialportengine_p_unix.cpp deleted file mode 100644 index bc37900..0000000 --- a/src/serialportengine_p_unix.cpp +++ /dev/null @@ -1,1474 +0,0 @@ -/* - License... -*/ - -/*! - \class UnixSerialPortEngine - \internal - - \brief The UnixSerialPortEngine class provides *nix OS - platform-specific low level access to a serial port. - - \reentrant - \ingroup serial - \inmodule QSerialDevice - - Currently the class supports all POSIX-compatible OS (GNU/Linux, *BSD, - Mac OSX and etc). - - UnixSerialPortEngine (as well as other platform-dependent engines) - is a class with multiple inheritance, which on the one hand, - derives from a general abstract class interface SerialPortEngine, - on the other hand of a class inherited from QObject. - - From the abstract class SerialPortEngine, it inherits all virtual - interface methods that are common to all serial ports on any platform. - These methods, the class UnixSerialPortEngine implements use - POSIX ABI. - - From QObject-like class, it inherits a specific system Qt features. - For example, to track of events from a serial port uses the virtual - QObject method eventFilter(), who the make analysis of the events - from the type classes QSocketNotifier. - - That is, as seen from the above, the functional UnixSerialPortEngine - completely covers all the necessary tasks. -*/ - -#include "serialportengine_p_unix.h" -#include "ttylocker_p_unix.h" - -#include -#include -#include -#include - -#if defined (Q_OS_LINUX) -# include -#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) -# include -# endif -#endif - -#include -#include -#include - -QT_USE_NAMESPACE - -/* Public methods */ - -/*! - Constructs a UnixSerialPortEngine with \a parent and - initializes all the internal variables of the initial values. - - A pointer \a parent to the object class SerialPortPrivate - is required for the recursive call some of its methods. -*/ -UnixSerialPortEngine::UnixSerialPortEngine(SerialPortPrivate *parent) - : m_descriptor(-1) - , m_readNotifier(0) - , m_writeNotifier(0) - , m_exceptionNotifier(0) -{ - Q_ASSERT(parent); - m_parent = parent; - int size = sizeof(struct termios); - ::memset(&m_currTermios, 0, size); - ::memset(&m_oldTermios, 0, size); -} - -/*! - Stops the tracking events of the serial port and - destructs a UnixSerialPortEngine. -*/ -UnixSerialPortEngine::~UnixSerialPortEngine() -{ - if (m_readNotifier) - m_readNotifier->setEnabled(false); - if (m_writeNotifier) - m_writeNotifier->setEnabled(false); - if (m_exceptionNotifier) - m_exceptionNotifier->setEnabled(false); -} - -/*! - Tries to open the descriptor desired serial port by \a location - in the given open \a mode. - - Before the opening of the serial port, checking for on exists the - appropriate lock the file and the information therein. If the - lock file is present, and the information contained in it is - relevant - it is concluded that the current serial port is - already occupied. - - In the process of discovery, always set a serial port in - non-blocking mode (when the read operation returns immediately) - and tries to determine its current configuration and install them. - - Since the port in the POSIX OS by default opens in shared mode, - then this method forcibly puts a port in exclusive mode access. - This is done simultaneously in two ways: - - set to the pre-open descriptor a flag TIOCEXCL - - creates a lock file, which writes the pid of the process, that - opened the port and other information - - Need to use two methods due to the fact that on some platforms can - not be defined constant TIOCEXCL, in this case, try to use the - lock file. Creation and analysis of lock file, by using a special - helper class TTYLocker. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) -{ - // First, here need check locked device or not. - bool byCurrPid = false; - if (TTYLocker::isLocked(location, &byCurrPid)) { - m_parent->setError(SerialPort::PermissionDeniedError); - return false; - } - - int flags = (O_NOCTTY | O_NDELAY); - - switch (mode & QIODevice::ReadWrite) { - case QIODevice::WriteOnly: - flags |= O_WRONLY; - break; - case QIODevice::ReadWrite: - flags |= O_RDWR; - break; - default: - flags |= O_RDONLY; - break; - } - - // Try opened serial device. - m_descriptor = ::open(location.toLocal8Bit().constData(), flags); - - if (m_descriptor == -1) { - switch (errno) { - case ENODEV: - m_parent->setError(SerialPort::NoSuchDeviceError); - break; - case EACCES: - m_parent->setError(SerialPort::PermissionDeniedError); - break; - default: - m_parent->setError(SerialPort::UnknownPortError); - } - return false; - } - - // Try lock device by location and check it state is locked. - TTYLocker::lock(location); - if (!TTYLocker::isLocked(location, &byCurrPid)) { - m_parent->setError(SerialPort::PermissionDeniedError); - return false; - } - - // Try set exclusive mode. -#if defined (TIOCEXCL) - ::ioctl(m_descriptor, TIOCEXCL); -#endif - - // Save current port settings. - if (::tcgetattr(m_descriptor, &m_oldTermios) == -1) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - ::memcpy(&m_currTermios, &m_oldTermios, sizeof(struct termios)); - - // Set other options. - ::cfmakeraw(&m_currTermios); - m_currTermios.c_cflag |= (CREAD | CLOCAL); - m_currTermios.c_cc[VTIME] = 0; - - // Apply new init settings. - if (!updateTermios()) - return false; - - detectDefaultSettings(); - return true; -} - -/*! - Closes a serial port descriptor. Before closing - clears exclusive - access flag and removes the lock file, restore previous serial port - settings if necessary. -*/ -void UnixSerialPortEngine::close(const QString &location) -{ - // Restore saved port settings. - if (m_parent->m_restoreSettingsOnClose) - ::tcsetattr(m_descriptor, TCSANOW, &m_oldTermios); - - // Try clean exclusive mode. -#if defined (TIOCNXCL) - ::ioctl(m_descriptor, TIOCNXCL); -#endif - - ::close(m_descriptor); - - // Try unlock device by location. - bool byCurrPid = false; - if (TTYLocker::isLocked(location, &byCurrPid) && byCurrPid) - TTYLocker::unlock(location); - - m_descriptor = -1; -} - -/*! - Returns a bitmap state of RS-232 line signals. On error, - bitmap will be empty (equal zero). - - POSIX ABI allows you to receive all the state of signals: - LE, DTR, RTS, ST, SR, CTS, DCD, RING, DSR. Of course, if the - corresponding constants are defined in a particular platform. -*/ -SerialPort::Lines UnixSerialPortEngine::lines() const -{ - int arg = 0; - SerialPort::Lines ret = 0; - - if (::ioctl(m_descriptor, TIOCMGET, &arg) == -1) { - // Print error? - return ret; - } - -#if defined (TIOCM_LE) - if (arg & TIOCM_LE) ret |= SerialPort::Le; -#endif -#if defined (TIOCM_DTR) - if (arg & TIOCM_DTR) ret |= SerialPort::Dtr; -#endif -#if defined (TIOCM_RTS) - if (arg & TIOCM_RTS) ret |= SerialPort::Rts; -#endif -#if defined (TIOCM_ST) - if (arg & TIOCM_ST) ret |= SerialPort::St; -#endif -#if defined (TIOCM_SR) - if (arg & TIOCM_SR) ret |= SerialPort::Sr; -#endif -#if defined (TIOCM_CTS) - if (arg & TIOCM_CTS) ret |= SerialPort::Cts; -#endif - -#if defined (TIOCM_CAR) - if (arg & TIOCM_CAR) ret |= SerialPort::Dcd; -#elif defined (TIOCM_CD) - if (arg & TIOCM_CD) ret |= SerialPort::Dcd; -#endif - -#if defined (TIOCM_RNG) - if (arg & TIOCM_RNG) ret |= SerialPort::Ri; -#elif defined (TIOCM_RI) - if (arg & TIOCM_RI) ret |= SerialPort::Ri; -#endif - -#if defined (TIOCM_DSR) - if (arg & TIOCM_DSR) ret |= SerialPort::Dsr; -#endif - - return ret; -} - -// -static bool trigger_out_line(int fd, int bit, bool set) -{ - int arg = 0; - bool ret = (::ioctl(fd, TIOCMGET, &arg) != -1); - - if (ret) { - int tmp = arg & bit; - - // If line already installed, then it no need change. - if ((tmp && set) || (!(tmp || set))) - return true; - - if (set) - arg |= bit; - else - arg &= (~bit); - - ret = (::ioctl(fd, TIOCMSET, &arg) != -1); - } - return ret; -} - -/*! - Set DTR signal to state \a set. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::setDtr(bool set) -{ - bool ret = trigger_out_line(m_descriptor, TIOCM_DTR, set); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - Set RTS signal to state \a set. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::setRts(bool set) -{ - bool ret = trigger_out_line(m_descriptor, TIOCM_RTS, set); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - The shall block until all data output written to the serial - port is transmitted. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::flush() -{ - bool ret = (::tcdrain(m_descriptor) != -1); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - Flushes both data received but not read and data written - but not transmitted. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::reset() -{ - bool ret = (::tcflush(m_descriptor, TCIOFLUSH) != -1); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - Send a break for a specific \a duration. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::sendBreak(int duration) -{ - bool ret = (::tcsendbreak(m_descriptor, duration) != -1); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - Turn break on or off, that is, start or stop sending zero - bits, depending on the parameter \a set. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::setBreak(bool set) -{ - bool ret = (::ioctl(m_descriptor, set ? TIOCSBRK : TIOCCBRK) != -1); - if (!ret) { - // FIXME: Here need call errno - // and set error type. - } - return ret; -} - -/*! - If successful, returns the number of bytes that are - immediately available for reading; otherwise -1. -*/ -qint64 UnixSerialPortEngine::bytesAvailable() const -{ - int cmd = 0; -#if defined (FIONREAD) - cmd = FIONREAD; -#else - cmd = TIOCINQ; -#endif - qint64 nbytes = 0; - if (::ioctl(m_descriptor, cmd, &nbytes) == -1) - return -1; - return nbytes; -} - -/*! - Not supported on POSIX-compatible platform, - always returns 0. -*/ -qint64 UnixSerialPortEngine::bytesToWrite() const -{ - // FIXME: FIONWRITE (or analogy) is exists? - return 0; -} - -/*! - If successful, returns to the external buffer \a data the - real number of bytes read, which can be less than the - requested \a len; otherwise returned -1 with set error code. - In any case, reading function returns immediately. - - Some platforms do not support the mark or space parity, so - running software emulation of these modes in the process of - reading. - - Also, this method processed the policy of operating with the - received symbol, in which the parity or frame error is detected. -*/ -qint64 UnixSerialPortEngine::read(char *data, qint64 len) -{ - qint64 bytesRead = 0; -#if defined (CMSPAR) - if ((m_parent->m_parity == SerialPort::NoParity) || (m_parent->m_policy != SerialPort::StopReceivingPolicy)) -#else - if ((m_parent->m_parity != SerialPort::MarkParity) && (m_parent->m_parity != SerialPort::SpaceParity)) -#endif - bytesRead = ::read(m_descriptor, data, len); - else // Perform parity emulation. - bytesRead = readPerChar(data, len); - - // 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; -#if defined (Q_OS_SYMBIAN) - case EPIPE: -#endif - case ECONNRESET: -#if defined (Q_OS_VXWORKS) - case ESHUTDOWN: -#endif - bytesRead = 0; - break; - default:; - } - // FIXME: Here need call errno - // and set error type? - if (bytesRead == -1) - m_parent->setError(SerialPort::IoError); - } - return bytesRead; -} - -/*! - Write \a data to serial port. If successful, returns the - real number of bytes write, which can be less than the - requested \a len; otherwise returned -1 with set error code. - - Some platforms do not support the mark or space parity, so - running software emulation of these modes in the process of - writting. -*/ -qint64 UnixSerialPortEngine::write(const char *data, qint64 len) -{ - qint64 bytesWritten = 0; -#if defined (CMSPAR) - bytesWritten = ::write(m_descriptor, data, len); -#else - if ((m_parent->m_parity != SerialPort::MarkParity) && (m_parent->m_parity != SerialPort::SpaceParity)) - bytesWritten = ::write(m_descriptor, data, len); - else // Perform parity emulation. - bytesWritten = writePerChar(data, len); -#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:; - } - // FIXME: Here need call errno - // and set error type? - if (bytesWritten == -1) - m_parent->setError(SerialPort::IoError); - } - return bytesWritten; -} - -/*! - Implements a function blocking for waiting of events on the - \a timeout in millisecond, those listed in fdread will be watched - to see if characters become available for reading (more precisely, - to see if a read will not block; in particular, a file descriptor - is also ready on end-of-file), those in fdwrite will be watched - to see if a write will not block. - - Event fdread controlled, if the flag \a checkRead is set on true, - and fdwrite wehn flag \a checkWrite is set on true. The result - of catch in each of the events, save to the corresponding - variables \a selectForRead and \a selectForWrite. - - Returns true if the occurrence of any event before the timeout; - otherwise returns false. -*/ -bool UnixSerialPortEngine::select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) -{ - fd_set fdread; - FD_ZERO(&fdread); - if (checkRead) - FD_SET(m_descriptor, &fdread); - - fd_set fdwrite; - FD_ZERO(&fdwrite); - if (checkWrite) - FD_SET(m_descriptor, &fdwrite); - - struct timeval tv; - tv.tv_sec = (timeout / 1000); - tv.tv_usec = (timeout % 1000) * 1000; - - if (::select(m_descriptor + 1, &fdread, &fdwrite, 0, (timeout < 0) ? 0 : &tv) <= 0) { - Q_ASSERT(selectForRead); - *selectForRead = false; - Q_ASSERT(selectForWrite); - *selectForWrite = false; - return false; - } - - if (checkRead) { - Q_ASSERT(selectForRead); - *selectForRead = FD_ISSET(m_descriptor, &fdread); - } - - if (checkWrite) { - Q_ASSERT(selectForWrite); - *selectForWrite = FD_ISSET(m_descriptor, &fdwrite); - } - return true; -} - -#if defined (Q_OS_MAC) -static const QString defaultPathPrefix = "/dev/cu."; -static const QString notUsedPathPrefix = "/dev/tty."; -#else -static const QString defaultPathPrefix = "/dev/"; -#endif - -/*! - Converts a platform specific \a port name to system location - and return result. -*/ -QString UnixSerialPortEngine::toSystemLocation(const QString &port) const -{ - QString ret = port; - -#if defined (Q_OS_MAC) - ret.remove(notUsedPathPrefix); -#endif - - if (!ret.contains(defaultPathPrefix)) - ret.prepend(defaultPathPrefix); - return ret; -} - -/*! - Converts a platform specific system \a location to port name - and return result. -*/ -QString UnixSerialPortEngine::fromSystemLocation(const QString &location) const -{ - QString ret = location; - -#if defined (Q_OS_MAC) - ret.remove(notUsedPathPrefix); -#endif - - ret.remove(defaultPathPrefix); - return ret; -} - -// Returned -1 if rate it is custom baud -// otherwise returned unix speed as speed_t. -static qint32 detect_standard_rate(qint32 rate) -{ - switch (rate) { -#if defined (B0) - case 0: - return B0; -#endif -#if defined (B50) - case 50: - return B50; -#endif -#if defined (B75) - case 75: - return B75; -#endif -#if defined (B110) - case 110: - return B110; -#endif -#if defined (B134) - case 134: - return B134; -#endif -#if defined (B150) - case 150: - return B150; -#endif -#if defined (B200) - case 200: - return B200; -#endif -#if defined (B300) - case 300: - return B300; -#endif -#if defined (B600) - case 600: - return B600; -#endif -#if defined (B1200) - case 1200: - return B1200; -#endif -#if defined (B1800) - case 1800: - return B1800; -#endif -#if defined (B2400) - case 2400: - return B2400; -#endif -#if defined (B4800) - case 4800: - return B4800; -#endif -#if defined (B9600) - case 9600: - return B9600; -#endif -#if defined (B19200) - case 19200: - return B19200; -#endif -#if defined (B38400) - case 38400: - return B38400; -#endif -#if defined (B57600) - case 57600: - return B57600; -#endif -#if defined (B115200) - case 115200: - return B115200; -#endif -#if defined (B230400) - case 230400: - return B230400; -#endif -#if defined (B460800) - case 460800: - return B460800; -#endif -#if defined (B500000) - case 500000: - return B500000; -#endif -#if defined (B576000) - case 576000: - return B576000; -#endif -#if defined (B921600) - case 921600: - return B921600; -#endif -#if defined (B1000000) - case 1000000: - return B1000000; -#endif -#if defined (B1152000) - case 1152000: - return B1152000; -#endif -#if defined (B1500000) - case 1500000: - return B1500000; -#endif -#if defined (B2000000) - case 2000000: - return B2000000; -#endif -#if defined (B2500000) - case 2500000: - return B2500000; -#endif -#if defined (B3000000) - case 3000000: - return B3000000; -#endif -#if defined (B3500000) - case 3500000: - return B3500000; -#endif -#if defined (B4000000) - case 4000000: - return B4000000; -#endif - default: - return -1; - } -} - -/*! - Set desired \a rate by given direction \a dir, - where \a rate is expressed by any positive integer type qint32. - The method attempts to analyze the type of the desired speed: - standard or custom, and the results of the analysis trying to - install it using the corresponding internal function - setCustomRate() or setStandartRate(). - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) -{ - qint32 detectedRate = detect_standard_rate(rate); - bool ret = false; - if (detectedRate == -1) - ret = setCustomRate(rate); - else - ret = setStandartRate(dir, detectedRate); - - if (!ret) - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return ret; -} - -/*! - Set desired number of data bits \a dataBits in byte. POSIX - native supported all present number of data bits 5, 6, 7, 8. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) -{ - m_currTermios.c_cflag &= (~CSIZE); - switch (dataBits) { - case SerialPort::Data5: - m_currTermios.c_cflag |= CS5; - break; - case SerialPort::Data6: - m_currTermios.c_cflag |= CS6; - break; - case SerialPort::Data7: - m_currTermios.c_cflag |= CS7; - break; - case SerialPort::Data8: - m_currTermios.c_cflag |= CS8; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateTermios(); -} - -/*! - Set desired \a parity control mode. POSIX native not supported - modes mark and space, so is their software emulation in the - methods read() and write(). But, in particular, some GNU/Linux - has hardware support for these modes, therefore, no need to - emulate. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::setParity(SerialPort::Parity parity) -{ - m_currTermios.c_iflag &= ~(PARMRK | INPCK); - m_currTermios.c_iflag |= IGNPAR; - - switch (parity) { - -#if defined (CMSPAR) - // Here Installation parity only for GNU/Linux where the macro CMSPAR. - case SerialPort::SpaceParity: - m_currTermios.c_cflag &= (~PARODD); - m_currTermios.c_cflag |= (PARENB | CMSPAR); - break; - case SerialPort::MarkParity: - m_currTermios.c_cflag |= (PARENB | CMSPAR | PARODD); - break; -#endif - case SerialPort::NoParity: - m_currTermios.c_cflag &= (~PARENB); - break; - case SerialPort::EvenParity: - m_currTermios.c_cflag &= (~PARODD); - m_currTermios.c_cflag |= PARENB; - break; - case SerialPort::OddParity: - m_currTermios.c_cflag |= (PARENB | PARODD); - break; - default: - m_currTermios.c_cflag |= PARENB; - m_currTermios.c_iflag |= (PARMRK | INPCK); - m_currTermios.c_iflag &= ~IGNPAR; - break; - } - - return updateTermios(); -} - -/*! - Set desired number of stop bits \a stopBits in frame. POSIX - native supported only 1, 2 number of stop bits. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) -{ - switch (stopBits) { - case SerialPort::OneStop: - m_currTermios.c_cflag &= (~CSTOPB); - break; - case SerialPort::TwoStop: - m_currTermios.c_cflag |= CSTOPB; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateTermios(); -} - -/*! - Set desired \a flow control mode. POSIX native supported all - present flow control modes no control, hardware (RTS/CTS), - software (XON/XOFF). - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool UnixSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) -{ - switch (flow) { - case SerialPort::NoFlowControl: - m_currTermios.c_cflag &= (~CRTSCTS); - m_currTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); - break; - case SerialPort::HardwareControl: - m_currTermios.c_cflag |= CRTSCTS; - m_currTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); - break; - case SerialPort::SoftwareControl: - m_currTermios.c_cflag &= (~CRTSCTS); - m_currTermios.c_iflag |= (IXON | IXOFF | IXANY); - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateTermios(); -} - -/*! - Set desired char error \a policy when errors are detected - frame or parity. -*/ -bool UnixSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) -{ - tcflag_t parmrkMask = PARMRK; -#ifndef CMSPAR - //in space/mark parity emulation also used PARMRK flag - if (m_parent->m_parity == SerialPort::SpaceParity || m_parent->m_parity == SerialPort::MarkParity) - parmrkMask = 0; -#endif //CMSPAR - switch(policy) { - case SerialPort::SkipPolicy: - m_currTermios.c_iflag &= ~parmrkMask; - m_currTermios.c_iflag |= IGNPAR | INPCK; - break; - case SerialPort::PassZeroPolicy: - m_currTermios.c_iflag &= ~(IGNPAR | parmrkMask); - m_currTermios.c_iflag |= INPCK; - break; - case SerialPort::IgnorePolicy: - m_currTermios.c_iflag &= ~INPCK; - break; - case SerialPort::StopReceivingPolicy: - m_currTermios.c_iflag &= ~IGNPAR; - m_currTermios.c_iflag |= (parmrkMask | INPCK); - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateTermios(); -} - -/*! - Returns the current status of the read notification subsystem. -*/ -bool UnixSerialPortEngine::isReadNotificationEnabled() const -{ - return (m_readNotifier && m_readNotifier->isEnabled()); -} - -/*! - Enables or disables read notification subsystem, depending on - the \a enable parameter. If the subsystem is enabled, it will - asynchronously track the occurrence of an event fdread. - Thanks to that, SerialPort can emit a signal readyRead() and - fill up the internal receive buffer with new data, that - automatically received from a serial port in the event loop. -*/ -void UnixSerialPortEngine::setReadNotificationEnabled(bool enable) -{ - if (m_readNotifier) - m_readNotifier->setEnabled(enable); - else if (enable) { - m_readNotifier = - new QSocketNotifier(m_descriptor, QSocketNotifier::Read, this); - - m_readNotifier->installEventFilter(this); - m_readNotifier->setEnabled(true); - } -} - -/*! - Returns the current status of the write notification subsystem. -*/ -bool UnixSerialPortEngine::isWriteNotificationEnabled() const -{ - return (m_writeNotifier && m_writeNotifier->isEnabled()); -} - -/*! - Enables or disables write notification subsystem, depending on - the \a enable parameter. If the subsystem is enabled, it will - asynchronously track the occurrence of an event fdwrite. - Thanks to that, SerialPort can write data from internal transfer - buffer, to serial port automatically in the event loop. -*/ -void UnixSerialPortEngine::setWriteNotificationEnabled(bool enable) -{ - if (m_writeNotifier) - m_writeNotifier->setEnabled(enable); - else if (enable) { - m_writeNotifier = - new QSocketNotifier(m_descriptor, QSocketNotifier::Write, this); - - m_writeNotifier->installEventFilter(this); - m_writeNotifier->setEnabled(true); - } -} - -/*! - Not used in POSIX implementation, error handling is carried - out in other ways. - - Always returned false. -*/ -bool UnixSerialPortEngine::processIOErrors() -{ - // No need impl. - return false; -} - -/// - -/* Protected methods */ - -// Convert unix rate as speed_t to -// really value as qint32. -static qint32 unixrate2valuerate(speed_t unixrate) -{ - qint32 ret = SerialPort::UnknownRate; - - switch (unixrate) { -#if defined (B50) - case B50: - ret = 50; - break; -#endif -#if defined (B75) - case B75: - ret = 75; - break; -#endif -#if defined (B110) - case B110: - ret = 110; - break; -#endif -#if defined (B134) - case B134: - ret = 134; - break; -#endif -#if defined (B150) - case B150: - ret = 150; - break; -#endif -#if defined (B200) - case B200: - ret = 200; - break; -#endif -#if defined (B300) - case B300: - ret = 300; - break; -#endif -#if defined (B600) - case B600: - ret = 600; - break; -#endif -#if defined (B1200) - case B1200: - ret = 1200; - break; -#endif -#if defined (B1800) - case B1800: - ret = 1800; - break; -#endif -#if defined (B2400) - case B2400: - ret = 2400; - break; -#endif -#if defined (B4800) - case B4800: - ret = 4800; - break; -#endif -#if defined (B9600) - case B9600: - ret = 9600; - break; -#endif -#if defined (B19200) - case B19200: - ret = 19200; - break; -#endif -#if defined (B38400) - case B38400: - ret = 38400; - break; -#endif -#if defined (B57600) - case B57600: - ret = 57600; - break; -#endif -#if defined (B115200) - case B115200: - ret = 115200; - break; -#endif -#if defined (B230400) - case B230400: - ret = 230400; - break; -#endif -#if defined (B460800) - case B460800: - ret = 460800; - break; -#endif -#if defined (B500000) - case B500000: - ret = 500000; - break; -#endif -#if defined (B576000) - case B576000: - ret = 576000; - break; -#endif -#if defined (B921600) - case B921600: - ret = 921600; - break; -#endif -#if defined (B1000000) - case B1000000: - ret = 1000000; - break; -#endif -#if defined (B1152000) - case B1152000: - ret = 1152000; - break; -#endif -#if defined (B1500000) - case B1500000: - ret = 1500000; - break; -#endif -#if defined (B2000000) - case B2000000: - ret = 2000000; - break; -#endif -#if defined (B2500000) - case B2500000: - ret = 2500000; - break; -#endif -#if defined (B3000000) - case B3000000: - ret = 3000000; - break; -#endif -#if defined (B3500000) - case B3500000: - ret = 3500000; - break; -#endif -#if defined (B4000000) - case B4000000: - ret = 4000000; - break; -#endif - default:; - } - return ret; -} - -/*! - Attempts to determine the current settings of the serial port, - wehn it opened. Used only in the method open(). -*/ -void UnixSerialPortEngine::detectDefaultSettings() -{ - // Detect rate. - m_parent->m_inRate = unixrate2valuerate(::cfgetispeed(&m_currTermios)); - m_parent->m_outRate = unixrate2valuerate(::cfgetospeed(&m_currTermios)); - - // Detect databits. - switch (m_currTermios.c_cflag & CSIZE) { - case CS5: - m_parent->m_dataBits = SerialPort::Data5; - break; - case CS6: - m_parent->m_dataBits = SerialPort::Data6; - break; - case CS7: - m_parent->m_dataBits = SerialPort::Data7; - break; - case CS8: - m_parent->m_dataBits = SerialPort::Data8; - break; - default: - m_parent->m_dataBits = SerialPort::UnknownDataBits; - } - - // Detect parity. -#if defined (CMSPAR) - if (m_currTermios.c_cflag & CMSPAR) { - m_parent->m_parity = (m_currTermios.c_cflag & PARODD) ? - SerialPort::MarkParity : SerialPort::SpaceParity; - } else { -#endif - if (m_currTermios.c_cflag & PARENB) { - m_parent->m_parity = (m_currTermios.c_cflag & PARODD) ? - SerialPort::OddParity : SerialPort::EvenParity; - } else - m_parent->m_parity = SerialPort::NoParity; -#if defined (CMSPAR) - } -#endif - - // Detect stopbits. - m_parent->m_stopBits = (m_currTermios.c_cflag & CSTOPB) ? - SerialPort::TwoStop : SerialPort::OneStop; - - // Detect flow control. - if ((!(m_currTermios.c_cflag & CRTSCTS)) && (!(m_currTermios.c_iflag & (IXON | IXOFF | IXANY)))) - m_parent->m_flow = SerialPort::NoFlowControl; - else if ((!(m_currTermios.c_cflag & CRTSCTS)) && (m_currTermios.c_iflag & (IXON | IXOFF | IXANY))) - m_parent->m_flow = SerialPort::SoftwareControl; - else if ((m_currTermios.c_cflag & CRTSCTS) && (!(m_currTermios.c_iflag & (IXON | IXOFF | IXANY)))) - m_parent->m_flow = SerialPort::HardwareControl; - else - m_parent->m_flow = SerialPort::UnknownFlowControl; - - //detect error policy - if (m_currTermios.c_iflag & INPCK) { - if (m_currTermios.c_iflag & IGNPAR) - m_parent->m_policy = SerialPort::SkipPolicy; - else if (m_currTermios.c_iflag & PARMRK) - m_parent->m_policy = SerialPort::StopReceivingPolicy; - else - m_parent->m_policy = SerialPort::PassZeroPolicy; - } else { - m_parent->m_policy = SerialPort::IgnorePolicy; - } -} - -/*! - POSIX event loop for notification subsystem. - Asynchronously in event loop continuous mode tracking the - events from the serial port, as: fderror, fdread, fdwrite. - When is occur a relevant event, calls him handler from - a parent class SerialPortPrivate. -*/ -bool UnixSerialPortEngine::eventFilter(QObject *obj, QEvent *e) -{ - if (e->type() == QEvent::SockAct) { - if (obj == m_readNotifier) { - m_parent->canReadNotification(); - return true; - } - if (obj == m_writeNotifier) { - m_parent->canWriteNotification(); - return true; - } - if (obj == m_exceptionNotifier) { - m_parent->canErrorNotification(); - return true; - } - } - return QObject::eventFilter(obj, e); -} - -/* Private methods */ - -/*! - Updates the termios structure wehn changing of any the - parameters a serial port. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::updateTermios() -{ - if (::tcsetattr(m_descriptor, TCSANOW, &m_currTermios) == -1) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return true; -} - -/*! - Set only standard serial port \a rate as speed_t by given - deirection \a dir. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::setStandartRate(SerialPort::Directions dir, speed_t rate) -{ - if (((dir & SerialPort::Input) && (::cfsetispeed(&m_currTermios, rate) == -1)) - || ((dir & SerialPort::Output) && (::cfsetospeed(&m_currTermios, rate) == -1))) { - return false; - } - return updateTermios(); -} - -/*! - Attempts to set desired the custom \a rate as qint32. Not all - POSIX-compatible platforms support this feature, at least for - GNU/Linux and MacOSX is possible. - - If successful, returns true; otherwise false. -*/ -bool UnixSerialPortEngine::setCustomRate(qint32 rate) -{ - int result = -1; -#if defined (Q_OS_LINUX) - -# if defined (TIOCGSERIAL) && defined (TIOCSSERIAL) - if (rate > 0) { - struct serial_struct ser_info; - result = ::ioctl(m_descriptor, TIOCGSERIAL, &ser_info); - if (result != -1) { - ser_info.flags &= ~ASYNC_SPD_MASK; - ser_info.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); - ser_info.custom_divisor = ser_info.baud_base / rate; - if (ser_info.custom_divisor) - result = ::ioctl(m_descriptor, TIOCSSERIAL, &ser_info); - } - } -# endif - -#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. - result = ::ioctl(m_descriptor, IOSSIOSPEED, &rate); -# endif - -#else - Q_UNUSED(rate); -#endif - return (result != -1); -} - -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) -} - -#if !defined (CMSPAR) - -/*! - For platforms that do not have the support of parities mark and space - performed character by character emulation data transmitted, that - one by one character is written to the port. -*/ -qint64 UnixSerialPortEngine::writePerChar(const char *data, qint64 maxSize) -{ - qint64 ret = 0; - quint8 const charMask = (0xFF >> (8 - m_parent->m_dataBits)); - - while (ret < maxSize) { - - bool par = evenParity(*data & charMask); - // False if need EVEN, true if need ODD. - par ^= (m_parent->m_parity == SerialPort::MarkParity); - if (par ^ bool(m_currTermios.c_cflag & PARODD)) { // Need switch parity mode? - m_currTermios.c_cflag ^= PARODD; - flush(); //force sending already buffered data, because updateTermios() cleares buffers - //todo: add receiving buffered data!!! - if (!updateTermios()) - break; - } - - int r = ::write(m_descriptor, data, 1); - if (r < 0) - return -1; - if (r > 0) { - data += r; - ret += r; - } - } - return ret; -} - -#endif //CMSPAR - -/*! - Platforms which does not have the support for mark and space parity checking - requires emulation using character by character data receiving. -*/ -qint64 UnixSerialPortEngine::readPerChar(char *data, qint64 maxSize) -{ - qint64 ret = 0; - quint8 const charMask = (0xFF >> (8 - m_parent->m_dataBits)); - - // 0 - prefix not started, - // 1 - received 0xFF, - // 2 - received 0xFF and 0x00 - int prefix = 0; - while (ret < maxSize) { - - qint64 r = ::read(m_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 ^= bool(m_currTermios.c_cflag & PARODD); //par contains parity bit value for current mode - if (par ^ bool(m_parent->m_parity == SerialPort::SpaceParity)) { //if parity error - switch(m_parent->m_policy) { - case SerialPort::SkipPolicy: - continue; //ignore received character - case SerialPort::StopReceivingPolicy: - if (m_parent->m_parity != SerialPort::NoParity) - m_parent->m_portError = SerialPort::ParityError; - else - m_parent->m_portError = (*data == '\0') ? SerialPort::BreakConditionError : SerialPort::FramingError; - return ++ret; //abort receiving - break; - case SerialPort::UnknownPolicy: - qWarning() << "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; -} - -// From -SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) -{ - return new UnixSerialPortEngine(parent); -} diff --git a/src/serialportengine_p_unix.h b/src/serialportengine_p_unix.h deleted file mode 100644 index e83e84f..0000000 --- a/src/serialportengine_p_unix.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - License... -*/ - -#ifndef SERIALPORTENGINE_P_UNIX_H -#define SERIALPORTENGINE_P_UNIX_H - -#include "serialport.h" -#include "serialportengine_p.h" - -#include -//# undef CMSPAR - -QT_BEGIN_NAMESPACE - -class QSocketNotifier; - -class UnixSerialPortEngine : public QObject, public SerialPortEngine -{ - Q_OBJECT -public: - UnixSerialPortEngine(SerialPortPrivate *parent); - virtual ~UnixSerialPortEngine(); - - virtual bool open(const QString &location, QIODevice::OpenMode mode); - virtual void close(const QString &location); - - virtual SerialPort::Lines lines() const; - - virtual bool setDtr(bool set); - virtual bool setRts(bool set); - - virtual bool flush(); - virtual bool reset(); - - virtual bool sendBreak(int duration); - virtual bool setBreak(bool set); - - virtual qint64 bytesAvailable() const; - virtual qint64 bytesToWrite() const; - - virtual qint64 read(char *data, qint64 len); - virtual qint64 write(const char *data, qint64 len); - virtual bool select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite); - - virtual QString toSystemLocation(const QString &port) const; - virtual QString fromSystemLocation(const QString &location) const; - - virtual bool setRate(qint32 rate, SerialPort::Directions dir); - virtual bool setDataBits(SerialPort::DataBits dataBits); - virtual bool setParity(SerialPort::Parity parity); - virtual bool setStopBits(SerialPort::StopBits stopBits); - virtual bool setFlowControl(SerialPort::FlowControl flowControl); - - virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); - - virtual bool isReadNotificationEnabled() const; - virtual void setReadNotificationEnabled(bool enable); - virtual bool isWriteNotificationEnabled() const; - virtual void setWriteNotificationEnabled(bool enable); - - virtual bool processIOErrors(); - -protected: - virtual void detectDefaultSettings(); - virtual bool eventFilter(QObject *obj, QEvent *e); - -private: - struct termios m_currTermios; - struct termios m_oldTermios; - int m_descriptor; - - QSocketNotifier *m_readNotifier; - QSocketNotifier *m_writeNotifier; - QSocketNotifier *m_exceptionNotifier; - - bool updateTermios(); - bool setStandartRate(SerialPort::Directions dir, speed_t rate); - bool setCustomRate(qint32 rate); - -#if !defined (CMSPAR) - qint64 writePerChar(const char *data, qint64 maxSize); -#endif - qint64 readPerChar(char *data, qint64 maxSize); -}; - -QT_END_NAMESPACE - -#endif // SERIALPORTENGINE_P_UNIX_H diff --git a/src/serialportengine_p_win.cpp b/src/serialportengine_p_win.cpp deleted file mode 100644 index 9790312..0000000 --- a/src/serialportengine_p_win.cpp +++ /dev/null @@ -1,1301 +0,0 @@ -/* - License... -*/ - -/*! - \class WinSerialPortEngine - \internal - - \brief The WinSerialPortEngine class provides windows OS - platform-specific low level access to a serial port. - - \reentrant - \ingroup serial - \inmodule QSerialDevice - - Currently the class supports as NT-based OS (Win 2K/XP/Vista/7), - and as various embedded WinCE. - - WinSerialPortEngine (as well as other platform-dependent engines) - is a class with multiple inheritance, which on the one hand, - derives from a general abstract class interface SerialPortEngine, - on the other hand of a class inherited from QObject. - - From the abstract class SerialPortEngine, it inherits all virtual - interface methods that are common to all serial ports on any platform. - These methods, the class WinSerialPortEngine implements on the OS - Windows platform, using a corresponding Win API. - - From QObject-like class, it inherits a specific system Qt features. - For example, for NT-based platforms WinSerialPortEngine uses private - Qt class QWinEventNotifier. Thanks to this class, it have the - opportunity to asynchronously track the events from the serial port, - such as the appearance of a character in the receive buffer, - error I/O, and etc. Ie events are handled in Qt core in its event - loop, so no need to create additional threads to perform these - operations. However, for embedded systems, this approach does not work, - because they have a another Win API. In this case, WinSerialPortEngine - is derived from QThread and creates an additional thread to keep track - of events. - - That is, as seen from the above, the functional WinSerialPortEngine - completely covers all the necessary tasks. -*/ - -#include "serialportengine_p_win.h" - -#include -#if !defined (Q_OS_WINCE) -# include -#endif -//#include - -#ifndef Q_CC_MSVC -# include -#else - -# 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 - -#endif - -QT_USE_NAMESPACE - -/* Public methods */ - -/*! - Constructs a WinSerialPortEngine with \a parent and - initializes all the internal variables of the initial values. - - A pointer \a parent to the object class SerialPortPrivate - is required for the recursive call some of its methods. -*/ -WinSerialPortEngine::WinSerialPortEngine(SerialPortPrivate *parent) - : m_descriptor(INVALID_HANDLE_VALUE) - , m_flagErrorFromCommEvent(false) - , m_currentMask(0) - , m_setMask(EV_ERR) - #if defined (Q_OS_WINCE) - , m_running(true) - #endif -{ - Q_ASSERT(parent); - m_parent = parent; - size_t size = sizeof(DCB); - ::memset(&m_currDCB, 0, size); - ::memset(&m_oldDCB, 0, size); - size = sizeof(COMMTIMEOUTS); - ::memset(&m_currCommTimeouts, 0, size); - ::memset(&m_oldCommTimeouts, 0, size); - -#if !defined (Q_OS_WINCE) - size = sizeof(OVERLAPPED); - ::memset(&m_ovRead, 0, size); - ::memset(&m_ovWrite, 0, size); - ::memset(&m_ovSelect, 0, size); - ::memset(&m_ov, 0, size); -#endif -} - -/*! - Stops the tracking events of the serial port and - destructs a WinSerialPortEngine. -*/ -WinSerialPortEngine::~WinSerialPortEngine() -{ -#if defined (Q_OS_WINCE) - m_running = false; - ::SetCommMask(m_descriptor, 0); - //terminate(); - wait(); -#else - setEnabled(false); -#endif -} - -/*! - Tries to open the handle desired serial port by \a location in the - given open \a mode. In the process of discovery, always set a - serial port in non-blocking mode (when the read operation returns - immediately) and tries to determine its current configuration and - install them. - - It should be noted the following features that Windows performs - when using the serial port: - - support only binary transfers mode - - always open in exclusive mode - - For Windows NT-based platforms, the serial port is opened in the - overlapped mode, with flag FILE_FLAG_OVERLAPPED. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) -{ - DWORD desiredAccess = 0; - DWORD shareMode = 0; - DWORD flagsAndAttributes = 0; - bool rxflag = false; - bool txflag = false; - -#if !defined (Q_OS_WINCE) - flagsAndAttributes |= FILE_FLAG_OVERLAPPED; -#endif - - if (mode & QIODevice::ReadOnly) { - desiredAccess |= GENERIC_READ; - //shareMode = FILE_SHARE_READ; - rxflag = true; - } - if (mode & QIODevice::WriteOnly) { - desiredAccess |= GENERIC_WRITE; - //shareMode = FILE_SHARE_WRITE; - txflag = true; - } - - QByteArray filePath = QByteArray((const char *)location.utf16(), - location.size() * 2 + 1); - - // Try opened serial device. - m_descriptor = ::CreateFile((const wchar_t*)filePath.constData(), - desiredAccess, shareMode, 0, OPEN_EXISTING, flagsAndAttributes, 0); - - if (m_descriptor == INVALID_HANDLE_VALUE) { - switch (::GetLastError()) { - case ERROR_FILE_NOT_FOUND: - m_parent->setError(SerialPort::NoSuchDeviceError); - break; - case ERROR_ACCESS_DENIED: - m_parent->setError(SerialPort::PermissionDeniedError); - break; - default: - m_parent->setError(SerialPort::UnknownPortError); - } - return false; - } - - // Save current DCB port settings. - DWORD confSize = sizeof(DCB); - if (::GetCommState(m_descriptor, &m_oldDCB) == 0) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - ::memcpy(&m_currDCB, &m_oldDCB, confSize); - - // Set other DCB port options. - m_currDCB.fBinary = true; - m_currDCB.fInX = false; - m_currDCB.fOutX = false; - m_currDCB.fAbortOnError = false; - m_currDCB.fNull = false; - m_currDCB.fErrorChar = false; - - // Apply new DCB init settings. - if (!updateDcb()) - return false; - - // Save current port timeouts. - confSize = sizeof(COMMTIMEOUTS); - if (::GetCommTimeouts(m_descriptor, &m_oldCommTimeouts) == 0) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } - ::memcpy(&m_currCommTimeouts, &m_oldCommTimeouts, confSize); - - // Set new port timeouts. - ::memset(&m_currCommTimeouts, 0, confSize); - m_currCommTimeouts.ReadIntervalTimeout = MAXDWORD; - - // Apply new port timeouts. - if (!updateCommTimeouts()) - return false; - -#if !defined (Q_OS_WINCE) - if (!createEvents(rxflag, txflag)) { - m_parent->setError(SerialPort::UnknownPortError); - return false; - } -#endif - - detectDefaultSettings(); - return true; -} - -/*! - Closes a serial port handle. Before closing - restore previous - serial port settings if necessary. -*/ -void WinSerialPortEngine::close(const QString &location) -{ - Q_UNUSED(location); - -#if !defined (Q_OS_WINCE) - ::CancelIo(m_descriptor); -#endif - - if (m_parent->m_restoreSettingsOnClose) { - ::SetCommState(m_descriptor, &m_oldDCB); - ::SetCommTimeouts(m_descriptor, &m_oldCommTimeouts); - } - - ::CloseHandle(m_descriptor); - -#if !defined (Q_OS_WINCE) - closeEvents(); -#endif - m_descriptor = INVALID_HANDLE_VALUE; -} - -/*! - Returns a bitmap state of RS-232 line signals. On error, - bitmap will be empty (equal zero). - - Win API allows you to receive only the state of signals: - CTS, DSR, RING, DCD, DTR, RTS. Other signals are not available. -*/ -SerialPort::Lines WinSerialPortEngine::lines() const -{ - DWORD modemStat = 0; - SerialPort::Lines ret = 0; - - if (::GetCommModemStatus(m_descriptor, &modemStat) == 0) { - // Print error? - 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(m_descriptor, IOCTL_SERIAL_GET_DTRRTS, 0, 0, - &modemStat, sizeof(DWORD), - &bytesReturned, 0)) { - - if (modemStat & SERIAL_DTR_STATE) - ret |= SerialPort::Dtr; - if (modemStat & SERIAL_RTS_STATE) - ret |= SerialPort::Rts; - } - - return ret; -} - -/*! - Set DTR signal to state \a set. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::setDtr(bool set) -{ - bool ret = ::EscapeCommFunction(m_descriptor, (set) ? SETDTR : CLRDTR); - if (!ret) { - // FIXME: Here need call ::GetLastError() - // and set error type. - } - return ret; -} - -/*! - Set RTS signal to state \a set. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::setRts(bool set) -{ - bool ret = ::EscapeCommFunction(m_descriptor, (set) ? SETRTS : CLRRTS); - if (!ret) { - // FIXME: Here need call ::GetLastError() - // and set error type. - } - return ret; -} - -/*! - Flushes the buffers of a specified serial port and - causes all buffered data to be written to a serial port. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::flush() -{ - bool ret = ::FlushFileBuffers(m_descriptor); - if (!ret) { - // FIXME: Here need call ::GetLastError() - // and set error type. - } - return ret; -} - -/*! - Discards all characters from the output or input buffer of - a specified communications resource. It can also terminate - pending read or write operations on the resource. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::reset() -{ - DWORD flags = (PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); - bool ret = ::PurgeComm(m_descriptor, flags); - if (!ret) { - // FIXME: Here need call ::GetLastError() - // and set error type. - } - return ret; -} - -/*! - Sends a continuous stream of zero bits during a specified - period of time \a duration in msec. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::sendBreak(int duration) -{ - // FIXME: - if (setBreak(true)) { - ::Sleep(duration); - if (setBreak(false)) - return true; - } - return false; -} - -/*! - Restores or suspend character transmission and places the - transmission line in a nonbreak or break state, - depending on the parameter \a set. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::setBreak(bool set) -{ - bool ret = (set) ? - (::SetCommBreak(m_descriptor)) : (::ClearCommBreak(m_descriptor)); - if (!ret) { - // FIXME: Here need call ::GetLastError() - // and set error type. - } - return ret; -} - -enum CommStatQue { CS_IN_QUE, CS_OUT_QUE }; -static qint64 get_commstat_que(HANDLE descriptor, enum CommStatQue que) -{ - DWORD err; - COMSTAT cs; - if (::ClearCommError(descriptor, &err, &cs) == 0) - return -1; - return qint64((que == CS_IN_QUE) ? (cs.cbInQue) : (cs.cbOutQue)); -} - -/*! - Returns the number of bytes received by the serial provider - but not yet read by a read() operation. Also it clears the - device's error flag to enable additional input and output - (I/O) operations. - - If successful, returns true; otherwise false. -*/ -qint64 WinSerialPortEngine::bytesAvailable() const -{ - return get_commstat_que(m_descriptor, CS_IN_QUE); -} - -/*! - Returns the number of bytes of user data remaining to be - transmitted for all write operations. This value will be zero - for a nonoverlapped write (for embedded platform as WinCE). - Also it clears the device's error flag to enable additional - input and output (I/O) operations. - - If successful, returns true; otherwise false. -*/ -qint64 WinSerialPortEngine::bytesToWrite() const -{ - return get_commstat_que(m_descriptor, CS_OUT_QUE); -} - -#if !defined (Q_OS_WINCE) -// Clear overlapped structure, but does not affect the event. -static void clear_overlapped(OVERLAPPED *overlapped) -{ - overlapped->Internal = 0; - overlapped->InternalHigh = 0; - overlapped->Offset = 0; - overlapped->OffsetHigh = 0; -} -#endif - -/*! - Read data from serial port. For NT-based platform, process - data's reading with the waiting wehn of pending I/O - operations is complete. Maybe this can cause some freezes. - - If successful, returns to the external buffer \a data the - real number of bytes read, which can be less than the - requested \a len; otherwise returned -1 with set error code. - - Also, this method processed the policy of operating with the - received symbol, in which the parity or frame error is detected. - This analysis and processing is executed by software-way in - this method. Parity or frame error flag determines subsystem - notification when it receives an event type EV_ERR. Since the - EV_ERR event appears before the event EV_RXCHAR, therefore, - we are able to handle errors by ordered, for each bad charachter - in this read method. This is true only when enabled the internal - read buffer of class SerialPort, ie when it is automatically - filled when the notification mode of reading is enabled. In - other cases, policy processing bad char is not guaranteed. -*/ -qint64 WinSerialPortEngine::read(char *data, qint64 len) -{ -#if !defined (Q_OS_WINCE) - clear_overlapped(&m_ovRead); -#endif - - DWORD readBytes = 0; - bool sucessResult = false; - - // FIXME: - if (m_parent->m_policy != SerialPort::IgnorePolicy) - len = 1; - -#if defined (Q_OS_WINCE) - sucessResult = ::ReadFile(m_descriptor, data, len, &readBytes, 0); -#else - if (::ReadFile(m_descriptor, data, len, &readBytes, &m_ovRead)) - sucessResult = true; - else { - if (::GetLastError() == ERROR_IO_PENDING) { - // FIXME: Instead of an infinite wait I/O (not looped), we expect, for example 5 seconds. - // Although, maybe there is a better solution. - switch (::WaitForSingleObject(m_ovRead.hEvent, 5000)) { - case WAIT_OBJECT_0: - if (::GetOverlappedResult(m_descriptor, &m_ovRead, &readBytes, false)) - sucessResult = true; - break; - default: ; - } - } - } -#endif - - if(!sucessResult) { - m_parent->setError(SerialPort::IoError); - return -1; - } - - // FIXME: Process emulate policy. - if (m_flagErrorFromCommEvent) { - m_flagErrorFromCommEvent = false; - - switch (m_parent->m_policy) { - case SerialPort::SkipPolicy: - return 0; - case SerialPort::PassZeroPolicy: - *data = '\0'; - break; - case SerialPort::StopReceivingPolicy: - break; - default:; - } - } - return qint64(readBytes); -} - -/*! - Write \a data to serial port. For NT-based platform, process - data's writing with the waiting wehn of pending I/O - operations is complete. Maybe this can cause some freezes. - - If successful, returns the real number of bytes write, which - can be less than the requested \a len; otherwise returned -1 - with set error code. -*/ -qint64 WinSerialPortEngine::write(const char *data, qint64 len) -{ -#if !defined (Q_OS_WINCE) - clear_overlapped(&m_ovWrite); -#endif - - DWORD writeBytes = 0; - bool sucessResult = false; - -#if defined (Q_OS_WINCE) - sucessResult = ::WriteFile(m_descriptor, data, len, &writeBytes, 0); -#else - if (::WriteFile(m_descriptor, data, len, &writeBytes, &m_ovWrite)) - sucessResult = true; - else { - if (::GetLastError() == ERROR_IO_PENDING) { - // Instead of an infinite wait I/O (not looped), we expect, for example 5 seconds. - // Although, maybe there is a better solution. - switch (::WaitForSingleObject(m_ovWrite.hEvent, 5000)) { - case WAIT_OBJECT_0: - if (::GetOverlappedResult(m_descriptor, &m_ovWrite, &writeBytes, false)) - sucessResult = true; - break; - default: ; - } - } - } -#endif - - if(!sucessResult) { - m_parent->setError(SerialPort::IoError); - return -1; - } - return quint64(writeBytes); -} - -/*! - Implements a function blocking for waiting of events EV_RXCHAR or - EV_TXEMPTY, on the \a timeout in millisecond. Event EV_RXCHAR - controlled, if the flag \a checkRead is set on true, and - EV_TXEMPTY wehn flag \a checkWrite is set on true. The result - of catch in each of the events, save to the corresponding - variables \a selectForRead and \a selectForWrite. - - For NT-based OS and embedded, this method have different - implementation. WinCE has no mechanism to exit out of a timeout, - therefore for this feature special class is used - WinCeWaitCommEventBreaker, without which it is locked to wait - forever in the absence of events EV_RXCHAR or EV_TXEMPTY. For - satisfactory operation of the breaker, the timeout should be - guaranteed a great, to the timer in the breaker does not trip - happen sooner than a function call WaitCommEvent(); otherwise it - will block forever (in the absence of events EV_RXCHAR or EV_TXEMPTY). - - Returns true if the occurrence of any event before the timeout; - otherwise returns false. -*/ -bool WinSerialPortEngine::select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) -{ - // Forward checking data for read. - if (checkRead && (bytesAvailable() > 0)) { - Q_ASSERT(selectForRead); - *selectForRead = true; - return true; - } - -#if !defined (Q_OS_WINCE) - clear_overlapped(&m_ovSelect); -#endif - - DWORD oldEventMask = 0; - DWORD currEventMask = 0; - - if (checkRead) - currEventMask |= EV_RXCHAR; - if (checkWrite) - currEventMask |= EV_TXEMPTY; - - // Save old mask. - if (::GetCommMask(m_descriptor, &oldEventMask) == 0) { - //Print error? - return false; - } - - // Checking the old mask bits as in the current mask. - // And if these bits are not exists, then add them and set the reting mask. - if (currEventMask != (oldEventMask & currEventMask)) { - currEventMask |= oldEventMask; - if (::SetCommMask(m_descriptor, currEventMask) == 0) { - //Print error? - return false; - } - } - - currEventMask = 0; - bool sucessResult = false; - -#if !defined (Q_OS_WINCE) - if (::WaitCommEvent(m_descriptor, &currEventMask, &m_ovSelect)) - sucessResult = true; - else { - if (::GetLastError() == ERROR_IO_PENDING) { - DWORD bytesTransferred = 0; - switch (::WaitForSingleObject(m_ovSelect.hEvent, (timeout < 0) ? 0 : timeout)) { - case WAIT_OBJECT_0: - if (::GetOverlappedResult(m_descriptor, &m_ovSelect, &bytesTransferred, false)) - sucessResult = true; - break; - default: ; - } - } - } -#else - // 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! - WinCeWaitCommEventBreaker breaker(m_descriptor, (timeout < 0) ? 0 : timeout); - ::WaitCommEvent(m_descriptor, &currEventMask, 0); - breaker.stop(); - sucessResult = !breaker.isWorked(); -#endif - - if (sucessResult) { - // Here call the bytesAvailable() to protect against false positives WaitForSingleObject(), - // for example, when manually pulling USB/Serial converter from system, - // ie when devices are in fact not. - // While it may be possible to make additional checks - to catch an event EV_ERR, - // adding (in the code above) extra bits in the mask currEventMask. - if (checkRead) { - Q_ASSERT(selectForRead); - *selectForRead = (currEventMask & EV_RXCHAR) && (bytesAvailable() > 0); - } - if (checkWrite) { - Q_ASSERT(selectForWrite); - *selectForWrite = (currEventMask & EV_TXEMPTY); - } - } - - // Rerair old mask. - ::SetCommMask(m_descriptor, oldEventMask); - return sucessResult; -} - -#if !defined (Q_OS_WINCE) -static const QString defaultPathPrefix = "\\\\.\\"; -#else -static const QString defaultPathPostfix = ":"; -#endif - -/*! - Converts a platform specific \a port name to system location - and return result. -*/ -QString WinSerialPortEngine::toSystemLocation(const QString &port) const -{ - QString ret = port; -#if !defined (Q_OS_WINCE) - if (!ret.contains(defaultPathPrefix)) - ret.prepend(defaultPathPrefix); -#else - if (!ret.contains(defaultPathPostfix)) - ret.append(defaultPathPostfix); -#endif - return ret; -} - -/*! - Converts a platform specific system \a location to port name - and return result. -*/ -QString WinSerialPortEngine::fromSystemLocation(const QString &location) const -{ - QString ret = location; -#if !defined (Q_OS_WINCE) - if (ret.contains(defaultPathPrefix)) - ret.remove(defaultPathPrefix); -#else - if (ret.contains(defaultPathPostfix)) - ret.remove(defaultPathPostfix); -#endif - return ret; -} - -/*! - Set desired \a rate by given direction \a dir. - However, windows does not support separate directions, so the - method will return an error. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) -{ - if (dir != SerialPort::AllDirections) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - m_currDCB.BaudRate = DWORD(rate); - return updateDcb(); -} - -/*! - Set desired number of data bits \a dataBits in byte. Windows - native supported all present number of data bits 5, 6, 7, 8. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) -{ - m_currDCB.ByteSize = BYTE(dataBits); - return updateDcb(); -} - -/*! - Set desired \a parity control mode. Windows native supported - all present parity types no parity, space, mark, even, odd. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::setParity(SerialPort::Parity parity) -{ - m_currDCB.fParity = true; - switch (parity) { - case SerialPort::NoParity: - m_currDCB.Parity = NOPARITY; - m_currDCB.fParity = false; - break; - case SerialPort::SpaceParity: - m_currDCB.Parity = SPACEPARITY; - break; - case SerialPort::MarkParity: - m_currDCB.Parity = MARKPARITY; - break; - case SerialPort::EvenParity: - m_currDCB.Parity = EVENPARITY; - break; - case SerialPort::OddParity: - m_currDCB.Parity = ODDPARITY; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateDcb(); -} - -/*! - Set desired number of stop bits \a stopBits in frame. - Windows native supported all present number of stop bits - 1, 1.5, 2. - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) -{ - switch (stopBits) { - case SerialPort::OneStop: - m_currDCB.StopBits = ONESTOPBIT; - break; - case SerialPort::OneAndHalfStop: - m_currDCB.StopBits = ONE5STOPBITS; - break; - case SerialPort::TwoStop: - m_currDCB.StopBits = TWOSTOPBITS; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateDcb(); -} - -/*! - Set desired \a flow control mode. Windows native supported all - present flow control modes no control, hardware (RTS/CTS), - software (XON/XOFF). - - If successful, returns true; otherwise false, with the setup a - error code. -*/ -bool WinSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) -{ - switch (flow) { - case SerialPort::NoFlowControl: - m_currDCB.fOutxCtsFlow = false; - m_currDCB.fRtsControl = RTS_CONTROL_DISABLE; - m_currDCB.fInX = m_currDCB.fOutX = false; - break; - case SerialPort::SoftwareControl: - m_currDCB.fOutxCtsFlow = false; - m_currDCB.fRtsControl = RTS_CONTROL_DISABLE; - m_currDCB.fInX = m_currDCB.fOutX = true; - break; - case SerialPort::HardwareControl: - m_currDCB.fOutxCtsFlow = true; - m_currDCB.fRtsControl = RTS_CONTROL_HANDSHAKE; - m_currDCB.fInX = m_currDCB.fOutX = false; - break; - default: - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return updateDcb(); -} - -/*! - Empty stub. Setting a variable is carried out methods in a - private class SerialPortPrivate. -*/ -bool WinSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) -{ - Q_UNUSED(policy) - return true; -} - -/*! - Returns the current status of the read notification subsystem. -*/ -bool WinSerialPortEngine::isReadNotificationEnabled() const -{ -#if defined (Q_OS_WINCE) - bool flag = isRunning(); -#else - bool flag = isEnabled(); -#endif - return (flag && (m_setMask & EV_RXCHAR)); -} - -/*! - Enables or disables read notification subsystem, depending on - the \a enable parameter. If the subsystem is enabled, it will - asynchronously track the occurrence of an event EV_RXCHAR. - Thanks to that, SerialPort can emit a signal readyRead() and - fill up the internal receive buffer with new data, that - automatically received from a serial port in the event loop. -*/ -void WinSerialPortEngine::setReadNotificationEnabled(bool enable) -{ -#if defined (Q_OS_WINCE) - m_setCommMaskMutex.lock(); - ::GetCommMask(m_descriptor, &m_currentMask); -#endif - - if (enable) - m_setMask |= EV_RXCHAR; - else - m_setMask &= ~EV_RXCHAR; - -#if defined (Q_OS_WINCE) - if (m_setMask != m_currentMask) - ::SetCommMask(m_descriptor, m_setMask); - - m_setCommMaskMutex.unlock(); - - if (enable && !isRunning()) - start(); -#else - setMaskAndActivateEvent(); -#endif -} - -/*! - Returns the current status of the write notification subsystem. -*/ -bool WinSerialPortEngine::isWriteNotificationEnabled() const -{ -#if defined (Q_OS_WINCE) - bool flag = isRunning(); -#else - bool flag = isEnabled(); -#endif - return (flag && (m_setMask & EV_TXEMPTY)); -} - -/*! - Enables or disables write notification subsystem, depending on - the \a enable parameter. If the subsystem is enabled, it will - asynchronously track the occurrence of an event EV_TXEMPTY. - Thanks to that, SerialPort can write data from internal transfer - buffer, to serial port automatically in the event loop. -*/ -void WinSerialPortEngine::setWriteNotificationEnabled(bool enable) -{ -#if defined (Q_OS_WINCE) - m_setCommMaskMutex.lock(); - ::GetCommMask(m_descriptor, &m_currentMask); -#endif - - if (enable) - m_setMask |= EV_TXEMPTY; - else - m_setMask &= ~EV_TXEMPTY; - -#if defined (Q_OS_WINCE) - if (m_setMask != m_currentMask) - ::SetCommMask(m_descriptor, m_setMask); - - m_setCommMaskMutex.unlock(); - - if (enable && !isRunning()) - start(); -#else - setMaskAndActivateEvent(); -#endif - // This only for OS Windows, as EV_TXEMPTY event is triggered only - // after the last byte of data. - // Therefore, we are forced to run writeNotification(), as EV_TXEMPTY does not work. - if (enable) - m_parent->canWriteNotification(); -} - -/*! - Defines the type of parity or frame error when an event - occurs EV_ERR. In addition, in case of any errors, this method - sets to true a flag m_flagErrorFromCommEvent, that used in the - method of reading for policy processing. - - This method is called automatically from an error handler in - parent class SerialPortPrivate, that called by error notification - subsystem, wehn occurred a event EV_ERR. - -*/ -bool WinSerialPortEngine::processIOErrors() -{ - DWORD err = 0; - COMSTAT cs; - bool ret = (::ClearCommError(m_descriptor, &err, &cs) != 0); - if (ret && err) { - if (err & CE_FRAME) - m_parent->setError(SerialPort::FramingError); - else if (err & CE_RXPARITY) - m_parent->setError(SerialPort::ParityError); - else if (err & CE_BREAK) - m_parent->setError(SerialPort::BreakConditionError); - else - m_parent->setError(SerialPort::UnknownPortError); - - m_flagErrorFromCommEvent = true; - } - return ret; -} - -#if defined (Q_OS_WINCE) - -void WinSerialPortEngine::lockNotification(NotificationLockerType type, bool uselocker) -{ - QMutex *mutex = 0; - switch (type) { - case CanReadLocker: - mutex = &m_readNotificationMutex; - break; - case CanWriteLocker: - mutex = &m_writeNotificationMutex; - break; - case CanErrorLocker: - mutex = &m_errorNotificationMutex; - break; - } - - if (uselocker) - QMutexLocker locker(mutex); - else - mutex->lock(); -} - -void WinSerialPortEngine::unlockNotification(NotificationLockerType type) -{ - switch (type) { - case CanReadLocker: m_readNotificationMutex.unlock(); - break; - case CanWriteLocker: m_writeNotificationMutex.unlock(); - break; - case CanErrorLocker: m_errorNotificationMutex.unlock(); - break; - } -} - -#endif - -/* Protected methods */ - -/*! - Attempts to determine the current settings of the serial port, - wehn it opened. Used only in the method open(). -*/ -void WinSerialPortEngine::detectDefaultSettings() -{ - // Detect rate. - m_parent->m_inRate = quint32(m_currDCB.BaudRate); - m_parent->m_outRate = m_parent->m_inRate; - - // Detect databits. - switch (m_currDCB.ByteSize) { - case 5: - m_parent->m_dataBits = SerialPort::Data5; - break; - case 6: - m_parent->m_dataBits = SerialPort::Data6; - break; - case 7: - m_parent->m_dataBits = SerialPort::Data7; - break; - case 8: - m_parent->m_dataBits = SerialPort::Data8; - break; - default: - m_parent->m_dataBits = SerialPort::UnknownDataBits; - } - - // Detect parity. - if ((m_currDCB.Parity == NOPARITY) && !m_currDCB.fParity) - m_parent->m_parity = SerialPort::NoParity; - else if ((m_currDCB.Parity == SPACEPARITY) && m_currDCB.fParity) - m_parent->m_parity = SerialPort::SpaceParity; - else if ((m_currDCB.Parity == MARKPARITY) && m_currDCB.fParity) - m_parent->m_parity = SerialPort::MarkParity; - else if ((m_currDCB.Parity == EVENPARITY) && m_currDCB.fParity) - m_parent->m_parity = SerialPort::EvenParity; - else if ((m_currDCB.Parity == ODDPARITY) && m_currDCB.fParity) - m_parent->m_parity = SerialPort::OddParity; - else - m_parent->m_parity = SerialPort::UnknownParity; - - // Detect stopbits. - switch (m_currDCB.StopBits) { - case ONESTOPBIT: - m_parent->m_stopBits = SerialPort::OneStop; - break; - case ONE5STOPBITS: - m_parent->m_stopBits = SerialPort::OneAndHalfStop; - break; - case TWOSTOPBITS: - m_parent->m_stopBits = SerialPort::TwoStop; - break; - default: - m_parent->m_stopBits = SerialPort::UnknownStopBits; - } - - // Detect flow control. - if (!m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_DISABLE) - && !m_currDCB.fInX && !m_currDCB.fOutX) { - m_parent->m_flow = SerialPort::NoFlowControl; - } else if (!m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_DISABLE) - && m_currDCB.fInX && m_currDCB.fOutX) { - m_parent->m_flow = SerialPort::SoftwareControl; - } else if (m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_HANDSHAKE) - && !m_currDCB.fInX && !m_currDCB.fOutX) { - m_parent->m_flow = SerialPort::HardwareControl; - } else - m_parent->m_flow = SerialPort::UnknownFlowControl; -} - -#if defined (Q_OS_WINCE) - -/*! - Embedded-based (WinCE) event loop for notification subsystem. - Tracking a separate thread the events from the serial port, as: - EV_ERR, EV_RXCHAR, EV_TXEMPTY. When is occur a relevant event, - calls him handler from a parent class SerialPortPrivate. - At the same time in handlers to capture/release the mutex - (see handlers implementation). -*/ -void WinSerialPortEngine::run() -{ - while (m_running) { - - m_setCommMaskMutex.lock(); - ::SetCommMask(m_descriptor, m_setMask); - m_setCommMaskMutex.unlock(); - - if (::WaitCommEvent(m_descriptor, &m_currentMask, 0) != 0) { - - // Wait until complete the operation changes the port settings, - // see updateDcb(). - m_settingsChangeMutex.lock(); - m_settingsChangeMutex.unlock(); - - if (EV_ERR & m_currentMask & m_setMask) { - m_parent->canErrorNotification(); - } - if (EV_RXCHAR & m_currentMask & m_setMask) { - m_parent->canReadNotification(); - } - //FIXME: This is why it does not work? - if (EV_TXEMPTY & m_currentMask & m_setMask) { - m_parent->canWriteNotification(); - } - } - } -} - -#else - -/*! - Windows NT-based event loop for notification subsystem. - Asynchronously in event loop continuous mode tracking the - events from the serial port, as: EV_ERR, EV_RXCHAR, EV_TXEMPTY. - When is occur a relevant event, calls him handler from - a parent class SerialPortPrivate. -*/ -bool WinSerialPortEngine::event(QEvent *e) -{ - bool ret = false; - if (e->type() == QEvent::WinEventAct) { - if (EV_ERR & m_currentMask & m_setMask) { - m_parent->canErrorNotification(); - ret = true; - } - if (EV_RXCHAR & m_currentMask & m_setMask) { - m_parent->canReadNotification(); - ret = true; - } - //FIXME: This is why it does not work? - if (EV_TXEMPTY & m_currentMask & m_setMask) { - m_parent->canWriteNotification(); - ret = true; - } - } - else - ret = QWinEventNotifier::event(e); - - ::WaitCommEvent(m_descriptor, &m_currentMask, &m_ov); - return ret; -} - -#endif - -/* Private methods */ - -#if !defined (Q_OS_WINCE) - -/*! - For Windows NT-based, creates handles events for OVERLAPPED - structures, that are used in the methods of reading \a rx, - writing \a tx, and waiting for data from the serial port. - This method is only used in the method open(). - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::createEvents(bool rx, bool tx) -{ - if (rx) { - m_ovRead.hEvent = ::CreateEvent(0, false, false, 0); - Q_ASSERT(m_ovRead.hEvent); - } - if (tx) { - m_ovWrite.hEvent = ::CreateEvent(0, false, false, 0); - Q_ASSERT(m_ovWrite.hEvent); - } - m_ovSelect.hEvent = ::CreateEvent(0, false, false, 0); - Q_ASSERT(m_ovSelect.hEvent); - m_ov.hEvent = ::CreateEvent(0, false, false, 0); - Q_ASSERT(m_ov.hEvent); - - setHandle(m_ov.hEvent); - return true; -} - -/*! - For Windows NT-based, release and closed handles events from - OVERLAPPED structures. -*/ -void WinSerialPortEngine::closeEvents() -{ - if (m_ovRead.hEvent) - ::CloseHandle(m_ovRead.hEvent); - if (m_ovWrite.hEvent) - ::CloseHandle(m_ovWrite.hEvent); - if (m_ovSelect.hEvent) - ::CloseHandle(m_ovSelect.hEvent); - if (m_ov.hEvent) - ::CloseHandle(m_ov.hEvent); - - size_t size = sizeof(OVERLAPPED); - ::memset(&m_ovRead, 0, size); - ::memset(&m_ovWrite, 0, size); - ::memset(&m_ovSelect, 0, size); - ::memset(&m_ov, 0, size); -} - -/*! - For Windows NT-based, sets the mask of tracking events. -*/ -void WinSerialPortEngine::setMaskAndActivateEvent() -{ - ::SetCommMask(m_descriptor, m_setMask); - if (m_setMask) - ::WaitCommEvent(m_descriptor, &m_currentMask, &m_ov); - switch (m_setMask) { - case 0: - if (isEnabled()) - setEnabled(false); - break; - default: - if (!isEnabled()) - setEnabled(true); - } -} - -#endif - -/*! - Updates the DCB structure wehn changing of any the parameters - a serial port. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::updateDcb() -{ -#if defined (Q_OS_WINCE) - // Grab a mutex, in order after exit WaitCommEvent - // block the flow of run() notifier until there is a change DCB. - QMutexLocker locker(&m_settingsChangeMutex); - // This way, we reset in class WaitCommEvent to - // be able to change the DCB. - // Otherwise WaitCommEvent blocking any change! - ::SetCommMask(m_descriptor, 0); -#endif - if (::SetCommState(m_descriptor, &m_currDCB) == 0) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return true; -} - -/*! - Updates the COMMTIMEUTS structure wehn changing of any timeout the - parameters a serial port. - - If successful, returns true; otherwise false. -*/ -bool WinSerialPortEngine::updateCommTimeouts() -{ - if (::SetCommTimeouts(m_descriptor, &m_currCommTimeouts) == 0) { - m_parent->setError(SerialPort::UnsupportedPortOperationError); - return false; - } - return true; -} - -// From -SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) -{ - return new WinSerialPortEngine(parent); -} - diff --git a/src/serialportengine_p_win.h b/src/serialportengine_p_win.h deleted file mode 100644 index ba1aa95..0000000 --- a/src/serialportengine_p_win.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - License... -*/ - -#ifndef SERIALPORTENGINE_P_WIN_H -#define SERIALPORTENGINE_P_WIN_H - -#include "serialport.h" -#include "serialportengine_p.h" - -#include -#if defined (Q_OS_WINCE) -# include -# include -# include -#else -# include -#endif - -QT_BEGIN_NAMESPACE - -#if defined (Q_OS_WINCE) - -class WinCeWaitCommEventBreaker : public QThread -{ - Q_OBJECT -public: - WinCeWaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0) - : QThread(parent), m_descriptor(descriptor), - m_timeout(timeout), m_worked(false) { - start(); - } - virtual ~WinCeWaitCommEventBreaker() { - stop(); - wait(); - } - void stop() { exit(0); } - bool isWorked() const { return m_worked; } - -protected: - void run() { - QTimer timer; - QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(procTimeout()), Qt::DirectConnection); - timer.start(m_timeout); - exec(); - m_worked = true; - } - -private slots: - void procTimeout() { - ::SetCommMask(m_descriptor, 0); - stop(); - } - -private: - HANDLE m_descriptor; - int m_timeout; - volatile bool m_worked; -}; -#endif - -#if defined (Q_OS_WINCE) -class WinSerialPortEngine : public QThread, public SerialPortEngine - #else -class WinSerialPortEngine : public QWinEventNotifier, public SerialPortEngine - #endif -{ - Q_OBJECT -public: - WinSerialPortEngine(SerialPortPrivate *parent); - virtual ~WinSerialPortEngine(); - - virtual bool open(const QString &location, QIODevice::OpenMode mode); - virtual void close(const QString &location); - - virtual SerialPort::Lines lines() const; - - virtual bool setDtr(bool set); - virtual bool setRts(bool set); - - virtual bool flush(); - virtual bool reset(); - - virtual bool sendBreak(int duration); - virtual bool setBreak(bool set); - - virtual qint64 bytesAvailable() const; - virtual qint64 bytesToWrite() const; - - virtual qint64 read(char *data, qint64 len); - virtual qint64 write(const char *data, qint64 len); - virtual bool select(int timeout, - bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite); - - virtual QString toSystemLocation(const QString &port) const; - virtual QString fromSystemLocation(const QString &location) const; - - virtual bool setRate(qint32 rate, SerialPort::Directions dir); - virtual bool setDataBits(SerialPort::DataBits dataBits); - virtual bool setParity(SerialPort::Parity parity); - virtual bool setStopBits(SerialPort::StopBits stopBits); - virtual bool setFlowControl(SerialPort::FlowControl flowControl); - - virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); - - virtual bool isReadNotificationEnabled() const; - virtual void setReadNotificationEnabled(bool enable); - virtual bool isWriteNotificationEnabled() const; - virtual void setWriteNotificationEnabled(bool enable); - - virtual bool processIOErrors(); - -#if defined (Q_OS_WINCE) - virtual void lockNotification(NotificationLockerType type, bool uselocker); - virtual void unlockNotification(NotificationLockerType type); -#endif - -protected: - virtual void detectDefaultSettings(); - -#if defined (Q_OS_WINCE) - virtual void run(); -#else - virtual bool event(QEvent *e); -#endif - -private: - DCB m_currDCB; - DCB m_oldDCB; - COMMTIMEOUTS m_currCommTimeouts; - COMMTIMEOUTS m_oldCommTimeouts; - HANDLE m_descriptor; - bool m_flagErrorFromCommEvent; - DWORD m_currentMask; - DWORD m_setMask; - -#if defined (Q_OS_WINCE) - QMutex m_readNotificationMutex; - QMutex m_writeNotificationMutex; - QMutex m_errorNotificationMutex; - QMutex m_settingsChangeMutex; - QMutex m_setCommMaskMutex; - volatile bool m_running; -#else - OVERLAPPED m_ovRead; - OVERLAPPED m_ovWrite; - OVERLAPPED m_ovSelect; - OVERLAPPED m_ov; - - bool createEvents(bool rx, bool tx); - void closeEvents(); - void setMaskAndActivateEvent(); -#endif - - bool updateDcb(); - bool updateCommTimeouts(); -}; - -QT_END_NAMESPACE - -#endif // SERIALPORTENGINE_P_WIN_H diff --git a/src/serialportengine_symbian.cpp b/src/serialportengine_symbian.cpp new file mode 100644 index 0000000..733c9a3 --- /dev/null +++ b/src/serialportengine_symbian.cpp @@ -0,0 +1,983 @@ +/* + License... +*/ + +/*! + \class SymbianSerialPortEngine + \internal + + \brief The SymbianSerialPortEngine class provides *nix OS + platform-specific low level access to a serial port. + + \reentrant + \ingroup serial + \inmodule QSerialDevice + + Currently the class supports all?? version of Symbian OS. + + SymbianSerialPortEngine (as well as other platform-dependent engines) + is a class with multiple inheritance, which on the one hand, + derives from a general abstract class interface SerialPortEngine, + on the other hand of a class inherited from QObject. + + From the abstract class SerialPortEngine, it inherits all virtual + interface methods that are common to all serial ports on any platform. + These methods, the class SymbianSerialPortEngine implements use + Symbian API. + + From QObject-like class ... + ... + ... + ... + + That is, as seen from the above, the functional SymbianSerialPortEngine + completely covers all the necessary tasks. +*/ + +#include "serialportengine_symbian_p.h" + +#include +//#include +#include + +#include +//#include + + +// Physical device driver. +#if defined (__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; +#if defined (__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); + +#if !defined (__WINS__) + r = StartC32(); + if ((r != KErrNone) && (r != KErrAlreadyExists)) + return false; //User::Leave(r); +#endif + + return true; +} + +QT_BEGIN_NAMESPACE_SERIALPORT + +/* Public methods */ + +/*! + Constructs a SymbianSerialPortEngine with \a parent and + initializes all the internal variables of the initial values. + + A pointer \a parent to the object class SerialPortPrivate + is required for the recursive call some of its methods. +*/ +SymbianSerialPortEngine::SymbianSerialPortEngine(SerialPortPrivate *parent) +{ + Q_ASSERT(parent); + // Impl me + m_parent = parent; +} + +/*! + Destructs a SymbianSerialPortEngine, +*/ +SymbianSerialPortEngine::~SymbianSerialPortEngine() +{ + +} + +/*! + Tries to open the object desired serial port by \a location + in the given open \a mode. In the API of Symbian there is no flag + to open the port in r/o, w/o or r/w, most likely he always opens + as r/w. + + Since the port in the Symbian OS can be open in any access mode, + then this method forcibly puts a port in exclusive mode access. + In the process of discovery, always set a port in non-blocking + mode (when the read operation returns immediately) and tries to + determine its current configuration and install them. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) +{ + // Maybe need added check an ReadWrite open mode? + Q_UNUSED(mode) + + if (!loadDevices()) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + + if (location.contains("BTCOMM")) + r = server.LoadCommModule(KBluetoothModuleName); + else if (location.contains("IRCOMM")) + r = server.LoadCommModule(KInfraRedModuleName); + else if (location.contains("ACM")) + r = server.LoadCommModule(KACMModuleName); + else + r = server.LoadCommModule(KRS232ModuleName); + + if (r != KErrNone) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + + // In Symbian OS port opening only in R/W mode !? + TPtrC portName(static_cast(location.utf16()), location.length()); + r = m_descriptor.Open(server, portName, ECommExclusive); + + if (r != KErrNone) { + switch (r) { + case KErrPermissionDenied: + m_parent->setError(SerialPort::NoSuchDeviceError); break; + case KErrLocked: + case KErrAccessDenied: + m_parent->setError(SerialPort::PermissionDeniedError); break; + default: + m_parent->setError(SerialPort::UnknownPortError); + } + return false; + } + + // Save current port settings. + r = m_descriptor.Config(m_oldSettings); + if (r != KErrNone) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + + detectDefaultSettings(); + return true; +} + +/*! + Closes a serial port object. Before closing restore previous + serial port settings if necessary. +*/ +void SymbianSerialPortEngine::close(const QString &location) +{ + Q_UNUSED(location); + + if (m_parent->m_restoreSettingsOnClose) { + m_descriptor.SetConfig(m_oldSettings); + } + + m_descriptor.Close(); +} + +/*! + Returns a bitmap state of RS-232 line signals. On error, + bitmap will be empty (equal zero). + + Symbian API allows you to receive only the state of signals: + CTS, DSR, DCD, RING, RTS, DTR. Other signals are not available. +*/ +SerialPort::Lines SymbianSerialPortEngine::lines() const +{ + SerialPort::Lines ret = 0; + + TUint signalMask = 0; + m_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; +} + +/*! + Set DTR signal to state \a set. + + +*/ +bool SymbianSerialPortEngine::setDtr(bool set) +{ + TInt r; + if (set) + r = m_descriptor.SetSignalsToMark(KSignalDTR); + else + r = m_descriptor.SetSignalsToSpace(KSignalDTR); + + return (r == KErrNone); +} + +/*! + Set RTS signal to state \a set. + + +*/ +bool SymbianSerialPortEngine::setRts(bool set) +{ + TInt r; + if (set) + r = m_descriptor.SetSignalsToMark(KSignalRTS); + else + r = m_descriptor.SetSignalsToSpace(KSignalRTS); + + return (r == KErrNone); +} + +/*! + +*/ +bool SymbianSerialPortEngine::flush() +{ + // Impl me + return false; +} + +/*! + Resets the transmit and receive serial port buffers + independently. +*/ +bool SymbianSerialPortEngine::reset() +{ + TInt r = m_descriptor.ResetBuffers(KCommResetRx | KCommResetTx); + return (r == KErrNone); +} + +/*! + Sets a break condition for a specified time \a duration + in milliseconds. + + A break condition on a line is when a data line is held + permanently high for an indeterminate period which must be + greater than the time normally taken to transmit two characters. + It is sometimes used as an error signal between computers and + other devices attached to them over RS232 lines. + + Setting breaks is not supported on the integral ARM + serial hardware. EPOC has no support for detecting received + breaks. There is no way to detects whether setting a break is + supported using Caps(). +*/ +bool SymbianSerialPortEngine::sendBreak(int duration) +{ + TRequestStatus status; + m_descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000)); + return false; +} + +/*! + +*/ +bool SymbianSerialPortEngine::setBreak(bool set) +{ + // Impl me + return false; +} + +/*! + Gets the number of bytes currently waiting in the + driver's input buffer. A return value of zero means + the buffer is empty. +*/ +qint64 SymbianSerialPortEngine::bytesAvailable() const +{ + return qint64(m_descriptor.QueryReceiveBuffer()); +} + +/*! + + It is not possible to find out exactly how many bytes are + currently in the driver's output buffer waiting to be + transmitted. However, this is not an issue since it is easy + to ensure that the output buffer is empty. If the + KConfigWriteBufferedComplete bit (set via the TCommConfigV01 + structure's iHandshake field) is clear, then all write + requests will delay completion until the data has completely + cleared the driver's output buffer. + If the KConfigWriteBufferedComplete bit is set, a write of zero + bytes to a port which has data in the output buffer is guaranteed + to delay completion until the buffer has been fully drained. + +*/ +qint64 SymbianSerialPortEngine::bytesToWrite() const +{ + // Impl me + return 0; +} + +/*! + + Reads data from a serial port only if it arrives before a + specified time-out (zero). All reads from the serial device + use 8-bit descriptors as data buffers, even on a Unicode system. + + The length of the TDes8 is set to zero on entry, which means that + buffers can be reused without having to be zeroed first. + + The number of bytes to read is set to the maximum length of the + descriptor. + + If a read is issued with a data length of zero the Read() completes + immediately but with the side effect that the serial hardware is + powered up. + + When a Read() terminates with KErrTimedOut, different protocol + modules can show different behaviours. Some may write any data + received into the aDes buffer, while others may return just an + empty descriptor. In the case of a returned empty descriptor use + ReadOneOrMore() to read any data left in the buffer. + + The behaviour of this API after a call to NotifyDataAvailable() is + not prescribed and so different CSY's behave differently. IrComm + will allow a successful completion of this API after a call to + NotifyDataAvailable(), while ECUART and ECACM will complete the + request with KErrInUse. + +*/ +qint64 SymbianSerialPortEngine::read(char *data, qint64 len) +{ + TPtr8 buffer((TUint8 *)data, (int)len); + TRequestStatus status; + m_descriptor.Read(status, TTimeIntervalMicroSeconds32(0), buffer); + User::WaitForRequest(status); + TInt err = status.Int(); + if (err != KErrNone) { + m_parent->setError(SerialPort::IoError); + return qint64(-1); + } + return qint64(buffer.Length()); +} + +/*! + + Writes data to a serial port. All writes to the serial device + use 8-bit descriptors as data buffers, even on a Unicode system. + + The number of bytes to write is set to the maximum length of + the descriptor. + + When a Write() is issued with a data length of zero it cannot + complete until the current handshaking configuration and the + state of input control lines indicate that it is possible for + data to be immediately written to the serial line, even though no + data is to be written. This functionality is useful when + determining when serial devices come on line, and checking that + the output buffer is empty (if the KConfigWriteBufferedComplete + bit is set). + +*/ +qint64 SymbianSerialPortEngine::write(const char *data, qint64 len) +{ + TPtrC8 buffer((TUint8*)data, (int)len); + TRequestStatus status; + m_descriptor.Write(status, buffer); + User::WaitForRequest(status); + TInt err = status.Int(); + + if (err != KErrNone) { + m_parent->setError(SerialPort::IoError); + len = -1; + } + // FIXME: How to get the actual number of bytes written? + return qint64(len); +} + +/*! + +*/ +bool SymbianSerialPortEngine::select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) +{ + + // FIXME: I'm not sure in implementation this method. + // Someone needs to check and correct. + + TRequestStatus timerStatus; + TRequestStatus readStatus; + TRequestStatus writeStatus; + + if (timeout > 0) { + if (!m_selectTimer.Handle()) { + if (m_selectTimer.CreateLocal() != KErrNone) + return false; + } + m_selectTimer.HighRes(timerStatus, timeout * 1000); + } + + if (checkRead) + m_descriptor.NotifyDataAvailable(readStatus); + + if (checkWrite) + m_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 { + m_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) + m_descriptor.NotifyDataAvailableCancel(); + if (checkWrite) + m_descriptor.NotifyOutputEmptyCancel(); + + result = true; + } + return result; +} + +//static const QString defaultPathPostfix = ":"; + +/*! + Converts a platform specific \a port name to system location + and return result. + + Does not do anything because These concepts are equivalent. +*/ +QString SymbianSerialPortEngine::toSystemLocation(const QString &port) const +{ + // Port name is equval to port location. + return port; +} + +/*! + Converts a platform specific system \a location to port name + and return result. + + Does not do anything because These concepts are equivalent. +*/ +QString SymbianSerialPortEngine::fromSystemLocation(const QString &location) const +{ + // Port name is equval to port location. + return location; +} + +/*! + Set desired \a rate by given direction \a dir. + However, Symbian does not support separate directions, so the + method will return an error. Also it supports only the standard + set of speed. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) +{ + if (dir != SerialPort::AllDirections) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + switch (rate) { + case 50: + m_currSettings().iRate = EBps50; + break; + case 75: + m_currSettings().iRate = EBps75; + break; + case 110: + m_currSettings().iRate = EBps110; + break; + case 134: + m_currSettings().iRate = EBps134; + break; + case 150: + m_currSettings().iRate = EBps150; + break; + case 300: + m_currSettings().iRate = EBps300; + break; + case 600: + m_currSettings().iRate = EBps600; + break; + case 1200: + m_currSettings().iRate = EBps1200; + break; + case 1800: + m_currSettings().iRate = EBps1800; + break; + case 2000: + m_currSettings().iRate = EBps2000; + break; + case 2400: + m_currSettings().iRate = EBps2400; + break; + case 3600: + m_currSettings().iRate = EBps3600; + break; + case 4800: + m_currSettings().iRate = EBps4800; + break; + case 7200: + m_currSettings().iRate = EBps7200; + break; + case 9600: + m_currSettings().iRate = EBps9600; + break; + case 19200: + m_currSettings().iRate = EBps19200; + break; + case 38400: + m_currSettings().iRate = EBps38400; + break; + case 57600: + m_currSettings().iRate = EBps57600; + break; + case 115200: + m_currSettings().iRate = EBps115200; + break; + case 230400: + m_currSettings().iRate = EBps230400; + break; + case 460800: + m_currSettings().iRate = EBps460800; + break; + case 576000: + m_currSettings().iRate = EBps576000; + break; + case 1152000: + m_currSettings().iRate = EBps1152000; + break; + case 4000000: + m_currSettings().iRate = EBps4000000; + break; + case 921600: + m_currSettings().iRate = EBps921600; + break; + //case 1843200:; // Only for Symbian SR1 + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + return updateCommConfig(); +} + +/*! + Set desired number of data bits \a dataBits in byte. Symbian + native supported all present number of data bits 5, 6, 7, 8. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) +{ + switch (dataBits) { + case SerialPort::Data5: + m_currSettings().iDataBits = EData5; + break; + case SerialPort::Data6: + m_currSettings().iDataBits = EData6; + break; + case SerialPort::Data7: + m_currSettings().iDataBits = EData7; + break; + case SerialPort::Data8: + m_currSettings().iDataBits = EData8; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + return updateCommConfig(); +} + +/*! + Set desired \a parity control mode. Symbian native supported + all present parity types no parity, space, mark, even, odd. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::setParity(SerialPort::Parity parity) +{ + switch (parity) { + case SerialPort::NoParity: + m_currSettings().iParity = EParityNone; + break; + case SerialPort::EvenParity: + m_currSettings().iParity = EParityEven; + break; + case SerialPort::OddParity: + m_currSettings().iParity = EParityOdd; + break; + case SerialPort::MarkParity: + m_currSettings().iParity = EParityMark; + break; + case SerialPort::SpaceParity: + m_currSettings().iParity = EParitySpace; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + return updateCommConfig(); +} + +/*! + Set desired number of stop bits \a stopBits in frame. Symbian + native supported only 1, 2 number of stop bits. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) +{ + switch (stopBits) { + case SerialPort::OneStop: + m_currSettings().iStopBits = EStop1; + break; + case SerialPort::TwoStop: + m_currSettings().iStopBits = EStop2; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + return updateCommConfig(); +} + +/*! + Set desired \a flow control mode. Symbian native supported all + present flow control modes no control, hardware (RTS/CTS), + software (XON/XOFF). + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool SymbianSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) +{ + switch (flow) { + case SerialPort::NoFlowControl: + m_currSettings().iHandshake = KConfigFailDSR; + break; + case SerialPort::HardwareControl: + m_currSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS; + break; + case SerialPort::SoftwareControl: + m_currSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + + return updateCommConfig(); +} + +/*! + +*/ +bool SymbianSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) +{ + Q_UNUSED(policy) + // Impl me + return true; +} + +/*! + +*/ +bool SymbianSerialPortEngine::isReadNotificationEnabled() const +{ + // Impl me + return false; +} + +/*! + +*/ +void SymbianSerialPortEngine::setReadNotificationEnabled(bool enable) +{ + Q_UNUSED(enable) + // Impl me +} + +/*! + +*/ +bool SymbianSerialPortEngine::isWriteNotificationEnabled() const +{ + // Impl me + return false; +} + +/*! + +*/ +void SymbianSerialPortEngine::setWriteNotificationEnabled(bool enable) +{ + Q_UNUSED(enable) + // Impl me +} + +/*! + +*/ +bool SymbianSerialPortEngine::processIOErrors() +{ + // Impl me + return false; +} + +/// + +/* Protected methods */ + +/*! + Attempts to determine the current settings of the serial port, + wehn it opened. Used only in the method open(). +*/ +void SymbianSerialPortEngine::detectDefaultSettings() +{ + // Detect rate. + switch (m_currSettings().iRate) { + case EBps50: + m_parent->m_inRate = 50; + break; + case EBps75: + m_parent->m_inRate = 75; + break; + case EBps110: + m_parent->m_inRate = 110; + break; + case EBps134: + m_parent->m_inRate = 134; + break; + case EBps150: + m_parent->m_inRate = 150; + break; + case EBps300: + m_parent->m_inRate = 300; + break; + case EBps600: + m_parent->m_inRate = 600; + break; + case EBps1200: + m_parent->m_inRate = 1200; + break; + case EBps1800: + m_parent->m_inRate = 1800; + break; + case EBps2000: + m_parent->m_inRate = 2000; + break; + case EBps2400: + m_parent->m_inRate = 2400; + break; + case EBps3600: + m_parent->m_inRate = 3600; + break; + case EBps4800: + m_parent->m_inRate = 4800; + break; + case EBps7200: + m_parent->m_inRate = 7200; + break; + case EBps9600: + m_parent->m_inRate = 9600; + break; + case EBps19200: + m_parent->m_inRate = 19200; + break; + case EBps38400: + m_parent->m_inRate = 38400; + break; + case EBps57600: + m_parent->m_inRate = 57600; + break; + case EBps115200: + m_parent->m_inRate = 115200; + break; + case EBps230400: + m_parent->m_inRate = 230400; + break; + case EBps460800: + m_parent->m_inRate = 460800; + break; + case EBps576000: + m_parent->m_inRate = 576000; + break; + case EBps1152000: + m_parent->m_inRate = 1152000; + break; + case EBps4000000: + m_parent->m_inRate = 4000000; + break; + case EBps921600: + m_parent->m_inRate = 921600; + break; + //case EBps1843200: m_inRate = 1843200; break; + default: + m_parent->m_inRate = SerialPort::UnknownRate; + } + m_parent->m_outRate = m_parent->m_inRate; + + // Detect databits. + switch (m_currSettings().iDataBits) { + case EData5: + m_parent->m_dataBits = SerialPort::Data5; + break; + case EData6: + m_parent->m_dataBits = SerialPort::Data6; + break; + case EData7: + m_parent->m_dataBits = SerialPort::Data7; + break; + case EData8: + m_parent->m_dataBits = SerialPort::Data8; + break; + default: + m_parent->m_dataBits = SerialPort::UnknownDataBits; + } + + // Detect parity. + switch (m_currSettings().iParity) { + case EParityNone: + m_parent->m_parity = SerialPort::NoParity; + break; + case EParityEven: + m_parent->m_parity = SerialPort::EvenParity; + break; + case EParityOdd: + m_parent->m_parity = SerialPort::OddParity; + break; + case EParityMark: + m_parent->m_parity = SerialPort::MarkParity; + break; + case EParitySpace: + m_parent->m_parity = SerialPort::SpaceParity; + break; + default: + m_parent->m_parity = SerialPort::UnknownParity; + } + + // Detect stopbits. + switch (m_currSettings().iStopBits) { + case EStop1: + m_parent->m_stopBits = SerialPort::OneStop; + break; + case EStop2: + m_parent->m_stopBits = SerialPort::TwoStop; + break; + default: + m_parent->m_stopBits = SerialPort::UnknownStopBits; + } + + // Detect flow control. + if ((m_currSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff)) + == (KConfigObeyXoff | KConfigSendXoff)) + m_parent->m_flow = SerialPort::SoftwareControl; + else if ((m_currSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS)) + == (KConfigObeyCTS | KConfigFreeRTS)) + m_parent->m_flow = SerialPort::HardwareControl; + else if (m_currSettings().iHandshake & KConfigFailDSR) + m_parent->m_flow = SerialPort::NoFlowControl; + else + m_parent->m_flow = SerialPort::UnknownFlowControl; +} + +/* Private methods */ + +/*! + Updates the TCommConfig structure wehn changing of any the + parameters a serial port. + + If successful, returns true; otherwise false. +*/ +bool SymbianSerialPortEngine::updateCommConfig() +{ + if (m_descriptor.SetConfig(m_currSettings) != KErrNone) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return true; +} + +// From +SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) +{ + return new SymbianSerialPortEngine(parent); +} + +#include "moc_serialportengine_symbian_p.cpp" + +QT_END_NAMESPACE_SERIALPORT + + diff --git a/src/serialportengine_symbian_p.h b/src/serialportengine_symbian_p.h new file mode 100644 index 0000000..ce3851f --- /dev/null +++ b/src/serialportengine_symbian_p.h @@ -0,0 +1,78 @@ +/* + License... +*/ + +#ifndef SERIALPORTENGINE_SYMBIAN_P_H +#define SERIALPORTENGINE_SYMBIAN_P_H + +#include "serialport.h" +#include "serialportengine_p.h" + +#include + +QT_BEGIN_NAMESPACE_SERIALPORT + +class SymbianSerialPortEngine : public QObject, public SerialPortEngine +{ + Q_OBJECT +public: + SymbianSerialPortEngine(SerialPortPrivate *parent); + virtual ~SymbianSerialPortEngine(); + + virtual bool open(const QString &location, QIODevice::OpenMode mode); + virtual void close(const QString &location); + + virtual SerialPort::Lines lines() const; + + virtual bool setDtr(bool set); + virtual bool setRts(bool set); + + virtual bool flush(); + virtual bool reset(); + + virtual bool sendBreak(int duration); + virtual bool setBreak(bool set); + + virtual qint64 bytesAvailable() const; + virtual qint64 bytesToWrite() const; + + virtual qint64 read(char *data, qint64 len); + virtual qint64 write(const char *data, qint64 len); + virtual bool select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite); + + virtual QString toSystemLocation(const QString &port) const; + virtual QString fromSystemLocation(const QString &location) const; + + virtual bool setRate(qint32 rate, SerialPort::Directions dir); + virtual bool setDataBits(SerialPort::DataBits dataBits); + virtual bool setParity(SerialPort::Parity parity); + virtual bool setStopBits(SerialPort::StopBits stopBits); + virtual bool setFlowControl(SerialPort::FlowControl flowControl); + + virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); + + virtual bool isReadNotificationEnabled() const; + virtual void setReadNotificationEnabled(bool enable); + virtual bool isWriteNotificationEnabled() const; + virtual void setWriteNotificationEnabled(bool enable); + + virtual bool processIOErrors(); + +protected: + virtual void detectDefaultSettings(); + //virtual bool eventFilter(QObject *obj, QEvent *e); + +private: + TCommConfig m_currSettings; + TCommConfig m_oldSettings; + RComm m_descriptor; + mutable RTimer m_selectTimer; + + bool updateCommConfig(); +}; + +QT_END_NAMESPACE_SERIALPORT + +#endif // SERIALPORTENGINE_SYMBIAN_P_H diff --git a/src/serialportengine_unix.cpp b/src/serialportengine_unix.cpp new file mode 100644 index 0000000..8535e2e --- /dev/null +++ b/src/serialportengine_unix.cpp @@ -0,0 +1,1478 @@ +/* + License... +*/ + +/*! + \class UnixSerialPortEngine + \internal + + \brief The UnixSerialPortEngine class provides *nix OS + platform-specific low level access to a serial port. + + \reentrant + \ingroup serial + \inmodule QSerialDevice + + Currently the class supports all POSIX-compatible OS (GNU/Linux, *BSD, + Mac OSX and etc). + + UnixSerialPortEngine (as well as other platform-dependent engines) + is a class with multiple inheritance, which on the one hand, + derives from a general abstract class interface SerialPortEngine, + on the other hand of a class inherited from QObject. + + From the abstract class SerialPortEngine, it inherits all virtual + interface methods that are common to all serial ports on any platform. + These methods, the class UnixSerialPortEngine implements use + POSIX ABI. + + From QObject-like class, it inherits a specific system Qt features. + For example, to track of events from a serial port uses the virtual + QObject method eventFilter(), who the make analysis of the events + from the type classes QSocketNotifier. + + That is, as seen from the above, the functional UnixSerialPortEngine + completely covers all the necessary tasks. +*/ + +#include "serialportengine_unix_p.h" +#include "ttylocker_unix_p.h" + +#include +#include +#include +#include + +#if defined (Q_OS_LINUX) +# include +#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) +# include +# endif +#endif + +#include +#include +#include + +QT_BEGIN_NAMESPACE_SERIALPORT + +/* Public methods */ + +/*! + Constructs a UnixSerialPortEngine with \a parent and + initializes all the internal variables of the initial values. + + A pointer \a parent to the object class SerialPortPrivate + is required for the recursive call some of its methods. +*/ +UnixSerialPortEngine::UnixSerialPortEngine(SerialPortPrivate *parent) + : m_descriptor(-1) + , m_readNotifier(0) + , m_writeNotifier(0) + , m_exceptionNotifier(0) +{ + Q_ASSERT(parent); + m_parent = parent; + int size = sizeof(struct termios); + ::memset(&m_currTermios, 0, size); + ::memset(&m_oldTermios, 0, size); +} + +/*! + Stops the tracking events of the serial port and + destructs a UnixSerialPortEngine. +*/ +UnixSerialPortEngine::~UnixSerialPortEngine() +{ + if (m_readNotifier) + m_readNotifier->setEnabled(false); + if (m_writeNotifier) + m_writeNotifier->setEnabled(false); + if (m_exceptionNotifier) + m_exceptionNotifier->setEnabled(false); +} + +/*! + Tries to open the descriptor desired serial port by \a location + in the given open \a mode. + + Before the opening of the serial port, checking for on exists the + appropriate lock the file and the information therein. If the + lock file is present, and the information contained in it is + relevant - it is concluded that the current serial port is + already occupied. + + In the process of discovery, always set a serial port in + non-blocking mode (when the read operation returns immediately) + and tries to determine its current configuration and install them. + + Since the port in the POSIX OS by default opens in shared mode, + then this method forcibly puts a port in exclusive mode access. + This is done simultaneously in two ways: + - set to the pre-open descriptor a flag TIOCEXCL + - creates a lock file, which writes the pid of the process, that + opened the port and other information + + Need to use two methods due to the fact that on some platforms can + not be defined constant TIOCEXCL, in this case, try to use the + lock file. Creation and analysis of lock file, by using a special + helper class TTYLocker. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) +{ + // First, here need check locked device or not. + bool byCurrPid = false; + if (TTYLocker::isLocked(location, &byCurrPid)) { + m_parent->setError(SerialPort::PermissionDeniedError); + return false; + } + + int flags = (O_NOCTTY | O_NDELAY); + + switch (mode & QIODevice::ReadWrite) { + case QIODevice::WriteOnly: + flags |= O_WRONLY; + break; + case QIODevice::ReadWrite: + flags |= O_RDWR; + break; + default: + flags |= O_RDONLY; + break; + } + + // Try opened serial device. + m_descriptor = ::open(location.toLocal8Bit().constData(), flags); + + if (m_descriptor == -1) { + switch (errno) { + case ENODEV: + m_parent->setError(SerialPort::NoSuchDeviceError); + break; + case EACCES: + m_parent->setError(SerialPort::PermissionDeniedError); + break; + default: + m_parent->setError(SerialPort::UnknownPortError); + } + return false; + } + + // Try lock device by location and check it state is locked. + TTYLocker::lock(location); + if (!TTYLocker::isLocked(location, &byCurrPid)) { + m_parent->setError(SerialPort::PermissionDeniedError); + return false; + } + + // Try set exclusive mode. +#if defined (TIOCEXCL) + ::ioctl(m_descriptor, TIOCEXCL); +#endif + + // Save current port settings. + if (::tcgetattr(m_descriptor, &m_oldTermios) == -1) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + ::memcpy(&m_currTermios, &m_oldTermios, sizeof(struct termios)); + + // Set other options. + ::cfmakeraw(&m_currTermios); + m_currTermios.c_cflag |= (CREAD | CLOCAL); + m_currTermios.c_cc[VTIME] = 0; + + // Apply new init settings. + if (!updateTermios()) + return false; + + detectDefaultSettings(); + return true; +} + +/*! + Closes a serial port descriptor. Before closing - clears exclusive + access flag and removes the lock file, restore previous serial port + settings if necessary. +*/ +void UnixSerialPortEngine::close(const QString &location) +{ + // Restore saved port settings. + if (m_parent->m_restoreSettingsOnClose) + ::tcsetattr(m_descriptor, TCSANOW, &m_oldTermios); + + // Try clean exclusive mode. +#if defined (TIOCNXCL) + ::ioctl(m_descriptor, TIOCNXCL); +#endif + + ::close(m_descriptor); + + // Try unlock device by location. + bool byCurrPid = false; + if (TTYLocker::isLocked(location, &byCurrPid) && byCurrPid) + TTYLocker::unlock(location); + + m_descriptor = -1; +} + +/*! + Returns a bitmap state of RS-232 line signals. On error, + bitmap will be empty (equal zero). + + POSIX ABI allows you to receive all the state of signals: + LE, DTR, RTS, ST, SR, CTS, DCD, RING, DSR. Of course, if the + corresponding constants are defined in a particular platform. +*/ +SerialPort::Lines UnixSerialPortEngine::lines() const +{ + int arg = 0; + SerialPort::Lines ret = 0; + + if (::ioctl(m_descriptor, TIOCMGET, &arg) == -1) { + // Print error? + return ret; + } + +#if defined (TIOCM_LE) + if (arg & TIOCM_LE) ret |= SerialPort::Le; +#endif +#if defined (TIOCM_DTR) + if (arg & TIOCM_DTR) ret |= SerialPort::Dtr; +#endif +#if defined (TIOCM_RTS) + if (arg & TIOCM_RTS) ret |= SerialPort::Rts; +#endif +#if defined (TIOCM_ST) + if (arg & TIOCM_ST) ret |= SerialPort::St; +#endif +#if defined (TIOCM_SR) + if (arg & TIOCM_SR) ret |= SerialPort::Sr; +#endif +#if defined (TIOCM_CTS) + if (arg & TIOCM_CTS) ret |= SerialPort::Cts; +#endif + +#if defined (TIOCM_CAR) + if (arg & TIOCM_CAR) ret |= SerialPort::Dcd; +#elif defined (TIOCM_CD) + if (arg & TIOCM_CD) ret |= SerialPort::Dcd; +#endif + +#if defined (TIOCM_RNG) + if (arg & TIOCM_RNG) ret |= SerialPort::Ri; +#elif defined (TIOCM_RI) + if (arg & TIOCM_RI) ret |= SerialPort::Ri; +#endif + +#if defined (TIOCM_DSR) + if (arg & TIOCM_DSR) ret |= SerialPort::Dsr; +#endif + + return ret; +} + +// +static bool trigger_out_line(int fd, int bit, bool set) +{ + int arg = 0; + bool ret = (::ioctl(fd, TIOCMGET, &arg) != -1); + + if (ret) { + int tmp = arg & bit; + + // If line already installed, then it no need change. + if ((tmp && set) || (!(tmp || set))) + return true; + + if (set) + arg |= bit; + else + arg &= (~bit); + + ret = (::ioctl(fd, TIOCMSET, &arg) != -1); + } + return ret; +} + +/*! + Set DTR signal to state \a set. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::setDtr(bool set) +{ + bool ret = trigger_out_line(m_descriptor, TIOCM_DTR, set); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + Set RTS signal to state \a set. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::setRts(bool set) +{ + bool ret = trigger_out_line(m_descriptor, TIOCM_RTS, set); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + The shall block until all data output written to the serial + port is transmitted. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::flush() +{ + bool ret = (::tcdrain(m_descriptor) != -1); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + Flushes both data received but not read and data written + but not transmitted. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::reset() +{ + bool ret = (::tcflush(m_descriptor, TCIOFLUSH) != -1); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + Send a break for a specific \a duration. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::sendBreak(int duration) +{ + bool ret = (::tcsendbreak(m_descriptor, duration) != -1); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + Turn break on or off, that is, start or stop sending zero + bits, depending on the parameter \a set. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::setBreak(bool set) +{ + bool ret = (::ioctl(m_descriptor, set ? TIOCSBRK : TIOCCBRK) != -1); + if (!ret) { + // FIXME: Here need call errno + // and set error type. + } + return ret; +} + +/*! + If successful, returns the number of bytes that are + immediately available for reading; otherwise -1. +*/ +qint64 UnixSerialPortEngine::bytesAvailable() const +{ + int cmd = 0; +#if defined (FIONREAD) + cmd = FIONREAD; +#else + cmd = TIOCINQ; +#endif + qint64 nbytes = 0; + if (::ioctl(m_descriptor, cmd, &nbytes) == -1) + return -1; + return nbytes; +} + +/*! + Not supported on POSIX-compatible platform, + always returns 0. +*/ +qint64 UnixSerialPortEngine::bytesToWrite() const +{ + // FIXME: FIONWRITE (or analogy) is exists? + return 0; +} + +/*! + If successful, returns to the external buffer \a data the + real number of bytes read, which can be less than the + requested \a len; otherwise returned -1 with set error code. + In any case, reading function returns immediately. + + Some platforms do not support the mark or space parity, so + running software emulation of these modes in the process of + reading. + + Also, this method processed the policy of operating with the + received symbol, in which the parity or frame error is detected. +*/ +qint64 UnixSerialPortEngine::read(char *data, qint64 len) +{ + qint64 bytesRead = 0; +#if defined (CMSPAR) + if ((m_parent->m_parity == SerialPort::NoParity) || (m_parent->m_policy != SerialPort::StopReceivingPolicy)) +#else + if ((m_parent->m_parity != SerialPort::MarkParity) && (m_parent->m_parity != SerialPort::SpaceParity)) +#endif + bytesRead = ::read(m_descriptor, data, len); + else // Perform parity emulation. + bytesRead = readPerChar(data, len); + + // 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; +#if defined (Q_OS_SYMBIAN) + case EPIPE: +#endif + case ECONNRESET: +#if defined (Q_OS_VXWORKS) + case ESHUTDOWN: +#endif + bytesRead = 0; + break; + default:; + } + // FIXME: Here need call errno + // and set error type? + if (bytesRead == -1) + m_parent->setError(SerialPort::IoError); + } + return bytesRead; +} + +/*! + Write \a data to serial port. If successful, returns the + real number of bytes write, which can be less than the + requested \a len; otherwise returned -1 with set error code. + + Some platforms do not support the mark or space parity, so + running software emulation of these modes in the process of + writting. +*/ +qint64 UnixSerialPortEngine::write(const char *data, qint64 len) +{ + qint64 bytesWritten = 0; +#if defined (CMSPAR) + bytesWritten = ::write(m_descriptor, data, len); +#else + if ((m_parent->m_parity != SerialPort::MarkParity) && (m_parent->m_parity != SerialPort::SpaceParity)) + bytesWritten = ::write(m_descriptor, data, len); + else // Perform parity emulation. + bytesWritten = writePerChar(data, len); +#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:; + } + // FIXME: Here need call errno + // and set error type? + if (bytesWritten == -1) + m_parent->setError(SerialPort::IoError); + } + return bytesWritten; +} + +/*! + Implements a function blocking for waiting of events on the + \a timeout in millisecond, those listed in fdread will be watched + to see if characters become available for reading (more precisely, + to see if a read will not block; in particular, a file descriptor + is also ready on end-of-file), those in fdwrite will be watched + to see if a write will not block. + + Event fdread controlled, if the flag \a checkRead is set on true, + and fdwrite wehn flag \a checkWrite is set on true. The result + of catch in each of the events, save to the corresponding + variables \a selectForRead and \a selectForWrite. + + Returns true if the occurrence of any event before the timeout; + otherwise returns false. +*/ +bool UnixSerialPortEngine::select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) +{ + fd_set fdread; + FD_ZERO(&fdread); + if (checkRead) + FD_SET(m_descriptor, &fdread); + + fd_set fdwrite; + FD_ZERO(&fdwrite); + if (checkWrite) + FD_SET(m_descriptor, &fdwrite); + + struct timeval tv; + tv.tv_sec = (timeout / 1000); + tv.tv_usec = (timeout % 1000) * 1000; + + if (::select(m_descriptor + 1, &fdread, &fdwrite, 0, (timeout < 0) ? 0 : &tv) <= 0) { + Q_ASSERT(selectForRead); + *selectForRead = false; + Q_ASSERT(selectForWrite); + *selectForWrite = false; + return false; + } + + if (checkRead) { + Q_ASSERT(selectForRead); + *selectForRead = FD_ISSET(m_descriptor, &fdread); + } + + if (checkWrite) { + Q_ASSERT(selectForWrite); + *selectForWrite = FD_ISSET(m_descriptor, &fdwrite); + } + return true; +} + +#if defined (Q_OS_MAC) +static const QString defaultPathPrefix = QLatin1String("/dev/cu."); +static const QString notUsedPathPrefix = QLatin1String("/dev/tty."); +#else +static const QString defaultPathPrefix = QLatin1String("/dev/"); +#endif + +/*! + Converts a platform specific \a port name to system location + and return result. +*/ +QString UnixSerialPortEngine::toSystemLocation(const QString &port) const +{ + QString ret = port; + +#if defined (Q_OS_MAC) + ret.remove(notUsedPathPrefix); +#endif + + if (!ret.contains(defaultPathPrefix)) + ret.prepend(defaultPathPrefix); + return ret; +} + +/*! + Converts a platform specific system \a location to port name + and return result. +*/ +QString UnixSerialPortEngine::fromSystemLocation(const QString &location) const +{ + QString ret = location; + +#if defined (Q_OS_MAC) + ret.remove(notUsedPathPrefix); +#endif + + ret.remove(defaultPathPrefix); + return ret; +} + +// Returned -1 if rate it is custom baud +// otherwise returned unix speed as speed_t. +static qint32 detect_standard_rate(qint32 rate) +{ + switch (rate) { +#if defined (B0) + case 0: + return B0; +#endif +#if defined (B50) + case 50: + return B50; +#endif +#if defined (B75) + case 75: + return B75; +#endif +#if defined (B110) + case 110: + return B110; +#endif +#if defined (B134) + case 134: + return B134; +#endif +#if defined (B150) + case 150: + return B150; +#endif +#if defined (B200) + case 200: + return B200; +#endif +#if defined (B300) + case 300: + return B300; +#endif +#if defined (B600) + case 600: + return B600; +#endif +#if defined (B1200) + case 1200: + return B1200; +#endif +#if defined (B1800) + case 1800: + return B1800; +#endif +#if defined (B2400) + case 2400: + return B2400; +#endif +#if defined (B4800) + case 4800: + return B4800; +#endif +#if defined (B9600) + case 9600: + return B9600; +#endif +#if defined (B19200) + case 19200: + return B19200; +#endif +#if defined (B38400) + case 38400: + return B38400; +#endif +#if defined (B57600) + case 57600: + return B57600; +#endif +#if defined (B115200) + case 115200: + return B115200; +#endif +#if defined (B230400) + case 230400: + return B230400; +#endif +#if defined (B460800) + case 460800: + return B460800; +#endif +#if defined (B500000) + case 500000: + return B500000; +#endif +#if defined (B576000) + case 576000: + return B576000; +#endif +#if defined (B921600) + case 921600: + return B921600; +#endif +#if defined (B1000000) + case 1000000: + return B1000000; +#endif +#if defined (B1152000) + case 1152000: + return B1152000; +#endif +#if defined (B1500000) + case 1500000: + return B1500000; +#endif +#if defined (B2000000) + case 2000000: + return B2000000; +#endif +#if defined (B2500000) + case 2500000: + return B2500000; +#endif +#if defined (B3000000) + case 3000000: + return B3000000; +#endif +#if defined (B3500000) + case 3500000: + return B3500000; +#endif +#if defined (B4000000) + case 4000000: + return B4000000; +#endif + default: + return -1; + } +} + +/*! + Set desired \a rate by given direction \a dir, + where \a rate is expressed by any positive integer type qint32. + The method attempts to analyze the type of the desired speed: + standard or custom, and the results of the analysis trying to + install it using the corresponding internal function + setCustomRate() or setStandartRate(). + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) +{ + qint32 detectedRate = detect_standard_rate(rate); + bool ret = false; + if (detectedRate == -1) + ret = setCustomRate(rate); + else + ret = setStandartRate(dir, detectedRate); + + if (!ret) + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return ret; +} + +/*! + Set desired number of data bits \a dataBits in byte. POSIX + native supported all present number of data bits 5, 6, 7, 8. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) +{ + m_currTermios.c_cflag &= (~CSIZE); + switch (dataBits) { + case SerialPort::Data5: + m_currTermios.c_cflag |= CS5; + break; + case SerialPort::Data6: + m_currTermios.c_cflag |= CS6; + break; + case SerialPort::Data7: + m_currTermios.c_cflag |= CS7; + break; + case SerialPort::Data8: + m_currTermios.c_cflag |= CS8; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateTermios(); +} + +/*! + Set desired \a parity control mode. POSIX native not supported + modes mark and space, so is their software emulation in the + methods read() and write(). But, in particular, some GNU/Linux + has hardware support for these modes, therefore, no need to + emulate. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::setParity(SerialPort::Parity parity) +{ + m_currTermios.c_iflag &= ~(PARMRK | INPCK); + m_currTermios.c_iflag |= IGNPAR; + + switch (parity) { + +#if defined (CMSPAR) + // Here Installation parity only for GNU/Linux where the macro CMSPAR. + case SerialPort::SpaceParity: + m_currTermios.c_cflag &= (~PARODD); + m_currTermios.c_cflag |= (PARENB | CMSPAR); + break; + case SerialPort::MarkParity: + m_currTermios.c_cflag |= (PARENB | CMSPAR | PARODD); + break; +#endif + case SerialPort::NoParity: + m_currTermios.c_cflag &= (~PARENB); + break; + case SerialPort::EvenParity: + m_currTermios.c_cflag &= (~PARODD); + m_currTermios.c_cflag |= PARENB; + break; + case SerialPort::OddParity: + m_currTermios.c_cflag |= (PARENB | PARODD); + break; + default: + m_currTermios.c_cflag |= PARENB; + m_currTermios.c_iflag |= (PARMRK | INPCK); + m_currTermios.c_iflag &= ~IGNPAR; + break; + } + + return updateTermios(); +} + +/*! + Set desired number of stop bits \a stopBits in frame. POSIX + native supported only 1, 2 number of stop bits. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) +{ + switch (stopBits) { + case SerialPort::OneStop: + m_currTermios.c_cflag &= (~CSTOPB); + break; + case SerialPort::TwoStop: + m_currTermios.c_cflag |= CSTOPB; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateTermios(); +} + +/*! + Set desired \a flow control mode. POSIX native supported all + present flow control modes no control, hardware (RTS/CTS), + software (XON/XOFF). + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool UnixSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) +{ + switch (flow) { + case SerialPort::NoFlowControl: + m_currTermios.c_cflag &= (~CRTSCTS); + m_currTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); + break; + case SerialPort::HardwareControl: + m_currTermios.c_cflag |= CRTSCTS; + m_currTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); + break; + case SerialPort::SoftwareControl: + m_currTermios.c_cflag &= (~CRTSCTS); + m_currTermios.c_iflag |= (IXON | IXOFF | IXANY); + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateTermios(); +} + +/*! + Set desired char error \a policy when errors are detected + frame or parity. +*/ +bool UnixSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) +{ + tcflag_t parmrkMask = PARMRK; +#ifndef CMSPAR + //in space/mark parity emulation also used PARMRK flag + if (m_parent->m_parity == SerialPort::SpaceParity || m_parent->m_parity == SerialPort::MarkParity) + parmrkMask = 0; +#endif //CMSPAR + switch(policy) { + case SerialPort::SkipPolicy: + m_currTermios.c_iflag &= ~parmrkMask; + m_currTermios.c_iflag |= IGNPAR | INPCK; + break; + case SerialPort::PassZeroPolicy: + m_currTermios.c_iflag &= ~(IGNPAR | parmrkMask); + m_currTermios.c_iflag |= INPCK; + break; + case SerialPort::IgnorePolicy: + m_currTermios.c_iflag &= ~INPCK; + break; + case SerialPort::StopReceivingPolicy: + m_currTermios.c_iflag &= ~IGNPAR; + m_currTermios.c_iflag |= (parmrkMask | INPCK); + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateTermios(); +} + +/*! + Returns the current status of the read notification subsystem. +*/ +bool UnixSerialPortEngine::isReadNotificationEnabled() const +{ + return (m_readNotifier && m_readNotifier->isEnabled()); +} + +/*! + Enables or disables read notification subsystem, depending on + the \a enable parameter. If the subsystem is enabled, it will + asynchronously track the occurrence of an event fdread. + Thanks to that, SerialPort can emit a signal readyRead() and + fill up the internal receive buffer with new data, that + automatically received from a serial port in the event loop. +*/ +void UnixSerialPortEngine::setReadNotificationEnabled(bool enable) +{ + if (m_readNotifier) + m_readNotifier->setEnabled(enable); + else if (enable) { + m_readNotifier = + new QSocketNotifier(m_descriptor, QSocketNotifier::Read, this); + + m_readNotifier->installEventFilter(this); + m_readNotifier->setEnabled(true); + } +} + +/*! + Returns the current status of the write notification subsystem. +*/ +bool UnixSerialPortEngine::isWriteNotificationEnabled() const +{ + return (m_writeNotifier && m_writeNotifier->isEnabled()); +} + +/*! + Enables or disables write notification subsystem, depending on + the \a enable parameter. If the subsystem is enabled, it will + asynchronously track the occurrence of an event fdwrite. + Thanks to that, SerialPort can write data from internal transfer + buffer, to serial port automatically in the event loop. +*/ +void UnixSerialPortEngine::setWriteNotificationEnabled(bool enable) +{ + if (m_writeNotifier) + m_writeNotifier->setEnabled(enable); + else if (enable) { + m_writeNotifier = + new QSocketNotifier(m_descriptor, QSocketNotifier::Write, this); + + m_writeNotifier->installEventFilter(this); + m_writeNotifier->setEnabled(true); + } +} + +/*! + Not used in POSIX implementation, error handling is carried + out in other ways. + + Always returned false. +*/ +bool UnixSerialPortEngine::processIOErrors() +{ + // No need impl. + return false; +} + +/// + +/* Protected methods */ + +// Convert unix rate as speed_t to +// really value as qint32. +static qint32 unixrate2valuerate(speed_t unixrate) +{ + qint32 ret = SerialPort::UnknownRate; + + switch (unixrate) { +#if defined (B50) + case B50: + ret = 50; + break; +#endif +#if defined (B75) + case B75: + ret = 75; + break; +#endif +#if defined (B110) + case B110: + ret = 110; + break; +#endif +#if defined (B134) + case B134: + ret = 134; + break; +#endif +#if defined (B150) + case B150: + ret = 150; + break; +#endif +#if defined (B200) + case B200: + ret = 200; + break; +#endif +#if defined (B300) + case B300: + ret = 300; + break; +#endif +#if defined (B600) + case B600: + ret = 600; + break; +#endif +#if defined (B1200) + case B1200: + ret = 1200; + break; +#endif +#if defined (B1800) + case B1800: + ret = 1800; + break; +#endif +#if defined (B2400) + case B2400: + ret = 2400; + break; +#endif +#if defined (B4800) + case B4800: + ret = 4800; + break; +#endif +#if defined (B9600) + case B9600: + ret = 9600; + break; +#endif +#if defined (B19200) + case B19200: + ret = 19200; + break; +#endif +#if defined (B38400) + case B38400: + ret = 38400; + break; +#endif +#if defined (B57600) + case B57600: + ret = 57600; + break; +#endif +#if defined (B115200) + case B115200: + ret = 115200; + break; +#endif +#if defined (B230400) + case B230400: + ret = 230400; + break; +#endif +#if defined (B460800) + case B460800: + ret = 460800; + break; +#endif +#if defined (B500000) + case B500000: + ret = 500000; + break; +#endif +#if defined (B576000) + case B576000: + ret = 576000; + break; +#endif +#if defined (B921600) + case B921600: + ret = 921600; + break; +#endif +#if defined (B1000000) + case B1000000: + ret = 1000000; + break; +#endif +#if defined (B1152000) + case B1152000: + ret = 1152000; + break; +#endif +#if defined (B1500000) + case B1500000: + ret = 1500000; + break; +#endif +#if defined (B2000000) + case B2000000: + ret = 2000000; + break; +#endif +#if defined (B2500000) + case B2500000: + ret = 2500000; + break; +#endif +#if defined (B3000000) + case B3000000: + ret = 3000000; + break; +#endif +#if defined (B3500000) + case B3500000: + ret = 3500000; + break; +#endif +#if defined (B4000000) + case B4000000: + ret = 4000000; + break; +#endif + default:; + } + return ret; +} + +/*! + Attempts to determine the current settings of the serial port, + wehn it opened. Used only in the method open(). +*/ +void UnixSerialPortEngine::detectDefaultSettings() +{ + // Detect rate. + m_parent->m_inRate = unixrate2valuerate(::cfgetispeed(&m_currTermios)); + m_parent->m_outRate = unixrate2valuerate(::cfgetospeed(&m_currTermios)); + + // Detect databits. + switch (m_currTermios.c_cflag & CSIZE) { + case CS5: + m_parent->m_dataBits = SerialPort::Data5; + break; + case CS6: + m_parent->m_dataBits = SerialPort::Data6; + break; + case CS7: + m_parent->m_dataBits = SerialPort::Data7; + break; + case CS8: + m_parent->m_dataBits = SerialPort::Data8; + break; + default: + m_parent->m_dataBits = SerialPort::UnknownDataBits; + } + + // Detect parity. +#if defined (CMSPAR) + if (m_currTermios.c_cflag & CMSPAR) { + m_parent->m_parity = (m_currTermios.c_cflag & PARODD) ? + SerialPort::MarkParity : SerialPort::SpaceParity; + } else { +#endif + if (m_currTermios.c_cflag & PARENB) { + m_parent->m_parity = (m_currTermios.c_cflag & PARODD) ? + SerialPort::OddParity : SerialPort::EvenParity; + } else + m_parent->m_parity = SerialPort::NoParity; +#if defined (CMSPAR) + } +#endif + + // Detect stopbits. + m_parent->m_stopBits = (m_currTermios.c_cflag & CSTOPB) ? + SerialPort::TwoStop : SerialPort::OneStop; + + // Detect flow control. + if ((!(m_currTermios.c_cflag & CRTSCTS)) && (!(m_currTermios.c_iflag & (IXON | IXOFF | IXANY)))) + m_parent->m_flow = SerialPort::NoFlowControl; + else if ((!(m_currTermios.c_cflag & CRTSCTS)) && (m_currTermios.c_iflag & (IXON | IXOFF | IXANY))) + m_parent->m_flow = SerialPort::SoftwareControl; + else if ((m_currTermios.c_cflag & CRTSCTS) && (!(m_currTermios.c_iflag & (IXON | IXOFF | IXANY)))) + m_parent->m_flow = SerialPort::HardwareControl; + else + m_parent->m_flow = SerialPort::UnknownFlowControl; + + //detect error policy + if (m_currTermios.c_iflag & INPCK) { + if (m_currTermios.c_iflag & IGNPAR) + m_parent->m_policy = SerialPort::SkipPolicy; + else if (m_currTermios.c_iflag & PARMRK) + m_parent->m_policy = SerialPort::StopReceivingPolicy; + else + m_parent->m_policy = SerialPort::PassZeroPolicy; + } else { + m_parent->m_policy = SerialPort::IgnorePolicy; + } +} + +/*! + POSIX event loop for notification subsystem. + Asynchronously in event loop continuous mode tracking the + events from the serial port, as: fderror, fdread, fdwrite. + When is occur a relevant event, calls him handler from + a parent class SerialPortPrivate. +*/ +bool UnixSerialPortEngine::eventFilter(QObject *obj, QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + if (obj == m_readNotifier) { + m_parent->canReadNotification(); + return true; + } + if (obj == m_writeNotifier) { + m_parent->canWriteNotification(); + return true; + } + if (obj == m_exceptionNotifier) { + m_parent->canErrorNotification(); + return true; + } + } + return QObject::eventFilter(obj, e); +} + +/* Private methods */ + +/*! + Updates the termios structure wehn changing of any the + parameters a serial port. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::updateTermios() +{ + if (::tcsetattr(m_descriptor, TCSANOW, &m_currTermios) == -1) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return true; +} + +/*! + Set only standard serial port \a rate as speed_t by given + deirection \a dir. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::setStandartRate(SerialPort::Directions dir, speed_t rate) +{ + if (((dir & SerialPort::Input) && (::cfsetispeed(&m_currTermios, rate) == -1)) + || ((dir & SerialPort::Output) && (::cfsetospeed(&m_currTermios, rate) == -1))) { + return false; + } + return updateTermios(); +} + +/*! + Attempts to set desired the custom \a rate as qint32. Not all + POSIX-compatible platforms support this feature, at least for + GNU/Linux and MacOSX is possible. + + If successful, returns true; otherwise false. +*/ +bool UnixSerialPortEngine::setCustomRate(qint32 rate) +{ + int result = -1; +#if defined (Q_OS_LINUX) + +# if defined (TIOCGSERIAL) && defined (TIOCSSERIAL) + if (rate > 0) { + struct serial_struct ser_info; + result = ::ioctl(m_descriptor, TIOCGSERIAL, &ser_info); + if (result != -1) { + ser_info.flags &= ~ASYNC_SPD_MASK; + ser_info.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + ser_info.custom_divisor = ser_info.baud_base / rate; + if (ser_info.custom_divisor) + result = ::ioctl(m_descriptor, TIOCSSERIAL, &ser_info); + } + } +# endif + +#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. + result = ::ioctl(m_descriptor, IOSSIOSPEED, &rate); +# endif + +#else + Q_UNUSED(rate); +#endif + return (result != -1); +} + +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) +} + +#if !defined (CMSPAR) + +/*! + For platforms that do not have the support of parities mark and space + performed character by character emulation data transmitted, that + one by one character is written to the port. +*/ +qint64 UnixSerialPortEngine::writePerChar(const char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - m_parent->m_dataBits)); + + while (ret < maxSize) { + + bool par = evenParity(*data & charMask); + // False if need EVEN, true if need ODD. + par ^= (m_parent->m_parity == SerialPort::MarkParity); + if (par ^ bool(m_currTermios.c_cflag & PARODD)) { // Need switch parity mode? + m_currTermios.c_cflag ^= PARODD; + flush(); //force sending already buffered data, because updateTermios() cleares buffers + //todo: add receiving buffered data!!! + if (!updateTermios()) + break; + } + + int r = ::write(m_descriptor, data, 1); + if (r < 0) + return -1; + if (r > 0) { + data += r; + ret += r; + } + } + return ret; +} + +#endif //CMSPAR + +/*! + Platforms which does not have the support for mark and space parity checking + requires emulation using character by character data receiving. +*/ +qint64 UnixSerialPortEngine::readPerChar(char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - m_parent->m_dataBits)); + + // 0 - prefix not started, + // 1 - received 0xFF, + // 2 - received 0xFF and 0x00 + int prefix = 0; + while (ret < maxSize) { + + qint64 r = ::read(m_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 ^= bool(m_currTermios.c_cflag & PARODD); //par contains parity bit value for current mode + if (par ^ bool(m_parent->m_parity == SerialPort::SpaceParity)) { //if parity error + switch(m_parent->m_policy) { + case SerialPort::SkipPolicy: + continue; //ignore received character + case SerialPort::StopReceivingPolicy: + if (m_parent->m_parity != SerialPort::NoParity) + m_parent->m_portError = SerialPort::ParityError; + else + m_parent->m_portError = (*data == '\0') ? SerialPort::BreakConditionError : SerialPort::FramingError; + return ++ret; //abort receiving + break; + case SerialPort::UnknownPolicy: + qWarning() << "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; +} + +// From +SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) +{ + return new UnixSerialPortEngine(parent); +} + +#include "moc_serialportengine_unix_p.cpp" + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialportengine_unix_p.h b/src/serialportengine_unix_p.h new file mode 100644 index 0000000..78af7b7 --- /dev/null +++ b/src/serialportengine_unix_p.h @@ -0,0 +1,91 @@ +/* + License... +*/ + +#ifndef SERIALPORTENGINE_UNIX_P_H +#define SERIALPORTENGINE_UNIX_P_H + +#include "serialport.h" +#include "serialportengine_p.h" + +#include +//# undef CMSPAR + +class QSocketNotifier; + +QT_BEGIN_NAMESPACE_SERIALPORT + +class UnixSerialPortEngine : public QObject, public SerialPortEngine +{ + Q_OBJECT +public: + UnixSerialPortEngine(SerialPortPrivate *parent); + virtual ~UnixSerialPortEngine(); + + virtual bool open(const QString &location, QIODevice::OpenMode mode); + virtual void close(const QString &location); + + virtual SerialPort::Lines lines() const; + + virtual bool setDtr(bool set); + virtual bool setRts(bool set); + + virtual bool flush(); + virtual bool reset(); + + virtual bool sendBreak(int duration); + virtual bool setBreak(bool set); + + virtual qint64 bytesAvailable() const; + virtual qint64 bytesToWrite() const; + + virtual qint64 read(char *data, qint64 len); + virtual qint64 write(const char *data, qint64 len); + virtual bool select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite); + + virtual QString toSystemLocation(const QString &port) const; + virtual QString fromSystemLocation(const QString &location) const; + + virtual bool setRate(qint32 rate, SerialPort::Directions dir); + virtual bool setDataBits(SerialPort::DataBits dataBits); + virtual bool setParity(SerialPort::Parity parity); + virtual bool setStopBits(SerialPort::StopBits stopBits); + virtual bool setFlowControl(SerialPort::FlowControl flowControl); + + virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); + + virtual bool isReadNotificationEnabled() const; + virtual void setReadNotificationEnabled(bool enable); + virtual bool isWriteNotificationEnabled() const; + virtual void setWriteNotificationEnabled(bool enable); + + virtual bool processIOErrors(); + +protected: + virtual void detectDefaultSettings(); + virtual bool eventFilter(QObject *obj, QEvent *e); + +private: + struct termios m_currTermios; + struct termios m_oldTermios; + int m_descriptor; + + QSocketNotifier *m_readNotifier; + QSocketNotifier *m_writeNotifier; + QSocketNotifier *m_exceptionNotifier; + + bool updateTermios(); + bool setStandartRate(SerialPort::Directions dir, speed_t rate); + bool setCustomRate(qint32 rate); + +#if !defined (CMSPAR) + qint64 writePerChar(const char *data, qint64 maxSize); +#endif + qint64 readPerChar(char *data, qint64 maxSize); +}; + +QT_END_NAMESPACE_SERIALPORT + +#endif // SERIALPORTENGINE_UNIX_P_H diff --git a/src/serialportengine_win.cpp b/src/serialportengine_win.cpp new file mode 100644 index 0000000..b2b87d6 --- /dev/null +++ b/src/serialportengine_win.cpp @@ -0,0 +1,1305 @@ +/* + License... +*/ + +/*! + \class WinSerialPortEngine + \internal + + \brief The WinSerialPortEngine class provides windows OS + platform-specific low level access to a serial port. + + \reentrant + \ingroup serial + \inmodule QSerialDevice + + Currently the class supports as NT-based OS (Win 2K/XP/Vista/7), + and as various embedded WinCE. + + WinSerialPortEngine (as well as other platform-dependent engines) + is a class with multiple inheritance, which on the one hand, + derives from a general abstract class interface SerialPortEngine, + on the other hand of a class inherited from QObject. + + From the abstract class SerialPortEngine, it inherits all virtual + interface methods that are common to all serial ports on any platform. + These methods, the class WinSerialPortEngine implements on the OS + Windows platform, using a corresponding Win API. + + From QObject-like class, it inherits a specific system Qt features. + For example, for NT-based platforms WinSerialPortEngine uses private + Qt class QWinEventNotifier. Thanks to this class, it have the + opportunity to asynchronously track the events from the serial port, + such as the appearance of a character in the receive buffer, + error I/O, and etc. Ie events are handled in Qt core in its event + loop, so no need to create additional threads to perform these + operations. However, for embedded systems, this approach does not work, + because they have a another Win API. In this case, WinSerialPortEngine + is derived from QThread and creates an additional thread to keep track + of events. + + That is, as seen from the above, the functional WinSerialPortEngine + completely covers all the necessary tasks. +*/ + +#include "serialportengine_win_p.h" + +#include +#if !defined (Q_OS_WINCE) +# include +#endif +//#include + +#ifndef Q_CC_MSVC +# include +#else + +# 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 + +#endif + +QT_BEGIN_NAMESPACE_SERIALPORT + +/* Public methods */ + +/*! + Constructs a WinSerialPortEngine with \a parent and + initializes all the internal variables of the initial values. + + A pointer \a parent to the object class SerialPortPrivate + is required for the recursive call some of its methods. +*/ +WinSerialPortEngine::WinSerialPortEngine(SerialPortPrivate *parent) + : m_descriptor(INVALID_HANDLE_VALUE) + , m_flagErrorFromCommEvent(false) + , m_currentMask(0) + , m_setMask(EV_ERR) + #if defined (Q_OS_WINCE) + , m_running(true) + #endif +{ + Q_ASSERT(parent); + m_parent = parent; + size_t size = sizeof(DCB); + ::memset(&m_currDCB, 0, size); + ::memset(&m_oldDCB, 0, size); + size = sizeof(COMMTIMEOUTS); + ::memset(&m_currCommTimeouts, 0, size); + ::memset(&m_oldCommTimeouts, 0, size); + +#if !defined (Q_OS_WINCE) + size = sizeof(OVERLAPPED); + ::memset(&m_ovRead, 0, size); + ::memset(&m_ovWrite, 0, size); + ::memset(&m_ovSelect, 0, size); + ::memset(&m_ov, 0, size); +#endif +} + +/*! + Stops the tracking events of the serial port and + destructs a WinSerialPortEngine. +*/ +WinSerialPortEngine::~WinSerialPortEngine() +{ +#if defined (Q_OS_WINCE) + m_running = false; + ::SetCommMask(m_descriptor, 0); + //terminate(); + wait(); +#else + setEnabled(false); +#endif +} + +/*! + Tries to open the handle desired serial port by \a location in the + given open \a mode. In the process of discovery, always set a + serial port in non-blocking mode (when the read operation returns + immediately) and tries to determine its current configuration and + install them. + + It should be noted the following features that Windows performs + when using the serial port: + - support only binary transfers mode + - always open in exclusive mode + + For Windows NT-based platforms, the serial port is opened in the + overlapped mode, with flag FILE_FLAG_OVERLAPPED. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::open(const QString &location, QIODevice::OpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD shareMode = 0; + DWORD flagsAndAttributes = 0; + bool rxflag = false; + bool txflag = false; + +#if !defined (Q_OS_WINCE) + flagsAndAttributes |= FILE_FLAG_OVERLAPPED; +#endif + + if (mode & QIODevice::ReadOnly) { + desiredAccess |= GENERIC_READ; + //shareMode = FILE_SHARE_READ; + rxflag = true; + } + if (mode & QIODevice::WriteOnly) { + desiredAccess |= GENERIC_WRITE; + //shareMode = FILE_SHARE_WRITE; + txflag = true; + } + + QByteArray filePath = QByteArray((const char *)location.utf16(), + location.size() * 2 + 1); + + // Try opened serial device. + m_descriptor = ::CreateFile((const wchar_t*)filePath.constData(), + desiredAccess, shareMode, 0, OPEN_EXISTING, flagsAndAttributes, 0); + + if (m_descriptor == INVALID_HANDLE_VALUE) { + switch (::GetLastError()) { + case ERROR_FILE_NOT_FOUND: + m_parent->setError(SerialPort::NoSuchDeviceError); + break; + case ERROR_ACCESS_DENIED: + m_parent->setError(SerialPort::PermissionDeniedError); + break; + default: + m_parent->setError(SerialPort::UnknownPortError); + } + return false; + } + + // Save current DCB port settings. + DWORD confSize = sizeof(DCB); + if (::GetCommState(m_descriptor, &m_oldDCB) == 0) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + ::memcpy(&m_currDCB, &m_oldDCB, confSize); + + // Set other DCB port options. + m_currDCB.fBinary = true; + m_currDCB.fInX = false; + m_currDCB.fOutX = false; + m_currDCB.fAbortOnError = false; + m_currDCB.fNull = false; + m_currDCB.fErrorChar = false; + + // Apply new DCB init settings. + if (!updateDcb()) + return false; + + // Save current port timeouts. + confSize = sizeof(COMMTIMEOUTS); + if (::GetCommTimeouts(m_descriptor, &m_oldCommTimeouts) == 0) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } + ::memcpy(&m_currCommTimeouts, &m_oldCommTimeouts, confSize); + + // Set new port timeouts. + ::memset(&m_currCommTimeouts, 0, confSize); + m_currCommTimeouts.ReadIntervalTimeout = MAXDWORD; + + // Apply new port timeouts. + if (!updateCommTimeouts()) + return false; + +#if !defined (Q_OS_WINCE) + if (!createEvents(rxflag, txflag)) { + m_parent->setError(SerialPort::UnknownPortError); + return false; + } +#endif + + detectDefaultSettings(); + return true; +} + +/*! + Closes a serial port handle. Before closing - restore previous + serial port settings if necessary. +*/ +void WinSerialPortEngine::close(const QString &location) +{ + Q_UNUSED(location); + +#if !defined (Q_OS_WINCE) + ::CancelIo(m_descriptor); +#endif + + if (m_parent->m_restoreSettingsOnClose) { + ::SetCommState(m_descriptor, &m_oldDCB); + ::SetCommTimeouts(m_descriptor, &m_oldCommTimeouts); + } + + ::CloseHandle(m_descriptor); + +#if !defined (Q_OS_WINCE) + closeEvents(); +#endif + m_descriptor = INVALID_HANDLE_VALUE; +} + +/*! + Returns a bitmap state of RS-232 line signals. On error, + bitmap will be empty (equal zero). + + Win API allows you to receive only the state of signals: + CTS, DSR, RING, DCD, DTR, RTS. Other signals are not available. +*/ +SerialPort::Lines WinSerialPortEngine::lines() const +{ + DWORD modemStat = 0; + SerialPort::Lines ret = 0; + + if (::GetCommModemStatus(m_descriptor, &modemStat) == 0) { + // Print error? + 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(m_descriptor, IOCTL_SERIAL_GET_DTRRTS, 0, 0, + &modemStat, sizeof(DWORD), + &bytesReturned, 0)) { + + if (modemStat & SERIAL_DTR_STATE) + ret |= SerialPort::Dtr; + if (modemStat & SERIAL_RTS_STATE) + ret |= SerialPort::Rts; + } + + return ret; +} + +/*! + Set DTR signal to state \a set. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::setDtr(bool set) +{ + bool ret = ::EscapeCommFunction(m_descriptor, (set) ? SETDTR : CLRDTR); + if (!ret) { + // FIXME: Here need call ::GetLastError() + // and set error type. + } + return ret; +} + +/*! + Set RTS signal to state \a set. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::setRts(bool set) +{ + bool ret = ::EscapeCommFunction(m_descriptor, (set) ? SETRTS : CLRRTS); + if (!ret) { + // FIXME: Here need call ::GetLastError() + // and set error type. + } + return ret; +} + +/*! + Flushes the buffers of a specified serial port and + causes all buffered data to be written to a serial port. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::flush() +{ + bool ret = ::FlushFileBuffers(m_descriptor); + if (!ret) { + // FIXME: Here need call ::GetLastError() + // and set error type. + } + return ret; +} + +/*! + Discards all characters from the output or input buffer of + a specified communications resource. It can also terminate + pending read or write operations on the resource. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::reset() +{ + DWORD flags = (PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); + bool ret = ::PurgeComm(m_descriptor, flags); + if (!ret) { + // FIXME: Here need call ::GetLastError() + // and set error type. + } + return ret; +} + +/*! + Sends a continuous stream of zero bits during a specified + period of time \a duration in msec. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::sendBreak(int duration) +{ + // FIXME: + if (setBreak(true)) { + ::Sleep(duration); + if (setBreak(false)) + return true; + } + return false; +} + +/*! + Restores or suspend character transmission and places the + transmission line in a nonbreak or break state, + depending on the parameter \a set. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::setBreak(bool set) +{ + bool ret = (set) ? + (::SetCommBreak(m_descriptor)) : (::ClearCommBreak(m_descriptor)); + if (!ret) { + // FIXME: Here need call ::GetLastError() + // and set error type. + } + return ret; +} + +enum CommStatQue { CS_IN_QUE, CS_OUT_QUE }; +static qint64 get_commstat_que(HANDLE descriptor, enum CommStatQue que) +{ + DWORD err; + COMSTAT cs; + if (::ClearCommError(descriptor, &err, &cs) == 0) + return -1; + return qint64((que == CS_IN_QUE) ? (cs.cbInQue) : (cs.cbOutQue)); +} + +/*! + Returns the number of bytes received by the serial provider + but not yet read by a read() operation. Also it clears the + device's error flag to enable additional input and output + (I/O) operations. + + If successful, returns true; otherwise false. +*/ +qint64 WinSerialPortEngine::bytesAvailable() const +{ + return get_commstat_que(m_descriptor, CS_IN_QUE); +} + +/*! + Returns the number of bytes of user data remaining to be + transmitted for all write operations. This value will be zero + for a nonoverlapped write (for embedded platform as WinCE). + Also it clears the device's error flag to enable additional + input and output (I/O) operations. + + If successful, returns true; otherwise false. +*/ +qint64 WinSerialPortEngine::bytesToWrite() const +{ + return get_commstat_que(m_descriptor, CS_OUT_QUE); +} + +#if !defined (Q_OS_WINCE) +// Clear overlapped structure, but does not affect the event. +static void clear_overlapped(OVERLAPPED *overlapped) +{ + overlapped->Internal = 0; + overlapped->InternalHigh = 0; + overlapped->Offset = 0; + overlapped->OffsetHigh = 0; +} +#endif + +/*! + Read data from serial port. For NT-based platform, process + data's reading with the waiting wehn of pending I/O + operations is complete. Maybe this can cause some freezes. + + If successful, returns to the external buffer \a data the + real number of bytes read, which can be less than the + requested \a len; otherwise returned -1 with set error code. + + Also, this method processed the policy of operating with the + received symbol, in which the parity or frame error is detected. + This analysis and processing is executed by software-way in + this method. Parity or frame error flag determines subsystem + notification when it receives an event type EV_ERR. Since the + EV_ERR event appears before the event EV_RXCHAR, therefore, + we are able to handle errors by ordered, for each bad charachter + in this read method. This is true only when enabled the internal + read buffer of class SerialPort, ie when it is automatically + filled when the notification mode of reading is enabled. In + other cases, policy processing bad char is not guaranteed. +*/ +qint64 WinSerialPortEngine::read(char *data, qint64 len) +{ +#if !defined (Q_OS_WINCE) + clear_overlapped(&m_ovRead); +#endif + + DWORD readBytes = 0; + bool sucessResult = false; + + // FIXME: + if (m_parent->m_policy != SerialPort::IgnorePolicy) + len = 1; + +#if defined (Q_OS_WINCE) + sucessResult = ::ReadFile(m_descriptor, data, len, &readBytes, 0); +#else + if (::ReadFile(m_descriptor, data, len, &readBytes, &m_ovRead)) + sucessResult = true; + else { + if (::GetLastError() == ERROR_IO_PENDING) { + // FIXME: Instead of an infinite wait I/O (not looped), we expect, for example 5 seconds. + // Although, maybe there is a better solution. + switch (::WaitForSingleObject(m_ovRead.hEvent, 5000)) { + case WAIT_OBJECT_0: + if (::GetOverlappedResult(m_descriptor, &m_ovRead, &readBytes, false)) + sucessResult = true; + break; + default: ; + } + } + } +#endif + + if(!sucessResult) { + m_parent->setError(SerialPort::IoError); + return -1; + } + + // FIXME: Process emulate policy. + if (m_flagErrorFromCommEvent) { + m_flagErrorFromCommEvent = false; + + switch (m_parent->m_policy) { + case SerialPort::SkipPolicy: + return 0; + case SerialPort::PassZeroPolicy: + *data = '\0'; + break; + case SerialPort::StopReceivingPolicy: + break; + default:; + } + } + return qint64(readBytes); +} + +/*! + Write \a data to serial port. For NT-based platform, process + data's writing with the waiting wehn of pending I/O + operations is complete. Maybe this can cause some freezes. + + If successful, returns the real number of bytes write, which + can be less than the requested \a len; otherwise returned -1 + with set error code. +*/ +qint64 WinSerialPortEngine::write(const char *data, qint64 len) +{ +#if !defined (Q_OS_WINCE) + clear_overlapped(&m_ovWrite); +#endif + + DWORD writeBytes = 0; + bool sucessResult = false; + +#if defined (Q_OS_WINCE) + sucessResult = ::WriteFile(m_descriptor, data, len, &writeBytes, 0); +#else + if (::WriteFile(m_descriptor, data, len, &writeBytes, &m_ovWrite)) + sucessResult = true; + else { + if (::GetLastError() == ERROR_IO_PENDING) { + // Instead of an infinite wait I/O (not looped), we expect, for example 5 seconds. + // Although, maybe there is a better solution. + switch (::WaitForSingleObject(m_ovWrite.hEvent, 5000)) { + case WAIT_OBJECT_0: + if (::GetOverlappedResult(m_descriptor, &m_ovWrite, &writeBytes, false)) + sucessResult = true; + break; + default: ; + } + } + } +#endif + + if(!sucessResult) { + m_parent->setError(SerialPort::IoError); + return -1; + } + return quint64(writeBytes); +} + +/*! + Implements a function blocking for waiting of events EV_RXCHAR or + EV_TXEMPTY, on the \a timeout in millisecond. Event EV_RXCHAR + controlled, if the flag \a checkRead is set on true, and + EV_TXEMPTY wehn flag \a checkWrite is set on true. The result + of catch in each of the events, save to the corresponding + variables \a selectForRead and \a selectForWrite. + + For NT-based OS and embedded, this method have different + implementation. WinCE has no mechanism to exit out of a timeout, + therefore for this feature special class is used + WinCeWaitCommEventBreaker, without which it is locked to wait + forever in the absence of events EV_RXCHAR or EV_TXEMPTY. For + satisfactory operation of the breaker, the timeout should be + guaranteed a great, to the timer in the breaker does not trip + happen sooner than a function call WaitCommEvent(); otherwise it + will block forever (in the absence of events EV_RXCHAR or EV_TXEMPTY). + + Returns true if the occurrence of any event before the timeout; + otherwise returns false. +*/ +bool WinSerialPortEngine::select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) +{ + // Forward checking data for read. + if (checkRead && (bytesAvailable() > 0)) { + Q_ASSERT(selectForRead); + *selectForRead = true; + return true; + } + +#if !defined (Q_OS_WINCE) + clear_overlapped(&m_ovSelect); +#endif + + DWORD oldEventMask = 0; + DWORD currEventMask = 0; + + if (checkRead) + currEventMask |= EV_RXCHAR; + if (checkWrite) + currEventMask |= EV_TXEMPTY; + + // Save old mask. + if (::GetCommMask(m_descriptor, &oldEventMask) == 0) { + //Print error? + return false; + } + + // Checking the old mask bits as in the current mask. + // And if these bits are not exists, then add them and set the reting mask. + if (currEventMask != (oldEventMask & currEventMask)) { + currEventMask |= oldEventMask; + if (::SetCommMask(m_descriptor, currEventMask) == 0) { + //Print error? + return false; + } + } + + currEventMask = 0; + bool sucessResult = false; + +#if !defined (Q_OS_WINCE) + if (::WaitCommEvent(m_descriptor, &currEventMask, &m_ovSelect)) + sucessResult = true; + else { + if (::GetLastError() == ERROR_IO_PENDING) { + DWORD bytesTransferred = 0; + switch (::WaitForSingleObject(m_ovSelect.hEvent, (timeout < 0) ? 0 : timeout)) { + case WAIT_OBJECT_0: + if (::GetOverlappedResult(m_descriptor, &m_ovSelect, &bytesTransferred, false)) + sucessResult = true; + break; + default: ; + } + } + } +#else + // 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! + WinCeWaitCommEventBreaker breaker(m_descriptor, (timeout < 0) ? 0 : timeout); + ::WaitCommEvent(m_descriptor, &currEventMask, 0); + breaker.stop(); + sucessResult = !breaker.isWorked(); +#endif + + if (sucessResult) { + // Here call the bytesAvailable() to protect against false positives WaitForSingleObject(), + // for example, when manually pulling USB/Serial converter from system, + // ie when devices are in fact not. + // While it may be possible to make additional checks - to catch an event EV_ERR, + // adding (in the code above) extra bits in the mask currEventMask. + if (checkRead) { + Q_ASSERT(selectForRead); + *selectForRead = (currEventMask & EV_RXCHAR) && (bytesAvailable() > 0); + } + if (checkWrite) { + Q_ASSERT(selectForWrite); + *selectForWrite = (currEventMask & EV_TXEMPTY); + } + } + + // Rerair old mask. + ::SetCommMask(m_descriptor, oldEventMask); + return sucessResult; +} + +#if !defined (Q_OS_WINCE) +static const QString defaultPathPrefix = QLatin1String("\\\\.\\"); +#else +static const QString defaultPathPostfix = QLatin1String(":"); +#endif + +/*! + Converts a platform specific \a port name to system location + and return result. +*/ +QString WinSerialPortEngine::toSystemLocation(const QString &port) const +{ + QString ret = port; +#if !defined (Q_OS_WINCE) + if (!ret.contains(defaultPathPrefix)) + ret.prepend(defaultPathPrefix); +#else + if (!ret.contains(defaultPathPostfix)) + ret.append(defaultPathPostfix); +#endif + return ret; +} + +/*! + Converts a platform specific system \a location to port name + and return result. +*/ +QString WinSerialPortEngine::fromSystemLocation(const QString &location) const +{ + QString ret = location; +#if !defined (Q_OS_WINCE) + if (ret.contains(defaultPathPrefix)) + ret.remove(defaultPathPrefix); +#else + if (ret.contains(defaultPathPostfix)) + ret.remove(defaultPathPostfix); +#endif + return ret; +} + +/*! + Set desired \a rate by given direction \a dir. + However, windows does not support separate directions, so the + method will return an error. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::setRate(qint32 rate, SerialPort::Directions dir) +{ + if (dir != SerialPort::AllDirections) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + m_currDCB.BaudRate = DWORD(rate); + return updateDcb(); +} + +/*! + Set desired number of data bits \a dataBits in byte. Windows + native supported all present number of data bits 5, 6, 7, 8. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::setDataBits(SerialPort::DataBits dataBits) +{ + m_currDCB.ByteSize = BYTE(dataBits); + return updateDcb(); +} + +/*! + Set desired \a parity control mode. Windows native supported + all present parity types no parity, space, mark, even, odd. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::setParity(SerialPort::Parity parity) +{ + m_currDCB.fParity = true; + switch (parity) { + case SerialPort::NoParity: + m_currDCB.Parity = NOPARITY; + m_currDCB.fParity = false; + break; + case SerialPort::SpaceParity: + m_currDCB.Parity = SPACEPARITY; + break; + case SerialPort::MarkParity: + m_currDCB.Parity = MARKPARITY; + break; + case SerialPort::EvenParity: + m_currDCB.Parity = EVENPARITY; + break; + case SerialPort::OddParity: + m_currDCB.Parity = ODDPARITY; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateDcb(); +} + +/*! + Set desired number of stop bits \a stopBits in frame. + Windows native supported all present number of stop bits + 1, 1.5, 2. + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::setStopBits(SerialPort::StopBits stopBits) +{ + switch (stopBits) { + case SerialPort::OneStop: + m_currDCB.StopBits = ONESTOPBIT; + break; + case SerialPort::OneAndHalfStop: + m_currDCB.StopBits = ONE5STOPBITS; + break; + case SerialPort::TwoStop: + m_currDCB.StopBits = TWOSTOPBITS; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateDcb(); +} + +/*! + Set desired \a flow control mode. Windows native supported all + present flow control modes no control, hardware (RTS/CTS), + software (XON/XOFF). + + If successful, returns true; otherwise false, with the setup a + error code. +*/ +bool WinSerialPortEngine::setFlowControl(SerialPort::FlowControl flow) +{ + switch (flow) { + case SerialPort::NoFlowControl: + m_currDCB.fOutxCtsFlow = false; + m_currDCB.fRtsControl = RTS_CONTROL_DISABLE; + m_currDCB.fInX = m_currDCB.fOutX = false; + break; + case SerialPort::SoftwareControl: + m_currDCB.fOutxCtsFlow = false; + m_currDCB.fRtsControl = RTS_CONTROL_DISABLE; + m_currDCB.fInX = m_currDCB.fOutX = true; + break; + case SerialPort::HardwareControl: + m_currDCB.fOutxCtsFlow = true; + m_currDCB.fRtsControl = RTS_CONTROL_HANDSHAKE; + m_currDCB.fInX = m_currDCB.fOutX = false; + break; + default: + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return updateDcb(); +} + +/*! + Empty stub. Setting a variable is carried out methods in a + private class SerialPortPrivate. +*/ +bool WinSerialPortEngine::setDataErrorPolicy(SerialPort::DataErrorPolicy policy) +{ + Q_UNUSED(policy) + return true; +} + +/*! + Returns the current status of the read notification subsystem. +*/ +bool WinSerialPortEngine::isReadNotificationEnabled() const +{ +#if defined (Q_OS_WINCE) + bool flag = isRunning(); +#else + bool flag = isEnabled(); +#endif + return (flag && (m_setMask & EV_RXCHAR)); +} + +/*! + Enables or disables read notification subsystem, depending on + the \a enable parameter. If the subsystem is enabled, it will + asynchronously track the occurrence of an event EV_RXCHAR. + Thanks to that, SerialPort can emit a signal readyRead() and + fill up the internal receive buffer with new data, that + automatically received from a serial port in the event loop. +*/ +void WinSerialPortEngine::setReadNotificationEnabled(bool enable) +{ +#if defined (Q_OS_WINCE) + m_setCommMaskMutex.lock(); + ::GetCommMask(m_descriptor, &m_currentMask); +#endif + + if (enable) + m_setMask |= EV_RXCHAR; + else + m_setMask &= ~EV_RXCHAR; + +#if defined (Q_OS_WINCE) + if (m_setMask != m_currentMask) + ::SetCommMask(m_descriptor, m_setMask); + + m_setCommMaskMutex.unlock(); + + if (enable && !isRunning()) + start(); +#else + setMaskAndActivateEvent(); +#endif +} + +/*! + Returns the current status of the write notification subsystem. +*/ +bool WinSerialPortEngine::isWriteNotificationEnabled() const +{ +#if defined (Q_OS_WINCE) + bool flag = isRunning(); +#else + bool flag = isEnabled(); +#endif + return (flag && (m_setMask & EV_TXEMPTY)); +} + +/*! + Enables or disables write notification subsystem, depending on + the \a enable parameter. If the subsystem is enabled, it will + asynchronously track the occurrence of an event EV_TXEMPTY. + Thanks to that, SerialPort can write data from internal transfer + buffer, to serial port automatically in the event loop. +*/ +void WinSerialPortEngine::setWriteNotificationEnabled(bool enable) +{ +#if defined (Q_OS_WINCE) + m_setCommMaskMutex.lock(); + ::GetCommMask(m_descriptor, &m_currentMask); +#endif + + if (enable) + m_setMask |= EV_TXEMPTY; + else + m_setMask &= ~EV_TXEMPTY; + +#if defined (Q_OS_WINCE) + if (m_setMask != m_currentMask) + ::SetCommMask(m_descriptor, m_setMask); + + m_setCommMaskMutex.unlock(); + + if (enable && !isRunning()) + start(); +#else + setMaskAndActivateEvent(); +#endif + // This only for OS Windows, as EV_TXEMPTY event is triggered only + // after the last byte of data. + // Therefore, we are forced to run writeNotification(), as EV_TXEMPTY does not work. + if (enable) + m_parent->canWriteNotification(); +} + +/*! + Defines the type of parity or frame error when an event + occurs EV_ERR. In addition, in case of any errors, this method + sets to true a flag m_flagErrorFromCommEvent, that used in the + method of reading for policy processing. + + This method is called automatically from an error handler in + parent class SerialPortPrivate, that called by error notification + subsystem, wehn occurred a event EV_ERR. + +*/ +bool WinSerialPortEngine::processIOErrors() +{ + DWORD err = 0; + COMSTAT cs; + bool ret = (::ClearCommError(m_descriptor, &err, &cs) != 0); + if (ret && err) { + if (err & CE_FRAME) + m_parent->setError(SerialPort::FramingError); + else if (err & CE_RXPARITY) + m_parent->setError(SerialPort::ParityError); + else if (err & CE_BREAK) + m_parent->setError(SerialPort::BreakConditionError); + else + m_parent->setError(SerialPort::UnknownPortError); + + m_flagErrorFromCommEvent = true; + } + return ret; +} + +#if defined (Q_OS_WINCE) + +void WinSerialPortEngine::lockNotification(NotificationLockerType type, bool uselocker) +{ + QMutex *mutex = 0; + switch (type) { + case CanReadLocker: + mutex = &m_readNotificationMutex; + break; + case CanWriteLocker: + mutex = &m_writeNotificationMutex; + break; + case CanErrorLocker: + mutex = &m_errorNotificationMutex; + break; + } + + if (uselocker) + QMutexLocker locker(mutex); + else + mutex->lock(); +} + +void WinSerialPortEngine::unlockNotification(NotificationLockerType type) +{ + switch (type) { + case CanReadLocker: m_readNotificationMutex.unlock(); + break; + case CanWriteLocker: m_writeNotificationMutex.unlock(); + break; + case CanErrorLocker: m_errorNotificationMutex.unlock(); + break; + } +} + +#endif + +/* Protected methods */ + +/*! + Attempts to determine the current settings of the serial port, + wehn it opened. Used only in the method open(). +*/ +void WinSerialPortEngine::detectDefaultSettings() +{ + // Detect rate. + m_parent->m_inRate = quint32(m_currDCB.BaudRate); + m_parent->m_outRate = m_parent->m_inRate; + + // Detect databits. + switch (m_currDCB.ByteSize) { + case 5: + m_parent->m_dataBits = SerialPort::Data5; + break; + case 6: + m_parent->m_dataBits = SerialPort::Data6; + break; + case 7: + m_parent->m_dataBits = SerialPort::Data7; + break; + case 8: + m_parent->m_dataBits = SerialPort::Data8; + break; + default: + m_parent->m_dataBits = SerialPort::UnknownDataBits; + } + + // Detect parity. + if ((m_currDCB.Parity == NOPARITY) && !m_currDCB.fParity) + m_parent->m_parity = SerialPort::NoParity; + else if ((m_currDCB.Parity == SPACEPARITY) && m_currDCB.fParity) + m_parent->m_parity = SerialPort::SpaceParity; + else if ((m_currDCB.Parity == MARKPARITY) && m_currDCB.fParity) + m_parent->m_parity = SerialPort::MarkParity; + else if ((m_currDCB.Parity == EVENPARITY) && m_currDCB.fParity) + m_parent->m_parity = SerialPort::EvenParity; + else if ((m_currDCB.Parity == ODDPARITY) && m_currDCB.fParity) + m_parent->m_parity = SerialPort::OddParity; + else + m_parent->m_parity = SerialPort::UnknownParity; + + // Detect stopbits. + switch (m_currDCB.StopBits) { + case ONESTOPBIT: + m_parent->m_stopBits = SerialPort::OneStop; + break; + case ONE5STOPBITS: + m_parent->m_stopBits = SerialPort::OneAndHalfStop; + break; + case TWOSTOPBITS: + m_parent->m_stopBits = SerialPort::TwoStop; + break; + default: + m_parent->m_stopBits = SerialPort::UnknownStopBits; + } + + // Detect flow control. + if (!m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_DISABLE) + && !m_currDCB.fInX && !m_currDCB.fOutX) { + m_parent->m_flow = SerialPort::NoFlowControl; + } else if (!m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_DISABLE) + && m_currDCB.fInX && m_currDCB.fOutX) { + m_parent->m_flow = SerialPort::SoftwareControl; + } else if (m_currDCB.fOutxCtsFlow && (m_currDCB.fRtsControl == RTS_CONTROL_HANDSHAKE) + && !m_currDCB.fInX && !m_currDCB.fOutX) { + m_parent->m_flow = SerialPort::HardwareControl; + } else + m_parent->m_flow = SerialPort::UnknownFlowControl; +} + +#if defined (Q_OS_WINCE) + +/*! + Embedded-based (WinCE) event loop for notification subsystem. + Tracking a separate thread the events from the serial port, as: + EV_ERR, EV_RXCHAR, EV_TXEMPTY. When is occur a relevant event, + calls him handler from a parent class SerialPortPrivate. + At the same time in handlers to capture/release the mutex + (see handlers implementation). +*/ +void WinSerialPortEngine::run() +{ + while (m_running) { + + m_setCommMaskMutex.lock(); + ::SetCommMask(m_descriptor, m_setMask); + m_setCommMaskMutex.unlock(); + + if (::WaitCommEvent(m_descriptor, &m_currentMask, 0) != 0) { + + // Wait until complete the operation changes the port settings, + // see updateDcb(). + m_settingsChangeMutex.lock(); + m_settingsChangeMutex.unlock(); + + if (EV_ERR & m_currentMask & m_setMask) { + m_parent->canErrorNotification(); + } + if (EV_RXCHAR & m_currentMask & m_setMask) { + m_parent->canReadNotification(); + } + //FIXME: This is why it does not work? + if (EV_TXEMPTY & m_currentMask & m_setMask) { + m_parent->canWriteNotification(); + } + } + } +} + +#else + +/*! + Windows NT-based event loop for notification subsystem. + Asynchronously in event loop continuous mode tracking the + events from the serial port, as: EV_ERR, EV_RXCHAR, EV_TXEMPTY. + When is occur a relevant event, calls him handler from + a parent class SerialPortPrivate. +*/ +bool WinSerialPortEngine::event(QEvent *e) +{ + bool ret = false; + if (e->type() == QEvent::WinEventAct) { + if (EV_ERR & m_currentMask & m_setMask) { + m_parent->canErrorNotification(); + ret = true; + } + if (EV_RXCHAR & m_currentMask & m_setMask) { + m_parent->canReadNotification(); + ret = true; + } + //FIXME: This is why it does not work? + if (EV_TXEMPTY & m_currentMask & m_setMask) { + m_parent->canWriteNotification(); + ret = true; + } + } + else + ret = QWinEventNotifier::event(e); + + ::WaitCommEvent(m_descriptor, &m_currentMask, &m_ov); + return ret; +} + +#endif + +/* Private methods */ + +#if !defined (Q_OS_WINCE) + +/*! + For Windows NT-based, creates handles events for OVERLAPPED + structures, that are used in the methods of reading \a rx, + writing \a tx, and waiting for data from the serial port. + This method is only used in the method open(). + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::createEvents(bool rx, bool tx) +{ + if (rx) { + m_ovRead.hEvent = ::CreateEvent(0, false, false, 0); + Q_ASSERT(m_ovRead.hEvent); + } + if (tx) { + m_ovWrite.hEvent = ::CreateEvent(0, false, false, 0); + Q_ASSERT(m_ovWrite.hEvent); + } + m_ovSelect.hEvent = ::CreateEvent(0, false, false, 0); + Q_ASSERT(m_ovSelect.hEvent); + m_ov.hEvent = ::CreateEvent(0, false, false, 0); + Q_ASSERT(m_ov.hEvent); + + setHandle(m_ov.hEvent); + return true; +} + +/*! + For Windows NT-based, release and closed handles events from + OVERLAPPED structures. +*/ +void WinSerialPortEngine::closeEvents() +{ + if (m_ovRead.hEvent) + ::CloseHandle(m_ovRead.hEvent); + if (m_ovWrite.hEvent) + ::CloseHandle(m_ovWrite.hEvent); + if (m_ovSelect.hEvent) + ::CloseHandle(m_ovSelect.hEvent); + if (m_ov.hEvent) + ::CloseHandle(m_ov.hEvent); + + size_t size = sizeof(OVERLAPPED); + ::memset(&m_ovRead, 0, size); + ::memset(&m_ovWrite, 0, size); + ::memset(&m_ovSelect, 0, size); + ::memset(&m_ov, 0, size); +} + +/*! + For Windows NT-based, sets the mask of tracking events. +*/ +void WinSerialPortEngine::setMaskAndActivateEvent() +{ + ::SetCommMask(m_descriptor, m_setMask); + if (m_setMask) + ::WaitCommEvent(m_descriptor, &m_currentMask, &m_ov); + switch (m_setMask) { + case 0: + if (isEnabled()) + setEnabled(false); + break; + default: + if (!isEnabled()) + setEnabled(true); + } +} + +#endif + +/*! + Updates the DCB structure wehn changing of any the parameters + a serial port. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::updateDcb() +{ +#if defined (Q_OS_WINCE) + // Grab a mutex, in order after exit WaitCommEvent + // block the flow of run() notifier until there is a change DCB. + QMutexLocker locker(&m_settingsChangeMutex); + // This way, we reset in class WaitCommEvent to + // be able to change the DCB. + // Otherwise WaitCommEvent blocking any change! + ::SetCommMask(m_descriptor, 0); +#endif + if (::SetCommState(m_descriptor, &m_currDCB) == 0) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return true; +} + +/*! + Updates the COMMTIMEUTS structure wehn changing of any timeout the + parameters a serial port. + + If successful, returns true; otherwise false. +*/ +bool WinSerialPortEngine::updateCommTimeouts() +{ + if (::SetCommTimeouts(m_descriptor, &m_currCommTimeouts) == 0) { + m_parent->setError(SerialPort::UnsupportedPortOperationError); + return false; + } + return true; +} + +// From +SerialPortEngine *SerialPortEngine::create(SerialPortPrivate *parent) +{ + return new WinSerialPortEngine(parent); +} + +#include "moc_serialportengine_win_p.cpp" + +QT_END_NAMESPACE_SERIALPORT + diff --git a/src/serialportengine_win_p.h b/src/serialportengine_win_p.h new file mode 100644 index 0000000..e30335f --- /dev/null +++ b/src/serialportengine_win_p.h @@ -0,0 +1,162 @@ +/* + License... +*/ + +#ifndef SERIALPORTENGINE_WIN_P_H +#define SERIALPORTENGINE_WIN_P_H + +#include "serialport.h" +#include "serialportengine_p.h" + +#include +#if defined (Q_OS_WINCE) +# include +# include +# include +#else +# include +#endif + +QT_BEGIN_NAMESPACE_SERIALPORT + +#if defined (Q_OS_WINCE) + +class WinCeWaitCommEventBreaker : public QThread +{ + Q_OBJECT +public: + WinCeWaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0) + : QThread(parent), m_descriptor(descriptor), + m_timeout(timeout), m_worked(false) { + start(); + } + virtual ~WinCeWaitCommEventBreaker() { + stop(); + wait(); + } + void stop() { exit(0); } + bool isWorked() const { return m_worked; } + +protected: + void run() { + QTimer timer; + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(procTimeout()), Qt::DirectConnection); + timer.start(m_timeout); + exec(); + m_worked = true; + } + +private slots: + void procTimeout() { + ::SetCommMask(m_descriptor, 0); + stop(); + } + +private: + HANDLE m_descriptor; + int m_timeout; + volatile bool m_worked; +}; +#endif + +#if defined (Q_OS_WINCE) +class WinSerialPortEngine : public QThread, public SerialPortEngine + #else +class WinSerialPortEngine : public QWinEventNotifier, public SerialPortEngine + #endif +{ + Q_OBJECT +public: + WinSerialPortEngine(SerialPortPrivate *parent); + virtual ~WinSerialPortEngine(); + + virtual bool open(const QString &location, QIODevice::OpenMode mode); + virtual void close(const QString &location); + + virtual SerialPort::Lines lines() const; + + virtual bool setDtr(bool set); + virtual bool setRts(bool set); + + virtual bool flush(); + virtual bool reset(); + + virtual bool sendBreak(int duration); + virtual bool setBreak(bool set); + + virtual qint64 bytesAvailable() const; + virtual qint64 bytesToWrite() const; + + virtual qint64 read(char *data, qint64 len); + virtual qint64 write(const char *data, qint64 len); + virtual bool select(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite); + + virtual QString toSystemLocation(const QString &port) const; + virtual QString fromSystemLocation(const QString &location) const; + + virtual bool setRate(qint32 rate, SerialPort::Directions dir); + virtual bool setDataBits(SerialPort::DataBits dataBits); + virtual bool setParity(SerialPort::Parity parity); + virtual bool setStopBits(SerialPort::StopBits stopBits); + virtual bool setFlowControl(SerialPort::FlowControl flowControl); + + virtual bool setDataErrorPolicy(SerialPort::DataErrorPolicy policy); + + virtual bool isReadNotificationEnabled() const; + virtual void setReadNotificationEnabled(bool enable); + virtual bool isWriteNotificationEnabled() const; + virtual void setWriteNotificationEnabled(bool enable); + + virtual bool processIOErrors(); + +#if defined (Q_OS_WINCE) + virtual void lockNotification(NotificationLockerType type, bool uselocker); + virtual void unlockNotification(NotificationLockerType type); +#endif + +protected: + virtual void detectDefaultSettings(); + +#if defined (Q_OS_WINCE) + virtual void run(); +#else + virtual bool event(QEvent *e); +#endif + +private: + DCB m_currDCB; + DCB m_oldDCB; + COMMTIMEOUTS m_currCommTimeouts; + COMMTIMEOUTS m_oldCommTimeouts; + HANDLE m_descriptor; + bool m_flagErrorFromCommEvent; + DWORD m_currentMask; + DWORD m_setMask; + +#if defined (Q_OS_WINCE) + QMutex m_readNotificationMutex; + QMutex m_writeNotificationMutex; + QMutex m_errorNotificationMutex; + QMutex m_settingsChangeMutex; + QMutex m_setCommMaskMutex; + volatile bool m_running; +#else + OVERLAPPED m_ovRead; + OVERLAPPED m_ovWrite; + OVERLAPPED m_ovSelect; + OVERLAPPED m_ov; + + bool createEvents(bool rx, bool tx); + void closeEvents(); + void setMaskAndActivateEvent(); +#endif + + bool updateDcb(); + bool updateCommTimeouts(); +}; + +QT_END_NAMESPACE_SERIALPORT + +#endif // SERIALPORTENGINE_WIN_P_H diff --git a/src/serialportinfo.cpp b/src/serialportinfo.cpp index 7bf80ce..4b903ac 100644 --- a/src/serialportinfo.cpp +++ b/src/serialportinfo.cpp @@ -6,7 +6,7 @@ #include "serialportinfo_p.h" #include "serialport.h" -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT /*! @@ -188,3 +188,5 @@ QString SerialPortInfo::manufacturer() const Returns a list of available serial ports on the system. */ + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialportinfo.h b/src/serialportinfo.h new file mode 100644 index 0000000..02b9359 --- /dev/null +++ b/src/serialportinfo.h @@ -0,0 +1,53 @@ +/* + License... +*/ + +#ifndef SERIALPORTINFO_H +#define SERIALPORTINFO_H + +#include +#include + +#include "serialport-global.h" + +QT_BEGIN_NAMESPACE_SERIALPORT + +class SerialPort; +class SerialPortInfoPrivate; +class SerialInfoPrivateDeleter; + +class Q_ADDON_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; + + bool isNull() const; + bool isBusy() const; + bool isValid() const; + + QList standardRates() const; + static QList availablePorts(); + +private: + QScopedPointer d_ptr; +}; + +inline bool SerialPortInfo::isNull() const +{ return !d_ptr; } + +QT_END_NAMESPACE_SERIALPORT + +#endif // SERIALPORTINFO_H diff --git a/src/serialportinfo_mac.cpp b/src/serialportinfo_mac.cpp index 98bc71e..c0c2a04 100644 --- a/src/serialportinfo_mac.cpp +++ b/src/serialportinfo_mac.cpp @@ -23,7 +23,7 @@ #include #include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT /* Public methods */ @@ -217,3 +217,5 @@ bool SerialPortInfo::isValid() const QFile f(systemLocation()); return f.exists(); } + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialportinfo_p.h b/src/serialportinfo_p.h index eaf158b..b96b626 100644 --- a/src/serialportinfo_p.h +++ b/src/serialportinfo_p.h @@ -9,7 +9,7 @@ #include -QT_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT class SerialPortInfoPrivate { @@ -31,6 +31,6 @@ public: } }; -QT_END_NAMESPACE +QT_END_NAMESPACE_SERIALPORT #endif // SERIALPORTINFO_P_H diff --git a/src/serialportinfo_symbian.cpp b/src/serialportinfo_symbian.cpp index bae90b2..c9055c5 100644 --- a/src/serialportinfo_symbian.cpp +++ b/src/serialportinfo_symbian.cpp @@ -58,7 +58,7 @@ static bool loadDevices() return true; } -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT /* Public methods */ @@ -226,3 +226,5 @@ bool SerialPortInfo::isValid() const port.Close(); return (r == KErrNone ) || (r == KErrLocked); } + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialportinfo_unix.cpp b/src/serialportinfo_unix.cpp index 2081e5c..5a1161e 100644 --- a/src/serialportinfo_unix.cpp +++ b/src/serialportinfo_unix.cpp @@ -31,24 +31,48 @@ extern "C" #include #include -QT_USE_NAMESPACE + +#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV) +// +#else +// This name filters used only for a simple enumeration of all available +// devices on the mask in /dev, ie if there is no other way to enumerate +// the devices, used in the following cases: +// - for Gnu/Linux with no libudev +// - for any other *nix, bsd (exception mac OSX) static QStringList nameFilters() { static QStringList list; -#if defined (Q_OS_LINUX) - list << "ttyS*" /* Standart UART 8250 and etc. */ - << "ttyUSB*" /* Usb/serial converters PL2303 and etc. */ - << "ttyACM*" /* CDC_ACM converters (i.e. Mobile Phones). */ - << "ttyMI*" /* MOXA pci/serial converters. */ - << "rfcomm*"; /* Bluetooth serial device. */ -#elif defined (Q_OS_FREEBSD) - list << "cu*"; -#else +# if defined (Q_OS_LINUX) + list << 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("ttyMI*") /* MOXA pci/serial converters. */ + << QLatin1String("rfcomm*"); /* Bluetooth serial device. */ +# elif defined (Q_OS_FREEBSD) + list << QLatin1String("cu*"); +# else // Here for other *nix OS. -#endif +# endif return list; } +#endif + +static +const qint32 standardRates_begin[] = +{ + 50, 75, 110, 134, 150, + 200, 300, 600, 1200, 1800, + 2400, 4800, 9600, 19200, 38400, + 57600, 115200, 230400, 460800, + 500000, 576000, 921600, 1000000, + 1152000, 1500000, 2000000, 2500000, + 3000000, 3500000, 4000000 +}, *standardRates_end = standardRates_begin + sizeof(::standardRates_begin)/sizeof(*::standardRates_begin); + + +QT_BEGIN_NAMESPACE_SERIALPORT /* Public methods */ @@ -87,30 +111,30 @@ QList SerialPortInfo::availablePorts() SerialPortInfo info; info.d_ptr->device = - QString(udev_device_get_devnode(dev)); + QLatin1String(udev_device_get_devnode(dev)); info.d_ptr->portName = - QString(udev_device_get_sysname(dev)); + QLatin1String(udev_device_get_sysname(dev)); struct udev_device *parentdev = udev_device_get_parent(dev); if (parentdev) { - QString subsys(udev_device_get_subsystem(parentdev)); + QString subsys(QLatin1String(udev_device_get_subsystem(parentdev))); bool do_append = true; - if (subsys.contains("usb")) { + if (subsys.contains(QLatin1String("usb"))) { info.d_ptr->description = - QString(udev_device_get_property_value(dev, + QLatin1String(udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")); info.d_ptr->manufacturer = - QString(udev_device_get_property_value(dev, + QLatin1String(udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE")); - } else if (subsys == QString("pnp")) { + } else if (subsys.contains(QLatin1String("pnp"))) { info.d_ptr->description = - QString("Standard serial port."); + QLatin1String("Standard serial port."); info.d_ptr->manufacturer = - QString("Standard serial ports."); + QLatin1String("Standard serial ports."); } else { do_append = false; } @@ -135,7 +159,7 @@ QList SerialPortInfo::availablePorts() #else // Simple enumerate with device directory /dev scan. - QDir devDir("/dev"); + QDir devDir(QLatin1String("/dev")); if (devDir.exists()) { devDir.setNameFilters(nameFilters()); @@ -153,7 +177,7 @@ QList SerialPortInfo::availablePorts() SerialPortInfo info; info.d_ptr->device = s; - info.d_ptr->portName = s.remove(QRegExp("/[\\w|\\d|\\s]+/")); + info.d_ptr->portName = s.remove(QRegExp(QLatin1String("/[\\w|\\d|\\s]+/"))); info.d_ptr->description = QString(QObject::tr("Unknown.")); info.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); @@ -169,18 +193,6 @@ QList SerialPortInfo::availablePorts() return ports; } -static -const qint32 standardRates_begin[] = -{ - 50, 75, 110, 134, 150, - 200, 300, 600, 1200, 1800, - 2400, 4800, 9600, 19200, 38400, - 57600, 115200, 230400, 460800, - 500000, 576000, 921600, 1000000, - 1152000, 1500000, 2000000, 2500000, - 3000000, 3500000, 4000000 -}, *standardRates_end = standardRates_begin + sizeof(::standardRates_begin)/sizeof(*::standardRates_begin); - QList SerialPortInfo::standardRates() const { QList rates; @@ -229,3 +241,5 @@ bool SerialPortInfo::isValid() const QFile f(systemLocation()); return f.exists(); } + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/serialportinfo_win.cpp b/src/serialportinfo_win.cpp index e14e3de..31886cc 100644 --- a/src/serialportinfo_win.cpp +++ b/src/serialportinfo_win.cpp @@ -15,7 +15,7 @@ #include #include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE_SERIALPORT static const GUID guidArray[] = { @@ -142,7 +142,7 @@ static QString getNativeName(HDEVINFO deviceInfoSet, QString itemName = QString::fromUtf16(reinterpret_cast(bufKeyName.data()), lenKeyName); QString itemValue = QString::fromUtf16(((const ushort *)bufKeyVal.constData())); - if (itemName.contains("PortName")) { + if (itemName.contains(QLatin1String("PortName"))) { result = itemValue; break; } @@ -240,10 +240,10 @@ QList SerialPortInfo::availablePorts() QVariant v = getNativeName(deviceInfoSet, &deviceInfoData); QString s = v.toString(); - if (!(s.isEmpty() || s.contains("LPT"))) { + if (!(s.isEmpty() || s.contains(QLatin1String("LPT")))) { info.d_ptr->portName = s; - info.d_ptr->device = "\\\\.\\" + s; + info.d_ptr->device = QLatin1String("\\\\.\\") + s; v = getDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC); info.d_ptr->description = v.toString(); @@ -374,3 +374,5 @@ bool SerialPortInfo::isValid() const ::CloseHandle(descriptor); return true; } + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/src-lib.pri b/src/src-lib.pri new file mode 100644 index 0000000..fbe5160 --- /dev/null +++ b/src/src-lib.pri @@ -0,0 +1,79 @@ +INCLUDEPATH += $$PWD + +HEADERS += qtaddonserialportversion.h + +PUBLIC_HEADERS += \ + $$PWD/serialport-global.h \ + $$PWD/serialport.h \ + $$PWD/serialportinfo.h + +PRIVATE_HEADERS += \ + $$PWD/serialport_p.h \ + $$PWD/ringbuffer_p.h \ + $$PWD/serialportengine_p.h \ + $$PWD/serialportinfo_p.h + +SOURCES += \ + $$PWD/serialport.cpp \ + $$PWD/serialportinfo.cpp + + +win32 { + PRIVATE_HEADERS += \ + $$PWD/serialportengine_win_p.h + SOURCES += \ + $$PWD/serialportengine_win.cpp \ + $$PWD/serialportinfo_win.cpp + + !wince*: LIBS += -lsetupapi -luuid -ladvapi32 +} + +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/serialportengine_symbian_p.h + SOURCES += \ + $$PWD/serialportengine_symbian.cpp \ + $$PWD/serialportinfo_symbian.cpp + LIBS += -leuser -lefsrv -lc32 +} + +unix:!symbian { + maemo5 { + target.path = /opt/usr/lib + } else { + target.path = /usr/lib + } + INSTALLS += target + + PRIVATE_HEADERS += \ + $$PWD/ttylocker_unix_p.h \ + $$PWD/serialportengine_unix_p.h + SOURCES += \ + $$PWD/ttylocker_unix.cpp \ + $$PWD/serialportengine_unix.cpp + + macx { + SOURCES += $$PWD/serialportinfo_mac.cpp + LIBS += -framework IOKit -framework CoreFoundation + } else { + SOURCES += $$PWD/serialportinfo_unix.cpp + linux*:contains( DEFINES, HAVE_LIBUDEV ) { + LIBS += -ludev + } + } +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/src/src.pri b/src/src.pri deleted file mode 100644 index e24b24b..0000000 --- a/src/src.pri +++ /dev/null @@ -1,73 +0,0 @@ -INCLUDEPATH += ../include -HEADERS += \ - ../include/serialport.h \ - ../include/serialportinfo.h - -HEADERS += \ - $$PWD/serialport_p.h \ - $$PWD/ringbuffer_p.h \ - $$PWD/serialportengine_p.h \ - $$PWD/serialportinfo_p.h - -SOURCES += \ - $$PWD/serialport.cpp \ - $$PWD/serialportinfo.cpp - -win32 { - HEADERS += \ - $$PWD/serialportengine_p_win.h - SOURCES += \ - $$PWD/serialportengine_p_win.cpp \ - $$PWD/serialportinfo_win.cpp - - !wince*: LIBS += -lsetupapi -luuid -ladvapi32 -} - - -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 - - HEADERS += \ - $$PWD/serialportengine_p_symbian.h - SOURCES += \ - $$PWD/serialportengine_p_symbian.cpp \ - $$PWD/serialportinfo_symbian.cpp - LIBS += -leuser -lefsrv -lc32 -} - -unix:!symbian { - maemo5 { - target.path = /opt/usr/lib - } else { - target.path = /usr/lib - } - INSTALLS += target - - HEADERS += \ - $$PWD/ttylocker_p_unix.h \ - $$PWD/serialportengine_p_unix.h - SOURCES += \ - $$PWD/ttylocker_p_unix.cpp \ - $$PWD/serialportengine_p_unix.cpp - - macx { - SOURCES += $$PWD/serialportinfo_mac.cpp - LIBS += -framework IOKit -framework CoreFoundation - } else { - SOURCES += $$PWD/serialportinfo_unix.cpp - contains( DEFINES, HAVE_LIBUDEV ) { - LIBS += -ludev - } - } -} diff --git a/src/src.pro b/src/src.pro index 3d12d55..fdd5378 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,87 +1,18 @@ TEMPLATE = lib -CONFIG += dll -#CONFIG += staticlib -QT -= gui -TARGET = SerialPort +TARGET = $$QT.serialport.name +MODULE = serialport -win32 { - DEFINES += SERIALPORT_BUILD SERIALPORT_SHARED -} +load(qt_module) +load(qt_module_config) -INCLUDEPATH += ../include -HEADERS += \ - ../include/serialport.h \ - ../include/serialportinfo.h - -HEADERS += \ - serialport_p.h \ - ringbuffer_p.h \ - serialportengine_p.h \ - serialportinfo_p.h - -SOURCES += \ - serialport.cpp \ - serialportinfo.cpp - -win32 { - HEADERS += \ - serialportengine_p_win.h - SOURCES += \ - serialportengine_p_win.cpp \ - serialportinfo_win.cpp - - !wince*: LIBS += -lsetupapi -luuid -ladvapi32 -} - - -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 - - HEADERS += \ - serialportengine_p_symbian.h - SOURCES += \ - serialportengine_p_symbian.cpp \ - serialportinfo_symbian.cpp - LIBS += -leuser -lefsrv -lc32 -} - -unix:!symbian { - maemo5 { - target.path = /opt/usr/lib - } else { - target.path = /usr/lib - } - INSTALLS += target - - HEADERS += \ - ttylocker_p_unix.h \ - serialportengine_p_unix.h - SOURCES += \ - ttylocker_p_unix.cpp \ - serialportengine_p_unix.cpp - - macx { - SOURCES += serialportinfo_mac.cpp - LIBS += -framework IOKit -framework CoreFoundation - } else { - SOURCES += serialportinfo_unix.cpp - linux*:contains( DEFINES, HAVE_LIBUDEV ) { - LIBS += -ludev - } - } -} +DESTDIR = $$QT.serialport.libs +VERSION = $$QT.serialport.VERSION +DEFINES += QT_ADDON_SERIALPORT_LIB +CONFIG += module create_prl +MODULE_PRI = ../modules/qt_serialport.pri +include($$PWD/src-lib.pri) +mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$QT.serialport.name diff --git a/src/ttylocker_p_unix.cpp b/src/ttylocker_p_unix.cpp deleted file mode 100644 index 6613a76..0000000 --- a/src/ttylocker_p_unix.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - License... -*/ - -#include "ttylocker_p_unix.h" - -/* this directive by default will not work because when creating Makefile no checks on the existence of: -1. header: -ie using qmake to do this is impossible (difficult). -it is possible to solve the transition to CMake*/ -#if defined (HAVE_BAUDBOY_H) -# include -# include - -/* this directive by default will not work because when creating Makefile no checks on the existence of: -1. header: -2. library:-llockdev -ie using qmake to do this is impossible (difficult). -it is possible to solve the transition to CMake*/ -#elif defined (HAVE_LOCKDEV_H) -# include -# include - -#else -# include -# include -# include -# include - -# include -# include -# include - -#endif - -#include - -QT_USE_NAMESPACE - -// Truncate the full name of the device to short. -// For example the long name "/dev/ttyS0" will cut up to "ttyS0". -static QString short_name_from_location(const QString &location) -{ - return QDir::cleanPath(location).section(QDir::separator() , -1); -} - - -#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) - -enum { - LOCK_DIRS_COUNT = 5, - LOCK_FILE_FORMS_COUNT = 2 //< while unused -}; - -static const char *lock_dir_list[LOCK_DIRS_COUNT] = { - "/var/lock", - "/etc/locks", - "/var/spool/locks", - "/var/spool/uucp", - "/tmp" -}; - -// 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 get_first_shared_lock_dir() -{ - for (int i = 0; i < LOCK_DIRS_COUNT; ++i) { - if (::access(lock_dir_list[i], (R_OK | W_OK)) == 0) - return QString(lock_dir_list[i]); - } - return QString(); -} - -/* -// Returns the name of the lock file, which is tied to the -// major and minor device number, eg "LCK.30.50" etc. -static QString get_lock_file_in_numeric_form(const QString &location) -{ - QString result = get_first_shared_lock_dir(); - if (!result.isEmpty()) { - struct stat buf; - if (::stat(location.toLocal8Bit().constData(), &buf)) - result.clear(); - else { - result.append("/LCK.%1.%2"); - result = result.arg(major(buf.st_rdev)).arg(minor(buf.st_rdev)); - } - } - return result; -} -*/ - -// Returns the name of the lock file which is tied to the -// device name, eg "LCK..ttyS0", etc. -static QString get_lock_file_in_named_form(const QString &location) -{ - QString result(get_first_shared_lock_dir()); - if (!result.isEmpty()) { - result.append("/LCK..%1"); - result = result.arg(short_name_from_location(location)); - } - return result; -} - -/* -// Returns the name of the lock file, which is tied to the number of -// the process which uses a device, such as "LCK...999", etc. -static QString get_lock_file_in_pid_form(const QString &location) -{ - QString result = get_first_shared_lock_dir(); - if (!result.isEmpty()) { - result.append("/LCK...%1"); - result = result.arg(::getpid()); - } - return result; -} -*/ - -enum CheckPidResult { - CHK_PID_PROCESS_NOT_EXISTS, /* process does not exist */ - CHK_PID_PROCESS_EXISTS_FOREIGN, /* process exists and it is "foreign" (ie not current) */ - CHK_PID_PROCESS_EXISTS_CURRENT, /* process exists and it is "their" (ie, current) */ - CHK_PID_UNKNOWN_ERROR /* another error */ -}; -// Checks the validity of the process number that was obtained from the Lock file. -static enum CheckPidResult check_pid(int pid) -{ - if (::kill(pid_t(pid), 0) == -1) { - return (errno == ESRCH) ? - (CHK_PID_PROCESS_NOT_EXISTS) : (CHK_PID_UNKNOWN_ERROR); - } - return (::getpid() == pid) ? - (CHK_PID_PROCESS_EXISTS_CURRENT) : (CHK_PID_PROCESS_EXISTS_FOREIGN); -} - -static bool m_islocked(const QString &location, bool *current_pid) -{ - bool result = false; - *current_pid = false; - - QFile f(get_lock_file_in_named_form(location)); - - if (f.exists()) { - if (!f.open(QIODevice::ReadOnly)) { - result = true; - } else { - QString content(f.readAll()); - f.close(); - bool ok = false; - int pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt(&ok); - if (ok) { - switch (check_pid(pid)) { - case CHK_PID_PROCESS_NOT_EXISTS: - break; - case CHK_PID_PROCESS_EXISTS_FOREIGN: - result = true; - break; - case CHK_PID_PROCESS_EXISTS_CURRENT: - result = true; - *current_pid = true; - break; - default: - result = true; - } - } - } - } - return result; -} - -static bool m_unlock(const QString &location) { - QFile f(get_lock_file_in_named_form(location)); - f.remove(); - return true; -} - -bool m_lock(const QString &location) -{ - bool result = false; - QFile f(get_lock_file_in_named_form(location)); - if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QString content(" %1 %2\x0A"); - content = content.arg(::getpid()).arg(::getuid()); - - if (f.write(content.toLocal8Bit()) > 0) - result = true; - f.close(); - } - return result; -} - -#endif//HAVE_BAUDBOY_H, HAVE_LOCKDEV_H - - -// Try lock serial device. However, other processes can not access it. -bool TTYLocker::lock(const QString &location) -{ - bool result = false; -#if defined (HAVE_BAUDBOY_H) - if (::ttylock(short_name_from_location(location).toLocal8Bit().constData())) - ::ttywait(short_name_from_location(location).toLocal8Bit().constData()); - result = (::ttylock(short_name_from_location(location).toLocal8Bit().constData()) != -1); -#elif defined (HAVE_LOCKDEV_H) - result = (::dev_lock(short_name_from_location(location).toLocal8Bit().constData()) != -1); -#else - result = m_lock(location); -#endif - return result; -} - -// Try unlock serial device. However, other processes can access it. -bool TTYLocker::unlock(const QString &location) -{ - bool result = false; -#if defined (HAVE_BAUDBOY_H) - result = (::ttyunlock(short_name_from_location(location).toLocal8Bit().constData()) != -1); -#elif defined (HAVE_LOCKDEV_H) - result = (::dev_unlock(short_name_from_location(location).toLocal8Bit().constData(), ::getpid()) != -1); -#else - result = m_unlock(location); -#endif - return result; -} - -// 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 QString &location, bool *currentPid) -{ - bool result = false; -#if defined (HAVE_BAUDBOY_H) - result = (::ttylocked(short_name_from_location(location).toLocal8Bit().constData()) != -1); - *currentPid = false; -#elif defined (HAVE_LOCKDEV_H) - result = (::dev_testlock(short_name_from_location(location).toLocal8Bit().constData()) != -1); - *currentPid = false; -#else - result = m_islocked(location, currentPid); -#endif - return result; -} diff --git a/src/ttylocker_p_unix.h b/src/ttylocker_p_unix.h deleted file mode 100644 index 84a5adc..0000000 --- a/src/ttylocker_p_unix.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - License... -*/ - -#ifndef TTYLOCKER_P_UNIX_H -#define TTYLOCKER_P_UNIX_H - -#include - -QT_BEGIN_NAMESPACE - -class QString; - -class TTYLocker -{ -public: - static bool lock(const QString &location); - static bool unlock(const QString &location); - static bool isLocked(const QString &location, bool *currentPid); -}; - -QT_END_NAMESPACE - -#endif // TTYLOCKER_P_UNIX_H diff --git a/src/ttylocker_unix.cpp b/src/ttylocker_unix.cpp new file mode 100644 index 0000000..2d93e87 --- /dev/null +++ b/src/ttylocker_unix.cpp @@ -0,0 +1,212 @@ +/* + License... +*/ + +#include "ttylocker_p_unix.h" + +#if defined (HAVE_BAUDBOY_H) +# include +# include +#elif defined (HAVE_LOCKDEV_H) +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif // defined (HAVE_BAUDBOY_H) + +// Truncate the full name of the device to short. +// For example the long name "/dev/ttyS0" will cut up to "ttyS0". +static +QString shortNameFromLocation(const QString &location) +{ + return QDir::cleanPath(location).section(QDir::separator() , -1); +} + + +#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + +static +const char *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 getFirstSharedLockDir() +{ + 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 +// major and minor device number, eg "LCK.30.50" etc. +static QString get_lock_file_in_numeric_form(const QString &location) +{ + QString result = getFirstSharedLockDir(); + if (!result.isEmpty()) { + struct stat buf; + if (::stat(location.toLocal8Bit().constData(), &buf)) + result.clear(); + else { + result.append("/LCK.%1.%2"); + result = result.arg(major(buf.st_rdev)).arg(minor(buf.st_rdev)); + } + } + return result; +} +*/ + +// Returns the name of the lock file which is tied to the +// device name, eg "LCK..ttyS0", etc. +static +QString getLockFileInNamedForm(const QString &location) +{ + QString result(getFirstSharedLockDir()); + if (!result.isEmpty()) { + result.append(QLatin1String("/LCK..%1")); + result = result.arg(shortNameFromLocation(location)); + } + return result; +} + +/* +// Returns the name of the lock file, which is tied to the number of +// the process which uses a device, such as "LCK...999", etc. +static QString get_lock_file_in_pid_form(const QString &location) +{ + QString result = getFirstSharedLockDir(); + if (!result.isEmpty()) { + result.append("/LCK...%1"); + result = result.arg(::getpid()); + } + return result; +} +*/ + +#endif //!(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + + +QT_BEGIN_NAMESPACE_SERIALPORT + +// Try lock serial device. However, other processes can not access it. +bool TTYLocker::lock(const QString &location) +{ + bool result = false; +#if defined (HAVE_BAUDBOY_H) + if (::ttylock(shortNameFromLocation(location).toLocal8Bit().constData())) + ::ttywait(shortNameFromLocation(location).toLocal8Bit().constData()); + result = (::ttylock(shortNameFromLocation(location).toLocal8Bit().constData()) != -1); +#elif defined (HAVE_LOCKDEV_H) + result = (::dev_lock(shortNameFromLocation(location).toLocal8Bit().constData()) != -1); +#else + QFile f(getLockFileInNamedForm(location)); + 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) + result = true; + f.close(); + } +#endif + return result; +} + +// Try unlock serial device. However, other processes can access it. +bool TTYLocker::unlock(const QString &location) +{ + bool result = true; +#if defined (HAVE_BAUDBOY_H) + result = (::ttyunlock(shortNameFromLocation(location).toLocal8Bit().constData()) != -1); +#elif defined (HAVE_LOCKDEV_H) + result = (::dev_unlock(shortNameFromLocation(location).toLocal8Bit().constData(), ::getpid()) != -1); +#else + QFile f(getLockFileInNamedForm(location)); + f.remove(); +#endif + return result; +} + +// 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 QString &location, bool *currentPid) +{ + bool result = false; +#if defined (HAVE_BAUDBOY_H) + result = (::ttylocked(shortNameFromLocation(location).toLocal8Bit().constData()) != -1); + *currentPid = false; +#elif defined (HAVE_LOCKDEV_H) + result = (::dev_testlock(shortNameFromLocation(location).toLocal8Bit().constData()) != -1); + *currentPid = false; +#else + + enum CheckPidResult { + CHK_PID_PROCESS_NOT_EXISTS, /* process does not exist */ + CHK_PID_PROCESS_EXISTS_FOREIGN, /* process exists and it is "foreign" (ie not current) */ + CHK_PID_PROCESS_EXISTS_CURRENT, /* process exists and it is "their" (ie, current) */ + CHK_PID_UNKNOWN_ERROR /* another error */ + }; + + *currentPid = false; + + QFile f(getLockFileInNamedForm(location)); + if (f.exists()) { + if (!f.open(QIODevice::ReadOnly)) { + result = true; + } else { + QString content(QLatin1String(f.readAll())); + f.close(); + bool ok = false; + int pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt(&ok); + if (ok) { + + // Checks the validity of the process number that was obtained from the Lock file. + enum CheckPidResult pidResult = CHK_PID_UNKNOWN_ERROR; + + if (::kill(pid_t(pid), 0) == -1) { + pidResult = (errno == ESRCH) ? + (CHK_PID_PROCESS_NOT_EXISTS) : (CHK_PID_UNKNOWN_ERROR); + } else { + pidResult = (::getpid() == pid) ? + (CHK_PID_PROCESS_EXISTS_CURRENT) : (CHK_PID_PROCESS_EXISTS_FOREIGN); + } + + switch (pidResult) { + case CHK_PID_PROCESS_NOT_EXISTS: + break; + case CHK_PID_PROCESS_EXISTS_FOREIGN: + result = true; + break; + case CHK_PID_PROCESS_EXISTS_CURRENT: + result = true; + *currentPid = true; + break; + default: + result = true; + } + } + } + } +#endif + return result; +} + +QT_END_NAMESPACE_SERIALPORT diff --git a/src/ttylocker_unix_p.h b/src/ttylocker_unix_p.h new file mode 100644 index 0000000..1c2a0cc --- /dev/null +++ b/src/ttylocker_unix_p.h @@ -0,0 +1,22 @@ +/* + 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 QString &location); + static bool unlock(const QString &location); + static bool isLocked(const QString &location, bool *currentPid); +}; + +QT_END_NAMESPACE_SERIALPORT + +#endif // TTYLOCKER_UNIX_P_H diff --git a/sync.profile b/sync.profile new file mode 100644 index 0000000..23b9ac5 --- /dev/null +++ b/sync.profile @@ -0,0 +1,22 @@ +%modules = ( # path to module name map + "QtAddOnSerialPort" => "$basedir/src", +); +%moduleheaders = ( # restrict the module headers to those found in relative path +); +%classnames = ( + "qtaddonserialportversion.h" => "QtAddOnSerialPortVersion", +); +%mastercontent = ( +); +%modulepris = ( + "QtAddOnSerialPort" => "$basedir/modules/qt_serialport.pri", +); +# Module dependencies. +# Every module that is required to build this module should have one entry. +# Each of the module version specifiers can take one of the following values: +# - A specific Git revision. +# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) +# +%dependencies = ( + "qtbase" => "refs/heads/master", +); diff --git a/tests/consolewaitreader/consolewaitreader.pro b/tests/consolewaitreader/consolewaitreader.pro deleted file mode 100644 index 4418216..0000000 --- a/tests/consolewaitreader/consolewaitreader.pro +++ /dev/null @@ -1,25 +0,0 @@ -TEMPLATE = app -CONFIG += console -QT -= gui -OBJECTS_DIR = obj -MOC_DIR = moc - -INCLUDEPATH += \ - ../../include \ - ../../src - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += main.cpp - -CONFIG(debug, debug|release) { - DESTDIR = debug - TARGET = consolewaitreaderd -} else { - DESTDIR = release - TARGET = consolewaitreader -} diff --git a/tests/consolewaitreader/main.cpp b/tests/consolewaitreader/main.cpp deleted file mode 100644 index a06fa3e..0000000 --- a/tests/consolewaitreader/main.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -* ConsoleWaitReader -* -* This application is part of the examples on the use of the library QSerialDevice. -* -* ConsoleWaitReader - a test console application to read data from the port using the method -* of expectations waitForReadyRead(). -* -* Copyright (C) 2011 Denis Shienkov -* -* Contact Denis Shienkov: -* e-mail: -* ICQ: 321789831 -*/ - -#include -#include - -#include "serialport.h" - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - // 1. First - create an instance of an object. - SerialPort port; - - char inbuf[30]; - - std::cout << "Please enter serial device name,\n" - "specific by OS, example\n" - "- in Windows: COMn\n" - "- in GNU/Linux: ttyXYZn\n" - ":"; - std::cin >> inbuf; - - // 2. Second - set the device name. - port.setPort(QString(inbuf)); - - std::cout << "The port will be opened in read-only mode (QIODevice::ReadOnly).\n" - "But you can choose to buffered or not (QIODevice::Unbuffered).\n" - "To understand what is the difference - try to change these modes!\n" - "Disable buffering [y/N] ?:"; - std::cin >> inbuf; - - QIODevice::OpenMode mode = QIODevice::ReadOnly; - if (inbuf[0] == 'y') - mode |= QIODevice::Unbuffered; - - // 3. Third - open the device. - if (port.open(mode)) { - - // 4. Fourth - now you can configure it (only after successfully opened!). - if (port.setRate(115200) && port.setDataBits(SerialPort::Data8) - && port.setParity(SerialPort::NoParity) && port.setStopBits(SerialPort::OneStop) - && port.setFlowControl(SerialPort::NoFlowControl)) { - - int msecs = 0; - std::cout << "Please enter wait timeout for ready read, msec: "; - std::cin >> msecs; - - int len = 0; - std::cout << "Please enter len data for read, bytes: "; - std::cin >> len; - - // 5. Fifth - you can now read/write device, or further modify its settings, etc. - while (1) { - - std::cout << "Now starting wait data ..." << std::endl; - - if ((port.bytesAvailable() > 0) || port.waitForReadyRead(msecs)) { - - QByteArray data = port.read(len); - - std::cout << "Readed " << data.size() << " bytes" << std::endl; - } else { - std::cout << "Wait timeout expired." << std::endl; - } - } - } else { - std::cout << "Configure " << port.portName().toLocal8Bit().constData() << " fail."; - port.close(); - } - } else { - std::cout << "Open " << port.portName().toLocal8Bit().constData() << " fail."; - } - - return app.exec(); -} diff --git a/tests/consolewriter/consolewriter.pro b/tests/consolewriter/consolewriter.pro deleted file mode 100644 index 335d92c..0000000 --- a/tests/consolewriter/consolewriter.pro +++ /dev/null @@ -1,25 +0,0 @@ -TEMPLATE = app -CONFIG += console -QT -= gui -OBJECTS_DIR = obj -MOC_DIR = moc - -INCLUDEPATH += \ - ../../include \ - ../../src - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += main.cpp - -CONFIG(debug, debug|release) { - DESTDIR = debug - TARGET = consolewriterd -} else { - DESTDIR = release - TARGET = consolewriter -} diff --git a/tests/consolewriter/main.cpp b/tests/consolewriter/main.cpp deleted file mode 100644 index e2e47d1..0000000 --- a/tests/consolewriter/main.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* -* ConsoleWriter -* -* This application is part of the examples on the use of the library QSerialDevice. -* -* ConsoleWriter - a test console application to write data to the port. -* -* Copyright (C) 2011 Denis Shienkov -* -* Contact Denis Shienkov: -* e-mail: -* ICQ: 321789831 -*/ - -#include -#include - -#include "serialport.h" - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - // 1. First - create an instance of an object. - SerialPort port; - - char inbuf[30]; - - std::cout << "Please enter serial device name,\n" - "specific by OS, example\n" - "- in Windows: COMn\n" - "- in GNU/Linux: ttyXYZn\n" - ":"; - std::cin >> inbuf; - - // 2. Second - set the device name. - port.setPort(QString(inbuf)); - - std::cout << "The port will be opened in write-only mode (QIODevice::WriteOnly).\n" - "But you can choose to buffered or not (QIODevice::Unbuffered).\n" - "To understand what is the difference - try to change these modes!\n" - "Disable buffering [y/N] ?:"; - std::cin >> inbuf; - - QIODevice::OpenMode mode = QIODevice::WriteOnly; - if (inbuf[0] == 'y') - mode |= QIODevice::Unbuffered; - - // 3. Third - open the device. - if (port.open(mode)) { - - // 4. Fourth - now you can configure it (only after successfully opened!). - if (port.setRate(115200) && port.setDataBits(SerialPort::Data8) - && port.setParity(SerialPort::NoParity) && port.setStopBits(SerialPort::OneStop) - && port.setFlowControl(SerialPort::NoFlowControl)) { - - // 5. Fifth - you can now read/write device, or further modify its settings, etc. - while (1) { - - int len = 0; - std::cout << "Please enter len data for write, bytes: "; - std::cin >> len; - - QByteArray data(len, 0); - - if (port.write(data)) { - std::cout << "Writed " << data.size() << " bytes" << std::endl; - } else { - std::cout << "Write fail." << std::endl; - } - } - } else { - std::cout << "Configure " << port.portName().toLocal8Bit().constData() << " fail."; - port.close(); - } - } else { - std::cout << "Open " << port.portName().toLocal8Bit().constData() << " fail."; - } - - return app.exec(); -} diff --git a/tests/guiapp/guiapp.pro b/tests/guiapp/guiapp.pro deleted file mode 100644 index fd750b7..0000000 --- a/tests/guiapp/guiapp.pro +++ /dev/null @@ -1,33 +0,0 @@ -QT += core gui -TEMPLATE = app - -linux*:DEFINES += HAVE_LIBUDEV - -INCLUDEPATH += \ - ../../include \ - ../../src - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += main.cpp\ - maindialog.cpp \ - optionsdialog.cpp \ - tracedialog.cpp -HEADERS += maindialog.h \ - optionsdialog.h \ - tracedialog.h -FORMS += maindialog.ui \ - optionsdialog.ui \ - tracedialog.ui - -CONFIG(debug, debug|release) { - DESTDIR = debug - TARGET = guiappd -} else { - DESTDIR = release - TARGET = guiapp -} diff --git a/tests/guiapp/main.cpp b/tests/guiapp/main.cpp deleted file mode 100644 index 494c410..0000000 --- a/tests/guiapp/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "maindialog.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - MainDialog dlg; - dlg.show(); - - return a.exec(); -} diff --git a/tests/guiapp/maindialog.cpp b/tests/guiapp/maindialog.cpp deleted file mode 100644 index aafcc46..0000000 --- a/tests/guiapp/maindialog.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -//#include - -#include "maindialog.h" -#include "ui_maindialog.h" -#include "optionsdialog.h" -#include "tracedialog.h" - -#include "serialportinfo.h" -#include "serialport.h" - - -/* Public methods */ - - -MainDialog::MainDialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::MainDialog) - , m_port(0) - , m_timer(0) - , m_rts(false) - , m_dtr(false) -{ - ui->setupUi(this); - fillOpenModeComboBox(); - - m_port = new SerialPort(this); - m_timer = new QTimer(this); - m_timer->setInterval(500); - - connect(m_timer, SIGNAL(timeout()), this, SLOT(procUpdateLines())); - - procShowPorts(); - int idx = ui->boxName->currentIndex(); - if (idx >= 0) - procItemPortChanged(idx); - - connect(ui->boxName, SIGNAL(currentIndexChanged(int)), this, SLOT(procItemPortChanged(int))); - connect(ui->controlButton, SIGNAL(clicked()), this, SLOT(procControlButtonClick())); - connect(ui->optionsButton, SIGNAL(clicked()), this, SLOT(procOptionsButtonClick())); - connect(ui->ioButton, SIGNAL(clicked()), this, SLOT(procIOButtonClick())); - connect(ui->rtsButton, SIGNAL(clicked()), this, SLOT(procRtsButtonClick())); - connect(ui->dtrButton, SIGNAL(clicked()), this, SLOT(procDtrButtonClick())); -} - -MainDialog::~MainDialog() -{ - if (m_port->isOpen()) - m_port->close(); - delete ui; -} - - -/* Protected methods */ - - -void MainDialog::changeEvent(QEvent *e) -{ - QDialog::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} - - -/* Private slots */ - - -void MainDialog::procShowPorts() -{ - ui->boxName->clear(); - foreach(SerialPortInfo inf, SerialPortInfo::availablePorts()) { - QStringList sl; - sl << inf.systemLocation() << inf.description() << inf.manufacturer(); - ui->boxName->addItem(inf.portName(), QVariant(sl)); - } -} - -void MainDialog::procItemPortChanged(int idx) -{ - QStringList sl = ui->boxName->itemData(idx).toStringList(); - ui->lbLocation->setText(sl.at(0)); - ui->lbDescr->setText(sl.at(1)); - ui->lbMfg->setText(sl.at(2)); -} - -void MainDialog::procControlButtonClick() -{ - if (m_port->isOpen()) { - m_timer->stop(); - m_port->close(); - ui->controlButton->setText(tr("Open")); - ui->optionsButton->setEnabled(false); - ui->ioButton->setEnabled(false); - ui->rtsButton->setEnabled(false); - ui->dtrButton->setEnabled(false); - ui->boxName->setEnabled(true); - ui->modeGroupBox->setEnabled(true); - } else { - m_port->setPort(ui->boxName->currentText()); - int idx = ui->modeComboBox->currentIndex(); - bool ok = false; - idx = ui->modeComboBox->itemData(idx).toInt(&ok); - if (ok && m_port->open((QIODevice::OpenMode)idx)) { - ui->controlButton->setText(tr("Close")); - ui->optionsButton->setEnabled(true); - ui->ioButton->setEnabled(true); - ui->rtsButton->setEnabled(true); - ui->dtrButton->setEnabled(true); - ui->boxName->setEnabled(false); - ui->modeGroupBox->setEnabled(false); - m_timer->start(); - } - } -} - -void MainDialog::procOptionsButtonClick() -{ - OptionsDialog dlg(m_port); - dlg.exec(); -} - -void MainDialog::procIOButtonClick() -{ - TraceDialog dlg(m_port); - dlg.exec(); -} - -void MainDialog::procRtsButtonClick() -{ - m_port->setRts(!m_rts); -} - -void MainDialog::procDtrButtonClick() -{ - m_port->setDtr(!m_dtr); -} - -void MainDialog::procUpdateLines() -{ - SerialPort::Lines lines = m_port->lines(); - m_rts = SerialPort::Rts & lines; - m_dtr = SerialPort::Dtr & lines; - - ui->leLabel->setEnabled(SerialPort::Le & lines); - ui->dtrLabel->setEnabled(m_dtr); - ui->rtsLabel->setEnabled(m_rts); - //ui->stLabel->setEnabled(SerialPort::St & lines); - //ui->srLabel->setEnabled(SerialPort::Sr & lines); - ui->ctsLabel->setEnabled(SerialPort::Cts & lines); - ui->dcdLabel->setEnabled(SerialPort::Dcd & lines); - ui->ringLabel->setEnabled(SerialPort::Ri & lines); - ui->dsrLabel->setEnabled(SerialPort::Dsr & lines); - - ui->rtsButton->setText((m_rts) ? tr("Clear RTS") : tr("Set RTS")); - ui->dtrButton->setText((m_dtr) ? tr("Clear DTR") : tr("Set DTR")); -} - - -/* Private methods */ - - -void MainDialog::fillOpenModeComboBox() -{ - ui->modeComboBox->addItem(QString(tr("Read and write")), QVariant(QIODevice::ReadWrite)); - ui->modeComboBox->addItem(QString(tr("Read only")), QVariant(QIODevice::ReadOnly)); - ui->modeComboBox->addItem(QString(tr("Write only")), QVariant(QIODevice::WriteOnly)); -} diff --git a/tests/guiapp/maindialog.h b/tests/guiapp/maindialog.h deleted file mode 100644 index 889c8ce..0000000 --- a/tests/guiapp/maindialog.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef MAINDIALOG_H -#define MAINDIALOG_H - -#include - -namespace Ui { -class MainDialog; -} - -class SerialPort; -class QTimer; - -class MainDialog : public QDialog -{ - Q_OBJECT -public: - explicit MainDialog(QWidget *parent = 0); - ~MainDialog(); - -protected: - void changeEvent(QEvent *e); - -private slots: - void procShowPorts(); - void procItemPortChanged(int idx); - - void procControlButtonClick(); - void procOptionsButtonClick(); - void procIOButtonClick(); - void procRtsButtonClick(); - void procDtrButtonClick(); - - void procUpdateLines(); - -private: - Ui::MainDialog *ui; - - SerialPort *m_port; - QTimer *m_timer; - - bool m_rts; - bool m_dtr; - - void fillOpenModeComboBox(); - -}; - -#endif // MAINDIALOG_H diff --git a/tests/guiapp/maindialog.ui b/tests/guiapp/maindialog.ui deleted file mode 100644 index ed54e13..0000000 --- a/tests/guiapp/maindialog.ui +++ /dev/null @@ -1,275 +0,0 @@ - - - MainDialog - - - - 0 - 0 - 411 - 240 - - - - Simple GUI application for demonstrating the use of QSerialDevice. - - - - - - Open mode: - - - - - - - - - - - - Available ports: - - - - - - Name: - - - - - - - - - - Location: - - - - - - - *** - - - - - - - Description: - - - - - - - *** - - - - - - - Manufacturer: - - - - - - - *** - - - - - - - Busy: - - - - - - - *** - - - - - - - - - - Open - - - - - - - false - - - Options - - - - - - - false - - - Input/Output - - - - - - - false - - - Set RTS - - - - - - - Serial lines states - - - Qt::AlignCenter - - - - - - - false - - - Set DTR - - - - - - - - - Qt::Vertical - - - - - - - DSR - - - - - - - Qt::Vertical - - - - - - - DTR - - - - - - - Qt::Vertical - - - - - - - CTS - - - - - - - Qt::Vertical - - - - - - - RTS - - - - - - - Qt::Vertical - - - - - - - DCD - - - - - - - Qt::Vertical - - - - - - - RING - - - - - - - Qt::Vertical - - - - - - - LE - - - - - - - Qt::Vertical - - - - - - - - - - - diff --git a/tests/guiapp/optionsdialog.cpp b/tests/guiapp/optionsdialog.cpp deleted file mode 100644 index 0af227e..0000000 --- a/tests/guiapp/optionsdialog.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include - -#include "optionsdialog.h" -#include "ui_optionsdialog.h" - -#include "serialport.h" - - -/* Public methods */ - - -OptionsDialog::OptionsDialog(SerialPort *port, QWidget *parent) - : QDialog(parent) - , ui(new Ui::OptionsDialog) - , m_port(port) - , m_rate(0), m_data(0), m_parity(0), m_stop(0), m_flow(0), m_policy(0) -{ - ui->setupUi(this); - procFillingOptions(); - - connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(procApplyButtonClick())); -} - -OptionsDialog::~OptionsDialog() -{ - delete ui; -} - - -/* Protected methods. */ - - -void OptionsDialog::showEvent(QShowEvent *e) -{ - Q_UNUSED(e) - detectOptions(); -} - - -/* Private slots */ - - -void OptionsDialog::procFillingOptions() -{ - ui->baudBox->addItem(tr("9600"), SerialPort::Rate9600); - ui->baudBox->addItem(tr("19200"), SerialPort::Rate19200); - ui->baudBox->addItem(tr("38400"), SerialPort::Rate38400); - ui->baudBox->addItem(tr("57600"), SerialPort::Rate57600); - ui->baudBox->addItem(tr("115200"), SerialPort::Rate115200); - ui->baudBox->addItem(tr("Unknown"), SerialPort::UnknownRate); - - ui->dataBox->addItem(tr("5"), SerialPort::Data5); - ui->dataBox->addItem(tr("6"), SerialPort::Data6); - ui->dataBox->addItem(tr("7"), SerialPort::Data7); - ui->dataBox->addItem(tr("8"), SerialPort::Data8); - ui->dataBox->addItem(tr("Unknown"), SerialPort::UnknownDataBits); - - ui->parityBox->addItem(tr("None"), SerialPort::NoParity); - ui->parityBox->addItem(tr("Even"), SerialPort::EvenParity); - ui->parityBox->addItem(tr("Odd"), SerialPort::OddParity); - ui->parityBox->addItem(tr("Mark"), SerialPort::MarkParity); - ui->parityBox->addItem(tr("Space"), SerialPort::SpaceParity); - ui->parityBox->addItem(tr("Unknown"), SerialPort::UnknownParity); - - ui->stopBox->addItem(tr("1"), SerialPort::OneStop); - ui->stopBox->addItem(tr("1.5"), SerialPort::OneAndHalfStop); - ui->stopBox->addItem(tr("2"), SerialPort::TwoStop); - ui->stopBox->addItem(tr("Unknown"), SerialPort::UnknownStopBits); - - ui->flowBox->addItem(tr("Off"), SerialPort::NoFlowControl); - ui->flowBox->addItem(tr("Hardware"), SerialPort::HardwareControl); - ui->flowBox->addItem(tr("Software"), SerialPort::SoftwareControl); - ui->flowBox->addItem(tr("Unknown"), SerialPort::UnknownFlowControl); - - ui->policyBox->addItem(tr("Skip"), SerialPort::SkipPolicy); - ui->policyBox->addItem(tr("PassZero"), SerialPort::PassZeroPolicy); - ui->policyBox->addItem(tr("Ignore"), SerialPort::IgnorePolicy); - ui->policyBox->addItem(tr("StopReceiving"), SerialPort::StopReceivingPolicy); - ui->policyBox->addItem(tr("Unknown"), SerialPort::UnknownPolicy); -} - -void OptionsDialog::procApplyButtonClick() -{ - bool ok; - bool hasChanged = false; - - int val = ui->baudBox->itemData(ui->baudBox->currentIndex()).toInt(&ok); - if (val != m_rate) { - m_port->setRate(SerialPort::Rate(val)); - hasChanged = true; - } - - val = ui->dataBox->itemData(ui->dataBox->currentIndex()).toInt(&ok); - if (val != m_data) { - m_port->setDataBits(SerialPort::DataBits(val)); - hasChanged = true; - } - - val = ui->parityBox->itemData(ui->parityBox->currentIndex()).toInt(&ok); - if (val != m_parity) { - m_port->setParity(SerialPort::Parity(val)); - hasChanged = true; - } - - val = ui->stopBox->itemData(ui->stopBox->currentIndex()).toInt(&ok); - if (val != m_stop) { - m_port->setStopBits(SerialPort::StopBits(val)); - hasChanged = true; - } - - val = ui->flowBox->itemData(ui->flowBox->currentIndex()).toInt(&ok); - if (val != m_flow) { - m_port->setFlowControl(SerialPort::FlowControl(val)); - hasChanged = true; - } - - val = ui->policyBox->itemData(ui->policyBox->currentIndex()).toInt(&ok); - if (val != m_policy) { - m_port->setDataErrorPolicy(SerialPort::DataErrorPolicy(val)); - hasChanged = true; - } - - if (hasChanged) - detectOptions(); -} - - -/* Private methods */ - - -void OptionsDialog::detectOptions() -{ - m_rate = m_port->rate(); - switch (m_rate) { - case SerialPort::Rate9600: - case SerialPort::Rate19200: - case SerialPort::Rate38400: - case SerialPort::Rate57600: - case SerialPort::Rate115200: - break; - default: m_rate = SerialPort::UnknownRate; - } - int count = ui->baudBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->baudBox->itemData(i).toInt(&ok) == m_rate) { - ui->baudBox->setCurrentIndex(i); - break; - } - } - - m_data = m_port->dataBits(); - switch (m_data) { - case SerialPort::Data5: - case SerialPort::Data6: - case SerialPort::Data7: - case SerialPort::Data8: - break; - default: m_data = SerialPort::UnknownDataBits; - } - count = ui->dataBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->dataBox->itemData(i).toInt(&ok) == m_data) { - ui->dataBox->setCurrentIndex(i); - break; - } - } - - m_parity = m_port->parity(); - switch (m_parity) { - case SerialPort::NoParity: - case SerialPort::EvenParity: - case SerialPort::OddParity: - case SerialPort::MarkParity: - case SerialPort::SpaceParity: - break; - default: m_parity = SerialPort::UnknownParity; - } - count = ui->parityBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->parityBox->itemData(i).toInt(&ok) == m_parity) { - ui->parityBox->setCurrentIndex(i); - break; - } - } - - m_stop = m_port->stopBits(); - switch (m_stop) { - case SerialPort::OneStop: - case SerialPort::OneAndHalfStop: - case SerialPort::TwoStop: - break; - default: m_stop = SerialPort::UnknownStopBits; - } - count = ui->stopBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->stopBox->itemData(i).toInt(&ok) == m_stop) { - ui->stopBox->setCurrentIndex(i); - break; - } - } - - m_flow = m_port->flowControl(); - switch (m_flow) { - case SerialPort::NoFlowControl: - case SerialPort::HardwareControl: - case SerialPort::SoftwareControl: - break; - default: m_flow = SerialPort::UnknownFlowControl; - } - count = ui->flowBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->flowBox->itemData(i).toInt(&ok) == m_flow) { - ui->flowBox->setCurrentIndex(i); - break; - } - } - - m_policy = m_port->dataErrorPolicy(); - switch (m_policy) { - case SerialPort::PassZeroPolicy: - case SerialPort::IgnorePolicy: - case SerialPort::StopReceivingPolicy: - break; - default: m_flow = SerialPort::UnknownPolicy; - } - count = ui->policyBox->count(); - for (int i = 0; i < count; ++i) { - bool ok; - if (ui->policyBox->itemData(i).toInt(&ok) == m_policy) { - ui->policyBox->setCurrentIndex(i); - break; - } - } -} - - - - - - - - - - diff --git a/tests/guiapp/optionsdialog.h b/tests/guiapp/optionsdialog.h deleted file mode 100644 index c4ac69d..0000000 --- a/tests/guiapp/optionsdialog.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef OPTIONSDIALOG_H -#define OPTIONSDIALOG_H - -#include - -namespace Ui { -class OptionsDialog; -} - -class SerialPort; - -class OptionsDialog : public QDialog -{ - Q_OBJECT -public: - explicit OptionsDialog(SerialPort *port, QWidget *parent = 0); - ~OptionsDialog(); - -protected: - void showEvent(QShowEvent *e); - -private slots: - void procFillingOptions(); - void procApplyButtonClick(); - -private: - Ui::OptionsDialog *ui; - SerialPort *m_port; - int m_rate; - int m_data; - int m_parity; - int m_stop; - int m_flow; - int m_policy; - - void detectOptions(); -}; - -#endif // OPTIONSDIALOG_H diff --git a/tests/guiapp/optionsdialog.ui b/tests/guiapp/optionsdialog.ui deleted file mode 100644 index 6f5b065..0000000 --- a/tests/guiapp/optionsdialog.ui +++ /dev/null @@ -1,91 +0,0 @@ - - - OptionsDialog - - - - 0 - 0 - 161 - 197 - - - - Options - - - - - - Baud rate: - - - - - - - - - - Data bits: - - - - - - - - - - Parity: - - - - - - - - - - Stop bits: - - - - - - - - - - Flow control: - - - - - - - - - - Policy: - - - - - - - - - - true - - - Apply - - - - - - - - diff --git a/tests/guiapp/tracedialog.cpp b/tests/guiapp/tracedialog.cpp deleted file mode 100644 index f8d6d3e..0000000 --- a/tests/guiapp/tracedialog.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include "tracedialog.h" -#include "ui_tracedialog.h" - -#include "serialport.h" - - -/* Public methods */ - - -TraceDialog::TraceDialog(SerialPort *port, QWidget *parent) - : QDialog(parent) - , ui(new Ui::TraceDialog) - , m_port(port) -{ - ui->setupUi(this); - ui->textEdit->document()->setMaximumBlockCount(100); - - connect(ui->sendButton, SIGNAL(clicked()), this, SLOT(procSendButtonClick())); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(procClearButtonClick())); - - connect(m_port, SIGNAL(readyRead()), this, SLOT(procReadyRead())); -} - -TraceDialog::~TraceDialog() -{ - delete ui; -} - - -/* Protected methods */ - - -void TraceDialog::changeEvent(QEvent *e) -{ - QDialog::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} - - -/* Private slots */ - - -void TraceDialog::printTrace(const QByteArray &data, bool directionRx) -{ - ui->textEdit->setTextColor((directionRx) ? Qt::darkBlue : Qt::darkGreen); - ui->textEdit->insertPlainText(QString(data)); - - QScrollBar *bar = ui->textEdit->verticalScrollBar(); - bar->setValue(bar->maximum()); -} - -void TraceDialog::procSendButtonClick() -{ - QByteArray data; - data.append(ui->lineEdit->text()); - if (data.size() > 0) { - m_port->write(data); - printTrace(data, false); - ui->lbError->setText(QString::number(m_port->error())); - } -} - -void TraceDialog::procClearButtonClick() -{ - ui->textEdit->clear(); -} - -void TraceDialog::procReadyRead() -{ - QByteArray data = m_port->readAll(); - printTrace(data, true); - ui->lbError->setText(QString::number(m_port->error())); -} diff --git a/tests/guiapp/tracedialog.h b/tests/guiapp/tracedialog.h deleted file mode 100644 index 8d5c58a..0000000 --- a/tests/guiapp/tracedialog.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TRACEDIALOG_H -#define TRACEDIALOG_H - -#include - -namespace Ui { -class TraceDialog; -} - -class SerialPort; - -class TraceDialog : public QDialog -{ - Q_OBJECT -public: - explicit TraceDialog(SerialPort *port, QWidget *parent = 0); - ~TraceDialog(); - -protected: - void changeEvent(QEvent *e); - -private slots: - void printTrace(const QByteArray &data, bool directionRx); - void procSendButtonClick(); - void procClearButtonClick(); - void procReadyRead(); - -private: - Ui::TraceDialog *ui; - - SerialPort *m_port; -}; - -#endif // TRACEDIALOG_H diff --git a/tests/guiapp/tracedialog.ui b/tests/guiapp/tracedialog.ui deleted file mode 100644 index eef1a98..0000000 --- a/tests/guiapp/tracedialog.ui +++ /dev/null @@ -1,70 +0,0 @@ - - - TraceDialog - - - - 0 - 0 - 322 - 276 - - - - Trace - - - - - - true - - - - - - - Send - - - - - - - - - - Clear trace - - - - - - - (Here enter a line in text a format for sending, - for example: I will be transferred) - - - Qt::AlignCenter - - - - - - - Last error: - - - - - - - *** - - - - - - - - diff --git a/tests/guidevtest/guidevtest.pro b/tests/guidevtest/guidevtest.pro deleted file mode 100644 index b07e6f9..0000000 --- a/tests/guidevtest/guidevtest.pro +++ /dev/null @@ -1,45 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2011-10-15T16:26:56 -# -#------------------------------------------------- - -QT += core gui - -TARGET = guidevtest -TEMPLATE = app - -INCLUDEPATH += \ - ../../include \ - ../../src - -HEADERS += \ - ../../include/serialport.h \ - ../../include/serialportinfo.h - -include(../../src/src.pri) - -SOURCES += \ - main.cpp \ - maindialog.cpp \ - unittestinfo.cpp \ - unittestsignals.cpp \ - unittestwaitforx.cpp \ - unittestio.cpp - -HEADERS += \ - maindialog.h \ - unittests.h - -FORMS += \ - maindialog.ui - - - - - - - - - - diff --git a/tests/guidevtest/main.cpp b/tests/guidevtest/main.cpp deleted file mode 100644 index 44b9ad1..0000000 --- a/tests/guidevtest/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -#include "maindialog.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - - QCoreApplication::setOrganizationName("Kuzulis"); - QCoreApplication::setOrganizationDomain("kuzulis.com"); - QCoreApplication::setApplicationName("QSerialDevice unit test"); - - MainDialog w; - w.show(); - - return a.exec(); -} diff --git a/tests/guidevtest/maindialog.cpp b/tests/guidevtest/maindialog.cpp deleted file mode 100644 index 1e3b767..0000000 --- a/tests/guidevtest/maindialog.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "maindialog.h" -#include "ui_maindialog.h" - -#include -#include -#include -#include - -#include "unittests.h" -#include "serialportinfo.h" - - -// Logger - -/* Public methods */ - -Logger::Logger(QObject *parent) - : QObject(parent), m_file(new QFile(this)) -{ -} - -void Logger::setFileName(const QString &name) -{ - m_file->setFileName(name); -} - -void Logger::addContent(const QString &content, bool clearAll) -{ - QIODevice::OpenMode mode = - QIODevice::WriteOnly | QIODevice::Text; - mode |= (clearAll) ? - QIODevice::Truncate : QIODevice::Append; - - if (m_file->open(mode)) { - m_file->write(content.toLocal8Bit()); - m_file->close(); - } -} - - -// UnitTestBase - -/* Public methods */ - -UnitTestBase::UnitTestBase(UnitID id, Logger *logger, QObject *parent) - : QObject(parent), m_id(id), m_logger(logger) - , m_srcPort(0), m_dstPort(0) -{ - Q_ASSERT(logger); - m_enableParam = "TestID%1/enable"; - m_enableParam = m_enableParam.arg(id); -} - -void UnitTestBase::setPair(const QString &src, const QString &dst) -{ - m_srcPortName = src; - m_dstPortName = dst; -} - -void UnitTestBase::setEnable(bool enable) -{ - QSettings settings; - settings.setValue(m_enableParam, enable); -} - -bool UnitTestBase::isEnabled() const -{ - QSettings settings; - return settings.value(m_enableParam).toBool(); -} - -int UnitTestBase::id() const -{ - return m_id; -} - -QString UnitTestBase::name() const -{ - return m_name; -} - -QString UnitTestBase::description() const -{ - return m_description; -} - - -// UnitTestFactory - -/* Public methods */ - -UnitTestBase *UnitTestFactory::create(UnitTestBase::UnitID id, Logger *logger) -{ - switch (id) { - case UnitTestBase::InfoUnitId: - return new UnitTestInfo(logger); - case UnitTestBase::SignalsUnitId: - return new UnitTestSignals(logger); - case UnitTestBase::WaitForXUnitId: - return new UnitTestWaitForX(logger); - case UnitTestBase::IOUnitId: - return new UnitTestIO(logger); - default:; - } - - return 0; -} - - -// TestsViewModel - -/* Public methods */ - -TestsViewModel::TestsViewModel(const QList &list, QObject *parent) - : QAbstractListModel(parent) -{ - m_testsList = list; -} - -int TestsViewModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return m_testsList.count(); -} - -QVariant TestsViewModel::data(const QModelIndex &index, int role) const -{ - if (index.isValid() - && (index.row() < m_testsList.count())) { - UnitTestBase *item = m_testsList.at(index.row()); - if (role == Qt::DisplayRole) - return item->name(); - if (role == Qt::CheckStateRole) - return item->isEnabled() ? Qt::Checked : Qt::Unchecked; - } - return QVariant(); -} - -QVariant TestsViewModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section); - Q_UNUSED(orientation); - Q_UNUSED(role); - return QVariant(); -} - -Qt::ItemFlags TestsViewModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flag = Qt::ItemIsEnabled; - if (index.isValid()) - flag |= Qt::ItemIsUserCheckable | Qt::ItemIsSelectable; - return flag; -} - -bool TestsViewModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (index.isValid()) { - UnitTestBase *item = m_testsList.at(index.row()); - if (role == Qt::CheckStateRole) { - bool enable = value.toBool(); - if (item->isEnabled() != enable) { - item->setEnable(enable); - emit dataChanged(index, index); - return true; - } - } - } - return false; -} - -QModelIndex TestsViewModel::index(int row, int column, const QModelIndex &parent) const -{ - Q_UNUSED(parent); - if (row < m_testsList.count()) - return createIndex(row, column, m_testsList.at(row)); - return QModelIndex(); -} - - -// DescriptionDialog - -/* Public methods */ - -DescriptionDialog::DescriptionDialog(const QString &content, QWidget *parent) - : QDialog(parent) -{ - QTextEdit *widget = new QTextEdit; - widget->setReadOnly(true); - widget->setText(content); - QHBoxLayout *layout = new QHBoxLayout; - layout->addWidget(widget); - setLayout(layout); -} - - -// MainDialog - -/* Public methods */ - -MainDialog::MainDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::MainDialog) - , m_enabledTestsCount(0), m_it(0) -{ - ui->setupUi(this); - - m_logger = new Logger(this); - - fillPairs(); - showSettings(); - createAvailableTests(); - - m_model = new TestsViewModel(m_testsList, this); - ui->listView->setModel(m_model); - - connect(ui->logLineEdit, SIGNAL(textChanged(QString)), - this, SLOT(procLogChanged(QString))); - connect(ui->clearLogCheckBox, SIGNAL(clicked(bool)), - this, SLOT(procClearLogOnStartChanged(bool))); - connect(ui->breakAllCheckBox, SIGNAL(clicked(bool)), - this, SLOT(procBreakAllOnErrorChanged(bool))); - - connect(ui->startButton, SIGNAL(clicked()), - this, SLOT(procStartButtonClick())); - - connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), - this, SLOT(procItemDoubleClick(QModelIndex))); -} - -MainDialog::~MainDialog() -{ - delete ui; -} - -/* Private slots */ - -void MainDialog::procLogChanged(const QString &log) -{ - QSettings settings; - settings.setValue(logFileSettingsKey, log); -} - -void MainDialog::procClearLogOnStartChanged(bool enable) -{ - QSettings settings; - settings.setValue(clearLogOnStartSettingsKey, enable); -} - -void MainDialog::procBreakAllOnErrorChanged(bool enable) -{ - QSettings settings; - settings.setValue(breakOnErrorSettingsKey, enable); -} - -void MainDialog::procStartButtonClick() -{ - // Check pair - if (ui->srcComboBox->currentText() == ui->dstComboBox->currentText()) - return; - - // Get enabled tests num - m_enabledTestsCount = 0; - foreach (UnitTestBase *test, m_testsList) { - if (test->isEnabled()) - ++m_enabledTestsCount; - } - if (!m_enabledTestsCount) - return; - - ui->progressBar->setValue(0); - ui->progressBar->setMaximum(m_enabledTestsCount); - - m_logger->setFileName(qApp->applicationDirPath() - + "/" - + ui->logLineEdit->text()); - - // Start run - QString header(tr("\n*** S T A R T E D ***\n")); - m_logger->addContent(header, ui->clearLogCheckBox->isChecked()); - procTestStarted(); - enableUi(false); -} - -void MainDialog::procTestStarted() -{ - UnitTestBase *test = m_testsList.at(m_it++); - if (test->isEnabled()) { - test->setPair(ui->srcComboBox->currentText(), - ui->dstComboBox->currentText()); - QTimer::singleShot(1000, test, SLOT(start())); - } - else - procTestStarted(); -} - -void MainDialog::procTestFinished() -{ - ui->progressBar->setValue(ui->progressBar->maximum() - (--m_enabledTestsCount)); - if (m_enabledTestsCount == 0) { - enableUi(true); - m_it = 0; - - QString trailer(tr("\n*** S T O P P E D ***\n")); - m_logger->addContent(trailer); - return; - } - else - procTestStarted(); -} - -void MainDialog::procTestError() -{ - if (ui->breakAllCheckBox->isChecked()) { - m_enabledTestsCount = 0; - m_it = 0; - enableUi(true); - QString trailer(tr("\n*** B R E A K ***\n")); - m_logger->addContent(trailer); - } else { - procTestFinished(); - } -} - -void MainDialog::procItemDoubleClick(const QModelIndex &index) -{ - QString title(tr("About: <%1>")); - title = title.arg(index.data().toString()); - DescriptionDialog w(static_cast(index.internalPointer())->description()); - w.setWindowTitle(title); - w.exec(); -} - -/* Private methods */ - -const QString MainDialog::logFileSettingsKey = "MainDialog/logFileName"; -const QString MainDialog::breakOnErrorSettingsKey = "MainDialog/breakOnError"; -const QString MainDialog::clearLogOnStartSettingsKey = "MainDialog/clearLogOnStart"; - -void MainDialog::showSettings() -{ - QSettings settings; - ui->logLineEdit->setText(settings.value(logFileSettingsKey).toString()); - ui->clearLogCheckBox->setChecked(settings.value(clearLogOnStartSettingsKey).toBool()); - ui->breakAllCheckBox->setChecked(settings.value(breakOnErrorSettingsKey).toBool()); -} - -// Called only in constructor! -void MainDialog::createAvailableTests() -{ - // Create "Info test" - m_testsList.append(UnitTestFactory::create(UnitTestBase::InfoUnitId, m_logger)); - // Create "Signals test" - m_testsList.append(UnitTestFactory::create(UnitTestBase::SignalsUnitId, m_logger)); - // Create "WaitForX test" - m_testsList.append(UnitTestFactory::create(UnitTestBase::WaitForXUnitId, m_logger)); - // Create "IO test" - m_testsList.append(UnitTestFactory::create(UnitTestBase::IOUnitId, m_logger)); - - - foreach(UnitTestBase *test, m_testsList) { - connect(test, SIGNAL(finished()), this, SLOT(procTestFinished())); - connect(test, SIGNAL(error()), this, SLOT(procTestError())); - } -} - -// Called only in constructor! -void MainDialog::fillPairs() -{ - QStringList list; - foreach (SerialPortInfo inf, SerialPortInfo::availablePorts()) { - if (inf.isValid() && !inf.isBusy()) - list.append(inf.portName()); - } - ui->srcComboBox->addItems(list); - ui->dstComboBox->addItems(list); -} - -void MainDialog::enableUi(bool enable) -{ - ui->scrollArea->setEnabled(enable); - ui->startButton->setEnabled(enable); -} diff --git a/tests/guidevtest/maindialog.h b/tests/guidevtest/maindialog.h deleted file mode 100644 index 3e1a261..0000000 --- a/tests/guidevtest/maindialog.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef MAINDIALOG_H -#define MAINDIALOG_H - -#include -#include - - - -namespace Ui { -class MainDialog; -} - -class UnitTestBase; - -class TestsViewModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit TestsViewModel(const QList &list, QObject *parent = 0); - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole); - virtual QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const; - -private: - QList m_testsList; -}; - - -class DescriptionDialog : public QDialog -{ -public: - explicit DescriptionDialog(const QString &content, QWidget *parent = 0); -}; - - -class Logger; -class QModelIndex; - -class MainDialog : public QDialog -{ - Q_OBJECT -public: - explicit MainDialog(QWidget *parent = 0); - ~MainDialog(); - -private slots: - void procLogChanged(const QString &log); - void procClearLogOnStartChanged(bool enable); - void procBreakAllOnErrorChanged(bool enable); - - void procStartButtonClick(); - void procTestStarted(); - void procTestFinished(); - void procTestError(); - - void procItemDoubleClick(const QModelIndex &index); - -private: - Ui::MainDialog *ui; - TestsViewModel *m_model; - QList m_testsList; - Logger *m_logger; - int m_enabledTestsCount; - int m_it; - - static const QString logFileSettingsKey; - static const QString breakOnErrorSettingsKey; - static const QString clearLogOnStartSettingsKey; - - void showSettings(); - void createAvailableTests(); - void fillPairs(); - void enableUi(bool enable); -}; - -#endif // MAINDIALOG_H diff --git a/tests/guidevtest/maindialog.ui b/tests/guidevtest/maindialog.ui deleted file mode 100644 index a86bd72..0000000 --- a/tests/guidevtest/maindialog.ui +++ /dev/null @@ -1,152 +0,0 @@ - - - MainDialog - - - - 0 - 0 - 172 - 307 - - - - Quick test - - - - - - true - - - - - 0 - 0 - 158 - 248 - - - - - - - Double Click by test item for get a description. - - - - - - - - - Src: - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:7pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Select source port for pair.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; text-decoration: underline; color:#ff0000;">Note:</span><span style=" font-family:'MS Shell Dlg 2'; color:#ff0000;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; color:#ff0000;">Source port and destination port should be different!</span></p></body></html> - - - - - - - Dst: - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:7pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Select destination port for pair.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; text-decoration: underline; color:#ff0000;">Note:</span><span style=" font-family:'MS Shell Dlg 2'; color:#ff0000;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; color:#ff0000;">Source port and destination port should be different!</span></p></body></html> - - - - - - - Log: - - - - - - - Write here the name of the log file. - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:7pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Clears the log file before starting the queue test.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Otherwise, all subsequent entries will be appended to the end of file.</span></p></body></html> - - - Clear log on start. - - - - - - - Terminates all the tests, if at least one test failed. -Error condition is given by the developer within the test manually. -Change the condition on which an error, can only change your test code and recompiling the application again. - - - Break all on error - - - - - - - - - - - - - Start tests - - - - - - - 0 - - - - - - - - - diff --git a/tests/guidevtest/unittestinfo.cpp b/tests/guidevtest/unittestinfo.cpp deleted file mode 100644 index 08bcc26..0000000 --- a/tests/guidevtest/unittestinfo.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "unittests.h" -#include "serialportinfo.h" - - - -/* Public methods */ - -UnitTestInfo::UnitTestInfo(Logger *logger, QObject *parent) - : UnitTestBase(UnitTestBase::InfoUnitId, logger, parent) -{ - m_name = QString(tr("Info Test")); - m_description = QString(tr("\"Info Test\" tested class SerialPortInfo,\n" - "by calling its methods and write the results to a log.\n\n" - "In the log lists all serial ports that were discovered,\n" - "their properties, states, and supported standard rates.")); -} - -/* Public slots */ - -void UnitTestInfo::start(bool first) -{ - Q_UNUSED (first); - - QString header(tr("\n[ Test: ID#%1, Name: %2 ]\n%3\n\n")); - header = header - .arg(m_id) - .arg(m_name) - .arg(QString("timestamp"));/*.arg(UnitTestManager::timestamp());*/ - - m_logger->addContent(header); - - int it = 0; - foreach (SerialPortInfo inf, SerialPortInfo::availablePorts()) { - QString body(tr("Port# %1, name : %2\n" - " location : %3\n" - " description : %4\n" - " valid : %5\n" - " busy : %6\n" - " rates : %7\n")); - - QString r; - foreach (qint32 rate, inf.standardRates()) { - r.append(QString::number(rate)); - r.append(';'); - } - - body = body - .arg(it++) - .arg(inf.portName()) - .arg(inf.systemLocation()) - .arg(inf.description()) - .arg(inf.isValid()) - .arg(inf.isBusy()) - .arg(r); - - m_logger->addContent(body); - } - - QString trailer(tr("\nFound %1 ports.\n")); - trailer = trailer.arg(it); - m_logger->addContent(trailer); - - emit finished(); -} diff --git a/tests/guidevtest/unittestio.cpp b/tests/guidevtest/unittestio.cpp deleted file mode 100644 index 2aff9c0..0000000 --- a/tests/guidevtest/unittestio.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "unittests.h" -#include "serialport.h" - -#include -#include - - -enum { - RATES_COUNT = 2, - DATABITS_COUNT = 1, - PARITY_COUNT = 5, - STOPBITS_COUNT = 2, - FLOW_COUNT = 3 -}; - -static const SerialPort::Rate vratesarray[RATES_COUNT] = { - SerialPort::Rate9600, - SerialPort::Rate115200 -}; -static const char *sratesarray[] = { - "9600\0", - "115200\0" -}; - -static const SerialPort::DataBits vdatabitsarray[DATABITS_COUNT] = { - SerialPort::Data8 -}; -static const char *sdatabitsarray[] = { - "8\0" -}; - -static const SerialPort::Parity vparitysarray[PARITY_COUNT] = { - SerialPort::NoParity, - SerialPort::EvenParity, - SerialPort::OddParity, - SerialPort::SpaceParity, - SerialPort::MarkParity -}; -static const char *sparitysarray[] = { - "none\0", - "even\0", - "odd\0", - "space\0", - "mark\0" -}; - -static const SerialPort::StopBits vstopbitsarray[STOPBITS_COUNT] = { - SerialPort::OneStop, - SerialPort::TwoStop -}; -static const char *sstopbitsarray[] = { - "one\0", - "two\0" -}; - -static const SerialPort::FlowControl vflowsarray[FLOW_COUNT] = { - SerialPort::NoFlowControl, - SerialPort::HardwareControl, - SerialPort::SoftwareControl -}; -static const char *sflowsarray[] = { - "none\0", - "hardware\0", - "software\0" -}; - -static QString split_on_table(const QByteArray &data, int tablewidth) -{ - QString result; - int datacount = data.count(); - int i = 0; - - while (i < datacount) { - result.append(data.mid(i, tablewidth).toHex()); - result.append('\n'); - i += tablewidth; - } - return result; -} - -static QByteArray random_data_array(int arraysize) -{ - QByteArray result; - while (arraysize--) { - // Here, protection of control characters 11h, 13h - // with software flow control. - char c; - do { - c = qrand(); - } while ((c == 0x11) || (c == 0x13)); - - result.append(c); - } - return result; -} - - - -/* Public methods */ - -UnitTestIO::UnitTestIO(Logger *logger, QObject *parent) - : UnitTestBase(UnitTestBase::IOUnitId, logger, parent) - , m_rateIterator(0) - , m_databitsIterator(0) - , m_parityIterator(0) - , m_stopbitsIterator(0) - , m_flowIterator(0) - , m_bytesWrite(0) - , m_bytesRead(0) -{ - m_name = QString(tr("IO Test")); - m_description = QString(tr("\"IO Test\" designed to test the I/O between the two ports\n" - "Source port sends a data packet to the destination port,\n" - "that reads the packet.\n" - " The default packet size is 500 bytes, the size can be changed\n" - "programmatically by changing the value of the\n" - "variable TransferBytesCount. Also, before sending the package\n" - "is filled with a random value.\n" - " Both ports after each transaction, change their parameters:\n" - "speed, number of data bits, parity, number of stop bits,\n" - "flow regime, until the end all enumerated parameters.\n" - "After each transaction is recorded in a log the contents of the\n" - "sent and received packet, and check their size. If the packet\n" - "sizes are different, the test is aborted with an error which is\n" - "recorded in the log.\n" - )); - - m_srcPort = new SerialPort(this); - m_dstPort = new SerialPort(this); -} - -/* Public slots */ - -void UnitTestIO::start(bool first) -{ - if (first) { - QString header(tr("\n[ Test: ID#%1, Name: %2 ]\n%3\n\n")); - header = header - .arg(m_id) - .arg(m_name) - .arg(QString("timestamp"));/*.arg(UnitTestManager::timestamp());*/ - - m_logger->addContent(header); - - m_srcPort->setPort(m_srcPortName); - m_dstPort->setPort(m_dstPortName); - - if (!(open(UnitTestBase::SrcPort) && open(UnitTestBase::DstPort))) { - emit error(); - return; - } else { - QString content(tr("\nSource and destination ports is opened.\n")); - m_logger->addContent(content); - } - - m_rateIterator = 0; - m_databitsIterator = 0; - m_parityIterator = 0; - m_stopbitsIterator = 0; - m_flowIterator = 0; - } - - transaction(); -} - -/* Private slots */ - -void UnitTestIO::procSingleShot() -{ - QByteArray data = m_dstPort->readAll(); - - QString content("r:\n%1\n"); - content = content.arg(split_on_table(data, 32)); - m_logger->addContent(content); - - m_bytesRead = data.count(); - - content = QString(tr("= write: %1 read: %2 =\n")); - content = content - .arg(m_bytesWrite) - .arg(m_bytesRead); - m_logger->addContent(content); - - if (m_bytesWrite != m_bytesRead) { - content = QString(tr("\nError: Mismatch of write and read bytes.\n")); - m_logger->addContent(content); - close(UnitTestBase::SrcPort); - close(UnitTestBase::DstPort); - emit error(); - return; - } - - ++m_rateIterator; - if (m_rateIterator == RATES_COUNT) { - m_rateIterator = 0; - - ++m_databitsIterator; - if (m_databitsIterator == DATABITS_COUNT) { - m_databitsIterator = 0; - - ++m_parityIterator; - if (m_parityIterator == PARITY_COUNT) { - m_parityIterator = 0; - - ++m_stopbitsIterator; - if (m_stopbitsIterator == STOPBITS_COUNT) { - m_stopbitsIterator = 0; - - ++m_flowIterator; - if (m_flowIterator == FLOW_COUNT) { - m_flowIterator = 0; - - close(UnitTestBase::SrcPort); - close(UnitTestBase::DstPort); - emit finished(); - return; - } - } - } - } - } - - transaction(); -} - -void UnitTestIO::transaction() -{ - if (!(configure(UnitTestBase::SrcPort) && configure(UnitTestBase::DstPort))) { - emit error(); - return; - } - - QString content(tr("\nrate : %1" - "\ndatabits: %2" - "\npatity : %3" - "\nstopbits: %4" - "\nflow : %5\n\n")); - - content = content - .arg(QString(sratesarray[m_rateIterator])) - .arg(QString(sdatabitsarray[m_databitsIterator])) - .arg(QString(sparitysarray[m_parityIterator])) - .arg(QString(sstopbitsarray[m_stopbitsIterator])) - .arg(QString(sflowsarray[m_flowIterator])); - - m_logger->addContent(content); - - QByteArray data = random_data_array(TransferBytesCount); - m_bytesWrite = m_srcPort->write(data); - - content = "w:\n%1\n"; - content = content.arg(split_on_table(data, 32)); - m_logger->addContent(content); - - QTimer::singleShot(TransactionMsecDelay, this, SLOT(procSingleShot())); -} - -/* Private */ - -bool UnitTestIO::open(DirPorts dir) -{ - SerialPort *port = (dir == UnitTestBase::SrcPort) ? - m_srcPort : m_dstPort; - QIODevice::OpenMode mode = (dir == UnitTestBase::SrcPort) ? - QIODevice::WriteOnly : QIODevice::ReadOnly; - - QString error("\nError: Can\'t open port %1\n"); - if (!port->open(mode)) { - error = error.arg(port->portName()); - m_logger->addContent(error); - return false; - } - return true; -} - -bool UnitTestIO::configure(DirPorts dir) -{ - SerialPort *port = (dir == UnitTestBase::SrcPort) ? - m_srcPort : m_dstPort; - - if (!(port->setRate(vratesarray[m_rateIterator]) - && port->setDataBits(vdatabitsarray[m_databitsIterator]) - && port->setParity(vparitysarray[m_parityIterator]) - && port->setStopBits(vstopbitsarray[m_stopbitsIterator]) - && port->setFlowControl(vflowsarray[m_flowIterator]))) { - - QString error("\nError: Can\'t configure port %1\n"); - error = error.arg(port->portName()); - m_logger->addContent(error); - return false; - } - return true; -} - -void UnitTestIO::close(DirPorts dir) -{ - if (dir == UnitTestBase::SrcPort) { - if (m_srcPort->isOpen()) - m_srcPort->close(); - } else { - if (m_dstPort->isOpen()) - m_dstPort->close(); - } -} - - - - diff --git a/tests/guidevtest/unittests.h b/tests/guidevtest/unittests.h deleted file mode 100644 index 0b2fd94..0000000 --- a/tests/guidevtest/unittests.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef UNITTESTS_H -#define UNITTESTS_H - -#include - - -class QFile; - -class Logger : public QObject -{ - Q_OBJECT -public: - explicit Logger(QObject *parent = 0); - void setFileName(const QString &name); - void addContent(const QString &content, bool clearAll = false); - -private: - QFile *m_file; -}; - -class SerialPort; - -class UnitTestBase : public QObject -{ - Q_OBJECT -signals: - void finished(); - void error(); - -public: - enum UnitID { - InfoUnitId, - SignalsUnitId, - WaitForXUnitId, - IOUnitId, - - }; - - explicit UnitTestBase(UnitID id, Logger *logger, QObject *parent = 0); - void setPair(const QString &src, const QString &dst); - void setEnable(bool enable); - bool isEnabled() const; - int id() const; - QString name() const; - QString description() const; - -public slots: - virtual void start(bool first = true) = 0; - -protected: - enum DirPorts { SrcPort, DstPort }; - int m_id; - QString m_name; - QString m_description; - QString m_enableParam; - Logger *m_logger; - SerialPort *m_srcPort; - SerialPort *m_dstPort; - QString m_srcPortName; - QString m_dstPortName; -}; - - -class UnitTestInfo : public UnitTestBase -{ - Q_OBJECT -public: - explicit UnitTestInfo(Logger *logger, QObject *parent = 0); - -public slots: - virtual void start(bool first); -}; - -class UnitTestSignals : public UnitTestBase -{ - Q_OBJECT -public: - explicit UnitTestSignals(Logger *logger, QObject *parent = 0); - -public slots: - virtual void start(bool first); - -private slots: - void procSignalBytesWritten(qint64 bw); - void procSignalReadyRead(); - void procSingleShot(); - void transaction(); - -private: - enum { - TransactionLimit = 5, - TransactionMsecDelay = 1000, - MinBytesToWrite = 1, - StepBytesToWrite = 100 - }; - - bool m_started; - int m_transactionNum; - qint64 m_bytesToWrite; - qint64 m_bytesReallyWrited; - int m_countSignalsBytesWritten; - int m_countSignalsReadyRead; - - - bool open(DirPorts dir); - bool configure(DirPorts dir); - void close(DirPorts dir); -}; - -class UnitTestWaitForX : public UnitTestBase -{ - Q_OBJECT -public: - explicit UnitTestWaitForX(Logger *logger, QObject *parent = 0); - -public slots: - virtual void start(bool first); -}; - -class UnitTestIO : public UnitTestBase -{ - Q_OBJECT -public: - explicit UnitTestIO(Logger *logger, QObject *parent = 0); - -public slots: - virtual void start(bool first); - -private slots: - void procSingleShot(); - void transaction(); - -private: - enum { - TransferBytesCount = 500, - TransactionMsecDelay = 700 - }; - - int m_rateIterator; - int m_databitsIterator; - int m_parityIterator; - int m_stopbitsIterator; - int m_flowIterator; - - qint64 m_bytesWrite; - qint64 m_bytesRead; - - bool open(DirPorts dir); - bool configure(DirPorts dir); - void close(DirPorts dir); -}; - - - - - - - - - -class UnitTestFactory -{ -public: - static UnitTestBase *create(UnitTestBase::UnitID id, Logger *logger); -}; - - -#endif // UNITTESTS_H diff --git a/tests/guidevtest/unittestsignals.cpp b/tests/guidevtest/unittestsignals.cpp deleted file mode 100644 index ade4877..0000000 --- a/tests/guidevtest/unittestsignals.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "unittests.h" -#include "serialport.h" - -#include -//#include - - -/* Public methods */ - -UnitTestSignals::UnitTestSignals(Logger *logger, QObject *parent) - : UnitTestBase(UnitTestBase::SignalsUnitId, logger, parent) - , m_started(false), m_transactionNum(0), m_bytesToWrite(0) - , m_bytesReallyWrited(0), m_countSignalsBytesWritten(0) - , m_countSignalsReadyRead(0) -{ - m_name = QString(tr("Signals Test")); - m_description = QString(tr("\"Signals Test\" monitors and verifies the correctness of the\n" - "emission signals bytesWritten() and readyRead().\n\n" - "This test uses the source port and destination port.\n\n" - "The source port is opened only as write-only, and this\n" - "test from the port set control a signal bytesWritten().\n" - "In this case, count the number of emit signals bytesWritten()\n" - "and the number of bytes of data transmitted in the signal for\n" - "a single emit.\n\n" - "The destination port is opened as read-only, and this\n" - "test from the port set control a signal readyRead().\n" - "At the same time count the number of signals readyRead().\n\n" - "By default ports are opened in the mode: 9600 8 N 1, no flow control.\n" - "The testing process consists of several stages:\n\n" - " Stage1. Opened and initialized ports. If an error occurs, it is\n" - "recorded in the log and testing is completed with failure. If\n" - "everything goes well, then go to stage 2.\n\n" - " Stage2. Run single shot the timer interval to 1 second, and\n" - "further, the source port sends a byte, at the same time are tracked\n" - "and logged signals from the ports. Further, when the timer works,\n" - "there is a processing of the results of the signals. Compares the\n" - "number of bytes sent and received, and these results or an error is\n" - "generated with the termination of the test, or go to stage 3.\n\n" - " Stage3. No different from stage 2 with the exception of the number\n" - "of bytes transmitted. Now write not one but several bytes. The number\n" - "of bytes transmitted is now increasing, according to the formula:\n" - "NumCurr = NumPrev + K, where K - some constant. Further, the\n" - "termination of a test or go to stage 4.\n\n" - " Stage4. Does not differ from step 3, except the number of bytes.\n\n" - " StageN. No different from the previous steps.\n\n" - "By default, the number of transactions (steps) for the transfer of\n" - "data is five, but this value can be changed by editing the source\n" - "code of the test. In the source code you can change settings such as:\n" - "- timeout of timer (by default 1 sec)\n" - "- number of steps (by default 5)\n" - "- initial number of bytes transmitted (by default 1 byte)\n" - "- constant growth rate K of transmitted bytes (by default 100 byte).")); - - m_srcPort = new SerialPort(this); - m_dstPort = new SerialPort(this); - - connect(m_srcPort, SIGNAL(bytesWritten(qint64)), - this, SLOT(procSignalBytesWritten(qint64))); - connect(m_dstPort, SIGNAL(readyRead()), - this, SLOT(procSignalReadyRead())); -} - -/* Public slots */ - -void UnitTestSignals::start(bool first) -{ - if (first) { - QString header(tr("\n[ Test: ID#%1, Name: %2 ]\n%3\n\n")); - header = header - .arg(m_id) - .arg(m_name) - .arg(QString("timestamp"));/*.arg(UnitTestManager::timestamp());*/ - - m_logger->addContent(header); - - m_srcPort->setPort(m_srcPortName); - m_dstPort->setPort(m_dstPortName); - - if (!(open(UnitTestBase::SrcPort) && open(UnitTestBase::DstPort) - && configure(UnitTestBase::SrcPort) && configure(UnitTestBase::DstPort))) { - - close(UnitTestBase::SrcPort); - close(UnitTestBase::DstPort); - emit error(); - return; - } else { - QString content(tr("\nSource and destination ports\n" - "opened as 9600 8 N 1 by default.\n")); - m_logger->addContent(content); - } - - // Prepare transaction begin. - m_transactionNum = 0; - m_bytesToWrite = MinBytesToWrite; - m_bytesReallyWrited = 0; - m_countSignalsBytesWritten = 0; - m_countSignalsReadyRead = 0; - } - - transaction(); -} - -/* Private slots */ - -void UnitTestSignals::procSignalBytesWritten(qint64 bw) -{ - QString content(">signal bytesWritten(%1)\n"); - content = content.arg(bw); - m_logger->addContent(content); - ++m_countSignalsBytesWritten; - m_bytesReallyWrited += bw; -} - -void UnitTestSignals::procSignalReadyRead() -{ - ++m_countSignalsReadyRead; -} - -void UnitTestSignals::procSingleShot() -{ - QByteArray data = m_dstPort->readAll(); - qint64 reallyRead = data.count(); - - QString content(tr("- count signals bytesWritten : %1\n" - "- count signals readyRead : %2\n" - "- bytes really write : %3\n" - "- bytes really read : %4\n")); - content = content - .arg(m_countSignalsBytesWritten) - .arg(m_countSignalsReadyRead) - .arg(m_bytesReallyWrited) - .arg(reallyRead); - - m_logger->addContent(content); - - m_countSignalsBytesWritten = 0; - m_countSignalsReadyRead = 0; - - if ((m_bytesReallyWrited != m_bytesToWrite) - || (m_bytesToWrite != reallyRead)) { - - content = QString(tr("\nError: Mismatch of sent and received bytes.\n")); - m_logger->addContent(content); - close(UnitTestBase::SrcPort); - close(UnitTestBase::DstPort); - emit error(); - } - - m_bytesReallyWrited = 0; - m_bytesToWrite += StepBytesToWrite; - - transaction(); -} - -void UnitTestSignals::transaction() -{ - if (m_transactionNum++ != TransactionLimit) { - QString content(tr("\nTransaction #%1, bytes to write: %2\n")); - content = content.arg(m_transactionNum).arg(m_bytesToWrite); - m_logger->addContent(content); - - QByteArray data(m_bytesToWrite, qrand()); - QTimer::singleShot(TransactionMsecDelay, this, SLOT(procSingleShot())); - m_srcPort->write(data); - } else { - close(UnitTestBase::SrcPort); - close(UnitTestBase::DstPort); - emit finished(); - } -} - -/* Private */ - -bool UnitTestSignals::open(DirPorts dir) -{ - SerialPort *port = (dir == UnitTestBase::SrcPort) ? - m_srcPort : m_dstPort; - QIODevice::OpenMode mode = (dir == UnitTestBase::SrcPort) ? - QIODevice::WriteOnly : QIODevice::ReadOnly; - - QString error("\nError: Can\'t open port %1\n"); - if (!port->open(mode)) { - error = error.arg(port->portName()); - m_logger->addContent(error); - return false; - } - return true; -} - -bool UnitTestSignals::configure(DirPorts dir) -{ - SerialPort *port = (dir == UnitTestBase::SrcPort) ? - m_srcPort : m_dstPort; - - if (!(port->setRate(9600) && port->setDataBits(SerialPort::Data8) - && port->setParity(SerialPort::NoParity) && port->setStopBits(SerialPort::OneStop) - && port->setFlowControl(SerialPort::NoFlowControl))) { - - QString error("\nError: Can\'t configure port %1\n"); - error = error.arg(port->portName()); - m_logger->addContent(error); - return false; - } - return true; -} - -void UnitTestSignals::close(DirPorts dir) -{ - if (dir == UnitTestBase::SrcPort) { - if (m_srcPort->isOpen()) - m_srcPort->close(); - } else { - if (m_dstPort->isOpen()) - m_dstPort->close(); - } -} - - diff --git a/tests/guidevtest/unittestwaitforx.cpp b/tests/guidevtest/unittestwaitforx.cpp deleted file mode 100644 index a9dd3cb..0000000 --- a/tests/guidevtest/unittestwaitforx.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "unittests.h" -#include "serialport.h" - - - -/* Public methods */ - -UnitTestWaitForX::UnitTestWaitForX(Logger *logger, QObject *parent) - : UnitTestBase(UnitTestBase::WaitForXUnitId, logger, parent) -{ - m_name = QString(tr("WaitForX Test")); - m_description = QString(tr("\"WaitForX Test\" ...")); -} - -/* Public slots */ - -void UnitTestWaitForX::start(bool first) -{ - Q_UNUSED(first); - - QString header(tr("\n[ Test: ID#%1, Name: %2 ]\n%3\n\n")); - header = header - .arg(m_id) - .arg(m_name) - .arg(QString("timestamp"));/*.arg(UnitTestManager::timestamp());*/ - - m_logger->addContent(header); - - //// - - emit finished(); -} - -- cgit v1.2.1