summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@theqtcompany.com>2015-10-15 12:28:59 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-11-30 06:56:33 +0000
commitcd7165c29cab5543acd30c1a1f1279495700b2bb (patch)
tree7173acc2da6bba34641d1a2a9d85fe0f18e9c115 /tests
parentf7784d73d7fa78773f97e9b5488eda4ca69dbbbd (diff)
Bluetooth: Partial implementation of GATT server functionality.
Available so far are all "read" and "find" requests (BlueZ only). Things left to do: - Access checks regarding authentication, authorization and encryption requirements. - Handling write requests. - Notifications and Indications. Change-Id: Idfcb863b1b375cd0414580b5ce1cba67c23a6bf8 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp107
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp107
2 files changed, 205 insertions, 9 deletions
diff --git a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
index c3d5b5e0..ddba0ddb 100644
--- a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
+++ b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
@@ -34,23 +34,118 @@
#include <QtBluetooth/qlowenergyadvertisingdata.h>
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
#include <QtBluetooth/qlowenergycontroller.h>
+#include <QtBluetooth/qlowenergycharacteristicdata.h>
+#include <QtBluetooth/qlowenergydescriptordata.h>
+#include <QtBluetooth/qlowenergyservicedata.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qhash.h>
#include <QtCore/qscopedpointer.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qvector.h>
-int main(int argc, char *argv[])
+static QByteArray deviceName() { return "Qt GATT server"; }
+
+static QScopedPointer<QLowEnergyController> leController;
+typedef QSharedPointer<QLowEnergyService> ServicePtr;
+static QHash<QBluetoothUuid, ServicePtr> services;
+
+void addService(const QLowEnergyServiceData &serviceData)
{
- QCoreApplication app(argc, argv);
+ const ServicePtr service(leController->addService(serviceData));
+ Q_ASSERT(service);
+ services.insert(service->serviceUuid(), service);
+}
+
+void addRunningSpeedService()
+{
+ QLowEnergyServiceData serviceData;
+ serviceData.setUuid(QBluetoothUuid::RunningSpeedAndCadence);
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+
+ QLowEnergyDescriptorData desc;
+ desc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
+ desc.setValue(QByteArray(1, 0)); // Default: No indication, no notification.
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid::RSCMeasurement);
+ charData.addDescriptor(desc);
+ charData.setProperties(QLowEnergyCharacteristic::Notify);
+ QByteArray value(4, 0);
+ value[0] = 1 << 2; // "Running", no optional fields.
+ charData.setValue(value);
+ serviceData.addCharacteristic(charData);
+ charData = QLowEnergyCharacteristicData();
+ charData.setUuid(QBluetoothUuid::RSCFeature);
+ charData.setProperties(QLowEnergyCharacteristic::Read);
+ value = QByteArray(2, 0);
+ value[0] = 1 << 2; // "Walking or Running" supported.
+ charData.setValue(value);
+ serviceData.addCharacteristic(charData);
+ addService(serviceData);
+}
+
+void addGenericAccessService()
+{
+ QLowEnergyServiceData serviceData;
+ serviceData.setUuid(QBluetoothUuid::GenericAccess);
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid::DeviceName);
+ charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
+ charData.setValue(deviceName());
+ serviceData.addCharacteristic(charData);
+
+ charData = QLowEnergyCharacteristicData();
+ charData.setUuid(QBluetoothUuid::Appearance);
+ charData.setProperties(QLowEnergyCharacteristic::Read);
+ QByteArray value(2, 0);
+ value[0] = -1; // 128 => Generic computer.
+ charData.setValue(value);
+ serviceData.addCharacteristic(charData);
+
+ serviceData.addIncludedService(services.value(QBluetoothUuid::RunningSpeedAndCadence).data());
+ addService(serviceData);
+}
+
+void addCustomService()
+{
+ QLowEnergyServiceData serviceData;
+ serviceData.setUuid(QBluetoothUuid(quint16(0x2000))); // Made up.
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(quint16(0x5000))); // Made up.
+ charData.setProperties(QLowEnergyCharacteristic::Read);
+ charData.setValue(QByteArray(1024, 'x')); // Long value to test "Read Blob".
+ serviceData.addCharacteristic(charData);
+
+ addService(serviceData);
+}
+
+void startAdvertising()
+{
QLowEnergyAdvertisingParameters params;
params.setMode(QLowEnergyAdvertisingParameters::AdvInd);
QLowEnergyAdvertisingData data;
data.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityLimited);
- data.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::AlertNotificationService);
+ data.setServices(services.keys());
data.setIncludePowerLevel(true);
- data.setLocalName("Qt GATT server");
- const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
+ data.setLocalName(deviceName());
leController->startAdvertising(params, data);
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ leController.reset(QLowEnergyController::createPeripheral());
+ addRunningSpeedService();
+ addGenericAccessService();
+ addCustomService();
+ startAdvertising();
+
+ // TODO: Change characteristics, client checks that it gets indication/notification
+ // TODO: Where to test that we get the characteristicChanged signal for characteristics that the client writes?
return app.exec();
}
-
diff --git a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
index 4fa62d43..12d0db17 100644
--- a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
+++ b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
@@ -52,15 +52,21 @@ class TestQLowEnergyControllerGattServer : public QObject
private slots:
void initTestCase();
+
+ // Static, local stuff goes here.
void advertisingParameters();
void advertisingData();
- void advertisedData();
void controllerType();
void serviceData();
+ // Interaction with actual GATT server goes here. Order is relevant.
+ void advertisedData();
+ void initialServices();
+
private:
QBluetoothAddress m_serverAddress;
QBluetoothDeviceInfo m_serverInfo;
+ QScopedPointer<QLowEnergyController> m_leController;
};
@@ -157,8 +163,103 @@ void TestQLowEnergyControllerGattServer::advertisedData()
// name is seen on the scanning machine.
// QCOMPARE(m_serverInfo.name(), QString("Qt GATT server"));
- QCOMPARE(m_serverInfo.serviceUuids(),
- QList<QBluetoothUuid>() << QBluetoothUuid::AlertNotificationService);
+ QCOMPARE(m_serverInfo.serviceUuids().count(), 3);
+ QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::GenericAccess));
+ QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::RunningSpeedAndCadence));
+ QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid(quint16(0x2000))));
+}
+
+void TestQLowEnergyControllerGattServer::initialServices()
+{
+ if (m_serverAddress.isNull())
+ QSKIP("No server address provided");
+ m_leController.reset(QLowEnergyController::createCentral(m_serverInfo));
+ QVERIFY(!m_leController.isNull());
+ m_leController->connectToDevice();
+ QScopedPointer<QSignalSpy> spy(new QSignalSpy(m_leController.data(),
+ &QLowEnergyController::connected));
+ QVERIFY(spy->wait(30000));
+ m_leController->discoverServices();
+ spy.reset(new QSignalSpy(m_leController.data(), &QLowEnergyController::discoveryFinished));
+ QVERIFY(spy->wait(30000));
+ const QList<QBluetoothUuid> serviceUuids = m_leController->services();
+ QCOMPARE(serviceUuids.count(), 3);
+ QVERIFY(serviceUuids.contains(QBluetoothUuid::GenericAccess));
+ QVERIFY(serviceUuids.contains(QBluetoothUuid::RunningSpeedAndCadence));
+ QVERIFY(serviceUuids.contains(QBluetoothUuid(quint16(0x2000))));
+
+ const QScopedPointer<QLowEnergyService> genericAccessService(
+ m_leController->createServiceObject(QBluetoothUuid::GenericAccess));
+ QVERIFY(!genericAccessService.isNull());
+ genericAccessService->discoverDetails();
+ while (genericAccessService->state() != QLowEnergyService::ServiceDiscovered) {
+ spy.reset(new QSignalSpy(genericAccessService.data(), &QLowEnergyService::stateChanged));
+ QVERIFY(spy->wait(3000));
+ }
+ QCOMPARE(genericAccessService->includedServices().count(), 1);
+ QCOMPARE(genericAccessService->includedServices().first(),
+ QBluetoothUuid(QBluetoothUuid::RunningSpeedAndCadence));
+ QCOMPARE(genericAccessService->characteristics().count(), 2);
+ const QLowEnergyCharacteristic deviceNameChar
+ = genericAccessService->characteristic(QBluetoothUuid::DeviceName);
+ QVERIFY(deviceNameChar.isValid());
+ QCOMPARE(deviceNameChar.descriptors().count(), 0);
+ QCOMPARE(deviceNameChar.properties(),
+ QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
+ QCOMPARE(deviceNameChar.value().constData(), "Qt GATT server");
+ const QLowEnergyCharacteristic appearanceChar
+ = genericAccessService->characteristic(QBluetoothUuid::Appearance);
+ QVERIFY(appearanceChar.isValid());
+ QCOMPARE(appearanceChar.descriptors().count(), 0);
+ QCOMPARE(appearanceChar.properties(), QLowEnergyCharacteristic::Read);
+ QByteArray appearanceValue(2, 0);
+ appearanceValue[0] = -1;
+ QCOMPARE(appearanceChar.value(), appearanceValue);
+
+ const QScopedPointer<QLowEnergyService> runningSpeedService(
+ m_leController->createServiceObject(QBluetoothUuid::RunningSpeedAndCadence));
+ QVERIFY(!runningSpeedService.isNull());
+ runningSpeedService->discoverDetails();
+ while (runningSpeedService->state() != QLowEnergyService::ServiceDiscovered) {
+ spy.reset(new QSignalSpy(runningSpeedService.data(), &QLowEnergyService::stateChanged));
+ QVERIFY(spy->wait(3000));
+ }
+ QCOMPARE(runningSpeedService->includedServices().count(), 0);
+ QCOMPARE(runningSpeedService->characteristics().count(), 2);
+ QLowEnergyCharacteristic measurementChar
+ = runningSpeedService->characteristic(QBluetoothUuid::RSCMeasurement);
+ QVERIFY(measurementChar.isValid());
+ QCOMPARE(measurementChar.descriptors().count(), 1);
+ const QLowEnergyDescriptor clientConfigDesc
+ = measurementChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ QVERIFY(clientConfigDesc.isValid());
+ QCOMPARE(clientConfigDesc.value(), QByteArray(1, 0));
+ QCOMPARE(measurementChar.properties(), QLowEnergyCharacteristic::Notify);
+ QCOMPARE(measurementChar.value(), QByteArray()); // Empty because Read property not set
+ QLowEnergyCharacteristic featureChar
+ = runningSpeedService->characteristic(QBluetoothUuid::RSCFeature);
+ QVERIFY(featureChar.isValid());
+ QCOMPARE(featureChar.descriptors().count(), 0);
+ QCOMPARE(featureChar.properties(), QLowEnergyCharacteristic::Read);
+ QByteArray featureValue = QByteArray(2, 0);
+ featureValue[0] = 1 << 2;
+ QCOMPARE(featureChar.value(), featureValue);
+
+ const QScopedPointer<QLowEnergyService> customService(
+ m_leController->createServiceObject(QBluetoothUuid(quint16(0x2000))));
+ QVERIFY(!customService.isNull());
+ customService->discoverDetails();
+ while (customService->state() != QLowEnergyService::ServiceDiscovered) {
+ spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::stateChanged));
+ QVERIFY(spy->wait(3000));
+ }
+ QCOMPARE(customService->includedServices().count(), 0);
+ QCOMPARE(customService->characteristics().count(), 1);
+ QLowEnergyCharacteristic customChar
+ = customService->characteristic(QBluetoothUuid(quint16(0x5000)));
+ QVERIFY(customChar.isValid());
+ QCOMPARE(customChar.descriptors().count(), 0);
+ QCOMPARE(customChar.value(), QByteArray(1024, 'x'));
}
void TestQLowEnergyControllerGattServer::controllerType()