summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2014-05-27 19:34:06 +0400
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-06-03 14:08:41 +0200
commitd598a00e823d8509fc67fc2452dcaf2939092804 (patch)
tree7c51ffa04a408da27e453c6527838c641d9790a1
parent2271479ff5d58b792af2c3823afe0f88fbf047ea (diff)
downloadqtserialport-d598a00e823d8509fc67fc2452dcaf2939092804.tar.gz
Fix waitForReadyRead() on windows
The commit 2360c401ae2012ed1b5a2b470a088cbbdb0d7f27 introduced an regression into waitForReadyRead(). Before this commit each read transaction was started again until the zero number of bytes will returns from FIFO. When FIFO is empty, all data has been read, and only then the waitForReadyRead() return true. I.e. condition "qint64(readBuffer.size()) != currentReadBufferSize" does not mean that reading is finished. But after that commit this condition is incorrect, because now each read operation started once and can not return zero bytes (in case the number of read bytes less than ReadChunkSize). Thus it led to returning of TimeoutError error. Now, this issue has been fixed. Also is added the set of auto-tests to testing of the waitForReadyRead() method. Tested on Windows 7/8 using Qt5 and then Qt4. Task-number: QTBUG-39314 Change-Id: I8abbf986c2a1cc77af634ddbc1747fb46f416a39 Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r--src/serialport/qserialport_win.cpp9
-rw-r--r--tests/auto/qserialport/tst_qserialport.cpp103
2 files changed, 110 insertions, 2 deletions
diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp
index 5411d17..111a8ce 100644
--- a/src/serialport/qserialport_win.cpp
+++ b/src/serialport/qserialport_win.cpp
@@ -403,10 +403,15 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs)
_q_completeAsyncCommunication();
} else if (triggeredEvent == readCompletionOverlapped.hEvent) {
_q_completeAsyncRead();
- if (qint64(readBuffer.size()) != currentReadBufferSize)
+ const qint64 readBytesForOneReadOperation = qint64(readBuffer.size()) - currentReadBufferSize;
+ if (readBytesForOneReadOperation == ReadChunkSize) {
currentReadBufferSize = readBuffer.size();
- else if (initialReadBufferSize != currentReadBufferSize)
+ } else if (readBytesForOneReadOperation == 0) {
+ if (initialReadBufferSize != currentReadBufferSize)
+ return true;
+ } else {
return true;
+ }
} else if (triggeredEvent == writeCompletionOverlapped.hEvent) {
_q_completeAsyncWrite();
} else {
diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp
index 96d3788..192541c 100644
--- a/tests/auto/qserialport/tst_qserialport.cpp
+++ b/tests/auto/qserialport/tst_qserialport.cpp
@@ -60,6 +60,18 @@ public:
--loopLevel;
}
+ static void enterLoopMsecs(int msecs)
+ {
+ ++loopLevel;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ QTestEventLoop::instance().enterLoopMSecs(msecs);
+#else
+ Q_UNUSED(msecs);
+ QTestEventLoop::instance().enterLoop(1);
+#endif
+ --loopLevel;
+ }
+
static void exitLoop()
{
if (loopLevel > 0)
@@ -88,11 +100,19 @@ private slots:
void waitForBytesWritten();
+ void waitForReadyReadWithTimeout();
+ void waitForReadyReadWithOneByte();
+ void waitForReadyReadWithAlphabet();
+
protected slots:
void handleBytesWrittenAndExitLoopSlot(qint64 bytesWritten);
void handleBytesWrittenAndExitLoopSlot2(qint64 bytesWritten);
private:
+#ifdef Q_OS_WIN
+ void clearReceiver();
+#endif
+
QString m_senderPortName;
QString m_receiverPortName;
QStringList m_availablePortNames;
@@ -111,6 +131,25 @@ tst_QSerialPort::tst_QSerialPort()
{
}
+#ifdef Q_OS_WIN
+// This method is a workaround for the "com0com" virtual serial port
+// driver, which is installed on CI. The problem is that the close/clear
+// methods have no effect on sender serial port. If any data didn't manage
+// to be transferred before closing, then this data will continue to be
+// transferred at next opening of sender port.
+// Thus, this behavior influences other tests and leads to the wrong results
+// (e.g. the receiver port on other test can receive some data which are
+// not expected). It is recommended to use this method for cleaning of
+// read FIFO of receiver for those tests in which reception of data is
+// required.
+void tst_QSerialPort::clearReceiver()
+{
+ QSerialPort receiver(m_receiverPortName);
+ if (receiver.open(QIODevice::ReadOnly))
+ enterLoopMsecs(100);
+}
+#endif
+
void tst_QSerialPort::initTestCase()
{
m_senderPortName = QString::fromLocal8Bit(qgetenv("QTEST_SERIALPORT_SENDER"));
@@ -335,5 +374,69 @@ void tst_QSerialPort::waitForBytesWritten()
QVERIFY(toWrite > serialPort.bytesToWrite());
}
+void tst_QSerialPort::waitForReadyReadWithTimeout()
+{
+#ifdef Q_OS_WIN
+ clearReceiver();
+ // the dummy device on other side also has to be open
+ QSerialPort dummySerialPort(m_senderPortName);
+ QVERIFY(dummySerialPort.open(QIODevice::WriteOnly));
+#endif
+
+ QSerialPort receiverSerialPort(m_receiverPortName);
+ QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly));
+ QVERIFY(!receiverSerialPort.waitForReadyRead(5));
+ QCOMPARE(receiverSerialPort.bytesAvailable(), qint64(0));
+ QCOMPARE(receiverSerialPort.error(), QSerialPort::TimeoutError);
+}
+
+void tst_QSerialPort::waitForReadyReadWithOneByte()
+{
+#ifdef Q_OS_WIN
+ clearReceiver();
+#endif
+
+ const qint64 oneByte = 1;
+ const int waitMsecs = 50;
+
+ QSerialPort senderSerialPort(m_senderPortName);
+ QVERIFY(senderSerialPort.open(QIODevice::WriteOnly));
+ QSerialPort receiverSerialPort(m_receiverPortName);
+ QSignalSpy readyReadSpy(&receiverSerialPort, SIGNAL(readyRead()));
+ QVERIFY(readyReadSpy.isValid());
+ QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly));
+ QCOMPARE(senderSerialPort.write(alphabetArray.constData(), oneByte), oneByte);
+ QVERIFY(senderSerialPort.waitForBytesWritten(waitMsecs));
+ QVERIFY(receiverSerialPort.waitForReadyRead(waitMsecs));
+ QCOMPARE(receiverSerialPort.bytesAvailable(), oneByte);
+ QCOMPARE(receiverSerialPort.error(), QSerialPort::NoError);
+ QCOMPARE(readyReadSpy.count(), 1);
+}
+
+void tst_QSerialPort::waitForReadyReadWithAlphabet()
+{
+#ifdef Q_OS_WIN
+ clearReceiver();
+#endif
+
+ const int waitMsecs = 50;
+
+ QSerialPort senderSerialPort(m_senderPortName);
+ QVERIFY(senderSerialPort.open(QIODevice::WriteOnly));
+ QSerialPort receiverSerialPort(m_receiverPortName);
+ QSignalSpy readyReadSpy(&receiverSerialPort, SIGNAL(readyRead()));
+ QVERIFY(readyReadSpy.isValid());
+ QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly));
+ QCOMPARE(senderSerialPort.write(alphabetArray), qint64(alphabetArray.size()));
+ QVERIFY(senderSerialPort.waitForBytesWritten(waitMsecs));
+
+ do {
+ QVERIFY(receiverSerialPort.waitForReadyRead(waitMsecs));
+ } while (receiverSerialPort.bytesAvailable() < qint64(alphabetArray.size()));
+
+ QCOMPARE(receiverSerialPort.error(), QSerialPort::NoError);
+ QVERIFY(readyReadSpy.count() > 0);
+}
+
QTEST_MAIN(tst_QSerialPort)
#include "tst_qserialport.moc"