summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-06-22 03:00:45 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-06-22 03:00:45 +0200
commitd13960846930c5782df3aa01aaa28e202c4b2c34 (patch)
tree4f8e64ddf234c0157c05236f1df328f117242406
parenteb78e559661ac86715d7546d28a88160acb8ec30 (diff)
parentb96ed240e7479641b9dc4feb0aee4f002228a21e (diff)
Merge remote-tracking branch 'origin/5.13' into dev
-rw-r--r--dist/changes-5.13.059
-rw-r--r--src/bluetooth/bluetooth.pro2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.cpp10
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h36
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_winrt.cpp202
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new.cpp509
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new_p.h34
7 files changed, 626 insertions, 226 deletions
diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0
new file mode 100644
index 00000000..921b45a9
--- /dev/null
+++ b/dist/changes-5.13.0
@@ -0,0 +1,59 @@
+Qt 5.13 introduces many new features and improvements as well as bugfixes
+over the 5.12.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.13 series is binary compatible with the 5.12.x series.
+Applications compiled for 5.12 will continue to run with 5.13.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.13.0 Changes *
+****************************************************************************
+
+QtBluetooth
+-----------
+
+ - [QTBUG-58660] Added ability to connect to BLE devices on WinRT without
+ pairing.
+
+ - [QTBUG-69954] Fixed potential crash due to late callbacks on WinRT.
+
+ - Improved WinRT implementation signficantly. This incorporates a large
+ number of patches (each improving the stability and general robustness of
+ the code base). During the process the number of potential asserts was
+ reduced as well.
+
+ - Deprecated QBluetoothDeviceInfo::DataCompleteness related APIs.
+
+ - Replaced QBluetoothDeviceInfo::LanAccessDevice with QBluetoothDeviceInfo::NetworkDevice.
+ LanAccessDevice was deprecated.
+
+ - Implemented support for QBluetoothDeviceDiscoveryAgent::deviceUpdated() on Apple and WinRT
+ platforms.
+
+ - [QTBUG-71943] Implemented RSSI and manufacturer data discovery on WinRT.
+
+ - [QTBUG-74394] Fixed broken QLowEnergyController::disconnectFromDevice() on WinRT.
+
+ - Added a compile fix for g++ 8.
+
+ - [QTBUG-73717] Fixed warnings in QDeclarativeBluetoothDiscoveryModel.
+
+QtNfc
+-----
+
+ - QNearFieldManager:
+ * adapterStateChanged() now has a fully qualified parameter
+ QNearFieldManager::AdapterState. This can cause a problem if the
+ connection/method invocation was done with just AdapterState as the
+ parameter type, in which case these need to be changed to use
+ QNearFieldManager::AdapaterState instead.
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index d2b711d9..974d8e8a 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -211,7 +211,7 @@ qtConfig(bluez) {
SOURCES += \
qbluetoothdevicediscoveryagent_winrt.cpp \
- qbluetoothlocaldevice_p.cpp \
+ qbluetoothlocaldevice_winrt.cpp \
qbluetoothserver_winrt.cpp \
qbluetoothservicediscoveryagent_winrt.cpp \
qbluetoothserviceinfo_winrt.cpp \
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.cpp b/src/bluetooth/qbluetoothlocaldevice_p.cpp
index 793a8311..fa4a509e 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_p.cpp
@@ -51,7 +51,7 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
QObject(parent),
d_ptr(new QBluetoothLocalDevicePrivate(this, QBluetoothAddress()))
{
-#if !defined(QT_IOS_BLUETOOTH) && !defined(QT_WINRT_BLUETOOTH)
+#if !defined(QT_IOS_BLUETOOTH)
printDummyWarning();
#endif
registerQBluetoothLocalDeviceMetaType();
@@ -85,11 +85,7 @@ void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
{
-#ifdef QT_WINRT_BLUETOOTH
- return HostConnectable;
-#else
return HostPoweredOff;
-#endif
}
QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
@@ -116,11 +112,7 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
const QBluetoothAddress &address) const
{
Q_UNUSED(address);
-#ifdef QT_WINRT_BLUETOOTH
- return Paired;
-#else
return Unpaired;
-#endif
}
void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index 98c62151..8f3e2b43 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -84,6 +84,21 @@ QT_END_NAMESPACE
#include <QtCore/QPair>
#endif
+#ifdef QT_WINRT_BLUETOOTH
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ struct IBluetoothDeviceStatics;
+ struct IBluetoothLEDeviceStatics;
+ }
+ }
+ }
+}
+#endif
+
QT_BEGIN_NAMESPACE
extern void registerQBluetoothLocalDeviceMetaType();
@@ -208,7 +223,22 @@ private:
void initializeAdapter();
void initializeAdapterBluez5();
};
-#elif !defined(QT_OSX_BLUETOOTH) // winrt and dummy backend
+#elif defined(QT_WINRT_BLUETOOTH)
+class QBluetoothLocalDevicePrivate : public QObject
+{
+ Q_DECLARE_PUBLIC(QBluetoothLocalDevice)
+public:
+ QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
+ QBluetoothAddress = QBluetoothAddress());
+
+ bool isValid() const;
+
+private:
+ QBluetoothLocalDevice *q_ptr;
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothDeviceStatics> mStatics;
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics> mLEStatics;
+};
+#elif !defined(QT_OSX_BLUETOOTH) // dummy backend
class QBluetoothLocalDevicePrivate : public QObject
{
public:
@@ -219,11 +249,7 @@ public:
bool isValid() const
{
-#ifndef QT_WINRT_BLUETOOTH
return false;
-#else
- return true;
-#endif
}
};
#endif
diff --git a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
new file mode 100644
index 00000000..ae794db0
--- /dev/null
+++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothlocaldevice.h"
+#include "qbluetoothaddress.h"
+
+#include "qbluetoothlocaldevice_p.h"
+
+#ifdef CLASSIC_APP_BUILD
+#define Q_OS_WINRT
+#endif
+#include <QtCore/qfunctions_winrt.h>
+
+#include <robuffer.h>
+#include <windows.devices.bluetooth.h>
+#include <wrl.h>
+
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Devices::Bluetooth;
+using namespace ABI::Windows::Devices::Enumeration;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+QT_BEGIN_NAMESPACE
+
+template <class DeviceStatics, class OpResult, class Device, class Device2>
+ComPtr<IDeviceInformationPairing> getPairingInfo(ComPtr<DeviceStatics> deviceStatics,
+ const QBluetoothAddress &address)
+{
+ ComPtr<IAsyncOperation<OpResult *>> op;
+ if (!deviceStatics)
+ return nullptr;
+ HRESULT hr = deviceStatics->FromBluetoothAddressAsync(address.toUInt64(), &op);
+ RETURN_IF_FAILED("Could not obtain device from address", return nullptr);
+ ComPtr<Device> device;
+ hr = QWinRTFunctions::await(op, device.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000);
+ if (FAILED(hr) || !device) {
+ qErrnoWarning("Could not obtain device from address");
+ return nullptr;
+ }
+ ComPtr<Device2> device2;
+ hr = device.As(&device2);
+ RETURN_IF_FAILED("Could not cast device", return nullptr);
+ ComPtr<IDeviceInformation> deviceInfo;
+ hr = device2->get_DeviceInformation(&deviceInfo);
+ if (FAILED(hr) || !deviceInfo) {
+ qErrnoWarning("Could not obtain device information");
+ return nullptr;
+ }
+ ComPtr<IDeviceInformation2> deviceInfo2;
+ hr = deviceInfo.As(&deviceInfo2);
+ RETURN_IF_FAILED("Could not cast device information", return nullptr);
+ ComPtr<IDeviceInformationPairing> pairingInfo;
+ hr = deviceInfo2->get_Pairing(&pairingInfo);
+ RETURN_IF_FAILED("Could not obtain pairing information", return nullptr);
+ return pairingInfo;
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, QBluetoothAddress()))
+{
+ registerQBluetoothLocalDeviceMetaType();
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent) :
+ QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, address))
+{
+ registerQBluetoothLocalDeviceMetaType();
+}
+
+QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress)
+ : q_ptr(q)
+{
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &mLEStatics);
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &mStatics);
+}
+
+bool QBluetoothLocalDevicePrivate::isValid() const
+{
+ return (mStatics != nullptr && mLEStatics != nullptr);
+}
+
+void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
+{
+ Q_UNUSED(address);
+ Q_UNUSED(pairing);
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+}
+
+QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
+ const QBluetoothAddress &address) const
+{
+ if (!isValid() || address.isNull())
+ return QBluetoothLocalDevice::Unpaired;
+
+ ComPtr<IDeviceInformationPairing> pairingInfo = getPairingInfo<IBluetoothLEDeviceStatics,
+ BluetoothLEDevice, IBluetoothLEDevice, IBluetoothLEDevice2>(d_ptr->mLEStatics, address);
+ if (!pairingInfo)
+ pairingInfo = getPairingInfo<IBluetoothDeviceStatics, BluetoothDevice,
+ IBluetoothDevice, IBluetoothDevice2>(d_ptr->mStatics, address);
+ if (!pairingInfo)
+ return QBluetoothLocalDevice::Unpaired;
+ boolean isPaired;
+ HRESULT hr = pairingInfo->get_IsPaired(&isPaired);
+ RETURN_IF_FAILED("Could not obtain device pairing", return QBluetoothLocalDevice::Unpaired);
+ if (!isPaired)
+ return QBluetoothLocalDevice::Unpaired;
+
+ ComPtr<IDeviceInformationPairing2> pairingInfo2;
+ hr = pairingInfo.As(&pairingInfo2);
+ RETURN_IF_FAILED("Could not cast pairing info", return QBluetoothLocalDevice::Paired);
+ DevicePairingProtectionLevel protection = DevicePairingProtectionLevel_None;
+ hr = pairingInfo2->get_ProtectionLevel(&protection);
+ RETURN_IF_FAILED("Could not obtain pairing protection level", return QBluetoothLocalDevice::Paired);
+ if (protection == DevicePairingProtectionLevel_Encryption
+ || protection == DevicePairingProtectionLevel_EncryptionAndAuthentication)
+ return QBluetoothLocalDevice::AuthorizedPaired;
+ return QBluetoothLocalDevice::Paired;
+}
+
+void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
+{
+ Q_UNUSED(confirmation);
+}
+
+void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
+{
+ Q_UNUSED(mode);
+}
+
+QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
+{
+ return HostConnectable;
+}
+
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ return QList<QBluetoothAddress>();
+}
+
+void QBluetoothLocalDevice::powerOn()
+{
+}
+
+QString QBluetoothLocalDevice::name() const
+{
+ return QString();
+}
+
+QBluetoothAddress QBluetoothLocalDevice::address() const
+{
+ return QBluetoothAddress();
+}
+
+QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
+{
+ QList<QBluetoothHostInfo> localDevices;
+ return localDevices;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
index 45a80252..bb9894ff 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
@@ -41,6 +41,7 @@
#include "qlowenergycontroller_winrt_p.h"
#include "qbluetoothutils_winrt_p.h"
+#include <QtBluetooth/qbluetoothlocaldevice.h>
#include <QtBluetooth/QLowEnergyCharacteristicData>
#include <QtBluetooth/QLowEnergyDescriptorData>
#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
@@ -57,6 +58,7 @@
#include <robuffer.h>
#include <windows.devices.enumeration.h>
#include <windows.devices.bluetooth.h>
+#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <windows.foundation.collections.h>
#include <windows.foundation.metadata.h>
#include <windows.storage.streams.h>
@@ -91,15 +93,18 @@ typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharCo
continue; \
}
-#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret) \
if (FAILED(hr)) { \
qCWarning(QT_BT_WINRT) << msg; \
- unregisterFromStatusChanges(); \
- setError(QLowEnergyController::ConnectionError); \
- setState(QLowEnergyController::UnconnectedState); \
+ this->unregisterFromStatusChanges(); \
+ this->setError(QLowEnergyController::ConnectionError); \
+ this->setState(QLowEnergyController::UnconnectedState); \
ret; \
}
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
+ CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret)
+
#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret) \
if (FAILED(hr)) { \
qCDebug(QT_BT_WINRT) << msg; \
@@ -436,6 +441,7 @@ QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew()
{
unregisterFromStatusChanges();
unregisterFromValueChanges();
+ mAbortPending = true;
}
void QLowEnergyControllerPrivateWinRTNew::init()
@@ -445,6 +451,7 @@ void QLowEnergyControllerPrivateWinRTNew::init()
void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
{
qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ mAbortPending = false;
Q_Q(QLowEnergyController);
if (remoteDevice.isNull()) {
qWarning() << "Invalid/null remote device address";
@@ -473,138 +480,18 @@ void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
BluetoothConnectionStatus status;
hr = mDevice->get_ConnectionStatus(&status);
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain device's connection status", return)
- hr = QEventDispatcherWinRT::runOnXamlThread([this, q]() {
- HRESULT hr;
- hr = mDevice->add_ConnectionStatusChanged(
- Callback<StatusHandler>([this, q](IBluetoothLEDevice *dev, IInspectable *) {
- BluetoothConnectionStatus status;
- HRESULT hr;
- hr = dev->get_ConnectionStatus(&status);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain connection status", return S_OK)
- if (state == QLowEnergyController::ConnectingState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- } else if (state != QLowEnergyController::UnconnectedState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
- invalidateServices();
- unregisterFromValueChanges();
- unregisterFromStatusChanges();
- mDevice = nullptr;
- setError(QLowEnergyController::RemoteHostClosedError);
- setState(QLowEnergyController::UnconnectedState);
- emit q->disconnected();
- }
- return S_OK;
- }).Get(), &mStatusChangedToken);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register connection status callback", return S_OK)
- return S_OK;
- });
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not add status callback on Xaml thread", return)
-
if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
setState(QLowEnergyController::ConnectedState);
emit q->connected();
return;
}
- ComPtr<IBluetoothLEDevice3> device3;
- hr = mDevice.As(&device3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
- hr = device3->GetGattServicesAsync(&deviceServicesOp);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
- ComPtr<IGattDeviceServicesResult> deviceServicesResult;
- hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
-
- GattCommunicationStatus commStatus;
- hr = deviceServicesResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT()) << "Service operation failed";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- unregisterFromStatusChanges();
- return;
- }
-
- ComPtr<IVectorView <GattDeviceService *>> deviceServices;
- hr = deviceServicesResult->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain list of services", return)
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service count", return)
-
- // Windows automatically connects to the device as soon as a service value is read/written.
- // Thus we read one value in order to establish the connection.
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
- ComPtr<IGattDeviceService3> service3;
- hr = service.As(&service3);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not cast service");
- ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
- hr = service3->GetCharacteristicsAsync(&characteristicsOp);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic");
- ComPtr<IGattCharacteristicsResult> characteristicsResult;
- hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await characteristic operation");
- GattCommunicationStatus commStatus;
- hr = characteristicsResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Characteristic operation failed";
- continue;
- }
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = characteristicsResult->get_Characteristics(&characteristics);
- if (hr == E_ACCESSDENIED) {
- // Everything will work as expected up until this point if the manifest capabilties
- // for bluetooth LE are not set.
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
- "manifest capabilities";
- setState(QLowEnergyController::UnconnectedState);
- setError(QLowEnergyController::ConnectionError);
- unregisterFromStatusChanges();
- return;
- }
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic list");
- uint characteristicsCount;
- hr = characteristics->get_Size(&characteristicsCount);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic list's size");
- for (uint j = 0; j < characteristicsCount; ++j) {
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(j, &characteristic);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic");
- ComPtr<IAsyncOperation<GattReadResult *>> op;
- GattCharacteristicProperties props;
- hr = characteristic->get_CharacteristicProperties(&props);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic's properties");
- if (!(props & GattCharacteristicProperties_Read))
- continue;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read characteristic value");
- ComPtr<IGattReadResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf());
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could await characteristic read");
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- hr = result->get_Value(&buffer);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic value");
- if (!buffer) {
- qCDebug(QT_BT_WINRT) << "Problem reading value";
- continue;
- }
- return;
- }
- }
-
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic read result that triggers"
- "device connection. Is the device reachable?";
- unregisterFromStatusChanges();
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
+ QBluetoothLocalDevice localDevice;
+ QBluetoothLocalDevice::Pairing pairing = localDevice.pairingStatus(remoteDevice);
+ if (pairing == QBluetoothLocalDevice::Unpaired)
+ connectToUnpairedDevice();
+ else
+ connectToPairedDevice();
}
void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
@@ -614,6 +501,7 @@ void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
setState(QLowEnergyController::ClosingState);
unregisterFromValueChanges();
unregisterFromStatusChanges();
+ mAbortPending = true;
mDevice = nullptr;
setState(QLowEnergyController::UnconnectedState);
emit q->disconnected();
@@ -691,18 +579,8 @@ void QLowEnergyControllerPrivateWinRTNew::registerForValueChanges(const QBluetoo
EventRegistrationToken token;
HRESULT hr;
hr = characteristic->add_ValueChanged(
- Callback<ValueChangedHandler>(
- [this](IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args) {
- HRESULT hr;
- quint16 handle;
- hr = characteristic->get_AttributeHandle(&handle);
- RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
- ComPtr<IBuffer> buffer;
- hr = args->get_CharacteristicValue(&buffer);
- RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
- characteristicChanged(handle, byteArrayFromBuffer(buffer));
- return S_OK;
- }).Get(), &token);
+ Callback<ValueChangedHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onValueChange).Get(),
+ &token);
RETURN_IF_FAILED("Could not register characteristic for value changes", return)
mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service"
@@ -726,6 +604,39 @@ void QLowEnergyControllerPrivateWinRTNew::unregisterFromValueChanges()
mValueChangedTokens.clear();
}
+HRESULT QLowEnergyControllerPrivateWinRTNew::onValueChange(IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args)
+{
+ HRESULT hr;
+ quint16 handle;
+ hr = characteristic->get_AttributeHandle(&handle);
+ RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
+ ComPtr<IBuffer> buffer;
+ hr = args->get_CharacteristicValue(&buffer);
+ RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
+ characteristicChanged(handle, byteArrayFromBuffer(buffer));
+ return S_OK;
+}
+
+bool QLowEnergyControllerPrivateWinRTNew::registerForStatusChanges()
+{
+ if (!mDevice)
+ return false;
+
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = mDevice->add_ConnectionStatusChanged(
+ Callback<StatusHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onStatusChange).Get(),
+ &mStatusChangedToken);
+ RETURN_IF_FAILED("Could not register connection status callback", return hr)
+ return S_OK;
+ });
+ RETURN_FALSE_IF_FAILED("Could not add status callback on Xaml thread")
+ return true;
+}
+
void QLowEnergyControllerPrivateWinRTNew::unregisterFromStatusChanges()
{
qCDebug(QT_BT_WINRT) << __FUNCTION__;
@@ -735,6 +646,30 @@ void QLowEnergyControllerPrivateWinRTNew::unregisterFromStatusChanges()
}
}
+HRESULT QLowEnergyControllerPrivateWinRTNew::onStatusChange(IBluetoothLEDevice *dev, IInspectable *)
+{
+ Q_Q(QLowEnergyController);
+ BluetoothConnectionStatus status;
+ HRESULT hr;
+ hr = dev->get_ConnectionStatus(&status);
+ RETURN_IF_FAILED("Could not obtain connection status", return S_OK)
+ if (state == QLowEnergyController::ConnectingState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ } else if (state != QLowEnergyController::UnconnectedState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
+ invalidateServices();
+ unregisterFromValueChanges();
+ unregisterFromStatusChanges();
+ mDevice = nullptr;
+ setError(QLowEnergyController::RemoteHostClosedError);
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+ }
+ return S_OK;
+}
+
void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
QSharedPointer<QLowEnergyServicePrivate> servicePointer,
ComPtr<IGattDeviceService> service)
@@ -791,10 +726,68 @@ void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
}
}
-void QLowEnergyControllerPrivateWinRTNew::discoverServices()
+HRESULT QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
{
Q_Q(QLowEnergyController);
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain services";
+ return S_OK;
+ }
+ ComPtr<IGattDeviceServicesResult> result;
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ HRESULT hr = op->GetResults(&result);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
+ return S_OK);
+ GattCommunicationStatus commStatus;
+ hr = result->get_Status(&commStatus);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
+ return S_OK);
+ if (commStatus != GattCommunicationStatus_Success)
+ return S_OK;
+ hr = result->get_Services(&deviceServices);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
+ return S_OK);
+
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
+ return S_OK);
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> deviceService;
+ hr = deviceServices->GetAt(i, &deviceService);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
+ GUID guuid;
+ hr = deviceService->get_Uuid(&guuid);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
+ const QBluetoothUuid service(guuid);
+
+ QSharedPointer<QLowEnergyServicePrivate> pointer;
+ if (serviceList.contains(service)) {
+ pointer = serviceList.value(service);
+ } else {
+ QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
+ priv->uuid = service;
+ priv->setController(this);
+
+ pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
+ serviceList.insert(service, pointer);
+ }
+ pointer->type |= QLowEnergyService::PrimaryService;
+
+ obtainIncludedServices(pointer, deviceService);
+
+ emit q->serviceDiscovered(service);
+ }
+
+ setState(QLowEnergyController::DiscoveredState);
+ emit q->discoveryFinished();
+
+ return S_OK;
+}
+
+void QLowEnergyControllerPrivateWinRTNew::discoverServices()
+{
qCDebug(QT_BT_WINRT) << "Service discovery initiated";
ComPtr<IBluetoothLEDevice3> device3;
@@ -803,67 +796,10 @@ void QLowEnergyControllerPrivateWinRTNew::discoverServices()
ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
hr = device3->GetGattServicesAsync(&asyncResult);
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return);
- hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, q, this] () {
+ hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, this] () {
HRESULT hr = asyncResult->put_Completed(
Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
- [this, q](IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *> *op,
- AsyncStatus status) {
- if (status != AsyncStatus::Completed) {
- qCDebug(QT_BT_WINRT) << "Could not obtain services";
- return S_OK;
- }
- ComPtr<IGattDeviceServicesResult> result;
- ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- HRESULT hr = op->GetResults(&result);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
- return S_OK);
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
- return S_OK);
- if (commStatus != GattCommunicationStatus_Success)
- return S_OK;
-
- hr = result->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
- return S_OK);
-
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
- return S_OK);
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> deviceService;
- hr = deviceServices->GetAt(i, &deviceService);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
- GUID guuid;
- hr = deviceService->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
- const QBluetoothUuid service(guuid);
-
- QSharedPointer<QLowEnergyServicePrivate> pointer;
- if (serviceList.contains(service)) {
- pointer = serviceList.value(service);
- } else {
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = service;
- priv->setController(this);
-
- pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
- serviceList.insert(service, pointer);
- }
- pointer->type |= QLowEnergyService::PrimaryService;
-
- obtainIncludedServices(pointer, deviceService);
-
- emit q->serviceDiscovered(service);
- }
-
- setState(QLowEnergyController::DiscoveredState);
- emit q->discoveryFinished();
-
- return S_OK;
- }).Get());
+ this, &QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished).Get());
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register service discovery callback",
return S_OK)
return hr;
@@ -1305,7 +1241,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could write characteristic",
service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- auto writeCompletedLambda =[charData, charHandle, newValue, service, writeWithResponse, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charData, charHandle, newValue, service, writeWithResponse, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1332,7 +1269,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
// only update cache when property is readable. Otherwise it remains
// empty.
if (charData.properties & QLowEnergyCharacteristic::Read)
- updateValueOfCharacteristic(charHandle, newValue, false);
+ thisPtr->updateValueOfCharacteristic(charHandle, newValue, false);
if (writeWithResponse)
emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle),
newValue);
@@ -1412,7 +1349,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
HRESULT hr = characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write client characteristic configuration",
service, QLowEnergyService::DescriptorWriteError, return S_OK)
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1430,7 +1368,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
newValue);
return S_OK;
@@ -1505,7 +1443,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write descriptor value",
service, QLowEnergyService::DescriptorWriteError, return S_OK)
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1523,7 +1462,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
newValue);
return S_OK;
@@ -1583,6 +1522,160 @@ void QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError(const QStrin
setError(QLowEnergyController::ConnectionError);
}
+void QLowEnergyControllerPrivateWinRTNew::connectToPairedDevice()
+{
+ Q_Q(QLowEnergyController);
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ while (!mAbortPending) {
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT()) << "Service operation failed";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ ComPtr<IVectorView <GattDeviceService *>> deviceServices;
+ hr = deviceServicesResult->get_Services(&deviceServices);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain list of services", return)
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service count", return)
+
+ if (serviceCount == 0) {
+ qCWarning(QT_BT_WINRT()) << "Found devices without services";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ // Windows automatically connects to the device as soon as a service value is read/written.
+ // Thus we read one value in order to establish the connection.
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> service;
+ hr = deviceServices->GetAt(i, &service);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service", return);
+ ComPtr<IGattDeviceService3> service3;
+ hr = service.As(&service3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast service", return);
+ ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
+ hr = service3->GetCharacteristicsAsync(&characteristicsOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
+ ComPtr<IGattCharacteristicsResult> characteristicsResult;
+ hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic operation", return);
+ GattCommunicationStatus commStatus;
+ hr = characteristicsResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT) << "Characteristic operation failed";
+ break;
+ }
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = characteristicsResult->get_Characteristics(&characteristics);
+ if (hr == E_ACCESSDENIED) {
+ // Everything will work as expected up until this point if the manifest capabilties
+ // for bluetooth LE are not set.
+ qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
+ "manifest capabilities";
+ setState(QLowEnergyController::UnconnectedState);
+ setError(QLowEnergyController::ConnectionError);
+ unregisterFromStatusChanges();
+ return;
+ }
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list", return);
+ uint characteristicsCount;
+ hr = characteristics->get_Size(&characteristicsCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list's size", return);
+ for (uint j = 0; j < characteristicsCount; ++j) {
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(j, &characteristic);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
+ ComPtr<IAsyncOperation<GattReadResult *>> op;
+ GattCharacteristicProperties props;
+ hr = characteristic->get_CharacteristicProperties(&props);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic's properties", return);
+ if (!(props & GattCharacteristicProperties_Read))
+ continue;
+ hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not read characteristic value", return);
+ ComPtr<IGattReadResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessThreadEvents, 500);
+ // E_ILLEGAL_METHOD_CALL will be the result for a device, that is not reachable at
+ // the moment. In this case we should jump back into the outer loop and keep trying.
+ if (hr == E_ILLEGAL_METHOD_CALL)
+ break;
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic read", return);
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ hr = result->get_Value(&buffer);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic value", return);
+ if (!buffer) {
+ qCDebug(QT_BT_WINRT) << "Problem reading value";
+ break;
+ }
+
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ if (!registerForStatusChanges()) {
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ return;
+ }
+ }
+ }
+}
+
+void QLowEnergyControllerPrivateWinRTNew::connectToUnpairedDevice()
+{
+ if (!registerForStatusChanges()) {
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ while (!mAbortPending) {
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (commStatus == GattCommunicationStatus_Unreachable)
+ continue;
+
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT()) << "Service operation failed";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ break;
+ }
+}
+
QT_END_NAMESPACE
#include "qlowenergycontroller_winrt_new.moc"
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
index bf409745..8cc5f9ce 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h
+++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
@@ -60,8 +60,28 @@
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ namespace GenericAttributeProfile {
+ class GattDeviceServicesResult;
+ struct IGattCharacteristic;
+ struct IGattDeviceService;
+ struct IGattValueChangedEventArgs;
+ }
+
+ struct IBluetoothLEDevice;
+ }
+ }
+ namespace Foundation {
+ template <typename T> struct IAsyncOperation;
+ enum class AsyncStatus;
+ }
+ }
+}
+
#include <wrl.h>
-#include <windows.devices.bluetooth.h>
#include <functional>
@@ -77,7 +97,6 @@ QLowEnergyControllerPrivate *createWinRTLowEnergyController();
class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate
{
- Q_OBJECT
public:
QLowEnergyControllerPrivateWinRTNew();
~QLowEnergyControllerPrivateWinRTNew() override;
@@ -121,6 +140,10 @@ private slots:
void handleServiceHandlerError(const QString &error);
private:
+ void connectToPairedDevice();
+ void connectToUnpairedDevice();
+
+ bool mAbortPending = false;
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice;
EventRegistrationToken mStatusChangedToken;
struct ValueChangedEntry {
@@ -142,12 +165,17 @@ private:
void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
void unregisterFromValueChanges();
+ HRESULT onValueChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic *characteristic,
+ ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattValueChangedEventArgs *args);
+ bool registerForStatusChanges();
void unregisterFromStatusChanges();
+ HRESULT onStatusChange(ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice *dev, IInspectable *);
void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
-
+ HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult *> *op,
+ ABI::Windows::Foundation::AsyncStatus status);
};
QT_END_NAMESPACE