diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-07-10 10:16:01 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-07-10 10:16:01 +0200 |
commit | aa22914a0a796c912a500ab1854801c6b7ebdd8e (patch) | |
tree | bb1e0ff23c8b9a92129417fe83eac26758f47113 | |
parent | 4f1ab4d73b25e983991e310206237fd9b6474130 (diff) | |
parent | c3460993440172f0f29fe2bc290c0b2f10d3de5a (diff) | |
download | qtserialport-aa22914a0a796c912a500ab1854801c6b7ebdd8e.tar.gz |
Merge remote-tracking branch 'origin/5.3' into dev
Change-Id: I64b13e135d58980ea4cf7429224aa1877778cb46
-rw-r--r-- | src/serialport/qserialport.h | 6 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 11 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 133 | ||||
-rw-r--r-- | src/serialport/qserialport_win_p.h | 8 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_mac.cpp | 337 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_unix.cpp | 8 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 152 | ||||
-rw-r--r-- | src/serialport/qt4support/include/private/qcore_mac_p.h | 148 | ||||
-rw-r--r-- | src/serialport/serialport-lib.pri | 11 | ||||
-rw-r--r-- | tests/manual/qserialportinfo/tst_qserialportinfo.cpp | 21 |
10 files changed, 497 insertions, 338 deletions
diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index ae5eaf3..45b9bbf 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -282,9 +282,9 @@ private: Q_DISABLE_COPY(QSerialPort) #if defined (Q_OS_WIN32) || defined(Q_OS_WIN64) - Q_PRIVATE_SLOT(d_func(), void _q_completeAsyncCommunication()) - Q_PRIVATE_SLOT(d_func(), void _q_completeAsyncRead()) - Q_PRIVATE_SLOT(d_func(), void _q_completeAsyncWrite()) + Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncCommunication()) + Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncRead()) + Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncWrite()) #endif }; diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 70c160b..29822d5 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -435,14 +435,11 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) return false; } - if (readyToRead) { - if (readNotification()) - return true; - } - - if (readyToWrite) - completeAsyncWrite(); + if (readyToRead) + return readNotification(); + if (readyToWrite && !completeAsyncWrite()) + return false; } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); return false; } diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 111a8ce..3432fc9 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -400,9 +400,11 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) } if (triggeredEvent == communicationOverlapped.hEvent) { - _q_completeAsyncCommunication(); + if (!_q_completeAsyncCommunication()) + return false; } else if (triggeredEvent == readCompletionOverlapped.hEvent) { - _q_completeAsyncRead(); + if (!_q_completeAsyncRead()) + return false; const qint64 readBytesForOneReadOperation = qint64(readBuffer.size()) - currentReadBufferSize; if (readBytesForOneReadOperation == ReadChunkSize) { currentReadBufferSize = readBuffer.size(); @@ -413,7 +415,8 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) return true; } } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { - _q_completeAsyncWrite(); + if (!_q_completeAsyncWrite()) + return false; } else { return false; } @@ -433,8 +436,8 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) QElapsedTimer stopWatch; stopWatch.start(); - if (!writeStarted) - startAsyncWrite(); + if (!writeStarted && !startAsyncWrite()) + return false; forever { bool timedOut = false; @@ -446,13 +449,12 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) return false; } - if (triggeredEvent == communicationOverlapped.hEvent) { - _q_completeAsyncRead(); - } else if (triggeredEvent == readCompletionOverlapped.hEvent) { - _q_completeAsyncRead(); + if (triggeredEvent == communicationOverlapped.hEvent + || triggeredEvent == readCompletionOverlapped.hEvent) { + if (!_q_completeAsyncRead()) + return false; } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { - _q_completeAsyncWrite(); - return writeBuffer.isEmpty(); + return _q_completeAsyncWrite(); } else { return false; } @@ -561,83 +563,50 @@ bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) return true; } -void QSerialPortPrivate::_q_completeAsyncCommunication() +bool QSerialPortPrivate::_q_completeAsyncCommunication() { - Q_Q(QSerialPort); - - DWORD numberOfBytesTransferred = 0; - - if (!::GetOverlappedResult(handle, &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; - } - - if (error) - q->setError(QSerialPort::ResourceError); - + if (handleOverlappedResult(0, communicationOverlapped) == qint64(-1)) + return false; if (EV_ERR & triggeredEventMask) handleLineStatusErrors(); - if (!error) - startAsyncRead(); + return startAsyncRead(); } -void QSerialPortPrivate::_q_completeAsyncRead() +bool QSerialPortPrivate::_q_completeAsyncRead() { - Q_Q(QSerialPort); - - DWORD numberOfBytesTransferred = 0; - if (!::GetOverlappedResult(handle, &readCompletionOverlapped, &numberOfBytesTransferred, FALSE)) - q->setError(decodeSystemError()); - - if (numberOfBytesTransferred > 0) { - - readBuffer.append(readChunkBuffer.left(numberOfBytesTransferred)); - + const qint64 bytesTransferred = handleOverlappedResult(QSerialPort::Input, readCompletionOverlapped); + if (bytesTransferred == qint64(-1)) + return false; + if (bytesTransferred > 0) { + readBuffer.append(readChunkBuffer.left(bytesTransferred)); if (!emulateErrorPolicy()) emitReadyRead(); } // start async read for possible remainder into driver queue - if ((numberOfBytesTransferred == ReadChunkSize) && (policy == QSerialPort::IgnorePolicy)) - startAsyncRead(); + if ((bytesTransferred == ReadChunkSize) && (policy == QSerialPort::IgnorePolicy)) + return startAsyncRead(); else // driver queue is emplty, so startup wait comm event - startAsyncCommunication(); + return startAsyncCommunication(); } -void QSerialPortPrivate::_q_completeAsyncWrite() +bool QSerialPortPrivate::_q_completeAsyncWrite() { Q_Q(QSerialPort); if (writeStarted) { writeStarted = false; - DWORD numberOfBytesTransferred = 0; - if (!::GetOverlappedResult(handle, &writeCompletionOverlapped, &numberOfBytesTransferred, FALSE)) { - numberOfBytesTransferred = 0; - q->setError(decodeSystemError()); - return; - } - - if (numberOfBytesTransferred > 0) { - writeBuffer.free(numberOfBytesTransferred); - emit q->bytesWritten(numberOfBytesTransferred); + const qint64 bytesTransferred = handleOverlappedResult(QSerialPort::Output, writeCompletionOverlapped); + if (bytesTransferred == qint64(-1)) + return false; + if (bytesTransferred > 0) { + writeBuffer.free(bytesTransferred); + emit q->bytesWritten(bytesTransferred); } } - startAsyncWrite(); + return startAsyncWrite(); } bool QSerialPortPrivate::startAsyncCommunication() @@ -646,9 +615,11 @@ bool QSerialPortPrivate::startAsyncCommunication() initializeOverlappedStructure(communicationOverlapped); if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) { - const QSerialPort::SerialPortError error = decodeSystemError(); + QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { - q->setError(decodeSystemError()); + if (error == QSerialPort::PermissionError) + error = QSerialPort::ResourceError; + q->setError(error); return false; } } @@ -676,10 +647,11 @@ bool QSerialPortPrivate::startAsyncRead() QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { + if (error == QSerialPort::PermissionError) + error = QSerialPort::ResourceError; if (error != QSerialPort::ResourceError) error = QSerialPort::ReadError; q->setError(error); - return false; } @@ -791,6 +763,28 @@ bool QSerialPortPrivate::updateCommTimeouts() return true; } +qint64 QSerialPortPrivate::handleOverlappedResult(int direction, OVERLAPPED &overlapped) +{ + Q_Q(QSerialPort); + + DWORD bytesTransferred = 0; + if (!::GetOverlappedResult(handle, &overlapped, &bytesTransferred, FALSE)) { + const QSerialPort::SerialPortError error = decodeSystemError(); + if (error == QSerialPort::NoError) + return qint64(0); + if (error != QSerialPort::ResourceError) { + if (direction == QSerialPort::Input) + q->setError(QSerialPort::ReadError); + else if (direction == QSerialPort::Output) + q->setError(QSerialPort::WriteError); + else + q->setError(error); + return qint64(-1); + } + } + return bytesTransferred; +} + QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const { QSerialPort::SerialPortError error; @@ -822,6 +816,9 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const case ERROR_DEVICE_REMOVED: error = QSerialPort::ResourceError; break; + case ERROR_OPERATION_ABORTED: + 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 4e66685..daf5788 100644 --- a/src/serialport/qserialport_win_p.h +++ b/src/serialport/qserialport_win_p.h @@ -91,9 +91,9 @@ public: void handleLineStatusErrors(); QSerialPort::SerialPortError decodeSystemError() const; - void _q_completeAsyncCommunication(); - void _q_completeAsyncRead(); - void _q_completeAsyncWrite(); + bool _q_completeAsyncCommunication(); + bool _q_completeAsyncRead(); + bool _q_completeAsyncWrite(); bool startAsyncCommunication(); bool startAsyncRead(); @@ -132,7 +132,7 @@ public: private: bool updateDcb(); bool updateCommTimeouts(); - + qint64 handleOverlappedResult(int direction, OVERLAPPED &overlapped); bool waitAnyEvent(int msecs, bool *timedOut, HANDLE *triggeredEvent); diff --git a/src/serialport/qserialportinfo_mac.cpp b/src/serialport/qserialportinfo_mac.cpp index 2c2564e..03f95e7 100644 --- a/src/serialport/qserialportinfo_mac.cpp +++ b/src/serialport/qserialportinfo_mac.cpp @@ -43,6 +43,9 @@ #include "qserialportinfo.h" #include "qserialportinfo_p.h" +#include "qserialport_unix_p.h" + +#include "private/qcore_mac_p.h" #include <sys/param.h> @@ -59,235 +62,193 @@ QT_BEGIN_NAMESPACE -QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +static QCFType<CFTypeRef> searchProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey) { - QList<QSerialPortInfo> serialPortInfoList; - - static const int propertyCount = 7; + return ::IORegistryEntrySearchCFProperty( + ioRegistryEntry, kIOServicePlane, propertyKey, kCFAllocatorDefault, 0); +} +static QString searchStringProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey) +{ + const QCFString result(searchProperty(ioRegistryEntry, propertyKey).as<CFStringRef>()); + return QCFString::toQString(result); +} - ::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue); - if (!matching) - return serialPortInfoList; +static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey, + bool &ok) +{ + const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey)); + quint16 value = 0; + ok = result.as<CFNumberRef>() + && (::CFNumberGetValue(result.as<CFNumberRef>(), kCFNumberShortType, &value) > 0); + return value; +} - ::CFDictionaryAddValue(matching, - CFSTR(kIOSerialBSDTypeKey), - CFSTR(kIOSerialBSDAllTypes)); +static bool isCompleteInfo(const QSerialPortInfo &portInfo) +{ + return !portInfo.portName().isEmpty() + && !portInfo.systemLocation().isEmpty() + && !portInfo.manufacturer().isEmpty() + && !portInfo.description().isEmpty() + && !portInfo.serialNumber().isEmpty() + && portInfo.hasProductIdentifier() + && portInfo.hasVendorIdentifier(); +} - io_iterator_t iter = 0; - kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault, - matching, - &iter); +static QString devicePortName(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kIOTTYDeviceKey)); +} - if (kr != kIOReturnSuccess) - return serialPortInfoList; +static QString deviceSystemLocation(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kIOCalloutDeviceKey)); +} - io_registry_entry_t service; +static QString deviceDescription(io_registry_entry_t ioRegistryEntry) +{ + QString result = searchStringProperty(ioRegistryEntry, QCFString(kIOPropertyProductNameKey)); + if (result.isEmpty()) + result = searchStringProperty(ioRegistryEntry, QCFString(kUSBProductString)); + if (result.isEmpty()) + result = searchStringProperty(ioRegistryEntry, QCFString("BTName")); + return result; +} - while ((service = ::IOIteratorNext(iter))) { +static QString deviceManufacturer(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kUSBVendorString)); +} - ::CFTypeRef device = 0; - ::CFTypeRef portName = 0; - ::CFTypeRef description = 0; - ::CFTypeRef manufacturer = 0; - ::CFTypeRef serialNumber = 0; - ::CFTypeRef vendorIdentifier = 0; - ::CFTypeRef productIdentifier = 0; +static QString deviceSerialNumber(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kUSBSerialNumberString)); +} - int matchingPropertiesCounter = 0; +static quint16 deviceVendorIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok) +{ + return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBVendorID), ok); +} - io_registry_entry_t entry = service; +static quint16 deviceProductIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok) +{ + return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBProductID), ok); +} - do { +static io_registry_entry_t parentSerialPortService(io_registry_entry_t currentSerialPortService) +{ + io_registry_entry_t result = 0; + ::IORegistryEntryGetParentEntry(currentSerialPortService, kIOServicePlane, &result); + ::IOObjectRelease(currentSerialPortService); + return result; +} - if (!device) { - device = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOCalloutDeviceKey), - kCFAllocatorDefault, - 0); - if (device) - ++matchingPropertiesCounter; - } +QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +{ + CFMutableDictionaryRef serialPortDictionary = ::IOServiceMatching(kIOSerialBSDServiceValue); + if (!serialPortDictionary) + return QList<QSerialPortInfo>(); - if (!portName) { - portName = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOTTYDeviceKey), - kCFAllocatorDefault, - 0); - if (portName) - ++matchingPropertiesCounter; - } + ::CFDictionaryAddValue(serialPortDictionary, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); - if (!description) { - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOPropertyProductNameKey), - kCFAllocatorDefault, - 0); - if (!description) - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBProductString), - kCFAllocatorDefault, - 0); - if (!description) - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR("BTName"), - kCFAllocatorDefault, - 0); - - if (description) - ++matchingPropertiesCounter; - } + io_iterator_t serialPortIterator = 0; + if (::IOServiceGetMatchingServices(kIOMasterPortDefault, serialPortDictionary, + &serialPortIterator) != KERN_SUCCESS) { + return QList<QSerialPortInfo>(); + } - if (!manufacturer) { - manufacturer = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBVendorString), - kCFAllocatorDefault, - 0); - if (manufacturer) - ++matchingPropertiesCounter; + QList<QSerialPortInfo> serialPortInfoList; - } + forever { + io_registry_entry_t serialPortService = ::IOIteratorNext(serialPortIterator); + if (!serialPortService) + break; - if (!serialNumber) { - serialNumber = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBSerialNumberString), - kCFAllocatorDefault, - 0); - if (serialNumber) - ++matchingPropertiesCounter; + QSerialPortInfo serialPortInfo; - } + forever { + if (serialPortInfo.portName().isEmpty()) + serialPortInfo.d_ptr->portName = devicePortName(serialPortService); + if (serialPortInfo.systemLocation().isEmpty()) + serialPortInfo.d_ptr->device = deviceSystemLocation(serialPortService); - if (!vendorIdentifier) { - vendorIdentifier = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBVendorID), - kCFAllocatorDefault, - 0); - if (vendorIdentifier) - ++matchingPropertiesCounter; + if (serialPortInfo.description().isEmpty()) + serialPortInfo.d_ptr->description = deviceDescription(serialPortService); - } + if (serialPortInfo.manufacturer().isEmpty()) + serialPortInfo.d_ptr->manufacturer = deviceManufacturer(serialPortService); - if (!productIdentifier) { - productIdentifier = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBProductID), - kCFAllocatorDefault, - 0); - if (productIdentifier) - ++matchingPropertiesCounter; + if (serialPortInfo.serialNumber().isEmpty()) + serialPortInfo.d_ptr->serialNumber = deviceSerialNumber(serialPortService); + if (!serialPortInfo.hasVendorIdentifier()) { + serialPortInfo.d_ptr->vendorIdentifier = + deviceVendorIdentifier(serialPortService, + serialPortInfo.d_ptr->hasVendorIdentifier); } - if (matchingPropertiesCounter == propertyCount) - break; - - kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry); - - } while (kr == kIOReturnSuccess); - - (void) ::IOObjectRelease(entry); - - if (matchingPropertiesCounter > 0) { - - QSerialPortInfo serialPortInfo; - QByteArray buffer(MAXPATHLEN, 0); - - if (device) { - if (::CFStringGetCString(CFStringRef(device), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->device = QString::fromUtf8(buffer); - } - ::CFRelease(device); + if (!serialPortInfo.hasProductIdentifier()) { + serialPortInfo.d_ptr->productIdentifier = + deviceProductIdentifier(serialPortService, + serialPortInfo.d_ptr->hasProductIdentifier); } - if (portName) { - if (::CFStringGetCString(CFStringRef(portName), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->portName = QString::fromUtf8(buffer); - } - ::CFRelease(portName); + if (isCompleteInfo(serialPortInfo)) { + ::IOObjectRelease(serialPortService); + break; } - if (description) { - if (::CFStringGetCString(CFStringRef(description), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->description = QString::fromUtf8(buffer); - } - ::CFRelease(description); - } + serialPortService = parentSerialPortService(serialPortService); + if (!serialPortService) + break; + } - if (manufacturer) { - if (::CFStringGetCString(CFStringRef(manufacturer), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->manufacturer = QString::fromUtf8(buffer); - } - ::CFRelease(manufacturer); - } + serialPortInfoList.append(serialPortInfo); + } - if (serialNumber) { - if (::CFStringGetCString(CFStringRef(serialNumber), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->serialNumber = QString::fromUtf8(buffer); - } - ::CFRelease(serialNumber); - } + ::IOObjectRelease(serialPortIterator); - quint16 value = 0; + return serialPortInfoList; +} - if (vendorIdentifier) { - serialPortInfo.d_ptr->hasVendorIdentifier = ::CFNumberGetValue(CFNumberRef(vendorIdentifier), kCFNumberIntType, &value); - if (serialPortInfo.d_ptr->hasVendorIdentifier) - serialPortInfo.d_ptr->vendorIdentifier = value; +QList<qint32> QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} - ::CFRelease(vendorIdentifier); - } +bool QSerialPortInfo::isBusy() const +{ + QString lockFilePath = serialPortLockFilePath(portName()); + if (lockFilePath.isEmpty()) + return false; - if (productIdentifier) { - serialPortInfo.d_ptr->hasProductIdentifier = ::CFNumberGetValue(CFNumberRef(productIdentifier), kCFNumberIntType, &value); - if (serialPortInfo.d_ptr->hasProductIdentifier) - serialPortInfo.d_ptr->productIdentifier = value; + QFile reader(lockFilePath); + if (!reader.open(QIODevice::ReadOnly)) + return false; - ::CFRelease(productIdentifier); - } + QByteArray pidLine = reader.readLine(); + pidLine.chop(1); + if (pidLine.isEmpty()) + return false; - serialPortInfoList.append(serialPortInfo); - } + qint64 pid = pidLine.toLongLong(); - (void) ::IOObjectRelease(service); - } + if (pid && (::kill(pid, 0) == -1) && (errno == ESRCH)) + return false; // PID doesn't exist anymore - (void) ::IOObjectRelease(iter); + return true; +} - return serialPortInfoList; +bool QSerialPortInfo::isValid() const +{ + QFile f(systemLocation()); + return f.exists(); } QT_END_NAMESPACE diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp index ce5f3a9..0ed8703 100644 --- a/src/serialport/qserialportinfo_unix.cpp +++ b/src/serialport/qserialportinfo_unix.cpp @@ -55,16 +55,10 @@ #include <sys/types.h> // kill #include <signal.h> // kill -#ifndef Q_OS_MAC - #include "qtudev_p.h" -#endif - QT_BEGIN_NAMESPACE -#ifndef Q_OS_MAC - static QStringList filteredDeviceFilePaths() { static const QStringList deviceFileNameFilterList = QStringList() @@ -379,8 +373,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() return serialPortInfoList; } -#endif - QList<qint32> QSerialPortInfo::standardBaudRates() { return QSerialPortPrivate::standardBaudRates(); diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index 8e449c4..dbef314 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -51,6 +51,7 @@ #include <initguid.h> #include <setupapi.h> +#include <cfgmgr32.h> QT_BEGIN_NAMESPACE @@ -122,21 +123,33 @@ static QString deviceRegistryProperty(HDEVINFO deviceInfoSet, return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(devicePropertyByteArray.constData())); } -static QString deviceInstanceIdentifier(HDEVINFO deviceInfoSet, - PSP_DEVINFO_DATA deviceInfoData) +static QString deviceInstanceIdentifier(DEVINST deviceInstanceNumber) { - DWORD requiredSize = 0; - if (::SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, NULL, 0, &requiredSize)) + ULONG numberOfChars = 0; + if (::CM_Get_Device_ID_Size(&numberOfChars, deviceInstanceNumber, 0) != CR_SUCCESS) return QString(); - - QByteArray data(requiredSize * sizeof(wchar_t), 0); - if (!::SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, - reinterpret_cast<wchar_t *>(data.data()), data.size(), NULL)) { - // TODO: error handling with GetLastError + // The size does not include the terminating null character. + ++numberOfChars; + QByteArray outputBuffer(numberOfChars * sizeof(wchar_t), 0); + if (::CM_Get_Device_ID(deviceInstanceNumber, reinterpret_cast<wchar_t *>(outputBuffer.data()), + outputBuffer.size(), 0) != CR_SUCCESS) { return QString(); } + return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(outputBuffer.constData())); +} - return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData())); +static DEVINST parentDeviceInstanceNumber(DEVINST childDeviceInstanceNumber) +{ + ULONG nodeStatus = 0; + ULONG problemNumber = 0; + if (::CM_Get_DevNode_Status(&nodeStatus, &problemNumber, + childDeviceInstanceNumber, 0) != CR_SUCCESS) { + return 0; + } + DEVINST parentInstanceNumber = 0; + if (::CM_Get_Parent(&parentInstanceNumber, childDeviceInstanceNumber, 0) != CR_SUCCESS) + return 0; + return parentInstanceNumber; } static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) @@ -191,7 +204,51 @@ private: const QString &m_serialPortName; }; -static QString deviceSerialNumber(const QString &instanceIdentifier) +static QString deviceDescription(HDEVINFO deviceInfoSet, + PSP_DEVINFO_DATA deviceInfoData) +{ + return deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_DEVICEDESC); +} + +static QString deviceManufacturer(HDEVINFO deviceInfoSet, + PSP_DEVINFO_DATA deviceInfoData) +{ + return deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_MFG); +} + +static quint16 parseDeviceIdentifier(const QString &instanceIdentifier, + const QString &identifierPrefix, + int identifierSize, bool &ok) +{ + const int index = instanceIdentifier.indexOf(identifierPrefix); + if (index == -1) + return quint16(0); + return instanceIdentifier.mid(index + identifierPrefix.size(), identifierSize).toInt(&ok, 16); +} + +static quint16 deviceVendorIdentifier(const QString &instanceIdentifier, bool &ok) +{ + static const int vendorIdentifierSize = 4; + quint16 result = parseDeviceIdentifier( + instanceIdentifier, QStringLiteral("VID_"), vendorIdentifierSize, ok); + if (!ok) + result = parseDeviceIdentifier( + instanceIdentifier, QStringLiteral("VEN_"), vendorIdentifierSize, ok); + return result; +} + +static quint16 deviceProductIdentifier(const QString &instanceIdentifier, bool &ok) +{ + static const int productIdentifierSize = 4; + quint16 result = parseDeviceIdentifier( + instanceIdentifier, QStringLiteral("PID_"), productIdentifierSize, ok); + if (!ok) + result = parseDeviceIdentifier( + instanceIdentifier, QStringLiteral("DEV_"), productIdentifierSize, ok); + return result; +} + +static QString parseDeviceSerialNumber(const QString &instanceIdentifier) { int firstbound = instanceIdentifier.lastIndexOf(QLatin1Char('\\')); int lastbound = instanceIdentifier.indexOf(QLatin1Char('_'), firstbound); @@ -213,16 +270,20 @@ static QString deviceSerialNumber(const QString &instanceIdentifier) return instanceIdentifier.mid(firstbound + 1, lastbound - firstbound - 1); } -QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +static QString deviceSerialNumber(const QString &instanceIdentifier, + DEVINST deviceInstanceNumber) { - static const QString usbVendorIdentifierPrefix(QStringLiteral("VID_")); - static const QString usbProductIdentifierPrefix(QStringLiteral("PID_")); - static const QString pciVendorIdentifierPrefix(QStringLiteral("VEN_")); - static const QString pciDeviceIdentifierPrefix(QStringLiteral("DEV_")); - - static const int vendorIdentifierSize = 4; - static const int productIdentifierSize = 4; + QString result = parseDeviceSerialNumber(instanceIdentifier); + if (result.isEmpty()) { + const DEVINST parentNumber = parentDeviceInstanceNumber(deviceInstanceNumber); + const QString parentInstanceIdentifier = deviceInstanceIdentifier(parentNumber).toUpper(); + result = parseDeviceSerialNumber(parentInstanceIdentifier); + } + return result; +} +QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +{ QList<QSerialPortInfo> serialPortInfoList; foreach (const GuidFlagsPair &uniquePair, guidFlagsPairs()) { @@ -236,49 +297,30 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() DWORD index = 0; while (::SetupDiEnumDeviceInfo(deviceInfoSet, index++, &deviceInfoData)) { - QSerialPortInfo serialPortInfo; - - QString s = devicePortName(deviceInfoSet, &deviceInfoData); - if (s.isEmpty() || s.contains(QStringLiteral("LPT"))) + const QString portName = devicePortName(deviceInfoSet, &deviceInfoData); + if (portName.isEmpty() || portName.contains(QStringLiteral("LPT"))) continue; if (std::find_if(serialPortInfoList.begin(), serialPortInfoList.end(), - SerialPortNameEqualFunctor(s)) != serialPortInfoList.end()) { + SerialPortNameEqualFunctor(portName)) != serialPortInfoList.end()) { continue; } - serialPortInfo.d_ptr->portName = s; - serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s); - serialPortInfo.d_ptr->description = - deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC); - serialPortInfo.d_ptr->manufacturer = - deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG); - - s = deviceInstanceIdentifier(deviceInfoSet, &deviceInfoData).toUpper(); - - serialPortInfo.d_ptr->serialNumber = deviceSerialNumber(s); - - int index = s.indexOf(usbVendorIdentifierPrefix); - if (index != -1) { - serialPortInfo.d_ptr->vendorIdentifier = s.mid(index + usbVendorIdentifierPrefix.size(), vendorIdentifierSize) - .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); - } else { - index = s.indexOf(pciVendorIdentifierPrefix); - if (index != -1) - serialPortInfo.d_ptr->vendorIdentifier = s.mid(index + pciVendorIdentifierPrefix.size(), vendorIdentifierSize) - .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); - } + QSerialPortInfo serialPortInfo; - index = s.indexOf(usbProductIdentifierPrefix); - if (index != -1) { - serialPortInfo.d_ptr->productIdentifier = s.mid(index + usbProductIdentifierPrefix.size(), productIdentifierSize) - .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); - } else { - index = s.indexOf(pciDeviceIdentifierPrefix); - if (index != -1) - serialPortInfo.d_ptr->productIdentifier = s.mid(index + pciDeviceIdentifierPrefix.size(), productIdentifierSize) - .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); - } + serialPortInfo.d_ptr->portName = portName; + serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(portName); + serialPortInfo.d_ptr->description = deviceDescription(deviceInfoSet, &deviceInfoData); + serialPortInfo.d_ptr->manufacturer = deviceManufacturer(deviceInfoSet, &deviceInfoData); + + const QString instanceIdentifier = deviceInstanceIdentifier(deviceInfoData.DevInst).toUpper(); + + serialPortInfo.d_ptr->serialNumber = + deviceSerialNumber(instanceIdentifier, deviceInfoData.DevInst); + serialPortInfo.d_ptr->vendorIdentifier = + deviceVendorIdentifier(instanceIdentifier, serialPortInfo.d_ptr->hasVendorIdentifier); + serialPortInfo.d_ptr->productIdentifier = + deviceProductIdentifier(instanceIdentifier, serialPortInfo.d_ptr->hasProductIdentifier); serialPortInfoList.append(serialPortInfo); } diff --git a/src/serialport/qt4support/include/private/qcore_mac_p.h b/src/serialport/qt4support/include/private/qcore_mac_p.h new file mode 100644 index 0000000..b893025 --- /dev/null +++ b/src/serialport/qt4support/include/private/qcore_mac_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCORE_MAC_P_H +#define QCORE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef __IMAGECAPTURE__ +# define __IMAGECAPTURE__ +#endif + +#if defined(QT_BOOTSTRAPPED) +#include <ApplicationServices/ApplicationServices.h> +#else +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include "qglobal.h" + +#ifdef Q_OS_MACX +#include <CoreServices/CoreServices.h> +#endif + +#ifdef __OBJC__ +#include <Foundation/Foundation.h> +#endif + +#include "qstring.h" + +#if defined( __OBJC__) && defined(QT_NAMESPACE) +#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__) +#else +#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) +#endif + +QT_BEGIN_NAMESPACE + +/* + Helper class that automates refernce counting for CFtypes. + After constructing the QCFType object, it can be copied like a + value-based type. + + Note that you must own the object you are wrapping. + This is typically the case if you get the object from a Core + Foundation function with the word "Create" or "Copy" in it. If + you got the object from a "Get" function, either retain it or use + constructFromGet(). One exception to this rule is the + HIThemeGet*Shape functions, which in reality are "Copy" functions. +*/ +template <typename T> +class Q_CORE_EXPORT QCFType +{ +public: + inline QCFType(const T &t = 0) : type(t) {} + inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } + inline ~QCFType() { if (type) CFRelease(type); } + inline operator T() { return type; } + inline QCFType operator =(const QCFType &helper) + { + if (helper.type) + CFRetain(helper.type); + CFTypeRef type2 = type; + type = helper.type; + if (type2) + CFRelease(type2); + return *this; + } + inline T *operator&() { return &type; } + template <typename X> X as() const { return reinterpret_cast<X>(type); } + static QCFType constructFromGet(const T &t) + { + CFRetain(t); + return QCFType<T>(t); + } +protected: + T type; +}; + +class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef> +{ +public: + inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {} + inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {} + inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {} + operator QString() const; + operator CFStringRef() const; + static QString toQString(CFStringRef cfstr); + static CFStringRef toCFStringRef(const QString &str); +#ifdef __OBJC__ + static QString toQString(const NSString *nsstr); + static NSString *toNSString(const QString &string); +#endif + +private: + QString string; +}; + +QT_END_NAMESPACE + +#endif // QCORE_MAC_P_H diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri index 166a6fa..9c9b076 100644 --- a/src/serialport/serialport-lib.pri +++ b/src/serialport/serialport-lib.pri @@ -78,11 +78,14 @@ unix:!symbian { $$PWD/qserialport_unix_p.h SOURCES += \ - $$PWD/qserialport_unix.cpp \ - $$PWD/qserialportinfo_unix.cpp + $$PWD/qserialport_unix.cpp - macx { - SOURCES += $$PWD/qserialportinfo_mac.cpp + !mac { + SOURCES += \ + $$PWD/qserialportinfo_unix.cpp + } else { + SOURCES += \ + $$PWD/qserialportinfo_mac.cpp LIBS_PRIVATE += -framework IOKit -framework CoreFoundation } diff --git a/tests/manual/qserialportinfo/tst_qserialportinfo.cpp b/tests/manual/qserialportinfo/tst_qserialportinfo.cpp index c73aa00..1908dc0 100644 --- a/tests/manual/qserialportinfo/tst_qserialportinfo.cpp +++ b/tests/manual/qserialportinfo/tst_qserialportinfo.cpp @@ -54,6 +54,7 @@ class tst_QSerialPortInfo : public QObject private slots: void serialPortInfoList(); + void standardBaudRateList(); void constructors(); void assignment(); }; @@ -64,9 +65,27 @@ void tst_QSerialPortInfo::serialPortInfoList() QCOMPARE(list.isEmpty(), false); } +void tst_QSerialPortInfo::standardBaudRateList() +{ + QList<qint32> list(QSerialPortInfo::standardBaudRates()); + QCOMPARE(list.isEmpty(), false); +} + void tst_QSerialPortInfo::constructors() { - // FIXME + QSerialPortInfo serialPortInfo; + QCOMPARE(serialPortInfo.portName().isEmpty(), true); + QCOMPARE(serialPortInfo.systemLocation().isEmpty(), true); + QCOMPARE(serialPortInfo.description().isEmpty(), true); + QCOMPARE(serialPortInfo.manufacturer().isEmpty(), true); + QCOMPARE(serialPortInfo.serialNumber().isEmpty(), true); + QCOMPARE(serialPortInfo.vendorIdentifier(), quint16(0)); + QCOMPARE(serialPortInfo.productIdentifier(), quint16(0)); + QCOMPARE(serialPortInfo.hasVendorIdentifier(), false); + QCOMPARE(serialPortInfo.hasProductIdentifier(), false); + QCOMPARE(serialPortInfo.isNull(), false); + QCOMPARE(serialPortInfo.isBusy(), false); + QCOMPARE(serialPortInfo.isValid(), false); } void tst_QSerialPortInfo::assignment() |