From 4419f9657724ab8d2f3931966f2861a6737d2083 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Mon, 22 Aug 2022 17:35:50 +0200 Subject: Bluetooth Windows: refactor getNativeService ... to get rid of await() call. The function now requests the services asynchronously and executes a custom callback, passing the selected service as a parameter. After that the refactoring is quite simple: we put all the code after the getNativeService() call into a lambda, and pass this lambda as a last parameter of the updated method. Task-number: QTBUG-105556 Change-Id: If474a7446ee70059e06d46bab48771c31ba37a89 Reviewed-by: Juha Vuolle Reviewed-by: Oliver Wolff (cherry picked from commit 595ce0449b16133d6708c7d0a17ce618f4d01724) Reviewed-by: Qt Cherry-pick Bot --- src/bluetooth/qlowenergycontroller_winrt.cpp | 215 +++++++++++++++------------ src/bluetooth/qlowenergycontroller_winrt_p.h | 10 +- 2 files changed, 132 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index 26b3069b..e7b87d12 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -715,108 +715,129 @@ void QLowEnergyControllerPrivateWinRT::disconnectFromDevice() emit q->disconnected(); } -ComPtr QLowEnergyControllerPrivateWinRT::getNativeService( - const QBluetoothUuid &serviceUuid) +HRESULT QLowEnergyControllerPrivateWinRT::getNativeService(const QBluetoothUuid &serviceUuid, + NativeServiceCallback callback) { - if (m_openedServices.contains(serviceUuid)) - return m_openedServices.value(serviceUuid); + if (m_openedServices.contains(serviceUuid)) { + callback(m_openedServices.value(serviceUuid)); + return S_OK; + } ComPtr device3; HRESULT hr = mDevice.As(&device3); - RETURN_IF_FAILED("Could not convert to IBluetoothDevice3", return nullptr); + RETURN_IF_FAILED("Could not convert to IBluetoothDevice3", return hr); ComPtr> servicesResultOperation; hr = device3->GetGattServicesForUuidAsync(serviceUuid, &servicesResultOperation); - RETURN_IF_FAILED("Could not start async services request", return nullptr); + RETURN_IF_FAILED("Could not start async services request", return hr); - ComPtr result; QPointer thisPtr(this); - hr = QWinRTFunctions::await(servicesResultOperation, result.GetAddressOf(), - QWinRTFunctions::ProcessMainThreadEvents, 5000); - // Guard against the object being deleted while we are awaiting. - if (!thisPtr) { - qCWarning(QT_BT_WINDOWS) << "LE controller was removed while awaiting"; - return nullptr; - } - RETURN_IF_FAILED("Failed to get result of async services request", return nullptr); + hr = servicesResultOperation->put_Completed( + Callback>( + [thisPtr, callback, &serviceUuid]( + IAsyncOperation *op, AsyncStatus status) + { + if (thisPtr) { + if (status != AsyncStatus::Completed) { + qCDebug(QT_BT_WINDOWS) << "Failed to get result of async service request"; + return S_OK; + } + ComPtr result; + ComPtr> deviceServices; + HRESULT hr = op->GetResults(&result); + RETURN_IF_FAILED("Failed to get result of async service request", return hr); - ComPtr> services; - hr = result->get_Services(&services); - RETURN_IF_FAILED("Failed to extract services from the result", return nullptr); + ComPtr> services; + hr = result->get_Services(&services); + RETURN_IF_FAILED("Failed to extract services from the result", return hr); - uint servicesCount = 0; - hr = services->get_Size(&servicesCount); - RETURN_IF_FAILED("Failed to extract services count", return nullptr); + uint servicesCount = 0; + hr = services->get_Size(&servicesCount); + RETURN_IF_FAILED("Failed to extract services count", return hr); - if (servicesCount > 0) { - if (servicesCount > 1) { - qWarning() << "getNativeService: more than one service detected for UUID" << serviceUuid - << "The first service will be used."; + if (servicesCount > 0) { + if (servicesCount > 1) { + qWarning() << "getNativeService: more than one service detected for UUID" + << serviceUuid << "The first service will be used."; + } + ComPtr service; + hr = services->GetAt(0, &service); + if (FAILED(hr)) { + qCDebug(QT_BT_WINDOWS) << "Could not obtain native service for Uuid" + << serviceUuid; + } + if (service) { + thisPtr->m_openedServices[serviceUuid] = service; + callback(service); // Use the service in a custom callback + } + } else { + qCWarning(QT_BT_WINDOWS) << "No services found for Uuid" << serviceUuid; + } + } else { + qCWarning(QT_BT_WINDOWS) << "LE controller was removed while getting native service"; } - ComPtr service; - hr = services->GetAt(0, &service); - if (FAILED(hr)) - qCDebug(QT_BT_WINDOWS) << "Could not obtain native service for Uuid" << serviceUuid; - if (service) - m_openedServices[serviceUuid] = service; - return service; - } else { - qCWarning(QT_BT_WINDOWS) << "No services found for Uuid" << serviceUuid; - } - return nullptr; + return S_OK; + }).Get()); + + return hr; } HRESULT QLowEnergyControllerPrivateWinRT::getNativeCharacteristic( const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid, NativeCharacteristicCallback callback) { - ComPtr service = getNativeService(serviceUuid); - if (!service) - return -1; - - ComPtr service3; - HRESULT hr = service.As(&service3); - RETURN_IF_FAILED("Could not cast service to service3", return hr); - - ComPtr> characteristicRequestOp; - hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp); - QPointer thisPtr(this); - hr = characteristicRequestOp->put_Completed( - Callback>( - [thisPtr, callback]( - IAsyncOperation *op, AsyncStatus status) - { - if (thisPtr) { - if (status != AsyncStatus::Completed) { - qCDebug(QT_BT_WINDOWS) << "Failed to get result of async characteristic operation"; - return S_OK; - } - ComPtr result; - HRESULT hr = op->GetResults(&result); - RETURN_IF_FAILED("Failed to get result of async characteristic operation", return hr); - GattCommunicationStatus status; - hr = result->get_Status(&status); - if (FAILED(hr) || status != GattCommunicationStatus_Success) { - qErrnoWarning(hr, "Native characteristic operation failed."); - return hr; + auto serviceCallback = [thisPtr, callback, charUuid](ComPtr service) { + ComPtr service3; + HRESULT hr = service.As(&service3); + RETURN_IF_FAILED("Could not cast service to service3", return); + + ComPtr> characteristicRequestOp; + hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp); + + hr = characteristicRequestOp->put_Completed( + Callback>( + [thisPtr, callback]( + IAsyncOperation *op, AsyncStatus status) + { + if (thisPtr) { + if (status != AsyncStatus::Completed) { + qCDebug(QT_BT_WINDOWS) << "Failed to get result of async characteristic " + "operation"; + return S_OK; + } + ComPtr result; + HRESULT hr = op->GetResults(&result); + RETURN_IF_FAILED("Failed to get result of async characteristic operation", + return hr); + GattCommunicationStatus status; + hr = result->get_Status(&status); + if (FAILED(hr) || status != GattCommunicationStatus_Success) { + qErrnoWarning(hr, "Native characteristic operation failed."); + return S_OK; + } + ComPtr> characteristics; + hr = result->get_Characteristics(&characteristics); + RETURN_IF_FAILED("Could not obtain characteristic list.", return S_OK); + uint size; + hr = characteristics->get_Size(&size); + RETURN_IF_FAILED("Could not obtain characteristic list's size.", return S_OK); + if (size != 1) + qErrnoWarning("More than 1 characteristic found."); + ComPtr characteristic; + hr = characteristics->GetAt(0, &characteristic); + RETURN_IF_FAILED("Could not obtain first characteristic for service", return S_OK); + if (characteristic) + callback(characteristic); // use the characteristic in a custom callback } - ComPtr> characteristics; - hr = result->get_Characteristics(&characteristics); - RETURN_IF_FAILED("Could not obtain characteristic list.", return hr); - uint size; - hr = characteristics->get_Size(&size); - RETURN_IF_FAILED("Could not obtain characteristic list's size.", return hr); - if (size != 1) - qErrnoWarning("More than 1 characteristic found."); - ComPtr characteristic; - hr = characteristics->GetAt(0, &characteristic); - RETURN_IF_FAILED("Could not obtain first characteristic for service", return hr); - if (characteristic) - callback(characteristic); // use the characteristic in a custom callback - } - return S_OK; - }).Get()); + return S_OK; + }).Get()); + }; + + HRESULT hr = getNativeService(serviceUuid, serviceCallback); + if (FAILED(hr)) + qCDebug(QT_BT_WINDOWS) << "Failed to get native service for" << serviceUuid; return hr; } @@ -1162,12 +1183,19 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( // clear the cache to rediscover service details closeAndRemoveService(service); - ComPtr deviceService = getNativeService(service); - if (!deviceService) { + auto serviceCallback = [service, mode, this](ComPtr deviceService) { + discoverServiceDetailsHelper(service, mode, deviceService); + }; + + HRESULT hr = getNativeService(service, serviceCallback); + if (FAILED(hr)) qCDebug(QT_BT_WINDOWS) << "Could not obtain native service for uuid " << service; - return; - } +} +void QLowEnergyControllerPrivateWinRT::discoverServiceDetailsHelper( + const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode, + GattDeviceServiceComPtr deviceService) +{ auto reactOnDiscoveryError = [](QSharedPointer service, const QString &msg) { @@ -1178,7 +1206,7 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( //update service data QSharedPointer pointer = serviceList.value(service); qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread" - << QThread::currentThread(); + << QThread::currentThread(); pointer->setState(QLowEnergyService::RemoteServiceDiscovering); ComPtr deviceService3; HRESULT hr = deviceService.As(&deviceService3); @@ -1189,34 +1217,39 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( ComPtr> op; hr = deviceService3->GetIncludedServicesAsync(&op); if (FAILED(hr)) { - reactOnDiscoveryError(pointer, QStringLiteral("Could not obtain included service list: %1").arg(hr)); + reactOnDiscoveryError(pointer, + QStringLiteral("Could not obtain included service list: %1").arg(hr)); return; } ComPtr result; hr = QWinRTFunctions::await(op, result.GetAddressOf()); if (FAILED(hr)) { - reactOnDiscoveryError(pointer, QStringLiteral("Could not await service operation: %1").arg(hr)); + reactOnDiscoveryError(pointer, + QStringLiteral("Could not await service operation: %1").arg(hr)); return; } GattCommunicationStatus status; hr = result->get_Status(&status); if (FAILED(hr) || status != GattCommunicationStatus_Success) { reactOnDiscoveryError(pointer, - QStringLiteral("Obtaining list of included services failed: %1").arg(hr)); + QStringLiteral("Obtaining list of included services failed: %1"). + arg(hr)); return; } ComPtr> deviceServices; hr = result->get_Services(&deviceServices); if (FAILED(hr)) { reactOnDiscoveryError(pointer, - QStringLiteral("Could not obtain service list from result: %1").arg(hr)); + QStringLiteral("Could not obtain service list from result: %1"). + arg(hr)); return; } uint serviceCount; hr = deviceServices->get_Size(&serviceCount); if (FAILED(hr)) { reactOnDiscoveryError(pointer, - QStringLiteral("Could not obtain included service list's size: %1").arg(hr)); + QStringLiteral("Could not obtain included service list's size: %1"). + arg(hr)); return; } for (uint i = 0; i < serviceCount; ++i) { diff --git a/src/bluetooth/qlowenergycontroller_winrt_p.h b/src/bluetooth/qlowenergycontroller_winrt_p.h index 1f59c087..77a7716d 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_p.h @@ -123,9 +123,12 @@ private: EventRegistrationToken token; }; QList mValueChangedTokens; - QMap> m_openedServices; - Microsoft::WRL::ComPtr getNativeService(const QBluetoothUuid &serviceUuid); + using GattDeviceServiceComPtr = Microsoft::WRL::ComPtr; + QMap m_openedServices; + + using NativeServiceCallback = std::function; + HRESULT getNativeService(const QBluetoothUuid &serviceUuid, NativeServiceCallback callback); using GattCharacteristicComPtr = Microsoft::WRL::ComPtr; using NativeCharacteristicCallback = std::function; @@ -167,6 +170,9 @@ private: const QLowEnergyHandle descriptorHandle, const QByteArray &newValue, GattCharacteristicComPtr characteristic); + void discoverServiceDetailsHelper(const QBluetoothUuid &service, + QLowEnergyService::DiscoveryMode mode, + GattDeviceServiceComPtr deviceService); void clearAllServices(); void closeAndRemoveService(const QBluetoothUuid &uuid); -- cgit v1.2.1