diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-01-17 15:14:00 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-01-18 10:22:49 +0000 |
commit | a1d54b78d33c9216d8915209403088526e9acfe6 (patch) | |
tree | 6c4db1cb619bf62d41fc214400b39470deae8ecd /tests | |
parent | 1abcd7501220d4f3e248426a1ac1ce2920f7ef9c (diff) | |
download | qtconnectivity-a1d54b78d33c9216d8915209403088526e9acfe6.tar.gz |
Android LE Peripheral: properly update characteristic and descriptor local values
Android backend did not update the serivice's characteristic and
descriptor values after executing writeCharacteristic/writeDescriptor.
As a result, the connected central saw the correct updated value, while
local request still returned the old value.
This patch fixes it by properly updating the local values when the write
operations complete successfully.
Change-Id: Ie09299b6c72bbf92ab6c824c3ca23f0136f0457e
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit e5d1b776b1445eb6fde6ce33b54fd98e9fb49994)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests')
3 files changed, 203 insertions, 0 deletions
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt index e53c7e10..2cce14f6 100644 --- a/tests/manual/CMakeLists.txt +++ b/tests/manual/CMakeLists.txt @@ -3,5 +3,6 @@ if(TARGET Qt::Bluetooth) add_subdirectory(qlowenergycontroller) + add_subdirectory(qlowenergycontroller_peripheral) endif() diff --git a/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt b/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt new file mode 100644 index 00000000..abd84bb8 --- /dev/null +++ b/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16...3.21) + +if(NOT TARGET Qt::Bluetooth) + # for standalone build (and the only way for iOS) + project(tst_qlowenergycontroller_peripheral LANGUAGES CXX) + + set(CMAKE_AUTOMOC ON) + + find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Test Gui) + + qt_add_executable(tst_qlowenergycontroller_peripheral + tst_qlowenergycontroller_peripheral.cpp + ) + target_link_libraries(tst_qlowenergycontroller_peripheral + PUBLIC + Qt::Core + Qt::Bluetooth + Qt::Test + Qt::Gui + ) + +else() + + qt_internal_add_test(tst_qlowenergycontroller_peripheral + SOURCES + tst_qlowenergycontroller_peripheral.cpp + LIBRARIES + Qt::Bluetooth + ) + + qt_internal_extend_target(tst_qlowenergycontroller_peripheral + CONDITION ANDROID AND NOT ANDROID_EMBEDDED + DEFINES + QT_ANDROID_BLUETOOTH + ) + +endif() + +set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +if(APPLE) + # Ninja has trouble with relative paths, convert to absolute as a workaround + get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE) + if(IOS) + set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.ios.plist" + ) + else() + set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist" + ) + endif() +endif() diff --git a/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp b/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp new file mode 100644 index 00000000..0d7efa07 --- /dev/null +++ b/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QTest> + +#include <QBluetoothLocalDevice> +#include <QLowEnergyController> +#include <QLowEnergyServiceData> +#include <QLowEnergyCharacteristicData> +#include <QLowEnergyDescriptorData> + +using namespace Qt::Literals::StringLiterals; + +static constexpr auto leServiceUuid{"10f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1}; +static constexpr auto leCharUuid1{"11f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1}; +static const qsizetype leCharacteristicSize = 4; // Set to 1...512 bytes +static QByteArray leCharacteristicValue = QByteArray{leCharacteristicSize, 1}; +static QByteArray leDescriptorValue = "a descriptor value"_ba; + +class tst_qlowenergycontroller_peripheral : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void init(); + void cleanup(); + + void localCharacteristicReadAfterUpdate(); + void localDescriptorReadAfterUpdate(); + +private: + QBluetoothHostInfo mDevice; + std::unique_ptr<QLowEnergyController> mController; + QList<QSharedPointer<QLowEnergyService>> mServices; +}; + +void tst_qlowenergycontroller_peripheral::initTestCase() +{ +#ifndef Q_OS_IOS + auto devices = QBluetoothLocalDevice::allDevices(); + if (devices.isEmpty()) + QSKIP("Failed to find local adapter"); + else + mDevice = devices.back(); +#endif // Q_OS_IOS +} + +void tst_qlowenergycontroller_peripheral::init() +{ + QList<QLowEnergyServiceData> serviceDefinitions; + + QLowEnergyServiceData sd; + sd.setType(QLowEnergyServiceData::ServiceTypePrimary); + sd.setUuid(QBluetoothUuid(leServiceUuid)); + + QLowEnergyCharacteristicData charData; + charData.setUuid(QBluetoothUuid(leCharUuid1)); + charData.setValue(leCharacteristicValue); + charData.setValueLength(leCharacteristicSize, leCharacteristicSize); + charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read + | QLowEnergyCharacteristic::PropertyType::Write + | QLowEnergyCharacteristic::PropertyType::Notify + | QLowEnergyCharacteristic::ExtendedProperty); + + const QLowEnergyDescriptorData clientConfig( + QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration, + QLowEnergyCharacteristic::CCCDDisable); + charData.addDescriptor(clientConfig); + + const QLowEnergyDescriptorData userDescription( + QBluetoothUuid::DescriptorType::CharacteristicUserDescription, + leDescriptorValue); + charData.addDescriptor(userDescription); + + const QLowEnergyDescriptorData extendedProperties( + QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties, + // From bluetooth specs: length 2 bytes + // bit 0: reliable write, bit 1: writable auxiliaries + QByteArray::fromHex("0300")); + charData.addDescriptor(extendedProperties); + + sd.addCharacteristic(charData); + + serviceDefinitions << sd; + + +#ifndef Q_OS_IOS + mController.reset(QLowEnergyController::createPeripheral(mDevice.address())); +#else + mController.reset(QLowEnergyController::createPeripheral()); +#endif // Q_OS_IOS + QVERIFY(mController); + + for (const auto &serviceData : serviceDefinitions) { + mServices.emplaceBack(mController->addService(serviceData)); + } +} + +void tst_qlowenergycontroller_peripheral::cleanup() +{ + if (mController) + mController->stopAdvertising(); + + mController.reset(); + mServices.clear(); +} + +void tst_qlowenergycontroller_peripheral::localCharacteristicReadAfterUpdate() +{ +#ifdef Q_OS_WINDOWS + QSKIP("Windows does not support peripheral"); +#endif + auto characteristic = mServices[0]->characteristic(QBluetoothUuid(leCharUuid1)); + QVERIFY(characteristic.isValid()); + const auto initialValue = characteristic.value(); + auto newValue = initialValue; + newValue[0] = newValue[0] + 1; + mServices[0]->writeCharacteristic(characteristic, newValue); + QTRY_COMPARE(characteristic.value(), newValue); +} + +void tst_qlowenergycontroller_peripheral::localDescriptorReadAfterUpdate() +{ +#ifdef Q_OS_WINDOWS + QSKIP("Windows does not support peripheral"); +#elif defined Q_OS_DARWIN + QSKIP("Apple devices do not support descriptor value update"); +#endif + auto characteristic = mServices[0]->characteristic(QBluetoothUuid(leCharUuid1)); + QVERIFY(characteristic.isValid()); + auto descriptor = characteristic.descriptor( + QBluetoothUuid::DescriptorType::CharacteristicUserDescription); + QVERIFY(descriptor.isValid()); + const auto initialValue = descriptor.value(); + auto newValue = initialValue; + newValue[0] = newValue[0] + 1; + mServices[0]->writeDescriptor(descriptor, newValue); + QCOMPARE(descriptor.value(), newValue); +} + +QTEST_MAIN(tst_qlowenergycontroller_peripheral) + +#include "tst_qlowenergycontroller_peripheral.moc" |