BluetoothLink.cc 10 KB
Newer Older
1
2
3
4
5
6
7
8
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
dogmaphobic's avatar
dogmaphobic committed
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26


/**
 * @file
 *   @brief Definition of Bluetooth connection for unmanned vehicles
 *   @author Gus Grubba <mavlink@grubba.com>
 *
 */

#include <QtGlobal>
#include <QTimer>
#include <QList>
#include <QDebug>
#include <iostream>

#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QtBluetooth/QBluetoothUuid>
dogmaphobic's avatar
dogmaphobic committed
27
#include <QtBluetooth/QBluetoothSocket>
dogmaphobic's avatar
dogmaphobic committed
28
29
30
31

#include "BluetoothLink.h"
#include "QGC.h"

32
33
BluetoothLink::BluetoothLink(SharedLinkConfigurationPointer& config)
    : LinkInterface(config)
34
    , _config(qobject_cast<BluetoothConfiguration*>(config.data()))
35
    , _connectState(false)
dogmaphobic's avatar
dogmaphobic committed
36
    , _targetSocket(NULL)
dogmaphobic's avatar
dogmaphobic committed
37
38
39
40
#ifdef __ios__
    , _discoveryAgent(NULL)
#endif
    , _shutDown(false)
dogmaphobic's avatar
dogmaphobic committed
41
{
42

dogmaphobic's avatar
dogmaphobic committed
43
44
45
46
47
}

BluetoothLink::~BluetoothLink()
{
    _disconnect();
dogmaphobic's avatar
dogmaphobic committed
48
49
50
51
52
53
54
55
#ifdef __ios__
    if(_discoveryAgent) {
        _shutDown = true;
        _discoveryAgent->stop();
        _discoveryAgent->deleteLater();
        _discoveryAgent = NULL;
    }
#endif
dogmaphobic's avatar
dogmaphobic committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
}

void BluetoothLink::run()
{
}

void BluetoothLink::_restartConnection()
{
    if(this->isConnected())
    {
        _disconnect();
        _connect();
    }
}

QString BluetoothLink::getName() const
{
    return _config->name();
}

76
void BluetoothLink::_writeBytes(const QByteArray bytes)
dogmaphobic's avatar
dogmaphobic committed
77
78
79
80
81
{
    if(_targetSocket)
    {
        if(_targetSocket->isWritable())
        {
82
            if(_targetSocket->write(bytes) > 0) {
83
                _logOutputDataRate(bytes.size(), QDateTime::currentMSecsSinceEpoch());
dogmaphobic's avatar
dogmaphobic committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
            }
            else
                qWarning() << "Bluetooth write error";
        }
        else
            qWarning() << "Bluetooth not writable error";
    }
}

void BluetoothLink::readBytes()
{
    while (_targetSocket->bytesAvailable() > 0)
    {
        QByteArray datagram;
        datagram.resize(_targetSocket->bytesAvailable());
        _targetSocket->read(datagram.data(), datagram.size());
        emit bytesReceived(this, datagram);
        _logInputDataRate(datagram.length(), QDateTime::currentMSecsSinceEpoch());
    }
}

void BluetoothLink::_disconnect(void)
{
dogmaphobic's avatar
dogmaphobic committed
107
108
109
110
111
112
#ifdef __ios__
    if(_discoveryAgent) {
        _shutDown = true;
        _discoveryAgent->stop();
        _discoveryAgent->deleteLater();
        _discoveryAgent = NULL;
dogmaphobic's avatar
dogmaphobic committed
113
    }
dogmaphobic's avatar
dogmaphobic committed
114
#endif
dogmaphobic's avatar
dogmaphobic committed
115
116
    if(_targetSocket)
    {
dogmaphobic's avatar
dogmaphobic committed
117
        delete _targetSocket;
dogmaphobic's avatar
dogmaphobic committed
118
119
120
121
122
123
124
125
        _targetSocket = NULL;
        emit disconnected();
    }
    _connectState = false;
}

bool BluetoothLink::_connect(void)
{
dogmaphobic's avatar
dogmaphobic committed
126
    _hardwareConnect();
dogmaphobic's avatar
dogmaphobic committed
127
128
129
130
    return true;
}

bool BluetoothLink::_hardwareConnect()
dogmaphobic's avatar
dogmaphobic committed
131
132
133
134
135
136
137
138
139
{
#ifdef __ios__
    if(_discoveryAgent) {
        _shutDown = true;
        _discoveryAgent->stop();
        _discoveryAgent->deleteLater();
        _discoveryAgent = NULL;
    }
    _discoveryAgent = new QBluetoothServiceDiscoveryAgent(this);
Tomaz Canabrava's avatar
Tomaz Canabrava committed
140
141
142
    QObject::connect(_discoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered, this, &BluetoothLink::serviceDiscovered);
    QObject::connect(_discoveryAgent, &QBluetoothServiceDiscoveryAgent::finished, this, &BluetoothLink::discoveryFinished);
    QObject::connect(_discoveryAgent, &QBluetoothServiceDiscoveryAgent::canceled, this, &BluetoothLink::discoveryFinished);
dogmaphobic's avatar
dogmaphobic committed
143
144
145
146
    _shutDown = false;
    _discoveryAgent->start();
#else
    _createSocket();
147
    _targetSocket->connectToService(QBluetoothAddress(_config->device().address), QBluetoothUuid(QBluetoothUuid::SerialPort));
dogmaphobic's avatar
dogmaphobic committed
148
149
150
151
152
#endif
    return true;
}

void BluetoothLink::_createSocket()
dogmaphobic's avatar
dogmaphobic committed
153
154
155
156
157
158
159
{
    if(_targetSocket)
    {
        delete _targetSocket;
        _targetSocket = NULL;
    }
    _targetSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
160
    QObject::connect(_targetSocket, &QBluetoothSocket::connected, this, &BluetoothLink::deviceConnected);
Tomaz Canabrava's avatar
Tomaz Canabrava committed
161

162
163
    QObject::connect(_targetSocket, &QBluetoothSocket::readyRead, this, &BluetoothLink::readBytes);
    QObject::connect(_targetSocket, &QBluetoothSocket::disconnected, this, &BluetoothLink::deviceDisconnected);
Tomaz Canabrava's avatar
Tomaz Canabrava committed
164
165
166

    QObject::connect(_targetSocket, static_cast<void (QBluetoothSocket::*)(QBluetoothSocket::SocketError)>(&QBluetoothSocket::error),
            this, &BluetoothLink::deviceError);
dogmaphobic's avatar
dogmaphobic committed
167
168
}

dogmaphobic's avatar
dogmaphobic committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#ifdef __ios__
void BluetoothLink::serviceDiscovered(const QBluetoothServiceInfo& info)
{
    if(!info.device().name().isEmpty() && !_targetSocket)
    {
        if(_config->device().uuid == info.device().deviceUuid() && _config->device().name == info.device().name())
        {
            _createSocket();
            _targetSocket->connectToService(info);
        }
    }
}
#endif

#ifdef __ios__
void BluetoothLink::discoveryFinished()
{
    if(_discoveryAgent && !_shutDown)
    {
        _shutDown = true;
        _discoveryAgent->deleteLater();
        _discoveryAgent = NULL;
        if(!_targetSocket)
        {
            _connectState = false;
            emit communicationError("Could not locate Bluetooth device:", _config->device().name);
        }
    }
}
#endif

dogmaphobic's avatar
dogmaphobic committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
void BluetoothLink::deviceConnected()
{
    _connectState = true;
    emit connected();
}

void BluetoothLink::deviceDisconnected()
{
    _connectState = false;
    qWarning() << "Bluetooth disconnected";
}

void BluetoothLink::deviceError(QBluetoothSocket::SocketError error)
{
    _connectState = false;
    qWarning() << "Bluetooth error" << error;
DonLakeFlyer's avatar
DonLakeFlyer committed
216
    emit communicationError(tr("Bluetooth Link Error"), _targetSocket->errorString());
dogmaphobic's avatar
dogmaphobic committed
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
}

bool BluetoothLink::isConnected() const
{
    return _connectState;
}

qint64 BluetoothLink::getConnectionSpeed() const
{
    return 1000000; // 1 Mbit
}

qint64 BluetoothLink::getCurrentInDataRate() const
{
    return 0;
}

qint64 BluetoothLink::getCurrentOutDataRate() const
{
    return 0;
}

//--------------------------------------------------------------------------
//-- BluetoothConfiguration

BluetoothConfiguration::BluetoothConfiguration(const QString& name)
    : LinkConfiguration(name)
    , _deviceDiscover(NULL)
{

}

BluetoothConfiguration::BluetoothConfiguration(BluetoothConfiguration* source)
    : LinkConfiguration(source)
    , _deviceDiscover(NULL)
{
dogmaphobic's avatar
dogmaphobic committed
253
    _device = source->device();
dogmaphobic's avatar
dogmaphobic committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
}

BluetoothConfiguration::~BluetoothConfiguration()
{
    if(_deviceDiscover)
    {
        _deviceDiscover->stop();
        delete _deviceDiscover;
    }
}

void BluetoothConfiguration::copyFrom(LinkConfiguration *source)
{
    LinkConfiguration::copyFrom(source);
    BluetoothConfiguration* usource = dynamic_cast<BluetoothConfiguration*>(source);
    Q_ASSERT(usource != NULL);
dogmaphobic's avatar
dogmaphobic committed
270
    _device = usource->device();
dogmaphobic's avatar
dogmaphobic committed
271
272
273
274
275
}

void BluetoothConfiguration::saveSettings(QSettings& settings, const QString& root)
{
    settings.beginGroup(root);
dogmaphobic's avatar
dogmaphobic committed
276
277
278
279
280
281
    settings.setValue("deviceName", _device.name);
#ifdef __ios__
    settings.setValue("uuid", _device.uuid.toString());
#else
    settings.setValue("address",_device.address);
#endif
dogmaphobic's avatar
dogmaphobic committed
282
283
284
285
286
287
    settings.endGroup();
}

void BluetoothConfiguration::loadSettings(QSettings& settings, const QString& root)
{
    settings.beginGroup(root);
dogmaphobic's avatar
dogmaphobic committed
288
289
290
291
292
    _device.name    = settings.value("deviceName", _device.name).toString();
#ifdef __ios__
    QString suuid   = settings.value("uuid", _device.uuid.toString()).toString();
    _device.uuid    = QUuid(suuid);
#else
dogmaphobic's avatar
dogmaphobic committed
293
    _device.address = settings.value("address", _device.address).toString();
dogmaphobic's avatar
dogmaphobic committed
294
#endif
dogmaphobic's avatar
dogmaphobic committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    settings.endGroup();
}

void BluetoothConfiguration::updateSettings()
{
    if(_link) {
        BluetoothLink* ulink = dynamic_cast<BluetoothLink*>(_link);
        if(ulink) {
            ulink->_restartConnection();
        }
    }
}

void BluetoothConfiguration::stopScan()
{
    if(_deviceDiscover)
    {
dogmaphobic's avatar
dogmaphobic committed
312
313
314
315
        _deviceDiscover->stop();
        _deviceDiscover->deleteLater();
        _deviceDiscover = NULL;
        emit scanningChanged();
dogmaphobic's avatar
dogmaphobic committed
316
317
318
319
320
321
322
323
    }
}

void BluetoothConfiguration::startScan()
{
    if(!_deviceDiscover)
    {
        _deviceDiscover = new QBluetoothDeviceDiscoveryAgent(this);
dogmaphobic's avatar
dogmaphobic committed
324
325
        connect(_deviceDiscover, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,  this, &BluetoothConfiguration::deviceDiscovered);
        connect(_deviceDiscover, &QBluetoothDeviceDiscoveryAgent::finished,          this, &BluetoothConfiguration::doneScanning);
dogmaphobic's avatar
dogmaphobic committed
326
327
328
329
330
331
        emit scanningChanged();
    }
    else
    {
        _deviceDiscover->stop();
    }
dogmaphobic's avatar
dogmaphobic committed
332
    _nameList.clear();
dogmaphobic's avatar
dogmaphobic committed
333
    _deviceList.clear();
dogmaphobic's avatar
dogmaphobic committed
334
    emit nameListChanged();
dogmaphobic's avatar
dogmaphobic committed
335
336
337
338
339
340
    _deviceDiscover->setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
    _deviceDiscover->start();
}

void BluetoothConfiguration::deviceDiscovered(QBluetoothDeviceInfo info)
{
dogmaphobic's avatar
dogmaphobic committed
341
342
    if(!info.name().isEmpty() && info.isValid())
    {
343
344
345
346
347
348
349
350
351
#if 0
        qDebug() << "Name:           " << info.name();
        qDebug() << "Address:        " << info.address().toString();
        qDebug() << "Service Classes:" << info.serviceClasses();
        QList<QBluetoothUuid> uuids = info.serviceUuids();
        foreach (QBluetoothUuid uuid, uuids) {
            qDebug() << "Service UUID:   " << uuid.toString();
        }
#endif
dogmaphobic's avatar
dogmaphobic committed
352
353
        BluetoothData data;
        data.name    = info.name();
dogmaphobic's avatar
dogmaphobic committed
354
355
356
#ifdef __ios__
        data.uuid    = info.deviceUuid();
#else
dogmaphobic's avatar
dogmaphobic committed
357
        data.address = info.address().toString();
dogmaphobic's avatar
dogmaphobic committed
358
#endif
dogmaphobic's avatar
dogmaphobic committed
359
360
361
362
363
364
365
366
        if(!_deviceList.contains(data))
        {
            _deviceList += data;
            _nameList   += data.name;
            emit nameListChanged();
            return;
        }
    }
dogmaphobic's avatar
dogmaphobic committed
367
368
369
370
371
372
373
374
375
376
377
378
}

void BluetoothConfiguration::doneScanning()
{
    if(_deviceDiscover)
    {
        _deviceDiscover->deleteLater();
        _deviceDiscover = NULL;
        emit scanningChanged();
    }
}

dogmaphobic's avatar
dogmaphobic committed
379
void BluetoothConfiguration::setDevName(const QString &name)
dogmaphobic's avatar
dogmaphobic committed
380
{
dogmaphobic's avatar
dogmaphobic committed
381
    foreach(const BluetoothData& data, _deviceList)
dogmaphobic's avatar
dogmaphobic committed
382
    {
dogmaphobic's avatar
dogmaphobic committed
383
384
385
386
        if(data.name == name)
        {
            _device = data;
            emit devNameChanged();
dogmaphobic's avatar
dogmaphobic committed
387
#ifndef __ios__
dogmaphobic's avatar
dogmaphobic committed
388
            emit addressChanged();
dogmaphobic's avatar
dogmaphobic committed
389
#endif
dogmaphobic's avatar
dogmaphobic committed
390
391
            return;
        }
dogmaphobic's avatar
dogmaphobic committed
392
393
394
    }
}

dogmaphobic's avatar
dogmaphobic committed
395
396
397
398
399
400
401
402
QString BluetoothConfiguration::address()
{
#ifdef __ios__
    return QString("");
#else
    return _device.address;
#endif
}