Commit 18dc3d04 authored by Don Gagne's avatar Don Gagne

Auto connect support

- Pervasive change to automatically connect to known board types
- Lots of additional changes along with this:
- More exposure of objects/properties to Qml
- Much restructuring in LinkManager and LinkManager clients
parent eb13a148
...@@ -270,7 +270,6 @@ HEADERS += \ ...@@ -270,7 +270,6 @@ HEADERS += \
src/QmlControls/QGCQGeoCoordinate.h \ src/QmlControls/QGCQGeoCoordinate.h \
src/QmlControls/QGroundControlQmlGlobal.h \ src/QmlControls/QGroundControlQmlGlobal.h \
src/QmlControls/QmlObjectListModel.h \ src/QmlControls/QmlObjectListModel.h \
src/SerialPortIds.h \
src/uas/FileManager.h \ src/uas/FileManager.h \
src/uas/UAS.h \ src/uas/UAS.h \
src/uas/UASInterface.h \ src/uas/UASInterface.h \
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
<file alias="PowerComponent.qml">src/AutoPilotPlugins/PX4/PowerComponent.qml</file> <file alias="PowerComponent.qml">src/AutoPilotPlugins/PX4/PowerComponent.qml</file>
<file alias="PowerComponentSummary.qml">src/AutoPilotPlugins/PX4/PowerComponentSummary.qml</file> <file alias="PowerComponentSummary.qml">src/AutoPilotPlugins/PX4/PowerComponentSummary.qml</file>
<file alias="PX4FlowSensor.qml">src/VehicleSetup/PX4FlowSensor.qml</file> <file alias="PX4FlowSensor.qml">src/VehicleSetup/PX4FlowSensor.qml</file>
<file alias="QGroundControl/Controls/ClickableColor.qml">src/QmlControls/ClickableColor.qml</file> <file alias="QGroundControl/Controls/ClickableColor.qml">src/QmlControls/ClickableColor.qml</file>
<file alias="QGroundControl/Controls/DropButton.qml">src/QmlControls/DropButton.qml</file> <file alias="QGroundControl/Controls/DropButton.qml">src/QmlControls/DropButton.qml</file>
<file alias="QGroundControl/Controls/ExclusiveGroupItem.qml">src/QmlControls/ExclusiveGroupItem.qml</file> <file alias="QGroundControl/Controls/ExclusiveGroupItem.qml">src/QmlControls/ExclusiveGroupItem.qml</file>
...@@ -42,7 +41,6 @@ ...@@ -42,7 +41,6 @@
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file> <file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file> <file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file> <file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCCanvas.qml">src/QmlControls/QGCCanvas.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file> <file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
<file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file> <file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file>
<file alias="QGroundControl/Controls/QGCComboBox.qml">src/QmlControls/QGCComboBox.qml</file> <file alias="QGroundControl/Controls/QGCComboBox.qml">src/QmlControls/QGCComboBox.qml</file>
...@@ -62,20 +60,17 @@ ...@@ -62,20 +60,17 @@
<file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file> <file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file>
<file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file> <file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file>
<file alias="QGroundControl/Controls/ViewWidget.qml">src/ViewWidgets/ViewWidget.qml</file> <file alias="QGroundControl/Controls/ViewWidget.qml">src/ViewWidgets/ViewWidget.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file> <file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file> <file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file> <file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactPanel.qml">src/FactSystem/FactControls/FactPanel.qml</file> <file alias="QGroundControl/FactControls/FactPanel.qml">src/FactSystem/FactControls/FactPanel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file> <file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file> <file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewVideo.qml">src/FlightDisplay/FlightDisplayViewVideo.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayViewVideo.qml">src/FlightDisplay/FlightDisplayViewVideo.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewWidgets.qml">src/FlightDisplay/FlightDisplayViewWidgets.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayViewWidgets.qml">src/FlightDisplay/FlightDisplayViewWidgets.qml</file>
<file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file> <file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file>
<file alias="QGroundControl/FlightMap/FlightMap.qml">src/FlightMap/FlightMap.qml</file> <file alias="QGroundControl/FlightMap/FlightMap.qml">src/FlightMap/FlightMap.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicator.qml">src/FlightMap/MapItems/MissionItemIndicator.qml</file> <file alias="QGroundControl/FlightMap/MissionItemIndicator.qml">src/FlightMap/MapItems/MissionItemIndicator.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemView.qml">src/FlightMap/MapItems/MissionItemView.qml</file> <file alias="QGroundControl/FlightMap/MissionItemView.qml">src/FlightMap/MapItems/MissionItemView.qml</file>
...@@ -90,10 +85,8 @@ ...@@ -90,10 +85,8 @@
<file alias="QGroundControl/FlightMap/QGCVideoBackground.qml">src/FlightMap/QGCVideoBackground.qml</file> <file alias="QGroundControl/FlightMap/QGCVideoBackground.qml">src/FlightMap/QGCVideoBackground.qml</file>
<file alias="QGroundControl/FlightMap/qmldir">src/FlightMap/qmldir</file> <file alias="QGroundControl/FlightMap/qmldir">src/FlightMap/qmldir</file>
<file alias="QGroundControl/FlightMap/VehicleMapItem.qml">src/FlightMap/MapItems/VehicleMapItem.qml</file> <file alias="QGroundControl/FlightMap/VehicleMapItem.qml">src/FlightMap/MapItems/VehicleMapItem.qml</file>
<file alias="QGroundControl/ScreenTools/qmldir">src/QmlControls/QGroundControl.ScreenTools.qmldir</file> <file alias="QGroundControl/ScreenTools/qmldir">src/QmlControls/QGroundControl.ScreenTools.qmldir</file>
<file alias="QGroundControl/ScreenTools/ScreenTools.qml">src/QmlControls/ScreenTools.qml</file> <file alias="QGroundControl/ScreenTools/ScreenTools.qml">src/QmlControls/ScreenTools.qml</file>
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file> <file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="RadioComponent.qml">src/AutoPilotPlugins/PX4/RadioComponent.qml</file> <file alias="RadioComponent.qml">src/AutoPilotPlugins/PX4/RadioComponent.qml</file>
<file alias="RadioComponentSummary.qml">src/AutoPilotPlugins/PX4/RadioComponentSummary.qml</file> <file alias="RadioComponentSummary.qml">src/AutoPilotPlugins/PX4/RadioComponentSummary.qml</file>
......
...@@ -139,7 +139,7 @@ void AirframeComponentController::_rebootAfterStackUnwind(void) ...@@ -139,7 +139,7 @@ void AirframeComponentController::_rebootAfterStackUnwind(void)
QGC::SLEEP::usleep(500); QGC::SLEEP::usleep(500);
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents); qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
} }
qgcApp()->toolbox()->linkManager()->disconnectAll(); qgcApp()->toolbox()->linkManager()->disconnectAll(false /* disconnectAutoconnectLink */);
qgcApp()->restoreOverrideCursor(); qgcApp()->restoreOverrideCursor();
} }
......
...@@ -50,14 +50,13 @@ HomePositionManager::HomePositionManager(QGCApplication* app) ...@@ -50,14 +50,13 @@ HomePositionManager::HomePositionManager(QGCApplication* app)
, homeLon(8.549444) , homeLon(8.549444)
, homeAlt(470.0) , homeAlt(470.0)
{ {
qmlRegisterUncreatableType<HomePositionManager> ("QGroundControl", 1, 0, "HomePositionManager", "Reference only");
} }
void HomePositionManager::setToolbox(QGCToolbox *toolbox) void HomePositionManager::setToolbox(QGCToolbox *toolbox)
{ {
QGCTool::setToolbox(toolbox); QGCTool::setToolbox(toolbox);
qmlRegisterUncreatableType<HomePositionManager> ("QGroundControl", 1, 0, "HomePositionManager", "Reference only");
_loadSettings(); _loadSettings();
} }
......
...@@ -184,7 +184,7 @@ Item { ...@@ -184,7 +184,7 @@ Item {
id: dropDownItem id: dropDownItem
visible: checked visible: checked
QGCCanvas { Canvas {
id: arrowCanvas id: arrowCanvas
anchors.fill: parent anchors.fill: parent
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
/// Canvas has some sort of bug in it which can cause it to not paint when top level Views
/// are switched. In order to fix this we ahve a signal hacked into ScreenTools to force
/// a repaint.
Canvas {
id: _root
Connections {
target: ScreenTools
onRepaintRequested: _root.requestPaint()
}
}
...@@ -9,7 +9,6 @@ QGCComboBox 1.0 QGCComboBox.qml ...@@ -9,7 +9,6 @@ QGCComboBox 1.0 QGCComboBox.qml
QGCColoredImage 1.0 QGCColoredImage.qml QGCColoredImage 1.0 QGCColoredImage.qml
QGCToolBarButton 1.0 QGCToolBarButton.qml QGCToolBarButton 1.0 QGCToolBarButton.qml
QGCMovableItem 1.0 QGCMovableItem.qml QGCMovableItem 1.0 QGCMovableItem.qml
QGCCanvas 1.0 QGCCanvas.qml
SubMenuButton 1.0 SubMenuButton.qml SubMenuButton 1.0 SubMenuButton.qml
IndicatorButton 1.0 IndicatorButton.qml IndicatorButton 1.0 IndicatorButton.qml
......
...@@ -33,6 +33,8 @@ static const char* kQmlGlobalKeyName = "QGCQml"; ...@@ -33,6 +33,8 @@ static const char* kQmlGlobalKeyName = "QGCQml";
QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCToolbox* toolbox, QObject* parent) QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCToolbox* toolbox, QObject* parent)
: QObject(parent) : QObject(parent)
, _multiVehicleManager(toolbox->multiVehicleManager())
, _linkManager(toolbox->linkManager())
, _homePositionManager(toolbox->homePositionManager()) , _homePositionManager(toolbox->homePositionManager())
, _flightMapSettings(toolbox->flightMapSettings()) , _flightMapSettings(toolbox->flightMapSettings())
{ {
...@@ -70,25 +72,25 @@ bool QGroundControlQmlGlobal::loadBoolGlobalSetting (const QString& key, bool de ...@@ -70,25 +72,25 @@ bool QGroundControlQmlGlobal::loadBoolGlobalSetting (const QString& key, bool de
#ifdef QT_DEBUG #ifdef QT_DEBUG
void QGroundControlQmlGlobal::_startMockLink(MockConfiguration* mockConfig) void QGroundControlQmlGlobal::_startMockLink(MockConfiguration* mockConfig)
{ {
MockLink* mockLink = new MockLink(mockConfig);
LinkManager* linkManager = qgcApp()->toolbox()->linkManager(); LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
linkManager->_addLink(mockLink); mockConfig->setDynamic(true);
linkManager->connectLink(mockLink); linkManager->linkConfigurations()->append(mockConfig);
linkManager->createConnectedLink(mockConfig, false /* autoconnectLink */);
} }
#endif #endif
void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText) void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText)
{ {
#ifdef QT_DEBUG #ifdef QT_DEBUG
MockConfiguration mockConfig("PX4 MockLink"); MockConfiguration* mockConfig = new MockConfiguration("PX4 MockLink");
mockConfig.setFirmwareType(MAV_AUTOPILOT_PX4); mockConfig->setFirmwareType(MAV_AUTOPILOT_PX4);
mockConfig.setVehicleType(MAV_TYPE_QUADROTOR); mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
mockConfig.setSendStatusText(sendStatusText); mockConfig->setSendStatusText(sendStatusText);
_startMockLink(&mockConfig); _startMockLink(mockConfig);
#else #else
Q_UNUSED(sendStatusText); Q_UNUSED(sendStatusText);
#endif #endif
...@@ -97,13 +99,13 @@ void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText) ...@@ -97,13 +99,13 @@ void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText) void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText)
{ {
#ifdef QT_DEBUG #ifdef QT_DEBUG
MockConfiguration mockConfig("Generic MockLink"); MockConfiguration* mockConfig = new MockConfiguration("Generic MockLink");
mockConfig.setFirmwareType(MAV_AUTOPILOT_GENERIC); mockConfig->setFirmwareType(MAV_AUTOPILOT_GENERIC);
mockConfig.setVehicleType(MAV_TYPE_QUADROTOR); mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
mockConfig.setSendStatusText(sendStatusText); mockConfig->setSendStatusText(sendStatusText);
_startMockLink(&mockConfig); _startMockLink(mockConfig);
#else #else
Q_UNUSED(sendStatusText); Q_UNUSED(sendStatusText);
#endif #endif
...@@ -112,13 +114,13 @@ void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText) ...@@ -112,13 +114,13 @@ void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText) void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText)
{ {
#ifdef QT_DEBUG #ifdef QT_DEBUG
MockConfiguration mockConfig("APM ArduCopter MockLink"); MockConfiguration* mockConfig = new MockConfiguration("APM ArduCopter MockLink");
mockConfig.setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA); mockConfig->setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
mockConfig.setVehicleType(MAV_TYPE_QUADROTOR); mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
mockConfig.setSendStatusText(sendStatusText); mockConfig->setSendStatusText(sendStatusText);
_startMockLink(&mockConfig); _startMockLink(mockConfig);
#else #else
Q_UNUSED(sendStatusText); Q_UNUSED(sendStatusText);
#endif #endif
...@@ -127,13 +129,13 @@ void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText) ...@@ -127,13 +129,13 @@ void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startAPMArduPlaneMockLink(bool sendStatusText) void QGroundControlQmlGlobal::startAPMArduPlaneMockLink(bool sendStatusText)
{ {
#ifdef QT_DEBUG #ifdef QT_DEBUG
MockConfiguration mockConfig("APM ArduPlane MockLink"); MockConfiguration* mockConfig = new MockConfiguration("APM ArduPlane MockLink");
mockConfig.setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA); mockConfig->setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
mockConfig.setVehicleType(MAV_TYPE_FIXED_WING); mockConfig->setVehicleType(MAV_TYPE_FIXED_WING);
mockConfig.setSendStatusText(sendStatusText); mockConfig->setSendStatusText(sendStatusText);
_startMockLink(&mockConfig); _startMockLink(mockConfig);
#else #else
Q_UNUSED(sendStatusText); Q_UNUSED(sendStatusText);
#endif #endif
...@@ -144,12 +146,12 @@ void QGroundControlQmlGlobal::stopAllMockLinks(void) ...@@ -144,12 +146,12 @@ void QGroundControlQmlGlobal::stopAllMockLinks(void)
#ifdef QT_DEBUG #ifdef QT_DEBUG
LinkManager* linkManager = qgcApp()->toolbox()->linkManager(); LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
QList<LinkInterface*> links = linkManager->getLinks(); for (int i=0; i<linkManager->links()->count(); i++) {
for (int i=0; i<links.count(); i++) { LinkInterface* link = linkManager->links()->value<LinkInterface*>(i);
LinkInterface* link = links[i];
MockLink* mockLink = qobject_cast<MockLink*>(link); MockLink* mockLink = qobject_cast<MockLink*>(link);
if (mockLink) { if (mockLink) {
linkManager->disconnectLink(mockLink); linkManager->disconnectLink(mockLink, false /* disconnectAutoconnectLink */);
} }
} }
#endif #endif
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "QGCApplication.h" #include "QGCApplication.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "LinkManager.h"
#include "HomePositionManager.h" #include "HomePositionManager.h"
#include "FlightMapSettings.h" #include "FlightMapSettings.h"
...@@ -47,6 +48,8 @@ class QGroundControlQmlGlobal : public QObject ...@@ -47,6 +48,8 @@ class QGroundControlQmlGlobal : public QObject
public: public:
QGroundControlQmlGlobal(QGCToolbox* toolbox, QObject* parent = NULL); QGroundControlQmlGlobal(QGCToolbox* toolbox, QObject* parent = NULL);
Q_PROPERTY(LinkManager* linkManager READ linkManager CONSTANT)
Q_PROPERTY(MultiVehicleManager* multiVehicleManager READ multiVehicleManager CONSTANT)
Q_PROPERTY(HomePositionManager* homePositionManager READ homePositionManager CONSTANT) Q_PROPERTY(HomePositionManager* homePositionManager READ homePositionManager CONSTANT)
Q_PROPERTY(FlightMapSettings* flightMapSettings READ flightMapSettings CONSTANT) Q_PROPERTY(FlightMapSettings* flightMapSettings READ flightMapSettings CONSTANT)
...@@ -81,6 +84,8 @@ public: ...@@ -81,6 +84,8 @@ public:
// Property accesors // Property accesors
LinkManager* linkManager () { return _linkManager; }
MultiVehicleManager* multiVehicleManager () { return _multiVehicleManager; }
HomePositionManager* homePositionManager () { return _homePositionManager; } HomePositionManager* homePositionManager () { return _homePositionManager; }
FlightMapSettings* flightMapSettings () { return _flightMapSettings; } FlightMapSettings* flightMapSettings () { return _flightMapSettings; }
...@@ -124,6 +129,8 @@ private: ...@@ -124,6 +129,8 @@ private:
void _startMockLink(MockConfiguration* mockConfig); void _startMockLink(MockConfiguration* mockConfig);
#endif #endif
MultiVehicleManager* _multiVehicleManager;
LinkManager* _linkManager;
HomePositionManager* _homePositionManager; HomePositionManager* _homePositionManager;
FlightMapSettings* _flightMapSettings; FlightMapSettings* _flightMapSettings;
}; };
......
...@@ -197,11 +197,6 @@ int QmlObjectListModel::count(void) const ...@@ -197,11 +197,6 @@ int QmlObjectListModel::count(void) const
return rowCount(); return rowCount();
} }
QObject* QmlObjectListModel::get(int index)
{
return _objectList[index];
}
void QmlObjectListModel::setDirty(bool dirty) void QmlObjectListModel::setDirty(bool dirty)
{ {
_dirty = dirty; _dirty = dirty;
......
...@@ -34,14 +34,14 @@ public: ...@@ -34,14 +34,14 @@ public:
QmlObjectListModel(QObject* parent = NULL); QmlObjectListModel(QObject* parent = NULL);
~QmlObjectListModel(); ~QmlObjectListModel();
Q_INVOKABLE QObject* get(int index);
Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(int count READ count NOTIFY countChanged)
/// Returns true if any of the items in the list are dirty. Requires each object to have /// Returns true if any of the items in the list are dirty. Requires each object to have
/// a dirty property and dirtyChanged signal. /// a dirty property and dirtyChanged signal.
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
Q_INVOKABLE QObject* get(int index) { return _objectList[index]; }
// Property accessors // Property accessors
int count(void) const; int count(void) const;
...@@ -52,13 +52,14 @@ public: ...@@ -52,13 +52,14 @@ public:
void append(QObject* object); void append(QObject* object);
void clear(void); void clear(void);
QObject* removeAt(int i); QObject* removeAt(int i);
QObject* removeOne(QObject* object) { return removeAt(indexOf(object)); }
void insert(int i, QObject* object); void insert(int i, QObject* object);
QObject* operator[](int i); QObject* operator[](int i);
const QObject* operator[](int i) const; const QObject* operator[](int i) const;
bool contains(QObject* object) { return _objectList.indexOf(object) != -1; }
template <class T> int indexOf(QObject* object) { return _objectList.indexOf(object); }
const QList<T*>& list(void) { return *((QList<T*>*)((void*)(&_objectList))); } template<class T> T value(int index) { return qobject_cast<T>(_objectList[index]); }
signals: signals:
void countChanged(int count); void countChanged(int count);
void dirtyChanged(bool dirtyChanged); void dirtyChanged(bool dirtyChanged);
......
...@@ -47,9 +47,4 @@ Item { ...@@ -47,9 +47,4 @@ Item {
property real fontWidth: contentWidth * (ScreenToolsController.testHighDPI ? 2 : 1) property real fontWidth: contentWidth * (ScreenToolsController.testHighDPI ? 2 : 1)
property real fontHeight: contentHeight * (ScreenToolsController.testHighDPI ? 2 : 1) property real fontHeight: contentHeight * (ScreenToolsController.testHighDPI ? 2 : 1)
} }
Connections {
target: ScreenToolsController
onRepaintRequested: repaintRequested()
}
} }
...@@ -43,15 +43,5 @@ const double ScreenToolsController::_largeFontPixelSizeRatio = 1.66; ...@@ -43,15 +43,5 @@ const double ScreenToolsController::_largeFontPixelSizeRatio = 1.66;
ScreenToolsController::ScreenToolsController() ScreenToolsController::ScreenToolsController()
{ {
MainWindow* mainWindow = MainWindow::instance();
// Unit tests can run Qml without MainWindow
if (mainWindow) {
connect(mainWindow, &MainWindow::repaintCanvas, this, &ScreenToolsController::_updateCanvas);
}
}
void ScreenToolsController::_updateCanvas()
{
emit repaintRequested();
} }
...@@ -114,12 +114,6 @@ public: ...@@ -114,12 +114,6 @@ public:
bool testHighDPI () { return false; } bool testHighDPI () { return false; }
#endif #endif
signals:
void repaintRequested();
private slots:
void _updateCanvas();
private: private:
static const double _defaultFontPixelSizeRatio; static const double _defaultFontPixelSizeRatio;
static const double _smallFontPixelSizeRatio; static const double _smallFontPixelSizeRatio;
......
...@@ -57,33 +57,26 @@ void MultiVehicleManager::setToolbox(QGCToolbox *toolbox) ...@@ -57,33 +57,26 @@ void MultiVehicleManager::setToolbox(QGCToolbox *toolbox)
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<MultiVehicleManager>("QGroundControl.MultiVehicleManager", 1, 0, "MultiVehicleManager", "Reference only"); qmlRegisterUncreatableType<MultiVehicleManager>("QGroundControl.MultiVehicleManager", 1, 0, "MultiVehicleManager", "Reference only");
connect(_toolbox->linkManager(), &LinkManager::linkActive, this, &MultiVehicleManager::_linkActive);
} }
bool MultiVehicleManager::notifyHeartbeatInfo(LinkInterface* link, int vehicleId, mavlink_heartbeat_t& heartbeat) void MultiVehicleManager::_linkActive(LinkInterface* link, int vehicleId, int vehicleFirmwareType, int vehicleType)
{ {
if (!getVehicleById(vehicleId) && !_ignoreVehicleIds.contains(vehicleId)) { if (!getVehicleById(vehicleId)) {
if (vehicleId == _mavlinkProtocol->getSystemId()) { qCDebug(MultiVehicleManagerLog) << "Adding new vehicle linkName:vehicleId:vehicleFirmwareType:vehicleType"
_app->showToolBarMessage(QString("Warning: A vehicle is using the same system id as QGroundControl: %1").arg(vehicleId)); << link->getName()
} << vehicleId
<< vehicleFirmwareType
QSettings settings; << vehicleType;
bool mavlinkVersionCheck = settings.value("VERSION_CHECK_ENABLED", true).toBool();
if (mavlinkVersionCheck && heartbeat.mavlink_version != MAVLINK_VERSION) {
_ignoreVehicleIds += vehicleId;
_app->showToolBarMessage(QString("The MAVLink protocol version on vehicle #%1 and QGroundControl differ! "
"It is unsafe to use different MAVLink versions. "
"QGroundControl therefore refuses to connect to vehicle #%1, which sends MAVLink version %2 (QGroundControl uses version %3).").arg(vehicleId).arg(heartbeat.mavlink_version).arg(MAVLINK_VERSION));
return false;
}
Vehicle* vehicle = new Vehicle(link, vehicleId, (MAV_AUTOPILOT)heartbeat.autopilot, (MAV_TYPE)heartbeat.type, _firmwarePluginManager, _autopilotPluginManager, _joystickManager); Vehicle* vehicle = new Vehicle(link, vehicleId, (MAV_AUTOPILOT)vehicleFirmwareType, (MAV_TYPE)vehicleType, _firmwarePluginManager, _autopilotPluginManager, _joystickManager);
if (!vehicle) { if (!vehicle) {
qWarning() << "New Vehicle allocation failed"; qWarning() << "New Vehicle allocation failed";
return false; return;
} }
connect(vehicle, &Vehicle::allLinksDisconnected, this, &MultiVehicleManager::_deleteVehiclePhase1); connect(vehicle, &Vehicle::allLinksInactive, this, &MultiVehicleManager::_deleteVehiclePhase1);
connect(vehicle->autopilotPlugin(), &AutoPilotPlugin::parametersReadyChanged, this, &MultiVehicleManager::_autopilotParametersReadyChanged); connect(vehicle->autopilotPlugin(), &AutoPilotPlugin::parametersReadyChanged, this, &MultiVehicleManager::_autopilotParametersReadyChanged);
_vehicles.append(vehicle); _vehicles.append(vehicle);
...@@ -92,22 +85,20 @@ bool MultiVehicleManager::notifyHeartbeatInfo(LinkInterface* link, int vehicleId ...@@ -92,22 +85,20 @@ bool MultiVehicleManager::notifyHeartbeatInfo(LinkInterface* link, int vehicleId
setActiveVehicle(vehicle); setActiveVehicle(vehicle);
} }
return true;
} }
/// This slot is connected to the Vehicle::allLinksDestroyed signal such that the Vehicle is deleted /// This slot is connected to the Vehicle::allLinksDestroyed signal such that the Vehicle is deleted
/// and all other right things happen when the Vehicle goes away. /// and all other right things happen when the Vehicle goes away.
void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle) void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle)
{ {
qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase1"; qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase1" << vehicle;
_vehicleBeingDeleted = vehicle; _vehiclesBeingDeleted << vehicle;
// Remove from map // Remove from map
bool found = false; bool found = false;
for (int i=0; i<_vehicles.count(); i++) { for (int i=0; i<_vehicles.count(); i++) {
if (_vehicles[i] == _vehicleBeingDeleted) { if (_vehicles[i] == vehicle) {
_vehicles.removeAt(i); _vehicles.removeAt(i);
found = true; found = true;
break; break;
...@@ -136,9 +127,9 @@ void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle) ...@@ -136,9 +127,9 @@ void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle)
QTimer::singleShot(20, this, &MultiVehicleManager::_deleteVehiclePhase2); QTimer::singleShot(20, this, &MultiVehicleManager::_deleteVehiclePhase2);
} }
void MultiVehicleManager::_deleteVehiclePhase2 (void) void MultiVehicleManager::_deleteVehiclePhase2(void)
{ {
qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase2"; qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase2" << _vehiclesBeingDeleted[0];
/// Qml has been notified of vehicle about to go away and should be disconnected from it by now. /// Qml has been notified of vehicle about to go away and should be disconnected from it by now.
/// This means we can now clear the active vehicle property and delete the Vehicle for real. /// This means we can now clear the active vehicle property and delete the Vehicle for real.
...@@ -159,7 +150,8 @@ void MultiVehicleManager::_deleteVehiclePhase2 (void) ...@@ -159,7 +150,8 @@ void MultiVehicleManager::_deleteVehiclePhase2 (void)
} }
} }
_vehicleBeingDeleted->deleteLater(); delete _vehiclesBeingDeleted[0];
_vehiclesBeingDeleted.removeAt(0);
} }
void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle) void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle)
...@@ -189,7 +181,7 @@ void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle) ...@@ -189,7 +181,7 @@ void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle)
void MultiVehicleManager::_setActiveVehiclePhase2(void) void MultiVehicleManager::_setActiveVehiclePhase2(void)
{ {
qCDebug(MultiVehicleManagerLog) << "_setActiveVehiclePhase2"; qCDebug(MultiVehicleManagerLog) << "_setActiveVehiclePhase2 _vehicleBeingSetActive" << _vehicleBeingSetActive;
// Now we signal the new active vehicle // Now we signal the new active vehicle
_activeVehicle = _vehicleBeingSetActive; _activeVehicle = _vehicleBeingSetActive;
......
...@@ -58,14 +58,6 @@ public: ...@@ -58,14 +58,6 @@ public:
// Methods // Methods
/// Called to notify that a heartbeat was received with the specified information. MultiVehicleManager
/// will create/update Vehicles as necessary.
/// @param link Heartbeat came through on this link
/// @param vehicleId Mavlink system id for vehicle
/// @param heartbeat Mavlink heartbeat message
/// @return true: continue further processing of this message, false: disregard this message
bool notifyHeartbeatInfo(LinkInterface* link, int vehicleId, mavlink_heartbeat_t& heartbeat);
Q_INVOKABLE Vehicle* getVehicleById(int vehicleId); Q_INVOKABLE Vehicle* getVehicleById(int vehicleId);
UAS* activeUas(void) { return _activeVehicle ? _activeVehicle->uas() : NULL; } UAS* activeUas(void) { return _activeVehicle ? _activeVehicle->uas() : NULL; }
...@@ -98,6 +90,7 @@ private slots: ...@@ -98,6 +90,7 @@ private slots:
void _deleteVehiclePhase2(void); void _deleteVehiclePhase2(void);
void _setActiveVehiclePhase2(void); void _setActiveVehiclePhase2(void);
void _autopilotParametersReadyChanged(bool parametersReady); void _autopilotParametersReadyChanged(bool parametersReady);
void _linkActive(LinkInterface* link, int vehicleId, int vehicleFirmwareType, int vehicleType);
private: private:
bool _vehicleExists(int vehicleId); bool _vehicleExists(int vehicleId);
...@@ -106,8 +99,8 @@ private: ...@@ -106,8 +99,8 @@ private:
bool _parameterReadyVehicleAvailable; ///< true: An active vehicle with ready parameters is available bool _parameterReadyVehicleAvailable; ///< true: An active vehicle with ready parameters is available
Vehicle* _activeVehicle; ///< Currently active vehicle from a ui perspective Vehicle* _activeVehicle; ///< Currently active vehicle from a ui perspective
Vehicle* _vehicleBeingDeleted; ///< Vehicle being deleted in queued phases QList<Vehicle*> _vehiclesBeingDeleted; ///< List of Vehicles being deleted in queued phases
Vehicle* _vehicleBeingSetActive; ///< Vehicle being set active in queued phases Vehicle* _vehicleBeingSetActive; ///< Vehicle being set active in queued phases
QList<int> _ignoreVehicleIds; ///< List of vehicle id for which we ignore further communication QList<int> _ignoreVehicleIds; ///< List of vehicle id for which we ignore further communication
......
...@@ -94,6 +94,8 @@ Vehicle::Vehicle(LinkInterface* link, ...@@ -94,6 +94,8 @@ Vehicle::Vehicle(LinkInterface* link,
, _satelliteCount(-1) , _satelliteCount(-1)
, _satelliteLock(0) , _satelliteLock(0)
, _updateCount(0) , _updateCount(0)
, _rcRSSI(0)
, _rcRSSIstore(100.0)
, _missionManager(NULL) , _missionManager(NULL)
, _missionManagerInitialRequestComplete(false) , _missionManagerInitialRequestComplete(false)
, _parameterLoader(NULL) , _parameterLoader(NULL)
...@@ -106,6 +108,7 @@ Vehicle::Vehicle(LinkInterface* link, ...@@ -106,6 +108,7 @@ Vehicle::Vehicle(LinkInterface* link,
, _autopilotPluginManager(autopilotPluginManager) , _autopilotPluginManager(autopilotPluginManager)
, _joystickManager(joystickManager) , _joystickManager(joystickManager)
, _flowImageIndex(0) , _flowImageIndex(0)
, _allLinksInactiveSent(false)
{ {
_addLink(link); _addLink(link);
...@@ -119,9 +122,10 @@ Vehicle::Vehicle(LinkInterface* link, ...@@ -119,9 +122,10 @@ Vehicle::Vehicle(LinkInterface* link,
setLatitude(_uas->getLatitude()); setLatitude(_uas->getLatitude());
setLongitude(_uas->getLongitude()); setLongitude(_uas->getLongitude());
connect(_uas, &UAS::latitudeChanged, this, &Vehicle::setLatitude); connect(_uas, &UAS::latitudeChanged, this, &Vehicle::setLatitude);
connect(_uas, &UAS::longitudeChanged, this, &Vehicle::setLongitude); connect(_uas, &UAS::longitudeChanged, this, &Vehicle::setLongitude);
connect(_uas, &UAS::imageReady, this, &Vehicle::_imageReady); connect(_uas, &UAS::imageReady, this, &Vehicle::_imageReady);
connect(_uas, &UAS::remoteControlRSSIChanged, this, &Vehicle::_remoteControlRSSIChanged);
_firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType); _firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType);
_autopilotPlugin = _autopilotPluginManager->newAutopilotPluginForVehicle(this); _autopilotPlugin = _autopilotPluginManager->newAutopilotPluginForVehicle(this);
...@@ -186,6 +190,8 @@ Vehicle::Vehicle(LinkInterface* link, ...@@ -186,6 +190,8 @@ Vehicle::Vehicle(LinkInterface* link,
Vehicle::~Vehicle() Vehicle::~Vehicle()
{ {
qCDebug(VehicleLog) << "~Vehicle" << this;
delete _missionManager; delete _missionManager;
_missionManager = NULL; _missionManager = NULL;
...@@ -285,38 +291,29 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message) ...@@ -285,38 +291,29 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message)
bool Vehicle::_containsLink(LinkInterface* link) bool Vehicle::_containsLink(LinkInterface* link)
{ {
foreach (SharedLinkInterface sharedLink, _links) { return _links.contains(link);
if (sharedLink.data() == link) {
return true;
}
}
return false;
} }
void Vehicle::_addLink(LinkInterface* link) void Vehicle::_addLink(LinkInterface* link)
{ {
if (!_containsLink(link)) { if (!_containsLink(link)) {
_links += qgcApp()->toolbox()->linkManager()->sharedPointerForLink(link); _links += link;
qCDebug(VehicleLog) << "_addLink:" << QString("%1").arg((ulong)link, 0, 16); qCDebug(VehicleLog) << "_addLink:" << QString("%1").arg((ulong)link, 0, 16);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDisconnected, this, &Vehicle::_linkDisconnected); connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkInactive, this, &Vehicle::_linkInactiveOrDeleted);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDeleted, this, &Vehicle::_linkInactiveOrDeleted);
} }
} }
void Vehicle::_linkDisconnected(LinkInterface* link) void Vehicle::_linkInactiveOrDeleted(LinkInterface* link)
{ {
qCDebug(VehicleLog) << "_linkDisconnected:" << link->getName(); qCDebug(VehicleLog) << "_linkInactiveOrDeleted linkCount" << _links.count();
qCDebug(VehicleLog) << "link count:" << _links.count();
for (int i=0; i<_links.count(); i++) { _links.removeOne(link);
if (_links[i].data() == link) {
_links.removeAt(i);
break;
}
}
if (_links.count() == 0) { if (_links.count() == 0 && !_allLinksInactiveSent) {
emit allLinksDisconnected(this); // Make sure to not send this more than one time
_allLinksInactiveSent = true;
emit allLinksInactive(this);
} }
} }
...@@ -328,10 +325,7 @@ void Vehicle::sendMessage(mavlink_message_t message) ...@@ -328,10 +325,7 @@ void Vehicle::sendMessage(mavlink_message_t message)
void Vehicle::_sendMessage(mavlink_message_t message) void Vehicle::_sendMessage(mavlink_message_t message)
{ {
// Emit message on all links that are currently connected // Emit message on all links that are currently connected
foreach (SharedLinkInterface sharedLink, _links) { foreach (LinkInterface* link, _links) {
LinkInterface* link = sharedLink.data();
Q_ASSERT(link);
if (link->isConnected()) { if (link->isConnected()) {
MAVLinkProtocol* mavlink = _mavlink; MAVLinkProtocol* mavlink = _mavlink;
...@@ -350,17 +344,6 @@ void Vehicle::_sendMessage(mavlink_message_t message) ...@@ -350,17 +344,6 @@ void Vehicle::_sendMessage(mavlink_message_t message)
} }
} }
QList<LinkInterface*> Vehicle::links(void)
{
QList<LinkInterface*> list;
foreach (SharedLinkInterface sharedLink, _links) {
list += sharedLink.data();
}
return list;
}
void Vehicle::setLatitude(double latitude) void Vehicle::setLatitude(double latitude)
{ {
_coordinate.setLatitude(latitude); _coordinate.setLatitude(latitude);
...@@ -1035,11 +1018,11 @@ void Vehicle::_parametersReady(bool parametersReady) ...@@ -1035,11 +1018,11 @@ void Vehicle::_parametersReady(bool parametersReady)
void Vehicle::_communicationInactivityTimedOut(void) void Vehicle::_communicationInactivityTimedOut(void)
{ {
// Vechile is no longer communicating with us, disconnect all links // Vehicle is no longer communicating with us, disconnect all links inactive
LinkManager* linkMgr = qgcApp()->toolbox()->linkManager(); LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();
for (int i=0; i<_links.count(); i++) { for (int i=0; i<_links.count(); i++) {
linkMgr->disconnectLink(_links[i].data()); linkMgr->disconnectLink(_links[i], false /* disconnectAutoconnectLink */);
} }
} }
...@@ -1058,3 +1041,17 @@ void Vehicle::_imageReady(UASInterface*) ...@@ -1058,3 +1041,17 @@ void Vehicle::_imageReady(UASInterface*)
emit flowImageIndexChanged(); emit flowImageIndexChanged();
} }
} }
void Vehicle::_remoteControlRSSIChanged(uint8_t rssi)
{
// Low pass to git rid of jitter
_rcRSSIstore = (_rcRSSIstore * 0.9f) + ((float)rssi * 0.1);
uint8_t filteredRSSI = (uint8_t)ceil(_rcRSSIstore);
if(_rcRSSIstore < 0.1) {
filteredRSSI = 0;
}
if(_rcRSSI != filteredRSSI) {
_rcRSSI = filteredRSSI;
emit rcRSSIChanged(_rcRSSI);
}
}
...@@ -107,6 +107,7 @@ public: ...@@ -107,6 +107,7 @@ public:
Q_PROPERTY(bool joystickEnabled READ joystickEnabled WRITE setJoystickEnabled NOTIFY joystickEnabledChanged) Q_PROPERTY(bool joystickEnabled READ joystickEnabled WRITE setJoystickEnabled NOTIFY joystickEnabledChanged)
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(int flowImageIndex READ flowImageIndex NOTIFY flowImageIndexChanged) Q_PROPERTY(int flowImageIndex READ flowImageIndex NOTIFY flowImageIndexChanged)
Q_PROPERTY(int rcRSSI READ rcRSSI NOTIFY rcRSSIChanged)
/// Returns the number of buttons which are reserved for firmware use in the MANUAL_CONTROL mavlink /// Returns the number of buttons which are reserved for firmware use in the MANUAL_CONTROL mavlink
/// message. For example PX4 Flight Stack reserves the first 8 buttons to simulate rc switches. /// message. For example PX4 Flight Stack reserves the first 8 buttons to simulate rc switches.
...@@ -166,8 +167,6 @@ public: ...@@ -166,8 +167,6 @@ public:
/// Provides access to the Firmware Plugin for this Vehicle /// Provides access to the Firmware Plugin for this Vehicle
FirmwarePlugin* firmwarePlugin(void) { return _firmwarePlugin; } FirmwarePlugin* firmwarePlugin(void) { return _firmwarePlugin; }
QList<LinkInterface*> links(void);
int manualControlReservedButtonCount(void); int manualControlReservedButtonCount(void);
MissionManager* missionManager(void) { return _missionManager; } MissionManager* missionManager(void) { return _missionManager; }
...@@ -245,6 +244,7 @@ public: ...@@ -245,6 +244,7 @@ public:
QString currentState () { return _currentState; } QString currentState () { return _currentState; }
int satelliteLock () { return _satelliteLock; } int satelliteLock () { return _satelliteLock; }
unsigned int heartbeatTimeout () { return _currentHeartbeatTimeout; } unsigned int heartbeatTimeout () { return _currentHeartbeatTimeout; }
int rcRSSI () { return _rcRSSI; }
ParameterLoader* getParameterLoader(void); ParameterLoader* getParameterLoader(void);
...@@ -253,7 +253,7 @@ public slots: ...@@ -253,7 +253,7 @@ public slots:
void setLongitude(double longitude); void setLongitude(double longitude);
signals: signals:
void allLinksDisconnected(Vehicle* vehicle); void allLinksInactive(Vehicle* vehicle);
void coordinateChanged(QGeoCoordinate coordinate); void coordinateChanged(QGeoCoordinate coordinate);
void coordinateValidChanged(bool coordinateValid); void coordinateValidChanged(bool coordinateValid);
void joystickModeChanged(int mode); void joystickModeChanged(int mode);
...@@ -293,15 +293,17 @@ signals: ...@@ -293,15 +293,17 @@ signals:
void currentStateChanged (); void currentStateChanged ();
void satelliteLockChanged (); void satelliteLockChanged ();
void flowImageIndexChanged (); void flowImageIndexChanged ();
void rcRSSIChanged (int rcRSSI);
private slots: private slots:
void _mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message); void _mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message);
void _linkDisconnected(LinkInterface* link); void _linkInactiveOrDeleted(LinkInterface* link);
void _sendMessage(mavlink_message_t message); void _sendMessage(mavlink_message_t message);
void _sendMessageMultipleNext(void); void _sendMessageMultipleNext(void);
void _addNewMapTrajectoryPoint(void); void _addNewMapTrajectoryPoint(void);
void _parametersReady(bool parametersReady); void _parametersReady(bool parametersReady);
void _communicationInactivityTimedOut(void); void _communicationInactivityTimedOut(void);
void _remoteControlRSSIChanged(uint8_t rssi);
void _handleTextMessage (int newCount); void _handleTextMessage (int newCount);
/** @brief Attitude from main autopilot / system state */ /** @brief Attitude from main autopilot / system state */
...@@ -347,10 +349,7 @@ private: ...@@ -347,10 +349,7 @@ private:
AutoPilotPlugin* _autopilotPlugin; AutoPilotPlugin* _autopilotPlugin;
MAVLinkProtocol* _mavlink; MAVLinkProtocol* _mavlink;
/// List of all links associated with this vehicle. We keep SharedLinkInterface objects QList<LinkInterface*> _links;
/// which are QSharedPointer's in order to maintain reference counts across threads.
/// This way Link deletion works correctly.
QList<SharedLinkInterface> _links;
JoystickMode_t _joystickMode; JoystickMode_t _joystickMode;
bool _joystickEnabled; bool _joystickEnabled;
...@@ -394,6 +393,8 @@ private: ...@@ -394,6 +393,8 @@ private:
int _satelliteCount; int _satelliteCount;
int _satelliteLock; int _satelliteLock;
int _updateCount; int _updateCount;
int _rcRSSI;
double _rcRSSIstore;
MissionManager* _missionManager; MissionManager* _missionManager;
bool _missionManagerInitialRequestComplete; bool _missionManagerInitialRequestComplete;
...@@ -434,6 +435,8 @@ private: ...@@ -434,6 +435,8 @@ private:
int _flowImageIndex; int _flowImageIndex;
bool _allLinksInactiveSent; ///< true: allLinkInactive signal already sent one time
// Settings keys // Settings keys
static const char* _settingsGroup; static const char* _settingsGroup;
static const char* _joystickModeSettingsKey; static const char* _joystickModeSettingsKey;
......
...@@ -26,12 +26,13 @@ import QtQuick.Controls 1.2 ...@@ -26,12 +26,13 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QGroundControl.Controls 1.0 import QGroundControl 1.0
import QGroundControl.FactSystem 1.0 import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Controllers 1.0 import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0 import QGroundControl.Controllers 1.0
import QGroundControl.ScreenTools 1.0
QGCView { QGCView {
id: qgcView id: qgcView
...@@ -88,7 +89,7 @@ QGCView { ...@@ -88,7 +89,7 @@ QGCView {
onBoardFound: { onBoardFound: {
if (initialBoardSearch) { if (initialBoardSearch) {
// Board was found right away, so something is already plugged in before we've started upgrade // Board was found right away, so something is already plugged in before we've started upgrade
if (controller.qgcConnections) { if (QGroundControl.linkManager.anyActiveLinks) {
statusTextArea.append(qgcDisconnectText) statusTextArea.append(qgcDisconnectText)
} else { } else {
statusTextArea.append(usbUnplugText.replace('{0}', controller.boardType)) statusTextArea.append(usbUnplugText.replace('{0}', controller.boardType))
......
...@@ -68,13 +68,17 @@ FirmwareUpgradeController::FirmwareUpgradeController(void) : ...@@ -68,13 +68,17 @@ FirmwareUpgradeController::FirmwareUpgradeController(void) :
connect(_threadController, &PX4FirmwareUpgradeThreadController::flashComplete, this, &FirmwareUpgradeController::_flashComplete); connect(_threadController, &PX4FirmwareUpgradeThreadController::flashComplete, this, &FirmwareUpgradeController::_flashComplete);
connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &FirmwareUpgradeController::_updateProgress); connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &FirmwareUpgradeController::_updateProgress);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDisconnected, this, &FirmwareUpgradeController::_linkDisconnected);
connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick); connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick);
} }
FirmwareUpgradeController::~FirmwareUpgradeController()
{
qgcApp()->toolbox()->linkManager()->setConnectionsAllowed();
}
void FirmwareUpgradeController::startBoardSearch(void) void FirmwareUpgradeController::startBoardSearch(void)
{ {
qgcApp()->toolbox()->linkManager()->setConnectionsSuspended(tr("Connect not allowed during Firmware Upgrade."));
_bootloaderFound = false; _bootloaderFound = false;
_startFlashWhenBootloaderFound = false; _startFlashWhenBootloaderFound = false;
_threadController->startFindBoardLoop(); _threadController->startFindBoardLoop();
...@@ -556,17 +560,6 @@ void FirmwareUpgradeController::_appendStatusLog(const QString& text, bool criti ...@@ -556,17 +560,6 @@ void FirmwareUpgradeController::_appendStatusLog(const QString& text, bool criti
Q_ARG(QVariant, varText)); Q_ARG(QVariant, varText));
} }
bool FirmwareUpgradeController::qgcConnections(void)
{
return qgcApp()->toolbox()->linkManager()->anyConnectedLinks();
}
void FirmwareUpgradeController::_linkDisconnected(LinkInterface* link)
{
Q_UNUSED(link);
emit qgcConnectionsChanged(qgcConnections());
}
void FirmwareUpgradeController::_errorCancel(const QString& msg) void FirmwareUpgradeController::_errorCancel(const QString& msg)
{ {
_appendStatusLog(msg, false); _appendStatusLog(msg, false);
......
...@@ -104,7 +104,8 @@ public: ...@@ -104,7 +104,8 @@ public:
}; };
FirmwareUpgradeController(void); FirmwareUpgradeController(void);
~FirmwareUpgradeController();
Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound) Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound)
Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound) Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound)
Q_PROPERTY(QString boardType MEMBER _foundBoardType NOTIFY boardFound) Q_PROPERTY(QString boardType MEMBER _foundBoardType NOTIFY boardFound)
...@@ -115,9 +116,6 @@ public: ...@@ -115,9 +116,6 @@ public:
/// Progress bar for you know what /// Progress bar for you know what
Q_PROPERTY(QQuickItem* progressBar READ progressBar WRITE setProgressBar) Q_PROPERTY(QQuickItem* progressBar READ progressBar WRITE setProgressBar)
/// Returns true if there are active QGC connections
Q_PROPERTY(bool qgcConnections READ qgcConnections NOTIFY qgcConnectionsChanged)
/// Starts searching for boards on the background thread /// Starts searching for boards on the background thread
Q_INVOKABLE void startBoardSearch(void); Q_INVOKABLE void startBoardSearch(void);
...@@ -140,8 +138,6 @@ public: ...@@ -140,8 +138,6 @@ public:
QQuickItem* statusLog(void) { return _statusLog; } QQuickItem* statusLog(void) { return _statusLog; }
void setStatusLog(QQuickItem* statusLog) { _statusLog = statusLog; } void setStatusLog(QQuickItem* statusLog) { _statusLog = statusLog; }
bool qgcConnections(void);
QString boardPort(void) { return _foundBoardInfo.portName(); } QString boardPort(void) { return _foundBoardInfo.portName(); }
QString boardDescription(void) { return _foundBoardInfo.description(); } QString boardDescription(void) { return _foundBoardInfo.description(); }
...@@ -151,7 +147,6 @@ signals: ...@@ -151,7 +147,6 @@ signals:
void boardGone(void); void boardGone(void);
void flashComplete(void); void flashComplete(void);
void flashCancelled(void); void flashCancelled(void);
void qgcConnectionsChanged(bool connections);
void error(void); void error(void);
private slots: private slots:
...@@ -170,7 +165,6 @@ private slots: ...@@ -170,7 +165,6 @@ private slots:
void _eraseStarted(void); void _eraseStarted(void);
void _eraseComplete(void); void _eraseComplete(void);
void _eraseProgressTick(void); void _eraseProgressTick(void);
void _linkDisconnected(LinkInterface* link);
private: private:
void _getFirmwareFile(FirmwareIdentifier firmwareId); void _getFirmwareFile(FirmwareIdentifier firmwareId);
......
...@@ -42,19 +42,20 @@ This file is part of the QGROUNDCONTROL project ...@@ -42,19 +42,20 @@ This file is part of the QGROUNDCONTROL project
#define LINK_SETTING_ROOT "LinkConfigurations" #define LINK_SETTING_ROOT "LinkConfigurations"
LinkConfiguration::LinkConfiguration(const QString& name) LinkConfiguration::LinkConfiguration(const QString& name)
: _preferred(false) : _link(NULL)
, _name(name)
, _dynamic(false) , _dynamic(false)
{ {
_link = NULL;
_name = name; _name = name;
Q_ASSERT(!_name.isEmpty()); if (_name.isEmpty()) {
qWarning() << "Internal error";
}
} }
LinkConfiguration::LinkConfiguration(LinkConfiguration* copy) LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
{ {
_link = copy->getLink(); _link = copy->link();
_name = copy->name(); _name = copy->name();
_preferred = copy->isPreferred();
_dynamic = copy->isDynamic(); _dynamic = copy->isDynamic();
Q_ASSERT(!_name.isEmpty()); Q_ASSERT(!_name.isEmpty());
} }
...@@ -62,9 +63,8 @@ LinkConfiguration::LinkConfiguration(LinkConfiguration* copy) ...@@ -62,9 +63,8 @@ LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
void LinkConfiguration::copyFrom(LinkConfiguration* source) void LinkConfiguration::copyFrom(LinkConfiguration* source)
{ {
Q_ASSERT(source != NULL); Q_ASSERT(source != NULL);
_link = source->getLink(); _link = source->link();
_name = source->name(); _name = source->name();
_preferred = source->isPreferred();
_dynamic = source->isDynamic(); _dynamic = source->isDynamic();
} }
...@@ -138,3 +138,15 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc ...@@ -138,3 +138,15 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc
} }
return dupe; return dupe;
} }
void LinkConfiguration::setName(const QString name)
{
_name = name;
emit nameChanged(name);
}
void LinkConfiguration::setLink(LinkInterface* link)
{
_link = link;
emit linkChanged(link);
}
...@@ -30,13 +30,26 @@ class LinkInterface; ...@@ -30,13 +30,26 @@ class LinkInterface;
/// Interface holding link specific settings. /// Interface holding link specific settings.
class LinkConfiguration class LinkConfiguration : public QObject
{ {
Q_OBJECT
public: public:
LinkConfiguration(const QString& name); LinkConfiguration(const QString& name);
LinkConfiguration(LinkConfiguration* copy); LinkConfiguration(LinkConfiguration* copy);
virtual ~LinkConfiguration() {} virtual ~LinkConfiguration() {}
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(LinkInterface* link READ link WRITE setLink NOTIFY linkChanged)
// Property accessors
const QString name(void) { return _name; }
LinkInterface* link(void) { return _link; }
void setName(const QString name);
void setLink(LinkInterface* link);
/// The link types supported by QGC /// The link types supported by QGC
enum { enum {
#ifndef __ios__ #ifndef __ios__
...@@ -55,48 +68,6 @@ public: ...@@ -55,48 +68,6 @@ public:
TypeLast // Last type value (type >= TypeLast == invalid) TypeLast // Last type value (type >= TypeLast == invalid)
}; };
/*!
* @brief Get configuration name
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @return The name of this link.
*/
const QString name() { return _name; }
/*!
* @brief Set the name of this link configuration.
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @param[in] name The configuration name
*/
void setName(const QString name) {_name = name; }
/*!
* @brief Set the link this configuration is currently attched to.
*
* @param[in] link The pointer to the current LinkInterface instance (if any)
*/
void setLink(LinkInterface* link) { _link = link; }
/*!
* @brief Get the link this configuration is currently attched to.
*
* @return The pointer to the current LinkInterface instance (if any)
*/
LinkInterface* getLink() { return _link; }
/*!
*
* Is this a preferred configuration? (decided at runtime)
* @return True if this is a known configuration (PX4, etc.)
*/
bool isPreferred() { return _preferred; }
/*!
* Set if this is this a preferred configuration. (decided at runtime)
*/
void setPreferred(bool preferred = true) { _preferred = preferred; }
/*! /*!
* *
* Is this a dynamic configuration? (non persistent) * Is this a dynamic configuration? (non persistent)
...@@ -178,11 +149,14 @@ public: ...@@ -178,11 +149,14 @@ public:
*/ */
static LinkConfiguration* duplicateSettings(LinkConfiguration *source); static LinkConfiguration* duplicateSettings(LinkConfiguration *source);
signals:
void nameChanged(const QString& name);
void linkChanged(LinkInterface* link);
protected: protected:
LinkInterface* _link; ///< Link currently using this configuration (if any) LinkInterface* _link; ///< Link currently using this configuration (if any)
private: private:
QString _name; QString _name;
bool _preferred; ///< Determined internally if this is a preferred connection. It comes up first in the drop down box.
bool _dynamic; ///< A connection added automatically and not persistent (unless it's edited). bool _dynamic; ///< A connection added automatically and not persistent (unless it's edited).
}; };
......
...@@ -57,6 +57,15 @@ class LinkInterface : public QThread ...@@ -57,6 +57,15 @@ class LinkInterface : public QThread
friend class LinkManager; friend class LinkManager;
public: public:
Q_PROPERTY(bool autoconnect READ autoconnect WRITE setAutoconnect NOTIFY autoconnectChanged)
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
// Property accessors
bool autoconnect(void) { return _autoconnect; }
void setAutoconnect(bool autoconnect) { _autoconnect = autoconnect; emit autoconnectChanged(autoconnect); }
bool active(void) { return _active; }
void setActive(bool active) { _active = active; emit activeChanged(active); }
/** /**
* @brief Get link configuration (if used) * @brief Get link configuration (if used)
* @return A pointer to the instance of LinkConfiguration if supported. NULL otherwise. * @return A pointer to the instance of LinkConfiguration if supported. NULL otherwise.
...@@ -128,6 +137,7 @@ public: ...@@ -128,6 +137,7 @@ public:
/// @return true: "sh /etc/init.d/rc.usb" must be sent on link to start mavlink /// @return true: "sh /etc/init.d/rc.usb" must be sent on link to start mavlink
virtual bool requiresUSBMavlinkStart(void) const { return false; } virtual bool requiresUSBMavlinkStart(void) const { return false; }
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of // 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. // connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void); bool connect(void);
...@@ -148,6 +158,8 @@ public slots: ...@@ -148,6 +158,8 @@ public slots:
virtual void writeBytes(const char *bytes, qint64 length) = 0; virtual void writeBytes(const char *bytes, qint64 length) = 0;
signals: signals:
void autoconnectChanged(bool autoconnect);
void activeChanged(bool active);
/** /**
* @brief New data arrived * @brief New data arrived
...@@ -184,8 +196,10 @@ signals: ...@@ -184,8 +196,10 @@ signals:
protected: protected:
// Links are only created by LinkManager so constructor is not public // Links are only created by LinkManager so constructor is not public
LinkInterface() : LinkInterface() :
QThread(0), QThread(0)
_mavlinkChannelSet(false) , _mavlinkChannelSet(false)
, _autoconnect(false)
, _active(false)
{ {
// Initialize everything for the data rate calculation buffers. // Initialize everything for the data rate calculation buffers.
_inDataIndex = 0; _inDataIndex = 0;
...@@ -321,12 +335,7 @@ private: ...@@ -321,12 +335,7 @@ private:
**/ **/
virtual bool _connect(void) = 0; virtual bool _connect(void) = 0;
/** virtual void _disconnect(void) = 0;
* @brief Disconnect this interface logically
*
* @return True if connection could be terminated, false otherwise
**/
virtual bool _disconnect(void) = 0;
/// Sets the mavlink channel to use for this link /// Sets the mavlink channel to use for this link
void _setMavlinkChannel(uint8_t channel) { Q_ASSERT(!_mavlinkChannelSet); _mavlinkChannelSet = true; _mavlinkChannel = channel; } void _setMavlinkChannel(uint8_t channel) { Q_ASSERT(!_mavlinkChannelSet); _mavlinkChannelSet = true; _mavlinkChannel = channel; }
...@@ -351,6 +360,9 @@ private: ...@@ -351,6 +360,9 @@ private:
qint64 _outDataWriteTimes[_dataRateBufferSize]; // in ms qint64 _outDataWriteTimes[_dataRateBufferSize]; // in ms
mutable QMutex _dataRateMutex; // Mutex for accessing the data rate member variables mutable QMutex _dataRateMutex; // Mutex for accessing the data rate member variables
bool _autoconnect; ///< true: Link is an autoconnect connection and should never be disconnected
bool _active; ///< true: link is actively receiving mavlink messages
}; };
typedef QSharedPointer<LinkInterface> SharedLinkInterface; typedef QSharedPointer<LinkInterface> SharedLinkInterface;
......
...@@ -42,8 +42,17 @@ This file is part of the QGROUNDCONTROL project ...@@ -42,8 +42,17 @@ This file is part of the QGROUNDCONTROL project
#include "QGCMessageBox.h" #include "QGCMessageBox.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "UDPLink.h"
#include "TCPLink.h"
QGC_LOGGING_CATEGORY(LinkManagerLog, "LinkManagerLog") QGC_LOGGING_CATEGORY(LinkManagerLog, "LinkManagerLog")
QGC_LOGGING_CATEGORY(LinkManagerVerboseLog, "LinkManagerVerboseLog")
const char* LinkManager::_settingsGroup = "LinkManager";
const char* LinkManager::_autoconnectUDPKey = "AutoconnectUDP";
const char* LinkManager::_autoconnectPixhawkKey = "AutoconnectPixhawk";
const char* LinkManager::_autoconnect3DRRadioKey = "Autoconnect3DRRadio";
const char* LinkManager::_autoconnectPX4FlowKey = "AutoconnectPX4Flow";
LinkManager::LinkManager(QGCApplication* app) LinkManager::LinkManager(QGCApplication* app)
: QGCTool(app) : QGCTool(app)
...@@ -51,21 +60,32 @@ LinkManager::LinkManager(QGCApplication* app) ...@@ -51,21 +60,32 @@ LinkManager::LinkManager(QGCApplication* app)
, _configurationsLoaded(false) , _configurationsLoaded(false)
, _connectionsSuspended(false) , _connectionsSuspended(false)
, _mavlinkChannelsUsedBitMask(0) , _mavlinkChannelsUsedBitMask(0)
, _nullSharedLink(NULL)
, _mavlinkProtocol(NULL) , _mavlinkProtocol(NULL)
, _autoconnectUDPConfig(NULL)
, _autoconnectUDP(true)
, _autoconnectPixhawk(true)
, _autoconnect3DRRadio(true)
, _autoconnectPX4Flow(true)
{ {
qmlRegisterUncreatableType<LinkManager> ("QGroundControl", 1, 0, "LinkManager", "Reference only");
qmlRegisterUncreatableType<LinkConfiguration> ("QGroundControl", 1, 0, "LinkConfiguration", "Reference only");
qmlRegisterUncreatableType<LinkInterface> ("QGroundControl", 1, 0, "LinkInterface", "Reference only");
QSettings settings;
settings.beginGroup(_settingsGroup);
_autoconnectUDP = settings.value(_autoconnectUDPKey, true).toBool();
_autoconnectPixhawk = settings.value(_autoconnectPixhawkKey, true).toBool();
_autoconnect3DRRadio = settings.value(_autoconnect3DRRadioKey, true).toBool();
_autoconnectPX4Flow = settings.value(_autoconnectPX4FlowKey, true).toBool();
} }
LinkManager::~LinkManager() LinkManager::~LinkManager()
{ {
// Clear configuration list if (anyActiveLinks()) {
while(_linkConfigurations.count()) { qWarning() << "Why are there still active links?";
LinkConfiguration* pLink = _linkConfigurations.at(0);
if(pLink) delete pLink;
_linkConfigurations.removeAt(0);
} }
Q_ASSERT_X(_links.count() == 0, "LinkManager", "LinkManager::_shutdown should have been called previously");
} }
void LinkManager::setToolbox(QGCToolbox *toolbox) void LinkManager::setToolbox(QGCToolbox *toolbox)
...@@ -73,14 +93,15 @@ void LinkManager::setToolbox(QGCToolbox *toolbox) ...@@ -73,14 +93,15 @@ void LinkManager::setToolbox(QGCToolbox *toolbox)
QGCTool::setToolbox(toolbox); QGCTool::setToolbox(toolbox);
_mavlinkProtocol = _toolbox->mavlinkProtocol(); _mavlinkProtocol = _toolbox->mavlinkProtocol();
connect(_mavlinkProtocol, &MAVLinkProtocol::vehicleHeartbeatInfo, this, &LinkManager::_vehicleHeartbeatInfo);
#ifndef __ios__ #ifndef __ios__
connect(&_portListTimer, &QTimer::timeout, this, &LinkManager::_updateConfigurationList); connect(&_portListTimer, &QTimer::timeout, this, &LinkManager::_updateAutoConnectLinks);
_portListTimer.start(1000); _portListTimer.start(1000);
#endif #endif
} }
LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config) LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config, bool autoconnectLink)
{ {
Q_ASSERT(config); Q_ASSERT(config);
LinkInterface* pLink = NULL; LinkInterface* pLink = NULL;
...@@ -106,30 +127,36 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config) ...@@ -106,30 +127,36 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
#endif #endif
} }
if(pLink) { if(pLink) {
pLink->setAutoconnect(autoconnectLink);
_addLink(pLink); _addLink(pLink);
connectLink(pLink); connectLink(pLink);
} }
return pLink; return pLink;
} }
LinkInterface* LinkManager::createConnectedLink(const QString& name) LinkInterface* LinkManager::createConnectedLink(const QString& name, bool autoconnectLink)
{ {
Q_ASSERT(name.isEmpty() == false); Q_ASSERT(name.isEmpty() == false);
for(int i = 0; i < _linkConfigurations.count(); i++) { for(int i = 0; i < _linkConfigurations.count(); i++) {
LinkConfiguration* conf = _linkConfigurations.at(i); LinkConfiguration* conf = _linkConfigurations.value<LinkConfiguration*>(i);
if(conf && conf->name() == name) if(conf && conf->name() == name)
return createConnectedLink(conf); return createConnectedLink(conf, autoconnectLink);
} }
return NULL; return NULL;
} }
void LinkManager::_addLink(LinkInterface* link) void LinkManager::_addLink(LinkInterface* link)
{ {
Q_ASSERT(link); if (thread() != QThread::currentThread()) {
qWarning() << "_deleteLink called from incorrect thread";
return;
}
_linkListMutex.lock(); if (!link) {
return;
}
if (!containsLink(link)) { if (!_links.contains(link)) {
// Find a mavlink channel to use for this link // Find a mavlink channel to use for this link
for (int i=0; i<32; i++) { for (int i=0; i<32; i++) {
if (!(_mavlinkChannelsUsedBitMask && 1 << i)) { if (!(_mavlinkChannelsUsedBitMask && 1 << i)) {
...@@ -140,11 +167,8 @@ void LinkManager::_addLink(LinkInterface* link) ...@@ -140,11 +167,8 @@ void LinkManager::_addLink(LinkInterface* link)
} }
} }
_links.append(QSharedPointer<LinkInterface>(link)); _links.append(link);
_linkListMutex.unlock();
emit newLink(link); emit newLink(link);
} else {
_linkListMutex.unlock();
} }
// MainWindow may be around when doing things like running unit tests // MainWindow may be around when doing things like running unit tests
...@@ -161,39 +185,12 @@ void LinkManager::_addLink(LinkInterface* link) ...@@ -161,39 +185,12 @@ void LinkManager::_addLink(LinkInterface* link)
connect(link, &LinkInterface::disconnected, this, &LinkManager::_linkDisconnected); connect(link, &LinkInterface::disconnected, this, &LinkManager::_linkDisconnected);
} }
bool LinkManager::connectAll() void LinkManager::disconnectAll(bool disconnectAutoconnectLink)
{ {
if (_connectionsSuspendedMsg()) { // Walk list in reverse order to preserve indices during delete
return false; for (int i=_links.count()-1; i>=0; i--) {
} disconnectLink(_links.value<LinkInterface*>(i), disconnectAutoconnectLink);
bool allConnected = true;
foreach (SharedLinkInterface sharedLink, _links) {
Q_ASSERT(sharedLink.data());
if (!sharedLink.data()->_connect()) {
allConnected = false;
}
} }
return allConnected;
}
bool LinkManager::disconnectAll()
{
bool allDisconnected = true;
// Make a copy so the list is modified out from under us
QList<SharedLinkInterface> links = _links;
foreach (SharedLinkInterface sharedLink, links) {
Q_ASSERT(sharedLink.data());
if (!disconnectLink(sharedLink.data())) {
allDisconnected = false;
}
}
return allDisconnected;
} }
bool LinkManager::connectLink(LinkInterface* link) bool LinkManager::connectLink(LinkInterface* link)
...@@ -204,68 +201,60 @@ bool LinkManager::connectLink(LinkInterface* link) ...@@ -204,68 +201,60 @@ bool LinkManager::connectLink(LinkInterface* link)
return false; return false;
} }
bool previousAnyConnectedLinks = anyConnectedLinks();
bool previousAnyNonAutoconnectConnectedLinks = anyNonAutoconnectConnectedLinks();
if (link->_connect()) { if (link->_connect()) {
if (!previousAnyConnectedLinks) {
emit anyConnectedLinksChanged(true);
}
if (!previousAnyNonAutoconnectConnectedLinks && anyNonAutoconnectConnectedLinks()) {
emit anyNonAutoconnectConnectedLinksChanged(true);
}
return true; return true;
} else { } else {
return false; return false;
} }
} }
bool LinkManager::disconnectLink(LinkInterface* link) bool LinkManager::disconnectLink(LinkInterface* link, bool disconnectAutoconnectLink)
{ {
Q_ASSERT(link); Q_ASSERT(link);
if (link->_disconnect()) {
if (disconnectAutoconnectLink || !link->autoconnect()) {
link->_disconnect();
LinkConfiguration* config = link->getLinkConfiguration(); LinkConfiguration* config = link->getLinkConfiguration();
if(config) { if(config) {
config->setLink(NULL); config->setLink(NULL);
} }
_deleteLink(link); _deleteLink(link);
return true; return true;
} else {
return false;
} }
return false;
} }
void LinkManager::_deleteLink(LinkInterface* link) void LinkManager::_deleteLink(LinkInterface* link)
{ {
Q_ASSERT(link); if (thread() != QThread::currentThread()) {
qWarning() << "_deleteLink called from incorrect thread";
return;
}
if (!link) {
return;
}
_linkListMutex.lock();
// Free up the mavlink channel associated with this link // Free up the mavlink channel associated with this link
_mavlinkChannelsUsedBitMask &= ~(1 << link->getMavlinkChannel()); _mavlinkChannelsUsedBitMask &= ~(1 << link->getMavlinkChannel());
bool found = false; _links.removeOne(link);
for (int i=0; i<_links.count(); i++) { delete link;
if (_links[i].data() == link) {
_links.removeAt(i);
found = true;
break;
}
}
Q_UNUSED(found);
Q_ASSERT(found);
_linkListMutex.unlock();
// Emit removal of link // Emit removal of link
emit linkDeleted(link); emit linkDeleted(link);
} }
/**
*
*/
const QList<LinkInterface*> LinkManager::getLinks()
{
QList<LinkInterface*> list;
foreach (SharedLinkInterface sharedLink, _links) {
list << sharedLink.data();
}
return list;
}
/// @brief If all new connections should be suspended a message is displayed to the user and true /// @brief If all new connections should be suspended a message is displayed to the user and true
/// is returned; /// is returned;
bool LinkManager::_connectionsSuspendedMsg(void) bool LinkManager::_connectionsSuspendedMsg(void)
...@@ -286,13 +275,6 @@ void LinkManager::setConnectionsSuspended(QString reason) ...@@ -286,13 +275,6 @@ void LinkManager::setConnectionsSuspended(QString reason)
Q_ASSERT(!reason.isEmpty()); Q_ASSERT(!reason.isEmpty());
} }
void LinkManager::_shutdown(void)
{
while (_links.count() != 0) {
disconnectLink(_links[0].data());
}
}
void LinkManager::_linkConnected(void) void LinkManager::_linkConnected(void)
{ {
emit linkConnected((LinkInterface*)sender()); emit linkConnected((LinkInterface*)sender());
...@@ -303,33 +285,6 @@ void LinkManager::_linkDisconnected(void) ...@@ -303,33 +285,6 @@ void LinkManager::_linkDisconnected(void)
emit linkDisconnected((LinkInterface*)sender()); emit linkDisconnected((LinkInterface*)sender());
} }
void LinkManager::addLinkConfiguration(LinkConfiguration* link)
{
Q_ASSERT(link != NULL);
//-- If not there already, add it
int idx = _linkConfigurations.indexOf(link);
if(idx < 0)
{
_linkConfigurations.append(link);
}
}
void LinkManager::removeLinkConfiguration(LinkConfiguration *link)
{
Q_ASSERT(link != NULL);
int idx = _linkConfigurations.indexOf(link);
if(idx >= 0)
{
_linkConfigurations.removeAt(idx);
delete link;
}
}
const QList<LinkConfiguration*> LinkManager::getLinkConfigurationList()
{
return _linkConfigurations;
}
void LinkManager::suspendConfigurationUpdates(bool suspend) void LinkManager::suspendConfigurationUpdates(bool suspend)
{ {
_configUpdateSuspended = suspend; _configUpdateSuspended = suspend;
...@@ -339,30 +294,35 @@ void LinkManager::saveLinkConfigurationList() ...@@ -339,30 +294,35 @@ void LinkManager::saveLinkConfigurationList()
{ {
QSettings settings; QSettings settings;
settings.remove(LinkConfiguration::settingsRoot()); settings.remove(LinkConfiguration::settingsRoot());
int index = 0;
foreach (LinkConfiguration* pLink, _linkConfigurations) { for (int i=0; i<_linkConfigurations.count(); i++) {
Q_ASSERT(pLink != NULL); LinkConfiguration* linkConfig = _linkConfigurations.value<LinkConfiguration*>(i);
if(!pLink->isDynamic())
{ if (linkConfig) {
QString root = LinkConfiguration::settingsRoot(); if(!linkConfig->isDynamic())
root += QString("/Link%1").arg(index++); {
settings.setValue(root + "/name", pLink->name()); QString root = LinkConfiguration::settingsRoot();
settings.setValue(root + "/type", pLink->type()); root += QString("/Link%1").arg(i);
settings.setValue(root + "/preferred", pLink->isPreferred()); settings.setValue(root + "/name", linkConfig->name());
// Have the instance save its own values settings.setValue(root + "/type", linkConfig->type());
pLink->saveSettings(settings, root); // Have the instance save its own values
linkConfig->saveSettings(settings, root);
}
} else {
qWarning() << "Internal error";
} }
} }
QString root(LinkConfiguration::settingsRoot()); QString root(LinkConfiguration::settingsRoot());
settings.setValue(root + "/count", index); settings.setValue(root + "/count", _linkConfigurations.count());
emit linkConfigurationChanged(); emit linkConfigurationChanged();
} }
void LinkManager::loadLinkConfigurationList() void LinkManager::loadLinkConfigurationList()
{ {
bool udpExists = false;
bool linksChanged = false; bool linksChanged = false;
QSettings settings; QSettings settings;
// Is the group even there? // Is the group even there?
if(settings.contains(LinkConfiguration::settingsRoot() + "/count")) { if(settings.contains(LinkConfiguration::settingsRoot() + "/count")) {
// Find out how many configurations we have // Find out how many configurations we have
...@@ -376,49 +336,33 @@ void LinkManager::loadLinkConfigurationList() ...@@ -376,49 +336,33 @@ void LinkManager::loadLinkConfigurationList()
if(settings.contains(root + "/name")) { if(settings.contains(root + "/name")) {
QString name = settings.value(root + "/name").toString(); QString name = settings.value(root + "/name").toString();
if(!name.isEmpty()) { if(!name.isEmpty()) {
bool preferred = false;
if(settings.contains(root + "/preferred")) {
preferred = settings.value(root + "/preferred").toBool();
}
LinkConfiguration* pLink = NULL; LinkConfiguration* pLink = NULL;
switch(type) { switch(type) {
#ifndef __ios__ #ifndef __ios__
case LinkConfiguration::TypeSerial: case LinkConfiguration::TypeSerial:
pLink = (LinkConfiguration*)new SerialConfiguration(name); pLink = (LinkConfiguration*)new SerialConfiguration(name);
pLink->setPreferred(preferred);
break; break;
#endif #endif
case LinkConfiguration::TypeUdp: case LinkConfiguration::TypeUdp:
pLink = (LinkConfiguration*)new UDPConfiguration(name); pLink = (LinkConfiguration*)new UDPConfiguration(name);
pLink->setPreferred(preferred);
break; break;
case LinkConfiguration::TypeTcp: case LinkConfiguration::TypeTcp:
pLink = (LinkConfiguration*)new TCPConfiguration(name); pLink = (LinkConfiguration*)new TCPConfiguration(name);
pLink->setPreferred(preferred);
break; break;
case LinkConfiguration::TypeLogReplay: case LinkConfiguration::TypeLogReplay:
pLink = (LinkConfiguration*)new LogReplayLinkConfiguration(name); pLink = (LinkConfiguration*)new LogReplayLinkConfiguration(name);
pLink->setPreferred(preferred);
break; break;
#ifdef QT_DEBUG #ifdef QT_DEBUG
case LinkConfiguration::TypeMock: case LinkConfiguration::TypeMock:
pLink = (LinkConfiguration*)new MockConfiguration(name); pLink = (LinkConfiguration*)new MockConfiguration(name);
pLink->setPreferred(false);
break; break;
#endif #endif
} }
if(pLink) { if(pLink) {
// Have the instance load its own values // Have the instance load its own values
pLink->loadSettings(settings, root); pLink->loadSettings(settings, root);
addLinkConfiguration(pLink); _linkConfigurations.append(pLink);
linksChanged = true; linksChanged = true;
// Check for UDP links
if(pLink->type() == LinkConfiguration::TypeUdp) {
UDPConfiguration* uLink = dynamic_cast<UDPConfiguration*>(pLink);
if(uLink && uLink->localPort() == QGC_UDP_LOCAL_PORT) {
udpExists = true;
}
}
} }
} else { } else {
qWarning() << "Link Configuration " << root << " has an empty name." ; qWarning() << "Link Configuration " << root << " has an empty name." ;
...@@ -439,37 +383,32 @@ void LinkManager::loadLinkConfigurationList() ...@@ -439,37 +383,32 @@ void LinkManager::loadLinkConfigurationList()
#ifdef QT_DEBUG #ifdef QT_DEBUG
MockConfiguration* pMock = new MockConfiguration("Mock Link PX4"); MockConfiguration* pMock = new MockConfiguration("Mock Link PX4");
pMock->setDynamic(true); pMock->setDynamic(true);
addLinkConfiguration(pMock); _linkConfigurations.append(pMock);
linksChanged = true; linksChanged = true;
#endif #endif
//-- If we don't have a configured UDP link, create a default one
if(!udpExists) {
UDPConfiguration* uLink = new UDPConfiguration("Default UDP Link");
uLink->setLocalPort(QGC_UDP_LOCAL_PORT);
uLink->setDynamic();
addLinkConfiguration(uLink);
linksChanged = true;
}
if(linksChanged) { if(linksChanged) {
emit linkConfigurationChanged(); emit linkConfigurationChanged();
} }
// Enable automatic Serial PX4/3DR Radio hunting // Enable automatic Serial PX4/3DR Radio hunting
_configurationsLoaded = true; _configurationsLoaded = true;
} }
#ifndef __ios__ #ifndef __ios__
SerialConfiguration* LinkManager::_findSerialConfiguration(const QString& portName) SerialConfiguration* LinkManager::_autoconnectConfigurationsContainsPort(const QString& portName)
{ {
QString searchPort = portName.trimmed(); QString searchPort = portName.trimmed();
foreach (LinkConfiguration* pLink, _linkConfigurations) {
Q_ASSERT(pLink != NULL); for (int i=0; i<_autoconnectConfigurations.count(); i++) {
if(pLink->type() == LinkConfiguration::TypeSerial) { SerialConfiguration* linkConfig = _autoconnectConfigurations.value<SerialConfiguration*>(i);
SerialConfiguration* pSerial = dynamic_cast<SerialConfiguration*>(pLink);
if(pSerial->portName() == searchPort) { if (linkConfig) {
return pSerial; if (linkConfig->portName() == searchPort) {
return linkConfig;
} }
} else {
qWarning() << "Internal error";
} }
} }
return NULL; return NULL;
...@@ -477,26 +416,34 @@ SerialConfiguration* LinkManager::_findSerialConfiguration(const QString& portNa ...@@ -477,26 +416,34 @@ SerialConfiguration* LinkManager::_findSerialConfiguration(const QString& portNa
#endif #endif
#ifndef __ios__ #ifndef __ios__
void LinkManager::_updateConfigurationList(void) void LinkManager::_updateAutoConnectLinks(void)
{ {
if (_configUpdateSuspended || !_configurationsLoaded) { if (_connectionsSuspended || qgcApp()->runningUnitTests()) {
return; return;
} }
bool saveList = false;
if (_autoconnectUDP && !_autoconnectUDPConfig) {
_autoconnectUDPConfig = new UDPConfiguration("Default UDP Link");
_autoconnectUDPConfig->setLocalPort(QGC_UDP_LOCAL_PORT);
_autoconnectUDPConfig->setDynamic(true);
createConnectedLink(_autoconnectUDPConfig, true /* persistenLink */);
}
QStringList currentPorts; QStringList currentPorts;
QList<QGCSerialPortInfo> portList = QGCSerialPortInfo::availablePorts(); QList<QGCSerialPortInfo> portList = QGCSerialPortInfo::availablePorts();
// Iterate Comm Ports // Iterate Comm Ports
foreach (QGCSerialPortInfo portInfo, portList) { foreach (QGCSerialPortInfo portInfo, portList) {
#if 0 qCDebug(LinkManagerVerboseLog) << "-----------------------------------------------------";
// Too noisy for most logging, so turn on as needed qCDebug(LinkManagerVerboseLog) << "portName: " << portInfo.portName();
qCDebug(LinkManagerLog) << "-----------------------------------------------------"; qCDebug(LinkManagerVerboseLog) << "systemLocation: " << portInfo.systemLocation();
qCDebug(LinkManagerLog) << "portName: " << portInfo.portName(); qCDebug(LinkManagerVerboseLog) << "description: " << portInfo.description();
qCDebug(LinkManagerLog) << "systemLocation: " << portInfo.systemLocation(); qCDebug(LinkManagerVerboseLog) << "manufacturer: " << portInfo.manufacturer();
qCDebug(LinkManagerLog) << "description: " << portInfo.description(); qCDebug(LinkManagerVerboseLog) << "serialNumber: " << portInfo.serialNumber();
qCDebug(LinkManagerLog) << "manufacturer: " << portInfo.manufacturer(); qCDebug(LinkManagerVerboseLog) << "vendorIdentifier: " << portInfo.vendorIdentifier();
qCDebug(LinkManagerLog) << "serialNumber: " << portInfo.serialNumber(); qCDebug(LinkManagerVerboseLog) << "productIdentifier: " << portInfo.productIdentifier();
qCDebug(LinkManagerLog) << "vendorIdentifier: " << portInfo.vendorIdentifier();
#endif
// Save port name // Save port name
currentPorts << portInfo.systemLocation(); currentPorts << portInfo.systemLocation();
...@@ -508,76 +455,98 @@ void LinkManager::_updateConfigurationList(void) ...@@ -508,76 +455,98 @@ void LinkManager::_updateConfigurationList(void)
continue; continue;
} }
SerialConfiguration* pSerial = _findSerialConfiguration(portInfo.systemLocation()); if (!_autoconnectConfigurationsContainsPort(portInfo.systemLocation())) {
if (pSerial) { SerialConfiguration* pSerialConfig = NULL;
//-- If this port is configured make sure it has the preferred flag set
if(!pSerial->isPreferred()) {
pSerial->setPreferred(true);
saveList = true;
}
} else {
switch (boardType) { switch (boardType) {
case QGCSerialPortInfo::BoardTypePX4FMUV1: case QGCSerialPortInfo::BoardTypePX4FMUV1:
case QGCSerialPortInfo::BoardTypePX4FMUV2: case QGCSerialPortInfo::BoardTypePX4FMUV2:
pSerial = new SerialConfiguration(QString("Pixhawk on %1").arg(portInfo.portName().trimmed())); if (_autoconnectPixhawk) {
pSerialConfig = new SerialConfiguration(QString("Pixhawk on %1").arg(portInfo.portName().trimmed()));
}
break; break;
case QGCSerialPortInfo::BoardTypeAeroCore: case QGCSerialPortInfo::BoardTypeAeroCore:
pSerial = new SerialConfiguration(QString("AeroCore on %1").arg(portInfo.portName().trimmed())); if (_autoconnectPixhawk) {
pSerialConfig = new SerialConfiguration(QString("AeroCore on %1").arg(portInfo.portName().trimmed()));
}
break; break;
case QGCSerialPortInfo::BoardTypePX4Flow: case QGCSerialPortInfo::BoardTypePX4Flow:
pSerial = new SerialConfiguration(QString("PX4Flow on %1").arg(portInfo.portName().trimmed())); if (_autoconnectPX4Flow) {
pSerialConfig = new SerialConfiguration(QString("PX4Flow on %1").arg(portInfo.portName().trimmed()));
}
break; break;
case QGCSerialPortInfo::BoardType3drRadio: case QGCSerialPortInfo::BoardType3drRadio:
pSerial = new SerialConfiguration(QString("3DR Radio on %1").arg(portInfo.portName().trimmed())); if (_autoconnect3DRRadio) {
pSerialConfig = new SerialConfiguration(QString("3DR Radio on %1").arg(portInfo.portName().trimmed()));
}
break;
default: default:
qWarning() << "Internal error"; qWarning() << "Internal error";
break; continue;
} }
pSerial->setBaud(boardType == QGCSerialPortInfo::BoardType3drRadio ? 57600 : 115200); if (pSerialConfig) {
pSerial->setDynamic(true); qCDebug(LinkManagerLog) << "New auto-connect port added: " << pSerialConfig->name() << portInfo.systemLocation();
pSerial->setPreferred(true); pSerialConfig->setBaud(boardType == QGCSerialPortInfo::BoardType3drRadio ? 57600 : 115200);
pSerial->setPortName(portInfo.systemLocation()); pSerialConfig->setDynamic(true);
addLinkConfiguration(pSerial); pSerialConfig->setPortName(portInfo.systemLocation());
saveList = true;
_autoconnectConfigurations.append(pSerialConfig);
createConnectedLink(pSerialConfig, true /* persistenLink */);
}
} }
} }
} }
// Now we go through the current configuration list and make sure any dynamic config has gone away // Now we go through the current configuration list and make sure any dynamic config has gone away
QList<LinkConfiguration*> _confToDelete; QList<LinkConfiguration*> _confToDelete;
foreach (LinkConfiguration* pLink, _linkConfigurations) { for (int i=0; i<_autoconnectConfigurations.count(); i++) {
Q_ASSERT(pLink != NULL); SerialConfiguration* linkConfig = _autoconnectConfigurations.value<SerialConfiguration*>(i);
// We only care about dynamic links
if(pLink->isDynamic()) { if (linkConfig) {
if(pLink->type() == LinkConfiguration::TypeSerial) { if (!currentPorts.contains(linkConfig->portName())) {
// Don't mess with connected link. Let it deal with the disapearing device. _confToDelete.append(linkConfig);
if(pLink->getLink() == NULL) {
SerialConfiguration* pSerial = dynamic_cast<SerialConfiguration*>(pLink);
if(!currentPorts.contains(pSerial->portName())) {
_confToDelete.append(pSerial);
}
}
} }
} else {
qWarning() << "Internal error";
} }
} }
// Now remove all links that are gone
foreach (LinkConfiguration* pDelete, _confToDelete) { // Now disconnect/remove all links that are gone
removeLinkConfiguration(pDelete); foreach (LinkConfiguration* pDeleteConfig, _confToDelete) {
saveList = true; LinkInterface* link = pDeleteConfig->link();
} if (link) {
// Save configuration list, which will also trigger a signal for the UI disconnectLink(link, true /* disconnectAutoconnectLink */);
if(saveList) { }
saveLinkConfigurationList(); _autoconnectConfigurations.removeOne(pDeleteConfig);
delete pDeleteConfig;
} }
} }
#endif #endif
bool LinkManager::containsLink(LinkInterface* link) bool LinkManager::anyConnectedLinks(void)
{
bool found = false;
for (int i=0; i<_links.count(); i++) {
LinkInterface* link = _links.value<LinkInterface*>(i);
if (link && link->isConnected()) {
found = true;
break;
}
}
return found;
}
bool LinkManager::anyNonAutoconnectConnectedLinks(void)
{ {
// FIXME: Should remove this duplication with anyConnectedLinks
bool found = false; bool found = false;
foreach (SharedLinkInterface sharedLink, _links) { for (int i=0; i<_links.count(); i++) {
if (sharedLink.data() == link) { LinkInterface* link = _links.value<LinkInterface*>(i);
if (link && !link->autoconnect() && link->isConnected()) {
found = true; found = true;
break; break;
} }
...@@ -585,11 +554,13 @@ bool LinkManager::containsLink(LinkInterface* link) ...@@ -585,11 +554,13 @@ bool LinkManager::containsLink(LinkInterface* link)
return found; return found;
} }
bool LinkManager::anyConnectedLinks(void) bool LinkManager::anyActiveLinks(void)
{ {
bool found = false; bool found = false;
foreach (SharedLinkInterface sharedLink, _links) { for (int i=0; i<_links.count(); i++) {
if (sharedLink.data()->isConnected()) { LinkInterface* link = _links.value<LinkInterface*>(i);
if (link && link->active()) {
found = true; found = true;
break; break;
} }
...@@ -597,14 +568,117 @@ bool LinkManager::anyConnectedLinks(void) ...@@ -597,14 +568,117 @@ bool LinkManager::anyConnectedLinks(void)
return found; return found;
} }
SharedLinkInterface& LinkManager::sharedPointerForLink(LinkInterface* link) bool LinkManager::anyNonAutoconnectActiveLinks(void)
{ {
// FIXME: Should remove this duplication with anyActiveLinks
bool found = false;
for (int i=0; i<_links.count(); i++) { for (int i=0; i<_links.count(); i++) {
if (_links[i].data() == link) { LinkInterface* link = _links.value<LinkInterface*>(i);
return _links[i];
if (link && !link->autoconnect() && link->active()) {
found = true;
break;
}
}
return found;
}
void LinkManager::_vehicleHeartbeatInfo(LinkInterface* link, int vehicleId, int vehicleMavlinkVersion, int vehicleFirmwareType, int vehicleType)
{
if (!link->active() && !_ignoreVehicleIds.contains(vehicleId)) {
qCDebug(LinkManagerLog) << "New heartbeat on link:vehicleId:vehicleMavlinkVersion:vehicleFirmwareType:vehicleType "
<< link->getName()
<< vehicleId
<< vehicleMavlinkVersion
<< vehicleFirmwareType
<< vehicleType;
if (vehicleId == _mavlinkProtocol->getSystemId()) {
_app->showToolBarMessage(QString("Warning: A vehicle is using the same system id as QGroundControl: %1").arg(vehicleId));
}
QSettings settings;
bool mavlinkVersionCheck = settings.value("VERSION_CHECK_ENABLED", true).toBool();
if (mavlinkVersionCheck && vehicleMavlinkVersion != MAVLINK_VERSION) {
_ignoreVehicleIds += vehicleId;
_app->showToolBarMessage(QString("The MAVLink protocol version on vehicle #%1 and QGroundControl differ! "
"It is unsafe to use different MAVLink versions. "
"QGroundControl therefore refuses to connect to vehicle #%1, which sends MAVLink version %2 (QGroundControl uses version %3).").arg(vehicleId).arg(vehicleMavlinkVersion).arg(MAVLINK_VERSION));
return;
}
bool previousAnyActiveLinks = anyActiveLinks();
bool previousAnyNonAutoconnectActiveLinks = anyNonAutoconnectActiveLinks();
link->setActive(true);
emit linkActive(link, vehicleId, vehicleFirmwareType, vehicleType);
if (!previousAnyActiveLinks) {
emit anyActiveLinksChanged(true);
} }
if (!previousAnyNonAutoconnectActiveLinks && anyNonAutoconnectActiveLinks()) {
emit anyNonAutoconnectActiveLinksChanged(true);
}
}
}
void LinkManager::shutdown(void)
{
setConnectionsSuspended("Shutdown");
disconnectAll(true /* disconnectAutoconnectLink */);
}
void LinkManager::setAutoconnectUDP(bool autoconnect)
{
if (_autoconnectUDP != autoconnect) {
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_autoconnectUDPKey, autoconnect);
_autoconnectUDP = autoconnect;
emit autoconnectUDPChanged(autoconnect);
} }
// This should never happen }
Q_ASSERT(false);
return _nullSharedLink; void LinkManager::setAutoconnectPixhawk(bool autoconnect)
{
if (_autoconnectPixhawk != autoconnect) {
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_autoconnectPixhawkKey, autoconnect);
_autoconnectPixhawk = autoconnect;
emit autoconnectPixhawkChanged(autoconnect);
}
}
void LinkManager::setAutoconnect3DRRadio(bool autoconnect)
{
if (_autoconnect3DRRadio != autoconnect) {
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_autoconnect3DRRadioKey, autoconnect);
_autoconnect3DRRadio = autoconnect;
emit autoconnect3DRRadioChanged(autoconnect);
}
}
void LinkManager::setAutoconnectPX4Flow(bool autoconnect)
{
if (_autoconnectPX4Flow != autoconnect) {
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_autoconnectPX4FlowKey, autoconnect);
_autoconnectPX4Flow = autoconnect;
emit autoconnectPX4FlowChanged(autoconnect);
}
} }
...@@ -35,23 +35,23 @@ This file is part of the PIXHAWK project ...@@ -35,23 +35,23 @@ This file is part of the PIXHAWK project
#include "LinkInterface.h" #include "LinkInterface.h"
#include "QGCLoggingCategory.h" #include "QGCLoggingCategory.h"
#include "QGCToolbox.h" #include "QGCToolbox.h"
#include "ProtocolInterface.h"
#include "MAVLinkProtocol.h"
#include "LogReplayLink.h"
#include "QmlObjectListModel.h"
// Links
#ifndef __ios__ #ifndef __ios__
#include "SerialLink.h" #include "SerialLink.h"
#endif #endif
#include "UDPLink.h"
#include "TCPLink.h"
#include "LogReplayLink.h"
#ifdef QT_DEBUG #ifdef QT_DEBUG
#include "MockLink.h" #include "MockLink.h"
#endif #endif
#include "ProtocolInterface.h" class UDPConfiguration;
#include "MAVLinkProtocol.h"
Q_DECLARE_LOGGING_CATEGORY(LinkManagerLog) Q_DECLARE_LOGGING_CATEGORY(LinkManagerLog)
Q_DECLARE_LOGGING_CATEGORY(LinkManagerVerboseLog)
class QGCApplication; class QGCApplication;
...@@ -72,17 +72,36 @@ public: ...@@ -72,17 +72,36 @@ public:
LinkManager(QGCApplication* app); LinkManager(QGCApplication* app);
~LinkManager(); ~LinkManager();
/*! Q_PROPERTY(bool anyActiveLinks READ anyActiveLinks NOTIFY anyActiveLinksChanged)
Add a new link configuration setting to the list Q_PROPERTY(bool anyNonAutoconnectActiveLinks READ anyNonAutoconnectActiveLinks NOTIFY anyNonAutoconnectActiveLinksChanged)
@param[in] link An instance of the link setting. Q_PROPERTY(bool anyConnectedLinks READ anyConnectedLinks NOTIFY anyConnectedLinksChanged)
*/ Q_PROPERTY(bool anyNonAutoconnectConnectedLinks READ anyNonAutoconnectConnectedLinks NOTIFY anyNonAutoconnectConnectedLinksChanged)
void addLinkConfiguration(LinkConfiguration* link); Q_PROPERTY(bool autoconnectUDP READ autoconnectUDP WRITE setAutoconnectUDP NOTIFY autoconnectUDPChanged)
Q_PROPERTY(bool autoconnectPixhawk READ autoconnectPixhawk WRITE setAutoconnectPixhawk NOTIFY autoconnectPixhawkChanged)
Q_PROPERTY(bool autoconnect3DRRadio READ autoconnect3DRRadio WRITE setAutoconnect3DRRadio NOTIFY autoconnect3DRRadioChanged)
Q_PROPERTY(bool autoconnectPX4Flow READ autoconnectPX4Flow WRITE setAutoconnectPX4Flow NOTIFY autoconnectPX4FlowChanged)
Q_PROPERTY(QmlObjectListModel* links READ links CONSTANT)
Q_PROPERTY(QmlObjectListModel* linkConfigurations READ linkConfigurations CONSTANT)
// Property accessors
bool anyConnectedLinks(void);
bool anyNonAutoconnectConnectedLinks(void);
bool anyActiveLinks(void);
bool anyNonAutoconnectActiveLinks(void);
bool autoconnectUDP(void) { return _autoconnectUDP; }
bool autoconnectPixhawk(void) { return _autoconnectPixhawk; }
bool autoconnect3DRRadio(void) { return _autoconnect3DRRadio; }
bool autoconnectPX4Flow(void) { return _autoconnectPX4Flow; }
QmlObjectListModel* links(void) { return &_links; }
QmlObjectListModel* linkConfigurations(void) { return &_linkConfigurations; }
void setAutoconnectUDP(bool autoconnect);
void setAutoconnectPixhawk(bool autoconnect);
void setAutoconnect3DRRadio(bool autoconnect);
void setAutoconnectPX4Flow(bool autoconnect);
/*!
Removes (and deletes) an existing link configuration setting from the list
@param[in] link An instance of the link setting.
*/
void removeLinkConfiguration(LinkConfiguration* link);
/// Load list of link configurations from disk /// Load list of link configurations from disk
void loadLinkConfigurationList(); void loadLinkConfigurationList();
...@@ -90,19 +109,9 @@ public: ...@@ -90,19 +109,9 @@ public:
/// Save list of link configurations from disk /// Save list of link configurations from disk
void saveLinkConfigurationList(); void saveLinkConfigurationList();
/// Get a list of the configured links. This is the list of configured links that can be used by QGC.
const QList<LinkConfiguration*> getLinkConfigurationList();
/// Suspend automatic confguration updates (during link maintenance for instance) /// Suspend automatic confguration updates (during link maintenance for instance)
void suspendConfigurationUpdates(bool suspend); void suspendConfigurationUpdates(bool suspend);
/// Returns list of all links
const QList<LinkInterface*> getLinks();
// Returns list of all serial links
#ifndef __ios__
const QList<SerialLink*> getSerialLinks();
#endif
/// Sets the flag to suspend the all new connections /// Sets the flag to suspend the all new connections
/// @param reason User visible reason to suspend connections /// @param reason User visible reason to suspend connections
void setConnectionsSuspended(QString reason); void setConnectionsSuspended(QString reason);
...@@ -112,68 +121,85 @@ public: ...@@ -112,68 +121,85 @@ public:
/// Creates, connects (and adds) a link based on the given configuration instance. /// Creates, connects (and adds) a link based on the given configuration instance.
/// Link takes ownership of config. /// Link takes ownership of config.
LinkInterface* createConnectedLink(LinkConfiguration* config); Q_INVOKABLE LinkInterface* createConnectedLink(LinkConfiguration* config, bool persistenLink = false);
/// Creates, connects (and adds) a link based on the given configuration name. /// Creates, connects (and adds) a link based on the given configuration name.
LinkInterface* createConnectedLink(const QString& name); LinkInterface* createConnectedLink(const QString& name, bool persistenLink = false);
/// Returns true if the link manager is holding this link
bool containsLink(LinkInterface* link);
/// Returns the QSharedPointer for this link. You must use SharedLinkInterface if you are going to
/// keep references to a link in a thread other than the main ui thread.
SharedLinkInterface& sharedPointerForLink(LinkInterface* link);
/// Re-connects all existing links /// Disconnects all existing links, including persistent links.
bool connectAll(); /// @param disconnectAutoconnectLink See disconnectLink
void disconnectAll(bool disconnectAutoconnectLink);
/// Disconnects all existing links
bool disconnectAll();
/// Connect the specified link /// Connect the specified link
bool connectLink(LinkInterface* link); bool connectLink(LinkInterface* link);
/// Disconnect the specified link /// Disconnect the specified link.
bool disconnectLink(LinkInterface* link); /// @param disconnectAutoconnectLink
/// true: link is disconnected no matter what type
/// Returns true if there are any connected links /// false: if autoconnect link, link is marked as inactive and linkInactive is signalled
bool anyConnectedLinks(void); /// false: if not autoconnect link, link is disconnected
Q_INVOKABLE bool disconnectLink(LinkInterface* link, bool disconnectAutoconnectLink);
/// Called to notify that a heartbeat was received with the specified information. Will transition
/// a link to active as needed.
/// @param link Heartbeat came through on this link
/// @param vehicleId Mavlink system id for vehicle
/// @param heartbeat Mavlink heartbeat message
/// @return true: continue further processing of this message, false: disregard this message
bool notifyHeartbeatInfo(LinkInterface* link, int vehicleId, mavlink_heartbeat_t& heartbeat);
// The following APIs are public but should not be called in normal use. The are mainly exposed // The following APIs are public but should not be called in normal use. The are mainly exposed
// here for unit test code. // here for unit test code.
void _deleteLink(LinkInterface* link); void _deleteLink(LinkInterface* link);
void _addLink(LinkInterface* link); void _addLink(LinkInterface* link);
// Called to signal app shutdown. Disconnects all links while turning off auto-connect.
void shutdown(void);
// Override from QGCTool // Override from QGCTool
virtual void setToolbox(QGCToolbox *toolbox); virtual void setToolbox(QGCToolbox *toolbox);
signals: signals:
void anyActiveLinksChanged(bool anyActiveLinks);
void anyNonAutoconnectActiveLinksChanged(bool anyNonAutoconnectActiveLinks);
void anyConnectedLinksChanged(bool anyConnectedLinks);
void anyNonAutoconnectConnectedLinksChanged(bool anyNoAutoconnectConnectedLinks);
void autoconnectUDPChanged(bool autoconnect);
void autoconnectPixhawkChanged(bool autoconnect);
void autoconnect3DRRadioChanged(bool autoconnect);
void autoconnectPX4FlowChanged(bool autoconnect);
void newLink(LinkInterface* link); void newLink(LinkInterface* link);
// Link has been deleted. You may not necessarily get a linkInactive before the link is deleted.
void linkDeleted(LinkInterface* link); void linkDeleted(LinkInterface* link);
// Link has been connected, but no Vehicle seen on link yet.
void linkConnected(LinkInterface* link); void linkConnected(LinkInterface* link);
// Link disconnected, all vehicles on link should be gone as well.
void linkDisconnected(LinkInterface* link); void linkDisconnected(LinkInterface* link);
// New vehicle has been seen on the link.
void linkActive(LinkInterface* link, int vehicleId, int vehicleFirmwareType, int vehicleType);
// No longer hearing from any vehicles on this link.
void linkInactive(LinkInterface* link);
void linkConfigurationChanged(); void linkConfigurationChanged();
private slots: private slots:
void _linkConnected(void); void _linkConnected(void);
void _linkDisconnected(void); void _linkDisconnected(void);
void _vehicleHeartbeatInfo(LinkInterface* link, int vehicleId, int vehicleMavlinkVersion, int vehicleFirmwareType, int vehicleType);
private: private:
virtual void _shutdown(void);
bool _connectionsSuspendedMsg(void); bool _connectionsSuspendedMsg(void);
void _updateConfigurationList(void); void _updateAutoConnectLinks(void);
#ifndef __ios__ #ifndef __ios__
SerialConfiguration* _findSerialConfiguration(const QString& portName); SerialConfiguration* _autoconnectConfigurationsContainsPort(const QString& portName);
#endif #endif
QList<LinkConfiguration*> _linkConfigurations; ///< List of configured links
/// List of available links kept as QSharedPointers. We use QSharedPointer since
/// there are other objects that maintain copies of these links in other threads.
/// The reference counting allows for orderly deletion.
QList<SharedLinkInterface> _links;
QMutex _linkListMutex; ///< Mutex for thread safe access to _links list
bool _configUpdateSuspended; ///< true: stop updating configuration list bool _configUpdateSuspended; ///< true: stop updating configuration list
bool _configurationsLoaded; ///< true: Link configurations have been loaded bool _configurationsLoaded; ///< true: Link configurations have been loaded
...@@ -183,10 +209,25 @@ private: ...@@ -183,10 +209,25 @@ private:
QTimer _portListTimer; QTimer _portListTimer;
#endif #endif
uint32_t _mavlinkChannelsUsedBitMask; uint32_t _mavlinkChannelsUsedBitMask;
SharedLinkInterface _nullSharedLink;
MAVLinkProtocol* _mavlinkProtocol; MAVLinkProtocol* _mavlinkProtocol;
QList<int> _ignoreVehicleIds; ///< List of vehicle id for which we ignore further communication
QmlObjectListModel _links;
QmlObjectListModel _linkConfigurations;
QmlObjectListModel _autoconnectConfigurations;
UDPConfiguration* _autoconnectUDPConfig;
bool _autoconnectUDP;
bool _autoconnectPixhawk;
bool _autoconnect3DRRadio;
bool _autoconnectPX4Flow;
static const char* _settingsGroup;
static const char* _autoconnectUDPKey;
static const char* _autoconnectPixhawkKey;
static const char* _autoconnect3DRRadioKey;
static const char* _autoconnectPX4FlowKey;
}; };
#endif #endif
...@@ -102,7 +102,7 @@ LogReplayLink::~LogReplayLink(void) ...@@ -102,7 +102,7 @@ LogReplayLink::~LogReplayLink(void)
bool LogReplayLink::_connect(void) bool LogReplayLink::_connect(void)
{ {
// Disallow replay when any links are connected // Disallow replay when any links are connected
if (qgcApp()->toolbox()->linkManager()->anyConnectedLinks()) { if (qgcApp()->toolbox()->linkManager()->anyActiveLinks()) {
emit communicationError(_errorTitle, "You must close all connections prior to replaying a log."); emit communicationError(_errorTitle, "You must close all connections prior to replaying a log.");
return false; return false;
} }
...@@ -115,7 +115,7 @@ bool LogReplayLink::_connect(void) ...@@ -115,7 +115,7 @@ bool LogReplayLink::_connect(void)
return true; return true;
} }
bool LogReplayLink::_disconnect(void) void LogReplayLink::_disconnect(void)
{ {
if (_connected) { if (_connected) {
quit(); quit();
...@@ -123,7 +123,6 @@ bool LogReplayLink::_disconnect(void) ...@@ -123,7 +123,6 @@ bool LogReplayLink::_disconnect(void)
_connected = false; _connected = false;
emit disconnected(); emit disconnected();
} }
return true;
} }
void LogReplayLink::run(void) void LogReplayLink::run(void)
...@@ -366,7 +365,6 @@ void LogReplayLink::_readNextLogEntry(void) ...@@ -366,7 +365,6 @@ void LogReplayLink::_readNextLogEntry(void)
void LogReplayLink::_play(void) void LogReplayLink::_play(void)
{ {
// FIXME: With move to link I don't think this is needed any more? Except for the replay widget handling multi-uas?
qgcApp()->toolbox()->linkManager()->setConnectionsSuspended(tr("Connect not allowed during Flight Data replay.")); qgcApp()->toolbox()->linkManager()->setConnectionsSuspended(tr("Connect not allowed during Flight Data replay."));
#ifndef __mobile__ #ifndef __mobile__
qgcApp()->toolbox()->mavlinkProtocol()->suspendLogForReplay(true); qgcApp()->toolbox()->mavlinkProtocol()->suspendLogForReplay(true);
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
class LogReplayLinkConfiguration : public LinkConfiguration class LogReplayLinkConfiguration : public LinkConfiguration
{ {
Q_OBJECT
public: public:
LogReplayLinkConfiguration(const QString& name); LogReplayLinkConfiguration(const QString& name);
LogReplayLinkConfiguration(LogReplayLinkConfiguration* copy); LogReplayLinkConfiguration(LogReplayLinkConfiguration* copy);
...@@ -130,7 +132,7 @@ private: ...@@ -130,7 +132,7 @@ private:
// Virtuals from LinkInterface // Virtuals from LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
// Virtuals from QThread // Virtuals from QThread
virtual void run(void); virtual void run(void);
......
...@@ -193,13 +193,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected) ...@@ -193,13 +193,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected)
Q_ASSERT(link); Q_ASSERT(link);
if (connected) { if (connected) {
foreach (SharedLinkInterface sharedLink, _connectedLinks) {
Q_ASSERT(sharedLink.data() != link);
}
// Use the same shared pointer as LinkManager
_connectedLinks.append(_linkMgr->sharedPointerForLink(link));
if (link->requiresUSBMavlinkStart()) { if (link->requiresUSBMavlinkStart()) {
// Send command to start MAVLink // Send command to start MAVLink
// XXX hacky but safe // XXX hacky but safe
...@@ -210,17 +203,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected) ...@@ -210,17 +203,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected)
link->writeBytes(cmd, strlen(cmd)); link->writeBytes(cmd, strlen(cmd));
link->writeBytes(init, 4); link->writeBytes(init, 4);
} }
} else {
bool found = false;
for (int i=0; i<_connectedLinks.count(); i++) {
if (_connectedLinks[i].data() == link) {
found = true;
_connectedLinks.removeAt(i);
break;
}
}
Q_UNUSED(found);
Q_ASSERT(found);
} }
} }
...@@ -236,7 +218,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -236,7 +218,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
// Since receiveBytes signals cross threads we can end up with signals in the queue // Since receiveBytes signals cross threads we can end up with signals in the queue
// that come through after the link is disconnected. For these we just drop the data // that come through after the link is disconnected. For these we just drop the data
// since the link is closed. // since the link is closed.
if (!_linkMgr->containsLink(link)) { if (!_linkMgr->links()->contains(link)) {
return; return;
} }
...@@ -300,7 +282,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -300,7 +282,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
{ {
mavlink_message_t msg; mavlink_message_t msg;
mavlink_msg_ping_pack(getSystemId(), getComponentId(), &msg, ping.time_usec, ping.seq, message.sysid, message.compid); mavlink_msg_ping_pack(getSystemId(), getComponentId(), &msg, ping.time_usec, ping.seq, message.sysid, message.compid);
sendMessage(msg); _sendMessage(msg);
} }
} }
...@@ -359,12 +341,9 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -359,12 +341,9 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
_startLogging(); _startLogging();
#endif #endif
// Notify the vehicle manager of the heartbeat. This will create/update vehicles as needed.
mavlink_heartbeat_t heartbeat; mavlink_heartbeat_t heartbeat;
mavlink_msg_heartbeat_decode(&message, &heartbeat); mavlink_msg_heartbeat_decode(&message, &heartbeat);
if (!_multiVehicleManager->notifyHeartbeatInfo(link, message.sysid, heartbeat)) { emit vehicleHeartbeatInfo(link, message.sysid, heartbeat.mavlink_version, heartbeat.autopilot, heartbeat.type);
continue;
}
} }
// Increase receive counter // Increase receive counter
...@@ -417,15 +396,13 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -417,15 +396,13 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
// Multiplex message if enabled // Multiplex message if enabled
if (m_multiplexingEnabled) if (m_multiplexingEnabled)
{ {
// Get all links connected to this unit
QList<LinkInterface*> links = _linkMgr->getLinks();
// Emit message on all links that are currently connected // Emit message on all links that are currently connected
foreach (LinkInterface* currLink, links) for (int i=0; i<_linkMgr->links()->count(); i++) {
{ LinkInterface* currLink = _linkMgr->links()->value<LinkInterface*>(i);
// Only forward this message to the other links, // Only forward this message to the other links,
// not the link the message was received on // not the link the message was received on
if (currLink != link) sendMessage(currLink, message, message.sysid, message.compid); if (currLink && currLink != link) _sendMessage(currLink, message, message.sysid, message.compid);
} }
} }
} }
...@@ -460,17 +437,11 @@ int MAVLinkProtocol::getComponentId() ...@@ -460,17 +437,11 @@ int MAVLinkProtocol::getComponentId()
/** /**
* @param message message to send * @param message message to send
*/ */
void MAVLinkProtocol::sendMessage(mavlink_message_t message) void MAVLinkProtocol::_sendMessage(mavlink_message_t message)
{ {
// Get all links connected to this unit for (int i=0; i<_linkMgr->links()->count(); i++) {
QList<LinkInterface*> links = _linkMgr->getLinks(); LinkInterface* link = _linkMgr->links()->value<LinkInterface*>(i);
_sendMessage(link, message);
// Emit message on all links that are currently connected
QList<LinkInterface*>::iterator i;
for (i = links.begin(); i != links.end(); ++i)
{
sendMessage(*i, message);
// qDebug() << __FILE__ << __LINE__ << "SENT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size();
} }
} }
...@@ -478,7 +449,7 @@ void MAVLinkProtocol::sendMessage(mavlink_message_t message) ...@@ -478,7 +449,7 @@ void MAVLinkProtocol::sendMessage(mavlink_message_t message)
* @param link the link to send the message over * @param link the link to send the message over
* @param message message to send * @param message message to send
*/ */
void MAVLinkProtocol::sendMessage(LinkInterface* link, mavlink_message_t message) void MAVLinkProtocol::_sendMessage(LinkInterface* link, mavlink_message_t message)
{ {
// Create buffer // Create buffer
static uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; static uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
...@@ -501,7 +472,7 @@ void MAVLinkProtocol::sendMessage(LinkInterface* link, mavlink_message_t message ...@@ -501,7 +472,7 @@ void MAVLinkProtocol::sendMessage(LinkInterface* link, mavlink_message_t message
* @param systemid id of the system the message is originating from * @param systemid id of the system the message is originating from
* @param componentid id of the component the message is originating from * @param componentid id of the component the message is originating from
*/ */
void MAVLinkProtocol::sendMessage(LinkInterface* link, mavlink_message_t message, quint8 systemid, quint8 componentid) void MAVLinkProtocol::_sendMessage(LinkInterface* link, mavlink_message_t message, quint8 systemid, quint8 componentid)
{ {
// Create buffer // Create buffer
static uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; static uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
...@@ -529,7 +500,7 @@ void MAVLinkProtocol::sendHeartbeat() ...@@ -529,7 +500,7 @@ void MAVLinkProtocol::sendHeartbeat()
{ {
mavlink_message_t beat; mavlink_message_t beat;
mavlink_msg_heartbeat_pack(getSystemId(), getComponentId(),&beat, MAV_TYPE_GCS, MAV_AUTOPILOT_INVALID, MAV_MODE_MANUAL_ARMED, 0, MAV_STATE_ACTIVE); mavlink_msg_heartbeat_pack(getSystemId(), getComponentId(),&beat, MAV_TYPE_GCS, MAV_AUTOPILOT_INVALID, MAV_MODE_MANUAL_ARMED, 0, MAV_STATE_ACTIVE);
sendMessage(beat); _sendMessage(beat);
} }
if (m_authEnabled) if (m_authEnabled)
{ {
...@@ -538,7 +509,7 @@ void MAVLinkProtocol::sendHeartbeat() ...@@ -538,7 +509,7 @@ void MAVLinkProtocol::sendHeartbeat()
memset(&auth, 0, sizeof(auth)); memset(&auth, 0, sizeof(auth));
memcpy(auth.key, m_authKey.toStdString().c_str(), qMin(m_authKey.length(), MAVLINK_MSG_AUTH_KEY_FIELD_KEY_LEN)); memcpy(auth.key, m_authKey.toStdString().c_str(), qMin(m_authKey.length(), MAVLINK_MSG_AUTH_KEY_FIELD_KEY_LEN));
mavlink_msg_auth_key_encode(getSystemId(), getComponentId(), &msg, &auth); mavlink_msg_auth_key_encode(getSystemId(), getComponentId(), &msg, &auth);
sendMessage(msg); _sendMessage(msg);
} }
} }
......
...@@ -158,12 +158,6 @@ public slots: ...@@ -158,12 +158,6 @@ public slots:
void linkConnected(void); void linkConnected(void);
void linkDisconnected(void); void linkDisconnected(void);
/** @brief Send MAVLink message through serial interface */
void sendMessage(mavlink_message_t message);
/** @brief Send MAVLink message */
void sendMessage(LinkInterface* link, mavlink_message_t message);
/** @brief Send MAVLink message with correct system / component ID */
void sendMessage(LinkInterface* link, mavlink_message_t message, quint8 systemid, quint8 componentid);
/** @brief Set the rate at which heartbeats are emitted */ /** @brief Set the rate at which heartbeats are emitted */
void setHeartbeatRate(int rate); void setHeartbeatRate(int rate);
/** @brief Set the system id of this application */ /** @brief Set the system id of this application */
...@@ -238,6 +232,9 @@ protected: ...@@ -238,6 +232,9 @@ protected:
int systemId; int systemId;
signals: signals:
/// Heartbeat received on link
void vehicleHeartbeatInfo(LinkInterface* link, int vehicleId, int vehicleMavlinkVersion, int vehicleFirmwareType, int vehicleType);
/** @brief Message received and directly copied via signal */ /** @brief Message received and directly copied via signal */
void messageReceived(LinkInterface* link, mavlink_message_t message); void messageReceived(LinkInterface* link, mavlink_message_t message);
/** @brief Emitted if heartbeat emission mode is changed */ /** @brief Emitted if heartbeat emission mode is changed */
...@@ -289,6 +286,9 @@ private slots: ...@@ -289,6 +286,9 @@ private slots:
private: private:
void _linkStatusChanged(LinkInterface* link, bool connected); void _linkStatusChanged(LinkInterface* link, bool connected);
void _sendMessage(mavlink_message_t message);
void _sendMessage(LinkInterface* link, mavlink_message_t message);
void _sendMessage(LinkInterface* link, mavlink_message_t message, quint8 systemid, quint8 componentid);
#ifndef __mobile__ #ifndef __mobile__
bool _closeLogFile(void); bool _closeLogFile(void);
...@@ -303,12 +303,7 @@ private: ...@@ -303,12 +303,7 @@ private:
static const char* _tempLogFileTemplate; ///< Template for temporary log file static const char* _tempLogFileTemplate; ///< Template for temporary log file
static const char* _logFileExtension; ///< Extension for log files static const char* _logFileExtension; ///< Extension for log files
#endif #endif
/// List of all links connected to protocol. We keep SharedLinkInterface objects
/// which are QSharedPointer's in order to maintain reference counts across threads.
/// This way Link deletion works correctly.
QList<SharedLinkInterface> _connectedLinks;
QTimer _heartbeatTimer; ///< Timer to emit heartbeats QTimer _heartbeatTimer; ///< Timer to emit heartbeats
int _heartbeatRate; ///< Heartbeat rate, controls the timer interval int _heartbeatRate; ///< Heartbeat rate, controls the timer interval
bool _heartbeatsEnabled; ///< Enabled/disable heartbeat emission bool _heartbeatsEnabled; ///< Enabled/disable heartbeat emission
......
...@@ -98,6 +98,7 @@ MockLink::MockLink(MockConfiguration* config) ...@@ -98,6 +98,7 @@ MockLink::MockLink(MockConfiguration* config)
_firmwareType = config->firmwareType(); _firmwareType = config->firmwareType();
_vehicleType = config->vehicleType(); _vehicleType = config->vehicleType();
_sendStatusText = config->sendStatusText(); _sendStatusText = config->sendStatusText();
_config->setLink(this);
} }
union px4_custom_mode px4_cm; union px4_custom_mode px4_cm;
...@@ -136,7 +137,7 @@ bool MockLink::_connect(void) ...@@ -136,7 +137,7 @@ bool MockLink::_connect(void)
return true; return true;
} }
bool MockLink::_disconnect(void) void MockLink::_disconnect(void)
{ {
if (_connected) { if (_connected) {
_connected = false; _connected = false;
...@@ -144,8 +145,6 @@ bool MockLink::_disconnect(void) ...@@ -144,8 +145,6 @@ bool MockLink::_disconnect(void)
wait(); wait();
emit disconnected(); emit disconnected();
} }
return true;
} }
void MockLink::run(void) void MockLink::run(void)
......
...@@ -37,6 +37,8 @@ Q_DECLARE_LOGGING_CATEGORY(MockLinkVerboseLog) ...@@ -37,6 +37,8 @@ Q_DECLARE_LOGGING_CATEGORY(MockLinkVerboseLog)
class MockConfiguration : public LinkConfiguration class MockConfiguration : public LinkConfiguration
{ {
Q_OBJECT
public: public:
MockConfiguration(const QString& name); MockConfiguration(const QString& name);
MockConfiguration(MockConfiguration* source); MockConfiguration(MockConfiguration* source);
...@@ -146,7 +148,7 @@ private slots: ...@@ -146,7 +148,7 @@ private slots:
private: private:
// From LinkInterface // From LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
// QThread override // QThread override
virtual void run(void); virtual void run(void);
......
...@@ -124,7 +124,7 @@ void SerialLink::readBytes() ...@@ -124,7 +124,7 @@ void SerialLink::readBytes()
* *
* @return True if connection has been disconnected, false if connection couldn't be disconnected. * @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/ **/
bool SerialLink::_disconnect(void) void SerialLink::_disconnect(void)
{ {
if (_port) { if (_port) {
_port->close(); _port->close();
...@@ -135,7 +135,6 @@ bool SerialLink::_disconnect(void) ...@@ -135,7 +135,6 @@ bool SerialLink::_disconnect(void)
#ifdef __android__ #ifdef __android__
qgcApp()->toolbox()->linkManager()->suspendConfigurationUpdates(false); qgcApp()->toolbox()->linkManager()->suspendConfigurationUpdates(false);
#endif #endif
return true;
} }
/** /**
......
...@@ -59,6 +59,8 @@ Q_DECLARE_LOGGING_CATEGORY(SerialLinkLog) ...@@ -59,6 +59,8 @@ Q_DECLARE_LOGGING_CATEGORY(SerialLinkLog)
class SerialConfiguration : public LinkConfiguration class SerialConfiguration : public LinkConfiguration
{ {
Q_OBJECT
public: public:
SerialConfiguration(const QString& name); SerialConfiguration(const QString& name);
...@@ -158,7 +160,7 @@ private: ...@@ -158,7 +160,7 @@ private:
// From LinkInterface // From LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
// Internal methods // Internal methods
void _emitLinkError(const QString& errorMsg); void _emitLinkError(const QString& errorMsg);
......
...@@ -124,18 +124,16 @@ void TCPLink::readBytes() ...@@ -124,18 +124,16 @@ void TCPLink::readBytes()
* *
* @return True if connection has been disconnected, false if connection couldn't be disconnected. * @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/ **/
bool TCPLink::_disconnect(void) void TCPLink::_disconnect(void)
{ {
quit(); quit();
wait(); wait();
if (_socket) if (_socket) {
{
_socketIsConnected = false; _socketIsConnected = false;
_socket->deleteLater(); // Make sure delete happens on correct thread _socket->deleteLater(); // Make sure delete happens on correct thread
_socket = NULL; _socket = NULL;
emit disconnected(); emit disconnected();
} }
return true;
} }
/** /**
......
...@@ -52,6 +52,8 @@ class TCPLinkUnitTest; ...@@ -52,6 +52,8 @@ class TCPLinkUnitTest;
class TCPConfiguration : public LinkConfiguration class TCPConfiguration : public LinkConfiguration
{ {
Q_OBJECT
public: public:
/*! /*!
...@@ -164,7 +166,7 @@ private: ...@@ -164,7 +166,7 @@ private:
// From LinkInterface // From LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
bool _hardwareConnect(); bool _hardwareConnect();
void _restartConnection(); void _restartConnection();
......
...@@ -281,7 +281,7 @@ void UDPLink::readBytes() ...@@ -281,7 +281,7 @@ void UDPLink::readBytes()
* *
* @return True if connection has been disconnected, false if connection couldn't be disconnected. * @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/ **/
bool UDPLink::_disconnect(void) void UDPLink::_disconnect(void)
{ {
_running = false; _running = false;
quit(); quit();
...@@ -293,7 +293,6 @@ bool UDPLink::_disconnect(void) ...@@ -293,7 +293,6 @@ bool UDPLink::_disconnect(void)
emit disconnected(); emit disconnected();
} }
_connectState = false; _connectState = false;
return true;
} }
/** /**
......
...@@ -52,6 +52,8 @@ This file is part of the QGROUNDCONTROL project ...@@ -52,6 +52,8 @@ This file is part of the QGROUNDCONTROL project
class UDPConfiguration : public LinkConfiguration class UDPConfiguration : public LinkConfiguration
{ {
Q_OBJECT
public: public:
/*! /*!
...@@ -203,7 +205,7 @@ private: ...@@ -203,7 +205,7 @@ private:
// From LinkInterface // From LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
bool _hardwareConnect(); bool _hardwareConnect();
void _restartConnection(); void _restartConnection();
......
...@@ -158,7 +158,7 @@ bool XbeeLink::_connect(void) ...@@ -158,7 +158,7 @@ bool XbeeLink::_connect(void)
return true; return true;
} }
bool XbeeLink::_disconnect(void) void XbeeLink::_disconnect(void)
{ {
if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect
...@@ -170,7 +170,6 @@ bool XbeeLink::_disconnect(void) ...@@ -170,7 +170,6 @@ bool XbeeLink::_disconnect(void)
this->m_connected = false; this->m_connected = false;
emit disconnected(); emit disconnected();
return true;
} }
void XbeeLink::writeBytes(const char *bytes, qint64 length) // TO DO: delete the data array void XbeeLink::writeBytes(const char *bytes, qint64 length) // TO DO: delete the data array
......
...@@ -67,7 +67,7 @@ protected: ...@@ -67,7 +67,7 @@ protected:
private: private:
// From LinkInterface // From LinkInterface
virtual bool _connect(void); virtual bool _connect(void);
virtual bool _disconnect(void); virtual void _disconnect(void);
bool hardwareConnect(); bool hardwareConnect();
//void CALLTYPE portCallback(xbee_con *XbeeCon, xbee_pkt *XbeePkt); //void CALLTYPE portCallback(xbee_con *XbeeCon, xbee_pkt *XbeePkt);
......
...@@ -71,30 +71,29 @@ void LinkManagerTest::cleanup(void) ...@@ -71,30 +71,29 @@ void LinkManagerTest::cleanup(void)
void LinkManagerTest::_add_test(void) void LinkManagerTest::_add_test(void)
{ {
Q_ASSERT(_linkMgr); Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->getLinks().count() == 0); Q_ASSERT(_linkMgr->links()->count() == 0);
_connectMockLink(); _connectMockLink();
QList<LinkInterface*> links = _linkMgr->getLinks(); QCOMPARE(_linkMgr->links()->count(), 1);
QCOMPARE(links.count(), 1); QCOMPARE(_linkMgr->links()->value<MockLink*>(0), _mockLink);
QCOMPARE(dynamic_cast<MockLink*>(links[0]), _mockLink);
} }
void LinkManagerTest::_delete_test(void) void LinkManagerTest::_delete_test(void)
{ {
Q_ASSERT(_linkMgr); Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->getLinks().count() == 0); Q_ASSERT(_linkMgr->links()->count() == 0);
_connectMockLink(); _connectMockLink();
_disconnectMockLink(); _disconnectMockLink();
QCOMPARE(_linkMgr->getLinks().count(), 0); QCOMPARE(_linkMgr->links()->count(), 0);
} }
void LinkManagerTest::_addSignals_test(void) void LinkManagerTest::_addSignals_test(void)
{ {
Q_ASSERT(_linkMgr); Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->getLinks().count() == 0); Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true); Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink(); _connectMockLink();
...@@ -114,7 +113,7 @@ void LinkManagerTest::_addSignals_test(void) ...@@ -114,7 +113,7 @@ void LinkManagerTest::_addSignals_test(void)
void LinkManagerTest::_deleteSignals_test(void) void LinkManagerTest::_deleteSignals_test(void)
{ {
Q_ASSERT(_linkMgr); Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->getLinks().count() == 0); Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true); Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink(); _connectMockLink();
......
...@@ -387,7 +387,7 @@ void UnitTest::_disconnectMockLink(void) ...@@ -387,7 +387,7 @@ void UnitTest::_disconnectMockLink(void)
if (_mockLink) { if (_mockLink) {
QSignalSpy linkSpy(_linkManager, SIGNAL(linkDeleted(LinkInterface*))); QSignalSpy linkSpy(_linkManager, SIGNAL(linkDeleted(LinkInterface*)));
_linkManager->disconnectLink(_mockLink); _linkManager->disconnectLink(_mockLink, false /* disconnectAutoconnectLink */);
// Wait for link to go away // Wait for link to go away
linkSpy.wait(1000); linkSpy.wait(1000);
......
...@@ -141,12 +141,14 @@ void MAVLinkSettingsWidget::enableDroneOS(bool enable) ...@@ -141,12 +141,14 @@ void MAVLinkSettingsWidget::enableDroneOS(bool enable)
QString hostString = m_ui->droneOSComboBox->currentText(); QString hostString = m_ui->droneOSComboBox->currentText();
//QString host = hostString.split(":").first(); //QString host = hostString.split(":").first();
LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();
UDPLink* firstUdp = NULL;
// Delete from all lists first // Delete from all lists first
UDPLink* firstUdp = NULL; for (int i=0; i<linkMgr->links()->count(); i++) {
QList<LinkInterface*> links = qgcApp()->toolbox()->linkManager()->getLinks(); LinkInterface* link = linkMgr->links()->value<LinkInterface*>(i);
foreach (LinkInterface* link, links) UDPLink* udp = qobject_cast<UDPLink*>(link);
{
UDPLink* udp = dynamic_cast<UDPLink*>(link);
if (udp) if (udp)
{ {
if (!firstUdp) firstUdp = udp; if (!firstUdp) firstUdp = udp;
......
...@@ -208,10 +208,6 @@ MainWindow::MainWindow() ...@@ -208,10 +208,6 @@ MainWindow::MainWindow()
connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*))); connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
#endif //QGC_MOUSE_ENABLED_LINUX #endif //QGC_MOUSE_ENABLED_LINUX
// These also cause the screen to redraw so we need to update any OpenGL canvases in QML controls
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkConnected, this, &MainWindow::_linkStateChange);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDisconnected, this, &MainWindow::_linkStateChange);
// Connect link // Connect link
if (_autoReconnect) if (_autoReconnect)
{ {
...@@ -445,7 +441,7 @@ void MainWindow::closeEvent(QCloseEvent *event) ...@@ -445,7 +441,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes | QMessageBox::Cancel,
QMessageBox::Cancel); QMessageBox::Cancel);
if (button == QMessageBox::Yes) { if (button == QMessageBox::Yes) {
qgcApp()->toolbox()->linkManager()->disconnectAll(); qgcApp()->toolbox()->linkManager()->shutdown();
// The above disconnect causes a flurry of activity as the vehicle components are removed. This in turn // The above disconnect causes a flurry of activity as the vehicle components are removed. This in turn
// causes the Windows Version of Qt to crash if you allow the close event to be accepted. In order to prevent // causes the Windows Version of Qt to crash if you allow the close event to be accepted. In order to prevent
// the crash, we ignore the close event and setup a delayed timer to close the window after things settle down. // the crash, we ignore the close event and setup a delayed timer to close the window after things settle down.
...@@ -456,11 +452,17 @@ void MainWindow::closeEvent(QCloseEvent *event) ...@@ -456,11 +452,17 @@ void MainWindow::closeEvent(QCloseEvent *event)
return; return;
} }
// We still need to shutdown LinkManager even though no active connections so that we don't get any
// more auto-connect links during shutdown.
qgcApp()->toolbox()->linkManager()->shutdown();
// This will process any remaining flight log save dialogs // This will process any remaining flight log save dialogs
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents); qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
// Should not be any active connections // Should not be any active connections
Q_ASSERT(!qgcApp()->toolbox()->linkManager()->anyConnectedLinks()); if (qgcApp()->toolbox()->linkManager()->anyActiveLinks()) {
qWarning() << "All links should be disconnected by now";
}
// We have to pull out the QmlWidget from the main window and delete it here, before // We have to pull out the QmlWidget from the main window and delete it here, before
// the MainWindow ends up getting deleted. Otherwise the Qml has a reference to MainWindow // the MainWindow ends up getting deleted. Otherwise the Qml has a reference to MainWindow
...@@ -649,11 +651,6 @@ void MainWindow::restoreLastUsedConnection() ...@@ -649,11 +651,6 @@ void MainWindow::restoreLastUsedConnection()
} }
} }
void MainWindow::_linkStateChange(LinkInterface*)
{
emit repaintCanvas();
}
#ifdef QGC_MOUSE_ENABLED_LINUX #ifdef QGC_MOUSE_ENABLED_LINUX
bool MainWindow::x11Event(XEvent *event) bool MainWindow::x11Event(XEvent *event)
{ {
......
...@@ -159,8 +159,6 @@ signals: ...@@ -159,8 +159,6 @@ signals:
void initStatusChanged(const QString& message, int alignment, const QColor &color); void initStatusChanged(const QString& message, int alignment, const QColor &color);
/** Emitted when any value changes from any source */ /** Emitted when any value changes from any source */
void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec);
/** Emitted when any the Canvas elements within QML wudgets need updating */
void repaintCanvas();
// Used for unit tests to know when the main window closes // Used for unit tests to know when the main window closes
void mainWindowClosed(void); void mainWindowClosed(void);
...@@ -213,7 +211,6 @@ protected: ...@@ -213,7 +211,6 @@ protected:
QTimer windowNameUpdateTimer; QTimer windowNameUpdateTimer;
private slots: private slots:
void _linkStateChange(LinkInterface*);
void _closeWindow(void) { close(); } void _closeWindow(void) { close(); }
void _vehicleAdded(Vehicle* vehicle); void _vehicleAdded(Vehicle* vehicle);
......
...@@ -32,6 +32,8 @@ This file is part of the QGROUNDCONTROL project ...@@ -32,6 +32,8 @@ This file is part of the QGROUNDCONTROL project
#include "ui_QGCLinkConfiguration.h" #include "ui_QGCLinkConfiguration.h"
#include "QGCCommConfiguration.h" #include "QGCCommConfiguration.h"
#include "QGCMessageBox.h" #include "QGCMessageBox.h"
#include "UDPLink.h"
#include "TCPLink.h"
QGCLinkConfiguration::QGCLinkConfiguration(QWidget *parent) : QGCLinkConfiguration::QGCLinkConfiguration(QWidget *parent) :
QWidget(parent), QWidget(parent),
...@@ -69,14 +71,17 @@ void QGCLinkConfiguration::on_delLinkButton_clicked() ...@@ -69,14 +71,17 @@ void QGCLinkConfiguration::on_delLinkButton_clicked()
QMessageBox::Cancel); QMessageBox::Cancel);
if (button == QMessageBox::Yes) { if (button == QMessageBox::Yes) {
// Get link attached to this configuration (if any) // Get link attached to this configuration (if any)
LinkInterface* iface = config->getLink(); LinkInterface* iface = config->link();
if(iface) { if(iface) {
// Disconnect it (if connected) qgcApp()->toolbox()->linkManager()->disconnectLink(iface, false /* disconnectAutoconnectLink */);
qgcApp()->toolbox()->linkManager()->disconnectLink(iface);
} }
_viewModel->beginChange(); _viewModel->beginChange();
// Remove configuration // Remove configuration
qgcApp()->toolbox()->linkManager()->removeLinkConfiguration(config); QmlObjectListModel* linkConfigurations = qgcApp()->toolbox()->linkManager()->linkConfigurations();
linkConfigurations->removeOne(config);
delete config;
// Save list // Save list
qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList(); qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList();
_viewModel->endChange(); _viewModel->endChange();
...@@ -97,11 +102,11 @@ void QGCLinkConfiguration::on_connectLinkButton_clicked() ...@@ -97,11 +102,11 @@ void QGCLinkConfiguration::on_connectLinkButton_clicked()
if(index.row() >= 0) { if(index.row() >= 0) {
LinkConfiguration* config = _viewModel->getConfiguration(index.row()); LinkConfiguration* config = _viewModel->getConfiguration(index.row());
if(config) { if(config) {
LinkInterface* link = config->getLink(); LinkInterface* link = config->link();
if(link) { if(link) {
// Disconnect Link // Disconnect Link
if (link->isConnected()) { if (link->isConnected()) {
qgcApp()->toolbox()->linkManager()->disconnectLink(link); qgcApp()->toolbox()->linkManager()->disconnectLink(link, false /* disconnectAutoconnectLink */);
} }
} else { } else {
LinkInterface* link = qgcApp()->toolbox()->linkManager()->createConnectedLink(config); LinkInterface* link = qgcApp()->toolbox()->linkManager()->createConnectedLink(config);
...@@ -186,7 +191,7 @@ void QGCLinkConfiguration::on_addLinkButton_clicked() ...@@ -186,7 +191,7 @@ void QGCLinkConfiguration::on_addLinkButton_clicked()
if(config) { if(config) {
_fixUnnamed(config); _fixUnnamed(config);
_viewModel->beginChange(); _viewModel->beginChange();
qgcApp()->toolbox()->linkManager()->addLinkConfiguration(commDialog->getConfig()); qgcApp()->toolbox()->linkManager()->linkConfigurations()->append(commDialog->getConfig());
qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList(); qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList();
_viewModel->endChange(); _viewModel->endChange();
} }
...@@ -240,7 +245,7 @@ void QGCLinkConfiguration::_updateButtons() ...@@ -240,7 +245,7 @@ void QGCLinkConfiguration::_updateButtons()
if(config->isDynamic()) { if(config->isDynamic()) {
deleteEnabled = false; deleteEnabled = false;
} }
LinkInterface* link = config->getLink(); LinkInterface* link = config->link();
if(link) { if(link) {
_ui->connectLinkButton->setText("Disconnect"); _ui->connectLinkButton->setText("Disconnect");
} else { } else {
...@@ -261,16 +266,13 @@ LinkViewModel::LinkViewModel(QObject *parent) : QAbstractListModel(parent) ...@@ -261,16 +266,13 @@ LinkViewModel::LinkViewModel(QObject *parent) : QAbstractListModel(parent)
int LinkViewModel::rowCount( const QModelIndex & parent) const int LinkViewModel::rowCount( const QModelIndex & parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
QList<LinkConfiguration*> cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList(); return qgcApp()->toolbox()->linkManager()->linkConfigurations()->count();
int count = cfgList.count();
return count;
} }
QVariant LinkViewModel::data( const QModelIndex & index, int role) const QVariant LinkViewModel::data( const QModelIndex & index, int role) const
{ {
QList<LinkConfiguration*> cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList(); if (role == Qt::DisplayRole && index.row() < rowCount()) {
if (role == Qt::DisplayRole && index.row() < cfgList.count()) { QString name(qgcApp()->toolbox()->linkManager()->linkConfigurations()->value<LinkConfiguration*>(index.row())->name());
QString name(cfgList.at(index.row())->name());
return name; return name;
} }
return QVariant(); return QVariant();
...@@ -278,9 +280,8 @@ QVariant LinkViewModel::data( const QModelIndex & index, int role) const ...@@ -278,9 +280,8 @@ QVariant LinkViewModel::data( const QModelIndex & index, int role) const
LinkConfiguration* LinkViewModel::getConfiguration(int row) LinkConfiguration* LinkViewModel::getConfiguration(int row)
{ {
QList<LinkConfiguration*> cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList(); if(row < rowCount()) {
if(row < cfgList.count()) { return qgcApp()->toolbox()->linkManager()->linkConfigurations()->value<LinkConfiguration*>(row);
return cfgList.at(row);
} }
return NULL; return NULL;
} }
......
...@@ -490,7 +490,10 @@ void QGCMAVLinkInspector::changeStreamInterval(int msgid, int interval) ...@@ -490,7 +490,10 @@ void QGCMAVLinkInspector::changeStreamInterval(int msgid, int interval)
mavlink_message_t msg; mavlink_message_t msg;
mavlink_msg_request_data_stream_encode(_protocol->getSystemId(), _protocol->getComponentId(), &msg, &stream); mavlink_msg_request_data_stream_encode(_protocol->getSystemId(), _protocol->getComponentId(), &msg, &stream);
#if 0
// FIXME: Is this really used?
_protocol->sendMessage(msg); _protocol->sendMessage(msg);
#endif
} }
void QGCMAVLinkInspector::rateTreeItemChanged(QTreeWidgetItem* paramItem, int column) void QGCMAVLinkInspector::rateTreeItemChanged(QTreeWidgetItem* paramItem, int column)
......
...@@ -60,7 +60,7 @@ void QGCMAVLinkLogPlayer::_pause(void) ...@@ -60,7 +60,7 @@ void QGCMAVLinkLogPlayer::_pause(void)
void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void) void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void)
{ {
// Disallow replay when any links are connected // Disallow replay when any links are connected
if (qgcApp()->toolbox()->linkManager()->anyConnectedLinks()) { if (qgcApp()->toolbox()->linkManager()->anyActiveLinks()) {
QGCMessageBox::information(tr("Log Replay"), tr("You must close all connections prior to replaying a log.")); QGCMessageBox::information(tr("Log Replay"), tr("You must close all connections prior to replaying a log."));
return; return;
} }
...@@ -188,4 +188,4 @@ void QGCMAVLinkLogPlayer::_replayLinkDisconnected(void) ...@@ -188,4 +188,4 @@ void QGCMAVLinkLogPlayer::_replayLinkDisconnected(void)
{ {
_enablePlaybackControls(false); _enablePlaybackControls(false);
_replayLink = NULL; _replayLink = NULL;
} }
\ No newline at end of file
...@@ -181,6 +181,34 @@ Rectangle { ...@@ -181,6 +181,34 @@ Rectangle {
} }
} }
} }
//-----------------------------------------------------------------
//-- Autoconnect settings
QGCLabel { text: "Autoconnect to the following devices:" }
QGCCheckBox {
text: "Pixhawk"
checked: QGroundControl.linkManager.autoconnectPixhawk
onClicked: QGroundControl.linkManager.autoconnectPixhawk = checked
}
QGCCheckBox {
text: "3DR Radio"
checked: QGroundControl.linkManager.autoconnect3DRRadio
onClicked: QGroundControl.linkManager.autoconnect3DRRadio = checked
}
QGCCheckBox {
text: "PX4 Flow"
checked: QGroundControl.linkManager.autoconnectPX4Flow
onClicked: QGroundControl.linkManager.autoconnectPX4Flow = checked
}
QGCCheckBox {
text: "UDP"
checked: QGroundControl.linkManager.autoconnectUDP
onClicked: QGroundControl.linkManager.autoconnectUDP = checked
}
} }
} }
} }
...@@ -31,6 +31,7 @@ import QtQuick 2.5 ...@@ -31,6 +31,7 @@ import QtQuick 2.5
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
import QGroundControl 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0 import QGroundControl.Palette 1.0
...@@ -152,7 +153,7 @@ Rectangle { ...@@ -152,7 +153,7 @@ Rectangle {
} }
function showMavStatus() { function showMavStatus() {
return (multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout === 0 && _controller.connectionCount > 0); return (multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout === 0);
} }
Component.onCompleted: { Component.onCompleted: {
...@@ -250,7 +251,7 @@ Rectangle { ...@@ -250,7 +251,7 @@ Rectangle {
Item { Item {
visible: showMavStatus() && !connectionStatus.visible visible: showMavStatus() && !connectionStatus.visible
height: mainWindow.tbCellHeight height: mainWindow.tbCellHeight
width: (toolBar.width - viewRow.width - connectRow.width) width: (toolBar.width - viewRow.width)
anchors.left: viewRow.right anchors.left: viewRow.right
anchors.leftMargin: mainWindow.tbSpacing * 2 anchors.leftMargin: mainWindow.tbSpacing * 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
...@@ -273,125 +274,6 @@ Rectangle { ...@@ -273,125 +274,6 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Row {
id: connectRow
height: mainWindow.tbCellHeight
spacing: mainWindow.tbSpacing
anchors.rightMargin: mainWindow.tbSpacing
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Menu {
id: connectMenu
Component.onCompleted: {
_controller.configListChanged.connect(connectMenu.updateConnectionList);
connectMenu.updateConnectionList();
}
function addMenuEntry(name) {
var label = "Add Connection"
if(name !== "")
label = name;
var mItem = connectMenu.addItem(label);
var menuSlot = function() {_controller.onConnect(name)};
mItem.triggered.connect(menuSlot);
}
function updateConnectionList() {
connectMenu.clear();
for(var i = 0; i < _controller.configList.length; i++) {
connectMenu.addMenuEntry(_controller.configList[i]);
}
if(_controller.configList.length > 0) {
connectMenu.addSeparator();
}
// Add "Add Connection" to the list
connectMenu.addMenuEntry("");
}
}
Rectangle {
height: mainWindow.tbCellHeight
width: 1
color: Qt.rgba(1,1,1,0.45)
}
QGCToolBarButton {
id: connectButton
width: mainWindow.tbButtonWidth
height: mainWindow.tbCellHeight
visible: _controller.connectionCount === 0
source: "/qmlimages/Connect.svg"
checked: false
onClicked: {
checked = false
connectMenu.popup()
/*
console.log("Main Window Width: " + mainWindow.width)
console.log("Toolbar height: " + toolBar.height)
console.log("Default font: " + ScreenTools.defaultFontPixelSize)
console.log("Font (.75): " + ScreenTools.defaultFontPixelSize * 0.75)
console.log("Font (.85): " + ScreenTools.defaultFontPixelSize * 0.85)
console.log("Font 1.5): " + ScreenTools.defaultFontPixelSize * 1.5)
console.log("Default Font Width: " + ScreenTools.defaultFontPixelWidth)
console.log("Default Font Height: " + ScreenTools.defaultFontPixelHeight)
console.log("--")
console.log("Real Font Height: " + ScreenTools.realFontHeight)
console.log("fontHRatio: " + ScreenTools.fontHRatio)
console.log("--")
console.log("cellHeight: " + cellHeight)
console.log("tbFontSmall: " + tbFontSmall);
console.log("tbFontNormal: " + tbFontNormal);
console.log("tbFontLarge: " + tbFontLarge);
console.log("mainWindow.tbSpacing: " + tbSpacing);
*/
}
}
QGCToolBarButton {
id: disconnectButton
width: mainWindow.tbButtonWidth
height: mainWindow.tbCellHeight
visible: _controller.connectionCount === 1
source: "/qmlimages/Disconnect.svg"
checked: false
onClicked: {
checked = false
_controller.onDisconnect("");
}
}
Menu {
id: disconnectMenu
Component.onCompleted: {
_controller.connectedListChanged.connect(disconnectMenu.onConnectedListChanged)
}
function addMenuEntry(name) {
var mItem = disconnectMenu.addItem(name);
var menuSlot = function() {_controller.onDisconnect(name)};
mItem.triggered.connect(menuSlot);
}
function onConnectedListChanged(conList) {
disconnectMenu.clear();
for(var i = 0; i < conList.length; i++) {
disconnectMenu.addMenuEntry(conList[i]);
}
}
}
QGCToolBarButton {
id: multidisconnectButton
width: mainWindow.tbButtonWidth
height: mainWindow.tbCellHeight
visible: _controller.connectionCount > 1
source: "/qmlimages/Disconnect.svg"
checked: false
onClicked: {
checked = false
disconnectMenu.popup()
}
}
}
// Progress bar // Progress bar
Rectangle { Rectangle {
id: progressBar id: progressBar
......
...@@ -43,24 +43,14 @@ MainToolBarController::MainToolBarController(QObject* parent) ...@@ -43,24 +43,14 @@ MainToolBarController::MainToolBarController(QObject* parent)
: QObject(parent) : QObject(parent)
, _vehicle(NULL) , _vehicle(NULL)
, _mav(NULL) , _mav(NULL)
, _connectionCount(0)
, _progressBarValue(0.0f) , _progressBarValue(0.0f)
, _remoteRSSI(0)
, _remoteRSSIstore(100.0)
, _telemetryRRSSI(0) , _telemetryRRSSI(0)
, _telemetryLRSSI(0) , _telemetryLRSSI(0)
, _rollDownMessages(0) , _rollDownMessages(0)
, _toolbarMessageVisible(false) , _toolbarMessageVisible(false)
{ {
emit configListChanged();
emit connectionCountChanged(_connectionCount);
_activeVehicleChanged(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()); _activeVehicleChanged(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle());
// Link signals
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkConfigurationChanged, this, &MainToolBarController::_updateConfigurations);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkConnected, this, &MainToolBarController::_linkConnected);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDisconnected, this, &MainToolBarController::_linkDisconnected);
// RSSI (didn't like standard connection) // RSSI (didn't like standard connection)
connect(qgcApp()->toolbox()->mavlinkProtocol(), connect(qgcApp()->toolbox()->mavlinkProtocol(),
SIGNAL(radioStatusChanged(LinkInterface*, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)), this, SIGNAL(radioStatusChanged(LinkInterface*, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)), this,
...@@ -89,54 +79,6 @@ void MainToolBarController::onFlyView() ...@@ -89,54 +79,6 @@ void MainToolBarController::onFlyView()
MainWindow::instance()->showFlyView(); MainWindow::instance()->showFlyView();
} }
void MainToolBarController::onDisconnect(QString conf)
{
if(conf.isEmpty()) {
// Disconnect Only Connected Link
int connectedCount = 0;
LinkInterface* connectedLink = NULL;
QList<LinkInterface*> links = qgcApp()->toolbox()->linkManager()->getLinks();
foreach(LinkInterface* link, links) {
if (link->isConnected()) {
connectedCount++;
connectedLink = link;
}
}
Q_ASSERT(connectedCount == 1);
Q_ASSERT(_connectionCount == 1);
Q_ASSERT(connectedLink);
qgcApp()->toolbox()->linkManager()->disconnectLink(connectedLink);
} else {
// Disconnect Named Connected Link
QList<LinkInterface*> links = qgcApp()->toolbox()->linkManager()->getLinks();
foreach(LinkInterface* link, links) {
if (link->isConnected()) {
if(link->getLinkConfiguration() && link->getLinkConfiguration()->name() == conf) {
qgcApp()->toolbox()->linkManager()->disconnectLink(link);
}
}
}
}
}
void MainToolBarController::onConnect(QString conf)
{
// Connect Link
if(conf.isEmpty()) {
MainWindow::instance()->manageLinks();
} else {
// We don't want the list updating under our feet
qgcApp()->toolbox()->linkManager()->suspendConfigurationUpdates(true);
// Create a link
LinkInterface* link = qgcApp()->toolbox()->linkManager()->createConnectedLink(conf);
if(link) {
// Save last used connection
MainWindow::instance()->saveLastUsedConnection(conf);
}
qgcApp()->toolbox()->linkManager()->suspendConfigurationUpdates(false);
}
}
void MainToolBarController::onEnterMessageArea(int x, int y) void MainToolBarController::onEnterMessageArea(int x, int y)
{ {
Q_UNUSED(x); Q_UNUSED(x);
...@@ -177,7 +119,6 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle) ...@@ -177,7 +119,6 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle)
{ {
// Disconnect the previous one (if any) // Disconnect the previous one (if any)
if (_vehicle) { if (_vehicle) {
disconnect(_mav, &UASInterface::remoteControlRSSIChanged, this, &MainToolBarController::_remoteControlRSSIChanged);
disconnect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue); disconnect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue);
_mav = NULL; _mav = NULL;
_vehicle = NULL; _vehicle = NULL;
...@@ -188,109 +129,21 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle) ...@@ -188,109 +129,21 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle)
{ {
_vehicle = vehicle; _vehicle = vehicle;
_mav = vehicle->uas(); _mav = vehicle->uas();
connect(_mav, &UASInterface::remoteControlRSSIChanged, this, &MainToolBarController::_remoteControlRSSIChanged);
connect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue); connect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue);
} }
} }
void MainToolBarController::_updateConfigurations()
{
QStringList tmpList;
QList<LinkConfiguration*> configs = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList();
foreach(LinkConfiguration* conf, configs) {
if(conf) {
if(conf->isPreferred()) {
tmpList.insert(0,conf->name());
} else {
tmpList << conf->name();
}
}
}
// Any changes?
if(tmpList != _linkConfigurations) {
_linkConfigurations = tmpList;
emit configListChanged();
}
}
void MainToolBarController::_telemetryChanged(LinkInterface*, unsigned, unsigned, unsigned rssi, unsigned remrssi, unsigned, unsigned, unsigned) void MainToolBarController::_telemetryChanged(LinkInterface*, unsigned, unsigned, unsigned rssi, unsigned remrssi, unsigned, unsigned, unsigned)
{ {
// We only care if we haveone single connection if((unsigned)_telemetryLRSSI != rssi) {
if(_connectionCount == 1) { // According to the Silabs data sheet, the RSSI value is 0.5db per bit
if((unsigned)_telemetryLRSSI != rssi) { _telemetryLRSSI = rssi >> 1;
// According to the Silabs data sheet, the RSSI value is 0.5db per bit
_telemetryLRSSI = rssi >> 1;
emit telemetryLRSSIChanged(_telemetryLRSSI);
}
if((unsigned)_telemetryRRSSI != remrssi) {
// According to the Silabs data sheet, the RSSI value is 0.5db per bit
_telemetryRRSSI = remrssi >> 1;
emit telemetryRRSSIChanged(_telemetryRRSSI);
}
}
}
void MainToolBarController::_remoteControlRSSIChanged(uint8_t rssi)
{
// We only care if we have one single connection
if(_connectionCount == 1) {
// Low pass to git rid of jitter
_remoteRSSIstore = (_remoteRSSIstore * 0.9f) + ((float)rssi * 0.1);
uint8_t filteredRSSI = (uint8_t)ceil(_remoteRSSIstore);
if(_remoteRSSIstore < 0.1) {
filteredRSSI = 0;
}
if(_remoteRSSI != filteredRSSI) {
_remoteRSSI = filteredRSSI;
emit remoteRSSIChanged(_remoteRSSI);
}
}
}
void MainToolBarController::_linkConnected(LinkInterface*)
{
_updateConnection();
}
void MainToolBarController::_linkDisconnected(LinkInterface* link)
{
_updateConnection(link);
}
void MainToolBarController::_updateConnection(LinkInterface *disconnectedLink)
{
QStringList connList;
int oldCount = _connectionCount;
// If there are multiple connected links add/update the connect button menu
_connectionCount = 0;
QList<LinkInterface*> links = qgcApp()->toolbox()->linkManager()->getLinks();
foreach(LinkInterface* link, links) {
if (disconnectedLink != link && link->isConnected()) {
_connectionCount++;
if(link->getLinkConfiguration()) {
connList << link->getLinkConfiguration()->name();
}
}
}
if(oldCount != _connectionCount) {
emit connectionCountChanged(_connectionCount);
}
if(connList != _connectedList) {
_connectedList = connList;
emit connectedListChanged(_connectedList);
}
// Update telemetry RSSI display
if(_connectionCount != 1 && _telemetryRRSSI > 0) {
_telemetryRRSSI = 0;
emit telemetryRRSSIChanged(_telemetryRRSSI);
}
if(_connectionCount != 1 && _telemetryLRSSI > 0) {
_telemetryLRSSI = 0;
emit telemetryLRSSIChanged(_telemetryLRSSI); emit telemetryLRSSIChanged(_telemetryLRSSI);
} }
if(_connectionCount != 1 && _remoteRSSI > 0) { if((unsigned)_telemetryRRSSI != remrssi) {
_remoteRSSI = 0; // According to the Silabs data sheet, the RSSI value is 0.5db per bit
emit remoteRSSIChanged(_remoteRSSI); _telemetryRRSSI = remrssi >> 1;
emit telemetryRRSSIChanged(_telemetryRRSSI);
} }
} }
...@@ -344,3 +197,8 @@ void MainToolBarController::showSettings(void) ...@@ -344,3 +197,8 @@ void MainToolBarController::showSettings(void)
{ {
MainWindow::instance()->showSettings(); MainWindow::instance()->showSettings();
} }
void MainToolBarController::manageLinks(void)
{
MainWindow::instance()->manageLinks();
}
...@@ -53,35 +53,24 @@ public: ...@@ -53,35 +53,24 @@ public:
Q_INVOKABLE void onSetupView(); Q_INVOKABLE void onSetupView();
Q_INVOKABLE void onPlanView(); Q_INVOKABLE void onPlanView();
Q_INVOKABLE void onFlyView(); Q_INVOKABLE void onFlyView();
Q_INVOKABLE void onConnect(QString conf);
Q_INVOKABLE void onDisconnect(QString conf);
Q_INVOKABLE void onEnterMessageArea(int x, int y); Q_INVOKABLE void onEnterMessageArea(int x, int y);
Q_INVOKABLE void onToolBarMessageClosed(void); Q_INVOKABLE void onToolBarMessageClosed(void);
Q_INVOKABLE void showSettings(void); Q_INVOKABLE void showSettings(void);
Q_INVOKABLE void manageLinks(void);
Q_PROPERTY(double height MEMBER _toolbarHeight NOTIFY heightChanged) Q_PROPERTY(double height MEMBER _toolbarHeight NOTIFY heightChanged)
Q_PROPERTY(QStringList configList MEMBER _linkConfigurations NOTIFY configListChanged)
Q_PROPERTY(int connectionCount READ connectionCount NOTIFY connectionCountChanged)
Q_PROPERTY(QStringList connectedList MEMBER _connectedList NOTIFY connectedListChanged)
Q_PROPERTY(float progressBarValue MEMBER _progressBarValue NOTIFY progressBarValueChanged) Q_PROPERTY(float progressBarValue MEMBER _progressBarValue NOTIFY progressBarValueChanged)
Q_PROPERTY(int remoteRSSI READ remoteRSSI NOTIFY remoteRSSIChanged)
Q_PROPERTY(int telemetryRRSSI READ telemetryRRSSI NOTIFY telemetryRRSSIChanged) Q_PROPERTY(int telemetryRRSSI READ telemetryRRSSI NOTIFY telemetryRRSSIChanged)
Q_PROPERTY(int telemetryLRSSI READ telemetryLRSSI NOTIFY telemetryLRSSIChanged) Q_PROPERTY(int telemetryLRSSI READ telemetryLRSSI NOTIFY telemetryLRSSIChanged)
void viewStateChanged (const QString& key, bool value); void viewStateChanged (const QString& key, bool value);
int remoteRSSI () { return _remoteRSSI; }
int telemetryRRSSI () { return _telemetryRRSSI; } int telemetryRRSSI () { return _telemetryRRSSI; }
int telemetryLRSSI () { return _telemetryLRSSI; } int telemetryLRSSI () { return _telemetryLRSSI; }
int connectionCount () { return _connectionCount; }
void showToolBarMessage(const QString& message); void showToolBarMessage(const QString& message);
signals: signals:
void connectionCountChanged (int count);
void configListChanged ();
void connectedListChanged (QStringList connectedList);
void progressBarValueChanged (float value); void progressBarValueChanged (float value);
void remoteRSSIChanged (int value);
void telemetryRRSSIChanged (int value); void telemetryRRSSIChanged (int value);
void telemetryLRSSIChanged (int value); void telemetryLRSSIChanged (int value);
void heightChanged (double height); void heightChanged (double height);
...@@ -91,26 +80,15 @@ signals: ...@@ -91,26 +80,15 @@ signals:
private slots: private slots:
void _activeVehicleChanged (Vehicle* vehicle); void _activeVehicleChanged (Vehicle* vehicle);
void _updateConfigurations ();
void _linkConnected (LinkInterface* link);
void _linkDisconnected (LinkInterface* link);
void _leaveMessageView (); void _leaveMessageView ();
void _setProgressBarValue (float value); void _setProgressBarValue (float value);
void _remoteControlRSSIChanged (uint8_t rssi);
void _telemetryChanged (LinkInterface* link, unsigned rxerrors, unsigned fixed, unsigned rssi, unsigned remrssi, unsigned txbuf, unsigned noise, unsigned remnoise); void _telemetryChanged (LinkInterface* link, unsigned rxerrors, unsigned fixed, unsigned rssi, unsigned remrssi, unsigned txbuf, unsigned noise, unsigned remnoise);
void _delayedShowToolBarMessage (void); void _delayedShowToolBarMessage (void);
private:
void _updateConnection (LinkInterface *disconnectedLink = NULL);
private: private:
Vehicle* _vehicle; Vehicle* _vehicle;
UASInterface* _mav; UASInterface* _mav;
QStringList _linkConfigurations;
int _connectionCount;
QStringList _connectedList;
float _progressBarValue; float _progressBarValue;
int _remoteRSSI;
double _remoteRSSIstore; double _remoteRSSIstore;
int _telemetryRRSSI; int _telemetryRRSSI;
int _telemetryLRSSI; int _telemetryLRSSI;
......
...@@ -219,12 +219,12 @@ Row { ...@@ -219,12 +219,12 @@ Row {
smooth: true smooth: true
width: mainWindow.tbCellHeight * 0.65 width: mainWindow.tbCellHeight * 0.65
height: mainWindow.tbCellHeight * 0.5 height: mainWindow.tbCellHeight * 0.5
opacity: _controller.remoteRSSI < 1 ? 0.5 : 1 opacity: activeVehicle.rcRSSI < 1 ? 0.5 : 1
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
SignalStrength { SignalStrength {
size: mainWindow.tbCellHeight * 0.5 size: mainWindow.tbCellHeight * 0.5
percent: _controller.remoteRSSI percent: activeVehicle.rcRSSI
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
...@@ -284,10 +284,11 @@ Row { ...@@ -284,10 +284,11 @@ Row {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
//-- Vehicle Selector //-- Vehicle Selector
QGCButton { QGCButton {
width: ScreenTools.defaultFontPixelSize * 12 id: vehicleSelectorButton
height: mainWindow.tbButtonWidth width: ScreenTools.defaultFontPixelSize * 12
text: "Vehicle " + activeVehicle.id height: mainWindow.tbButtonWidth
visible: vehicleMenuItems.length > 0 text: "Vehicle " + activeVehicle.id
visible: QGroundControl.multiVehicleManager.vehicles.count > 1
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
menu: vehicleMenu menu: vehicleMenu
...@@ -331,7 +332,7 @@ Row { ...@@ -331,7 +332,7 @@ Row {
Connections { Connections {
target: multiVehicleManager.vehicles target: multiVehicleManager.vehicles
onCountChanged: parent.updateVehicleMenu onCountChanged: vehicleSelectorButton.updateVehicleMenu
} }
} }
......
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