summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/serialport/qserialport.cpp2
-rw-r--r--src/serialport/qserialport_unix.cpp5
-rw-r--r--src/serialport/qserialport_unix_p.h1
-rw-r--r--src/serialport/qserialport_win.cpp35
-rw-r--r--src/serialport/qserialport_win_p.h2
-rw-r--r--src/serialport/qserialport_wince.cpp5
-rw-r--r--src/serialport/qserialport_wince_p.h1
-rw-r--r--tests/auto/qserialport/tst_qserialport.cpp35
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"