void obtainCharList() { mIndicateChars.clear(); qCDebug(QT_BT_WINRT) << __FUNCTION__; ComPtr> characteristicsOp; ComPtr characteristicsResult; HRESULT hr = mDeviceService->GetCharacteristicsAsync(&characteristicsOp); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); GattCommunicationStatus status; hr = characteristicsResult->get_Status(&status); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); if (status != GattCommunicationStatus_Success) { emitErrorAndQuitThread(QLatin1String("Could not obtain char list")); return; } ComPtr> characteristics; hr = characteristicsResult->get_Characteristics(&characteristics); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); uint characteristicsCount; hr = characteristics->get_Size(&characteristicsCount); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); mCharacteristicsCountToBeDiscovered = characteristicsCount; for (uint i = 0; i < characteristicsCount; ++i) { ComPtr characteristic; hr = characteristics->GetAt(i, &characteristic); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain characteristic at" << i; --mCharacteristicsCountToBeDiscovered; continue; } ComPtr characteristic3; hr = characteristic.As(&characteristic3); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not cast characteristic"; --mCharacteristicsCountToBeDiscovered; continue; } // For some strange reason, Windows doesn't discover descriptors of characteristics (if not paired). // Qt API assumes that all characteristics and their descriptors are discovered in one go. // So we start 'GetDescriptorsAsync' for each discovered characteristic and finish only // when GetDescriptorsAsync for all characteristics return. ComPtr> descAsyncResult; hr = characteristic3->GetDescriptorsAsync(&descAsyncResult); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors"; --mCharacteristicsCountToBeDiscovered; continue; } hr = descAsyncResult->put_Completed( Callback>( [this, characteristic] (IAsyncOperation *op, AsyncStatus status) { if (status != AsyncStatus::Completed) { qCWarning(QT_BT_WINRT) << "Descriptor operation unsuccessful"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } quint16 handle; HRESULT hr = characteristic->get_AttributeHandle(&handle); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's attribute handle"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } QLowEnergyServicePrivate::CharData charData; charData.valueHandle = handle + 1; if (mStartHandle == 0 || mStartHandle > handle) mStartHandle = handle; if (mEndHandle == 0 || mEndHandle < handle) mEndHandle = handle; GUID guuid; hr = characteristic->get_Uuid(&guuid); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's Uuid"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } charData.uuid = QBluetoothUuid(guuid); GattCharacteristicProperties properties; hr = characteristic->get_CharacteristicProperties(&properties); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's properties"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties & 0xff); if (charData.properties & QLowEnergyCharacteristic::Read) { ComPtr> readOp; hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not read characteristic"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } ComPtr readResult; hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain characteristic read result"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } if (!readResult) qCWarning(QT_BT_WINRT) << "Characteristic read result is null"; else charData.value = byteArrayFromGattResult(readResult); } mCharacteristicList.insert(handle, charData); ComPtr> descriptors; ComPtr result; hr = op->GetResults(&result); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain descriptor read result"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } GattCommunicationStatus commStatus; hr = result->get_Status(&commStatus); if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) { qCWarning(QT_BT_WINRT) << "Descriptor operation failed"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } hr = result->get_Descriptors(&descriptors); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } uint descriptorCount; hr = descriptors->get_Size(&descriptorCount); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors' size"; --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; } for (uint j = 0; j < descriptorCount; ++j) { QLowEnergyServicePrivate::DescData descData; ComPtr descriptor; hr = descriptors->GetAt(j, &descriptor); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor") quint16 descHandle; hr = descriptor->get_AttributeHandle(&descHandle); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's attribute handle") GUID descriptorUuid; hr = descriptor->get_Uuid(&descriptorUuid); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's Uuid") descData.uuid = QBluetoothUuid(descriptorUuid); charData.descriptorList.insert(descHandle, descData); if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) { ComPtr> readOp; hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value") ComPtr readResult; mIndicateChars << charData.uuid; hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result. Fixed") GattClientCharacteristicConfigurationDescriptorValue value; hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not get descriptor value from result") quint16 result = 0; bool correct = false; if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) { result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate; correct = true; } if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) { result |= GattClientCharacteristicConfigurationDescriptorValue_Notify; correct = true; } if (value == GattClientCharacteristicConfigurationDescriptorValue_None) { correct = true; } if (!correct) continue; descData.value = QByteArray(2, Qt::Uninitialized); qToLittleEndian(result, descData.value.data()); // mIndicateChars << charData.uuid; } else { ComPtr> readOp; hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value") ComPtr readResult; hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); WARN_AND_CONTINUE_IF_FAILED(hr, "Could await descriptor read result") if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription) descData.value = byteArrayFromGattResult(readResult, true); else descData.value = byteArrayFromGattResult(readResult); } charData.descriptorList.insert(descHandle, descData); } mCharacteristicList.insert(handle, charData); --mCharacteristicsCountToBeDiscovered; checkAllCharacteristicsDiscovered(); return S_OK; }).Get()); if (FAILED(hr)) { qCWarning(QT_BT_WINRT) << "Could not register descriptor callback"; --mCharacteristicsCountToBeDiscovered; continue; } } checkAllCharacteristicsDiscovered(); }