diff options
author | Oliver Wolff <oliver.wolff@qt.io> | 2016-10-31 15:32:54 +0100 |
---|---|---|
committer | Oliver Wolff <oliver.wolff@qt.io> | 2016-11-01 12:06:02 +0000 |
commit | b825e8e5703c12902112fd96285a81c6f2824f96 (patch) | |
tree | ba0b2fe4e46e004798d3bb939100d8ecd530bbda /src | |
parent | d6e28d96927cec11df8bae6d8f150fb985984bbf (diff) |
winrt: BTLE: Handle characteristic changes
Task-number: QTBUG-37779
Change-Id: Ie368e85286a3d132c633ef759a2bdb0fb206172d
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.h | 33 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_winrt.cpp | 83 |
2 files changed, 99 insertions, 17 deletions
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index 38e38752..f6bf0ae3 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -84,20 +84,7 @@ QT_END_NAMESPACE #include "android/lowenergynotificationhub_p.h" #elif defined(QT_WINRT_BLUETOOTH) #include <wrl.h> - -namespace ABI { - namespace Windows { - namespace Devices { - namespace Bluetooth { - struct IBluetoothLEDevice; - namespace GenericAttributeProfile { - struct IGattDeviceService; - struct IGattCharacteristic; - } - } - } - } -} +#include <windows.devices.bluetooth.h> class QWinRTLowEnergyServiceHandler; #endif @@ -433,13 +420,31 @@ private slots: void characteristicChanged(int charHandle, const QByteArray &data); void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode); #elif defined(QT_WINRT_BLUETOOTH) +private slots: + void characteristicChanged(int charHandle, const QByteArray &data); + private: Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice; EventRegistrationToken mStatusChangedToken; + struct ValueChangedEntry { + ValueChangedEntry() {} + ValueChangedEntry(Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> c, + EventRegistrationToken t) + : characteristic(c) + , token(t) + { + } + + Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> characteristic; + EventRegistrationToken token; + }; + QVector<ValueChangedEntry> mValueChangedTokens; Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> getNativeService(const QBluetoothUuid &serviceUuid); Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid); + void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid); + void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer, Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService); #endif diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index 25371e74..868cadb3 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -63,6 +63,7 @@ using namespace ABI::Windows::Storage::Streams; QT_BEGIN_NAMESPACE typedef ITypedEventHandler<BluetoothLEDevice *, IInspectable *> StatusHandler; +typedef ITypedEventHandler<GattCharacteristic *, GattValueChangedEventArgs *> ValueChangedHandler; typedef GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult; typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult; @@ -141,6 +142,7 @@ public: public slots: void obtainCharList() { + QVector<QBluetoothUuid> indicateChars; quint16 startHandle = 0; quint16 endHandle = 0; qCDebug(QT_BT_WINRT) << __FUNCTION__; @@ -148,7 +150,7 @@ public slots: HRESULT hr = mDeviceService->GetAllCharacteristics(&characteristics); Q_ASSERT_SUCCEEDED(hr); if (!characteristics) { - emit charListObtained(mService, mCharacteristicList, startHandle, endHandle); + emit charListObtained(mService, mCharacteristicList, indicateChars, startHandle, endHandle); QThread::currentThread()->quit(); return; } @@ -236,6 +238,7 @@ public slots: descData.value = QByteArray(2, Qt::Uninitialized); qToLittleEndian(result, descData.value.data()); + indicateChars << charData.uuid; } else { ComPtr<IAsyncOperation<GattReadResult *>> readOp; hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp); @@ -252,7 +255,7 @@ public slots: } mCharacteristicList.insert(handle, charData); } - emit charListObtained(mService, mCharacteristicList, startHandle, endHandle); + emit charListObtained(mService, mCharacteristicList, indicateChars, startHandle, endHandle); QThread::currentThread()->quit(); } @@ -262,7 +265,9 @@ public: QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> mCharacteristicList; signals: - void charListObtained(const QBluetoothUuid &service, QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList, + void charListObtained(const QBluetoothUuid &service, QHash<QLowEnergyHandle, + QLowEnergyServicePrivate::CharData> charList, + QVector<QBluetoothUuid> indicateChars, QLowEnergyHandle startHandle, QLowEnergyHandle endHandle); }; @@ -278,6 +283,10 @@ QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate() { if (mDevice && mStatusChangedToken.value) mDevice->remove_ConnectionStatusChanged(mStatusChangedToken); + + qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens"; + for (const ValueChangedEntry &entry : mValueChangedTokens) + entry.characteristic->remove_ValueChanged(entry.token); } void QLowEnergyControllerPrivate::init() @@ -432,6 +441,39 @@ ComPtr<IGattCharacteristic> QLowEnergyControllerPrivate::getNativeCharacteristic return characteristic; } +void QLowEnergyControllerPrivate::registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid) +{ + qCDebug(QT_BT_WINRT) << "Registering characteristic" << charUuid << "in service" + << serviceUuid << "for value changes"; + for (const ValueChangedEntry &entry : mValueChangedTokens) { + GUID guuid; + HRESULT hr; + hr = entry.characteristic->get_Uuid(&guuid); + Q_ASSERT_SUCCEEDED(hr); + if (QBluetoothUuid(guuid) == charUuid) + return; + } + ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(serviceUuid, charUuid); + + EventRegistrationToken token; + HRESULT hr; + hr = characteristic->add_ValueChanged(Callback<ValueChangedHandler>([this](IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args) { + HRESULT hr; + quint16 handle; + hr = characteristic->get_AttributeHandle(&handle); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IBuffer> buffer; + hr = args->get_CharacteristicValue(&buffer); + Q_ASSERT_SUCCEEDED(hr); + characteristicChanged(handle, byteArrayFromBuffer(buffer)); + return S_OK; + }).Get(), &token); + Q_ASSERT_SUCCEEDED(hr); + mValueChangedTokens.append(ValueChangedEntry(characteristic, token)); + qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service" + << serviceUuid << "registered for value changes"; +} + void QLowEnergyControllerPrivate::obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer, ComPtr<IGattDeviceService> service) { @@ -574,6 +616,7 @@ void QLowEnergyControllerPrivate::discoverServiceDetails(const QBluetoothUuid &s connect(thread, &QThread::finished, worker, &QObject::deleteLater); connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained, [this, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList + , QVector<QBluetoothUuid> indicateChars , QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) { if (!serviceList.contains(service)) { qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:" @@ -585,6 +628,15 @@ void QLowEnergyControllerPrivate::discoverServiceDetails(const QBluetoothUuid &s pointer->startHandle = startHandle; pointer->endHandle = endHandle; pointer->characteristicList = charList; + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([indicateChars, service, this]() { + for (const QBluetoothUuid &indicateChar : indicateChars) + registerForValueChanges(service, indicateChar); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + pointer->setState(QLowEnergyService::ServiceDiscovered); thread->exit(0); }); @@ -1014,6 +1066,31 @@ void QLowEnergyControllerPrivate::addToGenericAttributeList(const QLowEnergyServ Q_UNIMPLEMENTED(); } +void QLowEnergyControllerPrivate::characteristicChanged( + int charHandle, const QByteArray &data) +{ + QSharedPointer<QLowEnergyServicePrivate> service = + serviceForHandle(charHandle); + if (service.isNull()) + return; + + qCDebug(QT_BT_WINRT) << "Characteristic change notification" << service->uuid + << charHandle << data.toHex(); + + QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle); + if (!characteristic.isValid()) { + qCWarning(QT_BT_WINRT) << "characteristicChanged: Cannot find characteristic"; + return; + } + + // only update cache when property is readable. Otherwise it remains + // empty. + if (characteristic.properties() & QLowEnergyCharacteristic::Read) + updateValueOfCharacteristic(characteristic.attributeHandle(), + data, false); + emit service->characteristicChanged(characteristic, data); +} + QT_END_NAMESPACE #include "qlowenergycontroller_winrt.moc" |