summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2018-01-04 13:08:29 +0100
committerAlex Blasche <alexander.blasche@qt.io>2018-01-25 09:31:44 +0000
commit1e03015803549e2865b2772fe5be43d7bec8ccc1 (patch)
tree1e0846a9ed2c608946e4886688d704e3c3f6de1c /src
parentda4273723f42bb53827124101d91afa97d14b984 (diff)
Implement Char read & write for dbus Gatt
Read/write is limited to central role support. Peripheral role support will follow at a later stage. Task-number: QTBUG-46819 Change-Id: Idc27ea31cf0629470dc46490235c57f64b51498d Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus.cpp122
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus_p.h3
2 files changed, 117 insertions, 8 deletions
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
index b398def7..3f3bcbaa 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
@@ -611,6 +611,43 @@ void QLowEnergyControllerPrivateBluezDBus::onDescReadFinished(QDBusPendingCallWa
prepareNextJob();
}
+void QLowEnergyControllerPrivateBluezDBus::onCharWriteFinished(QDBusPendingCallWatcher *call)
+{
+ Q_ASSERT(jobPending);
+ Q_ASSERT(!jobs.isEmpty());
+
+ const GattJob nextJob = jobs.constFirst();
+ Q_ASSERT(nextJob.flags.testFlag(GattJob::CharWrite));
+
+ QSharedPointer<QLowEnergyServicePrivate> service = nextJob.service;
+ if (!dbusServices.contains(service->uuid)) {
+ qCWarning(QT_BT_BLUEZ) << "onCharWriteFinished: Invalid GATT job. Skipping.";
+ call->deleteLater();
+ prepareNextJob();
+ return;
+ }
+
+ const QLowEnergyServicePrivate::CharData &charData =
+ service->characteristicList.value(nextJob.handle);
+
+ QDBusPendingReply<> reply = *call;
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot initiate writing of" << charData.uuid
+ << "of service" << service->uuid
+ << 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);
+
+ QLowEnergyCharacteristic ch(service, nextJob.handle);
+ emit service->characteristicWritten(ch, nextJob.value);
+ }
+
+ call->deleteLater();
+ prepareNextJob();
+}
+
void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
{
if (jobPending || jobs.isEmpty())
@@ -658,7 +695,34 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
return;
}
} else if (nextJob.flags.testFlag(GattJob::CharWrite)) {
- //TODO implement CharWrite ***************************************
+ // characteristic writing ***************************************
+ if (!service->characteristicList.contains(nextJob.handle)) {
+ qCWarning(QT_BT_BLUEZ) << "Invalid Char handle when writing. Skipping.";
+ prepareNextJob();
+ return;
+ }
+
+ const QLowEnergyServicePrivate::CharData &charData =
+ service->characteristicList.value(nextJob.handle);
+ bool foundChar = false;
+ for (const auto &gattChar : qAsConst(dbusServiceData.characteristics)) {
+ if (charData.uuid != QBluetoothUuid(gattChar.characteristic->uUID()))
+ continue;
+
+ QDBusPendingReply<> reply = gattChar.characteristic->WriteValue(nextJob.value, QVariantMap());
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ this, &QLowEnergyControllerPrivateBluezDBus::onCharWriteFinished);
+
+ foundChar = true;
+ break;
+ }
+
+ if (!foundChar) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot find char for writing. Skipping.";
+ prepareNextJob();
+ return;
+ }
} else if (nextJob.flags.testFlag(GattJob::DescRead)) {
// descriptor reading ***************************************
QLowEnergyCharacteristic ch = characteristicForHandle(nextJob.handle);
@@ -715,10 +779,32 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
}
void QLowEnergyControllerPrivateBluezDBus::readCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/)
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle)
{
+ Q_ASSERT(!service.isNull());
+ if (!service->characteristicList.contains(charHandle)) {
+ qCWarning(QT_BT_BLUEZ) << "Read characteristic does not belong to service"
+ << service->uuid;
+ return;
+ }
+
+ const QLowEnergyServicePrivate::CharData &charDetails
+ = service->characteristicList[charHandle];
+ if (!(charDetails.properties & QLowEnergyCharacteristic::Read)) {
+ // if this succeeds the device has a bug, char is advertised as
+ // non-readable. We try to be permissive and let the remote
+ // device answer to the read attempt
+ qCWarning(QT_BT_BLUEZ) << "Reading non-readable char" << charHandle;
+ }
+
+ GattJob job;
+ job.flags = GattJob::JobFlags({GattJob::CharRead});
+ job.service = service;
+ job.handle = charHandle;
+ jobs.append(job);
+ scheduleNextJob();
}
void QLowEnergyControllerPrivateBluezDBus::readDescriptor(
@@ -730,12 +816,32 @@ void QLowEnergyControllerPrivateBluezDBus::readDescriptor(
}
void QLowEnergyControllerPrivateBluezDBus::writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QByteArray &/*newValue*/,
- QLowEnergyService::WriteMode /*writeMode*/)
- {
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QByteArray &newValue,
+ QLowEnergyService::WriteMode writeMode)
+{
+ Q_ASSERT(!service.isNull());
+ if (!service->characteristicList.contains(charHandle)) {
+ qCWarning(QT_BT_BLUEZ) << "Write characteristic does not belong to service"
+ << service->uuid;
+ return;
+ }
+ if (role == QLowEnergyController::CentralRole) {
+ GattJob job;
+ job.flags = GattJob::JobFlags({GattJob::CharWrite});
+ job.service = service;
+ job.handle = charHandle;
+ job.value = newValue;
+ job.writeMode = writeMode;
+ jobs.append(job);
+
+ scheduleNextJob();
+ } else {
+ qWarning(QT_BT_BLUEZ) << "writeCharacteristic() not implemented for DBus Bluez GATT";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ }
}
void QLowEnergyControllerPrivateBluezDBus::writeDescriptor(
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
index 84326e48..c4845fc1 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
@@ -130,6 +130,7 @@ private slots:
void onCharReadFinished(QDBusPendingCallWatcher *call);
void onDescReadFinished(QDBusPendingCallWatcher *call);
+ void onCharWriteFinished(QDBusPendingCallWatcher *call);
private:
OrgBluezAdapter1Interface* adapter{};
OrgBluezDevice1Interface* device{};
@@ -169,6 +170,8 @@ private:
JobFlags flags = GattJob::Unset;
QLowEnergyHandle handle;
+ QByteArray value;
+ QLowEnergyService::WriteMode writeMode = QLowEnergyService::WriteWithResponse;
QSharedPointer<QLowEnergyServicePrivate> service;
};