Skip to content
This repository was archived by the owner on Jan 28, 2022. It is now read-only.

Commit a9dc41e

Browse files
authored
fix: Bluetooth dock setup improvements (#515)
- Fixed Bluetooth pairing with the updated Bluez stack on remote-os v1. - `dockSetupFailed` signal for UI to indicate immediate failure to avoid waiting for timeout. - Enhanced (error) logging. - Fixed QBluetoothLocalDevice signal handling: only setup once. - Potential memory leak fixes. Relates to #513
1 parent 2c42584 commit a9dc41e

File tree

4 files changed

+152
-52
lines changed

4 files changed

+152
-52
lines changed

setup/SetupStep8.qml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ Item {
5151
api.discoverNetworkServices("_yio-dock-api._tcp");
5252
mdnsDiscoveryTimeout.start();
5353
}
54+
55+
onDockSetupFailed: {
56+
bluetoothDiscoveryTimeout.stop();
57+
58+
_swipeView.dockSuccess = false;
59+
_swipeView.incrementCurrentIndex();
60+
}
5461
}
5562

5663
Connections {
@@ -92,7 +99,7 @@ Item {
9299
Timer {
93100
id: bluetoothDiscoveryTimeout
94101
running: _currentItem
95-
interval: 20000
102+
interval: 30000
96103
repeat: false
97104

98105
onTriggered: {
@@ -104,7 +111,7 @@ Item {
104111
Timer {
105112
id: mdnsDiscoveryTimeout
106113
running: false
107-
interval: 20000
114+
interval: 30000
108115
repeat: false
109116

110117
onTriggered: {

sources/bluetooth.cpp

Lines changed: 117 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,47 +27,67 @@
2727
#include "logging.h"
2828
#include "notifications.h"
2929

30-
BluetoothControl::BluetoothControl(QObject *parent) : QObject(parent) {
30+
BluetoothControl::BluetoothControl(QObject *parent)
31+
: QObject(parent), m_discoveryAgent(nullptr), m_dockSocket(nullptr) {
3132
qCInfo(lcBluetooth) << "Bluetooth starting";
3233

33-
// if there is a bluetooth device, let's set up some things
34+
// if there is a Bluetooth device, let's set up some things
35+
// FIXME move out of constructor
3436
if (m_localDevice.isValid()) {
3537
qCDebug(lcBluetooth) << "Bluetooth init OK";
3638

39+
QObject::connect(&m_localDevice, &QBluetoothLocalDevice::pairingDisplayConfirmation, this,
40+
&BluetoothControl::onPairingDisplayConfirmation);
41+
QObject::connect(&m_localDevice, &QBluetoothLocalDevice::pairingFinished, this,
42+
&BluetoothControl::onPairingDone);
43+
QObject::connect(&m_localDevice, &QBluetoothLocalDevice::error, this, &BluetoothControl::onPairingError);
3744
} else {
3845
qCCritical(lcBluetooth) << "Bluetooth device was not found.";
3946
Notifications::getInstance()->add(true, tr("Bluetooth device was not found."));
4047
}
4148
}
4249

43-
void BluetoothControl::turnOn() {
44-
if (m_localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
45-
m_localDevice.powerOn();
46-
qCDebug(lcBluetooth) << "Bluetooth on";
47-
}
50+
BluetoothControl::~BluetoothControl() {
51+
close();
4852
}
4953

50-
void BluetoothControl::turnOff() {
51-
m_localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
52-
qCDebug(lcBluetooth) << "Bluetooth off";
54+
bool BluetoothControl::isEnabled() {
55+
return (m_localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
56+
}
57+
58+
void BluetoothControl::setEnabled(bool enabled) {
59+
if (enabled) {
60+
if (m_localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
61+
m_localDevice.powerOn();
62+
qCInfo(lcBluetooth) << "Bluetooth on";
63+
}
64+
} else {
65+
m_localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
66+
qCInfo(lcBluetooth) << "Bluetooth off";
67+
}
68+
69+
emit bluetoothStatusChanged();
5370
}
5471

5572
void BluetoothControl::lookForDocks() {
56-
turnOn();
73+
setEnabled(true);
5774

58-
qCDebug(lcBluetooth) << "Creating bluetooth discovery agent";
75+
qCDebug(lcBluetooth) << "Creating Bluetooth discovery agent";
5976
m_discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
6077

6178
QObject::connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this,
6279
&BluetoothControl::onDeviceDiscovered);
6380
QObject::connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this,
6481
&BluetoothControl::onDiscoveryFinished);
65-
qCDebug(lcBluetooth) << "Starting Bluetooth discovery...";
82+
83+
qCInfo(lcBluetooth) << "Starting Bluetooth discovery...";
6684
m_discoveryAgent->start();
6785
}
6886

6987
void BluetoothControl::onDeviceDiscovered(const QBluetoothDeviceInfo &device) {
88+
qCDebug(lcBluetooth()) << "Discovered:" << device.address() << device.name();
7089
// if dock is found
90+
// FIXME support multiple discovered docks
7191
if (device.name().contains("YIO-Dock")) {
7292
// stop the discovery
7393
m_discoveryAgent->stop();
@@ -78,61 +98,117 @@ void BluetoothControl::onDeviceDiscovered(const QBluetoothDeviceInfo &device) {
7898
} else {
7999
m_dockServiceUuid = QBluetoothUuid(QStringLiteral("00001101-0000-1000-8000-00805f9b34fb"));
80100
}
101+
81102
QString name = device.name();
103+
emit dockFound(name);
82104

83-
emit dockFound(name);
84-
qCDebug(lcBluetooth) << "YIO Dock found" << name;
105+
// TODO(zehnm) split pairing & socket connection from discovery: UI should initiate pairing & command sending
106+
qCInfo(lcBluetooth) << "YIO Dock found. Request pairing with" << name;
85107

86-
QObject::connect(&m_localDevice, &QBluetoothLocalDevice::pairingFinished, this,
87-
&BluetoothControl::onPairingDone);
88-
qCDebug(lcBluetooth) << "Pairing requested.";
89108
m_localDevice.requestPairing(m_dockAddress, QBluetoothLocalDevice::Paired);
90109
}
91110
}
92111

93112
void BluetoothControl::onDiscoveryFinished() {
94-
qCDebug(lcBluetooth) << "Bluetooth discovery finished.";
95-
if (m_discoveryAgent) {
96-
m_discoveryAgent->deleteLater();
113+
if (m_discoveryAgent->error() != QBluetoothDeviceDiscoveryAgent::NoError) {
114+
qCWarning(lcBluetooth) << "Bluetooth discovery finished with error:" << m_discoveryAgent->error()
115+
<< m_discoveryAgent->errorString();
116+
dockSetupError();
117+
} else {
118+
QMap<QString, QString> devices;
119+
for (const QBluetoothDeviceInfo &device : m_discoveryAgent->discoveredDevices()) {
120+
devices.insert(device.address().toString(), device.name());
121+
}
122+
qCInfo(lcBluetooth) << "Bluetooth discovery finished." << devices;
97123
}
124+
125+
m_discoveryAgent->deleteLater();
126+
m_discoveryAgent = nullptr;
98127
}
99128

100129
void BluetoothControl::sendCredentialsToDock(const QString &msg) {
101130
qCDebug(lcBluetooth) << "Got the wifi credentials.";
102131
m_dockMessage = msg;
103132
}
104133

134+
void BluetoothControl::onPairingDisplayConfirmation(const QBluetoothAddress &address, QString pin) {
135+
qCInfo(lcBluetooth()) << "Confirming pairing request" << address << pin;
136+
m_localDevice.pairingConfirmation(true);
137+
}
138+
139+
void BluetoothControl::onPairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) {
140+
if (address == m_dockAddress && pairing == QBluetoothLocalDevice::Paired) {
141+
qCInfo(lcBluetooth) << "Pairing done with" << address;
142+
emit dockPaired(address.toString());
143+
m_dockSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
144+
145+
QObject::connect(m_dockSocket, &QBluetoothSocket::connected, this, &BluetoothControl::onDockConnected);
146+
QObject::connect(m_dockSocket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error), this,
147+
&BluetoothControl::onDockSocketError);
148+
149+
m_dockSocket->connectToService(m_dockAddress, m_dockServiceUuid);
150+
qCDebug(lcBluetooth) << "Connecting to Bluetooth service" << m_dockAddress << "with uuid" << m_dockServiceUuid;
151+
}
152+
}
153+
154+
void BluetoothControl::onPairingError(QBluetoothLocalDevice::Error error) {
155+
Q_UNUSED(error)
156+
qCWarning(lcBluetooth) << "Pairing failed with" << m_dockAddress;
157+
dockSetupError();
158+
}
159+
105160
void BluetoothControl::onDockConnected() {
106-
qCDebug(lcBluetooth) << "Open bluetooth socket";
107-
// open bluetooth socket
108-
m_dockSocket->open(QIODevice::WriteOnly);
161+
qCDebug(lcBluetooth) << "Opening Bluetooth socket to dock";
162+
emit dockConnected(m_dockAddress.toString(), m_dockServiceUuid.toString());
109163

110-
// format the message
164+
if (!m_dockSocket->open(QIODevice::WriteOnly)) {
165+
qCCritical(lcBluetooth()) << "Could not open Bluetooth socket to dock";
166+
dockSetupError();
167+
return;
168+
}
169+
170+
// send credential message
111171
QByteArray text = m_dockMessage.toUtf8() + '\n';
112172
qCDebug(lcBluetooth) << "Sending message to dock:" << text;
113-
m_dockSocket->write(text);
114-
qCDebug(lcBluetooth) << "Message sent to dock.";
173+
if (m_dockSocket->write(text) == -1) {
174+
qCCritical(lcBluetooth()) << "Could not send message to dock";
175+
dockSetupError();
176+
return;
177+
}
115178

179+
qCInfo(lcBluetooth) << "Wifi setup message sent to dock.";
180+
181+
// TODO(zehnm) why this delay? For the dock to connect to wifi?
116182
QTimer::singleShot(6000, [=]() {
117-
// close and delete the socket
118-
m_dockSocket->close();
119-
m_dockSocket->deleteLater();
183+
close();
184+
setEnabled(false);
120185

121-
// power off the bluetooth
122-
turnOff();
123-
m_discoveryAgent->deleteLater();
124186
emit dockMessageSent();
125187
});
126188
}
127189

128-
void BluetoothControl::onPairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) {
129-
if (address == m_dockAddress && pairing == QBluetoothLocalDevice::Paired) {
130-
qCDebug(lcBluetooth) << "Pairing done.";
131-
m_dockSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
132-
133-
QObject::connect(m_dockSocket, &QBluetoothSocket::connected, this, &BluetoothControl::onDockConnected);
190+
void BluetoothControl::onDockSocketError(QBluetoothSocket::SocketError error) {
191+
qCCritical(lcBluetooth()) << "Dock socket error:" << error << m_dockSocket->errorString();
192+
dockSetupError();
193+
}
134194

135-
m_dockSocket->connectToService(m_dockAddress, m_dockServiceUuid);
136-
qCDebug(lcBluetooth) << "Connecting to bluetooth service" << m_dockAddress << m_dockServiceUuid;
195+
void BluetoothControl::close() {
196+
if (m_dockSocket) {
197+
m_dockSocket->close();
198+
m_dockSocket->deleteLater();
199+
m_dockSocket = nullptr;
137200
}
201+
if (m_discoveryAgent) {
202+
m_discoveryAgent->deleteLater();
203+
m_discoveryAgent = nullptr;
204+
}
205+
}
206+
207+
void BluetoothControl::dockSetupError() {
208+
close();
209+
setEnabled(false);
210+
211+
// TODO(zehnm) restart Bluetooth service?
212+
213+
emit dockSetupFailed();
138214
}

sources/bluetooth.h

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,47 @@
3232

3333
class BluetoothControl : public QObject {
3434
Q_OBJECT
35+
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY bluetoothStatusChanged)
3536

3637
public:
3738
explicit BluetoothControl(QObject *parent = nullptr);
38-
virtual ~BluetoothControl() {}
39+
~BluetoothControl();
3940

40-
void turnOn();
41-
void turnOff();
41+
bool isEnabled();
42+
void setEnabled(bool enabled);
4243

4344
signals:
44-
void dockFound(QString name);
45+
void bluetoothStatusChanged();
46+
47+
void dockFound(const QString &name);
48+
void dockPaired(const QString &address);
49+
void dockConnected(const QString &address, const QString &serviceUuid);
50+
4551
void dockMessageSent();
52+
void dockSetupFailed();
4653

4754
public slots: // NOLINT open issue: https://github.com/cpplint/cpplint/pull/99
4855
void lookForDocks();
56+
void sendCredentialsToDock(const QString &msg);
57+
58+
private slots: // NOLINT open issue: https://github.com/cpplint/cpplint/pull/99
4959
void onDeviceDiscovered(const QBluetoothDeviceInfo &device);
5060
void onDiscoveryFinished();
51-
void sendCredentialsToDock(const QString &msg);
52-
void onDockConnected();
61+
void onPairingDisplayConfirmation(const QBluetoothAddress &address, QString pin);
5362
void onPairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
63+
void onPairingError(QBluetoothLocalDevice::Error error);
64+
void onDockConnected();
65+
void onDockSocketError(QBluetoothSocket::SocketError error);
66+
67+
private:
68+
void close();
69+
void dockSetupError();
5470

5571
private:
5672
QBluetoothDeviceDiscoveryAgent *m_discoveryAgent;
5773
QBluetoothLocalDevice m_localDevice;
5874

75+
// FIXME support multiple devices
5976
QBluetoothAddress m_dockAddress;
6077
QBluetoothUuid m_dockServiceUuid;
6178
QBluetoothSocket *m_dockSocket;

translations/en_US.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ To learn more about the project, visit
124124
<context>
125125
<name>BluetoothControl</name>
126126
<message>
127-
<location filename="../sources/bluetooth.cpp" line="39"/>
127+
<location filename="../sources/bluetooth.cpp" line="40"/>
128128
<source>Bluetooth device was not found.</source>
129129
<translation type="unfinished"></translation>
130130
</message>
@@ -721,7 +721,7 @@ to set up YIO remote</source>
721721
<context>
722722
<name>QGuiApplication</name>
723723
<message>
724-
<location filename="../sources/main.cpp" line="217"/>
724+
<location filename="../sources/main.cpp" line="221"/>
725725
<source>Factory reset failed.
726726
%1</source>
727727
<translation type="unfinished"></translation>
@@ -976,7 +976,7 @@ a power source and wait until it starts blinking.
976976
<context>
977977
<name>SetupStep8</name>
978978
<message>
979-
<location filename="../setup/SetupStep8.qml" line="136"/>
979+
<location filename="../setup/SetupStep8.qml" line="143"/>
980980
<source>Setting up your YIO Dock</source>
981981
<translation type="unfinished"></translation>
982982
</message>

0 commit comments

Comments
 (0)