summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bluetooth/bluetooth.pro2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.cpp10
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h36
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_winrt.cpp202
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp3
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp22
-rw-r--r--src/bluetooth/qbluetoothsocket.cpp7
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez.cpp3
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt.cpp64
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt_p.h15
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp8
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new.cpp509
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new_p.h34
13 files changed, 671 insertions, 244 deletions
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<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
@@ -116,11 +112,7 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
const QBluetoothAddress &address) const
{
Q_UNUSED(address);
-#ifdef QT_WINRT_BLUETOOTH
- return Paired;
-#else
return Unpaired;
-#endif
}
void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index 98c62151..8f3e2b43 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -84,6 +84,21 @@ QT_END_NAMESPACE
#include <QtCore/QPair>
#endif
+#ifdef QT_WINRT_BLUETOOTH
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ struct IBluetoothDeviceStatics;
+ struct IBluetoothLEDeviceStatics;
+ }
+ }
+ }
+}
+#endif
+
QT_BEGIN_NAMESPACE
extern void registerQBluetoothLocalDeviceMetaType();
@@ -208,7 +223,22 @@ private:
void initializeAdapter();
void initializeAdapterBluez5();
};
-#elif !defined(QT_OSX_BLUETOOTH) // winrt and dummy backend
+#elif defined(QT_WINRT_BLUETOOTH)
+class QBluetoothLocalDevicePrivate : public QObject
+{
+ Q_DECLARE_PUBLIC(QBluetoothLocalDevice)
+public:
+ QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
+ QBluetoothAddress = QBluetoothAddress());
+
+ bool isValid() const;
+
+private:
+ QBluetoothLocalDevice *q_ptr;
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothDeviceStatics> mStatics;
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics> mLEStatics;
+};
+#elif !defined(QT_OSX_BLUETOOTH) // dummy backend
class QBluetoothLocalDevicePrivate : public QObject
{
public:
@@ -219,11 +249,7 @@ public:
bool isValid() const
{
-#ifndef QT_WINRT_BLUETOOTH
return false;
-#else
- return true;
-#endif
}
};
#endif
diff --git a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
new file mode 100644
index 00000000..ae794db0
--- /dev/null
+++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothlocaldevice.h"
+#include "qbluetoothaddress.h"
+
+#include "qbluetoothlocaldevice_p.h"
+
+#ifdef CLASSIC_APP_BUILD
+#define Q_OS_WINRT
+#endif
+#include <QtCore/qfunctions_winrt.h>
+
+#include <robuffer.h>
+#include <windows.devices.bluetooth.h>
+#include <wrl.h>
+
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Devices::Bluetooth;
+using namespace ABI::Windows::Devices::Enumeration;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+QT_BEGIN_NAMESPACE
+
+template <class DeviceStatics, class OpResult, class Device, class Device2>
+ComPtr<IDeviceInformationPairing> getPairingInfo(ComPtr<DeviceStatics> deviceStatics,
+ const QBluetoothAddress &address)
+{
+ ComPtr<IAsyncOperation<OpResult *>> op;
+ if (!deviceStatics)
+ return nullptr;
+ HRESULT hr = deviceStatics->FromBluetoothAddressAsync(address.toUInt64(), &op);
+ RETURN_IF_FAILED("Could not obtain device from address", return nullptr);
+ ComPtr<Device> device;
+ hr = QWinRTFunctions::await(op, device.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000);
+ if (FAILED(hr) || !device) {
+ qErrnoWarning("Could not obtain device from address");
+ return nullptr;
+ }
+ ComPtr<Device2> device2;
+ hr = device.As(&device2);
+ RETURN_IF_FAILED("Could not cast device", return nullptr);
+ ComPtr<IDeviceInformation> deviceInfo;
+ hr = device2->get_DeviceInformation(&deviceInfo);
+ if (FAILED(hr) || !deviceInfo) {
+ qErrnoWarning("Could not obtain device information");
+ return nullptr;
+ }
+ ComPtr<IDeviceInformation2> deviceInfo2;
+ hr = deviceInfo.As(&deviceInfo2);
+ RETURN_IF_FAILED("Could not cast device information", return nullptr);
+ ComPtr<IDeviceInformationPairing> pairingInfo;
+ hr = deviceInfo2->get_Pairing(&pairingInfo);
+ RETURN_IF_FAILED("Could not obtain pairing information", return nullptr);
+ return pairingInfo;
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, QBluetoothAddress()))
+{
+ registerQBluetoothLocalDeviceMetaType();
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent) :
+ QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, address))
+{
+ registerQBluetoothLocalDeviceMetaType();
+}
+
+QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress)
+ : q_ptr(q)
+{
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &mLEStatics);
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &mStatics);
+}
+
+bool QBluetoothLocalDevicePrivate::isValid() const
+{
+ return (mStatics != nullptr && mLEStatics != nullptr);
+}
+
+void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
+{
+ Q_UNUSED(address);
+ Q_UNUSED(pairing);
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+}
+
+QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
+ const QBluetoothAddress &address) const
+{
+ if (!isValid() || address.isNull())
+ return QBluetoothLocalDevice::Unpaired;
+
+ ComPtr<IDeviceInformationPairing> pairingInfo = getPairingInfo<IBluetoothLEDeviceStatics,
+ BluetoothLEDevice, IBluetoothLEDevice, IBluetoothLEDevice2>(d_ptr->mLEStatics, address);
+ if (!pairingInfo)
+ pairingInfo = getPairingInfo<IBluetoothDeviceStatics, BluetoothDevice,
+ IBluetoothDevice, IBluetoothDevice2>(d_ptr->mStatics, address);
+ if (!pairingInfo)
+ return QBluetoothLocalDevice::Unpaired;
+ boolean isPaired;
+ HRESULT hr = pairingInfo->get_IsPaired(&isPaired);
+ RETURN_IF_FAILED("Could not obtain device pairing", return QBluetoothLocalDevice::Unpaired);
+ if (!isPaired)
+ return QBluetoothLocalDevice::Unpaired;
+
+ ComPtr<IDeviceInformationPairing2> pairingInfo2;
+ hr = pairingInfo.As(&pairingInfo2);
+ RETURN_IF_FAILED("Could not cast pairing info", return QBluetoothLocalDevice::Paired);
+ DevicePairingProtectionLevel protection = DevicePairingProtectionLevel_None;
+ hr = pairingInfo2->get_ProtectionLevel(&protection);
+ RETURN_IF_FAILED("Could not obtain pairing protection level", return QBluetoothLocalDevice::Paired);
+ if (protection == DevicePairingProtectionLevel_Encryption
+ || protection == DevicePairingProtectionLevel_EncryptionAndAuthentication)
+ return QBluetoothLocalDevice::AuthorizedPaired;
+ return QBluetoothLocalDevice::Paired;
+}
+
+void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
+{
+ Q_UNUSED(confirmation);
+}
+
+void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
+{
+ Q_UNUSED(mode);
+}
+
+QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
+{
+ return HostConnectable;
+}
+
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ return QList<QBluetoothAddress>();
+}
+
+void QBluetoothLocalDevice::powerOn()
+{
+}
+
+QString QBluetoothLocalDevice::name() const
+{
+ return QString();
+}
+
+QBluetoothAddress QBluetoothLocalDevice::address() const
+{
+ return QBluetoothAddress();
+}
+
+QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
+{
+ QList<QBluetoothHostInfo> localDevices;
+ return localDevices;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index da9c1386..9750b2aa 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -573,7 +573,8 @@ bool QBluetoothServiceDiscoveryAgentPrivate::isDuplicatedService(
const QBluetoothServiceInfo &info = discoveredServices.at(j);
if (info.device() == serviceInfo.device()
&& info.serviceClassUuids() == serviceInfo.serviceClassUuids()
- && info.serviceUuid() == serviceInfo.serviceUuid()) {
+ && info.serviceUuid() == serviceInfo.serviceUuid()
+ && info.serverChannel() == serviceInfo.serverChannel()) {
return true;
}
}
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
index 9f82a202..f1476758 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
@@ -52,6 +52,7 @@
#include <windows.devices.enumeration.h>
#include <windows.devices.bluetooth.h>
#include <windows.foundation.collections.h>
+#include <windows.networking.h>
#include <windows.storage.streams.h>
#include <wrl.h>
@@ -208,6 +209,14 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
hr = service->get_ConnectionServiceName(name.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
+ ComPtr<ABI::Windows::Networking::IHostName> host;
+ hr = service->get_ConnectionHostName(host.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ HString hostName;
+ hr = host->get_RawName(hostName.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString qHostName = QString::fromWCharArray(WindowsGetStringRawBuffer(hostName.Get(),
+ nullptr));
ComPtr<IRfcommServiceId> id;
hr = service->get_ServiceId(&id);
Q_ASSERT_SUCCEEDED(hr);
@@ -217,6 +226,8 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
Q_ASSERT_SUCCEEDED(hr);
QBluetoothServiceInfo info;
+ info.setAttribute(0xBEEF, QVariant(qHostName));
+ info.setAttribute(0xBEF0, QVariant(serviceName));
info.setServiceName(serviceName);
info.setServiceUuid(uuid);
ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
@@ -325,6 +336,17 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
}
hr = iterator->MoveNext(&current);
}
+ // Windows is only able to discover Rfcomm services but the according protocolDescriptor is
+ // not always set in the raw attribute map. If we encounter a service like that we should
+ // fill the protocol descriptor ourselves.
+ if (info.protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
+ QBluetoothServiceInfo::Sequence protocolDescriptorList;
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ << QVariant::fromValue(0);
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ info.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
+ }
emit serviceFound(address, info);
}
emit scanFinished(address);
diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp
index a18b8ed4..db7c8be4 100644
--- a/src/bluetooth/qbluetoothsocket.cpp
+++ b/src/bluetooth/qbluetoothsocket.cpp
@@ -640,6 +640,13 @@ void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
connectToService(service, d->openMode);
d->discoveryAgent->deleteLater();
d->discoveryAgent = nullptr;
+#ifdef QT_WINRT_BLUETOOTH
+ } else if (!service.attribute(0xBEEF).isNull()
+ && !service.attribute(0xBEF0).isNull()) {
+ connectToService(service, d->openMode);
+ d->discoveryAgent->deleteLater();
+ d->discoveryAgent = nullptr;
+#endif
} else {
qCDebug(QT_BT) << "Could not find port/psm for potential remote service";
}
diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp
index bbc32a90..25f07bb3 100644
--- a/src/bluetooth/qbluetoothsocket_bluez.cpp
+++ b/src/bluetooth/qbluetoothsocket_bluez.cpp
@@ -674,6 +674,9 @@ bool QBluetoothSocketPrivateBluez::setSocketDescriptor(int socketDescriptor, QBl
connectWriteNotifier = nullptr;
socketType = socketType_;
+ if (socket != -1)
+ QT_CLOSE(socket);
+
socket = socketDescriptor;
// ensure that O_NONBLOCK is set on new connections.
diff --git a/src/bluetooth/qbluetoothsocket_winrt.cpp b/src/bluetooth/qbluetoothsocket_winrt.cpp
index a4af8f72..72d72040 100644
--- a/src/bluetooth/qbluetoothsocket_winrt.cpp
+++ b/src/bluetooth/qbluetoothsocket_winrt.cpp
@@ -359,10 +359,11 @@ bool QBluetoothSocketPrivateWinRT::ensureNativeSocket(QBluetoothServiceInfo::Pro
return true;
}
-void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
+void QBluetoothSocketPrivateWinRT::connectToService(Microsoft::WRL::ComPtr<IHostName> hostName,
+ const QString &serviceName,
+ QIODevice::OpenMode openMode)
{
Q_Q(QBluetoothSocket);
- Q_UNUSED(openMode);
if (socket == -1 && !ensureNativeSocket(socketType)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
@@ -370,20 +371,9 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
return;
}
- const QString addressString = address.toString();
- HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
- ComPtr<IHostNameFactory> hostNameFactory;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
- &hostNameFactory);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IHostName> remoteHost;
- hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
- RETURN_VOID_IF_FAILED("QBluetoothSocketPrivateWinRT::connectToService: Could not create hostname.");
-
- const QString portString = QString::number(port);
- HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
+ HStringReference serviceNameReference(reinterpret_cast<LPCWSTR>(serviceName.utf16()));
- hr = m_socketObject->ConnectAsync(remoteHost.Get(), portReference.Get(), &m_connectOp);
+ HRESULT hr = m_socketObject->ConnectAsync(hostName.Get(), serviceNameReference.Get(), &m_connectOp);
if (hr == E_ACCESSDENIED) {
qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
"Please check your manifest capabilities.");
@@ -404,6 +394,29 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
Q_ASSERT_SUCCEEDED(hr);
}
+void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
+{
+ Q_Q(QBluetoothSocket);
+
+ if (socket == -1 && !ensureNativeSocket(socketType)) {
+ errorString = QBluetoothSocket::tr("Unknown socket error");
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+
+ const QString addressString = address.toString();
+ HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
+ ComPtr<IHostNameFactory> hostNameFactory;
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IHostName> remoteHost;
+ hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
+ RETURN_VOID_IF_FAILED("QBluetoothSocketPrivateWinRT::connectToService: Could not create hostname.");
+ const QString portString = QString::number(port);
+ connectToService(remoteHost, portString, openMode);
+}
+
void QBluetoothSocketPrivateWinRT::connectToService(
const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
{
@@ -425,6 +438,8 @@ void QBluetoothSocketPrivateWinRT::connectToService(
return;
}
+ const QString connectionHostName = service.attribute(0xBEEF).toString();
+ const QString connectionServiceName = service.attribute(0xBEF0).toString();
if (service.protocolServiceMultiplexer() > 0) {
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
@@ -434,7 +449,22 @@ void QBluetoothSocketPrivateWinRT::connectToService(
return;
}
connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), openMode);
- } else if (service.serverChannel() > 0) {
+ } else if (!connectionHostName.isEmpty() && !connectionServiceName.isEmpty()) {
+ Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
+ if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
+ errorString = QBluetoothSocket::tr("Unknown socket error");
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(connectionHostName.utf16()));
+ ComPtr<IHostNameFactory> hostNameFactory;
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IHostName> remoteHost;
+ hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
+ connectToService(remoteHost, connectionServiceName, openMode);
+ } else if (service.serverChannel() > 0) {
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
@@ -443,7 +473,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
return;
}
connectToServiceHelper(service.device().address(), service.serverChannel(), openMode);
- } else {
+ } else {
// try doing service discovery to see if we can find the socket
if (service.serviceUuid().isNull()
&& !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) {
diff --git a/src/bluetooth/qbluetoothsocket_winrt_p.h b/src/bluetooth/qbluetoothsocket_winrt_p.h
index 40e87f01..de8b7d67 100644
--- a/src/bluetooth/qbluetoothsocket_winrt_p.h
+++ b/src/bluetooth/qbluetoothsocket_winrt_p.h
@@ -57,6 +57,19 @@
QT_FORWARD_DECLARE_CLASS(SocketWorker)
+namespace ABI {
+ namespace Windows {
+ namespace Networking {
+ struct IHostName;
+ }
+ }
+}
+
+namespace Microsoft {
+ namespace WRL {
+ template <typename T> class ComPtr;
+ }
+}
QT_BEGIN_NAMESPACE
class QBluetoothSocketPrivateWinRT final: public QBluetoothSocketBasePrivate
@@ -125,6 +138,8 @@ private slots:
void handleError(QBluetoothSocket::SocketError error);
private:
+ void connectToService(Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> hostName,
+ const QString &serviceName, QIODevice::OpenMode openMode);
HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action,
ABI::Windows::Foundation::AsyncStatus status);
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index 65f4e0c2..dfa21004 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -3115,6 +3115,14 @@ void QLowEnergyControllerPrivateBluez::handleConnectionRequest()
if (connectionHandle == 0)
qCWarning(QT_BT_BLUEZ) << "Received client connection, but no connection complete event";
+ if (l2cpSocket) {
+ disconnect(l2cpSocket);
+ if (l2cpSocket->isOpen())
+ l2cpSocket->close();
+
+ l2cpSocket->deleteLater();
+ l2cpSocket = nullptr;
+ }
closeServerSocket();
QBluetoothSocketPrivateBluez *rawSocketPrivate = new QBluetoothSocketPrivateBluez();
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
index 45a80252..bb9894ff 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
@@ -41,6 +41,7 @@
#include "qlowenergycontroller_winrt_p.h"
#include "qbluetoothutils_winrt_p.h"
+#include <QtBluetooth/qbluetoothlocaldevice.h>
#include <QtBluetooth/QLowEnergyCharacteristicData>
#include <QtBluetooth/QLowEnergyDescriptorData>
#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
@@ -57,6 +58,7 @@
#include <robuffer.h>
#include <windows.devices.enumeration.h>
#include <windows.devices.bluetooth.h>
+#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <windows.foundation.collections.h>
#include <windows.foundation.metadata.h>
#include <windows.storage.streams.h>
@@ -91,15 +93,18 @@ typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharCo
continue; \
}
-#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret) \
if (FAILED(hr)) { \
qCWarning(QT_BT_WINRT) << msg; \
- unregisterFromStatusChanges(); \
- setError(QLowEnergyController::ConnectionError); \
- setState(QLowEnergyController::UnconnectedState); \
+ this->unregisterFromStatusChanges(); \
+ this->setError(QLowEnergyController::ConnectionError); \
+ this->setState(QLowEnergyController::UnconnectedState); \
ret; \
}
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
+ CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret)
+
#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret) \
if (FAILED(hr)) { \
qCDebug(QT_BT_WINRT) << msg; \
@@ -436,6 +441,7 @@ QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew()
{
unregisterFromStatusChanges();
unregisterFromValueChanges();
+ mAbortPending = true;
}
void QLowEnergyControllerPrivateWinRTNew::init()
@@ -445,6 +451,7 @@ void QLowEnergyControllerPrivateWinRTNew::init()
void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
{
qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ mAbortPending = false;
Q_Q(QLowEnergyController);
if (remoteDevice.isNull()) {
qWarning() << "Invalid/null remote device address";
@@ -473,138 +480,18 @@ void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
BluetoothConnectionStatus status;
hr = mDevice->get_ConnectionStatus(&status);
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain device's connection status", return)
- hr = QEventDispatcherWinRT::runOnXamlThread([this, q]() {
- HRESULT hr;
- hr = mDevice->add_ConnectionStatusChanged(
- Callback<StatusHandler>([this, q](IBluetoothLEDevice *dev, IInspectable *) {
- BluetoothConnectionStatus status;
- HRESULT hr;
- hr = dev->get_ConnectionStatus(&status);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain connection status", return S_OK)
- if (state == QLowEnergyController::ConnectingState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- } else if (state != QLowEnergyController::UnconnectedState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
- invalidateServices();
- unregisterFromValueChanges();
- unregisterFromStatusChanges();
- mDevice = nullptr;
- setError(QLowEnergyController::RemoteHostClosedError);
- setState(QLowEnergyController::UnconnectedState);
- emit q->disconnected();
- }
- return S_OK;
- }).Get(), &mStatusChangedToken);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register connection status callback", return S_OK)
- return S_OK;
- });
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not add status callback on Xaml thread", return)
-
if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
setState(QLowEnergyController::ConnectedState);
emit q->connected();
return;
}
- ComPtr<IBluetoothLEDevice3> device3;
- hr = mDevice.As(&device3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
- hr = device3->GetGattServicesAsync(&deviceServicesOp);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
- ComPtr<IGattDeviceServicesResult> deviceServicesResult;
- hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
-
- GattCommunicationStatus commStatus;
- hr = deviceServicesResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT()) << "Service operation failed";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- unregisterFromStatusChanges();
- return;
- }
-
- ComPtr<IVectorView <GattDeviceService *>> deviceServices;
- hr = deviceServicesResult->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain list of services", return)
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service count", return)
-
- // Windows automatically connects to the device as soon as a service value is read/written.
- // Thus we read one value in order to establish the connection.
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
- ComPtr<IGattDeviceService3> service3;
- hr = service.As(&service3);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not cast service");
- ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
- hr = service3->GetCharacteristicsAsync(&characteristicsOp);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic");
- ComPtr<IGattCharacteristicsResult> characteristicsResult;
- hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await characteristic operation");
- GattCommunicationStatus commStatus;
- hr = characteristicsResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Characteristic operation failed";
- continue;
- }
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = characteristicsResult->get_Characteristics(&characteristics);
- if (hr == E_ACCESSDENIED) {
- // Everything will work as expected up until this point if the manifest capabilties
- // for bluetooth LE are not set.
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
- "manifest capabilities";
- setState(QLowEnergyController::UnconnectedState);
- setError(QLowEnergyController::ConnectionError);
- unregisterFromStatusChanges();
- return;
- }
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic list");
- uint characteristicsCount;
- hr = characteristics->get_Size(&characteristicsCount);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic list's size");
- for (uint j = 0; j < characteristicsCount; ++j) {
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(j, &characteristic);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic");
- ComPtr<IAsyncOperation<GattReadResult *>> op;
- GattCharacteristicProperties props;
- hr = characteristic->get_CharacteristicProperties(&props);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic's properties");
- if (!(props & GattCharacteristicProperties_Read))
- continue;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read characteristic value");
- ComPtr<IGattReadResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf());
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could await characteristic read");
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- hr = result->get_Value(&buffer);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic value");
- if (!buffer) {
- qCDebug(QT_BT_WINRT) << "Problem reading value";
- continue;
- }
- return;
- }
- }
-
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic read result that triggers"
- "device connection. Is the device reachable?";
- unregisterFromStatusChanges();
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
+ QBluetoothLocalDevice localDevice;
+ QBluetoothLocalDevice::Pairing pairing = localDevice.pairingStatus(remoteDevice);
+ if (pairing == QBluetoothLocalDevice::Unpaired)
+ connectToUnpairedDevice();
+ else
+ connectToPairedDevice();
}
void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
@@ -614,6 +501,7 @@ void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
setState(QLowEnergyController::ClosingState);
unregisterFromValueChanges();
unregisterFromStatusChanges();
+ mAbortPending = true;
mDevice = nullptr;
setState(QLowEnergyController::UnconnectedState);
emit q->disconnected();
@@ -691,18 +579,8 @@ void QLowEnergyControllerPrivateWinRTNew::registerForValueChanges(const QBluetoo
EventRegistrationToken token;
HRESULT hr;
hr = characteristic->add_ValueChanged(
- Callback<ValueChangedHandler>(
- [this](IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args) {
- HRESULT hr;
- quint16 handle;
- hr = characteristic->get_AttributeHandle(&handle);
- RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
- ComPtr<IBuffer> buffer;
- hr = args->get_CharacteristicValue(&buffer);
- RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
- characteristicChanged(handle, byteArrayFromBuffer(buffer));
- return S_OK;
- }).Get(), &token);
+ Callback<ValueChangedHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onValueChange).Get(),
+ &token);
RETURN_IF_FAILED("Could not register characteristic for value changes", return)
mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service"
@@ -726,6 +604,39 @@ void QLowEnergyControllerPrivateWinRTNew::unregisterFromValueChanges()
mValueChangedTokens.clear();
}
+HRESULT QLowEnergyControllerPrivateWinRTNew::onValueChange(IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args)
+{
+ HRESULT hr;
+ quint16 handle;
+ hr = characteristic->get_AttributeHandle(&handle);
+ RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
+ ComPtr<IBuffer> buffer;
+ hr = args->get_CharacteristicValue(&buffer);
+ RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
+ characteristicChanged(handle, byteArrayFromBuffer(buffer));
+ return S_OK;
+}
+
+bool QLowEnergyControllerPrivateWinRTNew::registerForStatusChanges()
+{
+ if (!mDevice)
+ return false;
+
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = mDevice->add_ConnectionStatusChanged(
+ Callback<StatusHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onStatusChange).Get(),
+ &mStatusChangedToken);
+ RETURN_IF_FAILED("Could not register connection status callback", return hr)
+ return S_OK;
+ });
+ RETURN_FALSE_IF_FAILED("Could not add status callback on Xaml thread")
+ return true;
+}
+
void QLowEnergyControllerPrivateWinRTNew::unregisterFromStatusChanges()
{
qCDebug(QT_BT_WINRT) << __FUNCTION__;
@@ -735,6 +646,30 @@ void QLowEnergyControllerPrivateWinRTNew::unregisterFromStatusChanges()
}
}
+HRESULT QLowEnergyControllerPrivateWinRTNew::onStatusChange(IBluetoothLEDevice *dev, IInspectable *)
+{
+ Q_Q(QLowEnergyController);
+ BluetoothConnectionStatus status;
+ HRESULT hr;
+ hr = dev->get_ConnectionStatus(&status);
+ RETURN_IF_FAILED("Could not obtain connection status", return S_OK)
+ if (state == QLowEnergyController::ConnectingState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ } else if (state != QLowEnergyController::UnconnectedState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
+ invalidateServices();
+ unregisterFromValueChanges();
+ unregisterFromStatusChanges();
+ mDevice = nullptr;
+ setError(QLowEnergyController::RemoteHostClosedError);
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+ }
+ return S_OK;
+}
+
void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
QSharedPointer<QLowEnergyServicePrivate> servicePointer,
ComPtr<IGattDeviceService> service)
@@ -791,10 +726,68 @@ void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
}
}
-void QLowEnergyControllerPrivateWinRTNew::discoverServices()
+HRESULT QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
{
Q_Q(QLowEnergyController);
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain services";
+ return S_OK;
+ }
+ ComPtr<IGattDeviceServicesResult> result;
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ HRESULT hr = op->GetResults(&result);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
+ return S_OK);
+ GattCommunicationStatus commStatus;
+ hr = result->get_Status(&commStatus);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
+ return S_OK);
+ if (commStatus != GattCommunicationStatus_Success)
+ return S_OK;
+ hr = result->get_Services(&deviceServices);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
+ return S_OK);
+
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
+ return S_OK);
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> deviceService;
+ hr = deviceServices->GetAt(i, &deviceService);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
+ GUID guuid;
+ hr = deviceService->get_Uuid(&guuid);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
+ const QBluetoothUuid service(guuid);
+
+ QSharedPointer<QLowEnergyServicePrivate> pointer;
+ if (serviceList.contains(service)) {
+ pointer = serviceList.value(service);
+ } else {
+ QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
+ priv->uuid = service;
+ priv->setController(this);
+
+ pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
+ serviceList.insert(service, pointer);
+ }
+ pointer->type |= QLowEnergyService::PrimaryService;
+
+ obtainIncludedServices(pointer, deviceService);
+
+ emit q->serviceDiscovered(service);
+ }
+
+ setState(QLowEnergyController::DiscoveredState);
+ emit q->discoveryFinished();
+
+ return S_OK;
+}
+
+void QLowEnergyControllerPrivateWinRTNew::discoverServices()
+{
qCDebug(QT_BT_WINRT) << "Service discovery initiated";
ComPtr<IBluetoothLEDevice3> device3;
@@ -803,67 +796,10 @@ void QLowEnergyControllerPrivateWinRTNew::discoverServices()
ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
hr = device3->GetGattServicesAsync(&asyncResult);
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return);
- hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, q, this] () {
+ hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, this] () {
HRESULT hr = asyncResult->put_Completed(
Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
- [this, q](IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *> *op,
- AsyncStatus status) {
- if (status != AsyncStatus::Completed) {
- qCDebug(QT_BT_WINRT) << "Could not obtain services";
- return S_OK;
- }
- ComPtr<IGattDeviceServicesResult> result;
- ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- HRESULT hr = op->GetResults(&result);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
- return S_OK);
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
- return S_OK);
- if (commStatus != GattCommunicationStatus_Success)
- return S_OK;
-
- hr = result->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
- return S_OK);
-
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
- return S_OK);
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> deviceService;
- hr = deviceServices->GetAt(i, &deviceService);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
- GUID guuid;
- hr = deviceService->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
- const QBluetoothUuid service(guuid);
-
- QSharedPointer<QLowEnergyServicePrivate> pointer;
- if (serviceList.contains(service)) {
- pointer = serviceList.value(service);
- } else {
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = service;
- priv->setController(this);
-
- pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
- serviceList.insert(service, pointer);
- }
- pointer->type |= QLowEnergyService::PrimaryService;
-
- obtainIncludedServices(pointer, deviceService);
-
- emit q->serviceDiscovered(service);
- }
-
- setState(QLowEnergyController::DiscoveredState);
- emit q->discoveryFinished();
-
- return S_OK;
- }).Get());
+ this, &QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished).Get());
CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register service discovery callback",
return S_OK)
return hr;
@@ -1305,7 +1241,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could write characteristic",
service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- auto writeCompletedLambda =[charData, charHandle, newValue, service, writeWithResponse, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charData, charHandle, newValue, service, writeWithResponse, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1332,7 +1269,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
// only update cache when property is readable. Otherwise it remains
// empty.
if (charData.properties & QLowEnergyCharacteristic::Read)
- updateValueOfCharacteristic(charHandle, newValue, false);
+ thisPtr->updateValueOfCharacteristic(charHandle, newValue, false);
if (writeWithResponse)
emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle),
newValue);
@@ -1412,7 +1349,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
HRESULT hr = characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write client characteristic configuration",
service, QLowEnergyService::DescriptorWriteError, return S_OK)
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1430,7 +1368,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
newValue);
return S_OK;
@@ -1505,7 +1443,8 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write descriptor value",
service, QLowEnergyService::DescriptorWriteError, return S_OK)
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
(IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
{
if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
@@ -1523,7 +1462,7 @@ void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
newValue);
return S_OK;
@@ -1583,6 +1522,160 @@ void QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError(const QStrin
setError(QLowEnergyController::ConnectionError);
}
+void QLowEnergyControllerPrivateWinRTNew::connectToPairedDevice()
+{
+ Q_Q(QLowEnergyController);
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ while (!mAbortPending) {
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT()) << "Service operation failed";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ ComPtr<IVectorView <GattDeviceService *>> deviceServices;
+ hr = deviceServicesResult->get_Services(&deviceServices);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain list of services", return)
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service count", return)
+
+ if (serviceCount == 0) {
+ qCWarning(QT_BT_WINRT()) << "Found devices without services";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ // Windows automatically connects to the device as soon as a service value is read/written.
+ // Thus we read one value in order to establish the connection.
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> service;
+ hr = deviceServices->GetAt(i, &service);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service", return);
+ ComPtr<IGattDeviceService3> service3;
+ hr = service.As(&service3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast service", return);
+ ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
+ hr = service3->GetCharacteristicsAsync(&characteristicsOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
+ ComPtr<IGattCharacteristicsResult> characteristicsResult;
+ hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic operation", return);
+ GattCommunicationStatus commStatus;
+ hr = characteristicsResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT) << "Characteristic operation failed";
+ break;
+ }
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = characteristicsResult->get_Characteristics(&characteristics);
+ if (hr == E_ACCESSDENIED) {
+ // Everything will work as expected up until this point if the manifest capabilties
+ // for bluetooth LE are not set.
+ qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
+ "manifest capabilities";
+ setState(QLowEnergyController::UnconnectedState);
+ setError(QLowEnergyController::ConnectionError);
+ unregisterFromStatusChanges();
+ return;
+ }
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list", return);
+ uint characteristicsCount;
+ hr = characteristics->get_Size(&characteristicsCount);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list's size", return);
+ for (uint j = 0; j < characteristicsCount; ++j) {
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(j, &characteristic);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
+ ComPtr<IAsyncOperation<GattReadResult *>> op;
+ GattCharacteristicProperties props;
+ hr = characteristic->get_CharacteristicProperties(&props);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic's properties", return);
+ if (!(props & GattCharacteristicProperties_Read))
+ continue;
+ hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not read characteristic value", return);
+ ComPtr<IGattReadResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessThreadEvents, 500);
+ // E_ILLEGAL_METHOD_CALL will be the result for a device, that is not reachable at
+ // the moment. In this case we should jump back into the outer loop and keep trying.
+ if (hr == E_ILLEGAL_METHOD_CALL)
+ break;
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic read", return);
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ hr = result->get_Value(&buffer);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic value", return);
+ if (!buffer) {
+ qCDebug(QT_BT_WINRT) << "Problem reading value";
+ break;
+ }
+
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ if (!registerForStatusChanges()) {
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ return;
+ }
+ }
+ }
+}
+
+void QLowEnergyControllerPrivateWinRTNew::connectToUnpairedDevice()
+{
+ if (!registerForStatusChanges()) {
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ while (!mAbortPending) {
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (commStatus == GattCommunicationStatus_Unreachable)
+ continue;
+
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINRT()) << "Service operation failed";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ return;
+ }
+
+ break;
+ }
+}
+
QT_END_NAMESPACE
#include "qlowenergycontroller_winrt_new.moc"
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
index bf409745..8cc5f9ce 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h
+++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
@@ -60,8 +60,28 @@
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ namespace GenericAttributeProfile {
+ class GattDeviceServicesResult;
+ struct IGattCharacteristic;
+ struct IGattDeviceService;
+ struct IGattValueChangedEventArgs;
+ }
+
+ struct IBluetoothLEDevice;
+ }
+ }
+ namespace Foundation {
+ template <typename T> struct IAsyncOperation;
+ enum class AsyncStatus;
+ }
+ }
+}
+
#include <wrl.h>
-#include <windows.devices.bluetooth.h>
#include <functional>
@@ -77,7 +97,6 @@ QLowEnergyControllerPrivate *createWinRTLowEnergyController();
class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate
{
- Q_OBJECT
public:
QLowEnergyControllerPrivateWinRTNew();
~QLowEnergyControllerPrivateWinRTNew() override;
@@ -121,6 +140,10 @@ private slots:
void handleServiceHandlerError(const QString &error);
private:
+ void connectToPairedDevice();
+ void connectToUnpairedDevice();
+
+ bool mAbortPending = false;
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice;
EventRegistrationToken mStatusChangedToken;
struct ValueChangedEntry {
@@ -142,12 +165,17 @@ private:
void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
void unregisterFromValueChanges();
+ HRESULT onValueChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic *characteristic,
+ ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattValueChangedEventArgs *args);
+ bool registerForStatusChanges();
void unregisterFromStatusChanges();
+ HRESULT onStatusChange(ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice *dev, IInspectable *);
void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
-
+ HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult *> *op,
+ ABI::Windows::Foundation::AsyncStatus status);
};
QT_END_NAMESPACE