summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/bluetoothtestdevice/bluetoothtestdevice.cpp74
-rw-r--r--tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp83
2 files changed, 157 insertions, 0 deletions
diff --git a/tests/bluetoothtestdevice/bluetoothtestdevice.cpp b/tests/bluetoothtestdevice/bluetoothtestdevice.cpp
index b2cefa4d..62daa942 100644
--- a/tests/bluetoothtestdevice/bluetoothtestdevice.cpp
+++ b/tests/bluetoothtestdevice/bluetoothtestdevice.cpp
@@ -44,6 +44,27 @@ static const QLatin1String connectionCountCharUuid("9414ec2d-792f-46a2-a19e-186d
static const QLatin1String mtuServiceUuid("9a9483eb-cf4f-4c32-9a6b-794238d5b483");
static const QLatin1String mtuCharUuid("960d7e2a-a850-4a70-8064-cd74e9ccb6ff");
+static const QLatin1String repeatedWriteServiceUuid("72b12a31-98ea-406d-a89d-2c932d11ff67");
+static const QLatin1String repeatedWriteTargetCharUuid("2192ee43-6d17-4e78-b286-db2c3b696833");
+static const QLatin1String repeatedWriteNotifyCharUuid("b3f9d1a2-3d55-49c9-8b29-e09cec77ff86");
+
+static void establishNotifyOnWriteConnection(QLowEnergyService *svc)
+{
+ // Make sure that the value from the repeatedWriteTargetCharUuid
+ // characteristic is writted to the repeatedWriteNotifyCharUuid
+ // characteristic
+ Q_ASSERT(svc->serviceUuid() == QBluetoothUuid(repeatedWriteServiceUuid));
+ QObject::connect(svc, &QLowEnergyService::characteristicChanged, svc,
+ [svc](const QLowEnergyCharacteristic &characteristic,
+ const QByteArray &newValue)
+ {
+ if (characteristic.uuid() == QBluetoothUuid(repeatedWriteTargetCharUuid)) {
+ auto notifyChar = svc->characteristic(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ svc->writeCharacteristic(notifyChar, newValue);
+ }
+ });
+}
+
int main(int argc, char *argv[])
{
qDebug() << "build:" << __DATE__ << __TIME__;
@@ -231,6 +252,56 @@ int main(int argc, char *argv[])
serviceDefinitions << serviceData;
}
+ {
+ // repeated characteristic write service
+ //
+ // This service offers an 8 bytes large characteristic which can
+ // be read and written. Once the value is updated, it writes the
+ // same value to the other characteristic, which notifies the client
+ // about its change. This way we can make sure that all write were
+ // successful and happened in the right order.
+ // We can't use one characteristics for writing and notification,
+ // because on most backends when the characteristics was written
+ // by the client, there will be no notification about it.
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(repeatedWriteServiceUuid));
+
+ {
+ // The characteristics to be written by the client.
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(repeatedWriteTargetCharUuid));
+ QByteArray initialValue(8, 0);
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write);
+
+ serviceData.addCharacteristic(charData);
+ }
+ {
+ // The characteristics written by the server,
+ // it will send notifications to the client.
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ QByteArray initialValue(8, 0);
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write
+ | QLowEnergyCharacteristic::PropertyType::Notify);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ serviceData.addCharacteristic(charData);
+ }
+
+ serviceDefinitions << serviceData;
+ }
+
#ifndef Q_OS_IOS
auto localAdapters = QBluetoothLocalDevice::allDevices();
if (localAdapters.isEmpty()) {
@@ -281,6 +352,8 @@ int main(int argc, char *argv[])
services.emplaceBack(leController->addService(serviceData));
}
+ establishNotifyOnWriteConnection(services[5].get());
+
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,
advertisingData);
@@ -291,6 +364,7 @@ int main(int argc, char *argv[])
services[i].reset(leController->addService(serviceDefinitions[i]));
}
+ establishNotifyOnWriteConnection(services[5].get());
{
// set connection counter
diff --git a/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp b/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp
index 80dc1bef..5acf829d 100644
--- a/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp
+++ b/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp
@@ -32,6 +32,11 @@ static const QLatin1String
static const QLatin1String connectionCountServiceUuid("78c61a07-a0f9-4b92-be2d-2570d8dbf010");
static const QLatin1String connectionCountCharUuid("9414ec2d-792f-46a2-a19e-186d0fb38a08");
+static const QLatin1String repeatedWriteServiceUuid("72b12a31-98ea-406d-a89d-2c932d11ff67");
+static const QLatin1String repeatedWriteTargetCharUuid("2192ee43-6d17-4e78-b286-db2c3b696833");
+static const QLatin1String repeatedWriteNotifyCharUuid("b3f9d1a2-3d55-49c9-8b29-e09cec77ff86");
+
+
#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) || defined(Q_OS_DARWIN)
#define QT_BLUETOOTH_MTU_SUPPORTED
@@ -79,6 +84,7 @@ private slots:
void readDuringServiceDiscovery();
void readNotificationAndIndicationProperty();
void testNotificationAndIndication();
+ void testRepeatedCharacteristicsWrite();
public:
void checkconnectionCounter(std::unique_ptr<QLowEnergyController> &control);
@@ -654,6 +660,83 @@ void tst_qlowenergycontroller_device::testNotificationAndIndication()
}
}
+void tst_qlowenergycontroller_device::testRepeatedCharacteristicsWrite()
+{
+ // This test generates multiple consecutive writes to the same characteristic
+ // and waits for the notifications (on other characteristic) with the same
+ // values. After that it verifies that the received values are the same (and
+ // in the same order) as written values. The server writes each received
+ // value to a notifying characteristic, which allows us to perform the check.
+
+ // Discover services
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ // Get service object.
+ QSharedPointer<QLowEnergyService> service(mController->createServiceObject(
+ QBluetoothUuid(repeatedWriteServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ // Enable notification.
+ QLowEnergyCharacteristic notifyChar =
+ service->characteristic(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ const auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ QCOMPARE(notifyChar.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Notify);
+
+ QLowEnergyDescriptor cccd = notifyChar.clientCharacteristicConfiguration();
+ QVERIFY(cccd.isValid());
+
+ QObject dummy; // for lifetime management
+ bool cccdWritten = false;
+ connect(service.get(), &QLowEnergyService::descriptorWritten, &dummy,
+ [&cccdWritten](const QLowEnergyDescriptor &info, const QByteArray &) {
+ if (info.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ cccdWritten = true;
+ }
+ });
+ service->writeDescriptor(cccd, QLowEnergyCharacteristic::CCCDEnableNotification);
+ QTRY_VERIFY(cccdWritten);
+
+ // Track the notifications of value changes.
+ QList<QByteArray> receivedValues;
+ connect(service.get(), &QLowEnergyService::characteristicChanged, &dummy,
+ [&receivedValues](const QLowEnergyCharacteristic &characteristic,
+ const QByteArray &value)
+ {
+ if (characteristic.uuid() == QBluetoothUuid(repeatedWriteNotifyCharUuid)) {
+ receivedValues.push_back(value);
+ }
+ });
+
+ // Write characteristics multiple times. This shouldn't crash, and all
+ // values should be written. We use the notifications to track it.
+ receivedValues.clear();
+ QList<QByteArray> sentValues;
+ QLowEnergyCharacteristic writeChar =
+ service->characteristic(QBluetoothUuid(repeatedWriteTargetCharUuid));
+ static const int totalWrites = 50;
+ QByteArray value(8, 0);
+ for (int i = 0; i < totalWrites; ++i) {
+ value[0] += 1;
+ value[7] += 1;
+ service->writeCharacteristic(writeChar, value);
+ sentValues.push_back(value);
+ }
+
+ // We expect to get notifications about all writes.
+ // We set a large timeout to be on a safe side.
+ QTRY_COMPARE_WITH_TIMEOUT(receivedValues.size(), totalWrites, 60000);
+ QCOMPARE(receivedValues, sentValues);
+}
+
QTEST_MAIN(tst_qlowenergycontroller_device)
#include "tst_qlowenergycontroller_device.moc"