diff options
author | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-08-09 15:27:26 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-08-09 15:27:26 +0200 |
commit | 50956f5476487ee10b1d3a8e339ea3e3222f883d (patch) | |
tree | b21758e348ec4ba4e49de9a0316166c6414e478e | |
parent | eb0dd8763c235b027bea91d5ec7fd82f06cacbab (diff) | |
parent | c0aebf3dfe3c6837db8f91d65ac4b6b7b44e100e (diff) | |
download | qtserialport-50956f5476487ee10b1d3a8e339ea3e3222f883d.tar.gz |
Merge remote-tracking branch 'origin/5.5' into dev
Change-Id: I913394721091750d64dad3ed0fd08ef8616edcf9
-rw-r--r-- | examples/serialport/terminal/mainwindow.cpp | 29 | ||||
-rw-r--r-- | examples/serialport/terminal/mainwindow.h | 5 | ||||
-rw-r--r-- | src/serialport/qserialport.cpp | 87 | ||||
-rw-r--r-- | src/serialport/qserialport.h | 2 | ||||
-rw-r--r-- | src/serialport/qserialport_p.h | 26 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 226 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 198 | ||||
-rw-r--r-- | src/serialport/qserialport_wince.cpp | 118 | ||||
-rw-r--r-- | src/serialport/qserialportinfo.cpp | 2 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_mac.cpp | 13 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_unix.cpp | 11 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 11 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_wince.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qserialport/tst_qserialport.cpp | 112 | ||||
-rw-r--r-- | tests/manual/manual.pro | 3 | ||||
-rw-r--r-- | tests/manual/qserialport/qserialport.pro | 7 | ||||
-rw-r--r-- | tests/manual/qserialport/tst_qserialport.cpp | 208 | ||||
-rw-r--r-- | tests/manual/qserialportinfo/qserialportinfo.pro | 7 | ||||
-rw-r--r-- | tests/manual/qserialportinfo/tst_qserialportinfo.cpp | 100 | ||||
-rw-r--r-- | tests/tests.pro | 2 |
20 files changed, 463 insertions, 706 deletions
diff --git a/examples/serialport/terminal/mainwindow.cpp b/examples/serialport/terminal/mainwindow.cpp index 9a98456..3630b1f 100644 --- a/examples/serialport/terminal/mainwindow.cpp +++ b/examples/serialport/terminal/mainwindow.cpp @@ -38,6 +38,7 @@ #include "settingsdialog.h" #include <QMessageBox> +#include <QLabel> #include <QtSerialPort/QSerialPort> //! [0] @@ -60,6 +61,9 @@ MainWindow::MainWindow(QWidget *parent) : ui->actionQuit->setEnabled(true); ui->actionConfigure->setEnabled(true); + status = new QLabel; + ui->statusBar->addWidget(status); + initActionsConnections(); connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, @@ -90,18 +94,18 @@ void MainWindow::openSerialPort() serial->setStopBits(p.stopBits); serial->setFlowControl(p.flowControl); if (serial->open(QIODevice::ReadWrite)) { - console->setEnabled(true); - console->setLocalEchoEnabled(p.localEchoEnabled); - ui->actionConnect->setEnabled(false); - ui->actionDisconnect->setEnabled(true); - ui->actionConfigure->setEnabled(false); - ui->statusBar->showMessage(tr("Connected to %1 : %2, %3, %4, %5, %6") - .arg(p.name).arg(p.stringBaudRate).arg(p.stringDataBits) - .arg(p.stringParity).arg(p.stringStopBits).arg(p.stringFlowControl)); + console->setEnabled(true); + console->setLocalEchoEnabled(p.localEchoEnabled); + ui->actionConnect->setEnabled(false); + ui->actionDisconnect->setEnabled(true); + ui->actionConfigure->setEnabled(false); + showStatusMessage(tr("Connected to %1 : %2, %3, %4, %5, %6") + .arg(p.name).arg(p.stringBaudRate).arg(p.stringDataBits) + .arg(p.stringParity).arg(p.stringStopBits).arg(p.stringFlowControl)); } else { QMessageBox::critical(this, tr("Error"), serial->errorString()); - ui->statusBar->showMessage(tr("Open error")); + showStatusMessage(tr("Open error")); } } //! [4] @@ -115,7 +119,7 @@ void MainWindow::closeSerialPort() ui->actionConnect->setEnabled(true); ui->actionDisconnect->setEnabled(false); ui->actionConfigure->setEnabled(true); - ui->statusBar->showMessage(tr("Disconnected")); + showStatusMessage(tr("Disconnected")); } //! [5] @@ -162,3 +166,8 @@ void MainWindow::initActionsConnections() connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about())); connect(ui->actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); } + +void MainWindow::showStatusMessage(const QString &message) +{ + status->setText(message); +} diff --git a/examples/serialport/terminal/mainwindow.h b/examples/serialport/terminal/mainwindow.h index 51524e1..64b9e25 100644 --- a/examples/serialport/terminal/mainwindow.h +++ b/examples/serialport/terminal/mainwindow.h @@ -43,6 +43,8 @@ QT_BEGIN_NAMESPACE +class QLabel; + namespace Ui { class MainWindow; } @@ -73,7 +75,10 @@ private: void initActionsConnections(); private: + void showStatusMessage(const QString &message); + Ui::MainWindow *ui; + QLabel *status; Console *console; SettingsDialog *settings; QSerialPort *serial; diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 9d5aa40..9ed1c5f 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -97,6 +97,15 @@ int QSerialPortPrivate::timeoutValue(int msecs, int elapsed) return qMax(msecs, 0); } +void QSerialPortPrivate::setError(const QSerialPortErrorInfo &errorInfo) +{ + Q_Q(QSerialPort); + + error = errorInfo.errorCode; + q->setErrorString(errorInfo.errorString); + emit q->error(error); +} + /*! \class QSerialPort @@ -512,14 +521,14 @@ bool QSerialPort::open(OpenMode mode) Q_D(QSerialPort); if (isOpen()) { - setError(QSerialPort::OpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::OpenError, tr("Device is already open"))); return false; } // Define while not supported modes. static const OpenMode unsupportedModes = Append | Truncate | Text | Unbuffered; if ((mode & unsupportedModes) || mode == NotOpen) { - setError(QSerialPort::UnsupportedOperationError); + d->setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, tr("Unsupported open mode"))); return false; } @@ -552,7 +561,7 @@ void QSerialPort::close() { Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); return; } @@ -561,6 +570,7 @@ void QSerialPort::close() QIODevice::close(); } +#if QT_DEPRECATED_SINCE(5, 3) /*! \property QSerialPort::settingsRestoredOnClose \brief the flag which specifies to restore the previous settings when closing @@ -571,7 +581,6 @@ void QSerialPort::close() The default state of the QSerialPort class is to restore the settings. */ -#if QT_DEPRECATED_SINCE(5,3) void QSerialPort::setSettingsRestoredOnClose(bool restore) { Q_D(QSerialPort); @@ -588,6 +597,8 @@ bool QSerialPort::settingsRestoredOnClose() const return d->settingsRestoredOnClose; } #endif // QT_DEPRECATED_SINCE(5,3) + +#if QT_DEPRECATED_SINCE(5, 5) /*! \fn void QSerialPort::settingsRestoredOnCloseChanged(bool restore) \obsolete @@ -599,6 +610,7 @@ bool QSerialPort::settingsRestoredOnClose() const \sa QSerialPort::settingsRestoredOnClose */ +#endif // QT_DEPRECATED_SINCE(5, 5) /*! \property QSerialPort::baudRate @@ -862,7 +874,7 @@ bool QSerialPort::setDataTerminalReady(bool set) Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -909,7 +921,7 @@ bool QSerialPort::setRequestToSend(bool set) Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -959,7 +971,7 @@ QSerialPort::PinoutSignals QSerialPort::pinoutSignals() Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return QSerialPort::NoSignal; } @@ -989,7 +1001,7 @@ bool QSerialPort::flush() Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1011,7 +1023,7 @@ bool QSerialPort::clear(Directions directions) Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1051,6 +1063,7 @@ bool QSerialPort::atEnd() const return QIODevice::atEnd() && (!isOpen() || (d->buffer.size() == 0)); } +#if QT_DEPRECATED_SINCE(5, 2) /*! \property QSerialPort::dataErrorPolicy \brief the error policy for how the process receives characters in the case where @@ -1067,13 +1080,12 @@ bool QSerialPort::atEnd() const with the kernel and hardware. Hence, the two scenarios cannot be completely compared to each other. */ -#if QT_DEPRECATED_SINCE(5, 2) bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) { Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1093,6 +1105,8 @@ QSerialPort::DataErrorPolicy QSerialPort::dataErrorPolicy() const return d->policy; } #endif // QT_DEPRECATED_SINCE(5, 2) + +#if QT_DEPRECATED_SINCE(5, 5) /*! \fn void QSerialPort::dataErrorPolicyChanged(DataErrorPolicy policy) \obsolete @@ -1104,6 +1118,7 @@ QSerialPort::DataErrorPolicy QSerialPort::dataErrorPolicy() const \sa QSerialPort::dataErrorPolicy */ +#endif // QT_DEPRECATED_SINCE(5, 5) /*! \property QSerialPort::error @@ -1124,7 +1139,8 @@ QSerialPort::SerialPortError QSerialPort::error() const void QSerialPort::clearError() { - setError(QSerialPort::NoError); + Q_D(QSerialPort); + d->setError(QSerialPortErrorInfo(QSerialPort::NoError)); } /*! @@ -1211,7 +1227,13 @@ qint64 QSerialPort::bytesAvailable() const qint64 QSerialPort::bytesToWrite() const { Q_D(const QSerialPort); - return d->bytesToWrite() + QIODevice::bytesToWrite(); + qint64 bytes = QIODevice::bytesToWrite(); +#ifdef Q_OS_WIN32 + bytes += d->actualBytesToWrite; +#else + bytes += d->writeBuffer.size(); +#endif + return bytes; } /*! @@ -1267,6 +1289,7 @@ bool QSerialPort::waitForBytesWritten(int msecs) return d->waitForBytesWritten(msecs); } +#if QT_DEPRECATED_SINCE(5, 5) /*! Sends a continuous stream of zero bits during a specified period of time \a duration in msec if the terminal is using asynchronous @@ -1288,13 +1311,14 @@ bool QSerialPort::sendBreak(int duration) Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } return d->sendBreak(duration); } +#endif // QT_DEPRECATED_SINCE(5, 5) /*! \property QSerialPort::breakEnabled @@ -1317,7 +1341,7 @@ bool QSerialPort::setBreakEnabled(bool set) Q_D(QSerialPort); if (!isOpen()) { - setError(QSerialPort::NotOpenError); + d->setError(QSerialPortErrorInfo(QSerialPort::NotOpenError, tr("Device is not open"))); qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1341,10 +1365,27 @@ bool QSerialPort::isBreakEnabled() const /*! \reimp */ +// This function does not really read anything, as we use QIODevicePrivate's +// buffer. The buffer will be read inside of QIODevice before this +// method will be called. qint64 QSerialPort::readData(char *data, qint64 maxSize) { Q_D(QSerialPort); - return d->readData(data, maxSize); + + Q_UNUSED(data); + Q_UNUSED(maxSize); + +#ifdef Q_OS_WIN32 + // We need try to start async reading to read a remainder from a driver's queue + // in case we have a limited read buffer size. Because the read notification can + // be stalled since Windows do not re-triggered an EV_RXCHAR event if a driver's + // buffer has a remainder of data ready to read until a new data will be received. + if (d->readBufferMaxSize || d->flowControl == QSerialPort::HardwareControl) + d->startAsyncRead(); +#endif + + // return 0 indicating there may be more data in the future + return qint64(0); } /*! @@ -1364,20 +1405,6 @@ qint64 QSerialPort::writeData(const char *data, qint64 maxSize) return d->writeData(data, maxSize); } -void QSerialPort::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString) -{ - Q_D(QSerialPort); - - d->error = serialPortError; - - if (errorString.isNull() && (serialPortError != QSerialPort::NoError)) - setErrorString(qt_error_string(-1)); - else - setErrorString(errorString); - - emit error(serialPortError); -} - #include "moc_qserialport.cpp" QT_END_NAMESPACE diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index 51ff296..2815ebe 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -282,8 +282,6 @@ protected: qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE; private: - void setError(QSerialPort::SerialPortError error, const QString &errorString = QString()); - // ### Qt6: remove me. QSerialPortPrivate * const d_dummy; diff --git a/src/serialport/qserialport_p.h b/src/serialport/qserialport_p.h index 7da2204..571b0de 100644 --- a/src/serialport/qserialport_p.h +++ b/src/serialport/qserialport_p.h @@ -106,6 +106,19 @@ class QSocketNotifier; QString serialPortLockFilePath(const QString &portName); #endif +class QSerialPortErrorInfo +{ +public: + explicit QSerialPortErrorInfo(QSerialPort::SerialPortError errorCode = QSerialPort::UnknownError, + const QString &errorString = QString()) + : errorCode(errorCode) + , errorString(errorString) + { + } + QSerialPort::SerialPortError errorCode; + QString errorString; +}; + class QSerialPortPrivate : public QIODevicePrivate { Q_DECLARE_PUBLIC(QSerialPort) @@ -133,8 +146,6 @@ public: bool sendBreak(int duration); bool setBreakEnabled(bool set); - qint64 readData(char *data, qint64 maxSize); - bool waitForReadyRead(int msec); bool waitForBytesWritten(int msec); @@ -146,9 +157,10 @@ public: bool setFlowControl(QSerialPort::FlowControl flowControl); bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); - QSerialPort::SerialPortError decodeSystemError(int systemErrorCode = -1) const; + QSerialPortErrorInfo getSystemError(int systemErrorCode = -1) const; + + void setError(const QSerialPortErrorInfo &errorInfo); - qint64 bytesToWrite() const; qint64 writeData(const char *data, qint64 maxSize); static QString portNameToSystemLocation(const QString &port); @@ -240,11 +252,11 @@ public: bool initialize(QIODevice::OpenMode mode); bool updateTermios(); - QSerialPort::SerialPortError setBaudRate_helper(qint32 baudRate, + QSerialPortErrorInfo setBaudRate_helper(qint32 baudRate, QSerialPort::Directions directions); - QSerialPort::SerialPortError setCustomBaudRate(qint32 baudRate, + QSerialPortErrorInfo setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions); - QSerialPort::SerialPortError setStandardBaudRate(qint32 baudRate, + QSerialPortErrorInfo setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions); bool isReadNotificationEnabled() const; diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 1f90a18..612d84a 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -77,6 +77,10 @@ QString serialPortLockFilePath(const QString &portName) << QStringLiteral("/run/lock") #ifdef Q_OS_ANDROID << QStringLiteral("/data/local/tmp") +#elif defined(Q_OS_OSX) + // This is the workaround to specify a temporary directory + // on OSX when running the App Sandbox feature. + << QStandardPaths::writableLocation(QStandardPaths::TempLocation); #endif ; @@ -98,13 +102,6 @@ QString serialPortLockFilePath(const QString &portName) } } -#ifdef Q_OS_MAC - // This is the workaround to specify a temporary directory - // on OSX when running the App Sandbox feature. - if (lockFilePath.isEmpty()) - lockFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation); -#endif - if (lockFilePath.isEmpty()) { qWarning("The following directories are not readable or writable for detaling with lock files\n"); foreach (const QString &lockDirectoryPath, lockDirectoryPaths) @@ -117,19 +114,21 @@ QString serialPortLockFilePath(const QString &portName) class ReadNotifier : public QSocketNotifier { - Q_OBJECT public: ReadNotifier(QSerialPortPrivate *d, QObject *parent) : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent) , dptr(d) - {} + { + } protected: - bool event(QEvent *e) Q_DECL_OVERRIDE { - bool ret = QSocketNotifier::event(e); - if (ret) + bool event(QEvent *e) Q_DECL_OVERRIDE + { + if (e->type() == QEvent::SockAct) { dptr->readNotification(); - return ret; + return true; + } + return QSocketNotifier::event(e); } private: @@ -138,43 +137,41 @@ private: class WriteNotifier : public QSocketNotifier { - Q_OBJECT public: WriteNotifier(QSerialPortPrivate *d, QObject *parent) : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent) , dptr(d) - {} + { + } protected: - bool event(QEvent *e) Q_DECL_OVERRIDE { - bool ret = QSocketNotifier::event(e); - if (ret) + bool event(QEvent *e) Q_DECL_OVERRIDE + { + if (e->type() == QEvent::SockAct) { dptr->completeAsyncWrite(); - return ret; + return true; + } + return QSocketNotifier::event(e); } private: QSerialPortPrivate *dptr; }; -#include "qserialport_unix.moc" - bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { - Q_Q(QSerialPort); - QString lockFilePath = serialPortLockFilePath(QSerialPortInfoPrivate::portNameFromSystemLocation(systemLocation)); bool isLockFileEmpty = lockFilePath.isEmpty(); if (isLockFileEmpty) { qWarning("Failed to create a lock file for opening the device"); - q->setError(QSerialPort::PermissionError); + setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while creating lock file"))); return false; } QScopedPointer<QLockFile> newLockFileScopedPointer(new QLockFile(lockFilePath)); if (!newLockFileScopedPointer->tryLock()) { - q->setError(QSerialPort::PermissionError); + setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while locking the device"))); return false; } @@ -195,7 +192,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) descriptor = qt_safe_open(systemLocation.toLocal8Bit().constData(), flags); if (descriptor == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -211,32 +208,28 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) void QSerialPortPrivate::close() { - Q_Q(QSerialPort); - if (settingsRestoredOnClose) { if (::tcsetattr(descriptor, TCSANOW, &restoredTermios) == -1) - q->setError(decodeSystemError()); + setError(getSystemError()); } #ifdef TIOCNXCL if (::ioctl(descriptor, TIOCNXCL) == -1) - q->setError(decodeSystemError()); + setError(getSystemError()); #endif if (readNotifier) { - readNotifier->setEnabled(false); - readNotifier->deleteLater(); + delete readNotifier; readNotifier = Q_NULLPTR; } if (writeNotifier) { - writeNotifier->setEnabled(false); - writeNotifier->deleteLater(); + delete writeNotifier; writeNotifier = Q_NULLPTR; } if (qt_safe_close(descriptor) == -1) - q->setError(decodeSystemError()); + setError(getSystemError()); lockFileScopedPointer.reset(Q_NULLPTR); @@ -247,12 +240,10 @@ void QSerialPortPrivate::close() QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() { - Q_Q(QSerialPort); - int arg = 0; if (::ioctl(descriptor, TIOCMGET, &arg) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return QSerialPort::NoSignal; } @@ -306,11 +297,9 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() bool QSerialPortPrivate::setDataTerminalReady(bool set) { - Q_Q(QSerialPort); - int status = TIOCM_DTR; if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -319,11 +308,9 @@ bool QSerialPortPrivate::setDataTerminalReady(bool set) bool QSerialPortPrivate::setRequestToSend(bool set) { - Q_Q(QSerialPort); - int status = TIOCM_RTS; if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -337,11 +324,9 @@ bool QSerialPortPrivate::flush() bool QSerialPortPrivate::clear(QSerialPort::Directions directions) { - Q_Q(QSerialPort); - if (::tcflush(descriptor, (directions == QSerialPort::AllDirections) ? TCIOFLUSH : (directions & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -350,10 +335,8 @@ bool QSerialPortPrivate::clear(QSerialPort::Directions directions) bool QSerialPortPrivate::sendBreak(int duration) { - Q_Q(QSerialPort); - if (::tcsendbreak(descriptor, duration) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -362,21 +345,14 @@ bool QSerialPortPrivate::sendBreak(int duration) bool QSerialPortPrivate::setBreakEnabled(bool set) { - Q_Q(QSerialPort); - if (::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) -{ - return buffer.read(data, maxSize); -} - bool QSerialPortPrivate::waitForReadyRead(int msecs) { QElapsedTimer stopWatch; @@ -433,22 +409,22 @@ bool QSerialPortPrivate::setBaudRate() && setBaudRate(outputBaudRate, QSerialPort::Output)); } -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setBaudRate_helper(qint32 baudRate, QSerialPort::Directions directions) { if ((directions & QSerialPort::Input) && ::cfsetispeed(¤tTermios, baudRate) < 0) - return decodeSystemError(); + return getSystemError(); if ((directions & QSerialPort::Output) && ::cfsetospeed(¤tTermios, baudRate) < 0) - return decodeSystemError(); + return getSystemError(); - return QSerialPort::NoError; + return QSerialPortErrorInfo(QSerialPort::NoError); } #if defined(Q_OS_LINUX) -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions) { struct serial_struct currentSerialInfo; @@ -460,7 +436,7 @@ QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions currentSerialInfo.flags &= ~ASYNC_SPD_CUST; currentSerialInfo.custom_divisor = 0; if (::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) == -1) - return decodeSystemError(); + return getSystemError(); } return setBaudRate_helper(baudRate, directions); @@ -468,7 +444,7 @@ QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions #else -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions) { return setBaudRate_helper(baudRate, directions); @@ -478,7 +454,7 @@ QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions #if defined(Q_OS_LINUX) -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(directions); @@ -488,14 +464,14 @@ QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions d ::memset(¤tSerialInfo, 0, sizeof(currentSerialInfo)); if (::ioctl(descriptor, TIOCGSERIAL, ¤tSerialInfo) == -1) - return decodeSystemError(); + return getSystemError(); currentSerialInfo.flags &= ~ASYNC_SPD_MASK; currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baudRate; if (currentSerialInfo.custom_divisor == 0) - return QSerialPort::UnsupportedOperationError; + return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("No suitable custom baud rate divisor")); if (currentSerialInfo.custom_divisor * baudRate != currentSerialInfo.baud_base) { qWarning("Baud rate of serial port %s is set to %d instead of %d: divisor %f unsupported", @@ -505,31 +481,31 @@ QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions d } if (::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) == -1) - return decodeSystemError(); + return getSystemError(); return setBaudRate_helper(B38400, directions); } #elif defined(Q_OS_MAC) -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(directions); #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) == -1) - return decodeSystemError(); + return getSystemError(); - return QSerialPort::NoError; + return QSerialPortErrorInfo(QSerialPort::NoError); #endif - return QSerialPort::UnsupportedOperationError; + return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate is not supported")); } #elif defined(Q_OS_QNX) -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { // On QNX, the values of the 'Bxxxx' constants are set to 'xxxx' (i.e. @@ -541,36 +517,34 @@ QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions d #else -QSerialPort::SerialPortError +QSerialPortErrorInfo QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(baudRate); Q_UNUSED(directions); - return QSerialPort::UnsupportedOperationError; + return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError); } #endif bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions) { - Q_Q(QSerialPort); - if (baudRate <= 0) { - q->setError(QSerialPort::UnsupportedOperationError); + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Invalid baud rate value"))); return false; } const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate); - const QSerialPort::SerialPortError error = (unixBaudRate > 0) + const QSerialPortErrorInfo error = (unixBaudRate > 0) ? setStandardBaudRate(unixBaudRate, directions) : setCustomBaudRate(baudRate, directions); - if (error == QSerialPort::NoError) + if (error.errorCode == QSerialPort::NoError) return updateTermios(); - q->setError(error); + setError(error); return false; } @@ -727,12 +701,12 @@ bool QSerialPortPrivate::readNotification() const qint64 readBytes = readFromPort(ptr, bytesToRead); if (readBytes <= 0) { - QSerialPort::SerialPortError error = decodeSystemError(); - if (error != QSerialPort::ResourceError) - error = QSerialPort::ReadError; + QSerialPortErrorInfo error = getSystemError(); + if (error.errorCode != QSerialPort::ResourceError) + error.errorCode = QSerialPort::ReadError; else setReadNotificationEnabled(false); - q->setError(error); + setError(error); buffer.chop(bytesToRead); return false; } @@ -759,18 +733,16 @@ bool QSerialPortPrivate::readNotification() bool QSerialPortPrivate::startAsyncWrite() { - Q_Q(QSerialPort); - if (writeBuffer.isEmpty() || writeSequenceStarted) return true; // Attempt to write it all in one chunk. qint64 written = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize()); if (written < 0) { - QSerialPort::SerialPortError error = decodeSystemError(); - if (error != QSerialPort::ResourceError) - error = QSerialPort::WriteError; - q->setError(error); + QSerialPortErrorInfo error = getSystemError(); + if (error.errorCode != QSerialPort::ResourceError) + error.errorCode = QSerialPort::WriteError; + setError(error); return false; } @@ -808,15 +780,13 @@ bool QSerialPortPrivate::completeAsyncWrite() inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode) { - Q_Q(QSerialPort); - #ifdef TIOCEXCL if (::ioctl(descriptor, TIOCEXCL) == -1) - q->setError(decodeSystemError()); + setError(getSystemError()); #endif if (::tcgetattr(descriptor, &restoredTermios) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -846,11 +816,6 @@ inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode) return true; } -qint64 QSerialPortPrivate::bytesToWrite() const -{ - return writeBuffer.size(); -} - qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) { ::memcpy(writeBuffer.reserve(maxSize), data, maxSize); @@ -861,71 +826,72 @@ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) bool QSerialPortPrivate::updateTermios() { - Q_Q(QSerialPort); - if (::tcsetattr(descriptor, TCSANOW, ¤tTermios) == -1) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError(int systemErrorCode) const +QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const { - Q_UNUSED(systemErrorCode); + if (systemErrorCode == -1) + systemErrorCode = errno; + + QSerialPortErrorInfo error; + error.errorString = qt_error_string(systemErrorCode); - QSerialPort::SerialPortError error; - switch (errno) { + switch (systemErrorCode) { case ENODEV: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; #ifdef ENOENT case ENOENT: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; #endif case EACCES: - error = QSerialPort::PermissionError; + error.errorCode = QSerialPort::PermissionError; break; case EBUSY: - error = QSerialPort::PermissionError; + error.errorCode = QSerialPort::PermissionError; break; case EAGAIN: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case EIO: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case EBADF: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; #ifdef Q_OS_MAC case ENXIO: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; #endif #ifdef EINVAL case EINVAL: - error = QSerialPort::UnsupportedOperationError; + error.errorCode = QSerialPort::UnsupportedOperationError; break; #endif #ifdef ENOIOCTLCMD case ENOIOCTLCMD: - error = QSerialPort::UnsupportedOperationError; + error.errorCode = QSerialPort::UnsupportedOperationError; break; #endif #ifdef ENOTTY case ENOTTY: - error = QSerialPort::UnsupportedOperationError; + error.errorCode = QSerialPort::UnsupportedOperationError; break; #endif #ifdef EPERM case EPERM: - error = QSerialPort::PermissionError; + error.errorCode = QSerialPort::PermissionError; break; #endif default: - error = QSerialPort::UnknownError; + error.errorCode = QSerialPort::UnknownError; break; } return error; @@ -969,8 +935,6 @@ bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectFor bool checkRead, bool checkWrite, int msecs) { - Q_Q(QSerialPort); - Q_ASSERT(selectForRead); Q_ASSERT(selectForWrite); @@ -990,11 +954,11 @@ bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectFor const int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv); if (ret < 0) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } if (ret == 0) { - q->setError(QSerialPort::TimeoutError); + setError(QSerialPortErrorInfo(QSerialPort::TimeoutError, QSerialPort::tr("Operation timed out"))); return false; } @@ -1081,8 +1045,6 @@ qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize) qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize) { - Q_Q(QSerialPort); - qint64 ret = 0; quint8 const charMask = (0xFF >> (8 - dataBits)); @@ -1128,13 +1090,15 @@ qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize) switch (policy) { case QSerialPort::SkipPolicy: continue; //ignore received character - case QSerialPort::StopReceivingPolicy: + case QSerialPort::StopReceivingPolicy: { if (parity != QSerialPort::NoParity) - q->setError(QSerialPort::ParityError); + setError(QSerialPortErrorInfo(QSerialPort::ParityError, QSerialPort::tr("Parity error detected while reading"))); + else if (*data == '\0') + setError(QSerialPortErrorInfo(QSerialPort::BreakConditionError, QSerialPort::tr("Break condition detected while reading"))); else - q->setError(*data == '\0' ? - QSerialPort::BreakConditionError : QSerialPort::FramingError); + setError(QSerialPortErrorInfo(QSerialPort::FramingError, QSerialPort::tr("Framing error detected while reading"))); return ++ret; //abort receiving + } break; case QSerialPort::UnknownPolicy: // Unknown error policy is used! Falling back to PassZeroPolicy diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index e6e6924..a9687a2 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -77,8 +77,6 @@ QT_BEGIN_NAMESPACE bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { - Q_Q(QSerialPort); - DWORD desiredAccess = 0; originalEventMask = EV_ERR; @@ -93,7 +91,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) desiredAccess, 0, Q_NULLPTR, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, Q_NULLPTR); if (handle == INVALID_HANDLE_VALUE) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -106,13 +104,18 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) void QSerialPortPrivate::close() { - Q_Q(QSerialPort); - if (!::CancelIo(handle)) - q->setError(decodeSystemError()); + setError(getSystemError()); - if (notifier) - notifier->deleteLater(); + if (notifier) { + delete notifier; + notifier = Q_NULLPTR; + } + + if (startAsyncWriteTimer) { + delete startAsyncWriteTimer; + startAsyncWriteTimer = Q_NULLPTR; + } readStarted = false; writeStarted = false; @@ -123,25 +126,23 @@ void QSerialPortPrivate::close() if (settingsRestoredOnClose) { if (!::SetCommState(handle, &restoredDcb)) - q->setError(decodeSystemError()); + setError(getSystemError()); else if (!::SetCommTimeouts(handle, &restoredCommTimeouts)) - q->setError(decodeSystemError()); + setError(getSystemError()); } if (!::CloseHandle(handle)) - q->setError(decodeSystemError()); + setError(getSystemError()); handle = INVALID_HANDLE_VALUE; } QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() { - Q_Q(QSerialPort); - DWORD modemStat = 0; if (!::GetCommModemStatus(handle, &modemStat)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return QSerialPort::NoSignal; } @@ -160,7 +161,7 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() if (!::DeviceIoControl(handle, IOCTL_SERIAL_GET_DTRRTS, Q_NULLPTR, 0, &modemStat, sizeof(modemStat), &bytesReturned, Q_NULLPTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return ret; } @@ -174,10 +175,8 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() bool QSerialPortPrivate::setDataTerminalReady(bool set) { - Q_Q(QSerialPort); - if (!::EscapeCommFunction(handle, set ? SETDTR : CLRDTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -187,10 +186,8 @@ bool QSerialPortPrivate::setDataTerminalReady(bool set) bool QSerialPortPrivate::setRequestToSend(bool set) { - Q_Q(QSerialPort); - if (!::EscapeCommFunction(handle, set ? SETRTS : CLRRTS)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -204,8 +201,6 @@ bool QSerialPortPrivate::flush() bool QSerialPortPrivate::clear(QSerialPort::Directions directions) { - Q_Q(QSerialPort); - DWORD flags = 0; if (directions & QSerialPort::Input) flags |= PURGE_RXABORT | PURGE_RXCLEAR; @@ -214,7 +209,7 @@ bool QSerialPortPrivate::clear(QSerialPort::Directions directions) actualBytesToWrite = 0; } if (!::PurgeComm(handle, flags)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -242,32 +237,14 @@ bool QSerialPortPrivate::sendBreak(int duration) bool QSerialPortPrivate::setBreakEnabled(bool set) { - Q_Q(QSerialPort); - if (set ? !::SetCommBreak(handle) : !::ClearCommBreak(handle)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) -{ - Q_UNUSED(data); - Q_UNUSED(maxSize); - - // We need try to start async reading to read a remainder from a driver's queue - // in case we have a limited read buffer size. Because the read notification can - // be stalled since Windows do not re-triggered an EV_RXCHAR event if a driver's - // buffer has a remainder of data ready to read until a new data will be received. - if (readBufferMaxSize || flowControl == QSerialPort::HardwareControl) - startAsyncRead(); - - // return 0 indicating there may be more data in the future - return qint64(0); -} - bool QSerialPortPrivate::waitForReadyRead(int msecs) { if (!writeStarted && !_q_startAsyncWrite()) @@ -331,10 +308,8 @@ bool QSerialPortPrivate::setBaudRate() bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions) { - Q_Q(QSerialPort); - if (directions != QSerialPort::AllDirections) { - q->setError(QSerialPort::UnsupportedOperationError); + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate direction is unsupported"))); return false; } currentDcb.BaudRate = baudRate; @@ -442,18 +417,20 @@ bool QSerialPortPrivate::completeAsyncRead(qint64 bytesTransferred) if (bytesTransferred > 0) { char *ptr = buffer.reserve(bytesTransferred); ::memcpy(ptr, readChunkBuffer.constData(), bytesTransferred); - if (!emulateErrorPolicy()) - emitReadyRead(); } readStarted = false; + bool result = true; if ((bytesTransferred == ReadChunkSize) && (policy == QSerialPort::IgnorePolicy)) - return startAsyncRead(); + result = startAsyncRead(); else if (readBufferMaxSize == 0 || readBufferMaxSize > buffer.size()) - return startAsyncCommunication(); - else - return true; + result = startAsyncCommunication(); + + if ((bytesTransferred > 0) && !emulateErrorPolicy()) + emitReadyRead(); + + return result; } bool QSerialPortPrivate::completeAsyncWrite(qint64 bytesTransferred) @@ -476,15 +453,13 @@ bool QSerialPortPrivate::completeAsyncWrite(qint64 bytesTransferred) bool QSerialPortPrivate::startAsyncCommunication() { - Q_Q(QSerialPort); - ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped)); if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) { - QSerialPort::SerialPortError error = decodeSystemError(); - if (error != QSerialPort::NoError) { - if (error == QSerialPort::PermissionError) - error = QSerialPort::ResourceError; - q->setError(error); + QSerialPortErrorInfo error = getSystemError(); + if (error.errorCode != QSerialPort::NoError) { + if (error.errorCode == QSerialPort::PermissionError) + error.errorCode = QSerialPort::ResourceError; + setError(error); return false; } } @@ -493,8 +468,6 @@ bool QSerialPortPrivate::startAsyncCommunication() bool QSerialPortPrivate::startAsyncRead() { - Q_Q(QSerialPort); - if (readStarted) return true; @@ -515,13 +488,13 @@ bool QSerialPortPrivate::startAsyncRead() return true; } - QSerialPort::SerialPortError error = decodeSystemError(); - if (error != QSerialPort::NoError) { - if (error == QSerialPort::PermissionError) - error = QSerialPort::ResourceError; - if (error != QSerialPort::ResourceError) - error = QSerialPort::ReadError; - q->setError(error); + QSerialPortErrorInfo error = getSystemError(); + if (error.errorCode != QSerialPort::NoError) { + if (error.errorCode == QSerialPort::PermissionError) + error.errorCode = QSerialPort::ResourceError; + if (error.errorCode != QSerialPort::ResourceError) + error.errorCode = QSerialPort::ReadError; + setError(error); return false; } @@ -531,8 +504,6 @@ bool QSerialPortPrivate::startAsyncRead() bool QSerialPortPrivate::_q_startAsyncWrite() { - Q_Q(QSerialPort); - if (writeBuffer.isEmpty() || writeStarted) return true; @@ -541,11 +512,11 @@ bool QSerialPortPrivate::_q_startAsyncWrite() if (!::WriteFile(handle, writeBuffer.readPointer(), writeBytes, Q_NULLPTR, &writeCompletionOverlapped)) { - QSerialPort::SerialPortError error = decodeSystemError(); - if (error != QSerialPort::NoError) { - if (error != QSerialPort::ResourceError) - error = QSerialPort::WriteError; - q->setError(error); + QSerialPortErrorInfo error = getSystemError(); + if (error.errorCode != QSerialPort::NoError) { + if (error.errorCode != QSerialPort::ResourceError) + error.errorCode = QSerialPort::WriteError; + setError(error); return false; } } @@ -557,11 +528,9 @@ bool QSerialPortPrivate::_q_startAsyncWrite() void QSerialPortPrivate::_q_notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped) { - Q_Q(QSerialPort); - - const QSerialPort::SerialPortError error = decodeSystemError(errorCode); - if (error != QSerialPort::NoError) { - q->setError(error); + const QSerialPortErrorInfo error = getSystemError(errorCode); + if (error.errorCode != QSerialPort::NoError) { + setError(error); return; } @@ -610,11 +579,6 @@ void QSerialPortPrivate::emitReadyRead() emit q->readyRead(); } -qint64 QSerialPortPrivate::bytesToWrite() const -{ - return actualBytesToWrite; -} - qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) { Q_Q(QSerialPort); @@ -635,33 +599,29 @@ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) void QSerialPortPrivate::handleLineStatusErrors() { - Q_Q(QSerialPort); - DWORD errors = 0; if (!::ClearCommError(handle, &errors, Q_NULLPTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return; } if (errors & CE_FRAME) { - q->setError(QSerialPort::FramingError); + setError(QSerialPortErrorInfo(QSerialPort::FramingError, QSerialPort::tr("Framing error detected while reading"))); } else if (errors & CE_RXPARITY) { - q->setError(QSerialPort::ParityError); + setError(QSerialPortErrorInfo(QSerialPort::FramingError, QSerialPort::tr("ParityError error detected while reading"))); parityErrorOccurred = true; } else if (errors & CE_BREAK) { - q->setError(QSerialPort::BreakConditionError); + setError(QSerialPortErrorInfo(QSerialPort::BreakConditionError, QSerialPort::tr("Break condition detected while reading"))); } else { - q->setError(QSerialPort::UnknownError); + setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Unknown streaming error"))); } } OVERLAPPED *QSerialPortPrivate::waitForNotified(int msecs) { - Q_Q(QSerialPort); - OVERLAPPED *overlapped = notifier->waitForAnyNotified(msecs); if (!overlapped) { - q->setError(decodeSystemError(WAIT_TIMEOUT)); + setError(getSystemError(WAIT_TIMEOUT)); return 0; } return overlapped; @@ -675,7 +635,7 @@ inline bool QSerialPortPrivate::initialize() restoredDcb.DCBlength = sizeof(restoredDcb); if (!::GetCommState(handle, &restoredDcb)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -690,11 +650,13 @@ inline bool QSerialPortPrivate::initialize() if (currentDcb.fDtrControl == DTR_CONTROL_HANDSHAKE) currentDcb.fDtrControl = DTR_CONTROL_DISABLE; + currentDcb.BaudRate = inputBaudRate; + if (!updateDcb()) return false; if (!::GetCommTimeouts(handle, &restoredCommTimeouts)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -705,7 +667,7 @@ inline bool QSerialPortPrivate::initialize() return false; if (!::SetCommMask(handle, originalEventMask)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -723,10 +685,8 @@ inline bool QSerialPortPrivate::initialize() bool QSerialPortPrivate::updateDcb() { - Q_Q(QSerialPort); - if (!::SetCommState(handle, ¤tDcb)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; @@ -734,60 +694,60 @@ bool QSerialPortPrivate::updateDcb() bool QSerialPortPrivate::updateCommTimeouts() { - Q_Q(QSerialPort); - if (!::SetCommTimeouts(handle, ¤tCommTimeouts)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError(int systemErrorCode) const +QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const { if (systemErrorCode == -1) systemErrorCode = ::GetLastError(); - QSerialPort::SerialPortError error; + QSerialPortErrorInfo error; + error.errorString = qt_error_string(systemErrorCode); + switch (systemErrorCode) { case ERROR_SUCCESS: - error = QSerialPort::NoError; + error.errorCode = QSerialPort::NoError; break; case ERROR_IO_PENDING: - error = QSerialPort::NoError; + error.errorCode = QSerialPort::NoError; break; case ERROR_MORE_DATA: - error = QSerialPort::NoError; + error.errorCode = QSerialPort::NoError; break; case ERROR_FILE_NOT_FOUND: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; case ERROR_INVALID_NAME: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; case ERROR_ACCESS_DENIED: - error = QSerialPort::PermissionError; + error.errorCode = QSerialPort::PermissionError; break; case ERROR_INVALID_HANDLE: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case ERROR_INVALID_PARAMETER: - error = QSerialPort::UnsupportedOperationError; + error.errorCode = QSerialPort::UnsupportedOperationError; break; case ERROR_BAD_COMMAND: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case ERROR_DEVICE_REMOVED: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case ERROR_OPERATION_ABORTED: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case WAIT_TIMEOUT: - error = QSerialPort::TimeoutError; + error.errorCode = QSerialPort::TimeoutError; break; default: - error = QSerialPort::UnknownError; + error.errorCode = QSerialPort::UnknownError; break; } return error; diff --git a/src/serialport/qserialport_wince.cpp b/src/serialport/qserialport_wince.cpp index b8affb6..88872ad 100644 --- a/src/serialport/qserialport_wince.cpp +++ b/src/serialport/qserialport_wince.cpp @@ -83,21 +83,19 @@ signals: public: CommEventNotifier(DWORD mask, QSerialPortPrivate *d, QObject *parent) - : QThread(parent), dptr(d), running(true) { + : QThread(parent), dptr(d) { connect(this, SIGNAL(eventMask(quint32)), this, SLOT(processNotification(quint32))); ::SetCommMask(dptr->handle, mask); } virtual ~CommEventNotifier() { - running = false; ::SetCommMask(dptr->handle, 0); - wait(); } protected: void run() Q_DECL_OVERRIDE { DWORD mask = 0; - while (running) { + while (true) { if (::WaitCommEvent(dptr->handle, &mask, FALSE)) { // Wait until complete the operation changes the port settings, // see updateDcb(). @@ -131,7 +129,6 @@ private slots: private: QSerialPortPrivate *dptr; - mutable bool running; }; class WaitCommEventBreaker : public QThread @@ -181,8 +178,6 @@ private: bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { - Q_Q(QSerialPort); - DWORD desiredAccess = 0; DWORD eventMask = EV_ERR; @@ -199,7 +194,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) desiredAccess, 0, Q_NULLPTR, OPEN_EXISTING, 0, Q_NULLPTR); if (handle == INVALID_HANDLE_VALUE) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -213,7 +208,9 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) void QSerialPortPrivate::close() { if (eventNotifier) { - eventNotifier->deleteLater(); + eventNotifier->terminate(); + eventNotifier->wait(); + delete eventNotifier; eventNotifier = Q_NULLPTR; } @@ -228,12 +225,10 @@ void QSerialPortPrivate::close() QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() { - Q_Q(QSerialPort); - DWORD modemStat = 0; if (!::GetCommModemStatus(handle, &modemStat)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return QSerialPort::NoSignal; } @@ -252,7 +247,7 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() if (!::DeviceIoControl(handle, IOCTL_SERIAL_GET_DTRRTS, Q_NULLPTR, 0, &modemStat, sizeof(modemStat), &bytesReturned, Q_NULLPTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return ret; } @@ -266,10 +261,8 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() bool QSerialPortPrivate::setDataTerminalReady(bool set) { - Q_Q(QSerialPort); - if (!::EscapeCommFunction(handle, set ? SETDTR : CLRDTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -279,10 +272,8 @@ bool QSerialPortPrivate::setDataTerminalReady(bool set) bool QSerialPortPrivate::setRequestToSend(bool set) { - Q_Q(QSerialPort); - if (!::EscapeCommFunction(handle, set ? SETRTS : CLRRTS)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -319,21 +310,14 @@ bool QSerialPortPrivate::sendBreak(int duration) bool QSerialPortPrivate::setBreakEnabled(bool set) { - Q_Q(QSerialPort); - if (set ? !::SetCommBreak(handle) : !::ClearCommBreak(handle)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) -{ - return buffer.read(data, maxSize); -} - bool QSerialPortPrivate::waitForReadyRead(int msec) { if (!buffer.isEmpty()) @@ -395,10 +379,8 @@ bool QSerialPortPrivate::setBaudRate() bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions) { - Q_Q(QSerialPort); - if (directions != QSerialPort::AllDirections) { - q->setError(QSerialPort::UnsupportedOperationError); + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate direction is unsupported"))); return false; } currentDcb.BaudRate = baudRate; @@ -509,11 +491,11 @@ bool QSerialPortPrivate::notifyRead() if (!sucessResult) { buffer.chop(bytesToRead); - q->setError(QSerialPort::ReadError); + setError(QSerialPortErrorInfo(QSerialPort::ReadError, QSerialPort::tr("Error reading from device"))); return false; } - buffer.chop(readBytes); + buffer.chop(bytesToRead - qMax(readBytes, DWORD(0))); // Process emulate policy. if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { @@ -552,7 +534,7 @@ bool QSerialPortPrivate::notifyWrite() DWORD bytesWritten = 0; if (!::WriteFile(handle, ptr, nextSize, &bytesWritten, Q_NULLPTR)) { - q->setError(QSerialPort::WriteError); + setError(QSerialPortErrorInfo(QSerialPort::WriteError, QSerialPort::tr("Error writing to device"))); return false; } @@ -564,11 +546,6 @@ bool QSerialPortPrivate::notifyWrite() return true; } -qint64 QSerialPortPrivate::bytesToWrite() const -{ - return writeBuffer.size(); -} - qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) { ::memcpy(writeBuffer.reserve(maxSize), data, maxSize); @@ -577,30 +554,28 @@ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize) return maxSize; } -void QSerialPortPrivate::processIoErrors(bool error) +void QSerialPortPrivate::processIoErrors(bool hasError) { - Q_Q(QSerialPort); - - if (error) { - q->setError(QSerialPort::ResourceError); + if (hasError) { + setError(QSerialPortErrorInfo(QSerialPort::ResourceError, QSerialPort::tr("Device disappeared from the system"))); return; } DWORD errors = 0; if (!::ClearCommError(handle, &errors, Q_NULLPTR)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return; } if (errors & CE_FRAME) { - q->setError(QSerialPort::FramingError); + setError(QSerialPortErrorInfo(QSerialPort::FramingError, QSerialPort::tr("Framing error detected while reading"))); } else if (errors & CE_RXPARITY) { - q->setError(QSerialPort::ParityError); + setError(QSerialPortErrorInfo(QSerialPort::FramingError, QSerialPort::tr("ParityError error detected while reading"))); parityErrorOccurred = true; } else if (errors & CE_BREAK) { - q->setError(QSerialPort::BreakConditionError); + setError(QSerialPortErrorInfo(QSerialPort::BreakConditionError, QSerialPort::tr("Break condition detected while reading"))); } else { - q->setError(QSerialPort::UnknownError); + setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Unknown streaming error"))); } } @@ -612,7 +587,7 @@ inline bool QSerialPortPrivate::initialize(DWORD eventMask) restoredDcb.DCBlength = sizeof(restoredDcb); if (!::GetCommState(handle, &restoredDcb)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -631,7 +606,7 @@ inline bool QSerialPortPrivate::initialize(DWORD eventMask) return false; if (!::GetCommTimeouts(handle, &restoredCommTimeouts)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } @@ -649,8 +624,6 @@ inline bool QSerialPortPrivate::initialize(DWORD eventMask) bool QSerialPortPrivate::updateDcb() { - Q_Q(QSerialPort); - QMutexLocker locker(&settingsChangeMutex); DWORD eventMask = 0; @@ -663,7 +636,7 @@ bool QSerialPortPrivate::updateDcb() // Change parameters bool ret = ::SetCommState(handle, ¤tDcb); if (!ret) - q->setError(decodeSystemError()); + setError(getSystemError()); // Restore the event mask ::SetCommMask(handle, eventMask); @@ -672,50 +645,51 @@ bool QSerialPortPrivate::updateDcb() bool QSerialPortPrivate::updateCommTimeouts() { - Q_Q(QSerialPort); - if (!::SetCommTimeouts(handle, ¤tCommTimeouts)) { - q->setError(decodeSystemError()); + setError(getSystemError()); return false; } return true; } -QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError(int systemErrorCode) const +QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const { - Q_UNUSED(systemErrorCode); + if (systemErrorCode == -1) + systemErrorCode = ::GetLastError(); - QSerialPort::SerialPortError error; - switch (::GetLastError()) { + QSerialPortErrorInfo error; + error.errorString = qt_error_string(systemErrorCode); + + switch (systemErrorCode) { case ERROR_IO_PENDING: - error = QSerialPort::NoError; + error.errorCode = QSerialPort::NoError; break; case ERROR_MORE_DATA: - error = QSerialPort::NoError; + error.errorCode = QSerialPort::NoError; break; case ERROR_FILE_NOT_FOUND: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; case ERROR_INVALID_NAME: - error = QSerialPort::DeviceNotFoundError; + error.errorCode = QSerialPort::DeviceNotFoundError; break; case ERROR_ACCESS_DENIED: - error = QSerialPort::PermissionError; + error.errorCode = QSerialPort::PermissionError; break; case ERROR_INVALID_HANDLE: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case ERROR_INVALID_PARAMETER: - error = QSerialPort::UnsupportedOperationError; + error.errorCode = QSerialPort::UnsupportedOperationError; break; case ERROR_BAD_COMMAND: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; case ERROR_DEVICE_REMOVED: - error = QSerialPort::ResourceError; + error.errorCode = QSerialPort::ResourceError; break; default: - error = QSerialPort::UnknownError; + error.errorCode = QSerialPort::UnknownError; break; } return error; @@ -725,8 +699,6 @@ bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectFor bool checkRead, bool checkWrite, int msecs) { - Q_Q(QSerialPort); - DWORD eventMask = 0; // FIXME: Here the situation is not properly handled with zero timeout: // breaker can work out before you call a method WaitCommEvent() @@ -736,7 +708,7 @@ bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectFor breaker.stop(); if (breaker.isWorked()) { - q->setError(QSerialPort::TimeoutError); + setError(QSerialPortErrorInfo(QSerialPort::TimeoutError, QSerialPort::tr("Operation timed out"))); } else { if (checkRead) { Q_ASSERT(selectForRead); diff --git a/src/serialport/qserialportinfo.cpp b/src/serialport/qserialportinfo.cpp index be3eed1..3e7245e 100644 --- a/src/serialport/qserialportinfo.cpp +++ b/src/serialport/qserialportinfo.cpp @@ -266,6 +266,7 @@ bool QSerialPortInfo::hasProductIdentifier() const \sa isNull() */ +#if QT_DEPRECATED_SINCE(5, 2) /*! \fn bool QSerialPortInfo::isValid() const \obsolete @@ -275,6 +276,7 @@ bool QSerialPortInfo::hasProductIdentifier() const \sa isNull(), isBusy() */ +#endif // QT_DEPRECATED_SINCE(5, 2) /*! \fn QList<qint32> QSerialPortInfo::standardBaudRates() diff --git a/src/serialport/qserialportinfo_mac.cpp b/src/serialport/qserialportinfo_mac.cpp index 558dcbd..4e73025 100644 --- a/src/serialport/qserialportinfo_mac.cpp +++ b/src/serialport/qserialportinfo_mac.cpp @@ -64,7 +64,11 @@ static QCFType<CFTypeRef> searchProperty(io_registry_entry_t ioRegistryEntry, static QString searchStringProperty(io_registry_entry_t ioRegistryEntry, const QCFString &propertyKey) { - return QCFString::toQString(searchProperty(ioRegistryEntry, propertyKey).as<CFStringRef>()); + const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey)); + const CFStringRef ref = result.as<CFStringRef>(); + if (ref && (::CFGetTypeID(ref) == ::CFStringGetTypeID())) + return QCFString::toQString(ref); + return QString(); } static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry, @@ -72,9 +76,10 @@ static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry, bool &ok) { const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey)); + const CFNumberRef ref = result.as<CFNumberRef>(); quint16 value = 0; - ok = result.as<CFNumberRef>() - && (::CFNumberGetValue(result.as<CFNumberRef>(), kCFNumberShortType, &value) > 0); + ok = ref && (::CFGetTypeID(ref) == ::CFNumberGetTypeID()) + && (::CFNumberGetValue(ref, kCFNumberShortType, &value) > 0); return value; } @@ -231,11 +236,13 @@ bool QSerialPortInfo::isBusy() const return true; } +#if QT_DEPRECATED_SINCE(5, 2) bool QSerialPortInfo::isValid() const { QFile f(systemLocation()); return f.exists(); } +#endif // QT_DEPRECATED_SINCE(5, 2) QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source) { diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp index 0add5b6..0fc5046 100644 --- a/src/serialport/qserialportinfo_unix.cpp +++ b/src/serialport/qserialportinfo_unix.cpp @@ -84,6 +84,15 @@ static QStringList filteredDeviceFilePaths() QStringList deviceFilePaths; foreach (const QFileInfo &deviceFileInfo, deviceDir.entryInfoList()) { const QString deviceAbsoluteFilePath = deviceFileInfo.absoluteFilePath(); + +#ifdef Q_OS_FREEBSD + // it is a quick workaround to skip the non-serial devices + if (deviceFilePaths.endsWith(QLatin1String(".init")) + || deviceFilePaths.endsWith(QLatin1String(".lock"))) { + continue; + } +#endif + if (!deviceFilePaths.contains(deviceAbsoluteFilePath)) { deviceFilePaths.append(deviceAbsoluteFilePath); result.append(deviceAbsoluteFilePath); @@ -463,11 +472,13 @@ bool QSerialPortInfo::isBusy() const return true; } +#if QT_DEPRECATED_SINCE(5, 2) bool QSerialPortInfo::isValid() const { QFile f(systemLocation()); return f.exists(); } +#endif // QT_DEPRECATED_SINCE(5, 2) QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source) { diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index 546d5e1..38190b7 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -65,11 +65,10 @@ static inline const QList<GuidFlagsPair>& guidFlagsPairs() static QString toStringAndTrimNullCharacter(const QByteArray &buffer) { - QString result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(buffer.constData()), - buffer.size() / sizeof(wchar_t)); - while (!result.isEmpty() && (result.at(result.size() - 1).unicode() == 0)) - result.chop(1); - return result; + const QString result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(buffer.constData()), + buffer.size() / sizeof(wchar_t)); + const int index = result.indexOf(QChar(0)); + return index == -1 ? result : result.mid(0, index); } static QStringList portNamesFromHardwareDeviceMap() @@ -365,6 +364,7 @@ bool QSerialPortInfo::isBusy() const return false; } +#if QT_DEPRECATED_SINCE(5, 2) bool QSerialPortInfo::isValid() const { const HANDLE handle = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()), @@ -378,6 +378,7 @@ bool QSerialPortInfo::isValid() const } return true; } +#endif // QT_DEPRECATED_SINCE(5, 2) QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source) { diff --git a/src/serialport/qserialportinfo_wince.cpp b/src/serialport/qserialportinfo_wince.cpp index aa590ba..3688bc3 100644 --- a/src/serialport/qserialportinfo_wince.cpp +++ b/src/serialport/qserialportinfo_wince.cpp @@ -139,6 +139,7 @@ bool QSerialPortInfo::isBusy() const return false; } +#if QT_DEPRECATED_SINCE(5, 2) bool QSerialPortInfo::isValid() const { const HANDLE handle = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()), @@ -152,6 +153,7 @@ bool QSerialPortInfo::isValid() const } return true; } +#endif // QT_DEPRECATED_SINCE(5, 2) QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source) { diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp index 1a714b2..c5c9113 100644 --- a/tests/auto/qserialport/tst_qserialport.cpp +++ b/tests/auto/qserialport/tst_qserialport.cpp @@ -35,6 +35,8 @@ #include <QtSerialPort/QSerialPort> #include <QtSerialPort/QSerialPortInfo> +#include <QThread> + Q_DECLARE_METATYPE(QSerialPort::SerialPortError); Q_DECLARE_METATYPE(QIODevice::OpenMode); Q_DECLARE_METATYPE(QIODevice::OpenModeFlag); @@ -105,6 +107,7 @@ private slots: #ifdef Q_OS_WIN void readBufferOverflow(); void readAfterInputClear(); + void synchronousReadWriteAfterAsynchronousReadWrite(); #endif void controlBreak(); @@ -324,6 +327,10 @@ void tst_QSerialPort::flush() QSKIP("flush() does not work on Windows"); #endif + // the dummy device on other side also has to be open + QSerialPort dummySerialPort(m_receiverPortName); + QVERIFY(dummySerialPort.open(QIODevice::ReadOnly)); + QSerialPort serialPort(m_senderPortName); connect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(handleBytesWrittenAndExitLoopSlot(qint64))); QSignalSpy bytesWrittenSpy(&serialPort, SIGNAL(bytesWritten(qint64))); @@ -355,6 +362,10 @@ void tst_QSerialPort::doubleFlush() QSKIP("flush() does not work on Windows"); #endif + // the dummy device on other side also has to be open + QSerialPort dummySerialPort(m_receiverPortName); + QVERIFY(dummySerialPort.open(QIODevice::ReadOnly)); + QSerialPort serialPort(m_senderPortName); connect(&serialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(handleBytesWrittenAndExitLoopSlot2(qint64))); QSignalSpy bytesWrittenSpy(&serialPort, SIGNAL(bytesWritten(qint64))); @@ -739,6 +750,107 @@ void tst_QSerialPort::readAfterInputClear() // No more bytes available QVERIFY(receiverPort.bytesAvailable() == 0); } + +class MasterTransactor : public QObject +{ + Q_OBJECT +public: + explicit MasterTransactor(const QString &name) + : serialPort(name) + { + } + +public slots: + void open() + { + if (serialPort.open(QSerialPort::ReadWrite)) { + createAsynchronousConnection(); + serialPort.write("A", 1); + } + } + +private slots: + void synchronousTransaction() + { + serialPort.write("B", 1); + if (serialPort.waitForBytesWritten(100)) { + if (serialPort.waitForReadyRead(100)) + tst_QSerialPort::exitLoop(); + } + } + + void transaction() + { + deleteAsyncronousConnection(); + synchronousTransaction(); + } + +private: + void createAsynchronousConnection() + { + connect(&serialPort, &QSerialPort::readyRead, this, &MasterTransactor::transaction); + } + + void deleteAsyncronousConnection() + { + serialPort.disconnect(); + } + + QSerialPort serialPort; +}; + +class SlaveTransactor : public QObject +{ + Q_OBJECT +public: + explicit SlaveTransactor(const QString &name) + : serialPort(new QSerialPort(name, this)) + { + connect(serialPort, &QSerialPort::readyRead, this, &SlaveTransactor::transaction); + } + +public slots: + void open() + { + if (serialPort->open(QSerialPort::ReadWrite)) + emit ready(); + } + +signals: + void ready(); + +private slots: + void transaction() + { + serialPort->write("Z", 1); + } + +private: + QSerialPort *serialPort; +}; + +void tst_QSerialPort::synchronousReadWriteAfterAsynchronousReadWrite() +{ + MasterTransactor master(m_senderPortName); + SlaveTransactor *slave = new SlaveTransactor(m_receiverPortName); + + QThread thread; + slave->moveToThread(&thread); + thread.start(); + + QObject::connect(&thread, &QThread::finished, slave, &SlaveTransactor::deleteLater); + QObject::connect(slave, &SlaveTransactor::ready, &master, &MasterTransactor::open); + + QMetaObject::invokeMethod(slave, "open", Qt::QueuedConnection); + + tst_QSerialPort::enterLoopMsecs(500); + + thread.quit(); + thread.wait(); + + QVERIFY2(!timeout(), "Timed out when testing of transactions."); +} + #endif class BreakReader : public QObject diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro deleted file mode 100644 index 5be8160..0000000 --- a/tests/manual/manual.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += qserialportinfo \ - qserialport diff --git a/tests/manual/qserialport/qserialport.pro b/tests/manual/qserialport/qserialport.pro deleted file mode 100644 index 3858b6b..0000000 --- a/tests/manual/qserialport/qserialport.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = tst_qserialport - -QT = core testlib -QT += serialport - -SOURCES += tst_qserialport.cpp diff --git a/tests/manual/qserialport/tst_qserialport.cpp b/tests/manual/qserialport/tst_qserialport.cpp deleted file mode 100644 index f6f3252..0000000 --- a/tests/manual/qserialport/tst_qserialport.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtSerialPort module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtTest/QtTest> -#include <QtCore/QDebug> - -#include <QtSerialPort/qserialportinfo.h> -#include <QtSerialPort/qserialport.h> - -QT_USE_NAMESPACE - -class tst_QSerialPort : public QObject -{ - Q_OBJECT - -private slots: - void initTestCase(); - void open(); - void baudRate(); - void dataBits(); - void parity(); - void stopBits(); - void flowControl(); - -private: - QList<QSerialPortInfo> serialPortInfoList; -}; - -void tst_QSerialPort::initTestCase() -{ - serialPortInfoList = QSerialPortInfo::availablePorts(); - - if (serialPortInfoList.isEmpty()) { - QSKIP("Test doesn't work because the serial ports are not detected."); - } -} - -void tst_QSerialPort::open() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - if (serialPortInfo.isBusy()) - continue; - - QSerialPort object1; - - // Try open and check access to port by Info - object1.setPort(serialPortInfo); - QCOMPARE(object1.portName(), serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - QCOMPARE(object1.isOpen(), true); - object1.close(); - QCOMPARE(object1.isOpen(), false); - - // Try open and check access to port by Name - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.portName(), serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - QCOMPARE(object1.isOpen(), true); - object1.close(); - QCOMPARE(object1.isOpen(), false); - - // Try open and check access to port by Location - object1.setPortName(serialPortInfo.systemLocation()); - QCOMPARE(object1.portName(), serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - QCOMPARE(object1.isOpen(), true); - object1.close(); - QCOMPARE(object1.isOpen(), false); - } -} - -void tst_QSerialPort::baudRate() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - QSerialPort object1; - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - - QCOMPARE(object1.setBaudRate(QSerialPort::Baud1200), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud1200)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud2400), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud2400)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud4800), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud4800)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud9600), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud9600)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud19200), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud19200)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud38400), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud38400)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud57600), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud57600)); - QCOMPARE(object1.setBaudRate(QSerialPort::Baud115200), true); - QCOMPARE(object1.baudRate(), static_cast<qint32>(QSerialPort::Baud115200)); - - object1.close(); - } -} - -void tst_QSerialPort::dataBits() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - QSerialPort object1; - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - - QCOMPARE(object1.setDataBits(QSerialPort::Data8), true); - QCOMPARE(object1.dataBits(), QSerialPort::Data8); - - object1.close(); - } -} - -void tst_QSerialPort::parity() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - QSerialPort object1; - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - - QCOMPARE(object1.setParity(QSerialPort::NoParity), true); - QCOMPARE(object1.parity(), QSerialPort::NoParity); - QCOMPARE(object1.setParity(QSerialPort::EvenParity), true); - QCOMPARE(object1.parity(), QSerialPort::EvenParity); - QCOMPARE(object1.setParity(QSerialPort::OddParity), true); - QCOMPARE(object1.parity(), QSerialPort::OddParity); - QCOMPARE(object1.setParity(QSerialPort::MarkParity), true); - QCOMPARE(object1.parity(), QSerialPort::MarkParity); - QCOMPARE(object1.setParity(QSerialPort::SpaceParity), true); - QCOMPARE(object1.parity(), QSerialPort::SpaceParity); - - object1.close(); - } -} - -void tst_QSerialPort::stopBits() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - QSerialPort object1; - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - - QCOMPARE(object1.setStopBits(QSerialPort::OneStop), true); - QCOMPARE(object1.stopBits(), QSerialPort::OneStop); - // skip 1.5 stop bits - QCOMPARE(object1.setStopBits(QSerialPort::TwoStop), true); - QCOMPARE(object1.stopBits(), QSerialPort::TwoStop); - - object1.close(); - } -} - -void tst_QSerialPort::flowControl() -{ - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - - QSerialPort object1; - object1.setPortName(serialPortInfo.portName()); - QCOMPARE(object1.open(QIODevice::ReadWrite), true); - - QCOMPARE(object1.setFlowControl(QSerialPort::NoFlowControl), true); - QCOMPARE(object1.flowControl(), QSerialPort::NoFlowControl); - QCOMPARE(object1.setFlowControl(QSerialPort::HardwareControl), true); - QCOMPARE(object1.flowControl(), QSerialPort::HardwareControl); - QCOMPARE(object1.setFlowControl(QSerialPort::SoftwareControl), true); - QCOMPARE(object1.flowControl(), QSerialPort::SoftwareControl); - - object1.close(); - } -} - -QTEST_MAIN(tst_QSerialPort) -#include "tst_qserialport.moc" diff --git a/tests/manual/qserialportinfo/qserialportinfo.pro b/tests/manual/qserialportinfo/qserialportinfo.pro deleted file mode 100644 index 57f6ea6..0000000 --- a/tests/manual/qserialportinfo/qserialportinfo.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = tst_qserialportinfo - -QT = core testlib -QT += serialport - -SOURCES += tst_qserialportinfo.cpp diff --git a/tests/manual/qserialportinfo/tst_qserialportinfo.cpp b/tests/manual/qserialportinfo/tst_qserialportinfo.cpp deleted file mode 100644 index 3bcc0b3..0000000 --- a/tests/manual/qserialportinfo/tst_qserialportinfo.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com> -** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtSerialPort module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtTest/QtTest> -#include <QtCore/QDebug> - -#include <QtSerialPort/qserialportinfo.h> -#include <QtSerialPort/qserialport.h> - -QT_USE_NAMESPACE - -class tst_QSerialPortInfo : public QObject -{ - Q_OBJECT - -private slots: - void serialPortInfoList(); - void standardBaudRateList(); - void constructors(); - void assignment(); -}; - -void tst_QSerialPortInfo::serialPortInfoList() -{ - QList<QSerialPortInfo> list(QSerialPortInfo::availablePorts()); - QCOMPARE(list.isEmpty(), false); -} - -void tst_QSerialPortInfo::standardBaudRateList() -{ - QList<qint32> list(QSerialPortInfo::standardBaudRates()); - QCOMPARE(list.isEmpty(), false); -} - -void tst_QSerialPortInfo::constructors() -{ - QSerialPortInfo serialPortInfo; - QCOMPARE(serialPortInfo.portName().isEmpty(), true); - QCOMPARE(serialPortInfo.systemLocation().isEmpty(), true); - QCOMPARE(serialPortInfo.description().isEmpty(), true); - QCOMPARE(serialPortInfo.manufacturer().isEmpty(), true); - QCOMPARE(serialPortInfo.serialNumber().isEmpty(), true); - QCOMPARE(serialPortInfo.vendorIdentifier(), quint16(0)); - QCOMPARE(serialPortInfo.productIdentifier(), quint16(0)); - QCOMPARE(serialPortInfo.hasVendorIdentifier(), false); - QCOMPARE(serialPortInfo.hasProductIdentifier(), false); - QCOMPARE(serialPortInfo.isNull(), false); - QCOMPARE(serialPortInfo.isBusy(), false); - QCOMPARE(serialPortInfo.isValid(), false); -} - -void tst_QSerialPortInfo::assignment() -{ - QList<QSerialPortInfo> serialPortInfoList(QSerialPortInfo::availablePorts()); - - foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { - QSerialPortInfo otherSerialPortInfo = serialPortInfo; - QCOMPARE(otherSerialPortInfo.portName(), serialPortInfo.portName()); - QCOMPARE(otherSerialPortInfo.systemLocation(), serialPortInfo.systemLocation()); - QCOMPARE(otherSerialPortInfo.description(), serialPortInfo.description()); - QCOMPARE(otherSerialPortInfo.manufacturer(), serialPortInfo.manufacturer()); - QCOMPARE(otherSerialPortInfo.serialNumber(), serialPortInfo.serialNumber()); - QCOMPARE(otherSerialPortInfo.vendorIdentifier(), serialPortInfo.vendorIdentifier()); - QCOMPARE(otherSerialPortInfo.productIdentifier(), serialPortInfo.productIdentifier()); - } -} - -QTEST_MAIN(tst_QSerialPortInfo) -#include "tst_qserialportinfo.moc" diff --git a/tests/tests.pro b/tests/tests.pro index dcc8531..157ef34 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS += auto manual +SUBDIRS += auto |