diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2014-09-29 18:44:36 +0400 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2014-10-02 09:21:53 +0200 |
commit | ac0422e8c9e74f2275129e3c7c69ef64299f07a9 (patch) | |
tree | 5196d564d75318db03e399308c9893e6d480d4c1 /src/serialport | |
parent | 26d61928f5a50c74f843cd88276c5b18e1bed375 (diff) | |
download | qtserialport-ac0422e8c9e74f2275129e3c7c69ef64299f07a9.tar.gz |
Fix reading on Windows at limited read buffer size
In case the read buffer has a limited size then are impossible to read
remainder which is still can be in driver's queue, since no readyRead
signal emmitted and reading are stalled.
Problem is that Windows does not fire the EV_RXCHAR event in case a
driver's queue has ready to read remainder; this event will be triggered
only when a new data are received.
The solution is to start of asynchronous read operation for reading of
possible remainder from the queue after doing QSP::read() from the user.
Besides is necessary to meet conditions:
- do not start reading in case a reading already is started
- do not start reading in case is not in limited buffer size
- do not start reading in case is a previous reading returns
a less data than read buffer size or are not in the hardware
flow control mode
Tested on Windows 8 with virtual com0com serial ports using Qt5 and then
Qt4.
Task-number: QTBUG-41295
Change-Id: I01797e6f8d6006751244144fead3616b1de1b811
Reviewed-by: Robert Kurjata <rkurjata@gmail.com>
Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Diffstat (limited to 'src/serialport')
-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 |
7 files changed, 47 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); |