diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2014-11-14 20:02:16 +0300 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2014-12-04 16:10:46 +0100 |
commit | 02b415fe5d538645e95896eb70c9d38628388841 (patch) | |
tree | 25d3fb823590559604fa2d3750bae7846299dac7 /src | |
parent | 3fa9606bc804f1bb81b45d04142dc2d9db6717bd (diff) |
Add discovering for BLE devices on Windows
BLE devices are supported in Windows 8 and above. Windows has not
public API to discovering/pairing of BLE devices. A user shall do
it by means of standard "bluetooth" application which are inbox into
Windows. Only after that there is an opportunity to display the
discovered devices.
Change-Id: Idd3d2949456a32c8c333744205755853aef80422
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/bluetooth.pro | 2 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_p.h | 23 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp | 215 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinlowenergybluetooth.cpp | 264 | ||||
-rw-r--r-- | src/bluetooth/windows/qwinlowenergybluetooth_p.h | 74 | ||||
-rw-r--r-- | src/bluetooth/windows/windows.pri | 6 |
6 files changed, 551 insertions, 33 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index fe00eec0..db8d2e21 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -209,7 +209,7 @@ config_bluez:qtHaveModule(dbus) { qbluetoothserver_win.cpp \ qlowenergycontroller_p.cpp - LIBS += -lbthprops + LIBS += -lbthprops -lsetupapi } else { message("Unsupported Bluetooth platform, will not build a working QtBluetooth library.") diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h index 096f013c..cb247943 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h @@ -79,6 +79,7 @@ QT_END_NAMESPACE #ifdef Q_OS_WIN32 #include <QtConcurrent> #include "windows/qwinclassicbluetooth_p.h" +#include "windows/qwinlowenergybluetooth_p.h" #endif QT_BEGIN_NAMESPACE @@ -185,6 +186,7 @@ private: #ifdef Q_OS_WIN32 private slots: void classicDeviceDiscovered(); + void lowEnergyDeviceDiscovered(); private: void initialize(const QBluetoothAddress &deviceAdapter); @@ -195,13 +197,34 @@ private: 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); + QFutureWatcher<WinClassicBluetooth::RemoteDeviceDiscoveryResult> *classicDiscoveryWatcher; + QFutureWatcher<WinLowEnergyBluetooth::DeviceDiscoveryResult> *lowEnergyDiscoveryWatcher; bool pendingCancel; bool pendingStart; bool isClassicActive; bool isClassicValid; + bool isLowEnergyActive; + bool isLowEnergyValid; #endif QBluetoothDeviceDiscoveryAgent *q_ptr; diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp index 53e4d5aa..5a550e57 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp @@ -55,10 +55,13 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( : 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); @@ -66,10 +69,14 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() { - if (isClassicActive) { + if (isClassicActive || isLowEnergyActive) stop(); + + if (classicDiscoveryWatcher) classicDiscoveryWatcher->waitForFinished(); - } + + if (lowEnergyDiscoveryWatcher) + lowEnergyDiscoveryWatcher->waitForFinished(); } bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const @@ -79,12 +86,12 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const if (pendingCancel) return false; - return isClassicActive; + return isClassicActive || isLowEnergyActive; } void QBluetoothDeviceDiscoveryAgentPrivate::start() { - if (!isClassicValid) { + if (!isClassicValid && !isLowEnergyValid) { setError(ERROR_INVALID_HANDLE, QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device.")); return; @@ -97,12 +104,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start() discoveredDevices.clear(); - startDiscoveryForFirstClassicDevice(); + if (isClassicValid) + startDiscoveryForFirstClassicDevice(); + + if (isLowEnergyValid) + startDiscoveryForLowEnergyDevices(); } void QBluetoothDeviceDiscoveryAgentPrivate::stop() { - if (!isClassicActive) + if (!isClassicActive && !isLowEnergyActive) return; pendingCancel = true; @@ -111,21 +122,15 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop() void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceDiscovered() { - Q_Q(QBluetoothDeviceDiscoveryAgent); - const WinClassicBluetooth::RemoteDeviceDiscoveryResult result = classicDiscoveryWatcher->result(); - if (result.error == ERROR_SUCCESS - || result.error == ERROR_NO_MORE_ITEMS) { + if (isDiscoveredSuccessfully(result.error)) { - if (pendingCancel && !pendingStart) { - emit q->canceled(); - pendingCancel = false; - } else if (pendingStart) { - pendingCancel = false; - pendingStart = false; - start(); + if (canBeCanceled()) { + cancel(); + } else if (canBePendingStarted()) { + prepareToPendingStart(); } else { if (result.error != ERROR_NO_MORE_ITEMS) { acceptDiscoveredClassicDevice(result.device); @@ -135,18 +140,40 @@ void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceDiscovered() } } else { - setError(result.error); - pendingCancel = false; - pendingStart = false; + drop(result.error); } completeClassicDiscovery(result.hSearch); } +void QBluetoothDeviceDiscoveryAgentPrivate::lowEnergyDeviceDiscovered() +{ + 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); + } + + } else { + drop(result.error); + } + + completeLowEnergyDiscovery(); +} + void QBluetoothDeviceDiscoveryAgentPrivate::initialize( const QBluetoothAddress &deviceAdapter) { isClassicValid = isClassicAdapterValid(deviceAdapter); + isLowEnergyValid = isLowEnergyAdapterValid(deviceAdapter); } bool QBluetoothDeviceDiscoveryAgentPrivate::isClassicAdapterValid( @@ -155,8 +182,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isClassicAdapterValid( const WinClassicBluetooth::LocalRadiosDiscoveryResult result = WinClassicBluetooth::enumerateLocalRadios(); - if (result.error != NO_ERROR - && result.error != ERROR_NO_MORE_ITEMS) { + if (!isDiscoveredSuccessfully(result.error)) { qCWarning(QT_BT_WINDOWS) << "Occurred error during search of classic local radios"; return false; } else if (result.radios.isEmpty()) { @@ -166,7 +192,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isClassicAdapterValid( foreach (const BLUETOOTH_RADIO_INFO &radio, result.radios) { if (deviceAdapter == QBluetoothAddress() - || deviceAdapter == QBluetoothAddress(radio.address.ullLong)) { + || deviceAdapter == QBluetoothAddress(radio.address.ullLong)) { return true; } } @@ -204,18 +230,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startDiscoveryForNextClassicDevice( void QBluetoothDeviceDiscoveryAgentPrivate::completeClassicDiscovery( HBLUETOOTH_DEVICE_FIND hSearch) { - Q_Q(QBluetoothDeviceDiscoveryAgent); - WinClassicBluetooth::cancelRemoteDevicesDiscovery(hSearch); isClassicActive = false; - emit q->finished(); + finalize(); } void QBluetoothDeviceDiscoveryAgentPrivate::acceptDiscoveredClassicDevice( const BLUETOOTH_DEVICE_INFO &device) { - Q_Q(QBluetoothDeviceDiscoveryAgent); - QBluetoothDeviceInfo deviceInfo( QBluetoothAddress(device.Address.ullLong), QString::fromWCharArray(device.szName), @@ -224,8 +246,89 @@ void QBluetoothDeviceDiscoveryAgentPrivate::acceptDiscoveredClassicDevice( if (device.fRemembered) deviceInfo.setCached(true); - discoveredDevices.append(deviceInfo); - emit q->deviceDiscovered(deviceInfo); + processDuplicates(deviceInfo); +} + +bool QBluetoothDeviceDiscoveryAgentPrivate::isLowEnergyAdapterValid( + const QBluetoothAddress &deviceAdapter) +{ + 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(); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::startDiscoveryForLowEnergyDevices() +{ + isLowEnergyActive = true; + + if (!lowEnergyDiscoveryWatcher) { + lowEnergyDiscoveryWatcher = new QFutureWatcher< + WinLowEnergyBluetooth::DeviceDiscoveryResult>(this); + QObject::connect(lowEnergyDiscoveryWatcher, SIGNAL(finished()), + this, SLOT(lowEnergyDeviceDiscovered())); + } + + const QFuture<WinLowEnergyBluetooth::DeviceDiscoveryResult> future = + QtConcurrent::run(WinLowEnergyBluetooth::startDiscoveryOfRemoteDevices); + lowEnergyDiscoveryWatcher->setFuture(future); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::completeLowEnergyDiscovery() +{ + isLowEnergyActive = false; + finalize(); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::acceptDiscoveredLowEnergyDevice( + const WinLowEnergyBluetooth::DeviceInfo &device) +{ + QBluetoothDeviceInfo deviceInfo(device.address, device.name, 0); + deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + deviceInfo.setCached(true); + + processDuplicates(deviceInfo); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::processDuplicates( + 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()) { + qCDebug(QT_BT_WINDOWS) << "Duplicate: " << foundDevice.address(); + return; + } + + // We assume that if the existing device it is low energy, it means that + // the found device should be as classic, because it is impossible to get + // same low energy device. + if (mergedDevice.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) + mergedDevice = foundDevice; + + // We assume that it is impossible to have multiple devices with same core + // configurations, which have one address. This possible only in case a device + // provided both low energy and classic features at the same time. + mergedDevice.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); + mergedDevice.setCached(foundDevice.isCached()); + + discoveredDevices.replace(i, mergedDevice); + Q_Q(QBluetoothDeviceDiscoveryAgent); + qCDebug(QT_BT_WINDOWS) << "Updated: " << mergedDevice.address(); + + emit q->deviceDiscovered(mergedDevice); + return; + } + } + + qCDebug(QT_BT_WINDOWS) << "Emit: " << foundDevice.address(); + discoveredDevices.append(foundDevice); + emit q->deviceDiscovered(foundDevice); } void QBluetoothDeviceDiscoveryAgentPrivate::setError(DWORD error, const QString &str) @@ -239,4 +342,56 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(DWORD error, const QString 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/windows/qwinlowenergybluetooth.cpp b/src/bluetooth/windows/qwinlowenergybluetooth.cpp new file mode 100644 index 00000000..f4f34e42 --- /dev/null +++ b/src/bluetooth/windows/qwinlowenergybluetooth.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** 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 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 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. +** +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinlowenergybluetooth_p.h" + +#include <QtCore/quuid.h> + +QT_BEGIN_NAMESPACE + +namespace WinLowEnergyBluetooth { + +static QString deviceRegistryProperty( + HDEVINFO deviceInfoHandle, + const PSP_DEVINFO_DATA deviceInfoData, + DWORD registryProperty) +{ + DWORD propertyRegDataType = 0; + DWORD propertyBufferSize = 0; + QByteArray propertyBuffer; + + while (!::SetupDiGetDeviceRegistryProperty( + deviceInfoHandle, + deviceInfoData, + registryProperty, + &propertyRegDataType, + 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(); + } + + propertyBuffer.fill(0, propertyBufferSize * sizeof(WCHAR)); + } + + return QString::fromWCharArray( + 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) +{ + return deviceRegistryProperty( + 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) +{ +} + +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; + const HDEVINFO deviceInfoHandle = ::SetupDiGetClassDevs( + &deviceInterface, NULL, 0, flags); + + if (deviceInfoHandle == INVALID_HANDLE_VALUE) + return QStringList(); + + SP_DEVINFO_DATA deviceInfoData; + ::memset(&deviceInfoData, 0, sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + + DWORD index = 0; + QStringList result; + + while (::SetupDiEnumDeviceInfo( + deviceInfoHandle, index++, &deviceInfoData)) { + + const QString service = deviceService(deviceInfoHandle, &deviceInfoData); + if (service.isEmpty()) + continue; + + result.append(service); + } + + ::SetupDiDestroyDeviceInfoList(deviceInfoHandle); + return result; +} + +DeviceDiscoveryResult startDiscoveryOfRemoteDevices() +{ + return availableSystemInterfaces( + QUuid("781aee18-7733-4ce4-add0-91f41c67b592")); +} + +bool hasLocalRadio() +{ + const QStringList systemServices = + availableSystemServices( + QUuid("e0cbf06c-cd8b-4647-bb8a-263b43f0f974")); + + return systemServices.contains(QStringLiteral("BthLEEnum")); +} + +} // namespace WinLowEnergyBluetooth + +QT_END_NAMESPACE diff --git a/src/bluetooth/windows/qwinlowenergybluetooth_p.h b/src/bluetooth/windows/qwinlowenergybluetooth_p.h new file mode 100644 index 00000000..aa9127a4 --- /dev/null +++ b/src/bluetooth/windows/qwinlowenergybluetooth_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** 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 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 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. +** +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINLOWENERGYBLUETOOTH_P_H +#define QWINLOWENERGYBLUETOOTH_P_H + +#include <QtCore/qstringlist.h> + +#include <QtBluetooth/qbluetoothaddress.h> + +#include <qt_windows.h> +#include <setupapi.h> + +QT_BEGIN_NAMESPACE + +namespace WinLowEnergyBluetooth { + +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; +}; + +bool hasLocalRadio(); + +DeviceDiscoveryResult startDiscoveryOfRemoteDevices(); + +} // namespace WinLowEnergyBluetooth + +QT_END_NAMESPACE + +#endif // QWINLOWENERGYBLUETOOTH_P_H diff --git a/src/bluetooth/windows/windows.pri b/src/bluetooth/windows/windows.pri index f08e0497..84e7200a 100644 --- a/src/bluetooth/windows/windows.pri +++ b/src/bluetooth/windows/windows.pri @@ -1,5 +1,7 @@ PRIVATE_HEADERS += \ - windows/qwinclassicbluetooth_p.h + windows/qwinclassicbluetooth_p.h \ + windows/qwinlowenergybluetooth_p.h SOURCES += \ - windows/qwinclassicbluetooth.cpp + windows/qwinclassicbluetooth.cpp \ + windows/qwinlowenergybluetooth.cpp |