QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
BluetoothLink.cc
Go to the documentation of this file.
1#include "BluetoothLink.h"
2#include "BluetoothWorker.h"
4
5#include <QtCore/QCoreApplication>
6#include <QtCore/QPermissions>
7#include <QtCore/QThread>
8
9QGC_LOGGING_CATEGORY(BluetoothLinkLog, "Comms.Bluetooth.BluetoothLink")
10
11/*===========================================================================*/
12
14 : LinkInterface(config, parent)
15 , _bluetoothConfig(qobject_cast<BluetoothConfiguration*>(config.get()))
16 , _workerThread(new QThread(this))
17{
18 Q_ASSERT(_bluetoothConfig);
19 if (!_bluetoothConfig) {
20 qCCritical(BluetoothLinkLog) << "Invalid BluetoothConfiguration";
21 return;
22 }
23
24 _worker = BluetoothWorker::create(_bluetoothConfig);
25
26 qCDebug(BluetoothLinkLog) << this;
27
28 const QString threadName = (_bluetoothConfig->mode() == BluetoothConfiguration::BluetoothMode::ModeLowEnergy)
29 ? QStringLiteral("BLE_%1") : QStringLiteral("Bluetooth_%1");
30 _workerThread->setObjectName(threadName.arg(_bluetoothConfig->name()));
31
32 _worker->moveToThread(_workerThread.data());
33
34 (void) connect(_workerThread.data(), &QThread::started, _worker.data(), &BluetoothWorker::setupConnection);
35 (void) connect(_workerThread.data(), &QThread::finished, _worker.data(), &QObject::deleteLater);
36
37 (void) connect(_worker.data(), &BluetoothWorker::connected, this, &BluetoothLink::_onConnected, Qt::QueuedConnection);
38 (void) connect(_worker.data(), &BluetoothWorker::disconnected, this, &BluetoothLink::_onDisconnected, Qt::QueuedConnection);
39 (void) connect(_worker.data(), &BluetoothWorker::errorOccurred, this, &BluetoothLink::_onErrorOccurred, Qt::QueuedConnection);
40 (void) connect(_worker.data(), &BluetoothWorker::dataReceived, this, &BluetoothLink::_onDataReceived, Qt::QueuedConnection);
41 (void) connect(_worker.data(), &BluetoothWorker::dataSent, this, &BluetoothLink::_onDataSent, Qt::QueuedConnection);
42 (void) connect(_worker.data(), &BluetoothWorker::rssiUpdated, this, &BluetoothLink::_onRssiUpdated, Qt::QueuedConnection);
43
44 (void) connect(_bluetoothConfig, &BluetoothConfiguration::errorOccurred, this, &BluetoothLink::_onErrorOccurred);
45
46 _checkPermission();
47}
48
50{
51 if (_workerThread) {
52 if (_workerThread->isRunning() && _connectedCache && _worker) {
53 (void) QMetaObject::invokeMethod(_worker, "disconnectLink", Qt::QueuedConnection);
54 }
55
56 _shutdownWorkerThread(_workerThread, BluetoothLinkLog());
57 }
58
59 qCDebug(BluetoothLinkLog) << this;
60}
61
63{
64 return _connectedCache;
65}
66
67bool BluetoothLink::_connect()
68{
69 if (!_worker) {
70 return false;
71 }
72 if (_bluetoothConfig) {
73 _bluetoothConfig->stopScan();
74 }
75 return QMetaObject::invokeMethod(_worker.data(), "connectLink", Qt::QueuedConnection);
76}
77
79{
80 if (_worker) {
81 (void) QMetaObject::invokeMethod(_worker.data(), "disconnectLink", Qt::QueuedConnection);
82 }
83}
84
85void BluetoothLink::_onConnected()
86{
87 _connectedCache = true;
88 _disconnectedEmitted = false;
89 emit connected();
90}
91
92void BluetoothLink::_onDisconnected()
93{
94 _connectedCache = false;
95 if (!_disconnectedEmitted.exchange(true)) {
96 emit disconnected();
97 }
98}
99
100void BluetoothLink::_onErrorOccurred(const QString &errorString)
101{
102 qCWarning(BluetoothLinkLog) << "Communication error:" << errorString;
103
104 if (!_bluetoothConfig) {
105 emit communicationError(tr("Bluetooth Link Error"), errorString);
106 return;
107 }
108
109 const QString linkType = (_bluetoothConfig->mode() == BluetoothConfiguration::BluetoothMode::ModeLowEnergy)
110 ? tr("Bluetooth Low Energy") : tr("Bluetooth");
111
112 emit communicationError(tr("%1 Link Error").arg(linkType),
113 tr("Link %1: (Device: %2) %3").arg(_bluetoothConfig->name(),
114 _bluetoothConfig->device().name(),
115 errorString));
116}
117
118void BluetoothLink::_onDataReceived(const QByteArray &data)
119{
120 emit bytesReceived(this, data);
121}
122
123void BluetoothLink::_onDataSent(const QByteArray &data)
124{
125 emit bytesSent(this, data);
126}
127
128void BluetoothLink::_onRssiUpdated(qint16 rssi)
129{
130 if (_bluetoothConfig) {
131 _bluetoothConfig->setConnectedRssi(rssi);
132 }
133}
134
135void BluetoothLink::_writeBytes(const QByteArray &bytes)
136{
137 if (_worker) {
138 (void) QMetaObject::invokeMethod(_worker.data(), "writeData", Qt::QueuedConnection, Q_ARG(QByteArray, bytes));
139 }
140}
141
142void BluetoothLink::_checkPermission()
143{
144 QBluetoothPermission permission;
145 permission.setCommunicationModes(QBluetoothPermission::Access);
146
147 const Qt::PermissionStatus permissionStatus = QCoreApplication::instance()->checkPermission(permission);
148 if (permissionStatus == Qt::PermissionStatus::Undetermined) {
149 QCoreApplication::instance()->requestPermission(permission, this, [this](const QPermission &perm) {
150 _handlePermissionStatus(perm.status());
151 });
152 } else {
153 _handlePermissionStatus(permissionStatus);
154 }
155}
156
157void BluetoothLink::_handlePermissionStatus(Qt::PermissionStatus permissionStatus)
158{
159 if (permissionStatus != Qt::PermissionStatus::Granted) {
160 qCWarning(BluetoothLinkLog) << "Bluetooth Permission Denied";
161 _onErrorOccurred(tr("Bluetooth Permission Denied"));
162 _onDisconnected();
163 return;
164 }
165
166 qCDebug(BluetoothLinkLog) << "Bluetooth Permission Granted";
167
168 if (_workerThread && !_workerThread->isRunning()) {
169 _workerThread->start();
170 if (!_workerThread->isRunning()) {
171 qCCritical(BluetoothLinkLog) << "Failed to start worker thread";
172 _onErrorOccurred(tr("Failed to start Bluetooth worker thread"));
173 _worker->deleteLater();
174 _worker = nullptr;
175 }
176 }
177}
Config config
std::shared_ptr< LinkConfiguration > SharedLinkConfigurationPtr
QString errorString
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void errorOccurred(const QString &errorString)
const QBluetoothDeviceInfo & device() const
BluetoothMode mode() const
void dataReceived(const QByteArray &data)
void dataSent(const QByteArray &data)
void errorOccurred(const QString &errorString)
void rssiUpdated(qint16 rssi)
static BluetoothWorker * create(const BluetoothConfiguration *config, QObject *parent=nullptr)
QString name() const
The link interface defines the interface for all links used to communicate with the ground station ap...
void bytesReceived(LinkInterface *link, const QByteArray &data)
void disconnected()
void _shutdownWorkerThread(QThread *thread, const QLoggingCategory &category, bool allowTerminate=true)
void communicationError(const QString &title, const QString &error)
void bytesSent(LinkInterface *link, const QByteArray &data)
void connected()