diff options
-rw-r--r-- | src/serialport/qserialport.cpp | 2 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 5 | ||||
-rw-r--r-- | src/serialport/qserialport_unix_p.h | 1 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 35 | ||||
-rw-r--r-- | src/serialport/qserialport_win_p.h | 2 | ||||
-rw-r--r-- | src/serialport/qserialport_wince.cpp | 5 | ||||
-rw-r--r-- | src/serialport/qserialport_wince_p.h | 1 | ||||
-rw-r--r-- | tests/auto/qserialport/tst_qserialport.cpp | 35 |
8 files changed, 82 insertions, 4 deletions
diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index ffc763e..c815dd0 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -1343,7 +1343,7 @@ bool QSerialPort::setBreakEnabled(bool set) qint64 QSerialPort::readData(char *data, qint64 maxSize) { Q_D(QSerialPort); - return d->readBuffer.read(data, maxSize); + return d->readData(data, maxSize); } /*! diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index e80c0e8..b082275 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -383,6 +383,11 @@ void QSerialPortPrivate::startWriting() setWriteNotificationEnabled(true); } +qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) +{ + return readBuffer.read(data, maxSize); +} + bool QSerialPortPrivate::waitForReadyRead(int msecs) { Q_Q(QSerialPort); diff --git a/src/serialport/qserialport_unix_p.h b/src/serialport/qserialport_unix_p.h index 1213c30..408fdc5 100644 --- a/src/serialport/qserialport_unix_p.h +++ b/src/serialport/qserialport_unix_p.h @@ -120,6 +120,7 @@ public: bool setBreakEnabled(bool set); void startWriting(); + qint64 readData(char *data, qint64 maxSize); bool waitForReadyRead(int msecs); bool waitForBytesWritten(int msecs); diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 18cef1e..3174db5 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -98,6 +98,7 @@ QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) , readChunkBuffer(ReadChunkSize, 0) , readyReadEmitted(0) , writeStarted(false) + , readStarted(false) , communicationNotifier(new QWinEventNotifier(q)) , readCompletionNotifier(new QWinEventNotifier(q)) , writeCompletionNotifier(new QWinEventNotifier(q)) @@ -173,6 +174,7 @@ void QSerialPortPrivate::close() writeCompletionNotifier->setEnabled(false); communicationNotifier->setEnabled(false); + readStarted = false; readBuffer.clear(); writeStarted = false; @@ -267,8 +269,10 @@ bool QSerialPortPrivate::clear(QSerialPort::Directions directions) Q_Q(QSerialPort); DWORD flags = 0; - if (directions & QSerialPort::Input) + if (directions & QSerialPort::Input) { flags |= PURGE_RXABORT | PURGE_RXCLEAR; + readStarted = false; + } if (directions & QSerialPort::Output) { flags |= PURGE_TXABORT | PURGE_TXCLEAR; writeStarted = false; @@ -320,6 +324,21 @@ void QSerialPortPrivate::startWriting() } } +qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) +{ + const qint64 result = readBuffer.read(data, 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 + && result > 0 + && (result == readBufferMaxSize || flowControl == QSerialPort::HardwareControl)) { + startAsyncRead(); + } + return result; +} + bool QSerialPortPrivate::waitForReadyRead(int msecs) { Q_Q(QSerialPort); @@ -523,14 +542,18 @@ bool QSerialPortPrivate::_q_completeAsyncCommunication() bool QSerialPortPrivate::_q_completeAsyncRead() { const qint64 bytesTransferred = handleOverlappedResult(QSerialPort::Input, readCompletionOverlapped); - if (bytesTransferred == qint64(-1)) + if (bytesTransferred == qint64(-1)) { + readStarted = false; return false; + } if (bytesTransferred > 0) { readBuffer.append(readChunkBuffer.left(bytesTransferred)); if (!emulateErrorPolicy()) emitReadyRead(); } + readStarted = false; + // start async read for possible remainder into driver queue if ((bytesTransferred == ReadChunkSize) && (policy == QSerialPort::IgnorePolicy)) return startAsyncRead(); @@ -578,6 +601,9 @@ bool QSerialPortPrivate::startAsyncRead() { Q_Q(QSerialPort); + if (readStarted) + return true; + DWORD bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { @@ -590,8 +616,10 @@ bool QSerialPortPrivate::startAsyncRead() } initializeOverlappedStructure(readCompletionOverlapped); - if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, NULL, &readCompletionOverlapped)) + if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, NULL, &readCompletionOverlapped)) { + readStarted = true; return true; + } QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { @@ -603,6 +631,7 @@ bool QSerialPortPrivate::startAsyncRead() return false; } + readStarted = true; return true; } diff --git a/src/serialport/qserialport_win_p.h b/src/serialport/qserialport_win_p.h index cf30c18..8db3a74 100644 --- a/src/serialport/qserialport_win_p.h +++ b/src/serialport/qserialport_win_p.h @@ -87,6 +87,7 @@ public: bool setBreakEnabled(bool set); void startWriting(); + qint64 readData(char *data, qint64 maxSize); bool waitForReadyRead(int msec); bool waitForBytesWritten(int msec); @@ -130,6 +131,7 @@ public: QByteArray readChunkBuffer; bool readyReadEmitted; bool writeStarted; + bool readStarted; QWinEventNotifier *communicationNotifier; QWinEventNotifier *readCompletionNotifier; QWinEventNotifier *writeCompletionNotifier; diff --git a/src/serialport/qserialport_wince.cpp b/src/serialport/qserialport_wince.cpp index c06e748..d6c58aa 100644 --- a/src/serialport/qserialport_wince.cpp +++ b/src/serialport/qserialport_wince.cpp @@ -351,6 +351,11 @@ void QSerialPortPrivate::startWriting() notifyWrite(); } +qint64 QSerialPortPrivate::readData(char *data, qint64 maxSize) +{ + return readBuffer.read(data, maxSize); +} + bool QSerialPortPrivate::waitForReadyRead(int msec) { if (!readBuffer.isEmpty()) diff --git a/src/serialport/qserialport_wince_p.h b/src/serialport/qserialport_wince_p.h index 91bba3c..be08bc1 100644 --- a/src/serialport/qserialport_wince_p.h +++ b/src/serialport/qserialport_wince_p.h @@ -86,6 +86,7 @@ public: bool setBreakEnabled(bool set); void startWriting(); + qint64 readData(char *data, qint64 maxSize); bool waitForReadyRead(int msec); bool waitForBytesWritten(int msec); diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp index 2b8de92..0fdde48 100644 --- a/tests/auto/qserialport/tst_qserialport.cpp +++ b/tests/auto/qserialport/tst_qserialport.cpp @@ -115,6 +115,10 @@ private slots: void asynchronousWriteByTimer_data(); void asynchronousWriteByTimer(); +#ifdef Q_OS_WIN + void readBufferOverflow(); +#endif + protected slots: void handleBytesWrittenAndExitLoopSlot(qint64 bytesWritten); void handleBytesWrittenAndExitLoopSlot2(qint64 bytesWritten); @@ -667,5 +671,36 @@ void tst_QSerialPort::asynchronousWriteByTimer() QCOMPARE(receiverPort.readAll(), alphabetArray); } +#ifdef Q_OS_WIN +void tst_QSerialPort::readBufferOverflow() +{ + clearReceiver(); + + QSerialPort senderPort(m_senderPortName); + QVERIFY(senderPort.open(QSerialPort::WriteOnly)); + + QSerialPort receiverPort(m_receiverPortName); + QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); + + const int readBufferSize = alphabetArray.size() / 2; + receiverPort.setReadBufferSize(readBufferSize); + QCOMPARE(receiverPort.readBufferSize(), qint64(readBufferSize)); + + QCOMPARE(senderPort.write(alphabetArray), qint64(alphabetArray.size())); + QVERIFY2(senderPort.waitForBytesWritten(100), "Waiting for bytes written failed"); + + QByteArray readData; + while (receiverPort.waitForReadyRead(100)) { + QVERIFY(receiverPort.bytesAvailable() > 0); + readData += receiverPort.readAll(); + } + + QCOMPARE(readData, alphabetArray); + + // No more bytes available + QVERIFY(receiverPort.bytesAvailable() == 0); +} +#endif + QTEST_MAIN(tst_QSerialPort) #include "tst_qserialport.moc" |