summaryrefslogtreecommitdiffstats
path: root/tests/bttestui/btlocaldevice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/bttestui/btlocaldevice.cpp')
-rw-r--r--tests/bttestui/btlocaldevice.cpp1008
1 files changed, 875 insertions, 133 deletions
diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp
index 55b99fc3..19e78bb3 100644
--- a/tests/bttestui/btlocaldevice.cpp
+++ b/tests/bttestui/btlocaldevice.cpp
@@ -1,38 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "btlocaldevice.h"
+#include <QCoreApplication>
#include <QDebug>
#include <QTimer>
-#ifdef Q_OS_ANDROID
-#include <QtAndroidExtras/QtAndroid>
-#endif
#include <QtBluetooth/QBluetoothServiceInfo>
+#include <QtBluetooth/QLowEnergyCharacteristicData>
+#include <QtBluetooth/QLowEnergyDescriptorData>
+#include <QtBluetooth/QLowEnergyAdvertisingParameters>
#define BTCHAT_DEVICE_ADDR "00:15:83:38:17:C3"
@@ -45,12 +21,80 @@
#define SOCKET_PROTOCOL QBluetoothServiceInfo::RfcommProtocol
//#define SOCKET_PROTOCOL QBluetoothServiceInfo::L2capProtocol
-BtLocalDevice::BtLocalDevice(QObject *parent) :
- QObject(parent), securityFlags(QBluetooth::NoSecurity)
+using namespace Qt::Literals::StringLiterals;
+// Main service used for testing read/write/notify
+static constexpr auto leServiceUuid{"10f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leCharUuid1{"11f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+static constexpr auto leCharUuid2{"12f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+// Service for testing the included services
+static constexpr auto leSecondServiceUuid{"20f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leSecondServiceCharUuid1{"21f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+// Service for testing the secondary service and other miscellaneous
+static constexpr auto leThirdServiceUuid{"30f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leThirdServiceCharUuid1{"31f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+
+// Used for finding a matching LE peripheral device. Typically the default BtTestUi is ok
+// when running against macOS/iOS/Linux peripheral, but with Android this needs to be adjusted
+// to device's name. We can't use bluetooth address for matching as the public address of the
+// peripheral may change
+static const auto leRemotePeriphreralDeviceName = "BtTestUi"_L1;
+static const qsizetype leCharacteristicSize = 4; // Set to 1...512 bytes
+static QByteArray leCharacteristicValue = QByteArray{leCharacteristicSize, 1};
+static QByteArray leDescriptorValue = "a descriptor value"_ba;
+static auto leSecondCharacteristicValue = QByteArray{leCharacteristicSize, 2};
+static quint8 leCharacteristicValueUpdate = 1;
+static char leDescriptorValueUpdate = 'b';
+
+// String tables to shorten the enum strings to fit the screen estate.
+// The values in the tables must be in same order as the corresponding enums
+static constexpr const char* controllerStateString[] = {
+ "Unconnected",
+ "Connecting",
+ "Connected",
+ "Discovering",
+ "Discovered",
+ "Closing",
+ "Advertising",
+};
+
+static constexpr const char* controllerErrorString[] = {
+ "None",
+ "UnknownError",
+ "UnknownRemDev",
+ "NetworkError",
+ "InvAdapter",
+ "ConnectionErr",
+ "AdvertisingErr",
+ "RemHostClosed",
+ "AuthError",
+ "MissingPerm",
+ "RssiError"
+};
+
+static constexpr const char* serviceStateString[] = {
+ "InvalidService",
+ "RemoteService",
+ "RemDiscovering",
+ "RemDiscovered",
+ "LocalService",
+};
+
+static constexpr const char* serviceErrorString[] = {
+ "None",
+ "Operation",
+ "CharWrite",
+ "DescWrite",
+ "Unknown",
+ "CharRead",
+ "DescRead",
+};
+
+BtLocalDevice::BtLocalDevice(QObject *parent)
+ : QObject(parent), securityFlags(QBluetooth::Security::NoSecurity)
{
localDevice = new QBluetoothLocalDevice(this);
- connect(localDevice, &QBluetoothLocalDevice::error,
- this, &BtLocalDevice::error);
+ connect(localDevice, &QBluetoothLocalDevice::errorOccurred, this,
+ &BtLocalDevice::errorOccurred);
connect(localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
this, &BtLocalDevice::hostModeStateChanged);
connect(localDevice, &QBluetoothLocalDevice::pairingFinished,
@@ -59,19 +103,17 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
this, &BtLocalDevice::connected);
connect(localDevice, &QBluetoothLocalDevice::deviceDisconnected,
this, &BtLocalDevice::disconnected);
- connect(localDevice, &QBluetoothLocalDevice::pairingDisplayConfirmation,
- this, &BtLocalDevice::pairingDisplayConfirmation);
- connect(localDevice, &QBluetoothLocalDevice::pairingDisplayPinCode,
- this, &BtLocalDevice::pairingDisplayPinCode);
if (localDevice->isValid()) {
deviceAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &BtLocalDevice::deviceDiscovered);
+ connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::deviceUpdated,
+ this, &BtLocalDevice::deviceUpdated);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::finished,
this, &BtLocalDevice::discoveryFinished);
- connect(deviceAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
- this, &BtLocalDevice::discoveryError);
+ connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred, this,
+ &BtLocalDevice::discoveryError);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
this, &BtLocalDevice::discoveryCanceled);
@@ -82,14 +124,13 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
this, &BtLocalDevice::serviceDiscoveryFinished);
connect(serviceAgent, &QBluetoothServiceDiscoveryAgent::canceled,
this, &BtLocalDevice::serviceDiscoveryCanceled);
- connect(serviceAgent, QOverload<QBluetoothServiceDiscoveryAgent::Error>::of(&QBluetoothServiceDiscoveryAgent::error),
- this, &BtLocalDevice::serviceDiscoveryError);
+ connect(serviceAgent, &QBluetoothServiceDiscoveryAgent::errorOccurred, this,
+ &BtLocalDevice::serviceDiscoveryError);
socket = new QBluetoothSocket(SOCKET_PROTOCOL, this);
connect(socket, &QBluetoothSocket::stateChanged,
this, &BtLocalDevice::socketStateChanged);
- connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &BtLocalDevice::socketError);
+ connect(socket, &QBluetoothSocket::errorOccurred, this, &BtLocalDevice::socketError);
connect(socket, &QBluetoothSocket::connected, this, &BtLocalDevice::socketConnected);
connect(socket, &QBluetoothSocket::disconnected, this, &BtLocalDevice::socketDisconnected);
connect(socket, &QIODevice::readyRead, this, &BtLocalDevice::readData);
@@ -100,13 +141,7 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
server = new QBluetoothServer(SOCKET_PROTOCOL, this);
connect(server, &QBluetoothServer::newConnection, this, &BtLocalDevice::serverNewConnection);
- connect(server, QOverload<QBluetoothServer::Error>::of(&QBluetoothServer::error),
- this, &BtLocalDevice::serverError);
- } else {
- deviceAgent = nullptr;
- serviceAgent = nullptr;
- socket = nullptr;
- server = nullptr;
+ connect(server, &QBluetoothServer::errorOccurred, this, &BtLocalDevice::serverError);
}
}
@@ -120,9 +155,9 @@ BtLocalDevice::~BtLocalDevice()
}
}
-int BtLocalDevice::secFlags() const
+QBluetooth::SecurityFlags BtLocalDevice::secFlags() const
{
- return static_cast<int>(securityFlags);
+ return securityFlags;
}
void BtLocalDevice::setSecFlags(int newFlags)
@@ -137,15 +172,17 @@ void BtLocalDevice::setSecFlags(int newFlags)
QString BtLocalDevice::hostMode() const
{
- switch (localDevice->hostMode()) {
- case QBluetoothLocalDevice::HostDiscoverable:
- return QStringLiteral("HostMode: Discoverable");
- case QBluetoothLocalDevice::HostConnectable:
- return QStringLiteral("HostMode: Connectable");
- case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
- return QStringLiteral("HostMode: DiscoverableLimit");
- case QBluetoothLocalDevice::HostPoweredOff:
- return QStringLiteral("HostMode: Powered Off");
+ if (localDevice) {
+ switch (localDevice->hostMode()) {
+ case QBluetoothLocalDevice::HostDiscoverable:
+ return QStringLiteral("HostMode: Discoverable");
+ case QBluetoothLocalDevice::HostConnectable:
+ return QStringLiteral("HostMode: Connectable");
+ case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
+ return QStringLiteral("HostMode: DiscoverableLimit");
+ case QBluetoothLocalDevice::HostPoweredOff:
+ return QStringLiteral("HostMode: Powered Off");
+ }
}
return QStringLiteral("HostMode: <None>");
@@ -153,17 +190,16 @@ QString BtLocalDevice::hostMode() const
void BtLocalDevice::setHostMode(int newMode)
{
- localDevice->setHostMode(static_cast<QBluetoothLocalDevice::HostMode>(newMode));
+ if (localDevice)
+ localDevice->setHostMode(static_cast<QBluetoothLocalDevice::HostMode>(newMode));
}
void BtLocalDevice::requestPairingUpdate(bool isPairing)
{
QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
- if (baddr.isNull())
+ if (!localDevice || baddr.isNull())
return;
-
-
if (isPairing) {
//toggle between authorized and non-authorized pairing to achieve better
//level of testing
@@ -177,7 +213,7 @@ void BtLocalDevice::requestPairingUpdate(bool isPairing)
localDevice->requestPairing(baddr, QBluetoothLocalDevice::Unpaired);
}
- for (int i = 0; i < foundTestServers.count(); i++) {
+ for (qsizetype i = 0; i < foundTestServers.size(); ++i) {
if (isPairing)
localDevice->requestPairing(foundTestServers.at(i).device().address(),
QBluetoothLocalDevice::Paired);
@@ -202,37 +238,18 @@ void BtLocalDevice::disconnected(const QBluetoothAddress &addr)
qDebug() << "Newly disconnected device" << addr.toString();
}
-void BtLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin)
-{
- qDebug() << "PairingDisplayConfirmation" << address << pin;
- QTimer::singleShot(3000, this, SLOT(confirmPairing()));
-}
-
-void BtLocalDevice::pairingDisplayPinCode(const QBluetoothAddress &address, const QString &pin)
-{
- qDebug() << "PairingDisplayPinCode" << address << pin;
-}
-
-void BtLocalDevice::confirmPairing()
-{
- static bool confirm = false;
- confirm = !confirm; //toggle
- qDebug() << "######" << "Sending pairing confirmation: " << confirm;
- localDevice->pairingConfirmation(confirm);
-}
-
void BtLocalDevice::cycleSecurityFlags()
{
- if (securityFlags.testFlag(QBluetooth::Secure))
- setSecFlags(QBluetooth::NoSecurity);
- else if (securityFlags.testFlag(QBluetooth::Encryption))
- setSecFlags(secFlags() | QBluetooth::Secure);
- else if (securityFlags.testFlag(QBluetooth::Authentication))
- setSecFlags(secFlags() | QBluetooth::Encryption);
- else if (securityFlags.testFlag(QBluetooth::Authorization))
- setSecFlags(secFlags() | QBluetooth::Authentication);
+ if (securityFlags.testFlag(QBluetooth::Security::Secure))
+ setSecFlags(QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity));
+ else if (securityFlags.testFlag(QBluetooth::Security::Encryption))
+ setSecFlags(secFlags() | QBluetooth::Security::Secure);
+ else if (securityFlags.testFlag(QBluetooth::Security::Authentication))
+ setSecFlags(secFlags() | QBluetooth::Security::Encryption);
+ else if (securityFlags.testFlag(QBluetooth::Security::Authorization))
+ setSecFlags(secFlags() | QBluetooth::Security::Authentication);
else
- setSecFlags(secFlags() | QBluetooth::Authorization);
+ setSecFlags(secFlags() | QBluetooth::Security::Authorization);
}
void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
@@ -255,12 +272,29 @@ void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
if (info.serviceClasses() & QBluetoothDeviceInfo::InformationService)
services += "Information|";
- services.truncate(services.length()-1); //cut last '/'
+ services.truncate(services.size()-1); //cut last '/'
qDebug() << "Found new device: " << info.name() << info.isValid() << info.address().toString()
<< info.rssi() << info.majorDeviceClass()
<< info.minorDeviceClass() << services;
+ // With LE we match the device by its name as the public bluetooth address can change
+ if (info.name() == leRemotePeriphreralDeviceName) {
+ qDebug() << "#### Matching LE peripheral device found";
+ leRemotePeripheralDevice = info;
+ latestRSSI = QByteArray::number(info.rssi());
+ emit leChanged();
+ }
+}
+void BtLocalDevice::deviceUpdated(const QBluetoothDeviceInfo &info,
+ QBluetoothDeviceInfo::Fields updateFields)
+{
+ if (info.name() == leRemotePeriphreralDeviceName
+ && updateFields & QBluetoothDeviceInfo::Field::RSSI) {
+ qDebug() << "#### LE peripheral RSSI updated during scan";
+ latestRSSI = QByteArray::number(info.rssi());
+ emit leChanged();
+ }
}
void BtLocalDevice::discoveryFinished()
@@ -347,8 +381,8 @@ void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
bool matchingService =
(info.serviceUuid() == QBluetoothUuid(QString(TEST_SERVICE_UUID)));
#ifdef Q_OS_ANDROID
- if (QtAndroid::androidSdkVersion() >= 23) //bug introduced by Android 6.0.1
- matchingService = matchingService
+ // QTBUG-61392
+ matchingService = matchingService
|| (info.serviceUuid() == QBluetoothUuid(QString(TEST_REVERSE_SERVICE_UUID)));
#endif
@@ -357,7 +391,7 @@ void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
{
//This is here to detect the test server for SPP testing later on
bool alreadyKnown = false;
- for (const QBluetoothServiceInfo& found : qAsConst(foundTestServers)) {
+ for (const QBluetoothServiceInfo& found : std::as_const(foundTestServers)) {
if (found.device().address() == info.device().address()) {
alreadyKnown = true;
break;
@@ -395,7 +429,7 @@ void BtLocalDevice::dumpServiceDiscovery()
qDebug() << "Device Discovery active:" << deviceAgent->isActive();
qDebug() << "Error:" << deviceAgent->error() << deviceAgent->errorString();
const QList<QBluetoothDeviceInfo> list = deviceAgent->discoveredDevices();
- qDebug() << "Discovered Devices:" << list.count();
+ qDebug() << "Discovered Devices:" << list.size();
for (const QBluetoothDeviceInfo &info : list)
qDebug() << info.name() << info.address().toString() << info.rssi();
@@ -404,14 +438,14 @@ void BtLocalDevice::dumpServiceDiscovery()
qDebug() << "Service Discovery active:" << serviceAgent->isActive();
qDebug() << "Error:" << serviceAgent->error() << serviceAgent->errorString();
const QList<QBluetoothServiceInfo> list = serviceAgent->discoveredServices();
- qDebug() << "Discovered Services:" << list.count();
+ qDebug() << "Discovered Services:" << list.size();
for (const QBluetoothServiceInfo &i : list) {
qDebug() << i.device().address().toString() << i.device().name() << i.serviceName();
}
qDebug() << "###### TestServer offered by:";
- for (const QBluetoothServiceInfo& found : qAsConst(foundTestServers)) {
+ for (const QBluetoothServiceInfo& found : std::as_const(foundTestServers)) {
qDebug() << found.device().name() << found.device().address().toString();
}
}
@@ -514,13 +548,14 @@ void BtLocalDevice::dumpSocketInformation()
qDebug() << "socket bytesAvailable()" << socket->bytesAvailable();
QString tmp;
switch (socket->error()) {
- case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
- case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
- case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
- case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
- case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
- //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
- case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ case QBluetoothSocket::SocketError::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::SocketError::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::SocketError::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::SocketError::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::SocketError::NetworkError: tmp += "NetworkError"; break;
+ //case QBluetoothSocket::SocketError::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ case QBluetoothSocket::SocketError::MissingPermissionsError: tmp += "MissingPermissionsError"; break;
default: tmp+= "Undefined"; break;
}
@@ -533,7 +568,7 @@ void BtLocalDevice::dumpSocketInformation()
void BtLocalDevice::writeData()
{
const char * testData = "ABCABC\n";
- if (socket && socket->state() == QBluetoothSocket::ConnectedState) {
+ if (socket && socket->state() == QBluetoothSocket::SocketState::ConnectedState) {
socket->write(testData);
}
for (QBluetoothSocket* client : serverSockets) {
@@ -549,7 +584,7 @@ void BtLocalDevice::readData()
qDebug() << ">> peer(" << socket->peerName() << socket->peerAddress()
<< socket->peerPort() << ") local("
<< socket->localName() << socket->localAddress() << socket->localPort()
- << ")>>" << QString::fromUtf8(line.constData(), line.length());
+ << ")>>" << QString::fromUtf8(line.constData(), line.size());
}
}
}
@@ -581,7 +616,7 @@ void BtLocalDevice::serverListenPort()
QBluetoothServiceInfo::Sequence profileSequence;
QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
classId << QVariant::fromValue(quint16(0x100));
profileSequence.append(QVariant::fromValue(classId));
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
@@ -589,7 +624,7 @@ void BtLocalDevice::serverListenPort()
classId.clear();
classId << QVariant::fromValue(QBluetoothUuid(QString(TEST_SERVICE_UUID)));
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
// Service name, description and provider
@@ -604,20 +639,20 @@ void BtLocalDevice::serverListenPort()
// Service Discoverability
QBluetoothServiceInfo::Sequence browseSequence;
- browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+ browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseSequence);
// Protocol descriptor list
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
if (server->serverType() == QBluetoothServiceInfo::L2capProtocol)
protocol << QVariant::fromValue(server->serverPort());
protocolDescriptorList.append(QVariant::fromValue(protocol));
if (server->serverType() == QBluetoothServiceInfo::RfcommProtocol) {
protocol.clear();
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(server->serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
@@ -682,8 +717,7 @@ void BtLocalDevice::serverNewConnection()
connect(client, &QIODevice::readyRead, this, &BtLocalDevice::clientSocketReadyRead);
connect(client, &QBluetoothSocket::stateChanged,
this, &BtLocalDevice::socketStateChanged);
- connect(client, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &BtLocalDevice::socketError);
+ connect(client, &QBluetoothSocket::errorOccurred, this, &BtLocalDevice::socketError);
connect(client, &QBluetoothSocket::connected, this, &BtLocalDevice::socketConnected);
connect(client, &QBluetoothSocket::bytesWritten, this, [](qint64 bytesWritten){
qDebug() << "Bytes Written to Server socket:" << bytesWritten;
@@ -712,7 +746,7 @@ void BtLocalDevice::clientSocketReadyRead()
while (socket->canReadLine()) {
const QByteArray line = socket->readLine().trimmed();
- QString lineString = QString::fromUtf8(line.constData(), line.length());
+ QString lineString = QString::fromUtf8(line.constData(), line.size());
qDebug() << ">>(" << server->serverAddress() << server->serverPort() <<")>>"
<< lineString;
@@ -729,7 +763,7 @@ void BtLocalDevice::clientSocketReadyRead()
void BtLocalDevice::dumpServerInformation()
{
- static QBluetooth::SecurityFlags secFlag = QBluetooth::Authentication;
+ static QBluetooth::SecurityFlags secFlag = QBluetooth::Security::Authentication;
if (server) {
qDebug() << "*******************************";
qDebug() << "server port:" <<server->serverPort()
@@ -740,14 +774,14 @@ void BtLocalDevice::dumpServerInformation()
<< "hasPending:" << server->hasPendingConnections()
<< "maxPending:" << server->maxPendingConnections();
qDebug() << "security:" << server->securityFlags() << "Togling security flag";
- if (secFlag == QBluetooth::Authentication)
- secFlag = QBluetooth::Encryption;
+ if (secFlag == QBluetooth::SecurityFlags(QBluetooth::Security::Authentication))
+ secFlag = QBluetooth::Security::Encryption;
else
- secFlag = QBluetooth::Authentication;
+ secFlag = QBluetooth::Security::Authentication;
//server->setSecurityFlags(secFlag);
- for (const QBluetoothSocket *client : qAsConst(serverSockets)) {
+ for (const QBluetoothSocket *client : std::as_const(serverSockets)) {
qDebug() << "##" << client->localAddress().toString()
<< client->localName() << client->localPort();
qDebug() << "##" << client->peerAddress().toString()
@@ -756,13 +790,14 @@ void BtLocalDevice::dumpServerInformation()
qDebug() << "Pending bytes: " << client->bytesAvailable();
QString tmp;
switch (client->error()) {
- case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
- case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
- case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
- case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
- case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
- case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
- //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::SocketError::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::SocketError::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::SocketError::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::SocketError::NetworkError: tmp += "NetworkError"; break;
+ case QBluetoothSocket::SocketError::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ //case QBluetoothSocket::SocketError::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::MissingPermissionsError: tmp += "MissingPermissionsError"; break;
default: tmp += QString::number(static_cast<int>(client->error())); break;
}
@@ -771,12 +806,36 @@ void BtLocalDevice::dumpServerInformation()
}
}
+template <typename T>
+void printError(const QLatin1StringView name, T* ptr)
+{
+ if (!ptr)
+ return;
+ qDebug() << name << "error:" << ptr->error();
+}
+
+void BtLocalDevice::dumpErrors()
+{
+ qDebug() << "###### Errors";
+ printError("Device agent"_L1, deviceAgent);
+ printError("Service agent"_L1, serviceAgent);
+ printError("LE Central"_L1, leCentralController.get());
+ printError("LE Central Service"_L1, leCentralService.get());
+ printError("LE Peripheral"_L1, lePeripheralController.get());
+ if (!lePeripheralServices.isEmpty())
+ printError("LE Peripheral Service"_L1, lePeripheralServices[0].get());
+ printError("Socket"_L1, socket);
+ printError("Server"_L1, server);
+}
+
void BtLocalDevice::dumpInformation()
{
+ if (!localDevice)
+ return;
qDebug() << "###### default local device";
dumpLocalDevice(localDevice);
const QList<QBluetoothHostInfo> list = QBluetoothLocalDevice::allDevices();
- qDebug() << "Found local devices: " << list.count();
+ qDebug() << "Found local devices: " << list.size();
for (const QBluetoothHostInfo &info : list) {
qDebug() << " " << info.address().toString() << " " <<info.name();
}
@@ -826,17 +885,21 @@ void BtLocalDevice::dumpInformation()
QBluetoothServiceDiscoveryAgent validSAgent(localDevice->address());
validSAgent.start();
qDebug() << "######" << (validSAgent.error() == QBluetoothServiceDiscoveryAgent::NoError) << "(Expected: true)";
+
+ dumpLeInfo();
}
void BtLocalDevice::powerOn()
{
+ if (!localDevice)
+ return;
qDebug() << "Powering on";
localDevice->powerOn();
}
void BtLocalDevice::reset()
{
- emit error(static_cast<QBluetoothLocalDevice::Error>(1000));
+ emit errorOccurred(static_cast<QBluetoothLocalDevice::Error>(1000));
if (serviceAgent) {
serviceAgent->clear();
}
@@ -850,3 +913,682 @@ void BtLocalDevice::dumpLocalDevice(QBluetoothLocalDevice *dev)
qDebug() << " Address" << dev->address().toString();
qDebug() << " HostMode" << dev->hostMode();
}
+
+void BtLocalDevice::peripheralCreate()
+{
+ qDebug() << "######" << "LE create peripheral";
+ if (lePeripheralController) {
+ qDebug() << "Peripheral already existed";
+ return;
+ }
+
+ lePeripheralController.reset(QLowEnergyController::createPeripheral());
+ emit leChanged();
+
+ QObject::connect(lePeripheralController.get(), &QLowEnergyController::errorOccurred,
+ [this](QLowEnergyController::Error error) {
+ qDebug() << "QLowEnergyController peripheral errorOccurred:" << error;
+ emit leChanged();
+ });
+ QObject::connect(lePeripheralController.get(), &QLowEnergyController::stateChanged,
+ [this](QLowEnergyController::ControllerState state) {
+ qDebug() << "QLowEnergyController peripheral stateChanged:" << state;
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::peripheralAddServices()
+{
+ qDebug() << "######" << "LE add services";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+ if (lePeripheralServiceData.isEmpty()) {
+ // Create service data
+ {
+ 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);
+
+ // Set another characteristic without notifications
+ QLowEnergyCharacteristicData secondCharData;
+ secondCharData.setUuid(QBluetoothUuid(leCharUuid2));
+ secondCharData.setValue(leSecondCharacteristicValue);
+ secondCharData.setValueLength(leCharacteristicSize, leCharacteristicSize);
+ secondCharData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write);
+ sd.addCharacteristic(secondCharData);
+ lePeripheralServiceData << sd;
+ }
+ {
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ sd.setUuid(QBluetoothUuid(leSecondServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leSecondServiceCharUuid1));
+ charData.setValue("second service char"_ba);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+ sd.addCharacteristic(charData);
+ lePeripheralServiceData << sd;
+ }
+ {
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypeSecondary);
+ sd.setUuid(QBluetoothUuid(leThirdServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leThirdServiceCharUuid1));
+ charData.setValue("third service char"_ba);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+ sd.addCharacteristic(charData);
+ lePeripheralServiceData << sd;
+ }
+ }
+
+ Q_ASSERT(lePeripheralServiceData.size() == 3);
+ // Free previous services if any
+ lePeripheralServices.clear();
+ // Add first service, and then set the first service as the included service for the second
+ auto service = lePeripheralController->addService(lePeripheralServiceData[0]);
+ if (service) {
+ lePeripheralServiceData[1].setIncludedServices({service});
+ // Then add the services to controller
+ lePeripheralServices.emplaceBack(service);
+ lePeripheralServices.emplaceBack(
+ lePeripheralController->addService(lePeripheralServiceData[1]));
+ lePeripheralServices.emplaceBack(
+ lePeripheralController->addService(lePeripheralServiceData[2]));
+ }
+
+ emit leChanged();
+
+ if (lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral service creation failed";
+ return;
+ }
+
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicWritten,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value written" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicRead,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value read" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicChanged,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value changed" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::descriptorRead,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE peripheral service descriptor value read" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::descriptorWritten,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE peripheral service descriptor value written" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::errorOccurred,
+ [this](QLowEnergyService::ServiceError error){
+ qDebug() << "LE peripheral service errorOccurred:" << error;
+ emit leChanged();
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::stateChanged,
+ [this](QLowEnergyService::ServiceState state){
+ qDebug() << "LE peripheral service state changed:" << state;
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::peripheralStartAdvertising()
+{
+ qDebug() << "######" << "LE start advertising";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+
+ if (leAdvertisingData.localName().isEmpty()) {
+ // Create advertisement data
+ leAdvertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
+ leAdvertisingData.setIncludePowerLevel(true);
+ leAdvertisingData.setLocalName(leRemotePeriphreralDeviceName);
+
+ leAdvertisingData.setManufacturerData(0xCAFE, "maker");
+ // Here we use short unrelated UUID so we can fit both service UUID and manufacturer data
+ // into the advertisement. This is for testing purposes
+ leAdvertisingData.setServices(
+ {QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::AlertNotificationService)});
+ // May result in too big advertisement data, can be useful for testing such scenario
+ // leAdvertisingData.setServices({QBluetoothUuid(leServiceUuid)});
+ }
+ // Start advertising. For testing the advertising can be started without valid services
+ qDebug() << "Starting advertising, services are valid:" << !lePeripheralServiceData.isEmpty();
+ lePeripheralController->startAdvertising(QLowEnergyAdvertisingParameters{},
+ leAdvertisingData, leAdvertisingData);
+}
+
+void BtLocalDevice::peripheralStopAdvertising()
+{
+ qDebug() << "######" << "LE stop advertising";
+ if (!lePeripheralController) {
+ qDebug() << "Peripheral does not exist";
+ return;
+ }
+ lePeripheralController->stopAdvertising();
+}
+
+void BtLocalDevice::centralCharacteristicWrite()
+{
+ qDebug() << "######" << "LE central write characteristic";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ // Update value at the beginning and end so we can check whole data is sent in large writes
+ // Value is offset'd with 100 to easily see which end did the write when testing
+ leCharacteristicValueUpdate += 1;
+ leCharacteristicValue[0] = leCharacteristicValueUpdate + 100;
+ leCharacteristicValue[leCharacteristicSize - 1] = leCharacteristicValueUpdate + 100;
+ qDebug() << " Central writes value:" << leCharacteristicValue;
+ leCentralService->writeCharacteristic(characteristic, leCharacteristicValue);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::centralCharacteristicRead()
+{
+ qDebug() << "######" << "LE central read characteristic";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ qDebug() << " Value before issuing read():" << characteristic.value();
+ leCentralService->readCharacteristic(characteristic);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::centralDescriptorWrite()
+{
+ qDebug() << "######" << "LE central write descriptor";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto descriptor = leCentralService->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+
+ if (descriptor.isValid()) {
+ leDescriptorValue[0] = leDescriptorValueUpdate++;
+ qDebug() << " Central writes value: " << leDescriptorValue;
+ leCentralService->writeDescriptor(descriptor, leDescriptorValue);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+void BtLocalDevice::centralDescriptorRead()
+{
+ qDebug() << "######" << "LE central read descriptor";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto descriptor = leCentralService->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+ if (descriptor.isValid()) {
+ qDebug() << " Value before issuing read():" << descriptor.value();
+ leCentralService->readDescriptor(descriptor);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+
+void BtLocalDevice::peripheralCharacteristicWrite()
+{
+ qDebug() << "######" << "LE peripheral write characteristic";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+
+ auto characteristic = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ // Update value at the beginning and end so we can check whole data is sent in large writes
+ leCharacteristicValue[0] = ++leCharacteristicValueUpdate;
+ leCharacteristicValue[leCharacteristicSize - 1] = leCharacteristicValueUpdate;
+ qDebug() << " Peripheral writes value:" << leCharacteristicValue;
+ lePeripheralServices[0]->writeCharacteristic(characteristic, leCharacteristicValue);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::peripheralCharacteristicRead()
+{
+ qDebug() << "######" << "LE peripheral read characteristic";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto characteristic = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid())
+ qDebug() << " Value:" << characteristic.value();
+ else
+ qDebug() << "Characteristic was invalid";
+}
+
+void BtLocalDevice::peripheralDescriptorWrite()
+{
+ qDebug() << "######" << "LE peripheral write descriptor";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto descriptor = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+
+ if (descriptor.isValid()) {
+ leDescriptorValue[0] = leDescriptorValueUpdate++;
+ qDebug() << " Peripheral writes value: " << leDescriptorValue;
+ lePeripheralServices[0]->writeDescriptor(descriptor, leDescriptorValue);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+void BtLocalDevice::peripheralDescriptorRead()
+{
+ qDebug() << "######" << "LE peripheral read descriptor";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto descriptor = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+ if (descriptor.isValid())
+ qDebug() << " Value:" << descriptor.value();
+ else
+ qDebug() << "Descriptor was invalid";
+}
+
+void BtLocalDevice::startLeDeviceDiscovery()
+{
+ qDebug() << "######" << "LE device discovery start for:" << leRemotePeriphreralDeviceName;
+ if (deviceAgent)
+ deviceAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
+}
+
+void BtLocalDevice::centralStartServiceDiscovery()
+{
+ qDebug() << "######" << "LE service discovery start";
+ if (!leCentralController) {
+ qDebug() << "Create and connect central first";
+ return;
+ }
+ leCentralController->discoverServices();
+}
+
+void BtLocalDevice::centralCreate()
+{
+ qDebug() << "######" << "Central create";
+ if (leCentralController) {
+ qDebug() << "Central already existed";
+ return;
+ }
+
+ if (!leRemotePeripheralDevice.isValid()) {
+ qDebug() << "Creation failed, needs successful LE device discovery first";
+ return;
+ }
+
+ if (deviceAgent && deviceAgent->isActive()) {
+ qDebug() << "###### Stopping device discovery agent";
+ deviceAgent->stop();
+ }
+
+ leCentralController.reset(QLowEnergyController::createCentral(leRemotePeripheralDevice));
+ emit leChanged();
+
+ if (!leCentralController) {
+ qDebug() << "LE Central creation failed";
+ return;
+ }
+
+ QObject::connect(leCentralController.get(), &QLowEnergyController::errorOccurred,
+ [](QLowEnergyController::Error error) {
+ qDebug() << "QLowEnergyController central errorOccurred:" << error;
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::discoveryFinished, []() {
+ qDebug() << "QLowEnergyController central service discovery finished";
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::serviceDiscovered,
+ [](const QBluetoothUuid &newService){
+ qDebug() << "QLowEnergyController central service discovered:" << newService;
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::stateChanged,
+ [this](QLowEnergyController::ControllerState state) {
+ qDebug() << "QLowEnergyController central stateChanged:" << state;
+ if (state == QLowEnergyController::UnconnectedState)
+ latestRSSI = "N/A"_ba;
+ emit leChanged();
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::rssiRead,
+ [this](qint16 rssi) {
+ qDebug() << "QLowEnergyController central RSSI updated:" << rssi;
+ latestRSSI = QByteArray::number(rssi);
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::centralDiscoverServiceDetails()
+{
+ qDebug() << "###### Discover Service details";
+ if (!leCentralController) {
+ qDebug() << "Central does not exist";
+ return;
+ }
+ leCentralService.reset(
+ leCentralController->createServiceObject(QBluetoothUuid(leServiceUuid)));
+ emit leChanged();
+ if (!leCentralService) {
+ qDebug() << "Service creation failed, cannot discover details";
+ return;
+ }
+ QObject::connect(leCentralService.get(), &QLowEnergyService::stateChanged,
+ [this](QLowEnergyService::ServiceState state){
+ qDebug() << "LE central service state changed:" << state;
+ emit leChanged();
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicWritten,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value written" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicRead,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value read" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicChanged,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value changed" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::descriptorRead,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE central service descriptor value read" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::descriptorWritten,
+ [this](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE central service descriptor value written" << value;
+ emit leChanged();
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::errorOccurred,
+ [](QLowEnergyService::ServiceError error){
+ qDebug() << "LE central service error occurred:" << error;
+ });
+ leCentralService->discoverDetails(QLowEnergyService::FullDiscovery);
+}
+
+void BtLocalDevice::centralConnect()
+{
+ qDebug() << "######" << "Central connect";
+ if (!leCentralController) {
+ qDebug() << "Create central first";
+ return;
+ }
+ leCentralController->connectToDevice();
+}
+
+void BtLocalDevice::dumpLeInfo()
+{
+ const auto controllerDump = [](QLowEnergyController* controller) {
+ qDebug() << " State:" << controller->state();
+ qDebug() << " Role:" << controller->role();
+ qDebug() << " Error:" << controller->error();
+ qDebug() << " ErrorString:" << controller->errorString();
+ qDebug() << " MTU:" << controller->mtu();
+ qDebug() << " Local Address:" << controller->localAddress();
+ qDebug() << " RemoteAddress:" << controller->remoteAddress();
+ qDebug() << " RemoteName:" << controller->remoteName();
+ qDebug() << " Services count:" << controller->services().size();
+ };
+ qDebug() << "######" << "LE Peripheral controller";
+ if (lePeripheralController)
+ controllerDump(lePeripheralController.get());
+
+ qDebug() << "######" << "LE Central controller";
+ if (leCentralController)
+ controllerDump(leCentralController.get());
+
+ qDebug() << "######" << "LE Found peripheral device";
+ if (leRemotePeripheralDevice.isValid()) {
+ qDebug() << " Name:" << leRemotePeripheralDevice.name();
+ qDebug() << " UUID:" << leRemotePeripheralDevice.deviceUuid();
+ qDebug() << " Address:" << leRemotePeripheralDevice.address();
+ }
+
+ const auto serviceDump = [](QLowEnergyService* service){
+ qDebug() << " Name:" << service->serviceName();
+ qDebug() << " Uuid:" << service->serviceUuid();
+ qDebug() << " Error:" << service->error();
+ auto characteristics = service->characteristics();
+ for (const auto& characteristic : characteristics) {
+ qDebug() << " Characteristic";
+ qDebug() << " Uuid" << characteristic.uuid();
+ qDebug() << " Value" << characteristic.value();
+
+ }
+ };
+
+ qDebug() << "######" << "LE Central-side service";
+ if (leCentralService)
+ serviceDump(leCentralService.get());
+
+ qDebug() << "######" << "LE Peripheral-side service";
+ if (!lePeripheralServices.isEmpty())
+ serviceDump(lePeripheralServices[0].get());
+}
+
+void BtLocalDevice::centralSubscribeUnsubscribe()
+{
+ qDebug() << "######" << "LE Central (Un)Subscribe";
+ if (!leCentralService) {
+ qDebug() << "Service object does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (!characteristic.isValid()) {
+ qDebug() << "Characteristic is not valid";
+ return;
+ }
+
+ auto descriptor = characteristic.descriptor(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
+ if (!descriptor.isValid()) {
+ qDebug() << "Descriptor is not valid";
+ return;
+ }
+ if (descriptor.value() == QByteArray::fromHex("0000")) {
+ qDebug() << " Subscribing notifications";
+ leCentralService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
+ } else {
+ qDebug() << " Unsubscribing notifications";
+ leCentralService->writeDescriptor(descriptor, QByteArray::fromHex("0000"));
+ }
+ emit leChanged();
+}
+
+void BtLocalDevice::centralDelete()
+{
+ qDebug() << "######" << "Delete central" << leCentralController.get();
+ leCentralController.reset(nullptr);
+ latestRSSI = "(N/A)"_ba;
+ emit leChanged();
+}
+
+void BtLocalDevice::centralDisconnect()
+{
+ qDebug() << "######" << "LE central disconnect";
+ if (!leCentralController) {
+ qDebug() << "Create central first";
+ return;
+ }
+ leCentralController->disconnectFromDevice();
+}
+
+void BtLocalDevice::peripheralDelete()
+{
+ qDebug() << "######" << "Delete peripheral" << lePeripheralController.get();
+ lePeripheralController.reset(nullptr);
+ emit leChanged();
+}
+
+void BtLocalDevice::peripheralDisconnect()
+{
+ qDebug() << "######" << "LE peripheral disconnect";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+ lePeripheralController->disconnectFromDevice();
+}
+
+bool BtLocalDevice::centralExists() const
+{
+ return leCentralController.get();
+}
+
+bool BtLocalDevice::centralSubscribed() const
+{
+ if (!leCentralService)
+ return false;
+
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (!characteristic.isValid())
+ return false;
+
+ auto descriptor = characteristic.descriptor(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
+ if (!descriptor.isValid())
+ return false;
+
+ return (descriptor.value() != QByteArray::fromHex("0000"));
+}
+
+QByteArray BtLocalDevice::centralState() const
+{
+ if (!leCentralController)
+ return "(N/A)"_ba;
+
+ return controllerStateString[leCentralController->state()];
+}
+
+QByteArray BtLocalDevice::centralServiceState() const
+{
+ if (!leCentralService)
+ return "(N/A)"_ba;
+
+ return serviceStateString[leCentralService->state()];
+}
+
+QByteArray BtLocalDevice::centralError() const
+{
+ if (!leCentralController)
+ return "(N/A)"_ba;
+
+ return controllerErrorString[leCentralController->error()];
+}
+
+QByteArray BtLocalDevice::centralServiceError() const
+{
+ if (!leCentralService)
+ return "(N/A)"_ba;
+
+ return serviceErrorString[leCentralService->error()];
+}
+
+void BtLocalDevice::centralReadRSSI() const
+{
+ qDebug() << "######" << "LE central readRSSI";
+ if (!leCentralController)
+ return;
+ leCentralController->readRssi();
+}
+
+QByteArray BtLocalDevice::centralRSSI() const
+{
+ return latestRSSI;
+}
+
+QByteArray BtLocalDevice::peripheralState() const
+{
+ if (!lePeripheralController)
+ return "(N/A)"_ba;
+
+ return controllerStateString[lePeripheralController->state()];
+}
+
+QByteArray BtLocalDevice::peripheralServiceState() const
+{
+ if (lePeripheralServices.isEmpty())
+ return "(N/A)"_ba;
+
+ return serviceStateString[lePeripheralServices[0]->state()];
+}
+
+QByteArray BtLocalDevice::peripheralError() const
+{
+ if (!lePeripheralController)
+ return "(N/A)"_ba;
+
+ return controllerErrorString[lePeripheralController->error()];
+}
+
+QByteArray BtLocalDevice::peripheralServiceError() const
+{
+ if (lePeripheralServices.isEmpty())
+ return "(N/A)"_ba;
+
+ return serviceErrorString[lePeripheralServices[0]->error()];
+}
+
+bool BtLocalDevice::peripheralExists() const
+{
+ return lePeripheralController.get();
+}