diff options
Diffstat (limited to 'src/bluetooth/qlowenergycontroller_winrt.cpp')
-rw-r--r-- | src/bluetooth/qlowenergycontroller_winrt.cpp | 215 |
1 files changed, 124 insertions, 91 deletions
diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index 14eddfbb..88c93f4f 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -751,108 +751,129 @@ void QLowEnergyControllerPrivateWinRT::disconnectFromDevice() emit q->disconnected(); } -ComPtr<IGattDeviceService> 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<IBluetoothLEDevice3> 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<IAsyncOperation<GattDeviceServicesResult *>> 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<IGattDeviceServicesResult> result; QPointer<QLowEnergyControllerPrivateWinRT> 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<IAsyncOperationCompletedHandler< + GenericAttributeProfile::GattDeviceServicesResult *>>( + [thisPtr, callback, &serviceUuid]( + IAsyncOperation<GattDeviceServicesResult *> *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<IGattDeviceServicesResult> result; + ComPtr<IVectorView<GattDeviceService *>> deviceServices; + HRESULT hr = op->GetResults(&result); + RETURN_IF_FAILED("Failed to get result of async service request", return hr); - ComPtr<IVectorView<GattDeviceService *>> services; - hr = result->get_Services(&services); - RETURN_IF_FAILED("Failed to extract services from the result", return nullptr); + ComPtr<IVectorView<GattDeviceService *>> 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<IGattDeviceService> 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<IGattDeviceService> 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<IGattDeviceService> service = getNativeService(serviceUuid); - if (!service) - return -1; - - ComPtr<IGattDeviceService3> service3; - HRESULT hr = service.As(&service3); - RETURN_IF_FAILED("Could not cast service to service3", return hr); - - ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicRequestOp; - hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp); - QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this); - hr = characteristicRequestOp->put_Completed( - Callback<IAsyncOperationCompletedHandler<GattCharacteristicsResult *>>( - [thisPtr, callback]( - IAsyncOperation<GattCharacteristicsResult *> *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<IGattCharacteristicsResult> 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<IGattDeviceService> service) { + ComPtr<IGattDeviceService3> service3; + HRESULT hr = service.As(&service3); + RETURN_IF_FAILED("Could not cast service to service3", return); + + ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicRequestOp; + hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp); + + hr = characteristicRequestOp->put_Completed( + Callback<IAsyncOperationCompletedHandler<GattCharacteristicsResult *>>( + [thisPtr, callback]( + IAsyncOperation<GattCharacteristicsResult *> *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<IGattCharacteristicsResult> 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<IVectorView<GattCharacteristic *>> 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<IGattCharacteristic> 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<IVectorView<GattCharacteristic *>> 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<IGattCharacteristic> 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; } @@ -1198,12 +1219,19 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( // clear the cache to rediscover service details closeAndRemoveService(service); - ComPtr<IGattDeviceService> deviceService = getNativeService(service); - if (!deviceService) { + auto serviceCallback = [service, mode, this](ComPtr<IGattDeviceService> 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<QLowEnergyServicePrivate> service, const QString &msg) { @@ -1214,7 +1242,7 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( //update service data QSharedPointer<QLowEnergyServicePrivate> 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<IGattDeviceService3> deviceService3; HRESULT hr = deviceService.As(&deviceService3); @@ -1225,34 +1253,39 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails( ComPtr<IAsyncOperation<GattDeviceServicesResult *>> 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<IGattDeviceServicesResult> 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<IVectorView<GattDeviceService *>> 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) { |