diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-10-14 19:52:01 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-10-14 19:52:01 +0200 |
commit | d6584a7f1cc540eba1fed1fc7423459e9cfc8bb8 (patch) | |
tree | 07bd7c13cacaa42cebf15da8a85382ab08db5841 | |
parent | 4280d29fff431a87a2771cc37a555fc8cb54be8e (diff) | |
parent | 5f8f57dfb53c1954715257be926915d24734b391 (diff) | |
download | qtserialport-d6584a7f1cc540eba1fed1fc7423459e9cfc8bb8.tar.gz |
Merge remote-tracking branch 'origin/5.6' into dev
Change-Id: I2d36b5263242f91101e3720812ecf7e91c60df2d
-rw-r--r-- | dist/changes-5.5.1 | 41 | ||||
-rw-r--r-- | examples/serialport/doc/terminal.qdoc | 4 | ||||
-rw-r--r-- | src/serialport/qserialport.cpp | 16 | ||||
-rw-r--r-- | src/serialport/qserialport_p.h | 3 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 18 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 17 | ||||
-rw-r--r-- | src/serialport/qserialport_wince.cpp | 13 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 74 | ||||
-rw-r--r-- | tests/auto/qserialport/tst_qserialport.cpp | 45 |
9 files changed, 143 insertions, 88 deletions
diff --git a/dist/changes-5.5.1 b/dist/changes-5.5.1 new file mode 100644 index 0000000..8215a3f --- /dev/null +++ b/dist/changes-5.5.1 @@ -0,0 +1,41 @@ +Qt 5.5.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.5.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.5 series is binary compatible with the 5.4.x series. +Applications compiled for 5.4 will continue to run with 5.5. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + + - Improved the Terminal example: + * The example has a permanent status message now. + + - QSerialPortInfo: + * [QTBUG-46875] Fixed crash while enumerating available ports + on OS X 10.10 + * [QTBUG-47127] Available serial port information is not duplicated + anymore on Windows. + * [QTBUG-47210] Now do not return devices which are not serial ports + on FreeBSD. + * Now returns the full information about the serial port on FreeBSD. + + - QSerialPort: + * Fixed the serial ports closing and data reading on WinCE. + * [QTBUG-45338] Fixed opening of the serial ports when using the + App Sandbox on OS X. + * [QTBUG-46993] Fixed opening of the serial ports on Windows, which + are provided by the "Exar VCP" driver. diff --git a/examples/serialport/doc/terminal.qdoc b/examples/serialport/doc/terminal.qdoc index 16f12fe..d9b2d8d 100644 --- a/examples/serialport/doc/terminal.qdoc +++ b/examples/serialport/doc/terminal.qdoc @@ -91,7 +91,7 @@ \snippet terminal/mainwindow.cpp 1 The only QSerialPort signal invoked in this example is - \l{QIODevice::readyRead()}{readyRead()}, which shows that new data has been + \l{QIODevice::}{readyRead()}, which shows that new data has been received and hence available: \dots @@ -127,7 +127,7 @@ \l{terminal/console.cpp}{Console} widget to the serial port. When the serial port receives new data, the signal - \l{QTcpSocket::readyRead()}{readyRead()} is emitted, and that signal is + \l{QIODevice::}{readyRead()} is emitted, and that signal is connected to the \c MainWindow::readData() slot: \snippet terminal/mainwindow.cpp 7 diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 690eb65..6832883 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -123,14 +123,6 @@ QSerialPortPrivate::QSerialPortPrivate() { } -int QSerialPortPrivate::timeoutValue(int msecs, int elapsed) -{ - if (msecs == -1) - return msecs; - msecs -= elapsed; - return qMax(msecs, 0); -} - void QSerialPortPrivate::setError(const QSerialPortErrorInfo &errorInfo) { Q_Q(QSerialPort); @@ -1409,7 +1401,7 @@ qint64 QSerialPort::readData(char *data, qint64 maxSize) Q_UNUSED(data); Q_UNUSED(maxSize); -#ifdef Q_OS_WIN32 +#if defined(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 @@ -1417,6 +1409,12 @@ qint64 QSerialPort::readData(char *data, qint64 maxSize) Q_D(QSerialPort); if (d->readBufferMaxSize || d->flowControl == QSerialPort::HardwareControl) d->startAsyncRead(); +#elif defined(Q_OS_UNIX) + // We need try to re-trigger the read notification to read a remainder from a + // driver's queue in case we have a limited read buffer size. + Q_D(QSerialPort); + if (d->readBufferMaxSize && !d->isReadNotificationEnabled()) + d->setReadNotificationEnabled(true); #endif // return 0 indicating there may be more data in the future diff --git a/src/serialport/qserialport_p.h b/src/serialport/qserialport_p.h index d2527e3..4d37254 100644 --- a/src/serialport/qserialport_p.h +++ b/src/serialport/qserialport_p.h @@ -126,8 +126,6 @@ public: QSerialPortPrivate(); - static int timeoutValue(int msecs, int elapsed); - bool open(QIODevice::OpenMode mode); void close(); @@ -161,7 +159,6 @@ public: static QString portNameToSystemLocation(const QString &port); static QString portNameFromSystemLocation(const QString &location); - static qint32 baudRateFromSetting(qint32 setting); static qint32 settingFromBaudRate(qint32 baudRate); static QList<qint32> standardBaudRates(); diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 4659a18..4a558be 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -389,7 +389,7 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) bool readyToRead = false; bool readyToWrite = false; if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), - timeoutValue(msecs, stopWatch.elapsed()))) { + qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { return false; } @@ -398,7 +398,7 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) if (readyToWrite && !completeAsyncWrite()) return false; - } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0); return false; } @@ -414,7 +414,7 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) bool readyToRead = false; bool readyToWrite = false; if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), - timeoutValue(msecs, stopWatch.elapsed()))) { + qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { return false; } @@ -727,6 +727,7 @@ bool QSerialPortPrivate::readNotification() if (bytesToRead == 0) { // Buffer is full. User must read data from the buffer // before we can read more from the port. + setReadNotificationEnabled(false); return false; } } @@ -991,11 +992,11 @@ bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectFor if (checkWrite) FD_SET(descriptor, &fdwrite); - struct timeval tv; + struct timespec tv; tv.tv_sec = msecs / 1000; - tv.tv_usec = (msecs % 1000) * 1000; + tv.tv_nsec = (msecs % 1000) * 1000 * 1000; - const int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv); + const int ret = qt_safe_select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv); if (ret < 0) { setError(getSystemError()); return false; @@ -1230,11 +1231,6 @@ static const BaudRateMap& standardBaudRateMap() return baudRateMap; } -qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) -{ - return standardBaudRateMap().key(setting); -} - qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) { return standardBaudRateMap().value(baudRate); diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 39d7e33..8e7c278 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -260,7 +260,8 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) stopWatch.start(); do { - OVERLAPPED *overlapped = waitForNotified(timeoutValue(msecs, stopWatch.elapsed())); + OVERLAPPED *overlapped = waitForNotified( + qt_subtract_from_timeout(msecs, stopWatch.elapsed())); if (!overlapped) return false; @@ -276,7 +277,7 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) } } - } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0); return false; } @@ -293,7 +294,8 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) stopWatch.start(); forever { - OVERLAPPED *overlapped = waitForNotified(timeoutValue(msecs, stopWatch.elapsed())); + OVERLAPPED *overlapped = waitForNotified( + qt_subtract_from_timeout(msecs, stopWatch.elapsed())); if (!overlapped) return false; @@ -811,15 +813,6 @@ static const QList<qint32> standardBaudRatePairList() return standardBaudRatesTable; }; -qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) -{ - const QList<qint32> baudRatePairs = standardBaudRatePairList(); - const QList<qint32>::const_iterator baudRatePairListConstIterator - = std::find(baudRatePairs.constBegin(), baudRatePairs.constEnd(), setting); - - return (baudRatePairListConstIterator != baudRatePairs.constEnd()) ? *baudRatePairListConstIterator : 0; -} - qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) { const QList<qint32> baudRatePairList = standardBaudRatePairList(); diff --git a/src/serialport/qserialport_wince.cpp b/src/serialport/qserialport_wince.cpp index 18dd15d..b1975af 100644 --- a/src/serialport/qserialport_wince.cpp +++ b/src/serialport/qserialport_wince.cpp @@ -329,7 +329,7 @@ bool QSerialPortPrivate::waitForReadyRead(int msec) bool readyToWrite = false; if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), - timeoutValue(msec, stopWatch.elapsed()))) { + qt_subtract_from_timeout(msec, stopWatch.elapsed()))) { return false; } if (readyToRead) { @@ -355,7 +355,7 @@ bool QSerialPortPrivate::waitForBytesWritten(int msec) bool readyToWrite = false; if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), - timeoutValue(msec, stopWatch.elapsed()))) { + qt_subtract_from_timeout(msec, stopWatch.elapsed()))) { return false; } if (readyToRead) { @@ -743,15 +743,6 @@ static const QList<qint32> standardBaudRatePairList() return standardBaudRatesTable; }; -qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) -{ - const QList<qint32> baudRatePairs = standardBaudRatePairList(); - const QList<qint32>::const_iterator baudRatePairListConstIterator - = std::find(baudRatePairs.constBegin(), baudRatePairs.constEnd(), setting); - - return (baudRatePairListConstIterator != baudRatePairs.constEnd()) ? *baudRatePairListConstIterator : 0; -} - qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) { const QList<qint32> baudRatePairList = standardBaudRatePairList(); diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index 38190b7..06987f2 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -41,6 +41,8 @@ #include <QtCore/qpair.h> #include <QtCore/qstringlist.h> +#include <vector> + #include <initguid.h> #include <setupapi.h> #include <cfgmgr32.h> @@ -63,14 +65,6 @@ static inline const QList<GuidFlagsPair>& guidFlagsPairs() return guidFlagsPairList; } -static QString toStringAndTrimNullCharacter(const QByteArray &buffer) -{ - 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() { HKEY hKey = Q_NULLPTR; @@ -79,19 +73,22 @@ static QStringList portNamesFromHardwareDeviceMap() QStringList result; DWORD index = 0; - static const DWORD maximumValueNameInChars = 16383; - QByteArray outputValueName; - outputValueName.resize(maximumValueNameInChars * sizeof(wchar_t)); - QByteArray outputBuffer; - DWORD requiredDataBytes = 0; + + // This is a maximum length of value name, see: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872%28v=vs.85%29.aspx + enum { MaximumValueNameInChars = 16383 }; + + std::vector<wchar_t> outputValueName(MaximumValueNameInChars, 0); + std::vector<wchar_t> outputBuffer(MAX_PATH + 1, 0); + DWORD bytesRequired = MAX_PATH; forever { - DWORD requiredValueNameChars = maximumValueNameInChars; - const LONG ret = ::RegEnumValue(hKey, index, reinterpret_cast<wchar_t *>(outputValueName.data()), &requiredValueNameChars, - Q_NULLPTR, Q_NULLPTR, reinterpret_cast<unsigned char *>(outputBuffer.data()), &requiredDataBytes); + DWORD requiredValueNameChars = MaximumValueNameInChars; + const LONG ret = ::RegEnumValue(hKey, index, &outputValueName[0], &requiredValueNameChars, + Q_NULLPTR, Q_NULLPTR, reinterpret_cast<PBYTE>(&outputBuffer[0]), &bytesRequired); if (ret == ERROR_MORE_DATA) { - outputBuffer.resize(requiredDataBytes); + outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2, 0); } else if (ret == ERROR_SUCCESS) { - result.append(toStringAndTrimNullCharacter(outputBuffer)); + result.append(QString::fromWCharArray(&outputBuffer[0])); ++index; } else { break; @@ -106,12 +103,12 @@ static QString deviceRegistryProperty(HDEVINFO deviceInfoSet, DWORD property) { DWORD dataType = 0; - QByteArray devicePropertyByteArray; - DWORD requiredSize = 0; + std::vector<wchar_t> outputBuffer(MAX_PATH + 1, 0); + DWORD bytesRequired = MAX_PATH; forever { if (::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, - reinterpret_cast<unsigned char *>(devicePropertyByteArray.data()), - devicePropertyByteArray.size(), &requiredSize)) { + reinterpret_cast<PBYTE>(&outputBuffer[0]), + bytesRequired, &bytesRequired)) { break; } @@ -119,25 +116,22 @@ static QString deviceRegistryProperty(HDEVINFO deviceInfoSet, || (dataType != REG_SZ && dataType != REG_EXPAND_SZ)) { return QString(); } - devicePropertyByteArray.resize(requiredSize); + outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2, 0); } - return toStringAndTrimNullCharacter(devicePropertyByteArray); + return QString::fromWCharArray(&outputBuffer[0]); } static QString deviceInstanceIdentifier(DEVINST deviceInstanceNumber) { - ULONG numberOfChars = 0; - if (::CM_Get_Device_ID_Size(&numberOfChars, deviceInstanceNumber, 0) != CR_SUCCESS) - return QString(); - // The size does not include the terminating null character. - ++numberOfChars; - QByteArray outputBuffer; - outputBuffer.resize(numberOfChars * sizeof(wchar_t)); - if (::CM_Get_Device_ID(deviceInstanceNumber, reinterpret_cast<wchar_t *>(outputBuffer.data()), - outputBuffer.size(), 0) != CR_SUCCESS) { + std::vector<wchar_t> outputBuffer(MAX_DEVICE_ID_LEN + 1, 0); + if (::CM_Get_Device_ID( + deviceInstanceNumber, + &outputBuffer[0], + MAX_DEVICE_ID_LEN, + 0) != CR_SUCCESS) { return QString(); } - return toStringAndTrimNullCharacter(outputBuffer).toUpper(); + return QString::fromWCharArray(&outputBuffer[0]).toUpper(); } static DEVINST parentDeviceInstanceNumber(DEVINST childDeviceInstanceNumber) @@ -167,20 +161,20 @@ static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInf QString portName; foreach (const QString &portNameKey, portNameRegistryKeyList) { - DWORD bytesRequired = 0; DWORD dataType = 0; - QByteArray outputBuffer; + std::vector<wchar_t> outputBuffer(MAX_PATH + 1, 0); + DWORD bytesRequired = MAX_PATH; forever { const LONG ret = ::RegQueryValueEx(key, reinterpret_cast<const wchar_t *>(portNameKey.utf16()), Q_NULLPTR, &dataType, - reinterpret_cast<unsigned char *>(outputBuffer.data()), &bytesRequired); + reinterpret_cast<PBYTE>(&outputBuffer[0]), &bytesRequired); if (ret == ERROR_MORE_DATA) { - outputBuffer.resize(bytesRequired); + outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2, 0); continue; } else if (ret == ERROR_SUCCESS) { if (dataType == REG_SZ) - portName = toStringAndTrimNullCharacter(outputBuffer); + portName = QString::fromWCharArray(&outputBuffer[0]); else if (dataType == REG_DWORD) - portName = QStringLiteral("COM%1").arg(*(PDWORD(outputBuffer.constData()))); + portName = QStringLiteral("COM%1").arg(*(PDWORD(&outputBuffer[0]))); } break; } diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp index d50afe9..3a62bfa 100644 --- a/tests/auto/qserialport/tst_qserialport.cpp +++ b/tests/auto/qserialport/tst_qserialport.cpp @@ -120,6 +120,8 @@ private slots: void asynchronousWriteByTimer_data(); void asynchronousWriteByTimer(); + void asyncReadWithLimitedReadBufferSize(); + void readBufferOverflow(); void readAfterInputClear(); void synchronousReadWriteAfterAsynchronousReadWrite(); @@ -808,6 +810,49 @@ void tst_QSerialPort::asynchronousWriteByTimer() QCOMPARE(receiverPort.readAll(), alphabetArray); } +class AsyncReader2 : public QObject +{ + Q_OBJECT +public: + explicit AsyncReader2(QSerialPort &port, const QByteArray &expectedData) + : serialPort(port), expectedData(expectedData) + { + connect(&serialPort, &QSerialPort::readyRead, this, &AsyncReader2::receive); + } + +private slots: + void receive() + { + receivedData.append(serialPort.readAll()); + if (receivedData == expectedData) + tst_QSerialPort::exitLoop(); + } + +private: + QSerialPort &serialPort; + const QByteArray expectedData; + QByteArray receivedData; +}; + +void tst_QSerialPort::asyncReadWithLimitedReadBufferSize() +{ + QSerialPort senderPort(m_senderPortName); + QVERIFY(senderPort.open(QSerialPort::WriteOnly)); + + QSerialPort receiverPort(m_receiverPortName); + QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); + + receiverPort.setReadBufferSize(1); + QCOMPARE(receiverPort.readBufferSize(), qint64(1)); + + AsyncReader2 reader(receiverPort, alphabetArray); + + QCOMPARE(senderPort.write(alphabetArray), qint64(alphabetArray.size())); + + enterLoop(1); + QVERIFY2(!timeout(), "Timed out when waiting for the read or write."); +} + void tst_QSerialPort::readBufferOverflow() { QSerialPort senderPort(m_senderPortName); |