diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2015-10-13 17:18:15 +0300 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@theqtcompany.com> | 2015-10-14 08:26:40 +0000 |
commit | c18927e87e65eefccd8cda9e6671d234e95d387c (patch) | |
tree | b10d59ca000e674257927a548a5e378c08f2f1de /src | |
parent | 797624ac0c5f0a7ee3dd0a938454d55cb8786373 (diff) |
Windows: Refactor code related to discovering of a remote devices
* There is no need to do parallel scan for LE and Classic devices.
It is enough to do it one after another by using one QFutureWatcher
instead of two QFutureWatchers.
* Now the qwinclassicbluetooth(h).cpp files are deleted from the
'windows' directory, and its related code is moved into
QBluetoothDeviceDiscoveryAgentPrivate.
Change-Id: I2acf102c3a8d313d078b351e9a2ce54ebca79dee
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_p.h | 48 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp | 556 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_win.cpp | 57 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinclassicbluetooth.cpp | 94 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinclassicbluetooth_p.h | 75 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinlowenergybluetooth.cpp | 150 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinlowenergybluetooth_p.h | 18 | ||||
-rw-r--r-- | src/bluetooth/windows/windows.pri | 2 |
8 files changed, 363 insertions, 637 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h index 0d220ef9..d7da8e98 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h @@ -75,8 +75,6 @@ QT_END_NAMESPACE #ifdef Q_OS_WIN32 #include <QtConcurrent> -#include "windows/qwinclassicbluetooth_p.h" -#include "windows/qwinlowenergybluetooth_p.h" #endif QT_BEGIN_NAMESPACE @@ -157,47 +155,23 @@ private: #endif #ifdef Q_OS_WIN32 +public: + typedef void* SearchHandle; + static QString discoveredLeDeviceSystemPath(const QBluetoothAddress &deviceAddress); + private slots: - void classicDeviceDiscovered(); - void lowEnergyDeviceDiscovered(); + void taskFinished(); private: - void initialize(const QBluetoothAddress &deviceAdapter); - - bool isClassicAdapterValid(const QBluetoothAddress &deviceAdapter); - void startDiscoveryForFirstClassicDevice(); - void startDiscoveryForNextClassicDevice(HBLUETOOTH_DEVICE_FIND hSearch); - void completeClassicDiscovery(HBLUETOOTH_DEVICE_FIND hSearch); - void acceptDiscoveredClassicDevice(const BLUETOOTH_DEVICE_INFO &device); - - bool isLowEnergyAdapterValid(const QBluetoothAddress &deviceAdapter); - void startDiscoveryForLowEnergyDevices(); - void completeLowEnergyDiscovery(); - void acceptDiscoveredLowEnergyDevice(const WinLowEnergyBluetooth::DeviceInfo &device); - - void processDuplicates(const QBluetoothDeviceInfo &foundDevice); - - void setError(DWORD error, const QString &str = QString()); - - bool isDiscoveredSuccessfully(int systemError) const; - - bool canBeCanceled() const; - void cancel(); - - bool canBePendingStarted() const; - void prepareToPendingStart(); - - void finalize(); - void drop(int systemError); + void processDiscoveredDevice(const QBluetoothDeviceInfo &foundDevice); - QFutureWatcher<WinClassicBluetooth::RemoteDeviceDiscoveryResult> *classicDiscoveryWatcher; - QFutureWatcher<WinLowEnergyBluetooth::DeviceDiscoveryResult> *lowEnergyDiscoveryWatcher; + QBluetoothAddress adapterAddress; bool pendingCancel; bool pendingStart; - bool isClassicActive; - bool isClassicValid; - bool isLowEnergyActive; - bool isLowEnergyValid; + QFutureWatcher<QBluetoothDeviceInfo> *scanWatcher; + bool active; + int systemErrorCode; + SearchHandle searchHandle; #endif QBluetoothDeviceDiscoveryAgent *q_ptr; diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp index 937bc2a4..78626e85 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp @@ -33,253 +33,414 @@ ****************************************************************************/ #include "qbluetoothdevicediscoveryagent.h" -#include "qbluetoothdevicediscoveryagent_p.h" -#include "qbluetoothaddress.h" #include "qbluetoothuuid.h" +#include "qbluetoothdevicediscoveryagent_p.h" #include "qbluetoothlocaldevice_p.h" +#include <QtCore/qmutex.h> + +#include <qt_windows.h> +#include <setupapi.h> +#include <bluetoothapis.h> + QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) -QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( - const QBluetoothAddress &deviceAdapter, - QBluetoothDeviceDiscoveryAgent *parent) - : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry) - , lastError(QBluetoothDeviceDiscoveryAgent::NoError) - , classicDiscoveryWatcher(0) - , lowEnergyDiscoveryWatcher(0) - , pendingCancel(false) - , pendingStart(false) - , isClassicActive(false) - , isClassicValid(false) - , isLowEnergyActive(false) - , isLowEnergyValid(false) - , q_ptr(parent) -{ - initialize(deviceAdapter); -} +struct LeDeviceEntry { + LeDeviceEntry(const QString &path, const QBluetoothAddress &address) + : devicePath(path), deviceAddress(address) {} + QString devicePath; + QBluetoothAddress deviceAddress; +}; -QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() +Q_GLOBAL_STATIC(QList<LeDeviceEntry>, cachedLeDeviceEntries) +Q_GLOBAL_STATIC(QMutex, cachedLeDeviceEntriesGuard) + +static QString devicePropertyString( + HDEVINFO hDeviceInfo, + const PSP_DEVINFO_DATA deviceInfoData, + DWORD registryProperty) { - if (isClassicActive || isLowEnergyActive) - stop(); + DWORD propertyRegDataType = 0; + DWORD propertyBufferSize = 0; + QByteArray propertyBuffer; + + while (!::SetupDiGetDeviceRegistryProperty( + hDeviceInfo, + deviceInfoData, + registryProperty, + &propertyRegDataType, + propertyBuffer.isEmpty() ? NULL : reinterpret_cast<PBYTE>(propertyBuffer.data()), + propertyBuffer.size(), + &propertyBufferSize)) { + + const DWORD error = ::GetLastError(); + if (error != ERROR_INSUFFICIENT_BUFFER + || (propertyRegDataType != REG_SZ + && propertyRegDataType != REG_EXPAND_SZ)) { + return QString(); + } - if (classicDiscoveryWatcher) - classicDiscoveryWatcher->waitForFinished(); + // add +2 byte to allow to successfully convert to qstring + propertyBuffer.fill(0, propertyBufferSize + sizeof(wchar_t)); + } - if (lowEnergyDiscoveryWatcher) - lowEnergyDiscoveryWatcher->waitForFinished(); + return QString::fromWCharArray(reinterpret_cast<const wchar_t *>( + propertyBuffer.constData())); } -bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const +static QString deviceName(HDEVINFO hDeviceInfo, PSP_DEVINFO_DATA deviceInfoData) { - if (pendingStart) - return true; - if (pendingCancel) - return false; - - return isClassicActive || isLowEnergyActive; + return devicePropertyString(hDeviceInfo, deviceInfoData, SPDRP_FRIENDLYNAME); } -void QBluetoothDeviceDiscoveryAgentPrivate::start() +static QString deviceSystemPath(const PSP_INTERFACE_DEVICE_DETAIL_DATA detailData) { - if (!isClassicValid && !isLowEnergyValid) { - setError(ERROR_INVALID_HANDLE, - QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device.")); - return; - } - - if (pendingCancel == true) { - pendingStart = true; - return; - } - - discoveredDevices.clear(); - - if (isClassicValid) - startDiscoveryForFirstClassicDevice(); - - if (isLowEnergyValid) - startDiscoveryForLowEnergyDevices(); + return QString::fromWCharArray(detailData->DevicePath); } -void QBluetoothDeviceDiscoveryAgentPrivate::stop() +static QBluetoothAddress deviceAddress(const QString &devicePath) { - if (!isClassicActive && !isLowEnergyActive) - return; - - pendingCancel = true; - pendingStart = false; + const int firstbound = devicePath.indexOf(QStringLiteral("dev_")); + const int lastbound = devicePath.indexOf(QLatin1Char('#'), firstbound); + const QString hex = devicePath.mid(firstbound + 4, lastbound - firstbound - 4); + bool ok = false; + return QBluetoothAddress(hex.toULongLong(&ok, 16)); } -void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceDiscovered() +static QBluetoothDeviceInfo createClassicDeviceInfo(const BLUETOOTH_DEVICE_INFO &foundDevice) { - const WinClassicBluetooth::RemoteDeviceDiscoveryResult result = - classicDiscoveryWatcher->result(); - - if (isDiscoveredSuccessfully(result.error)) { + QBluetoothDeviceInfo deviceInfo( + QBluetoothAddress(foundDevice.Address.ullLong), + QString::fromWCharArray(foundDevice.szName), + foundDevice.ulClassofDevice); - if (canBeCanceled()) { - cancel(); - } else if (canBePendingStarted()) { - prepareToPendingStart(); - } else { - if (result.error != ERROR_NO_MORE_ITEMS) { - acceptDiscoveredClassicDevice(result.device); - startDiscoveryForNextClassicDevice(result.hSearch); - return; - } - } + if (foundDevice.fRemembered) + deviceInfo.setCached(true); + return deviceInfo; +} +static QBluetoothDeviceInfo findFirstClassicDevice( + int *systemErrorCode, HBLUETOOTH_DEVICE_FIND *searchHandle) +{ + BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams; + ::ZeroMemory(&searchParams, sizeof(searchParams)); + searchParams.dwSize = sizeof(searchParams); + searchParams.cTimeoutMultiplier = 10; // 12.8 sec + searchParams.fIssueInquiry = TRUE; + searchParams.fReturnAuthenticated = TRUE; + searchParams.fReturnConnected = TRUE; + searchParams.fReturnRemembered = TRUE; + searchParams.fReturnUnknown = TRUE; + searchParams.hRadio = NULL; + + BLUETOOTH_DEVICE_INFO deviceInfo; + ::ZeroMemory(&deviceInfo, sizeof(deviceInfo)); + deviceInfo.dwSize = sizeof(deviceInfo); + + const HBLUETOOTH_DEVICE_FIND hFind = ::BluetoothFindFirstDevice( + &searchParams, &deviceInfo); + + QBluetoothDeviceInfo foundDevice; + if (hFind) { + *searchHandle = hFind; + *systemErrorCode = NO_ERROR; + foundDevice = createClassicDeviceInfo(deviceInfo); } else { - drop(result.error); + *systemErrorCode = ::GetLastError(); } - completeClassicDiscovery(result.hSearch); + return foundDevice; } -void QBluetoothDeviceDiscoveryAgentPrivate::lowEnergyDeviceDiscovered() +static QBluetoothDeviceInfo findNextClassicDevice( + int *systemErrorCode, HBLUETOOTH_DEVICE_FIND searchHandle) { - const WinLowEnergyBluetooth::DeviceDiscoveryResult result = - lowEnergyDiscoveryWatcher->result(); - - if (isDiscoveredSuccessfully(result.error)) { - - if (canBeCanceled()) { - cancel(); - } else if (canBePendingStarted()) { - prepareToPendingStart(); - } else { - foreach (const WinLowEnergyBluetooth::DeviceInfo &deviceInfo, result.devices) - acceptDiscoveredLowEnergyDevice(deviceInfo); - } + BLUETOOTH_DEVICE_INFO deviceInfo; + ::ZeroMemory(&deviceInfo, sizeof(deviceInfo)); + deviceInfo.dwSize = sizeof(deviceInfo); + QBluetoothDeviceInfo foundDevice; + if (!::BluetoothFindNextDevice(searchHandle, &deviceInfo)) { + *systemErrorCode = ::GetLastError(); } else { - drop(result.error); + *systemErrorCode = NO_ERROR; + foundDevice = createClassicDeviceInfo(deviceInfo); } - completeLowEnergyDiscovery(); + return foundDevice; } -void QBluetoothDeviceDiscoveryAgentPrivate::initialize( - const QBluetoothAddress &deviceAdapter) +static void closeClassicSearch(HBLUETOOTH_DEVICE_FIND *searchHandle) { - isClassicValid = isClassicAdapterValid(deviceAdapter); - isLowEnergyValid = isLowEnergyAdapterValid(deviceAdapter); + if (searchHandle && *searchHandle) { + ::BluetoothFindDeviceClose(*searchHandle); + *searchHandle = 0; + } } -bool QBluetoothDeviceDiscoveryAgentPrivate::isClassicAdapterValid( - const QBluetoothAddress &deviceAdapter) +static QList<QBluetoothDeviceInfo> enumerateLeDevices( + int *systemErrorCode) { - foreach (const QBluetoothHostInfo &adapterInfo, QBluetoothLocalDevicePrivate::localAdapters()) { - if (deviceAdapter == QBluetoothAddress() - || deviceAdapter == adapterInfo.address()) { - return true; - } + const QUuid deviceInterfaceGuid("781aee18-7733-4ce4-add0-91f41c67b592"); + const HDEVINFO hDeviceInfo = ::SetupDiGetClassDevs( + reinterpret_cast<const GUID *>(&deviceInterfaceGuid), + NULL, + 0, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + if (hDeviceInfo == INVALID_HANDLE_VALUE) { + *systemErrorCode = ::GetLastError(); + return QList<QBluetoothDeviceInfo>(); } - qCWarning(QT_BT_WINDOWS) << "No matching for classic local radio:" << deviceAdapter; - return false; -} + QList<QBluetoothDeviceInfo> foundDevices; + DWORD index = 0; -void QBluetoothDeviceDiscoveryAgentPrivate::startDiscoveryForFirstClassicDevice() -{ - isClassicActive = true; + QList<LeDeviceEntry> cachedEntries; - if (!classicDiscoveryWatcher) { - classicDiscoveryWatcher = new QFutureWatcher< - WinClassicBluetooth::RemoteDeviceDiscoveryResult>(this); - connect(classicDiscoveryWatcher, &QFutureWatcher<WinClassicBluetooth::RemoteDeviceDiscoveryResult>::finished, - this, &QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceDiscovered); + forever { + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + ::ZeroMemory(&deviceInterfaceData, sizeof(deviceInterfaceData)); + deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); + + if (!::SetupDiEnumDeviceInterfaces( + hDeviceInfo, + NULL, + reinterpret_cast<const GUID *>(&deviceInterfaceGuid), + index++, + &deviceInterfaceData)) { + *systemErrorCode = ::GetLastError(); + break; + } + + DWORD deviceInterfaceDetailDataSize = 0; + if (!::SetupDiGetDeviceInterfaceDetail( + hDeviceInfo, + &deviceInterfaceData, + NULL, + deviceInterfaceDetailDataSize, + &deviceInterfaceDetailDataSize, + NULL)) { + if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + *systemErrorCode = ::GetLastError(); + break; + } + } + + SP_DEVINFO_DATA deviceInfoData; + ::ZeroMemory(&deviceInfoData, sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + + QByteArray deviceInterfaceDetailDataBuffer( + deviceInterfaceDetailDataSize, 0); + + PSP_INTERFACE_DEVICE_DETAIL_DATA deviceInterfaceDetailData = + reinterpret_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA> + (deviceInterfaceDetailDataBuffer.data()); + + deviceInterfaceDetailData->cbSize = + sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); + + if (!::SetupDiGetDeviceInterfaceDetail( + hDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + deviceInterfaceDetailDataBuffer.size(), + &deviceInterfaceDetailDataSize, + &deviceInfoData)) { + *systemErrorCode = ::GetLastError(); + break; + } + + const QString systemPath = deviceSystemPath(deviceInterfaceDetailData); + const QBluetoothAddress address = deviceAddress(systemPath); + if (address.isNull()) + continue; + const QString name = deviceName(hDeviceInfo, &deviceInfoData); + + QBluetoothDeviceInfo deviceInfo(address, name, QBluetoothDeviceInfo::MiscellaneousDevice); + deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + deviceInfo.setCached(true); + + foundDevices << deviceInfo; + cachedEntries << LeDeviceEntry(systemPath, address); } - const QFuture<WinClassicBluetooth::RemoteDeviceDiscoveryResult> future = - QtConcurrent::run(WinClassicBluetooth::startDiscoveryOfFirstRemoteDevice); - classicDiscoveryWatcher->setFuture(future); + QMutexLocker locker(cachedLeDeviceEntriesGuard()); + cachedLeDeviceEntries()->swap(cachedEntries); + + ::SetupDiDestroyDeviceInfoList(hDeviceInfo); + return foundDevices; } -void QBluetoothDeviceDiscoveryAgentPrivate::startDiscoveryForNextClassicDevice( - HBLUETOOTH_DEVICE_FIND hSearch) +QString QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath( + const QBluetoothAddress &deviceAddress) { - Q_ASSERT(classicDiscoveryWatcher); - - const QFuture<WinClassicBluetooth::RemoteDeviceDiscoveryResult> future = - QtConcurrent::run(WinClassicBluetooth::startDiscoveryOfNextRemoteDevice, hSearch); - classicDiscoveryWatcher->setFuture(future); + // update LE devices cache + int dummyErrorCode; + enumerateLeDevices(&dummyErrorCode); + + QMutexLocker locker(cachedLeDeviceEntriesGuard()); + for (int i = 0; i < cachedLeDeviceEntries()->count(); ++i) { + if (cachedLeDeviceEntries()->at(i).deviceAddress == deviceAddress) + return cachedLeDeviceEntries()->at(i).devicePath; + } + return QString(); } -void QBluetoothDeviceDiscoveryAgentPrivate::completeClassicDiscovery( - HBLUETOOTH_DEVICE_FIND hSearch) +QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( + const QBluetoothAddress &deviceAdapter, + QBluetoothDeviceDiscoveryAgent *parent) + : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry) + , lastError(QBluetoothDeviceDiscoveryAgent::NoError) + , adapterAddress(deviceAdapter) + , pendingCancel(false) + , pendingStart(false) + , scanWatcher(Q_NULLPTR) + , active(false) + , systemErrorCode(NO_ERROR) + , searchHandle(0) + , q_ptr(parent) { - WinClassicBluetooth::cancelRemoteDevicesDiscovery(hSearch); - isClassicActive = false; - finalize(); + scanWatcher = new QFutureWatcher<QBluetoothDeviceInfo>(this); + connect(scanWatcher, &QFutureWatcher<QBluetoothDeviceInfo>::finished, + this, &QBluetoothDeviceDiscoveryAgentPrivate::taskFinished); } -void QBluetoothDeviceDiscoveryAgentPrivate::acceptDiscoveredClassicDevice( - const BLUETOOTH_DEVICE_INFO &device) +QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() { - QBluetoothDeviceInfo deviceInfo( - QBluetoothAddress(device.Address.ullLong), - QString::fromWCharArray(device.szName), - device.ulClassofDevice); - - if (device.fRemembered) - deviceInfo.setCached(true); + if (active) + stop(); - processDuplicates(deviceInfo); + scanWatcher->waitForFinished(); } -bool QBluetoothDeviceDiscoveryAgentPrivate::isLowEnergyAdapterValid( - const QBluetoothAddress &deviceAdapter) +bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const { - Q_UNUSED(deviceAdapter); - - // We can not detect an address of local BLE adapter, - // but we can detect that some BLE adapter is present. - return WinLowEnergyBluetooth::hasLocalRadio(); + if (pendingStart) + return true; + if (pendingCancel) + return false; + return active; } -void QBluetoothDeviceDiscoveryAgentPrivate::startDiscoveryForLowEnergyDevices() +void QBluetoothDeviceDiscoveryAgentPrivate::start() { - isLowEnergyActive = true; + if (pendingCancel == true) { + pendingStart = true; + return; + } + + const QList<QBluetoothHostInfo> foundLocalAdapters = + QBluetoothLocalDevicePrivate::localAdapters(); - if (!lowEnergyDiscoveryWatcher) { - lowEnergyDiscoveryWatcher = new QFutureWatcher< - WinLowEnergyBluetooth::DeviceDiscoveryResult>(this); - connect(lowEnergyDiscoveryWatcher, &QFutureWatcher<WinLowEnergyBluetooth::DeviceDiscoveryResult>::finished, - this, &QBluetoothDeviceDiscoveryAgentPrivate::lowEnergyDeviceDiscovered); + Q_Q(QBluetoothDeviceDiscoveryAgent); + + if (foundLocalAdapters.isEmpty()) { + qCWarning(QT_BT_WINDOWS) << "Device does not support Bluetooth"; + lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError; + errorString = QBluetoothDeviceDiscoveryAgent::tr("Device does not support Bluetooth"); + emit q->error(lastError); + return; + } + + // Check for the local adapter address. + bool foundLocalAdapter = false; + foreach (const QBluetoothHostInfo &adapterInfo, foundLocalAdapters) { + if (adapterAddress == QBluetoothAddress() || adapterAddress == adapterInfo.address()) { + foundLocalAdapter = true; + break; + } } - const QFuture<WinLowEnergyBluetooth::DeviceDiscoveryResult> future = - QtConcurrent::run(WinLowEnergyBluetooth::startDiscoveryOfRemoteDevices); - lowEnergyDiscoveryWatcher->setFuture(future); + if (!foundLocalAdapter) { + qCWarning(QT_BT_WINDOWS) << "Incorrect local adapter passed."; + lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError; + errorString = QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device."); + emit q->error(lastError); + return; + } + + discoveredDevices.clear(); + active = true; + + // Start scan for first classic device. + const QFuture<QBluetoothDeviceInfo> future = QtConcurrent::run( + findFirstClassicDevice, &systemErrorCode, &searchHandle); + scanWatcher->setFuture(future); } -void QBluetoothDeviceDiscoveryAgentPrivate::completeLowEnergyDiscovery() +void QBluetoothDeviceDiscoveryAgentPrivate::stop() { - isLowEnergyActive = false; - finalize(); + if (!active) + return; + + pendingCancel = true; + pendingStart = false; } -void QBluetoothDeviceDiscoveryAgentPrivate::acceptDiscoveredLowEnergyDevice( - const WinLowEnergyBluetooth::DeviceInfo &device) +void QBluetoothDeviceDiscoveryAgentPrivate::taskFinished() { - QBluetoothDeviceInfo deviceInfo(device.address, device.name, 0); - deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); - deviceInfo.setCached(true); + Q_Q(QBluetoothDeviceDiscoveryAgent); - processDuplicates(deviceInfo); + if (pendingCancel && !pendingStart) { + closeClassicSearch(&searchHandle); + active = false; + pendingCancel = false; + emit q->canceled(); + } else if (pendingStart) { + closeClassicSearch(&searchHandle); + pendingStart = pendingCancel = false; + start(); + } else { + if (systemErrorCode == ERROR_NO_MORE_ITEMS) { + closeClassicSearch(&searchHandle); + // Enumerate LE devices. + const QList<QBluetoothDeviceInfo> foundDevices = + enumerateLeDevices(&systemErrorCode); + if (systemErrorCode == ERROR_NO_MORE_ITEMS) { + foreach (const QBluetoothDeviceInfo &foundDevice, foundDevices) + processDiscoveredDevice(foundDevice); + active = false; + emit q->finished(); + } else { + pendingStart = pendingCancel = false; + active = false; + lastError = (systemErrorCode == ERROR_INVALID_HANDLE) ? + QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError + : QBluetoothDeviceDiscoveryAgent::InputOutputError; + errorString = qt_error_string(systemErrorCode); + emit q->error(lastError); + } + } else if (systemErrorCode == NO_ERROR) { + processDiscoveredDevice(scanWatcher->result()); + // Start scan for next classic device. + const QFuture<QBluetoothDeviceInfo> future = QtConcurrent::run( + findNextClassicDevice, &systemErrorCode, searchHandle); + scanWatcher->setFuture(future); + } else { + closeClassicSearch(&searchHandle); + pendingStart = pendingCancel = false; + active = false; + lastError = (systemErrorCode == ERROR_INVALID_HANDLE) ? + QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError + : QBluetoothDeviceDiscoveryAgent::InputOutputError; + errorString = qt_error_string(systemErrorCode); + emit q->error(lastError); + } + } } -void QBluetoothDeviceDiscoveryAgentPrivate::processDuplicates( +void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevice( const QBluetoothDeviceInfo &foundDevice) { Q_Q(QBluetoothDeviceDiscoveryAgent); for (int i = 0; i < discoveredDevices.size(); i++) { QBluetoothDeviceInfo mergedDevice = discoveredDevices[i]; + if (mergedDevice.address() == foundDevice.address()) { if (mergedDevice == foundDevice || mergedDevice.coreConfigurations() == foundDevice.coreConfigurations()) { @@ -313,67 +474,4 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processDuplicates( emit q->deviceDiscovered(foundDevice); } -void QBluetoothDeviceDiscoveryAgentPrivate::setError(DWORD error, const QString &str) -{ - Q_Q(QBluetoothDeviceDiscoveryAgent); - - lastError = (error == ERROR_INVALID_HANDLE) ? - QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError - : QBluetoothDeviceDiscoveryAgent::InputOutputError; - errorString = str.isEmpty() ? qt_error_string(error) : str; - emit q->error(lastError); -} - -bool QBluetoothDeviceDiscoveryAgentPrivate::isDiscoveredSuccessfully( - int systemError) const -{ - return systemError == NO_ERROR || systemError == ERROR_NO_MORE_ITEMS; -} - -bool QBluetoothDeviceDiscoveryAgentPrivate::canBeCanceled() const -{ - if (isClassicActive || isLowEnergyActive) - return false; - return pendingCancel && !pendingStart; -} - -void QBluetoothDeviceDiscoveryAgentPrivate::cancel() -{ - Q_Q(QBluetoothDeviceDiscoveryAgent); - - emit q->canceled(); - pendingCancel = false; -} - -bool QBluetoothDeviceDiscoveryAgentPrivate::canBePendingStarted() const -{ - if (isClassicActive || isLowEnergyActive) - return false; - return pendingStart; -} - -void QBluetoothDeviceDiscoveryAgentPrivate::prepareToPendingStart() -{ - pendingCancel = false; - pendingStart = false; - start(); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::finalize() -{ - Q_Q(QBluetoothDeviceDiscoveryAgent); - - if (isClassicActive || isLowEnergyActive) - return; - - emit q->finished(); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::drop(int systemError) -{ - setError(systemError); - pendingCancel = false; - pendingStart = false; -} - QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller_win.cpp b/src/bluetooth/qlowenergycontroller_win.cpp index 8342e3ce..ed33c5c8 100644 --- a/src/bluetooth/qlowenergycontroller_win.cpp +++ b/src/bluetooth/qlowenergycontroller_win.cpp @@ -31,7 +31,10 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include "qlowenergycontroller_p.h" +#include "qbluetoothdevicediscoveryagent_p.h" + #include <QtCore/QLoggingCategory> QT_BEGIN_NAMESPACE @@ -75,49 +78,29 @@ void QLowEnergyControllerPrivate::connectToDevice() setState(QLowEnergyController::ConnectingState); - const WinLowEnergyBluetooth::DeviceDiscoveryResult result = - WinLowEnergyBluetooth::startDiscoveryOfRemoteDevices(); - - if (result.error != NO_ERROR - && result.error != ERROR_NO_MORE_ITEMS) { - qCWarning(QT_BT_WINDOWS) << qt_error_string(::GetLastError()); - setError(QLowEnergyController::UnknownRemoteDeviceError); - setState(QLowEnergyController::UnconnectedState); - return; - } - - foreach (const WinLowEnergyBluetooth::DeviceInfo &info, result.devices) { - - if (info.address != remoteDevice) - continue; - - const DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE; - const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + const QString deviceSystemPath = QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath(remoteDevice); - hRemoteDevice = ::CreateFile( - reinterpret_cast<const wchar_t *>(info.systemPath.utf16()), - desiredAccess, - shareMode, - NULL, - OPEN_EXISTING, - 0, - NULL); + const DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE; + const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - if (hRemoteDevice == INVALID_HANDLE_VALUE) { - qCWarning(QT_BT_WINDOWS) << qt_error_string(::GetLastError()); - setError(QLowEnergyController::ConnectionError); - setState(QLowEnergyController::UnconnectedState); - return; - } + hRemoteDevice = ::CreateFile( + reinterpret_cast<const wchar_t *>(deviceSystemPath.utf16()), + desiredAccess, + shareMode, + NULL, + OPEN_EXISTING, + 0, + NULL); - setState(QLowEnergyController::ConnectedState); - emit q->connected(); + if (hRemoteDevice == INVALID_HANDLE_VALUE) { + qCWarning(QT_BT_WINDOWS) << qt_error_string(::GetLastError()); + setError(QLowEnergyController::ConnectionError); + setState(QLowEnergyController::UnconnectedState); return; } - qCWarning(QT_BT_WINDOWS) << qt_error_string(ERROR_FILE_NOT_FOUND); - setError(QLowEnergyController::UnknownRemoteDeviceError); - setState(QLowEnergyController::UnconnectedState); + setState(QLowEnergyController::ConnectedState); + emit q->connected(); } void QLowEnergyControllerPrivate::disconnectFromDevice() diff --git a/src/bluetooth/windows/qwinclassicbluetooth.cpp b/src/bluetooth/windows/qwinclassicbluetooth.cpp deleted file mode 100644 index 88313ed7..00000000 --- a/src/bluetooth/windows/qwinclassicbluetooth.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwinclassicbluetooth_p.h" - -QT_BEGIN_NAMESPACE - -namespace WinClassicBluetooth { - -LocalRadiosDiscoveryResult::LocalRadiosDiscoveryResult() - : error(NO_ERROR) -{ -} - -RemoteDeviceDiscoveryResult::RemoteDeviceDiscoveryResult() - : hSearch(0) - , error(NO_ERROR) -{ - ::ZeroMemory(&device, sizeof(device)); - device.dwSize = sizeof(device); -} - -RemoteDeviceDiscoveryResult startDiscoveryOfFirstRemoteDevice() -{ - BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams; - ::ZeroMemory(&searchParams, sizeof(searchParams)); - searchParams.dwSize = sizeof(searchParams); - searchParams.cTimeoutMultiplier = 10; // 12.8 sec - searchParams.fIssueInquiry = TRUE; - searchParams.fReturnAuthenticated = TRUE; - searchParams.fReturnConnected = TRUE; - searchParams.fReturnRemembered = TRUE; - searchParams.fReturnUnknown = TRUE; - searchParams.hRadio = NULL; - - RemoteDeviceDiscoveryResult result; - result.hSearch = ::BluetoothFindFirstDevice( - &searchParams, &result.device); - - if (!result.hSearch) - result.error = ::GetLastError(); - return result; -} - -RemoteDeviceDiscoveryResult startDiscoveryOfNextRemoteDevice( - HBLUETOOTH_DEVICE_FIND hSearch) -{ - RemoteDeviceDiscoveryResult result; - result.hSearch = hSearch; - if (!::BluetoothFindNextDevice(hSearch, &result.device)) - result.error = ::GetLastError(); - return result; -} - -void cancelRemoteDevicesDiscovery(HBLUETOOTH_DEVICE_FIND hSearch) -{ - if (hSearch) - ::BluetoothFindDeviceClose(hSearch); -} - -} // namespace WinClassicBluetooth - -QT_END_NAMESPACE diff --git a/src/bluetooth/windows/qwinclassicbluetooth_p.h b/src/bluetooth/windows/qwinclassicbluetooth_p.h deleted file mode 100644 index 2ba255ce..00000000 --- a/src/bluetooth/windows/qwinclassicbluetooth_p.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINCLASSICBLUETOOTH_P_H -#define QWINCLASSICBLUETOOTH_P_H - -#include <QtCore/qlist.h> -#include <QtCore/qmetatype.h> - -#include <qt_windows.h> -#include <setupapi.h> -#include <bluetoothapis.h> - -QT_BEGIN_NAMESPACE - -namespace WinClassicBluetooth { - -struct LocalRadiosDiscoveryResult -{ - LocalRadiosDiscoveryResult(); - QList<BLUETOOTH_RADIO_INFO> radios; - DWORD error; -}; - -struct RemoteDeviceDiscoveryResult -{ - RemoteDeviceDiscoveryResult(); - BLUETOOTH_DEVICE_INFO device; - HBLUETOOTH_DEVICE_FIND hSearch; - DWORD error; -}; - -RemoteDeviceDiscoveryResult startDiscoveryOfFirstRemoteDevice(); -RemoteDeviceDiscoveryResult startDiscoveryOfNextRemoteDevice(HBLUETOOTH_DEVICE_FIND hSearch); -void cancelRemoteDevicesDiscovery(HBLUETOOTH_DEVICE_FIND hSearch); - -} // namespace WinClassicBluetooth - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(WinClassicBluetooth::LocalRadiosDiscoveryResult) -Q_DECLARE_METATYPE(WinClassicBluetooth::RemoteDeviceDiscoveryResult) - -#endif // QWINCLASSICBLUETOOTH_P_H diff --git a/src/bluetooth/windows/qwinlowenergybluetooth.cpp b/src/bluetooth/windows/qwinlowenergybluetooth.cpp index eeb8ae33..0b917bd3 100644 --- a/src/bluetooth/windows/qwinlowenergybluetooth.cpp +++ b/src/bluetooth/windows/qwinlowenergybluetooth.cpp @@ -102,6 +102,11 @@ static inline bool resolveFunctions(QLibrary *library) Q_GLOBAL_STATIC(QLibrary, bluetoothapis) +ServicesDiscoveryResult::ServicesDiscoveryResult() + : error(NO_ERROR) +{ +} + static QString deviceRegistryProperty( HDEVINFO deviceInfoHandle, const PSP_DEVINFO_DATA deviceInfoData, @@ -135,13 +140,6 @@ static QString deviceRegistryProperty( reinterpret_cast<const wchar_t *>(propertyBuffer.constData())); } -static QString deviceFriendlyName( - HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) -{ - return deviceRegistryProperty( - deviceInfoSet, deviceInfoData, SPDRP_FRIENDLYNAME); -} - static QString deviceService( HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) { @@ -149,138 +147,6 @@ static QString deviceService( deviceInfoSet, deviceInfoData, SPDRP_SERVICE); } -static QString deviceSystemPath( - const PSP_INTERFACE_DEVICE_DETAIL_DATA detailData) -{ - return QString::fromWCharArray(detailData->DevicePath); -} - -static QBluetoothAddress parseRemoteAddress(const QString &devicePath) -{ - const int firstbound = devicePath.indexOf(QStringLiteral("dev_")); - const int lastbound = devicePath.indexOf(QLatin1Char('#'), firstbound); - - const QString hex = - devicePath.mid(firstbound + 4, lastbound - firstbound - 4); - - bool ok = false; - return QBluetoothAddress(hex.toULongLong(&ok, 16)); -} - -DeviceInfo::DeviceInfo( - const QBluetoothAddress &address, - const QString &name, - const QString &systemPath) - : address(address) - , name(name) - , systemPath(systemPath) -{ -} - -DeviceDiscoveryResult::DeviceDiscoveryResult() - : error(NO_ERROR) -{ -} - -ServicesDiscoveryResult::ServicesDiscoveryResult() - : error(NO_ERROR) -{ -} - -static DeviceDiscoveryResult availableSystemInterfaces( - const GUID &deviceInterface) -{ - const DWORD flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE; - const HDEVINFO deviceInfoHandle = ::SetupDiGetClassDevs( - &deviceInterface, 0, 0, flags); - - DeviceDiscoveryResult result; - - if (deviceInfoHandle == INVALID_HANDLE_VALUE) { - result.error = ::GetLastError(); - return result; - } - - DWORD index = 0; - - forever { - - SP_DEVICE_INTERFACE_DATA deviceInterfaceData; - ::ZeroMemory(&deviceInterfaceData, sizeof(deviceInterfaceData)); - deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); - - if (!::SetupDiEnumDeviceInterfaces( - deviceInfoHandle, - NULL, - &deviceInterface, - index++, - &deviceInterfaceData)) { - - result.error = ::GetLastError(); - break; - } - - DWORD deviceInterfaceDetailDataSize = 0; - if (!::SetupDiGetDeviceInterfaceDetail( - deviceInfoHandle, - &deviceInterfaceData, - NULL, - deviceInterfaceDetailDataSize, - &deviceInterfaceDetailDataSize, - NULL)) { - - const DWORD error = ::GetLastError(); - if (error != ERROR_INSUFFICIENT_BUFFER) { - result.error = ::GetLastError(); - - break; - } - } - - SP_DEVINFO_DATA deviceInfoData; - ::ZeroMemory(&deviceInfoData, sizeof(deviceInfoData)); - deviceInfoData.cbSize = sizeof(deviceInfoData); - - QByteArray deviceInterfaceDetailDataBuffer( - deviceInterfaceDetailDataSize, 0); - - PSP_INTERFACE_DEVICE_DETAIL_DATA deviceInterfaceDetailData = - reinterpret_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA> - (deviceInterfaceDetailDataBuffer.data()); - - deviceInterfaceDetailData->cbSize = - sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); - - if (!::SetupDiGetDeviceInterfaceDetail( - deviceInfoHandle, - &deviceInterfaceData, - deviceInterfaceDetailData, - deviceInterfaceDetailDataBuffer.size(), - &deviceInterfaceDetailDataSize, - &deviceInfoData)) { - result.error = ::GetLastError(); - break; - } - - const QString systemPath = - deviceSystemPath(deviceInterfaceDetailData); - - const QBluetoothAddress address = parseRemoteAddress(systemPath); - if (address.isNull()) - continue; - - const QString friendlyName = - deviceFriendlyName(deviceInfoHandle, &deviceInfoData); - - const DeviceInfo info(address, friendlyName, systemPath); - result.devices.append(info); - - } - - ::SetupDiDestroyDeviceInfoList(deviceInfoHandle); - return result; -} - static QStringList availableSystemServices(const GUID &deviceInterface) { const DWORD flags = DIGCF_PRESENT; @@ -311,12 +177,6 @@ static QStringList availableSystemServices(const GUID &deviceInterface) return result; } -DeviceDiscoveryResult startDiscoveryOfRemoteDevices() -{ - return availableSystemInterfaces( - QUuid("781aee18-7733-4ce4-add0-91f41c67b592")); -} - ServicesDiscoveryResult startDiscoveryOfPrimaryServices( HANDLE hDevice) { diff --git a/src/bluetooth/windows/qwinlowenergybluetooth_p.h b/src/bluetooth/windows/qwinlowenergybluetooth_p.h index 08a99b38..adc8650e 100644 --- a/src/bluetooth/windows/qwinlowenergybluetooth_p.h +++ b/src/bluetooth/windows/qwinlowenergybluetooth_p.h @@ -157,23 +157,6 @@ typedef VOID (CALLBACK *PFNBLUETOOTH_GATT_EVENT_CALLBACK)( typedef ULONG64 BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, *PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT; -struct DeviceInfo -{ - DeviceInfo(const QBluetoothAddress &address, - const QString &name, - const QString &systemPath); - QBluetoothAddress address; - QString name; - QString systemPath; -}; - -struct DeviceDiscoveryResult -{ - DeviceDiscoveryResult(); - QList<DeviceInfo> devices; - DWORD error; -}; - struct ServicesDiscoveryResult { ServicesDiscoveryResult(); @@ -184,7 +167,6 @@ struct ServicesDiscoveryResult bool isSupported(); bool hasLocalRadio(); -DeviceDiscoveryResult startDiscoveryOfRemoteDevices(); ServicesDiscoveryResult startDiscoveryOfPrimaryServices(HANDLE hDevice); } // namespace WinLowEnergyBluetooth diff --git a/src/bluetooth/windows/windows.pri b/src/bluetooth/windows/windows.pri index 84e7200a..019d67e4 100644 --- a/src/bluetooth/windows/windows.pri +++ b/src/bluetooth/windows/windows.pri @@ -1,7 +1,5 @@ PRIVATE_HEADERS += \ - windows/qwinclassicbluetooth_p.h \ windows/qwinlowenergybluetooth_p.h SOURCES += \ - windows/qwinclassicbluetooth.cpp \ windows/qwinlowenergybluetooth.cpp |