From 576164fef388f312dcc7f59721de8237dfcd15b3 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 18 Apr 2019 10:19:40 +0200 Subject: Create qbluetoothlocaldevice_winrt In preparation for the followup patches. Change-Id: I9b1f6c181adb847f6aafdaf60fcef7139a12b638 Reviewed-by: Alex Blasche --- src/bluetooth/bluetooth.pro | 2 +- src/bluetooth/qbluetoothlocaldevice_p.cpp | 10 +- src/bluetooth/qbluetoothlocaldevice_p.h | 19 +++- src/bluetooth/qbluetoothlocaldevice_winrt.cpp | 127 ++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 src/bluetooth/qbluetoothlocaldevice_winrt.cpp diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index 2bcdee12..b104a902 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -224,7 +224,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 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..9b478b84 100644 --- a/src/bluetooth/qbluetoothlocaldevice_p.h +++ b/src/bluetooth/qbluetoothlocaldevice_p.h @@ -208,7 +208,20 @@ 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; +}; +#elif !defined(QT_OSX_BLUETOOTH) // dummy backend class QBluetoothLocalDevicePrivate : public QObject { public: @@ -219,11 +232,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..dbd17f50 --- /dev/null +++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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" + +QT_BEGIN_NAMESPACE + +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) +{ +} + +bool QBluetoothLocalDevicePrivate::isValid() const +{ + return true; +} + +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 +{ + Q_UNUSED(address); + return QBluetoothLocalDevice::Unpaired; +} + +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 QBluetoothLocalDevice::connectedDevices() const +{ + return QList(); +} + +void QBluetoothLocalDevice::powerOn() +{ +} + +QString QBluetoothLocalDevice::name() const +{ + return QString(); +} + +QBluetoothAddress QBluetoothLocalDevice::address() const +{ + return QBluetoothAddress(); +} + +QList QBluetoothLocalDevice::allDevices() +{ + QList localDevices; + return localDevices; +} + +QT_END_NAMESPACE -- cgit v1.2.3 From 23386ed8dab0a8b8280c2e1b935171adcce0d833 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 18 Apr 2019 10:28:43 +0200 Subject: winrt: Add QBluetoothLocalDevice::pairingStatus Task-number: QTBUG-62294 Change-Id: I61ee7dc30996c8e12c0fa75f7c85931a61c12554 Reviewed-by: Alex Blasche --- src/bluetooth/qbluetoothlocaldevice_p.h | 17 ++++++ src/bluetooth/qbluetoothlocaldevice_winrt.cpp | 81 ++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h index 9b478b84..8f3e2b43 100644 --- a/src/bluetooth/qbluetoothlocaldevice_p.h +++ b/src/bluetooth/qbluetoothlocaldevice_p.h @@ -84,6 +84,21 @@ QT_END_NAMESPACE #include #endif +#ifdef QT_WINRT_BLUETOOTH +#include + +namespace ABI { + namespace Windows { + namespace Devices { + namespace Bluetooth { + struct IBluetoothDeviceStatics; + struct IBluetoothLEDeviceStatics; + } + } + } +} +#endif + QT_BEGIN_NAMESPACE extern void registerQBluetoothLocalDeviceMetaType(); @@ -220,6 +235,8 @@ public: private: QBluetoothLocalDevice *q_ptr; + Microsoft::WRL::ComPtr mStatics; + Microsoft::WRL::ComPtr mLEStatics; }; #elif !defined(QT_OSX_BLUETOOTH) // dummy backend class QBluetoothLocalDevicePrivate : public QObject diff --git a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp index dbd17f50..ae794db0 100644 --- a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp @@ -42,8 +42,57 @@ #include "qbluetoothlocaldevice_p.h" +#ifdef CLASSIC_APP_BUILD +#define Q_OS_WINRT +#endif +#include + +#include +#include +#include + +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 +ComPtr getPairingInfo(ComPtr deviceStatics, + const QBluetoothAddress &address) +{ + ComPtr> 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; + hr = QWinRTFunctions::await(op, device.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000); + if (FAILED(hr) || !device) { + qErrnoWarning("Could not obtain device from address"); + return nullptr; + } + ComPtr device2; + hr = device.As(&device2); + RETURN_IF_FAILED("Could not cast device", return nullptr); + ComPtr deviceInfo; + hr = device2->get_DeviceInformation(&deviceInfo); + if (FAILED(hr) || !deviceInfo) { + qErrnoWarning("Could not obtain device information"); + return nullptr; + } + ComPtr deviceInfo2; + hr = deviceInfo.As(&deviceInfo2); + RETURN_IF_FAILED("Could not cast device information", return nullptr); + ComPtr 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())) @@ -61,11 +110,13 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, Q 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 true; + return (mStatics != nullptr && mLEStatics != nullptr); } void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing) @@ -80,8 +131,32 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus( const QBluetoothAddress &address) const { - Q_UNUSED(address); - return QBluetoothLocalDevice::Unpaired; + if (!isValid() || address.isNull()) + return QBluetoothLocalDevice::Unpaired; + + ComPtr pairingInfo = getPairingInfo(d_ptr->mLEStatics, address); + if (!pairingInfo) + pairingInfo = getPairingInfo(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 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) -- cgit v1.2.3 From 5aa37aab69d89691ab7eded7f708915612f1afa3 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 25 Apr 2019 10:04:29 +0200 Subject: qlowenergycontroller_winrt_new: Add registerStatusChanges and onStatusChange functions In preparation for following patches, functionality related to status changes was moved into dedicated functions. That makes code more readable and avoids late callbacks which can happen when lambdas are used. Change-Id: Ie699adef238013bb5391b57a1794e0b3d6bf8312 Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_winrt_new.cpp | 79 +++++++++++++++--------- src/bluetooth/qlowenergycontroller_winrt_new_p.h | 2 + 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp index 45a80252..c3efec7f 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp @@ -473,35 +473,12 @@ 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([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 (!registerForStatusChanges()) { + qCWarning(QT_BT_WINRT) << "Could not register status changes"; + setError(QLowEnergyController::ConnectionError); + setState(QLowEnergyController::UnconnectedState); + return; + } if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) { setState(QLowEnergyController::ConnectedState); emit q->connected(); @@ -726,6 +703,26 @@ void QLowEnergyControllerPrivateWinRTNew::unregisterFromValueChanges() mValueChangedTokens.clear(); } +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(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 +732,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 servicePointer, ComPtr service) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h index bf409745..69ee3fca 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h @@ -143,7 +143,9 @@ private: void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid); void unregisterFromValueChanges(); + bool registerForStatusChanges(); void unregisterFromStatusChanges(); + HRESULT onStatusChange(ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice *dev, IInspectable *); void obtainIncludedServices(QSharedPointer servicePointer, Microsoft::WRL::ComPtr nativeService); -- cgit v1.2.3 From 68cb332228df1c8730e721061134c18bda37cf02 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 17 Apr 2019 12:17:21 +0200 Subject: qlowenergycontroller_winrt_new: Avoid late callbacks that lead to crashes Users may run into crashes on device disconnects in case that we run into a callback while the disconnects happen. Thus we have to avoid calling functions on deleted objects by avoiding lambdas if possible or using QPointers in lambda captures. Change-Id: Idcd3781bd396d4ef785191e4c65bae20e5149c04 Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_winrt_new.cpp | 174 ++++++++++++----------- src/bluetooth/qlowenergycontroller_winrt_new_p.h | 6 +- 2 files changed, 97 insertions(+), 83 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp index c3efec7f..fb83371b 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp @@ -91,15 +91,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; \ @@ -668,18 +671,8 @@ void QLowEnergyControllerPrivateWinRTNew::registerForValueChanges(const QBluetoo EventRegistrationToken token; HRESULT hr; hr = characteristic->add_ValueChanged( - Callback( - [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 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(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" @@ -703,6 +696,19 @@ 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 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) @@ -812,10 +818,68 @@ void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices( } } -void QLowEnergyControllerPrivateWinRTNew::discoverServices() +HRESULT QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation *op, AsyncStatus status) { Q_Q(QLowEnergyController); + if (status != AsyncStatus::Completed) { + qCDebug(QT_BT_WINRT) << "Could not obtain services"; + return S_OK; + } + ComPtr result; + ComPtr> 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 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 pointer; + if (serviceList.contains(service)) { + pointer = serviceList.value(service); + } else { + QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate(); + priv->uuid = service; + priv->setController(this); + pointer = QSharedPointer(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 device3; @@ -824,67 +888,10 @@ void QLowEnergyControllerPrivateWinRTNew::discoverServices() ComPtr> 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>( - [this, q](IAsyncOperation *op, - AsyncStatus status) { - if (status != AsyncStatus::Completed) { - qCDebug(QT_BT_WINRT) << "Could not obtain services"; - return S_OK; - } - ComPtr result; - ComPtr> 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 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 pointer; - if (serviceList.contains(service)) { - pointer = serviceList.value(service); - } else { - QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate(); - priv->uuid = service; - priv->setController(this); - - pointer = QSharedPointer(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; @@ -1326,7 +1333,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 thisPtr(this); + auto writeCompletedLambda = [charData, charHandle, newValue, service, writeWithResponse, thisPtr] (IAsyncOperation *op, AsyncStatus status) { if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) { @@ -1353,7 +1361,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); @@ -1433,7 +1441,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 thisPtr(this); + auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr] (IAsyncOperation *op, AsyncStatus status) { if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) { @@ -1451,7 +1460,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; @@ -1526,7 +1535,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 thisPtr(this); + auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr] (IAsyncOperation *op, AsyncStatus status) { if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) { @@ -1544,7 +1554,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; diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h index 69ee3fca..fa8e516f 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h @@ -62,6 +62,7 @@ #include #include +#include #include @@ -142,6 +143,8 @@ 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(); @@ -149,7 +152,8 @@ private: void obtainIncludedServices(QSharedPointer servicePointer, Microsoft::WRL::ComPtr nativeService); - + HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation *op, + AsyncStatus status); }; QT_END_NAMESPACE -- cgit v1.2.3 From 1d4cb8a6782b74a379098da58f383aaaf61989bd Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Tue, 9 Apr 2019 09:58:50 +0200 Subject: winrt: Try "connectToDevice" indefinitely connectToDevice should not fail after a timeout, but try to connect to the device indefinitely. Unfortunately the behavior depends on the device's pairing status so two connectToDevice functions are needed. But the current implementations potentially wait indefinitely until the connection can be established. Change-Id: Iacb81e2c995974020b14d297528e54c326eb0453 Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_winrt_new.cpp | 267 ++++++++++++++--------- src/bluetooth/qlowenergycontroller_winrt_new_p.h | 4 + 2 files changed, 168 insertions(+), 103 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp index fb83371b..7bff47be 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 #include #include #include @@ -439,6 +440,7 @@ QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew() { unregisterFromStatusChanges(); unregisterFromValueChanges(); + mAbortPending = true; } void QLowEnergyControllerPrivateWinRTNew::init() @@ -448,6 +450,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"; @@ -476,115 +479,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) - if (!registerForStatusChanges()) { - qCWarning(QT_BT_WINRT) << "Could not register status changes"; - setError(QLowEnergyController::ConnectionError); - setState(QLowEnergyController::UnconnectedState); - return; - } if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) { setState(QLowEnergyController::ConnectedState); emit q->connected(); return; } - ComPtr device3; - hr = mDevice.As(&device3); - CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return) - ComPtr> deviceServicesOp; - hr = device3->GetGattServicesAsync(&deviceServicesOp); - CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return) - ComPtr 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> 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 service; - hr = deviceServices->GetAt(i, &service); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service"); - ComPtr service3; - hr = service.As(&service3); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could not cast service"); - ComPtr> characteristicsOp; - hr = service3->GetCharacteristicsAsync(&characteristicsOp); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic"); - ComPtr 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> 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 characteristic; - hr = characteristics->GetAt(j, &characteristic); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic"); - ComPtr> 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 result; - hr = QWinRTFunctions::await(op, result.GetAddressOf()); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could await characteristic read"); - ComPtr 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() @@ -594,6 +500,7 @@ void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice() setState(QLowEnergyController::ClosingState); unregisterFromValueChanges(); unregisterFromStatusChanges(); + mAbortPending = true; mDevice = nullptr; setState(QLowEnergyController::UnconnectedState); emit q->disconnected(); @@ -1614,6 +1521,160 @@ void QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError(const QStrin setError(QLowEnergyController::ConnectionError); } +void QLowEnergyControllerPrivateWinRTNew::connectToPairedDevice() +{ + Q_Q(QLowEnergyController); + ComPtr device3; + HRESULT hr = mDevice.As(&device3); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return) + ComPtr> deviceServicesOp; + while (!mAbortPending) { + hr = device3->GetGattServicesAsync(&deviceServicesOp); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return) + ComPtr 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> 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 service; + hr = deviceServices->GetAt(i, &service); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service", return); + ComPtr service3; + hr = service.As(&service3); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast service", return); + ComPtr> characteristicsOp; + hr = service3->GetCharacteristicsAsync(&characteristicsOp); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return); + ComPtr 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> 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 characteristic; + hr = characteristics->GetAt(j, &characteristic); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return); + ComPtr> 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 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 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 device3; + HRESULT hr = mDevice.As(&device3); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return) + ComPtr deviceServicesResult; + while (!mAbortPending) { + ComPtr> 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 fa8e516f..adb7bbcb 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h @@ -122,6 +122,10 @@ private slots: void handleServiceHandlerError(const QString &error); private: + void connectToPairedDevice(); + void connectToUnpairedDevice(); + + bool mAbortPending = false; Microsoft::WRL::ComPtr mDevice; EventRegistrationToken mStatusChangedToken; struct ValueChangedEntry { -- cgit v1.2.3 From 80c84c4df0cb8dc5389542dde34317102f7b25b8 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 25 Apr 2019 10:43:59 +0200 Subject: qlowenergycontroller_winrt_new_p.h: Use forward declarations instead of includes when possible Change-Id: Ic995631dfc15e34c7f2902bfa850c97671c52367 Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_winrt_new.cpp | 1 + src/bluetooth/qlowenergycontroller_winrt_new_p.h | 26 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp index 7bff47be..bb9894ff 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h index adb7bbcb..8cc5f9ce 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h @@ -60,9 +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 struct IAsyncOperation; + enum class AsyncStatus; + } + } +} + #include -#include -#include #include @@ -78,7 +97,6 @@ QLowEnergyControllerPrivate *createWinRTLowEnergyController(); class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate { - Q_OBJECT public: QLowEnergyControllerPrivateWinRTNew(); ~QLowEnergyControllerPrivateWinRTNew() override; @@ -157,7 +175,7 @@ private: void obtainIncludedServices(QSharedPointer servicePointer, Microsoft::WRL::ComPtr nativeService); HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation *op, - AsyncStatus status); + ABI::Windows::Foundation::AsyncStatus status); }; QT_END_NAMESPACE -- cgit v1.2.3 From 8f2d6640f959e35a8fd033a50aa57cb13b673cbb Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Fri, 3 May 2019 10:14:19 +0300 Subject: Add changes file for Qt 5.13.0 Change-Id: I9dae4c32cfe713c66a0fa9765357dc8162353caf Reviewed-by: Timur Pocheptsov --- dist/changes-5.13.0 | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 dist/changes-5.13.0 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. -- cgit v1.2.3