7#include <QtBluetooth/qbluetoothlocaldevice.h>
8#include <QtBluetooth/QLowEnergyCharacteristicData>
9#include <QtBluetooth/QLowEnergyDescriptorData>
10#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
11#include <QtBluetooth/QLowEnergyService>
13#include <QtCore/QtEndian>
14#include <QtCore/QLoggingCategory>
15#include <QtCore/private/qfunctions_winrt_p.h>
16#include <QtCore/QDeadlineTimer>
17#include <QtCore/qpointer.h>
22#include <windows.devices.enumeration.h>
23#include <windows.devices.bluetooth.h>
24#include <windows.devices.bluetooth.genericattributeprofile.h>
25#include <windows.foundation.collections.h>
26#include <windows.foundation.metadata.h>
27#include <windows.storage.streams.h>
30using namespace Microsoft::WRL::Wrappers;
32using namespace ABI::Windows::Foundation::Collections;
33using namespace ABI::Windows::Foundation::Metadata;
36using namespace ABI::Windows::Devices::Bluetooth::GenericAttributeProfile;
37using namespace ABI::Windows::Devices::Enumeration;
42typedef ITypedEventHandler<BluetoothLEDevice *, IInspectable *>
StatusHandler;
43typedef ITypedEventHandler<GattSession *, IInspectable *>
MtuHandler;
48#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr) \
50 emitErrorAndQuitThread(hr); \
54#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, message) \
56 emitErrorAndQuitThread(message); \
60#define WARN_AND_CONTINUE_IF_FAILED(hr, msg) \
62 qCWarning(QT_BT_WINDOWS) << msg; \
66#define DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, msg) \
68 qCWarning(QT_BT_WINDOWS) << msg; \
69 --mCharacteristicsCountToBeDiscovered; \
73#define CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret) \
75 this->handleConnectionError(msg); \
79#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
80 CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret)
82#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret) \
84 qCDebug(QT_BT_WINDOWS) << msg; \
85 service->setError(error); \
95 bool isWCharString =
false)
97 ComPtr<ABI::Windows::Storage::Streams::IBuffer>
buffer;
99 hr = gattResult->get_Value(&
buffer);
100 if (FAILED(hr) || !
buffer) {
101 qCWarning(QT_BT_WINDOWS) <<
"Could not obtain buffer from GattReadResult";
110 ComPtr<IClosable> closableService;
111 HRESULT hr = service.As(&closableService);
112 RETURN_IF_FAILED(
"Could not cast type to closable",
return);
113 hr = closableService->Close();
114 RETURN_IF_FAILED(
"Close() call failed",
return);
122 const ComPtr<IGattDeviceService3> &deviceService,
126 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
133 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
142 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
143 ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
144 ComPtr<IGattCharacteristicsResult> characteristicsResult;
147 hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
148 QWinRTFunctions::ProcessMainThreadEvents, 5000,
151 GattCommunicationStatus status;
152 hr = characteristicsResult->get_Status(&status);
154 if (status != GattCommunicationStatus_Success) {
155 emitErrorAndQuitThread(
QLatin1String(
"Could not obtain char list"));
158 ComPtr<IVectorView<GattCharacteristic *>> characteristics;
159 hr = characteristicsResult->get_Characteristics(&characteristics);
162 uint characteristicsCount;
163 hr = characteristics->get_Size(&characteristicsCount);
168 ComPtr<IGattCharacteristic> characteristic;
169 hr = characteristics->GetAt(
i, &characteristic);
171 qCWarning(QT_BT_WINDOWS) <<
"Could not obtain characteristic at" <<
i;
176 ComPtr<IGattCharacteristic3> characteristic3;
177 hr = characteristic.As(&characteristic3);
179 qCWarning(QT_BT_WINDOWS) <<
"Could not cast characteristic";
188 ComPtr<IAsyncOperation<GattDescriptorsResult *>> descAsyncOp;
189 hr = characteristic3->GetDescriptorsAsync(&descAsyncOp);
192 ComPtr<IGattDescriptorsResult> descResult;
193 hr = QWinRTFunctions::await(descAsyncOp, descResult.GetAddressOf(),
194 QWinRTFunctions::ProcessMainThreadEvents, 5000,
199 hr = characteristic->get_AttributeHandle(&
handle);
201 hr,
"Could not obtain characteristic's attribute handle")
209 hr = characteristic->get_Uuid(&guuid);
213 hr = characteristic->get_CharacteristicProperties(&
properties);
215 "Could not obtain characteristic's properties")
216 charData.properties = QLowEnergyCharacteristic::PropertyTypes(
properties & 0xff);
219 ComPtr<IAsyncOperation<GattReadResult *>> readOp;
220 hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
223 ComPtr<IGattReadResult> readResult;
224 hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
225 QWinRTFunctions::ProcessMainThreadEvents, 5000,
228 "Could not obtain characteristic read result")
230 qCWarning(QT_BT_WINDOWS) <<
"Characteristic read result is null";
236 ComPtr<IVectorView<GattDescriptor *>> descriptors;
238 GattCommunicationStatus commStatus;
239 hr = descResult->get_Status(&commStatus);
240 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
241 qCWarning(QT_BT_WINDOWS) <<
"Descriptor operation failed";
246 hr = descResult->get_Descriptors(&descriptors);
249 uint descriptorCount;
250 hr = descriptors->get_Size(&descriptorCount);
254 ComPtr<IGattDescriptor> descriptor;
255 hr = descriptors->GetAt(
j, &descriptor);
258 hr = descriptor->get_AttributeHandle(&descHandle);
261 hr = descriptor->get_Uuid(&descriptorUuid);
264 charData.descriptorList.insert(descHandle, descData);
267 ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
268 hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(
271 ComPtr<IClientCharConfigDescriptorResult> readResult;
272 hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
273 QWinRTFunctions::ProcessMainThreadEvents, 5000,
276 GattClientCharacteristicConfigurationDescriptorValue
value;
277 hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&
value);
279 "Could not get descriptor value from result")
281 bool correct =
false;
282 if (
value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
283 result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate;
286 if (
value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
287 result |= GattClientCharacteristicConfigurationDescriptorValue_Notify;
290 if (
value == GattClientCharacteristicConfigurationDescriptorValue_None)
301 ComPtr<IAsyncOperation<GattReadResult *>> readOp;
302 hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
305 ComPtr<IGattReadResult> readResult;
306 hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
307 QWinRTFunctions::ProcessMainThreadEvents, 5000,
316 charData.descriptorList.insert(descHandle, descData);
322 checkAllCharacteristicsDiscovered();
331 void checkAllCharacteristicsDiscovered();
332 void emitErrorAndQuitThread(
HRESULT hr);
348 QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList,
354void QWinRTLowEnergyServiceHandler::checkAllCharacteristicsDiscovered()
363void QWinRTLowEnergyServiceHandler::emitErrorAndQuitThread(
HRESULT hr)
368void QWinRTLowEnergyServiceHandler::emitErrorAndQuitThread(
const QString &
error)
381 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
387 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
389 mGattSession.Reset();
393 if (mInitialized == S_OK || mInitialized == S_FALSE)
406 void connectToPairedDevice();
407 void connectToUnpairedDevice();
409 void emitErrorAndQuitThread(
const char *
error);
410 void emitConnectedAndQuitThread();
412 ComPtr<IBluetoothLEDevice> mDevice =
nullptr;
413 ComPtr<IGattSession> mGattSession =
nullptr;
415 bool mAbortConnection =
false;
416 HRESULT mInitialized = E_UNEXPECTED;
421 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
422 mInitialized = CoInitializeEx(NULL, COINIT_MULTITHREADED);
425 auto earlyExit = [
this]() {
return mAbortConnection; };
426 ComPtr<IBluetoothLEDeviceStatics> deviceStatics;
427 HRESULT hr = GetActivationFactory(
428 HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(),
431 ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
432 hr = deviceStatics->FromBluetoothAddressAsync(mAddress.toUInt64(), &deviceFromIdOperation);
434 hr = QWinRTFunctions::await(deviceFromIdOperation, mDevice.GetAddressOf(),
435 QWinRTFunctions::ProcessMainThreadEvents, 5000, earlyExit);
436 if (FAILED(hr) || !mDevice) {
437 emitErrorAndQuitThread(
"Could not find LE device");
442 ComPtr<IBluetoothLEDevice4> device4;
443 hr = mDevice.As(&device4);
446 ComPtr<IBluetoothDeviceId> deviceId;
447 hr = device4->get_BluetoothDeviceId(&deviceId);
451 ComPtr<IGattSessionStatics> sessionStatics;
452 hr = GetActivationFactory(
453 HString::MakeReference(
454 RuntimeClass_Windows_Devices_Bluetooth_GenericAttributeProfile_GattSession)
460 ComPtr<IAsyncOperation<GattSession *>> gattSessionFromIdOperation;
461 hr = sessionStatics->FromDeviceIdAsync(deviceId.Get(), &gattSessionFromIdOperation);
463 hr = QWinRTFunctions::await(gattSessionFromIdOperation, mGattSession.GetAddressOf(),
464 QWinRTFunctions::ProcessMainThreadEvents, 5000, earlyExit);
467 BluetoothConnectionStatus status;
468 hr = mDevice->get_ConnectionStatus(&status);
470 if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
471 emitConnectedAndQuitThread();
478 connectToUnpairedDevice();
480 connectToPairedDevice();
485 mAbortConnection =
true;
494void QWinRTLowEnergyConnectionHandler::connectToPairedDevice()
496 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
497 ComPtr<IBluetoothLEDevice3> device3;
498 HRESULT hr = mDevice.As(&device3);
500 ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
501 auto earlyExit = [
this]() {
return mAbortConnection; };
504 hr = device3->GetGattServicesAsync(&deviceServicesOp);
506 ComPtr<IGattDeviceServicesResult> deviceServicesResult;
507 hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
508 QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
511 GattCommunicationStatus commStatus;
512 hr = deviceServicesResult->get_Status(&commStatus);
513 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
514 emitErrorAndQuitThread(
"Service operation failed");
518 ComPtr<IVectorView<GattDeviceService *>> deviceServices;
519 hr = deviceServicesResult->get_Services(&deviceServices);
522 hr = deviceServices->get_Size(&serviceCount);
525 if (serviceCount == 0) {
526 emitErrorAndQuitThread(
"Found devices without services");
532 for (
uint i = 0;
i < serviceCount; ++
i) {
533 ComPtr<IGattDeviceService>
service;
534 hr = deviceServices->GetAt(
i, &service);
536 ComPtr<IGattDeviceService3> service3;
539 ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
540 hr = service3->GetCharacteristicsAsync(&characteristicsOp);
542 ComPtr<IGattCharacteristicsResult> characteristicsResult;
543 hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
544 QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
546 GattCommunicationStatus commStatus;
547 hr = characteristicsResult->get_Status(&commStatus);
548 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
549 qCWarning(QT_BT_WINDOWS) <<
"Characteristic operation failed";
552 ComPtr<IVectorView<GattCharacteristic *>> characteristics;
553 hr = characteristicsResult->get_Characteristics(&characteristics);
554 if (hr == E_ACCESSDENIED) {
557 emitErrorAndQuitThread(
"Could not obtain characteristic list. "
558 "Please check your manifest capabilities");
562 uint characteristicsCount;
563 hr = characteristics->get_Size(&characteristicsCount);
565 "Could not obtain characteristic list's size");
566 for (
uint j = 0;
j < characteristicsCount; ++
j) {
567 ComPtr<IGattCharacteristic> characteristic;
568 hr = characteristics->GetAt(
j, &characteristic);
570 ComPtr<IAsyncOperation<GattReadResult *>> op;
571 GattCharacteristicProperties
props;
572 hr = characteristic->get_CharacteristicProperties(&
props);
574 hr,
"Could not obtain characteristic's properties");
575 if (!(
props & GattCharacteristicProperties_Read))
577 hr = characteristic->ReadValueWithCacheModeAsync(
578 BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
580 ComPtr<IGattReadResult>
result;
583 hr = QWinRTFunctions::await(op,
result.GetAddressOf(),
584 QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
587 if (hr == E_ILLEGAL_METHOD_CALL)
590 ComPtr<ABI::Windows::Storage::Streams::IBuffer>
buffer;
594 qCDebug(QT_BT_WINDOWS) <<
"Problem reading value";
598 emitConnectedAndQuitThread();
606 emitErrorAndQuitThread(
"Connect to device failed due to timeout!");
609void QWinRTLowEnergyConnectionHandler::connectToUnpairedDevice()
611 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
612 ComPtr<IBluetoothLEDevice3> device3;
613 HRESULT hr = mDevice.As(&device3);
615 ComPtr<IGattDeviceServicesResult> deviceServicesResult;
616 auto earlyExit = [
this]() {
return mAbortConnection; };
619 ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
620 hr = device3->GetGattServicesAsync(&deviceServicesOp);
622 hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
623 QWinRTFunctions::ProcessMainThreadEvents, 0, earlyExit);
626 GattCommunicationStatus commStatus;
627 hr = deviceServicesResult->get_Status(&commStatus);
628 if (commStatus == GattCommunicationStatus_Unreachable)
631 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
632 emitErrorAndQuitThread(
"Service operation failed");
636 emitConnectedAndQuitThread();
642 emitErrorAndQuitThread(
"Connect to device failed due to timeout!");
645void QWinRTLowEnergyConnectionHandler::emitErrorAndQuitThread(
const QString &
error)
651void QWinRTLowEnergyConnectionHandler::emitErrorAndQuitThread(
const char *
error)
656void QWinRTLowEnergyConnectionHandler::emitConnectedAndQuitThread()
667 this, &QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged,
673 unregisterFromStatusChanges();
674 unregisterFromValueChanges();
683 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
685 qCWarning(QT_BT_WINDOWS) <<
"Invalid/null remote device address";
702 [
this](ComPtr<IBluetoothLEDevice>
device, ComPtr<IGattSession> session) {
703 if (!
device || !session) {
704 handleConnectionError(
"Failed to get device or gatt service");
708 mGattSession = session;
710 if (!registerForStatusChanges() || !registerForMtuChanges()) {
711 handleConnectionError(
"Failed to register for changes");
724 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
728 unregisterFromValueChanges();
729 unregisterFromStatusChanges();
730 unregisterFromMtuChanges();
732 mGattSession =
nullptr;
735 emit q->disconnected();
739 NativeServiceCallback callback)
741 if (m_openedServices.contains(serviceUuid)) {
742 callback(m_openedServices.value(serviceUuid));
746 ComPtr<IBluetoothLEDevice3> device3;
747 HRESULT hr = mDevice.As(&device3);
748 RETURN_IF_FAILED(
"Could not convert to IBluetoothDevice3",
return hr);
750 ComPtr<IAsyncOperation<GattDeviceServicesResult *>> servicesResultOperation;
751 hr = device3->GetGattServicesForUuidAsync(serviceUuid, &servicesResultOperation);
752 RETURN_IF_FAILED(
"Could not start async services request",
return hr);
754 QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(
this);
755 hr = servicesResultOperation->put_Completed(
756 Callback<IAsyncOperationCompletedHandler<
757 GenericAttributeProfile::GattDeviceServicesResult *>>(
758 [thisPtr, callback, &serviceUuid](
759 IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
762 if (status != AsyncStatus::Completed) {
763 qCDebug(QT_BT_WINDOWS) <<
"Failed to get result of async service request";
766 ComPtr<IGattDeviceServicesResult>
result;
767 ComPtr<IVectorView<GattDeviceService *>> deviceServices;
769 RETURN_IF_FAILED(
"Failed to get result of async service request",
return hr);
771 ComPtr<IVectorView<GattDeviceService *>>
services;
773 RETURN_IF_FAILED(
"Failed to extract services from the result",
return hr);
775 uint servicesCount = 0;
776 hr =
services->get_Size(&servicesCount);
777 RETURN_IF_FAILED(
"Failed to extract services count",
return hr);
779 if (servicesCount > 0) {
780 if (servicesCount > 1) {
781 qWarning() <<
"getNativeService: more than one service detected for UUID"
782 << serviceUuid <<
"The first service will be used.";
784 ComPtr<IGattDeviceService>
service;
787 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native service for Uuid"
791 thisPtr->m_openedServices[serviceUuid] =
service;
795 qCWarning(QT_BT_WINDOWS) <<
"No services found for Uuid" << serviceUuid;
798 qCWarning(QT_BT_WINDOWS) <<
"LE controller was removed while getting native service";
806HRESULT QLowEnergyControllerPrivateWinRT::getNativeCharacteristic(
808 NativeCharacteristicCallback callback)
810 QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(
this);
811 auto serviceCallback = [thisPtr, callback, charUuid](ComPtr<IGattDeviceService>
service) {
812 ComPtr<IGattDeviceService3> service3;
814 RETURN_IF_FAILED(
"Could not cast service to service3",
return);
816 ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicRequestOp;
817 hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp);
819 hr = characteristicRequestOp->put_Completed(
820 Callback<IAsyncOperationCompletedHandler<GattCharacteristicsResult *>>(
822 IAsyncOperation<GattCharacteristicsResult *> *op, AsyncStatus status)
825 if (status != AsyncStatus::Completed) {
826 qCDebug(QT_BT_WINDOWS) <<
"Failed to get result of async characteristic "
830 ComPtr<IGattCharacteristicsResult>
result;
832 RETURN_IF_FAILED(
"Failed to get result of async characteristic operation",
834 GattCommunicationStatus status;
835 hr =
result->get_Status(&status);
836 if (FAILED(hr) || status != GattCommunicationStatus_Success) {
837 qErrnoWarning(hr,
"Native characteristic operation failed.");
840 ComPtr<IVectorView<GattCharacteristic *>> characteristics;
841 hr =
result->get_Characteristics(&characteristics);
842 RETURN_IF_FAILED(
"Could not obtain characteristic list.",
return S_OK);
844 hr = characteristics->get_Size(&
size);
845 RETURN_IF_FAILED(
"Could not obtain characteristic list's size.",
return S_OK);
848 ComPtr<IGattCharacteristic> characteristic;
849 hr = characteristics->GetAt(0, &characteristic);
850 RETURN_IF_FAILED(
"Could not obtain first characteristic for service",
return S_OK);
852 callback(characteristic);
858 HRESULT hr = getNativeService(serviceUuid, serviceCallback);
860 qCDebug(QT_BT_WINDOWS) <<
"Failed to get native service for" << serviceUuid;
865void QLowEnergyControllerPrivateWinRT::registerForValueChanges(
const QBluetoothUuid &serviceUuid,
868 qCDebug(QT_BT_WINDOWS) <<
"Registering characteristic" << charUuid <<
"in service"
869 << serviceUuid <<
"for value changes";
870 for (
const ValueChangedEntry &
entry :
std::as_const(mValueChangedTokens)) {
873 hr =
entry.characteristic->get_Uuid(&guuid);
879 auto callback = [
this, charUuid, serviceUuid](
ComPtr<IGattCharacteristic> characteristic) {
880 EventRegistrationToken
token;
882 hr = characteristic->add_ValueChanged(
883 Callback<ValueChangedHandler>(
884 this, &QLowEnergyControllerPrivateWinRT::onValueChange).Get(),
886 RETURN_IF_FAILED(
"Could not register characteristic for value changes",
return)
887 mValueChangedTokens.
append(ValueChangedEntry(characteristic,
token));
888 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charUuid <<
"in service"
889 << serviceUuid <<
"registered for value changes";
892 HRESULT hr = getNativeCharacteristic(serviceUuid, charUuid, callback);
894 qCDebug(QT_BT_WINDOWS).nospace() <<
"Could not obtain native characteristic "
895 << charUuid <<
" from service " << serviceUuid
896 <<
". Qt will not be able to signal"
897 <<
" changes for this characteristic.";
901void QLowEnergyControllerPrivateWinRT::unregisterFromValueChanges()
903 qCDebug(QT_BT_WINDOWS) <<
"Unregistering " << mValueChangedTokens.
size() <<
" value change tokens";
905 for (
const ValueChangedEntry &
entry :
std::as_const(mValueChangedTokens)) {
906 if (!
entry.characteristic) {
907 qCWarning(QT_BT_WINDOWS) <<
"Unregistering from value changes for characteristic failed."
908 <<
"Characteristic has been deleted";
911 hr =
entry.characteristic->remove_ValueChanged(
entry.token);
913 qCWarning(QT_BT_WINDOWS) <<
"Unregistering from value changes for characteristic failed.";
915 mValueChangedTokens.
clear();
918HRESULT QLowEnergyControllerPrivateWinRT::onValueChange(IGattCharacteristic *characteristic, IGattValueChangedEventArgs *
args)
922 hr = characteristic->get_AttributeHandle(&
handle);
923 RETURN_IF_FAILED(
"Could not obtain characteristic's handle",
return S_OK)
926 RETURN_IF_FAILED(
"Could not obtain characteristic's value",
return S_OK)
930HRESULT QLowEnergyControllerPrivateWinRT::onMtuChange(IGattSession *session, IInspectable *
args)
932 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
933 if (session != mGattSession.Get()) {
934 qCWarning(QT_BT_WINDOWS) <<
"Got MTU changed event for wrong or outdated GattSession.";
943bool QLowEnergyControllerPrivateWinRT::registerForStatusChanges()
948 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
951 hr = mDevice->add_ConnectionStatusChanged(
952 Callback<StatusHandler>(
this, &QLowEnergyControllerPrivateWinRT::onStatusChange).Get(),
953 &mStatusChangedToken);
954 RETURN_IF_FAILED(
"Could not add status callback",
return false)
958void QLowEnergyControllerPrivateWinRT::unregisterFromStatusChanges()
960 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
961 if (mDevice && mStatusChangedToken.value) {
962 mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
963 mStatusChangedToken.value = 0;
967bool QLowEnergyControllerPrivateWinRT::registerForMtuChanges()
969 if (!mDevice || !mGattSession)
972 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
975 hr = mGattSession->add_MaxPduSizeChanged(
976 Callback<MtuHandler>(
this, &QLowEnergyControllerPrivateWinRT::onMtuChange).Get(),
978 RETURN_IF_FAILED(
"Could not add MTU callback",
return false)
982void QLowEnergyControllerPrivateWinRT::unregisterFromMtuChanges()
984 qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
985 if (mDevice && mGattSession && mMtuChangedToken.value) {
986 mGattSession->remove_MaxPduSizeChanged(mMtuChangedToken);
987 mMtuChangedToken.value = 0;
991HRESULT QLowEnergyControllerPrivateWinRT::onStatusChange(IBluetoothLEDevice *dev, IInspectable *)
994 BluetoothConnectionStatus status;
996 hr = dev->get_ConnectionStatus(&status);
997 RETURN_IF_FAILED(
"Could not obtain connection status",
return S_OK)
999 && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
1001 emit q->connected();
1003 && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
1005 unregisterFromValueChanges();
1006 unregisterFromStatusChanges();
1007 unregisterFromMtuChanges();
1008 mGattSession =
nullptr;
1012 emit q->disconnected();
1017void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(
1018 QSharedPointer<QLowEnergyServicePrivate> servicePointer,
1019 ComPtr<IGattDeviceService> service)
1022 ComPtr<IGattDeviceService3> service3;
1024 RETURN_IF_FAILED(
"Could not cast service",
return);
1025 ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
1026 hr = service3->GetIncludedServicesAsync(&op);
1028 RETURN_IF_FAILED(
"Could not obtain included services",
return);
1029 ComPtr<IGattDeviceServicesResult>
result;
1030 hr = QWinRTFunctions::await(op,
result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
1031 RETURN_IF_FAILED(
"Could not await service operation",
return);
1035 GattCommunicationStatus status;
1036 hr =
result->get_Status(&status);
1037 if (FAILED(hr) || status != GattCommunicationStatus_Success) {
1038 qErrnoWarning(
"Could not obtain list of included services");
1041 ComPtr<IVectorView<GattDeviceService *>> includedServices;
1042 hr =
result->get_Services(&includedServices);
1043 RETURN_IF_FAILED(
"Could not obtain service list",
return);
1046 hr = includedServices->get_Size(&
count);
1047 RETURN_IF_FAILED(
"Could not obtain service list's size",
return);
1049 ComPtr<IGattDeviceService> includedService;
1050 hr = includedServices->GetAt(
i, &includedService);
1053 hr = includedService->get_Uuid(&guuid);
1056 QSharedPointer<QLowEnergyServicePrivate> includedPointer;
1057 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__
1058 <<
"Changing service pointer from thread"
1061 includedPointer =
serviceList.value(includedUuid);
1064 priv->uuid = includedUuid;
1065 priv->setController(
this);
1067 includedPointer = QSharedPointer<QLowEnergyServicePrivate>(
priv);
1068 serviceList.insert(includedUuid, includedPointer);
1071 servicePointer->includedServices.append(includedUuid);
1073 obtainIncludedServices(includedPointer, includedService);
1075 emit q->serviceDiscovered(includedUuid);
1091 if (status != AsyncStatus::Completed) {
1092 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain services";
1095 ComPtr<IGattDeviceServicesResult>
result;
1096 ComPtr<IVectorView<GattDeviceService *>> deviceServices;
1100 GattCommunicationStatus commStatus;
1101 hr =
result->get_Status(&commStatus);
1104 if (commStatus != GattCommunicationStatus_Success)
1107 hr =
result->get_Services(&deviceServices);
1112 hr = deviceServices->get_Size(&serviceCount);
1115 for (
uint i = 0;
i < serviceCount; ++
i) {
1116 ComPtr<IGattDeviceService> deviceService;
1117 hr = deviceServices->GetAt(
i, &deviceService);
1120 hr = deviceService->get_Uuid(&guuid);
1123 m_openedServices[
service] = deviceService;
1125 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__
1126 <<
"Changing service pointer from thread"
1128 QSharedPointer<QLowEnergyServicePrivate>
pointer;
1134 priv->setController(
this);
1136 pointer = QSharedPointer<QLowEnergyServicePrivate>(
priv);
1141 obtainIncludedServices(
pointer, deviceService);
1146 emit q->discoveryFinished();
1151 emit q->serviceDiscovered(service);
1155 emit q->discoveryFinished();
1160void QLowEnergyControllerPrivateWinRT::clearAllServices()
1164 for (
auto &uuid : m_requestDetailsServiceUuids)
1165 m_openedServices.
remove(uuid);
1166 m_requestDetailsServiceUuids.
clear();
1168 for (
auto service : m_openedServices) {
1171 m_openedServices.clear();
1174void QLowEnergyControllerPrivateWinRT::closeAndRemoveService(
const QBluetoothUuid &uuid)
1176 auto service = m_openedServices.take(uuid);
1183 qCDebug(QT_BT_WINDOWS) <<
"Service discovery initiated";
1186 ComPtr<IBluetoothLEDevice3> device3;
1187 HRESULT hr = mDevice.As(&device3);
1189 ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
1190 hr = device3->GetGattServicesAsync(&asyncResult);
1192 hr = asyncResult->put_Completed(
1193 Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
1194 this, &QLowEnergyControllerPrivateWinRT::onServiceDiscoveryFinished).Get());
1202 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service;
1204 qCWarning(QT_BT_WINDOWS) <<
"Discovery done of unknown service:"
1205 << service.toString();
1210 closeAndRemoveService(service);
1212 auto serviceCallback = [service,
mode,
this](ComPtr<IGattDeviceService> deviceService) {
1213 discoverServiceDetailsHelper(service,
mode, deviceService);
1216 HRESULT hr = getNativeService(service, serviceCallback);
1218 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native service for uuid " << service;
1221void QLowEnergyControllerPrivateWinRT::discoverServiceDetailsHelper(
1223 GattDeviceServiceComPtr deviceService)
1225 auto reactOnDiscoveryError = [](QSharedPointer<QLowEnergyServicePrivate> service,
1228 qCDebug(QT_BT_WINDOWS) << msg;
1235 qCDebug(QT_BT_WINDOWS) <<
"Device was disconnected while doing service discovery";
1238 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1241 ComPtr<IGattDeviceService3> deviceService3;
1242 HRESULT hr = deviceService.As(&deviceService3);
1247 ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
1248 hr = deviceService3->GetIncludedServicesAsync(&op);
1250 reactOnDiscoveryError(
pointer,
1254 ComPtr<IGattDeviceServicesResult>
result;
1255 hr = QWinRTFunctions::await(op,
result.GetAddressOf());
1257 reactOnDiscoveryError(
pointer,
1261 GattCommunicationStatus status;
1262 hr =
result->get_Status(&status);
1263 if (FAILED(hr) || status != GattCommunicationStatus_Success) {
1264 reactOnDiscoveryError(
pointer,
1265 QStringLiteral(
"Obtaining list of included services failed: %1").
1269 ComPtr<IVectorView<GattDeviceService *>> deviceServices;
1270 hr =
result->get_Services(&deviceServices);
1272 reactOnDiscoveryError(
pointer,
1278 hr = deviceServices->get_Size(&serviceCount);
1280 reactOnDiscoveryError(
pointer,
1281 QStringLiteral(
"Could not obtain included service list's size: %1").
1285 for (
uint i = 0;
i < serviceCount; ++
i) {
1286 ComPtr<IGattDeviceService> includedService;
1287 hr = deviceServices->GetAt(
i, &includedService);
1290 hr = includedService->get_Uuid(&guuid);
1294 if (service.isNull()) {
1295 qCDebug(QT_BT_WINDOWS) <<
"Could not find service";
1299 pointer->includedServices.append(service);
1302 QSharedPointer<QLowEnergyServicePrivate> otherService =
serviceList.value(service);
1303 if (!otherService.isNull())
1309 m_requestDetailsServiceUuids.
insert(service);
1318 this, &QLowEnergyControllerPrivateWinRT::handleServiceHandlerError);
1324 qCWarning(QT_BT_WINDOWS)
1325 <<
"Discovery complete for unknown service:" << service.toString();
1328 m_requestDetailsServiceUuids.
remove(service);
1331 pointer->startHandle = startHandle;
1332 pointer->endHandle = endHandle;
1333 pointer->characteristicList = charList;
1336 registerForValueChanges(
service, indicateChar);
1363 const QSharedPointer<QLowEnergyServicePrivate> service,
1366 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle;
1367 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1376 if (!service->characteristicList.contains(charHandle)) {
1377 qCDebug(QT_BT_WINDOWS) << charHandle <<
"could not be found in service" << service->uuid;
1382 const auto charData = service->characteristicList.value(charHandle);
1384 qCDebug(QT_BT_WINDOWS) <<
"Read flag is not set for characteristic" << charData.uuid;
1386 auto characteristicCallback = [charHandle, service,
this](
1387 ComPtr<IGattCharacteristic> characteristic) {
1388 readCharacteristicHelper(service, charHandle, characteristic);
1391 HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
1393 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native characteristic" << charData.uuid
1394 <<
"from service" << service->uuid;
1399void QLowEnergyControllerPrivateWinRT::readCharacteristicHelper(
1400 const QSharedPointer<QLowEnergyServicePrivate> service,
1402 GattCharacteristicComPtr characteristic)
1404 ComPtr<IAsyncOperation<GattReadResult *>> readOp;
1405 HRESULT hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
1408 auto readCompletedLambda = [charHandle, service]
1409 (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
1411 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1412 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charHandle <<
"read operation failed.";
1416 ComPtr<IGattReadResult> characteristicValue;
1418 hr = op->GetResults(&characteristicValue);
1423 auto charData =
service->characteristicList.value(charHandle);
1424 charData.value =
value;
1425 service->characteristicList.insert(charHandle, charData);
1429 hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
1430 readCompletedLambda).Get());
1436 const QSharedPointer<QLowEnergyServicePrivate> service,
1440 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << descHandle;
1441 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1450 if (!service->characteristicList.contains(charHandle)) {
1451 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"in characteristic" << charHandle
1452 <<
"cannot be found in service" << service->uuid;
1457 const auto charData = service->characteristicList.value(charHandle);
1459 auto characteristicCallback = [charHandle, descHandle, service,
this](
1460 ComPtr<IGattCharacteristic> characteristic) {
1461 readDescriptorHelper(service, charHandle, descHandle, characteristic);
1464 HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
1466 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native characteristic" << charData.uuid
1467 <<
"from service" << service->uuid;
1472void QLowEnergyControllerPrivateWinRT::readDescriptorHelper(
1473 const QSharedPointer<QLowEnergyServicePrivate> service,
1476 GattCharacteristicComPtr characteristic)
1479 const auto charData = service->characteristicList.value(charHandle);
1480 if (!charData.descriptorList.contains(descHandle)) {
1481 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"cannot be found in characteristic"
1484 const auto descData = charData.descriptorList.value(descHandle);
1488 ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
1489 HRESULT hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
1492 auto readCompletedLambda = [charHandle, descHandle,
service]
1493 (IAsyncOperation<ClientCharConfigDescriptorResult *> *op, AsyncStatus status)
1495 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1496 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"read operation failed";
1500 ComPtr<IClientCharConfigDescriptorResult> iValue;
1502 hr = op->GetResults(&iValue);
1505 GattClientCharacteristicConfigurationDescriptorValue
value;
1506 hr = iValue->get_ClientCharacteristicConfigurationDescriptor(&
value);
1510 bool correct =
false;
1511 if (
value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
1515 if (
value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
1519 if (
value == GattClientCharacteristicConfigurationDescriptorValue_None)
1522 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle
1523 <<
"read operation failed. Obtained unexpected value.";
1531 service->characteristicList[charHandle].descriptorList[descHandle] = descData;
1536 hr = readOp->put_Completed(
1537 Callback<IAsyncOperationCompletedHandler<ClientCharConfigDescriptorResult *>>(
1538 readCompletedLambda).Get());
1544 ComPtr<IGattCharacteristic3> characteristic3;
1545 HRESULT hr = characteristic.As(&characteristic3);
1548 ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
1549 hr = characteristic3->GetDescriptorsForUuidAsync(descData.
uuid, &op);
1552 ComPtr<IGattDescriptorsResult>
result;
1553 hr = QWinRTFunctions::await(op,
result.GetAddressOf(),
1554 QWinRTFunctions::ProcessMainThreadEvents, 5000);
1558 GattCommunicationStatus commStatus;
1559 hr =
result->get_Status(&commStatus);
1560 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
1566 ComPtr<IVectorView<GattDescriptor *>> descriptors;
1567 hr =
result->get_Descriptors(&descriptors);
1571 hr = descriptors->get_Size(&
size);
1575 qCWarning(QT_BT_WINDOWS) <<
"No descriptor with uuid" << descData.
uuid <<
"was found.";
1578 }
else if (
size > 1) {
1579 qCWarning(QT_BT_WINDOWS) <<
"There is more than 1 descriptor with uuid" << descData.
uuid;
1582 ComPtr<IGattDescriptor> descriptor;
1583 hr = descriptors->GetAt(0, &descriptor);
1586 ComPtr<IAsyncOperation<GattReadResult*>> readOp;
1587 hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
1590 auto readCompletedLambda = [charHandle, descHandle, descUuid,
service]
1591 (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
1593 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1594 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"read operation failed";
1598 ComPtr<IGattReadResult> descriptorValue;
1600 hr = op->GetResults(&descriptorValue);
1602 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain result for descriptor" << descHandle;
1607 descData.
uuid = descUuid;
1612 service->characteristicList[charHandle].descriptorList[descHandle] = descData;
1617 hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
1618 readCompletedLambda).Get());
1624 const QSharedPointer<QLowEnergyServicePrivate> service,
1629 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << newValue <<
mode;
1630 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1638 if (!service->characteristicList.contains(charHandle)) {
1639 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charHandle <<
"cannot be found in service"
1649 qCDebug(QT_BT_WINDOWS) <<
"Write flag is not set for characteristic" << charHandle;
1651 auto characteristicCallback = [charHandle, service, newValue, writeWithResponse,
this](
1652 ComPtr<IGattCharacteristic> characteristic) {
1653 writeCharacteristicHelper(service, charHandle, newValue, writeWithResponse,
1657 HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
1659 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native characteristic" << charData.uuid
1660 <<
"from service" << service->uuid;
1665void QLowEnergyControllerPrivateWinRT::writeCharacteristicHelper(
1666 const QSharedPointer<QLowEnergyServicePrivate> service,
1668 bool writeWithResponse, GattCharacteristicComPtr characteristic)
1670 ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
1671 HRESULT hr = GetActivationFactory(
1672 HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
1676 ComPtr<ABI::Windows::Storage::Streams::IBuffer>
buffer;
1684 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
1685 hr =
buffer.As(&byteAccess);
1689 hr = byteAccess->Buffer(&bytes);
1692 memcpy(bytes, newValue,
length);
1693 ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
1694 GattWriteOption
option = writeWithResponse ? GattWriteOption_WriteWithResponse
1695 : GattWriteOption_WriteWithoutResponse;
1696 hr = characteristic->WriteValueWithOptionAsync(
buffer.Get(),
option, &writeOp);
1699 const auto charData = service->characteristicList.value(charHandle);
1700 QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(
this);
1701 auto writeCompletedLambda =
1702 [charData, charHandle, newValue, service, writeWithResponse, thisPtr]
1703 (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
1705 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1706 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charHandle <<
"write operation failed";
1710 GattCommunicationStatus
result;
1712 hr = op->GetResults(&
result);
1713 if (hr == E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH) {
1714 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charHandle
1715 <<
"write operation was tried with invalid value length";
1721 if (
result != GattCommunicationStatus_Success) {
1722 qCDebug(QT_BT_WINDOWS) <<
"Characteristic" << charHandle <<
"write operation failed";
1729 thisPtr->updateValueOfCharacteristic(charHandle, newValue,
false);
1730 if (writeWithResponse) {
1736 hr = writeOp->put_Completed(
1737 Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
1738 writeCompletedLambda).Get());
1744 const QSharedPointer<QLowEnergyServicePrivate> service,
1749 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << descHandle << newValue;
1750 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1759 if (!service->characteristicList.contains(charHandle)) {
1760 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"in characteristic" << charHandle
1761 <<
"could not be found in service" << service->uuid;
1766 const auto charData = service->characteristicList.value(charHandle);
1768 auto characteristicCallback = [descHandle, charHandle, service, newValue,
this](
1769 ComPtr<IGattCharacteristic> characteristic) {
1770 writeDescriptorHelper(service, charHandle, descHandle, newValue, characteristic);
1773 HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
1775 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain native characteristic" << charData.uuid
1776 <<
"from service" << service->uuid;
1781void QLowEnergyControllerPrivateWinRT::writeDescriptorHelper(
1782 const QSharedPointer<QLowEnergyServicePrivate> service,
1786 GattCharacteristicComPtr characteristic)
1789 const auto charData = service->characteristicList.value(charHandle);
1790 if (!charData.descriptorList.contains(descHandle)) {
1791 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle
1792 <<
"could not be found in Characteristic" << charHandle;
1796 if (descData.
uuid ==
1798 GattClientCharacteristicConfigurationDescriptorValue
value;
1799 quint16 intValue = qFromLittleEndian<quint16>(newValue);
1800 if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate
1801 && intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
1802 qCWarning(QT_BT_WINDOWS) <<
"Setting both Indicate and Notify "
1803 "is not supported on WinRT";
1804 value = GattClientCharacteristicConfigurationDescriptorValue(
1805 (GattClientCharacteristicConfigurationDescriptorValue_Indicate
1806 | GattClientCharacteristicConfigurationDescriptorValue_Notify));
1807 }
else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
1808 value = GattClientCharacteristicConfigurationDescriptorValue_Indicate;
1809 }
else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
1810 value = GattClientCharacteristicConfigurationDescriptorValue_Notify;
1811 }
else if (intValue == 0) {
1812 value = GattClientCharacteristicConfigurationDescriptorValue_None;
1814 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle
1815 <<
"write operation failed: Invalid value";
1819 ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
1821 characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(
value, &writeOp);
1824 QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(
this);
1825 auto writeCompletedLambda = [charHandle, descHandle, newValue,
service, thisPtr]
1826 (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
1828 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1829 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"write operation failed";
1833 GattCommunicationStatus
result;
1835 hr = op->GetResults(&
result);
1838 if (
result != GattCommunicationStatus_Success) {
1839 qCWarning(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"write operation failed";
1844 thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue,
false);
1849 hr = writeOp->put_Completed(
1850 Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus >>(
1851 writeCompletedLambda).Get());
1857 ComPtr<IGattCharacteristic3> characteristic3;
1858 HRESULT hr = characteristic.As(&characteristic3);
1861 ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
1862 hr = characteristic3->GetDescriptorsForUuidAsync(descData.
uuid, &op);
1865 ComPtr<IGattDescriptorsResult>
result;
1866 hr = QWinRTFunctions::await(op,
result.GetAddressOf(),
1867 QWinRTFunctions::ProcessMainThreadEvents, 5000);
1870 GattCommunicationStatus commStatus;
1871 hr =
result->get_Status(&commStatus);
1872 if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
1873 qCWarning(QT_BT_WINDOWS) <<
"Descriptor operation failed";
1877 ComPtr<IVectorView<GattDescriptor *>> descriptors;
1878 hr =
result->get_Descriptors(&descriptors);
1882 hr = descriptors->get_Size(&
size);
1886 qCWarning(QT_BT_WINDOWS) <<
"No descriptor with uuid" << descData.
uuid <<
"was found.";
1888 }
else if (
size > 1) {
1889 qCWarning(QT_BT_WINDOWS) <<
"There is more than 1 descriptor with uuid" << descData.
uuid;
1891 ComPtr<IGattDescriptor> descriptor;
1892 hr = descriptors->GetAt(0, &descriptor);
1895 ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
1896 hr = GetActivationFactory(
1897 HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
1901 ComPtr<ABI::Windows::Storage::Streams::IBuffer>
buffer;
1909 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
1910 hr =
buffer.As(&byteAccess);
1914 hr = byteAccess->Buffer(&bytes);
1917 memcpy(bytes, newValue,
length);
1918 ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
1919 hr = descriptor->WriteValueAsync(
buffer.Get(), &writeOp);
1922 QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(
this);
1923 auto writeCompletedLambda = [charHandle, descHandle, newValue,
service, thisPtr]
1924 (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
1926 if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
1927 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"write operation failed";
1931 GattCommunicationStatus
result;
1933 hr = op->GetResults(&
result);
1936 if (
result != GattCommunicationStatus_Success) {
1937 qCDebug(QT_BT_WINDOWS) <<
"Descriptor" << descHandle <<
"write operation failed";
1942 thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue,
false);
1947 hr = writeOp->put_Completed(
1948 Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
1949 writeCompletedLambda).Get());
1963 if (!mGattSession) {
1964 qCDebug(QT_BT_WINDOWS) <<
"mtu queried before GattSession available. Using default mtu.";
1968 HRESULT hr = mGattSession->get_MaxPduSize(&
mtu);
1969 RETURN_IF_FAILED(
"could not obtain MTU size",
return mtu);
1970 qCDebug(QT_BT_WINDOWS) <<
"mtu determined to be" <<
mtu;
1974void QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged(
1977 qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << charHandle <<
data;
1978 qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ <<
"Changing service pointer from thread"
1980 QSharedPointer<QLowEnergyServicePrivate> service =
1982 if (service.isNull())
1985 qCDebug(QT_BT_WINDOWS) <<
"Characteristic change notification" << service->uuid
1986 << charHandle <<
data.toHex();
1989 if (!characteristic.
isValid()) {
1990 qCWarning(QT_BT_WINDOWS) <<
"characteristicChanged: Cannot find characteristic";
2002void QLowEnergyControllerPrivateWinRT::handleServiceHandlerError(
const QString &
error)
2007 qCWarning(QT_BT_WINDOWS) <<
"Error while discovering services:" <<
error;
2012void QLowEnergyControllerPrivateWinRT::handleConnectionError(
const char *logMessage)
2017 unregisterFromStatusChanges();
2018 unregisterFromMtuChanges();
2023#include "qlowenergycontroller_winrt.moc"
IOBluetoothDevice * device
std::vector< ObjCStrongReference< CBMutableService > > services
Pairing
This enum describes the pairing state between the two Bluetooth devices.
Pairing pairingStatus(const QBluetoothAddress &address) const
Returns the current bluetooth pairing status of address, if it's unpaired, paired,...
@ CharacteristicUserDescription
@ ClientCharacteristicConfiguration
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
qsizetype length() const noexcept
Same as size().
bool hasExpired() const noexcept
Returns true if this QDeadlineTimer object has expired, false if there remains time left.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qsizetype size() const noexcept
void append(parameter_type t)
The QLowEnergyAdvertisingData class represents the data to be broadcast during Bluetooth Low Energy a...
The QLowEnergyAdvertisingParameters class represents the parameters used for Bluetooth Low Energy adv...
QLowEnergyCharacteristic::PropertyTypes properties() const
Returns the properties of the characteristic.
bool isValid() const
Returns true if the QLowEnergyCharacteristic object is valid, otherwise returns false.
The QLowEnergyConnectionParameters class is used when requesting or reporting an update of the parame...
void discoverServiceDetails(const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode) override
void stopAdvertising() override
~QLowEnergyControllerPrivateWinRT() override
QLowEnergyControllerPrivateWinRT()
void characteristicChanged(quint16 charHandle, const QByteArray &data)
void addToGenericAttributeList(const QLowEnergyServiceData &service, QLowEnergyHandle startHandle) override
void readDescriptor(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QLowEnergyHandle descriptorHandle) override
void connectToDevice() override
void disconnectFromDevice() override
void writeDescriptor(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QLowEnergyHandle descriptorHandle, const QByteArray &newValue) override
void startAdvertising(const QLowEnergyAdvertisingParameters ¶ms, const QLowEnergyAdvertisingData &advertisingData, const QLowEnergyAdvertisingData &scanResponseData) override
void readCharacteristic(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle) override
void writeCharacteristic(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QByteArray &newValue, QLowEnergyService::WriteMode mode) override
void requestConnectionUpdate(const QLowEnergyConnectionParameters ¶ms) override
void discoverServices() override
QLowEnergyCharacteristic characteristicForHandle(QLowEnergyHandle handle)
Returns a valid characteristic if the given handle is the handle of the characteristic itself or one ...
QSharedPointer< QLowEnergyServicePrivate > serviceForHandle(QLowEnergyHandle handle)
void invalidateServices()
ServiceDataMap serviceList
QLowEnergyController::Error error
void setError(QLowEnergyController::Error newError)
QLowEnergyController::Role role
quint16 updateValueOfCharacteristic(QLowEnergyHandle charHandle, const QByteArray &value, bool appendValue)
Returns the length of the updated characteristic value.
QLowEnergyController::ControllerState state
QBluetoothAddress remoteDevice
void setState(QLowEnergyController::ControllerState newState)
@ UnknownRemoteDeviceError
The QLowEnergyServiceData class is used to set up GATT service data. \inmodule QtBluetooth.
DiscoveryMode
This enum lists service discovery modes.
@ CharacteristicWriteError
@ CharacteristicReadError
@ RemoteServiceDiscovered
@ RemoteServiceDiscovering
WriteMode
This enum describes the mode to be used when writing a characteristic value.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
QThread * thread() const
Returns the thread in which the object lives.
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
bool remove(const T &value)
iterator insert(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
void start(Priority=InheritPriority)
static QThread * currentThread()
void finished(QPrivateSignal)
void started(QPrivateSignal)
void deviceConnected(ComPtr< IBluetoothLEDevice > device, ComPtr< IGattSession > session)
QWinRTLowEnergyConnectionHandler(const QBluetoothAddress &address)
~QWinRTLowEnergyConnectionHandler()
void errorOccurred(const QString &error)
void handleDeviceDisconnectRequest()
uint mCharacteristicsCountToBeDiscovered
QList< QBluetoothUuid > mIndicateChars
void errorOccured(const QString &error)
void charListObtained(const QBluetoothUuid &service, QHash< QLowEnergyHandle, QLowEnergyServicePrivate::CharData > charList, QList< QBluetoothUuid > indicateChars, QLowEnergyHandle startHandle, QLowEnergyHandle endHandle)
QLowEnergyService::DiscoveryMode mMode
QWinRTLowEnergyServiceHandler(const QBluetoothUuid &service, const ComPtr< IGattDeviceService3 > &deviceService, QLowEnergyService::DiscoveryMode mode)
ComPtr< IGattDeviceService3 > mDeviceService
~QWinRTLowEnergyServiceHandler()
QHash< QLowEnergyHandle, QLowEnergyServicePrivate::CharData > mCharacteristicList
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Service service()
constexpr Initialization Uninitialized
static QT_BEGIN_NAMESPACE QByteArray byteArrayFromBuffer(const IBuffer &buffer)
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr T qToLittleEndian(T source)
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult
#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, message)
QT_BEGIN_NAMESPACE typedef ITypedEventHandler< BluetoothLEDevice *, IInspectable * > StatusHandler
#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret)
static QByteArray byteArrayFromGattResult(const ComPtr< IGattReadResult > &gattResult, bool isWCharString=false)
static void closeDeviceService(ComPtr< T > service)
#define DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, msg)
#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret)
ITypedEventHandler< GattSession *, IInspectable * > MtuHandler
GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult
static constexpr qint64 kMaxConnectTimeout
ITypedEventHandler< GattCharacteristic *, GattValueChangedEventArgs * > ValueChangedHandler
#define WARN_AND_CONTINUE_IF_FAILED(hr, msg)
#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr)
void registerQLowEnergyControllerMetaType()
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLsizei const GLenum * props
GLuint GLuint64EXT address
GLsizei const void * pointer
GLdouble GLdouble GLdouble GLdouble q
QLatin1StringView QLatin1String
#define QStringLiteral(str)
#define Q_UNIMPLEMENTED()
if(qFloatDistance(a, b)<(1<< 7))
[0]
settings remove("monkey")
QDeadlineTimer deadline(30s)
myObject disconnect()
[26]
QLowEnergyHandle valueHandle