summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2015-06-28 00:11:29 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2015-07-09 13:48:01 +0000
commiteb2ab3da76802a18f784e4f72a200e83ad2edc6c (patch)
tree8594bcc29bef84e29c24f80bc1b1f3e692d77eb3
parentfbe5c46ce311681b319f9cf277379958f3e10e93 (diff)
downloadqtserialport-eb2ab3da76802a18f784e4f72a200e83ad2edc6c.tar.gz
Fix reading when switching from asynchronous to synchronous approach
If one wants to use the asynchronous approach (using the signals and slots), and then - the synchronous (using the waitForXX functions) then synchronous reading stalls because the waitForReadyRead() method always returns the TimeoutError code. The reason is that the signal readyRead() is emitted before the startAsyncRead() (or the startAsyncCommunication()) called inside of completeAsyncRead(). Need to emit the readyRead() only after the next asynchronous reading (the startAsyncRead() or the startAsyncCommunication()) was cocked. Now the behavior is similar to behavior of QWindowsPipeReader. Besides, the auto-test which reveals this issue is added. Tested with the virtual com0com serial ports, using the auto-tests and set of the examples. (cherry-picked from b32740001f735be9f0938f85d325dc2cf3dbe598) Change-Id: I64bfb871d17c179f474d6672546e532566913a7f Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r--src/serialport/qserialport_win.cpp17
-rw-r--r--tests/auto/qserialport/tst_qserialport.cpp104
2 files changed, 113 insertions, 8 deletions
diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp
index 73fedc0..5379b13 100644
--- a/src/serialport/qserialport_win.cpp
+++ b/src/serialport/qserialport_win.cpp
@@ -508,20 +508,21 @@ bool QSerialPortPrivate::_q_completeAsyncRead()
readStarted = false;
return false;
}
- if (bytesTransferred > 0) {
+ if (bytesTransferred > 0)
readBuffer.append(readChunkBuffer.left(bytesTransferred));
- if (!emulateErrorPolicy())
- emitReadyRead();
- }
readStarted = false;
+ bool result = true;
if ((bytesTransferred == ReadChunkSize) && (policy == QSerialPort::IgnorePolicy))
- return startAsyncRead();
+ result = startAsyncRead();
else if (readBufferMaxSize == 0 || readBufferMaxSize > readBuffer.size())
- return startAsyncCommunication();
- else
- return true;
+ result = startAsyncCommunication();
+
+ if ((bytesTransferred > 0) && !emulateErrorPolicy())
+ emitReadyRead();
+
+ return result;
}
bool QSerialPortPrivate::_q_completeAsyncWrite()
diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp
index 53fa26d..a931101 100644
--- a/tests/auto/qserialport/tst_qserialport.cpp
+++ b/tests/auto/qserialport/tst_qserialport.cpp
@@ -43,6 +43,8 @@
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
+#include <QThread>
+
Q_DECLARE_METATYPE(QSerialPort::SerialPortError);
Q_DECLARE_METATYPE(QIODevice::OpenMode);
Q_DECLARE_METATYPE(QIODevice::OpenModeFlag);
@@ -114,6 +116,7 @@ private slots:
#ifdef Q_OS_WIN
void readBufferOverflow();
void readAfterInputClear();
+ void synchronousReadWriteAfterAsynchronousReadWrite();
#endif
void controlBreak();
@@ -742,6 +745,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, SIGNAL(readyRead()), this, SLOT(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, SIGNAL(readyRead()), this, SLOT(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, SIGNAL(finished()), slave, SLOT(deleteLater()));
+ QObject::connect(slave, SIGNAL(ready()), &master, SLOT(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