Commit 5b46a393 authored by dogmaphobic's avatar dogmaphobic

First shot at Bluetooth

parent c58f1378
......@@ -69,11 +69,16 @@ QT += \
xml \
!MobileBuild {
QT += \
QT += \
printsupport \
serialport \
}
!WindowsBuild {
QT += \
bluetooth \
}
contains(DEFINES, QGC_NOTIFY_TUNES_ENABLED) {
QT += multimedia
}
......@@ -304,6 +309,9 @@ HEADERS += \
WindowsBuild {
PRECOMPILED_HEADER += src/stable_headers.h
HEADERS += src/stable_headers.h
} else {
HEADERS += \
src/comm/BluetoothLink.h \
}
!iOSBuild {
......@@ -425,6 +433,11 @@ SOURCES += \
src/ui/SerialConfigurationWindow.cc \
}
!WindowsBuild {
SOURCES += \
src/comm/BluetoothLink.cc \
}
!MobileBuild {
SOURCES += \
src/comm/LogReplayLink.cc \
......
......@@ -16,6 +16,7 @@
<file alias="FlightModesComponent.qml">src/AutoPilotPlugins/PX4/FlightModesComponent.qml</file>
<file alias="FlightModesComponentSummary.qml">src/AutoPilotPlugins/PX4/FlightModesComponentSummary.qml</file>
<file alias="BluetoothSettings.qml">src/ui/preferences/BluetoothSettings.qml</file>
<file alias="DebugWindow.qml">src/ui/preferences/DebugWindow.qml</file>
<file alias="GeneralSettings.qml">src/ui/preferences/GeneralSettings.qml</file>
<file alias="LinkSettings.qml">src/ui/preferences/LinkSettings.qml</file>
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @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/QBluetoothSocket>
#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QtBluetooth/QBluetoothUuid>
#include "BluetoothLink.h"
#include "QGC.h"
static void print_device_info(QBluetoothDeviceInfo info)
{
qDebug() << "Bluetooth: " << info.name();
qDebug() << " Services:" << info.serviceClasses();
qDebug() << " Major Classs:" << info.majorDeviceClass();
qDebug() << " Minor Classs:" << info.minorDeviceClass();
qDebug() << " RSSI:" << info.rssi();
qDebug() << " UUID:" << info.deviceUuid();
qDebug() << " Service UUID:" << info.serviceUuids();
qDebug() << " Core Config:" << info.coreConfigurations();
qDebug() << " Valid:" << info.isValid();
}
BluetoothLink::BluetoothLink(BluetoothConfiguration* config)
: _connectState(false)
, _targetSocket(NULL)
, _targetDevice(NULL)
, _deviceDiscover(NULL)
, _running(false)
{
Q_ASSERT(config != NULL);
_config = config;
_config->setLink(this);
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
//moveToThread(this);
}
BluetoothLink::~BluetoothLink()
{
// Disconnect link from configuration
_config->setLink(NULL);
_disconnect();
// Tell the thread to exit
_running = false;
quit();
// Wait for it to exit
wait();
this->deleteLater();
}
void BluetoothLink::run()
{
while (!_targetDevice && _running)
this->msleep(50);
if(_running && _hardwareConnect()) {
exec();
}
}
void BluetoothLink::deviceDiscovered(QBluetoothDeviceInfo info)
{
if(info.name() == _config->device())
{
if(!_targetDevice)
{
print_device_info(info);
_targetDevice = new QBluetoothDeviceInfo(info);
//-- Start Thread
_running = true;
start(NormalPriority);
}
}
}
void BluetoothLink::doneScanning()
{
if(!_targetDevice)
{
_connectState = false;
qWarning() << "Bluetooth scanning did not find device" << _config->device();
emit communicationError("Bluetooth Link Error", "Device Not Found");
_running = false;
}
}
void BluetoothLink::_restartConnection()
{
if(this->isConnected())
{
_disconnect();
_connect();
}
}
QString BluetoothLink::getName() const
{
return _config->name();
}
void BluetoothLink::writeBytes(const char* data, qint64 size)
{
_sendBytes(data, size);
}
void BluetoothLink::_sendBytes(const char* data, qint64 size)
{
if(_targetSocket)
{
if(_targetSocket->isWritable())
{
if(_targetSocket->write(data, size) > 0) {
_logOutputDataRate(size, QDateTime::currentMSecsSinceEpoch());
}
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)
{
_running = false;
quit();
wait();
if(_targetDevice)
{
delete _targetDevice;
_targetDevice = NULL;
}
if(_targetSocket)
{
_targetSocket->deleteLater();
_targetSocket = NULL;
emit disconnected();
}
if(_deviceDiscover)
{
_deviceDiscover->stop();
delete _deviceDiscover;
_deviceDiscover = NULL;
}
_connectState = false;
}
bool BluetoothLink::_connect(void)
{
if(this->isRunning() || _running)
{
_running = false;
quit();
wait();
}
if(_deviceDiscover)
{
_deviceDiscover->stop();
delete _deviceDiscover;
_deviceDiscover = NULL;
}
if(_targetDevice)
{
delete _targetDevice;
_targetDevice = NULL;
}
//-- Scan devices
_deviceDiscover = new QBluetoothDeviceDiscoveryAgent();
QObject::connect(_deviceDiscover, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
QObject::connect(_deviceDiscover, SIGNAL(finished()), this, SLOT(doneScanning()));
_deviceDiscover->setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
_deviceDiscover->start();
return true;
}
bool BluetoothLink::_hardwareConnect()
{
if(_targetSocket)
{
delete _targetSocket;
_targetSocket = NULL;
}
// Build Device Class Descriptor
/*
quint32 device_class = 0;
device_class |= ((0x20 | 0x100) << 13); // Service Class
device_class |= (0x04 << 8); // Audio Device (CLASS MAJOR) The Crossfire presents itself as an "Audio Service"
device_class |= (0x01 << 2); // WearableHeadsetDevice (CLASS MINOR)
qDebug() << _config->address() << _config->device() << device_class;
_targetDevice = new QBluetoothDeviceInfo(QBluetoothAddress(_config->address()), _config->device(), device_class);
_targetDevice->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
*/
_targetSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
_targetSocket->moveToThread(this);
qDebug() << "Connecting...";
print_device_info(*_targetDevice);
QObject::connect(_targetSocket, SIGNAL(connected()), this, SLOT(deviceConnected()));
QObject::connect(_targetSocket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(deviceError(QBluetoothSocket::SocketError)));
QObject::connect(_targetSocket, SIGNAL(readyRead()), this, SLOT(readBytes()));
QObject::connect(_targetSocket, SIGNAL(disconnected()), this, SLOT(deviceDisconnected()));
QObject::connect(_targetSocket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(stateChanged(QBluetoothSocket::SocketState)));
_targetSocket->connectToService(_targetDevice->address(), QBluetoothUuid(QBluetoothUuid::Rfcomm));
return true;
}
void BluetoothLink::stateChanged(QBluetoothSocket::SocketState state)
{
qDebug() << "Bluetooth state:" << state;
}
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;
emit communicationError("Bluetooth Link Error", _targetSocket->errorString());
}
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)
{
_address = source->address();
_device = source->device();
}
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);
_address = usource->address();
_device = usource->device();
}
void BluetoothConfiguration::saveSettings(QSettings& settings, const QString& root)
{
settings.beginGroup(root);
settings.setValue("device", _device);
settings.setValue("address", _address);
settings.endGroup();
}
void BluetoothConfiguration::loadSettings(QSettings& settings, const QString& root)
{
settings.beginGroup(root);
QString device = settings.value("device", _device).toString();
QString address = settings.value("address", _address).toString();
_device = device;
_address = address;
settings.endGroup();
}
void BluetoothConfiguration::updateSettings()
{
if(_link) {
BluetoothLink* ulink = dynamic_cast<BluetoothLink*>(_link);
if(ulink) {
ulink->_restartConnection();
}
}
}
void BluetoothConfiguration::stopScan()
{
if(_deviceDiscover)
{
}
}
void BluetoothConfiguration::startScan()
{
if(!_deviceDiscover)
{
_deviceDiscover = new QBluetoothDeviceDiscoveryAgent(this);
connect(_deviceDiscover, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothConfiguration::deviceDiscovered);
connect(_deviceDiscover, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothConfiguration::doneScanning);
emit scanningChanged();
}
else
{
_deviceDiscover->stop();
}
_deviceList.clear();
_addressList.clear();
emit deviceListChanged();
_deviceDiscover->setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
_deviceDiscover->start();
}
void BluetoothConfiguration::deviceDiscovered(QBluetoothDeviceInfo info)
{
_deviceList += info.name();
_addressList += info.address().toString();
print_device_info(info);
emit deviceListChanged();
}
void BluetoothConfiguration::doneScanning()
{
if(_deviceDiscover)
{
_deviceDiscover->deleteLater();
_deviceDiscover = NULL;
emit scanningChanged();
}
}
void BluetoothConfiguration::setDevice(QString device)
{
int idx = _deviceList.indexOf(device);
if(idx >= 0)
{
_address = _addressList.at(idx);
_device = device;
emit deviceChanged();
emit addressChanged();
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/*!
* @file
* @brief Bluetooth connection for unmanned vehicles
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#ifndef BTLINK_H
#define BTLINK_H
#include <QString>
#include <QList>
#include <QMutex>
#include <QMutexLocker>
#include <QQueue>
#include <QByteArray>
#include <QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothSocket>
#include "QGCConfig.h"
#include "LinkManager.h"
class QBluetoothDeviceDiscoveryAgent;
class BluetoothConfiguration : public LinkConfiguration
{
Q_OBJECT
public:
BluetoothConfiguration(const QString& name);
BluetoothConfiguration(BluetoothConfiguration* source);
~BluetoothConfiguration();
Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged)
Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
Q_PROPERTY(QStringList deviceList READ deviceList NOTIFY deviceListChanged)
Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged)
Q_INVOKABLE void startScan ();
Q_INVOKABLE void stopScan ();
QString device () { return _device; }
QString address () { return _address; }
QStringList deviceList () { return _deviceList; }
bool scanning () { return _deviceDiscover != NULL; }
void setDevice (QString device);
void setAddress (QString address) { _address = address; emit addressChanged(); }
/// From LinkConfiguration
LinkType type () { return LinkConfiguration::TypeBluetooth; }
void copyFrom (LinkConfiguration* source);
void loadSettings (QSettings& settings, const QString& root);
void saveSettings (QSettings& settings, const QString& root);
void updateSettings ();
QString settingsURL () { return "BluetoothSettings.qml"; }
public slots:
void deviceDiscovered (QBluetoothDeviceInfo info);
void doneScanning ();
signals:
void newDevice (QBluetoothDeviceInfo info);
void deviceChanged ();
void addressChanged ();
void deviceListChanged ();
void scanningChanged ();
private:
private:
QBluetoothDeviceDiscoveryAgent* _deviceDiscover;
QString _device;
QString _address;
QStringList _deviceList;
QStringList _addressList;
};
class BluetoothLink : public LinkInterface
{
Q_OBJECT
friend class BluetoothConfiguration;
friend class LinkManager;
public:
void requestReset () { }
bool isConnected () const;
QString getName () const;
// Extensive statistics for scientific purposes
qint64 getConnectionSpeed () const;
qint64 getCurrentInDataRate () const;
qint64 getCurrentOutDataRate () const;
void run();
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect (void);
bool disconnect (void);
LinkConfiguration* getLinkConfiguration() { return _config; }
public slots:
void readBytes ();
void writeBytes (const char* data, qint64 length);
void deviceConnected ();
void deviceDisconnected ();
void deviceError (QBluetoothSocket::SocketError error);
void stateChanged (QBluetoothSocket::SocketState state);
void deviceDiscovered (QBluetoothDeviceInfo info);
void doneScanning ();
protected:
BluetoothConfiguration* _config;
bool _connectState;
private:
// Links are only created/destroyed by LinkManager so constructor/destructor is not public
BluetoothLink(BluetoothConfiguration* config);
~BluetoothLink();
// From LinkInterface
bool _connect (void);
void _disconnect (void);
bool _hardwareConnect ();
void _restartConnection ();
void _sendBytes (const char* data, qint64 size);
private:
QBluetoothSocket* _targetSocket;
QBluetoothDeviceInfo* _targetDevice;
QBluetoothDeviceDiscoveryAgent* _deviceDiscover;
bool _running;
};
#endif // BTLINK_H
......@@ -36,7 +36,9 @@ This file is part of the QGROUNDCONTROL project
#ifndef __mobile__
#include "LogReplayLink.h"
#endif
#ifndef Q_OS_WIN
#include "BluetoothLink.h"
#endif
#ifdef QT_DEBUG
#include "MockLink.h"
#endif
......@@ -101,6 +103,11 @@ LinkConfiguration* LinkConfiguration::createSettings(int type, const QString& na
case LinkConfiguration::TypeTcp:
config = new TCPConfiguration(name);
break;
#ifndef Q_OS_WIN
case LinkConfiguration::TypeBluetooth:
config = new BluetoothConfiguration(name);
break;
#endif
#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
config = new LogReplayLinkConfiguration(name);
......@@ -134,6 +141,11 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc
case TypeTcp:
dupe = new TCPConfiguration(dynamic_cast<TCPConfiguration*>(source));
break;
#ifndef Q_OS_WIN
case TypeBluetooth:
dupe = new BluetoothConfiguration(dynamic_cast<BluetoothConfiguration*>(source));
break;
#endif
#ifndef __mobile__
case TypeLogReplay:
dupe = new LogReplayLinkConfiguration(dynamic_cast<LogReplayLinkConfiguration*>(source));
......
......@@ -57,12 +57,16 @@ public:
void setLink(LinkInterface* link);
/// The link types supported by QGC
/// Any changes here MUST be reflected in LinkManager::linkTypeStrings()
enum LinkType {
#ifndef __ios__
TypeSerial, ///< Serial Link
#endif
TypeUdp, ///< UDP Link
TypeTcp, ///< TCP Link
#ifndef Q_OS_WIN
TypeBluetooth, ///< Bluetooth Link
#endif
#if 0
// TODO Below is not yet implemented
TypeForwarding, ///< Forwarding Link
......
......@@ -44,6 +44,9 @@ This file is part of the QGROUNDCONTROL project
#include "QGCApplication.h"
#include "UDPLink.h"
#include "TCPLink.h"
#ifndef Q_OS_WIN
#include "BluetoothLink.h"
#endif
QGC_LOGGING_CATEGORY(LinkManagerLog, "LinkManagerLog")
QGC_LOGGING_CATEGORY(LinkManagerVerboseLog, "LinkManagerVerboseLog")
......@@ -124,6 +127,11 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
case LinkConfiguration::TypeTcp:
pLink = new TCPLink(dynamic_cast<TCPConfiguration*>(config));
break;
#ifndef Q_OS_WIN
case LinkConfiguration::TypeBluetooth:
pLink = new BluetoothLink(dynamic_cast<BluetoothConfiguration*>(config));
break;
#endif
#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
pLink = new LogReplayLink(dynamic_cast<LogReplayLinkConfiguration*>(config));
......@@ -359,6 +367,11 @@ void LinkManager::loadLinkConfigurationList()
case LinkConfiguration::TypeTcp:
pLink = (LinkConfiguration*)new TCPConfiguration(name);
break;
#ifndef Q_OS_WIN
case LinkConfiguration::TypeBluetooth:
pLink = (LinkConfiguration*)new BluetoothConfiguration(name);
break;
#endif
#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
pLink = (LinkConfiguration*)new LogReplayLinkConfiguration(name);
......@@ -701,12 +714,16 @@ QStringList LinkManager::linkTypeStrings(void) const
#endif
list += "UDP";
list += "TCP";
#ifndef Q_OS_WIN
list += "Bluetooth";
#endif
#ifdef QT_DEBUG
list += "Mock Link";
#endif
#ifndef __mobile__
list += "Log Replay";
#endif
Q_ASSERT(list.size() == (int)LinkConfiguration::TypeLast);
}
return list;
}
......@@ -828,6 +845,15 @@ void LinkManager::_fixUnnamed(LinkConfiguration* config)
}
}
break;
#ifndef Q_OS_WIN
case LinkConfiguration::TypeBluetooth: {
BluetoothConfiguration* tconfig = dynamic_cast<BluetoothConfiguration*>(config);
if(tconfig) {
config->setName(QString("Bluetooth Device on %1").arg(tconfig->device()));
}
}
break;
#endif
#ifndef __mobile__
case LinkConfiguration::TypeLogReplay: {
LogReplayLinkConfiguration* tconfig = dynamic_cast<LogReplayLinkConfiguration*>(config);
......
......@@ -50,6 +50,10 @@ This file is part of the QGROUNDCONTROL project
#endif
#endif
#ifndef Q_OS_WIN
#include <QtBluetooth/QBluetoothSocket>
#endif
#include <iostream>
/* SDL does ugly things to main() */
......@@ -135,6 +139,10 @@ int main(int argc, char *argv[])
// anyway to silence the debug output.
#ifndef __ios__
qRegisterMetaType<QSerialPort::SerialPortError>();
#endif
#ifndef Q_OS_WIN
qRegisterMetaType<QBluetoothSocket::SocketError>();
qRegisterMetaType<QBluetoothServiceInfo>();
#endif
qRegisterMetaType<QAbstractSocket::SocketError>();
#ifndef __mobile__
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.1
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
Item {
id: _btSettings
width: parent ? parent.width : 0
height: btColumn.height
function saveSettings() {
// No need
}
property var _currentDevice: ""
Column {
id: btColumn
spacing: ScreenTools.defaultFontPixelHeight / 2
ExclusiveGroup { id: linkGroup }
QGCPalette {
id: qgcPal
colorGroupEnabled: enabled
}
QGCLabel {
id: btLabel
text: "Bluetooth Link Settings"
}
Rectangle {
height: 1
width: btLabel.width
color: qgcPal.button
}
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Device:"
width: _firstColumn
}
QGCLabel {
id: deviceField
text: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth ? subEditConfig.device : ""
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Address:"
width: _firstColumn
}
QGCLabel {
id: addressField
text: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth ? subEditConfig.address : ""
}
}
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
QGCLabel {
text: "Bluetooth Devices:"
}
Item {
width: hostRow.width
height: hostRow.height
Row {
id: hostRow
spacing: ScreenTools.defaultFontPixelWidth
Item {
height: 1
width: _firstColumn
}
Column {
id: hostColumn
spacing: ScreenTools.defaultFontPixelHeight / 2
Rectangle {
height: 1
width: _secondColumn
color: qgcPal.button
visible: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth && subEditConfig.deviceList.length > 0
}
Repeater {
model: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth ? subEditConfig.deviceList : ""
delegate:
QGCButton {
text: modelData
width: _secondColumn
anchors.leftMargin: ScreenTools.defaultFontPixelWidth * 2
exclusiveGroup: linkGroup
onClicked: {
checked = true
_btSettings._currentDevice = modelData
}
}
}
Rectangle {
height: 1
width: _secondColumn
color: qgcPal.button
}
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
Item {
width: _secondColumn
height: udpButtonRow.height
Row {
id: udpButtonRow
spacing: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 10
text: "Scan"
enabled: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth && !subEditConfig.scanning
onClicked: {
if(subEditConfig)
subEditConfig.startScan()
}
}
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 10
text: "Stop"
enabled: subEditConfig && subEditConfig.linkType === LinkConfiguration.TypeBluetooth && subEditConfig.scanning
onClicked: {
if(subEditConfig)
subEditConfig.stopScan()
}
}
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 10
enabled: _btSettings._currentDevice && _btSettings._currentDevice !== ""
text: "Select"
onClicked: {
if(subEditConfig)
subEditConfig.device = _btSettings._currentDevice
}
}
}
}
}
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment