diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2013-02-05 05:22:45 +0000 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2013-02-05 18:30:53 +0100 |
commit | b412c0e0e90945b041dfd4615ae92fb95c67d000 (patch) | |
tree | 92b201d619c042c2b91d870154f8edeea7401b92 /src/serialport | |
parent | 7a21332e69bc0ea25d885333ca16e987437db0b1 (diff) | |
download | qtserialport-b412c0e0e90945b041dfd4615ae92fb95c67d000.tar.gz |
Introduce new I/O errors and enhanced it implementation
Instead of a single I/O error type IoError introduced new errors
WriteError, ReadError and ResourceError.
WriteError - occurs when a write operation is failed.
ReadError - occurs when a read operation is failed.
ResourceError - is a critical error. Occur when the operation is the
I/O in a non-existent or invalid device handle. Also, this error
indicates the sudden removal of the device from the system,
for example, when pulled out already open USB/Serial converter.
When an ResourceError occurs the user must close the device by close()
method, otherwise it will lead to an infinite trigger a I/O notifiers
(at least on *nix platform).
Checked on Windows and Linux with USB/Serial PL2303 converter.
Change-Id: I911fcb0072e194ea449a8a2db9115266ad40e74e
Reviewed-by: Laszlo Papp <lpapp@kde.org>
Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
Diffstat (limited to 'src/serialport')
-rw-r--r-- | src/serialport/qserialport.cpp | 5 | ||||
-rw-r--r-- | src/serialport/qserialport.h | 4 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 73 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 96 | ||||
-rw-r--r-- | src/serialport/qserialport_win_p.h | 2 | ||||
-rw-r--r-- | src/serialport/qserialport_wince.cpp | 22 |
6 files changed, 113 insertions, 89 deletions
diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index af69f1f..c365f9b 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -367,7 +367,10 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \value FramingError Framing error detected by the hardware while reading data. \value BreakConditionError Break condition detected by the hardware on the input line. - \value IoError An I/O error occurred while reading or writing the data. + \value WriteError An I/O error occurred while writing the data. + \value ReadError An I/O error occurred while reading the data. + \value ResourceError An I/O error occurred when a resource becomes unavailable, + e.g. when the device is unexpectedly removed from the system. \value UnsupportedOperationError The requested device operation is not supported or prohibited by the running operating system. \value UnknownError An unidentified error occurred. diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index e3ac92e..4e0aff0 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -151,7 +151,9 @@ public: ParityError, FramingError, BreakConditionError, - IoError, + WriteError, + ReadError, + ResourceError, UnsupportedOperationError, UnknownError }; diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 65f3d9d..2acc26f 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -701,11 +701,17 @@ bool QSerialPortPrivate::readNotification() char *ptr = readBuffer.reserve(bytesToRead); const qint64 readBytes = readFromPort(ptr, bytesToRead); - if (readBytes == -2) { - // No bytes currently available for reading. + + if (readBytes <= 0) { readBuffer.chop(bytesToRead); - return true; + + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::ReadError; + q_ptr->setError(error); + return false; } + readBuffer.chop(bytesToRead - qMax(readBytes, qint64(0))); newBytes = readBuffer.size() - newBytes; @@ -752,7 +758,10 @@ bool QSerialPortPrivate::writeNotification(int maxSize) // Attempt to write it chunk. qint64 written = writeToPort(ptr, nextSize); if (written < 0) { - q_ptr->setError(decodeSystemError()); + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + q_ptr->setError(error); return false; } @@ -775,8 +784,10 @@ bool QSerialPortPrivate::writeNotification(int maxSize) bool QSerialPortPrivate::exceptionNotification() { - // FIXME: - return false; + QSerialPort::SerialPortError error = decodeSystemError(); + q_ptr->setError(error); + + return true; } bool QSerialPortPrivate::updateTermios() @@ -891,8 +902,14 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const case EBUSY: error = QSerialPort::PermissionError; break; - case ENOTTY: - error = QSerialPort::IoError; + case EAGAIN: + error = QSerialPort::ResourceError; + break; + case EIO: + error = QSerialPort::ResourceError; + break; + case EBADF: + error = QSerialPort::ResourceError; break; default: error = QSerialPort::UnknownError; @@ -997,29 +1014,6 @@ qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize) bytesRead = readPerChar(data, maxSize); } - // FIXME: Here 'errno' codes for sockets. - // You need to replace the codes for the serial port. - if (bytesRead < 0) { - bytesRead = -1; - switch (errno) { -#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - // No data was available for reading. - bytesRead = -2; - break; - case EBADF: - case EINVAL: - case EIO: - break; - case ECONNRESET: - bytesRead = 0; - break; - default: - break; - } - } return bytesRead; } @@ -1037,23 +1031,6 @@ qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize) } #endif - // FIXME: Here 'errno' codes for sockets. - // You need to replace the codes for the serial port. - if (bytesWritten < 0) { - switch (errno) { - case EPIPE: - case ECONNRESET: - bytesWritten = -1; - break; - case EAGAIN: - bytesWritten = 0; - break; - case EMSGSIZE: - break; - default: - break; - } - } return bytesWritten; } diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 950452d..fb3e970 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -140,10 +140,25 @@ public: virtual bool processCompletionRoutine() { DWORD numberOfBytesTransferred = 0; ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); - if (EV_ERR & triggeredEventMask) - dptr->processIoErrors(); - dptr->startAsyncRead(); - return true; + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if ((triggeredEventMask == 0) + || ((originalEventMask & triggeredEventMask) == 0)) { + error = true; + } + + // Start processing a caught error. + if (error || (EV_ERR & triggeredEventMask)) + dptr->processIoErrors(error); + + if (!error) + dptr->startAsyncRead(); + + return error; } private: @@ -621,24 +636,22 @@ bool QSerialPortPrivate::startAsyncRead() char *ptr = readBuffer.reserve(bytesToRead); AbstractOverlappedEventNotifier *n = lookupReadCompletionNotifier(); - if (!n) + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); return false; + } if (::ReadFile(descriptor, ptr, bytesToRead, NULL, n->overlappedPointer())) return true; - switch (::GetLastError()) { - case ERROR_IO_PENDING: - // This is not an error. We're getting notified, when data arrives. - case ERROR_MORE_DATA: - // This is not an error. The synchronous read succeeded. - return true; - default: - // error - break; + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + error = QSerialPort::ReadError; + q_ptr->setError(error); + return false; } - return false; + return true; } bool QSerialPortPrivate::startAsyncWrite(int maxSize) @@ -656,41 +669,47 @@ bool QSerialPortPrivate::startAsyncWrite(int maxSize) writeSequenceStarted = true; AbstractOverlappedEventNotifier *n = lookupFreeWriteCompletionNotifier(); - if (!n) + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); return false; + } n->setEnabled(true); if (::WriteFile(descriptor, ptr, nextSize, NULL, n->overlappedPointer())) return true; - switch (::GetLastError()) { - case ERROR_IO_PENDING: - // This is not an error. We're getting notified, when data arrives. - return true; - case ERROR_MORE_DATA: - // This is not an error. The synchronous read succeeded. - break; - default: - // error - writeSequenceStarted = false; - return false; + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + writeSequenceStarted = false; + + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + + q_ptr->setError(error); + return false; } + return true; } #endif // #ifndef Q_OS_WINCE -bool QSerialPortPrivate::processIoErrors() +bool QSerialPortPrivate::processIoErrors(bool error) { - DWORD error = 0; - const bool ret = ::ClearCommError(descriptor, &error, NULL); - if (ret && error) { + if (error) { + q_ptr->setError(QSerialPort::ResourceError); + return true; + } + + DWORD errors = 0; + const bool ret = ::ClearCommError(descriptor, &errors, NULL); + if (ret && errors) { if (error & CE_FRAME) q_ptr->setError(QSerialPort::FramingError); - else if (error & CE_RXPARITY) + else if (errors & CE_RXPARITY) q_ptr->setError(QSerialPort::ParityError); - else if (error & CE_BREAK) + else if (errors & CE_BREAK) q_ptr->setError(QSerialPort::BreakConditionError); else q_ptr->setError(QSerialPort::UnknownError); @@ -883,6 +902,12 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const { QSerialPort::SerialPortError error; switch (::GetLastError()) { + case ERROR_IO_PENDING: + error = QSerialPort::NoError; + break; + case ERROR_MORE_DATA: + error = QSerialPort::NoError; + break; case ERROR_FILE_NOT_FOUND: error = QSerialPort::DeviceNotFoundError; break; @@ -890,11 +915,14 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const error = QSerialPort::PermissionError; break; case ERROR_INVALID_HANDLE: - error = QSerialPort::DeviceIsNotOpenedError; + error = QSerialPort::ResourceError; break; case ERROR_INVALID_PARAMETER: error = QSerialPort::UnsupportedOperationError; break; + case ERROR_BAD_COMMAND: + error = QSerialPort::ResourceError; + break; default: error = QSerialPort::UnknownError; break; diff --git a/src/serialport/qserialport_win_p.h b/src/serialport/qserialport_win_p.h index 9fa9997..570a6c3 100644 --- a/src/serialport/qserialport_win_p.h +++ b/src/serialport/qserialport_win_p.h @@ -98,7 +98,7 @@ public: bool setFlowControl(QSerialPort::FlowControl flowControl); bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); - bool processIoErrors(); + bool processIoErrors(bool error); #ifndef Q_OS_WINCE bool startAsyncRead(); bool startAsyncWrite(int maxSize = INT_MAX); diff --git a/src/serialport/qserialport_wince.cpp b/src/serialport/qserialport_wince.cpp index dc7c54d..026d194 100644 --- a/src/serialport/qserialport_wince.cpp +++ b/src/serialport/qserialport_wince.cpp @@ -87,9 +87,20 @@ protected: private slots: void processNotification(quint32 eventMask) { - if (EV_ERR & eventMask) - dptr->processIoErrors(); - if (EV_RXCHAR &eventMask) + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if ((eventMask == 0) + || ((eventMask & (EV_ERR | EV_RXCHAR | EV_TXEMPTY)) == 0)) { + error = true; + } + + if (error || (EV_ERR & eventMask)) + dptr->processIoErrors(error); + if (EV_RXCHAR & eventMask) dptr->notifyRead(); if (EV_TXEMPTY & eventMask) dptr->notifyWrite(QSerialPortPrivateData::WriteChunkSize); @@ -358,6 +369,7 @@ bool QSerialPortPrivate::notifyRead() if (!sucessResult) { readBuffer.truncate(bytesToRead); + q_ptr->setError(QSerialPort::ReadError); return false; } @@ -396,8 +408,10 @@ bool QSerialPortPrivate::notifyWrite(int maxSize) const char *ptr = writeBuffer.readPointer(); DWORD bytesWritten = 0; - if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL)) + if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL)) { + q_ptr->setError(QSerialPort::WriteError); return false; + } writeBuffer.free(bytesWritten); |