summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-07-10 10:16:01 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-07-10 10:16:01 +0200
commitaa22914a0a796c912a500ab1854801c6b7ebdd8e (patch)
treebb1e0ff23c8b9a92129417fe83eac26758f47113
parent4f1ab4d73b25e983991e310206237fd9b6474130 (diff)
parentc3460993440172f0f29fe2bc290c0b2f10d3de5a (diff)
downloadqtserialport-aa22914a0a796c912a500ab1854801c6b7ebdd8e.tar.gz
Merge remote-tracking branch 'origin/5.3' into dev
Change-Id: I64b13e135d58980ea4cf7429224aa1877778cb46
-rw-r--r--src/serialport/qserialport.h6
-rw-r--r--src/serialport/qserialport_unix.cpp11
-rw-r--r--src/serialport/qserialport_win.cpp133
-rw-r--r--src/serialport/qserialport_win_p.h8
-rw-r--r--src/serialport/qserialportinfo_mac.cpp337
-rw-r--r--src/serialport/qserialportinfo_unix.cpp8
-rw-r--r--src/serialport/qserialportinfo_win.cpp152
-rw-r--r--src/serialport/qt4support/include/private/qcore_mac_p.h148
-rw-r--r--src/serialport/serialport-lib.pri11
-rw-r--r--tests/manual/qserialportinfo/tst_qserialportinfo.cpp21
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()