diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 new file mode 100644 index 0000000000000000000000000000000000000000..921b45a92b14cdcf15a23bd6bf01766862c1da9e --- /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 d2b711d9cebf02e79c5c2039cd90b62bae07fa60..974d8e8a1da3dd595f68a63e3b84f781ab13761e 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 793a8311bc76a54791612492bea4ddd8c3c2062c..fa4a509eb5fa8fff1bef35b7803e74cb23bd6c90 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 98c62151462634a01573bc97bfcfd057dd0e43e1..8f3e2b437e5489a59905b96ff37ed7612aadd889 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 0000000000000000000000000000000000000000..ae794db025217879a86d5bc9c7b88ea91c1cf629 --- /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 45a802521dc72688782521553f52a73b676a1e07..bb9894ff2b870678ddfead0d14855dddaafd6391 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 bf40974566375cabbfa30290885aec2ad5fdf67a..8cc5f9ce2a514e17f904fa628171de3678d11a50 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