summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@qt.io>2016-10-31 15:32:54 +0100
committerOliver Wolff <oliver.wolff@qt.io>2016-11-01 12:06:02 +0000
commitb825e8e5703c12902112fd96285a81c6f2824f96 (patch)
treeba0b2fe4e46e004798d3bb939100d8ecd530bbda /src
parentd6e28d96927cec11df8bae6d8f150fb985984bbf (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.h33
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt.cpp83
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"