diff options
Diffstat (limited to 'src/serialport')
-rw-r--r-- | src/serialport/qserialport.cpp | 81 | ||||
-rw-r--r-- | src/serialport/qserialport.h | 23 | ||||
-rw-r--r-- | src/serialport/qserialport_symbian.cpp | 26 | ||||
-rw-r--r-- | src/serialport/qserialport_symbian_p.h | 3 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 51 | ||||
-rw-r--r-- | src/serialport/qserialport_unix_p.h | 3 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 480 | ||||
-rw-r--r-- | src/serialport/qserialport_win_p.h | 29 | ||||
-rw-r--r-- | src/serialport/qserialport_wince.cpp | 29 | ||||
-rw-r--r-- | src/serialport/qserialportglobal.h | 4 | ||||
-rw-r--r-- | src/serialport/qserialportinfo.cpp | 1 | ||||
-rw-r--r-- | src/serialport/qserialportinfo.h | 7 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_mac.cpp | 3 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_symbian.cpp | 21 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_unix.cpp | 150 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 57 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_wince.cpp | 3 | ||||
-rw-r--r-- | src/serialport/qtudev_p.h | 2 | ||||
-rw-r--r-- | src/serialport/serialport-lib.pri | 2 |
19 files changed, 408 insertions, 567 deletions
diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 7c332cc..5d9442e 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -70,10 +70,10 @@ QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q) , error(QSerialPort::NoError) , inputBaudRate(0) , outputBaudRate(0) - , dataBits(QSerialPort::UnknownDataBits) - , parity(QSerialPort::UnknownParity) - , stopBits(QSerialPort::UnknownStopBits) - , flow(QSerialPort::UnknownFlowControl) + , dataBits(QSerialPort::Data8) + , parity(QSerialPort::NoParity) + , stopBits(QSerialPort::OneStop) + , flow(QSerialPort::NoFlowControl) , policy(QSerialPort::IgnorePolicy) , settingsRestoredOnClose(true) , q_ptr(q) @@ -198,7 +198,9 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \value Baud38400 38400 baud. \value Baud57600 57600 baud. \value Baud115200 115200 baud. - \value UnknownBaud Unknown baud. + \value UnknownBaud Unknown baud. This value is obsolete. It is provided to + keep old source code working. We strongly advise against + using it in new code. \sa QSerialPort::baudRate */ @@ -208,11 +210,21 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) This enum describes the number of data bits used. - \value Data5 Five bits. - \value Data6 Six bits. - \value Data7 Seven bits - \value Data8 Eight bits. - \value UnknownDataBits Unknown number of bits. + \value Data5 The number of data bits in each character is 5. It + is used for Baudot code. It generally only makes + sense with older equipments such as teleprinters. + \value Data6 The number of data bits in each character is 6. It + is rarely used. + \value Data7 The number of data bits in each character is 7. It + is used for true ASCII. It generally only makes + sense with older equipments such as teleprinters. + \value Data8 The number of data bits in each character is 8. It + is used for most kinds of data, as this size matches + the size of a byte. It is almost universally used in + newer applications. + \value UnknownDataBits Unknown number of bits. This value is obsolete. It + is provided to keep old source code working. We + strongly advise against using it in new code. \sa QSerialPort::dataBits */ @@ -222,12 +234,23 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) This enum describes the parity scheme used. - \value NoParity No parity. - \value EvenParity Even parity. - \value OddParity Odd parity. - \value SpaceParity Space parity. - \value MarkParity Mark parity. - \value UnknownParity Unknown parity. + \value NoParity No parity bit it sent. This is the most common + parity setting. Error detection is handled by the + communication protocol. + \value EvenParity The number of 1 bits in each character, including + the parity bit, is always even. + \value OddParity The number of 1 bits in each character, including + the parity bit, is always odd. It ensures that at + least one state transition occurs in each character. + \value SpaceParity Space parity. The parity bit is sent in the space + signal condition. It does not provide error + detection information. + \value MarkParity Mark parity. The parity bit is always set to the + mark signal condition (logical 1). It does not + provide error detection information. + \value UnknownParity Unknown parity. This value is obsolete. It is + provided to keep old source code working. We + strongly advise against using it in new code. \sa QSerialPort::parity */ @@ -238,9 +261,11 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) This enum describes the number of stop bits used. \value OneStop 1 stop bit. - \value OneAndHalfStop 1.5 stop bits. + \value OneAndHalfStop 1.5 stop bits. This is only for Windows platform. \value TwoStop 2 stop bits. - \value UnknownStopBits Unknown number of stop bit. + \value UnknownStopBits Unknown number of stop bit. This value is obsolete. + It is provided to keep old source code working. We + strongly advise against using it in new code. \sa QSerialPort::stopBits */ @@ -253,7 +278,9 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \value NoFlowControl No flow control. \value HardwareControl Hardware flow control (RTS/CTS). \value SoftwareControl Software flow control (XON/XOFF). - \value UnknownFlowControl Unknown flow control. + \value UnknownFlowControl Unknown flow control. This value is obsolete. It + is provided to keep old source code working. We + strongly advise against using it in new code. \sa QSerialPort::flowControl */ @@ -274,7 +301,6 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \value ClearToSendSignal CTS (Clear To Send). \value SecondaryTransmittedDataSignal STD (Secondary Transmitted Data). \value SecondaryReceivedDataSignal SRD (Secondary Received Data). - \value UnknownSignal Unknown line state. This value was introduced in QtSerialPort 5.2. \sa pinoutSignals(), QSerialPort::dataTerminalReady, QSerialPort::requestToSend @@ -621,7 +647,7 @@ qint32 QSerialPort::baudRate(Directions directions) const Q_D(const QSerialPort); if (directions == QSerialPort::AllDirections) return d->inputBaudRate == d->outputBaudRate ? - d->inputBaudRate : QSerialPort::UnknownBaud; + d->inputBaudRate : -1; return directions & QSerialPort::Input ? d->inputBaudRate : d->outputBaudRate; } @@ -953,8 +979,7 @@ bool QSerialPort::isRequestToSend() operating systems cannot provide proper notifications about the changes. \note The serial port has to be open before trying to get the pinout - signals; otherwise returns UnknownSignal and sets the NotOpenError error - code. + signals; otherwise returns NoSignal and sets the NotOpenError error code. \sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(), setRequestToSend() @@ -966,7 +991,7 @@ QSerialPort::PinoutSignals QSerialPort::pinoutSignals() if (!isOpen()) { setError(QSerialPort::NotOpenError); qWarning("%s: device not open", Q_FUNC_INFO); - return QSerialPort::UnknownSignal; + return QSerialPort::NoSignal; } return d->pinoutSignals(); @@ -1053,7 +1078,7 @@ bool QSerialPort::clear(Directions directions) bool QSerialPort::atEnd() const { Q_D(const QSerialPort); - return QIODevice::atEnd() && (!isOpen() || (d->bytesAvailable() == 0)); + return QIODevice::atEnd() && (!isOpen() || (d->readBuffer.size() == 0)); } /*! @@ -1201,7 +1226,7 @@ bool QSerialPort::isSequential() const qint64 QSerialPort::bytesAvailable() const { Q_D(const QSerialPort); - return d->bytesAvailable() + QIODevice::bytesAvailable(); + return d->readBuffer.size() + QIODevice::bytesAvailable(); } /*! @@ -1230,7 +1255,7 @@ qint64 QSerialPort::bytesToWrite() const bool QSerialPort::canReadLine() const { Q_D(const QSerialPort); - const bool hasLine = (d->bytesAvailable() > 0) && d->readBuffer.canReadLine(); + const bool hasLine = (d->readBuffer.size() > 0) && d->readBuffer.canReadLine(); return hasLine || QIODevice::canReadLine(); } @@ -1333,7 +1358,7 @@ bool QSerialPort::setBreakEnabled(bool set) qint64 QSerialPort::readData(char *data, qint64 maxSize) { Q_D(QSerialPort); - return d->readFromBuffer(data, maxSize); + return d->readBuffer.read(data, maxSize); } /*! diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index ada19fb..c07af91 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -47,10 +47,6 @@ #include <QtSerialPort/qserialportglobal.h> -#ifndef QT_DEPRECATED_SINCE -#define QT_DEPRECATED_SINCE(major, minor) 1 -#endif - QT_BEGIN_NAMESPACE class QSerialPortInfo; @@ -135,6 +131,16 @@ public: UnknownFlowControl = -1 }; +#if QT_DEPRECATED_SINCE(5, 2) +#if defined _MSC_VER +#pragma deprecated(UnknownBaud) +#pragma deprecated(UnknownDataBits) +#pragma deprecated(UnknownParity) +#pragma deprecated(UnknownStopBits) +#pragma deprecated(UnknownFlowControl) +#endif +#endif + enum PinoutSignal { NoSignal = 0x00, TransmittedDataSignal = 0x01, @@ -146,8 +152,7 @@ public: RequestToSendSignal = 0x40, ClearToSendSignal = 0x80, SecondaryTransmittedDataSignal = 0x100, - SecondaryReceivedDataSignal = 0x200, - UnknownSignal = -1 + SecondaryReceivedDataSignal = 0x200 }; Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal) @@ -269,6 +274,12 @@ private: QSerialPortPrivate * const d_ptr; Q_DISABLE_COPY(QSerialPort) + +#if defined (Q_OS_WIN32) || defined(Q_OS_WIN64) + Q_PRIVATE_SLOT(d_func(), void _q_canCompleteCommunication()) + Q_PRIVATE_SLOT(d_func(), void _q_canCompleteRead()) + Q_PRIVATE_SLOT(d_func(), void _q_canCompleteWrite()) +#endif }; Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions) diff --git a/src/serialport/qserialport_symbian.cpp b/src/serialport/qserialport_symbian.cpp index d905db1..6047793 100644 --- a/src/serialport/qserialport_symbian.cpp +++ b/src/serialport/qserialport_symbian.cpp @@ -248,17 +248,6 @@ qint64 QSerialPortPrivate::systemOutputQueueSize () const return 0; } -qint64 QSerialPortPrivate::bytesAvailable() const -{ - return readBuffer.size(); -} - -qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) -{ - // TODO: Implement me - return -1; -} - qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) { // TODO: Implement me @@ -433,7 +422,8 @@ void QSerialPortPrivate::detectDefaultSettings() dataBits = QSerialPort::Data8; break; default: - dataBits = QSerialPort::UnknownDataBits; + qWarning("%s: Unexpected data bits settings", Q_FUNC_INFO); + dataBits = QSerialPort::Data8; break; } @@ -455,7 +445,8 @@ void QSerialPortPrivate::detectDefaultSettings() parity = QSerialPort::SpaceParity; break; default: - parity = QSerialPort::UnknownParity; + qWarning("%s: Unexpected parity settings", Q_FUNC_INFO); + parity = QSerialPort::NoParity; break; } @@ -468,7 +459,8 @@ void QSerialPortPrivate::detectDefaultSettings() stopBits = QSerialPort::TwoStop; break; default: - stopBits = QSerialPort::UnknownStopBits; + qWarning("%s: Unexpected stop bits settings", Q_FUNC_INFO); + stopBits = QSerialPort::OneStop; break; } @@ -481,8 +473,10 @@ void QSerialPortPrivate::detectDefaultSettings() flow = QSerialPort::HardwareControl; else if (currentSettings().iHandshake & KConfigFailDSR) flow = QSerialPort::NoFlowControl; - else - flow = QSerialPort::UnknownFlowControl; + else { + qWarning("%s: Unexpected flow control settings", Q_FUNC_INFO); + flow = QSerialPort::NoFlowControl; + } } QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const diff --git a/src/serialport/qserialport_symbian_p.h b/src/serialport/qserialport_symbian_p.h index c56ddae..253aa11 100644 --- a/src/serialport/qserialport_symbian_p.h +++ b/src/serialport/qserialport_symbian_p.h @@ -72,9 +72,6 @@ public: qint64 systemInputQueueSize () const; qint64 systemOutputQueueSize () const; - qint64 bytesAvailable() const; - - qint64 readFromBuffer(char *data, qint64 maxSize); qint64 writeToBuffer(const char *data, qint64 maxSize); bool waitForReadyRead(int msec); diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 8b3d94b..51bb01e 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -305,7 +305,7 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() if (::ioctl(descriptor, TIOCMGET, &arg) == -1) { q->setError(decodeSystemError()); - return QSerialPort::UnknownSignal; + return QSerialPort::NoSignal; } QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; @@ -414,46 +414,6 @@ qint64 QSerialPortPrivate::systemOutputQueueSize () const return nbytes; } -qint64 QSerialPortPrivate::bytesAvailable() const -{ - return readBuffer.size(); -} - -qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) -{ - if (readBuffer.isEmpty()) - return 0; - - if (maxSize == 1) { - *data = readBuffer.getChar(); - if (readBuffer.isEmpty()) - setReadNotificationEnabled(true); - return 1; - } - - const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); - qint64 readSoFar = 0; - while (readSoFar < bytesToRead) { - const char *ptr = readBuffer.readPointer(); - const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), - readBuffer.nextDataBlockSize()); - ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); - readSoFar += bytesToReadFromThisBlock; - readBuffer.free(bytesToReadFromThisBlock); - } - - if (!isReadNotificationEnabled()) - setReadNotificationEnabled(true); - - if (readSoFar > 0) { - if (readBuffer.isEmpty()) - setReadNotificationEnabled(true); - return readSoFar; - } - - return readSoFar; -} - qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) { char *ptr = writeBuffer.reserve(maxSize); @@ -921,7 +881,8 @@ void QSerialPortPrivate::detectDefaultSettings() dataBits = QSerialPort::Data8; break; default: - dataBits = QSerialPort::UnknownDataBits; + qWarning("%s: Unexpected data bits settings", Q_FUNC_INFO); + dataBits = QSerialPort::Data8; break; } @@ -953,8 +914,10 @@ void QSerialPortPrivate::detectDefaultSettings() flow = QSerialPort::SoftwareControl; else if ((currentTermios.c_cflag & CRTSCTS) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY)))) flow = QSerialPort::HardwareControl; - else - flow = QSerialPort::UnknownFlowControl; + else { + qWarning("%s: Unexpected flow control settings", Q_FUNC_INFO); + flow = QSerialPort::NoFlowControl; + } } QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const diff --git a/src/serialport/qserialport_unix_p.h b/src/serialport/qserialport_unix_p.h index 15bb5f8..7c2b771 100644 --- a/src/serialport/qserialport_unix_p.h +++ b/src/serialport/qserialport_unix_p.h @@ -111,9 +111,6 @@ public: qint64 systemInputQueueSize () const; qint64 systemOutputQueueSize () const; - qint64 bytesAvailable() const; - - qint64 readFromBuffer(char *data, qint64 maxSize); qint64 writeToBuffer(const char *data, qint64 maxSize); bool waitForReadyRead(int msecs); diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 80cba34..506dc94 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -88,167 +88,55 @@ QT_BEGIN_NAMESPACE #ifndef Q_OS_WINCE -class AbstractOverlappedEventNotifier : public QWinEventNotifier +static void initializeOverlappedStructure(OVERLAPPED &overlapped) { - Q_OBJECT -public: - enum Type { CommEvent, ReadCompletionEvent, WriteCompletionEvent }; - - AbstractOverlappedEventNotifier(QSerialPortPrivate *d, Type type, bool manual, QObject *parent) - : QWinEventNotifier(parent), dptr(d), t(type) { - ::ZeroMemory(&o, sizeof(o)); - o.hEvent = ::CreateEvent(NULL, manual, FALSE, NULL); - if (!o.hEvent) { - dptr->setError(dptr->decodeSystemError()); - } else { - setHandle(o.hEvent); - dptr->notifiers[o.hEvent] = this; - } - } - - virtual bool processCompletionRoutine() = 0; - - virtual ~AbstractOverlappedEventNotifier() { - setEnabled(false); - if (!::CloseHandle(o.hEvent)) - dptr->setError(dptr->decodeSystemError()); - } - - Type type() const { return t; } - OVERLAPPED *overlappedPointer() { return &o; } - -protected: - bool event(QEvent *e) Q_DECL_OVERRIDE { - const bool ret = QWinEventNotifier::event(e); - if (e->type() == QEvent::WinEventAct) - processCompletionRoutine(); - return ret; - } - - QSerialPortPrivate *dptr; - Type t; - OVERLAPPED o; -}; - -class CommOverlappedEventNotifier : public AbstractOverlappedEventNotifier -{ - Q_OBJECT -public: - CommOverlappedEventNotifier(QSerialPortPrivate *d, DWORD eventMask, QObject *parent) - : AbstractOverlappedEventNotifier(d, CommEvent, false, parent) - , originalEventMask(eventMask), triggeredEventMask(0) { - if (!::SetCommMask(dptr->descriptor, originalEventMask)) - dptr->setError(dptr->decodeSystemError()); - else - startWaitCommEvent(); - } - - void startWaitCommEvent() { - if (!::WaitCommEvent(dptr->descriptor, &triggeredEventMask, &o)) { - const QSerialPort::SerialPortError error = dptr->decodeSystemError(); - if (error != QSerialPort::NoError) { - dptr->setError(dptr->decodeSystemError()); - return; - } - } - } - - bool processCompletionRoutine() Q_DECL_OVERRIDE { - DWORD numberOfBytesTransferred = 0; - - if (!::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE)) - dptr->setError(dptr->decodeSystemError()); - - 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) - error = true; - - // Workaround for standard CDC ACM serial ports, for which triggered an - // unexpected event EV_TXEMPTY at data transmission. - if ((originalEventMask & triggeredEventMask) == 0) { - if ((triggeredEventMask & EV_TXEMPTY) == 0) - error = true; - } - - // Start processing a caught error. - if (error || (EV_ERR & triggeredEventMask)) - dptr->processIoErrors(error); - - if (!error) - dptr->startAsyncRead(); - - return !error; - } - -private: - DWORD originalEventMask; - DWORD triggeredEventMask; -}; - -class ReadOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier -{ - Q_OBJECT -public: - ReadOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) - : AbstractOverlappedEventNotifier(d, ReadCompletionEvent, false, parent) {} - - bool processCompletionRoutine() Q_DECL_OVERRIDE { - DWORD numberOfBytesTransferred = 0; - if (!::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE)) - dptr->setError(dptr->decodeSystemError()); - - dptr->completeAsyncRead(numberOfBytesTransferred); - - // start async read for possible remainder into driver queue - if ((numberOfBytesTransferred > 0) && (dptr->policy == QSerialPort::IgnorePolicy)) { - dptr->startAsyncRead(); - } else { // driver queue is emplty, so startup wait comm event - CommOverlappedEventNotifier *n = - qobject_cast<CommOverlappedEventNotifier *>(dptr->lookupCommEventNotifier()); - if (n) - n->startWaitCommEvent(); - } - - return true; - } -}; - -class WriteOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier -{ - Q_OBJECT -public: - WriteOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) - : AbstractOverlappedEventNotifier(d, WriteCompletionEvent, false, parent) {} - - bool processCompletionRoutine() Q_DECL_OVERRIDE { - setEnabled(false); - DWORD numberOfBytesTransferred = 0; - if (!::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE)) { - numberOfBytesTransferred = 0; - dptr->setError(dptr->decodeSystemError()); - } - - dptr->completeAsyncWrite(numberOfBytesTransferred); - return true; - } -}; - -#include "qserialport_win.moc" + overlapped.Internal = 0; + overlapped.InternalHigh = 0; + overlapped.Offset = 0; + overlapped.OffsetHigh = 0; +} QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) : QSerialPortPrivateData(q) , descriptor(INVALID_HANDLE_VALUE) , parityErrorOccurred(false) - , actualReadBufferSize(0) + , readChunkBuffer(ReadChunkSize, 0) , actualWriteBufferSize(0) , acyncWritePosition(0) , readyReadEmitted(0) , writeSequenceStarted(false) + , communicationNotifier(new QWinEventNotifier(q)) + , readCompletionNotifier(new QWinEventNotifier(q)) + , writeCompletionNotifier(new QWinEventNotifier(q)) + , originalEventMask(0) + , triggeredEventMask(0) { + ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped)); + communicationOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + if (!communicationOverlapped.hEvent) + q->setError(decodeSystemError()); + else { + communicationNotifier->setHandle(communicationOverlapped.hEvent); + q->connect(communicationNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_canCompleteCommunication())); + } + + ::ZeroMemory(&readCompletionOverlapped, sizeof(readCompletionOverlapped)); + readCompletionOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + if (!readCompletionOverlapped.hEvent) + q->setError(decodeSystemError()); + else { + readCompletionNotifier->setHandle(readCompletionOverlapped.hEvent); + q->connect(readCompletionNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_canCompleteRead())); + } + + ::ZeroMemory(&writeCompletionOverlapped, sizeof(writeCompletionOverlapped)); + writeCompletionOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + if (!writeCompletionOverlapped.hEvent) + q->setError(decodeSystemError()); + else { + writeCompletionNotifier->setHandle(writeCompletionOverlapped.hEvent); + q->connect(writeCompletionNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_canCompleteWrite())); + } } bool QSerialPortPrivate::open(QIODevice::OpenMode mode) @@ -256,7 +144,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) Q_Q(QSerialPort); DWORD desiredAccess = 0; - DWORD originalEventMask = EV_ERR; + originalEventMask = EV_ERR; if (mode & QIODevice::ReadOnly) { desiredAccess |= GENERIC_READ; @@ -300,13 +188,27 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) if (!updateCommTimeouts()) return false; - if (originalEventMask & EV_RXCHAR) { - QWinEventNotifier *n = new ReadOverlappedCompletionNotifier(this, q); - n->setEnabled(true); + if (mode & QIODevice::ReadOnly) + readCompletionNotifier->setEnabled(true); + + if (mode & QIODevice::WriteOnly) + writeCompletionNotifier->setEnabled(true); + + if (!::SetCommMask(descriptor, originalEventMask)) { + q->setError(decodeSystemError()); + return false; + } + + initializeOverlappedStructure(communicationOverlapped); + if (!::WaitCommEvent(descriptor, &triggeredEventMask, &communicationOverlapped)) { + const QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + q->setError(decodeSystemError()); + return false; + } } - QWinEventNotifier *n = new CommOverlappedEventNotifier(this, originalEventMask, q); - n->setEnabled(true); + communicationNotifier->setEnabled(true); detectDefaultSettings(); return true; @@ -319,11 +221,11 @@ void QSerialPortPrivate::close() if (!::CancelIo(descriptor)) q->setError(decodeSystemError()); - qDeleteAll(notifiers); - notifiers.clear(); + readCompletionNotifier->setEnabled(false); + writeCompletionNotifier->setEnabled(false); + communicationNotifier->setEnabled(false); readBuffer.clear(); - actualReadBufferSize = 0; writeSequenceStarted = false; writeBuffer.clear(); @@ -356,7 +258,7 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() if (!::GetCommModemStatus(descriptor, &modemStat)) { q->setError(decodeSystemError()); - return QSerialPort::UnknownSignal; + return QSerialPort::NoSignal; } QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; @@ -405,10 +307,8 @@ bool QSerialPortPrivate::flush() bool QSerialPortPrivate::clear(QSerialPort::Directions directions) { DWORD flags = 0; - if (directions & QSerialPort::Input) { + if (directions & QSerialPort::Input) flags |= PURGE_RXABORT | PURGE_RXCLEAR; - actualReadBufferSize = 0; - } if (directions & QSerialPort::Output) { flags |= PURGE_TXABORT | PURGE_TXCLEAR; actualWriteBufferSize = 0; @@ -466,38 +366,6 @@ qint64 QSerialPortPrivate::systemOutputQueueSize () #ifndef Q_OS_WINCE -qint64 QSerialPortPrivate::bytesAvailable() const -{ - return actualReadBufferSize; -} - -qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) -{ - if (actualReadBufferSize == 0) - return 0; - - qint64 readSoFar = -1; - if (maxSize == 1 && actualReadBufferSize > 0) { - *data = readBuffer.getChar(); - actualReadBufferSize--; - readSoFar = 1; - } else { - const qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxSize); - readSoFar = 0; - while (readSoFar < bytesToRead) { - const char *ptr = readBuffer.readPointer(); - const int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, - qint64(readBuffer.nextDataBlockSize())); - ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); - readSoFar += bytesToReadFromThisBlock; - readBuffer.free(bytesToReadFromThisBlock); - actualReadBufferSize -= bytesToReadFromThisBlock; - } - } - - return readSoFar; -} - qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) { char *ptr = writeBuffer.reserve(maxSize); @@ -524,28 +392,28 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) do { bool timedOut = false; - AbstractOverlappedEventNotifier *n = 0; + HANDLE triggeredEvent = 0; - if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &triggeredEvent) || !triggeredEvent) { // This is occur timeout or another error if (!timedOut) q->setError(decodeSystemError()); return false; } - switch (n->type()) { - case AbstractOverlappedEventNotifier::CommEvent: - if (!n->processCompletionRoutine()) + if (triggeredEvent == communicationOverlapped.hEvent) { + _q_canCompleteCommunication(); + if (error != QSerialPort::NoError) return false; - break; - case AbstractOverlappedEventNotifier::ReadCompletionEvent: - return n->processCompletionRoutine(); - case AbstractOverlappedEventNotifier::WriteCompletionEvent: - n->processCompletionRoutine(); - break; - default: // newer called + } else if (triggeredEvent == readCompletionOverlapped.hEvent) { + _q_canCompleteRead(); + return error == QSerialPort::NoError; + } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { + _q_canCompleteWrite(); + } else { return false; } + } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); return false; @@ -563,25 +431,25 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) forever { bool timedOut = false; - AbstractOverlappedEventNotifier *n = 0; + HANDLE triggeredEvent = 0; - if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &triggeredEvent) || !triggeredEvent) { if (!timedOut) q->setError(decodeSystemError()); return false; } - switch (n->type()) { - case AbstractOverlappedEventNotifier::CommEvent: - // do nothing, jump to ReadCompletionEvent case - case AbstractOverlappedEventNotifier::ReadCompletionEvent: - n->processCompletionRoutine(); - break; - case AbstractOverlappedEventNotifier::WriteCompletionEvent: - return n->processCompletionRoutine(); - default: // newer called + if (triggeredEvent == communicationOverlapped.hEvent) { + _q_canCompleteRead(); + } else if (triggeredEvent == readCompletionOverlapped.hEvent) { + _q_canCompleteRead(); + } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { + _q_canCompleteWrite(); + return error == QSerialPort::NoError; + } else { return false; } + } return false; @@ -685,6 +553,75 @@ bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) #ifndef Q_OS_WINCE +void QSerialPortPrivate::_q_canCompleteCommunication() +{ + Q_Q(QSerialPort); + + DWORD numberOfBytesTransferred = 0; + + if (!::GetOverlappedResult(descriptor, &communicationOverlapped, &numberOfBytesTransferred, FALSE)) + q->setError(decodeSystemError()); + + 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) + error = true; + + // Workaround for standard CDC ACM serial ports, for which triggered an + // unexpected event EV_TXEMPTY at data transmission. + if ((originalEventMask & triggeredEventMask) == 0) { + if ((triggeredEventMask & EV_TXEMPTY) == 0) + error = true; + } + + // Start processing a caught error. + if (error || (EV_ERR & triggeredEventMask)) + processIoErrors(error); + + if (!error) + startAsyncRead(); +} + +void QSerialPortPrivate::_q_canCompleteRead() +{ + Q_Q(QSerialPort); + + DWORD numberOfBytesTransferred = 0; + if (!::GetOverlappedResult(descriptor, &readCompletionOverlapped, &numberOfBytesTransferred, FALSE)) + q->setError(decodeSystemError()); + + completeAsyncRead(numberOfBytesTransferred); + + // start async read for possible remainder into driver queue + if ((numberOfBytesTransferred > 0) && (policy == QSerialPort::IgnorePolicy)) { + startAsyncRead(); + } else { // driver queue is emplty, so startup wait comm event + initializeOverlappedStructure(communicationOverlapped); + if (!::WaitCommEvent(descriptor, &triggeredEventMask, &communicationOverlapped)) { + const QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + q->setError(decodeSystemError()); + } + } + } +} + +void QSerialPortPrivate::_q_canCompleteWrite() +{ + Q_Q(QSerialPort); + + DWORD numberOfBytesTransferred = 0; + if (!::GetOverlappedResult(descriptor, &writeCompletionOverlapped, &numberOfBytesTransferred, FALSE)) { + numberOfBytesTransferred = 0; + q->setError(decodeSystemError()); + } + + completeAsyncWrite(numberOfBytesTransferred); +} + bool QSerialPortPrivate::startAsyncRead() { Q_Q(QSerialPort); @@ -700,15 +637,8 @@ bool QSerialPortPrivate::startAsyncRead() } } - AbstractOverlappedEventNotifier *n = lookupReadCompletionNotifier(); - if (!n) { - q->setError(QSerialPort::ResourceError); - return false; - } - - char *ptr = readBuffer.reserve(bytesToRead); - - if (::ReadFile(descriptor, ptr, bytesToRead, NULL, n->overlappedPointer())) + initializeOverlappedStructure(readCompletionOverlapped); + if (::ReadFile(descriptor, readChunkBuffer.data(), bytesToRead, NULL, &readCompletionOverlapped)) return true; QSerialPort::SerialPortError error = decodeSystemError(); @@ -717,7 +647,6 @@ bool QSerialPortPrivate::startAsyncRead() error = QSerialPort::ReadError; q->setError(error); - readBuffer.truncate(actualReadBufferSize); return false; } @@ -740,15 +669,8 @@ bool QSerialPortPrivate::startAsyncWrite(int maxSize) writeSequenceStarted = true; - AbstractOverlappedEventNotifier *n = lookupFreeWriteCompletionNotifier(); - if (!n) { - q->setError(QSerialPort::ResourceError); - return false; - } - - n->setEnabled(true); - - if (::WriteFile(descriptor, ptr, nextSize, NULL, n->overlappedPointer())) + initializeOverlappedStructure(writeCompletionOverlapped); + if (::WriteFile(descriptor, ptr, nextSize, NULL, &writeCompletionOverlapped)) return true; QSerialPort::SerialPortError error = decodeSystemError(); @@ -800,11 +722,10 @@ void QSerialPortPrivate::completeAsyncRead(DWORD numberOfBytes) { Q_Q(QSerialPort); - actualReadBufferSize += qint64(numberOfBytes); - readBuffer.truncate(actualReadBufferSize); - if (numberOfBytes > 0) { + readBuffer.append(readChunkBuffer.left(numberOfBytes)); + // Process emulate policy. if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { @@ -854,39 +775,6 @@ void QSerialPortPrivate::completeAsyncWrite(DWORD numberOfBytes) startAsyncWrite(WriteChunkSize); } -AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupFreeWriteCompletionNotifier() -{ - Q_Q(QSerialPort); - - // find first free not running write notifier - foreach (AbstractOverlappedEventNotifier *n, notifiers) { - if ((n->type() == AbstractOverlappedEventNotifier::WriteCompletionEvent) - && !n->isEnabled()) { - return n; - } - } - // if all write notifiers in use, then create new write notifier - return new WriteOverlappedCompletionNotifier(this, q); -} - -AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupCommEventNotifier() -{ - foreach (AbstractOverlappedEventNotifier *n, notifiers) { - if (n->type() == AbstractOverlappedEventNotifier::CommEvent) - return n; - } - return 0; -} - -AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupReadCompletionNotifier() -{ - foreach (AbstractOverlappedEventNotifier *n, notifiers) { - if (n->type() == AbstractOverlappedEventNotifier::ReadCompletionEvent) - return n; - } - return 0; -} - bool QSerialPortPrivate::updateDcb() { Q_Q(QSerialPort); @@ -932,7 +820,8 @@ void QSerialPortPrivate::detectDefaultSettings() dataBits = QSerialPort::Data8; break; default: - dataBits = QSerialPort::UnknownDataBits; + qWarning("%s: Unexpected data bits settings", Q_FUNC_INFO); + dataBits = QSerialPort::Data8; break; } @@ -947,8 +836,10 @@ void QSerialPortPrivate::detectDefaultSettings() parity = QSerialPort::EvenParity; else if ((currentDcb.Parity == ODDPARITY) && currentDcb.fParity) parity = QSerialPort::OddParity; - else - parity = QSerialPort::UnknownParity; + else { + qWarning("%s: Unexpected parity settings", Q_FUNC_INFO); + parity = QSerialPort::NoParity; + } // Detect stopbits. switch (currentDcb.StopBits) { @@ -962,7 +853,8 @@ void QSerialPortPrivate::detectDefaultSettings() stopBits = QSerialPort::TwoStop; break; default: - stopBits = QSerialPort::UnknownStopBits; + qWarning("%s: Unexpected stop bits settings", Q_FUNC_INFO); + stopBits = QSerialPort::OneStop; break; } @@ -976,8 +868,10 @@ void QSerialPortPrivate::detectDefaultSettings() } else if (currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_HANDSHAKE) && !currentDcb.fInX && !currentDcb.fOutX) { flow = QSerialPort::HardwareControl; - } else - flow = QSerialPort::UnknownFlowControl; + } else { + qWarning("%s: Unexpected flow control settings", Q_FUNC_INFO); + flow = QSerialPort::NoFlowControl; + } } QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const @@ -1017,14 +911,17 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const #ifndef Q_OS_WINCE -bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut, - AbstractOverlappedEventNotifier **triggeredNotifier) +bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut, HANDLE *triggeredEvent) { Q_Q(QSerialPort); Q_ASSERT(timedOut); - QVector<HANDLE> handles = notifiers.keys().toVector(); + QVector<HANDLE> handles = QVector<HANDLE>() + << communicationOverlapped.hEvent + << readCompletionOverlapped.hEvent + << writeCompletionOverlapped.hEvent; + DWORD waitResult = ::WaitForMultipleObjects(handles.count(), handles.constData(), FALSE, // wait any event @@ -1038,8 +935,7 @@ bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut, if (waitResult >= DWORD(WAIT_OBJECT_0 + handles.count())) return false; - HANDLE h = handles.at(waitResult - WAIT_OBJECT_0); - *triggeredNotifier = notifiers.value(h); + *triggeredEvent = handles.at(waitResult - WAIT_OBJECT_0); return true; } @@ -1155,21 +1051,7 @@ qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) QList<qint32> QSerialPortPrivate::standardBaudRates() { - QList<qint32> ret; - const QList<qint32> baudRatePairs = standardBaudRatePairList(); - - foreach (qint32 baudRatePair, baudRatePairs) { - ret.append(baudRatePair); - } - - return ret; -} - -void QSerialPortPrivate::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString) -{ - Q_Q(QSerialPort); - - q->setError(serialPortError, errorString); + return standardBaudRatePairList(); } QSerialPort::Handle QSerialPort::handle() const diff --git a/src/serialport/qserialport_win_p.h b/src/serialport/qserialport_win_p.h index 414f026..059be87 100644 --- a/src/serialport/qserialport_win_p.h +++ b/src/serialport/qserialport_win_p.h @@ -57,10 +57,6 @@ QT_BEGIN_NAMESPACE class QThread; #endif -#ifndef Q_OS_WINCE -class AbstractOverlappedEventNotifier; -#endif - class QSerialPortPrivate : public QSerialPortPrivateData { Q_DECLARE_PUBLIC(QSerialPort) @@ -85,9 +81,6 @@ public: qint64 systemInputQueueSize (); qint64 systemOutputQueueSize (); - qint64 bytesAvailable() const; - - qint64 readFromBuffer(char *data, qint64 maxSize); qint64 writeToBuffer(const char *data, qint64 maxSize); bool waitForReadyRead(int msec); @@ -101,16 +94,16 @@ public: bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); void processIoErrors(bool error); - void setError(QSerialPort::SerialPortError error, const QString &errorString = QString()); QSerialPort::SerialPortError decodeSystemError() const; #ifndef Q_OS_WINCE + void _q_canCompleteCommunication(); + void _q_canCompleteRead(); + void _q_canCompleteWrite(); + bool startAsyncRead(); bool startAsyncWrite(int maxSize = INT_MAX); void completeAsyncRead(DWORD numberOfBytes); void completeAsyncWrite(DWORD numberOfBytes); - AbstractOverlappedEventNotifier *lookupFreeWriteCompletionNotifier(); - AbstractOverlappedEventNotifier *lookupCommEventNotifier(); - AbstractOverlappedEventNotifier *lookupReadCompletionNotifier(); #else bool notifyRead(); bool notifyWrite(int maxSize = INT_MAX); @@ -132,12 +125,19 @@ public: bool parityErrorOccurred; #ifndef Q_OS_WINCE - QHash<HANDLE, AbstractOverlappedEventNotifier *> notifiers; - qint64 actualReadBufferSize; + QByteArray readChunkBuffer; qint64 actualWriteBufferSize; qint64 acyncWritePosition; bool readyReadEmitted; bool writeSequenceStarted; + QWinEventNotifier *communicationNotifier; + QWinEventNotifier *readCompletionNotifier; + QWinEventNotifier *writeCompletionNotifier; + OVERLAPPED communicationOverlapped; + OVERLAPPED readCompletionOverlapped; + OVERLAPPED writeCompletionOverlapped; + DWORD originalEventMask; + DWORD triggeredEventMask; #else QThread *eventNotifier; QMutex settingsChangeMutex; @@ -150,8 +150,7 @@ private: void detectDefaultSettings(); #ifndef Q_OS_WINCE - bool waitAnyEvent(int msecs, bool *timedOut, - AbstractOverlappedEventNotifier **triggeredNotifier); + bool waitAnyEvent(int msecs, bool *timedOut, HANDLE *triggeredEvent); #else bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, bool checkRead, bool checkWrite, diff --git a/src/serialport/qserialport_wince.cpp b/src/serialport/qserialport_wince.cpp index 21bea1e..2983071 100644 --- a/src/serialport/qserialport_wince.cpp +++ b/src/serialport/qserialport_wince.cpp @@ -253,35 +253,6 @@ bool QSerialPortPrivate::clear(QSerialPort::Directions directions) return ::PurgeComm(descriptor, flags); } -qint64 QSerialPortPrivate::bytesAvailable() const -{ - return readBuffer.size(); -} - -qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) -{ - if (readBuffer.isEmpty()) - return 0; - - if (maxSize == 1) { - *data = readBuffer.getChar(); - return 1; - } - - const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); - qint64 readSoFar = 0; - while (readSoFar < bytesToRead) { - const char *ptr = readBuffer.readPointer(); - const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), - readBuffer.nextDataBlockSize()); - ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); - readSoFar += bytesToReadFromThisBlock; - readBuffer.free(bytesToReadFromThisBlock); - } - - return readSoFar; -} - qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) { char *ptr = writeBuffer.reserve(maxSize); diff --git a/src/serialport/qserialportglobal.h b/src/serialport/qserialportglobal.h index 09ba0df..d17ce6b 100644 --- a/src/serialport/qserialportglobal.h +++ b/src/serialport/qserialportglobal.h @@ -59,6 +59,10 @@ QT_BEGIN_NAMESPACE #endif // These macros have been available only since Qt 5.0 +#ifndef QT_DEPRECATED_SINCE +#define QT_DEPRECATED_SINCE(major, minor) 1 +#endif + #ifndef Q_DECL_OVERRIDE #define Q_DECL_OVERRIDE #endif diff --git a/src/serialport/qserialportinfo.cpp b/src/serialport/qserialportinfo.cpp index 78ef694..5172e60 100644 --- a/src/serialport/qserialportinfo.cpp +++ b/src/serialport/qserialportinfo.cpp @@ -258,6 +258,7 @@ bool QSerialPortInfo::hasProductIdentifier() const /*! \fn bool QSerialPortInfo::isValid() const + \obsolete Returns true if serial port is present on system; otherwise returns false. diff --git a/src/serialport/qserialportinfo.h b/src/serialport/qserialportinfo.h index 51f3b10..8320fc5 100644 --- a/src/serialport/qserialportinfo.h +++ b/src/serialport/qserialportinfo.h @@ -80,12 +80,17 @@ public: bool isNull() const; bool isBusy() const; - bool isValid() const; +#if QT_DEPRECATED_SINCE(5, 2) + QT_DEPRECATED bool isValid() const; +#endif static QList<qint32> standardBaudRates(); static QList<QSerialPortInfo> availablePorts(); private: + friend QList<QSerialPortInfo> availablePortsByUdev(); + friend QList<QSerialPortInfo> availablePortsBySysfs(); + friend QList<QSerialPortInfo> availablePortsByFiltersOfDevices(); QScopedPointer<QSerialPortInfoPrivate, QSerialPortInfoPrivateDeleter> d_ptr; }; diff --git a/src/serialport/qserialportinfo_mac.cpp b/src/serialport/qserialportinfo_mac.cpp index af57598..c69a4a3 100644 --- a/src/serialport/qserialportinfo_mac.cpp +++ b/src/serialport/qserialportinfo_mac.cpp @@ -97,7 +97,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() io_registry_entry_t entry = service; - // Find MacOSX-specific properties names. do { if (!device) { @@ -184,7 +183,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() } - // If all matching properties is found, then force break loop. if (matchingPropertiesCounter == propertyCount) break; @@ -194,7 +192,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() (void) ::IOObjectRelease(entry); - // Convert from MacOSX-specific properties to Qt4-specific. if (matchingPropertiesCounter > 0) { QSerialPortInfo serialPortInfo; diff --git a/src/serialport/qserialportinfo_symbian.cpp b/src/serialport/qserialportinfo_symbian.cpp index 5512048..cae00e9 100644 --- a/src/serialport/qserialportinfo_symbian.cpp +++ b/src/serialport/qserialportinfo_symbian.cpp @@ -46,7 +46,6 @@ #include "qserialport_symbian_p.h" #include <e32base.h> -//#include <e32test.h> #include <c32comm.h> #include <f32file.h> @@ -54,23 +53,19 @@ QT_BEGIN_NAMESPACE -// Physical device driver. #ifdef __WINS__ _LIT(KPddName, "ECDRV"); -#else // defined (__EPOC32__) +#else _LIT(KPddName, "EUART"); #endif -// Logical native device driver. _LIT(KLddName,"ECOMM"); -// Modules names. _LIT(KRS232ModuleName , "ECUART"); _LIT(KBluetoothModuleName , "BTCOMM"); _LIT(KInfraRedModuleName , "IRCOMM"); _LIT(KACMModuleName, "ECACM"); -// Return false on error load. static bool loadDevices() { TInt r = KErrNone; @@ -84,16 +79,16 @@ static bool loadDevices() r = User::LoadPhysicalDevice(KPddName); if (r != KErrNone && r != KErrAlreadyExists) - return false; //User::Leave(r); + return false; r = User::LoadLogicalDevice(KLddName); if (r != KErrNone && r != KErrAlreadyExists) - return false; //User::Leave(r); + return false; #ifndef __WINS__ r = StartC32(); if (r != KErrNone && r != KErrAlreadyExists) - return false; //User::Leave(r); + return false; #endif return true; @@ -109,14 +104,13 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() RCommServ server; TInt r = server.Connect(); if (r != KErrNone) - return serialPortInfoList; //User::LeaveIfError(r); + return serialPortInfoList; - TSerialInfo nativeSerialInfo; // Native Symbian OS port info class. + TSerialInfo nativeSerialInfo; QString s("%1::%2"); // FIXME: Get info about RS232 ports. r = server.LoadCommModule(KRS232ModuleName); - //User::LeaveIfError(r); if (r == KErrNone) { r = server.GetPortInfo(KRS232ModuleName, nativeSerialInfo); if (r == KErrNone) { @@ -138,7 +132,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() // FIXME: Get info about Bluetooth ports. r = server.LoadCommModule(KBluetoothModuleName); - //User::LeaveIfError(r); if (r == KErrNone) { r = server.GetPortInfo(KBluetoothModuleName, nativeSerialInfo); if (r == KErrNone) { @@ -160,7 +153,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() // FIXME: Get info about InfraRed ports. r = server.LoadCommModule(KInfraRedModuleName); - //User::LeaveIfError(r); if (r == KErrNone) { r = server.GetPortInfo(KInfraRedModuleName, nativeSerialInfo); if (r == KErrNone) { @@ -182,7 +174,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() // FIXME: Get info about ACM ports. r = server.LoadCommModule(KACMModuleName); - //User::LeaveIfError(r); if (r == KErrNone) { r = server.GetPortInfo(KACMModuleName, nativeSerialInfo); if (r == KErrNone) { diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp index 9b3bf94..4433a4e 100644 --- a/src/serialport/qserialportinfo_unix.cpp +++ b/src/serialport/qserialportinfo_unix.cpp @@ -47,29 +47,23 @@ #include <QtCore/qlockfile.h> #include <QtCore/qfile.h> +#include <QtCore/qdir.h> #ifndef Q_OS_MAC -#if defined(LINK_LIBUDEV) || defined(LOAD_LIBUDEV) #include "qtudev_p.h" -#else -#include <QtCore/qdir.h> -#include <QtCore/qstringlist.h> -#endif -#endif // Q_OS_MAC +#endif QT_BEGIN_NAMESPACE #ifndef Q_OS_MAC -#if !defined(LINK_LIBUDEV) && !defined(LOAD_LIBUDEV) - -static inline const QStringList& filtersOfDevices() +static QStringList filteredDeviceFilePaths() { static const QStringList deviceFileNameFilterList = QStringList() -# ifdef Q_OS_LINUX +#ifdef Q_OS_LINUX << QStringLiteral("ttyS*") // Standard UART 8250 and etc. << QStringLiteral("ttyO*") // OMAP UART 8250 and etc. << QStringLiteral("ttyUSB*") // Usb/serial converters PL2303 and etc. @@ -80,22 +74,17 @@ static inline const QStringList& filtersOfDevices() << QStringLiteral("ttyAMA*") // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi). << QStringLiteral("rfcomm*") // Bluetooth serial device. << QStringLiteral("ircomm*"); // IrDA serial device. -# elif defined (Q_OS_FREEBSD) +#elif defined (Q_OS_FREEBSD) << QStringLiteral("cu*"); -# else - ; // Here for other *nix OS. -# endif - - return deviceFileNameFilterList; -} +#else + ; +#endif -static QStringList filteredDeviceFilePaths() -{ QStringList result; QDir deviceDir(QStringLiteral("/dev")); if (deviceDir.exists()) { - deviceDir.setNameFilters(filtersOfDevices()); + deviceDir.setNameFilters(deviceFileNameFilterList); deviceDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks); QStringList deviceFilePaths; foreach (const QFileInfo &deviceFileInfo, deviceDir.entryInfoList()) { @@ -110,13 +99,23 @@ static QStringList filteredDeviceFilePaths() return result; } -QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +QList<QSerialPortInfo> availablePortsByFiltersOfDevices() { QList<QSerialPortInfo> serialPortInfoList; -#ifndef Q_OS_LINUX - static const bool sysfsEnabled = false; -#else + foreach (const QString &deviceFilePath, filteredDeviceFilePaths()) { + QSerialPortInfo serialPortInfo; + serialPortInfo.d_ptr->device = deviceFilePath; + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath); + serialPortInfoList.append(serialPortInfo); + } + + return serialPortInfoList; +} + +QList<QSerialPortInfo> availablePortsBySysfs() +{ + QList<QSerialPortInfo> serialPortInfoList; QDir ttySysClassDir(QStringLiteral("/sys/class/tty")); const bool sysfsEnabled = ttySysClassDir.exists() && ttySysClassDir.isReadable(); @@ -131,16 +130,12 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() if (lastIndexOfSlash == -1) continue; - bool canAppendToList = true; QSerialPortInfo serialPortInfo; if (targetPath.contains(QStringLiteral("pnp"))) { - // TODO: Implement me. + // TODO: Obtain more information } else if (targetPath.contains(QStringLiteral("platform"))) { - // Platform 'pseudo' bus for legacy device. - // Skip this devices because this type of subsystem does - // not include a real physical serial device. - canAppendToList = false; + continue; } else if (targetPath.contains(QStringLiteral("usb"))) { QDir targetDir(targetPath); @@ -185,26 +180,14 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() } } while (targetDir.cdUp()); + } else if (targetPath.contains(QStringLiteral("pci"))) { + // TODO: Obtain more information about the device } else { - // unknown types of devices - canAppendToList = false; - } - - if (canAppendToList) { - serialPortInfo.d_ptr->portName = targetPath.mid(lastIndexOfSlash + 1); - serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.d_ptr->portName); - serialPortInfoList.append(serialPortInfo); + continue; } - } - } -#endif - - if (!sysfsEnabled) { - foreach (const QString &deviceFilePath, filteredDeviceFilePaths()) { - QSerialPortInfo serialPortInfo; - serialPortInfo.d_ptr->device = deviceFilePath; - serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath); + serialPortInfo.d_ptr->portName = targetPath.mid(lastIndexOfSlash + 1); + serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.d_ptr->portName); serialPortInfoList.append(serialPortInfo); } } @@ -212,18 +195,15 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() return serialPortInfoList; } -#else - -QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +QList<QSerialPortInfo> availablePortsByUdev() { -#ifdef LOAD_LIBUDEV +#ifndef LINK_LIBUDEV static bool symbolsResolved = resolveSymbols(); if (!symbolsResolved) return QList<QSerialPortInfo>(); #endif QList<QSerialPortInfo> serialPortInfoList; - // White list for devices without a parent static const QString rfcommDeviceName(QStringLiteral("rfcomm")); struct ::udev *udev = ::udev_new(); @@ -256,15 +236,12 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() struct ::udev_device *parentdev = ::udev_device_get_parent(dev); - bool canAppendToList = true; - if (parentdev) { QString subsys = QString::fromLatin1(::udev_device_get_subsystem(parentdev)); if (subsys == QStringLiteral("usb-serial") - || subsys == QStringLiteral("usb")) { // USB bus type - // Append this devices and try get additional information about them. + || subsys == QStringLiteral("usb")) { serialPortInfo.d_ptr->description = QString::fromLatin1(::udev_device_get_property_value(dev, "ID_MODEL")).replace(QLatin1Char('_'), QLatin1Char(' ')); serialPortInfo.d_ptr->manufacturer = QString::fromLatin1(::udev_device_get_property_value(dev, @@ -278,39 +255,28 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() QString::fromLatin1(::udev_device_get_property_value(dev, "ID_MODEL_ID")).toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); - } else if (subsys == QStringLiteral("pnp")) { // PNP bus type - // Append this device. - // FIXME: How to get additional information about serial devices - // with this subsystem? - } else if (subsys == QStringLiteral("platform")) { // Platform 'pseudo' bus for legacy device. - // Skip this devices because this type of subsystem does - // not include a real physical serial device. - canAppendToList = false; - } else { // Others types of subsystems. - // Append this devices because we believe that any other types of - // subsystems provide a real serial devices. For example, for devices - // such as ttyGSx, its driver provide an empty subsystem name, but it - // devices is a real physical serial devices. - // FIXME: How to get additional information about serial devices - // with this subsystems? + } else if (subsys == QStringLiteral("pnp")) { + // TODO: Obtain more information + } else if (subsys == QStringLiteral("platform")) { + continue; + } else if (subsys == QStringLiteral("pci")) { + // TODO: Obtain more information about the device + } else { + // FIXME: Obtain more information } - } else { // Devices without a parent - if (serialPortInfo.d_ptr->portName.startsWith(rfcommDeviceName)) { // Bluetooth device + } else { + if (serialPortInfo.d_ptr->portName.startsWith(rfcommDeviceName)) { bool ok; - // Check for an unsigned decimal integer at the end of the device name: "rfcomm0", "rfcomm15" - // devices with negative and invalid numbers in the name are rejected int portNumber = serialPortInfo.d_ptr->portName.mid(rfcommDeviceName.length()).toInt(&ok); - if (!ok || (portNumber < 0) || (portNumber > 255)) { - canAppendToList = false; - } + if (!ok || (portNumber < 0) || (portNumber > 255)) + continue; } else { - canAppendToList = false; + continue; } } - if (canAppendToList) - serialPortInfoList.append(serialPortInfo); + serialPortInfoList.append(serialPortInfo); ::udev_device_unref(dev); } @@ -326,11 +292,29 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() return serialPortInfoList; } +QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +{ + QList<QSerialPortInfo> serialPortInfoList; + // TODO: Remove this condition once the udev runtime symbol resolution crash + // is fixed for Qt 4. +#if defined(LINK_LIBUDEV) || (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + serialPortInfoList = availablePortsByUdev(); #endif -#endif // Q_OS_MAC +#ifdef Q_OS_LINUX + if (serialPortInfoList.isEmpty()) + serialPortInfoList = availablePortsBySysfs(); + else + return serialPortInfoList; +#endif -// common part + if (serialPortInfoList.isEmpty()) + serialPortInfoList = availablePortsByFiltersOfDevices(); + + return serialPortInfoList; +} + +#endif QList<qint32> QSerialPortInfo::standardBaudRates() { diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index 7eec46a..51f529e 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -52,24 +52,28 @@ #include <QtCore/qvariant.h> #include <QtCore/qstringlist.h> +#include <QtCore/quuid.h> +#include <QtCore/qpair.h> QT_BEGIN_NAMESPACE #ifndef Q_OS_WINCE -static const GUID guidsArray[] = +typedef QPair<QUuid, DWORD> GuidFlagsPair; + +static inline const QList<GuidFlagsPair>& guidFlagsPairs() { - // Windows Ports Class GUID - { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, - // Virtual Ports Class GUID (i.e. com0com and etc) - { 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } }, - // Windows Modems Class GUID - { 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, - // Eltima Virtual Serial Port Driver v4 GUID - { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } }, - // Advanced Virtual COM Port GUID - { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } }, -}; + static const QList<GuidFlagsPair> guidFlagsPairList = QList<GuidFlagsPair>() + // Standard Setup Ports Class GUID + << qMakePair(QUuid(0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18), DWORD(DIGCF_PRESENT)) + // Standard Setup Modems Class GUID + << qMakePair(QUuid(0x4D36E96D, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18), DWORD(DIGCF_PRESENT)) + // Standard Serial Port Device Interface Class GUID + << qMakePair(QUuid(0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73), DWORD(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)) + // Standard Modem Device Interface Class GUID + << qMakePair(QUuid(0x2C7089AA, 0x2E0E, 0x11D1, 0xB1, 0x14, 0x00, 0xC0, 0x4F, 0xC2, 0xAA, 0xE4), DWORD(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + return guidFlagsPairList; +} static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, @@ -157,6 +161,23 @@ static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInf return QString::fromWCharArray(((const wchar_t *)data.constData())); } +class SerialPortNameEqualFunctor +{ +public: + explicit SerialPortNameEqualFunctor(const QString &serialPortName) + : m_serialPortName(serialPortName) + { + } + + bool operator() (const QSerialPortInfo &serialPortInfo) const + { + return serialPortInfo.portName() == m_serialPortName; + } + +private: + const QString &m_serialPortName; +}; + QList<QSerialPortInfo> QSerialPortInfo::availablePorts() { static const QString usbVendorIdentifierPrefix(QStringLiteral("VID_")); @@ -168,10 +189,9 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() static const int productIdentifierSize = 4; QList<QSerialPortInfo> serialPortInfoList; - static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]); - for (int i = 0; i < guidCount; ++i) { - const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT); + foreach (const GuidFlagsPair &uniquePair, guidFlagsPairs()) { + const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(reinterpret_cast<const GUID *>(&uniquePair.first), NULL, 0, uniquePair.second); if (deviceInfoSet == INVALID_HANDLE_VALUE) return serialPortInfoList; @@ -187,6 +207,11 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() if (s.isEmpty() || s.contains(QStringLiteral("LPT"))) continue; + if (std::find_if(serialPortInfoList.begin(), serialPortInfoList.end(), + SerialPortNameEqualFunctor(s)) != serialPortInfoList.end()) { + continue; + } + serialPortInfo.d_ptr->portName = s; serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s); serialPortInfo.d_ptr->description = @@ -227,8 +252,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() #endif -// common part - QList<qint32> QSerialPortInfo::standardBaudRates() { return QSerialPortPrivate::standardBaudRates(); diff --git a/src/serialport/qserialportinfo_wince.cpp b/src/serialport/qserialportinfo_wince.cpp index 0d0fd0d..27ecb28 100644 --- a/src/serialport/qserialportinfo_wince.cpp +++ b/src/serialport/qserialportinfo_wince.cpp @@ -119,9 +119,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() serialPortInfo.d_ptr->description = findDescription(HKEY_LOCAL_MACHINE, QString::fromWCharArray(di.szDeviceKey)); - // Get manufacturer, vendor identifier, product identifier are not - // possible. - serialPortInfoList.append(serialPortInfo); } while (::FindNextDevice(hSearch, &di)); diff --git a/src/serialport/qtudev_p.h b/src/serialport/qtudev_p.h index 457c3f0..1187165 100644 --- a/src/serialport/qtudev_p.h +++ b/src/serialport/qtudev_p.h @@ -47,7 +47,7 @@ extern "C" { #include <libudev.h> } -#elif defined(LOAD_LIBUDEV) +#else #include <QtCore/qlibrary.h> #include <QtCore/qstring.h> #include <QtCore/qdebug.h> diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri index 7ad55f8..4c7e732 100644 --- a/src/serialport/serialport-lib.pri +++ b/src/serialport/serialport-lib.pri @@ -1,6 +1,6 @@ INCLUDEPATH += $$PWD -!contains(DEFINES, LOAD_LIBUDEV): unix { +unix { greaterThan(QT_MAJOR_VERSION, 4) { contains(QT_CONFIG, libudev) { DEFINES += LINK_LIBUDEV |