| 1 | // Copyright (C) 2022 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #include "bluezperipheralconnectionmanager_p.h" |
| 5 | #include "device1_bluez5_p.h" |
| 6 | |
| 7 | #include <QtBluetooth/QBluetoothLocalDevice> |
| 8 | #include <QtDBus/QDBusConnection> |
| 9 | #include <QtCore/QLoggingCategory> |
| 10 | |
| 11 | QT_BEGIN_NAMESPACE |
| 12 | |
| 13 | Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) |
| 14 | |
| 15 | using namespace Qt::StringLiterals; |
| 16 | using namespace QtBluetoothPrivate; // for D-Bus wrappers |
| 17 | |
| 18 | QtBluezPeripheralConnectionManager::QtBluezPeripheralConnectionManager( |
| 19 | const QBluetoothAddress& localAddress, QObject* parent) |
| 20 | : QObject(parent), |
| 21 | m_localDevice(new QBluetoothLocalDevice(localAddress, this)) |
| 22 | { |
| 23 | QObject::connect(sender: m_localDevice, signal: &QBluetoothLocalDevice::deviceDisconnected, |
| 24 | context: this, slot: &QtBluezPeripheralConnectionManager::remoteDeviceDisconnected); |
| 25 | } |
| 26 | |
| 27 | void QtBluezPeripheralConnectionManager::remoteDeviceAccessEvent( |
| 28 | const QString& remoteDeviceObjectPath, quint16 mtu) |
| 29 | { |
| 30 | if (m_clients.contains(key: remoteDeviceObjectPath)) |
| 31 | return; // Already aware of the client |
| 32 | |
| 33 | std::unique_ptr<OrgBluezDevice1Interface> device{new OrgBluezDevice1Interface( |
| 34 | "org.bluez"_L1 , remoteDeviceObjectPath, |
| 35 | QDBusConnection::systemBus(), this)}; |
| 36 | |
| 37 | qCDebug(QT_BT_BLUEZ) << "New LE Gatt client connected: " << remoteDeviceObjectPath |
| 38 | << device->address() << device->name() << "mtu:" << mtu; |
| 39 | |
| 40 | RemoteDeviceDetails details{.address: QBluetoothAddress{device->address()}, .name: device->name(), .mtu: mtu}; |
| 41 | |
| 42 | m_clients.insert(key: remoteDeviceObjectPath, value: details); |
| 43 | if (!m_connected) { |
| 44 | m_connected = true; |
| 45 | emit connectivityStateChanged(connected: true); |
| 46 | } |
| 47 | emit remoteDeviceChanged(address: details.address, name: details.name, mtu: details.mtu); |
| 48 | } |
| 49 | |
| 50 | void QtBluezPeripheralConnectionManager::remoteDeviceDisconnected(const QBluetoothAddress& address) |
| 51 | { |
| 52 | // Find if the disconnected device was gatt client |
| 53 | bool remoteDetailsChanged{false}; |
| 54 | for (auto it = m_clients.begin(); it != m_clients.end(); it++) { |
| 55 | if (it.value().address == address) { |
| 56 | qCDebug(QT_BT_BLUEZ) << "LE Gatt client disconnected:" << address; |
| 57 | remoteDetailsChanged = true; |
| 58 | m_clients.remove(key: it.key()); |
| 59 | break; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | if (!remoteDetailsChanged) |
| 64 | return; |
| 65 | |
| 66 | if (m_clients.isEmpty() && m_connected) { |
| 67 | m_connected = false; |
| 68 | emit connectivityStateChanged(connected: false); |
| 69 | } |
| 70 | |
| 71 | // If a client disconnected but there are others, pick any other. |
| 72 | // Qt API doesn't distinguish between clients |
| 73 | if (!m_clients.isEmpty()) { |
| 74 | emit remoteDeviceChanged(address: m_clients.last().address, |
| 75 | name: m_clients.last().name, mtu: m_clients.last().mtu); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | void QtBluezPeripheralConnectionManager::disconnectDevices() |
| 80 | { |
| 81 | for (auto it = m_clients.begin(); it != m_clients.end(); it++) { |
| 82 | std::unique_ptr<OrgBluezDevice1Interface> device{new OrgBluezDevice1Interface( |
| 83 | "org.bluez"_L1 , it.key(), QDBusConnection::systemBus())}; |
| 84 | device->Disconnect(); |
| 85 | } |
| 86 | reset(); |
| 87 | } |
| 88 | |
| 89 | void QtBluezPeripheralConnectionManager::reset() |
| 90 | { |
| 91 | m_connected = false; |
| 92 | m_clients.clear(); |
| 93 | } |
| 94 | |
| 95 | QT_END_NAMESPACE |
| 96 | |
| 97 | #include "moc_bluezperipheralconnectionmanager_p.cpp" |
| 98 | |