From 3e26211bf0d92fb46a5a5f1830766be2ea832d7b Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Wed, 2 Jul 2014 10:52:17 +0200 Subject: Support writing of characteristic Right now we assume that the target characteristic is writable with confirmation response. WriteNoResponse support is still missing. Change-Id: Ie584db43f80a0bf90ec67499772488f509fc3d29 Reviewed-by: Fabian Bumberger --- .../tst_qlowenergycontroller.cpp | 150 ++++++++++++++++++++- 1 file changed, 146 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp index 2e88d97f..66f458f6 100644 --- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp +++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp @@ -72,6 +72,7 @@ private slots: void tst_connectNew(); void tst_concurrentDiscovery(); void tst_defaultBehavior(); + void tst_writeCharacteristic(); private: void verifyServiceProperties(const QLowEnergyServiceInfo &info); @@ -82,12 +83,17 @@ private: QList foundServices; }; +Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +Q_DECLARE_METATYPE(QLowEnergyService::ServiceError) + tst_QLowEnergyController::tst_QLowEnergyController() { qRegisterMetaType("QLowEnergyServiceInfo"); qRegisterMetaType("QLowEnergyController::Error"); + //qRegisterMetaType(); qRegisterMetaType("QLowEnergyCharacteristicInfo"); + qRegisterMetaType(); QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true")); const QString remote = qgetenv("BT_TEST_DEVICE"); @@ -932,7 +938,7 @@ void tst_QLowEnergyController::tst_concurrentDiscovery() // initialize services for (int i = 0; iparent() == this); QVERIFY(services[i]); + QVERIFY(services_second[i]->state() == QLowEnergyService::DiscoveryRequired); services_second[i]->discoverDetails(); } @@ -986,7 +994,6 @@ void tst_QLowEnergyController::tst_concurrentDiscovery() // verify discovered services (1st and 2nd round) for (int i = 0; i chars = services[i]->characteristics(); @@ -1198,7 +1205,7 @@ void tst_QLowEnergyController::verifyServiceProperties( QCOMPARE(chars[0].handle(), 0x25u); QCOMPARE(chars[0].properties(), (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify)); - //QCOMPARE(chars[0].value(), QByteArray("30303030")); + QCOMPARE(chars[0].value(), QByteArray("00000000")); QVERIFY(chars[0].isValid()); QCOMPARE(chars[0].descriptors().count(), 2); @@ -1762,6 +1769,141 @@ void tst_QLowEnergyController::tst_defaultBehavior() } +void tst_QLowEnergyController::tst_writeCharacteristic() +{ + QList localAdapters = QBluetoothLocalDevice::allDevices(); + if (localAdapters.isEmpty() || remoteDevice.isNull()) + QSKIP("No local Bluetooth or remote BTLE device found. Skipping test."); + + // quick setup - more elaborate test is done by connectNew() + QLowEnergyControllerNew control(remoteDevice); + QCOMPARE(control.state(), QLowEnergyControllerNew::UnconnectedState); + QCOMPARE(control.error(), QLowEnergyControllerNew::NoError); + + control.connectToDevice(); + { + QTRY_IMPL(control.state() != QLowEnergyControllerNew::ConnectingState, + 30000); + } + + if (control.state() == QLowEnergyControllerNew::ConnectingState + || control.error() != QLowEnergyControllerNew::NoError) { + // default BTLE backend forever hangs in ConnectingState + QSKIP("Cannot connect to remote device"); + } + + QCOMPARE(control.state(), QLowEnergyControllerNew::ConnectedState); + QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished())); + control.discoverServices(); + QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 10000); + + const QBluetoothUuid testService(QString("f000aa60-0451-4000-b000-000000000000")); + QList uuids = control.services(); + QVERIFY(uuids.contains(testService)); + + QLowEnergyService *service = control.createServiceObject(testService, this); + QVERIFY(service); + service->discoverDetails(); + QTRY_VERIFY_WITH_TIMEOUT( + service->state() == QLowEnergyService::ServiceDiscovered, 30000); + + //test service described by http://processors.wiki.ti.com/index.php/SensorTag_User_Guide + const QList chars = service->characteristics(); + + QLowEnergyCharacteristic dataChar; + QLowEnergyCharacteristic configChar; + for (int i = 0; i < chars.count(); i++) { + if (chars[i].uuid() == QBluetoothUuid(QString("f000aa61-0451-4000-b000-000000000000"))) + dataChar = chars[i]; + else if (chars[i].uuid() == QBluetoothUuid(QString("f000aa62-0451-4000-b000-000000000000"))) + configChar = chars[i]; + } + + QVERIFY(dataChar.isValid()); + QVERIFY(!(dataChar.properties() & ~QLowEnergyCharacteristic::Read)); // only a read char + QVERIFY(configChar.isValid()); + QVERIFY(configChar.properties() & QLowEnergyCharacteristic::Write); + + QCOMPARE(dataChar.value(), QByteArray("3f00")); + QVERIFY(configChar.value() == QByteArray("00") || configChar.value() == QByteArray("81")); + + QSignalSpy writeSpy(service, + SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray))); + + // ******************************************* + // test writing of characteristic + // enable Blinking LED if not already enabled + if (configChar.value() != QByteArray("81")) { + service->writeCharacteristic(configChar, QByteArray("81")); //0x81 blink LED D1 + QTRY_VERIFY_WITH_TIMEOUT(!writeSpy.isEmpty(), 10000); + QCOMPARE(configChar.value(), QByteArray("81")); + QList firstSignalData= writeSpy.first(); + QLowEnergyCharacteristic signalChar = firstSignalData[0].value(); + QByteArray signalValue = firstSignalData[1].toByteArray(); + + QCOMPARE(signalValue, QByteArray("81")); + QVERIFY(signalChar == configChar); + + writeSpy.clear(); + } + + service->writeCharacteristic(configChar, QByteArray("00")); //0x81 blink LED D1 + QTRY_VERIFY_WITH_TIMEOUT(!writeSpy.isEmpty(), 10000); + QCOMPARE(configChar.value(), QByteArray("00")); + QList firstSignalData = writeSpy.first(); + QLowEnergyCharacteristic signalChar = firstSignalData[0].value(); + QByteArray signalValue = firstSignalData[1].toByteArray(); + + QCOMPARE(signalValue, QByteArray("00")); + QVERIFY(signalChar == configChar); + + // ******************************************* + // write wrong value -> error response required + QSignalSpy errorSpy(service, SIGNAL(error(QLowEnergyService::ServiceError))); + writeSpy.clear(); + QCOMPARE(errorSpy.count(), 0); + QCOMPARE(writeSpy.count(), 0); + + // write 2 byte value to 1 byte characteristic + service->writeCharacteristic(configChar, QByteArray("1111")); + QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000); + QCOMPARE(errorSpy[0].at(0).value(), + QLowEnergyService::CharacteristicWriteError); + QCOMPARE(service->error(), QLowEnergyService::CharacteristicWriteError); + QCOMPARE(writeSpy.count(), 0); + QCOMPARE(configChar.value(), QByteArray("00")); + + // ******************************************* + // write to read-only characteristic -> error + errorSpy.clear(); + QCOMPARE(errorSpy.count(), 0); + service->writeCharacteristic(dataChar, QByteArray("ffff")); + + QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000); + QCOMPARE(errorSpy[0].at(0).value(), + QLowEnergyService::OperationError); + QCOMPARE(service->error(), QLowEnergyService::OperationError); + QCOMPARE(writeSpy.count(), 0); + QCOMPARE(dataChar.value(), QByteArray("3f00")); + + + control.disconnectFromDevice(); + + // ******************************************* + // write value while disconnected -> error + errorSpy.clear(); + QCOMPARE(errorSpy.count(), 0); + service->writeCharacteristic(configChar, QByteArray("ffff")); + QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 2000); + QCOMPARE(errorSpy[0].at(0).value(), + QLowEnergyService::OperationError); + QCOMPARE(service->error(), QLowEnergyService::OperationError); + QCOMPARE(writeSpy.count(), 0); + QCOMPARE(configChar.value(), QByteArray("00")); + + delete service; +} + QTEST_MAIN(tst_QLowEnergyController) #include "tst_qlowenergycontroller.moc" -- cgit v1.2.3