summaryrefslogtreecommitdiffstats
path: root/src/bluetooth
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2018-01-22 12:24:01 +0100
committerAlex Blasche <alexander.blasche@qt.io>2018-01-25 09:31:49 +0000
commite55981842b702dced8ed0301ff9550e7d98e8a14 (patch)
treecf742a883616bb24f87f027885f9357b41b10dfb /src/bluetooth
parent45ea69635f08f967b31660e2bcd33d3bb8187497 (diff)
BlueZ: Implements characteristicChanged() notifications
This feature depends on ClientCharacteristicConfiguration descriptor types which determine whether changed signals are sent or not. The patch also ensures that cached char values are not updated/cached when the char is not readable. Task-number: QTBUG-46819 Change-Id: I841bcaaca60c588eae7d4067b6ead6af28f957e3 Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src/bluetooth')
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus.cpp88
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus_p.h4
2 files changed, 83 insertions, 9 deletions
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
index 6cbe67bb..e9087642 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
@@ -123,6 +123,35 @@ void QLowEnergyControllerPrivateBluezDBus::devicePropertiesChanged(
}
}
+void QLowEnergyControllerPrivateBluezDBus::characteristicPropertiesChanged(
+ QLowEnergyHandle charHandle, const QString &interface,
+ const QVariantMap &changedProperties,
+ const QStringList &/*removedProperties*/)
+{
+ //qCDebug(QT_BT_BLUEZ) << "$$$$$$$$$$$$$$$$$$ char monitor"
+ // << interface << changedProperties << charHandle;
+ if (interface != QStringLiteral("org.bluez.GattCharacteristic1"))
+ return;
+
+ if (!changedProperties.contains(QStringLiteral("Value")))
+ return;
+
+ const QLowEnergyCharacteristic changedChar = characteristicForHandle(charHandle);
+ const QLowEnergyDescriptor ccnDescriptor = changedChar.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (!ccnDescriptor.isValid())
+ return;
+
+ const QByteArray newValue = changedProperties.value(QStringLiteral("Value")).toByteArray();
+ if (changedChar.properties() & QLowEnergyCharacteristic::Read)
+ updateValueOfCharacteristic(charHandle, newValue, false); //TODO upgrade to NEW_VALUE/APPEND_VALUE
+
+ auto service = serviceForHandle(charHandle);
+
+ if (!service.isNull())
+ emit service->characteristicChanged(changedChar, newValue);
+}
+
void QLowEnergyControllerPrivateBluezDBus::interfacesRemoved(
const QDBusObjectPath &objectPath, const QStringList &/*interfaces*/)
{
@@ -429,7 +458,7 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
//populate servicePrivate based on dbus data
serviceData->startHandle = runningHandle++;
- for (const GattCharacteristic &dbusChar : qAsConst(dbusData.characteristics)) {
+ for (GattCharacteristic &dbusChar : dbusData.characteristics) {
const QLowEnergyHandle indexHandle = runningHandle++;
QLowEnergyServicePrivate::CharData charData;
@@ -477,6 +506,23 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
descData.uuid = QBluetoothUuid(descEntry->uUID());
charData.descriptorList.insert(descriptorHandle, descData);
+
+ // every ClientCharacteristicConfiguration needs to track property changes
+ if (descData.uuid
+ == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ dbusChar.charMonitor = QSharedPointer<OrgFreedesktopDBusPropertiesInterface>::create(
+ QStringLiteral("org.bluez"),
+ dbusChar.characteristic->path(),
+ QDBusConnection::systemBus(), this);
+ connect(dbusChar.charMonitor.data(), &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
+ this, [this, indexHandle](const QString &interface, const QVariantMap &changedProperties,
+ const QStringList &removedProperties) {
+
+ characteristicPropertiesChanged(indexHandle, interface,
+ changedProperties, removedProperties);
+ });
+ }
+
// schedule read for initial descriptor value
GattJob job;
job.flags = GattJob::JobFlags({GattJob::DescRead, GattJob::ServiceDiscovery});
@@ -533,7 +579,8 @@ void QLowEnergyControllerPrivateBluezDBus::onCharReadFinished(QDBusPendingCallWa
service->setError(QLowEnergyService::CharacteristicReadError);
} else {
qCDebug(QT_BT_BLUEZ) << "Read Char:" << charData.uuid << reply.value().toHex();
- updateValueOfCharacteristic(nextJob.handle, reply.value(), false);
+ if (charData.properties.testFlag(QLowEnergyCharacteristic::Read))
+ updateValueOfCharacteristic(nextJob.handle, reply.value(), false);
if (isServiceDiscovery) {
if (nextJob.flags.testFlag(GattJob::LastServiceDiscovery))
@@ -636,11 +683,15 @@ void QLowEnergyControllerPrivateBluezDBus::onCharWriteFinished(QDBusPendingCallW
<< reply.error().name() << reply.error().message();
service->setError(QLowEnergyService::CharacteristicWriteError);
} else {
- qCDebug(QT_BT_BLUEZ) << "Write Char:" << charData.uuid << nextJob.value.toHex();
- updateValueOfCharacteristic(nextJob.handle, nextJob.value, false);
+ if (charData.properties.testFlag(QLowEnergyCharacteristic::Read))
+ updateValueOfCharacteristic(nextJob.handle, nextJob.value, false);
QLowEnergyCharacteristic ch(service, nextJob.handle);
- emit service->characteristicWritten(ch, nextJob.value);
+ // write without respone implies zero feedback
+ if (nextJob.writeMode == QLowEnergyService::WriteWithResponse) {
+ qCDebug(QT_BT_BLUEZ) << "Written Char:" << charData.uuid << nextJob.value.toHex();
+ emit service->characteristicWritten(ch, nextJob.value);
+ }
}
call->deleteLater();
@@ -837,10 +888,29 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
if (descUuid != QBluetoothUuid(gattDesc->uUID()))
continue;
- QDBusPendingReply<> reply = gattDesc->WriteValue(nextJob.value, QVariantMap());
- QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, &QDBusPendingCallWatcher::finished,
- this, &QLowEnergyControllerPrivateBluezDBus::onDescWriteFinished);
+ //notifications enabled via characteristics Start/StopNotify() functions
+ //otherwise regular WriteValue() calls on descriptor interface
+ if (descUuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ const QByteArray value = nextJob.value;
+
+ QDBusPendingReply<> reply;
+ qCDebug(QT_BT_BLUEZ) << "Init CCC change to" << value.toHex()
+ << charData.uuid << service->uuid;
+ if (value == QByteArray::fromHex("0100") || value == QByteArray::fromHex("0200"))
+ reply = gattChar.characteristic->StartNotify();
+ else
+ reply = gattChar.characteristic->StopNotify();
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ this, &QLowEnergyControllerPrivateBluezDBus::onDescWriteFinished);
+ } else {
+ QDBusPendingReply<> reply = gattDesc->WriteValue(nextJob.value, QVariantMap());
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ this, &QLowEnergyControllerPrivateBluezDBus::onDescWriteFinished);
+
+ }
+
foundDesc = true;
break;
}
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
index 7195bfbf..7ac1808f 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
@@ -126,6 +126,9 @@ private:
private slots:
void devicePropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
const QStringList &/*invalidatedProperties*/);
+ void characteristicPropertiesChanged(QLowEnergyHandle charHandle, const QString &interface,
+ const QVariantMap &changedProperties,
+ const QStringList &invalidatedProperties);
void interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces);
void onCharReadFinished(QDBusPendingCallWatcher *call);
@@ -145,6 +148,7 @@ private:
struct GattCharacteristic
{
QSharedPointer<OrgBluezGattCharacteristic1Interface> characteristic;
+ QSharedPointer<OrgFreedesktopDBusPropertiesInterface> charMonitor;
QVector<QSharedPointer<OrgBluezGattDescriptor1Interface>> descriptors;
};