diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index b3ba1acf4d8fc9551c8fbcdd7156a19b46265439..5a866dc2ec2b9ced7a0d70321519b94306c40e84 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -270,7 +270,6 @@ HEADERS += \
src/QmlControls/QGCQGeoCoordinate.h \
src/QmlControls/QGroundControlQmlGlobal.h \
src/QmlControls/QmlObjectListModel.h \
- src/SerialPortIds.h \
src/uas/FileManager.h \
src/uas/UAS.h \
src/uas/UASInterface.h \
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 176c47811750253476752f9905a47b43ad3e5ea3..dcaa8a389e5fe9c86874413a06fabb375b1be361 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -28,7 +28,6 @@
src/AutoPilotPlugins/PX4/PowerComponent.qml
src/AutoPilotPlugins/PX4/PowerComponentSummary.qml
src/VehicleSetup/PX4FlowSensor.qml
-
src/QmlControls/ClickableColor.qml
src/QmlControls/DropButton.qml
src/QmlControls/ExclusiveGroupItem.qml
@@ -42,7 +41,6 @@
src/QmlControls/ParameterEditor.qml
src/QmlControls/ParameterEditorDialog.qml
src/QmlControls/QGCButton.qml
- src/QmlControls/QGCCanvas.qml
src/QmlControls/QGCCheckBox.qml
src/QmlControls/QGCColoredImage.qml
src/QmlControls/QGCComboBox.qml
@@ -62,20 +60,17 @@
src/QmlControls/VehicleRotationCal.qml
src/QmlControls/VehicleSummaryRow.qml
src/ViewWidgets/ViewWidget.qml
-
src/FactSystem/FactControls/FactCheckBox.qml
src/FactSystem/FactControls/FactComboBox.qml
src/FactSystem/FactControls/FactLabel.qml
src/FactSystem/FactControls/FactPanel.qml
src/FactSystem/FactControls/FactTextField.qml
src/FactSystem/FactControls/qmldir
-
src/FlightDisplay/FlightDisplayView.qml
src/FlightDisplay/FlightDisplayViewMap.qml
src/FlightDisplay/FlightDisplayViewVideo.qml
src/FlightDisplay/FlightDisplayViewWidgets.qml
src/FlightDisplay/qmldir
-
src/FlightMap/FlightMap.qml
src/FlightMap/MapItems/MissionItemIndicator.qml
src/FlightMap/MapItems/MissionItemView.qml
@@ -90,10 +85,8 @@
src/FlightMap/QGCVideoBackground.qml
src/FlightMap/qmldir
src/FlightMap/MapItems/VehicleMapItem.qml
-
src/QmlControls/QGroundControl.ScreenTools.qmldir
src/QmlControls/ScreenTools.qml
-
src/QmlControls/QmlTest.qml
src/AutoPilotPlugins/PX4/RadioComponent.qml
src/AutoPilotPlugins/PX4/RadioComponentSummary.qml
diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc
index 757c64d9817cb928e65eb4159077687c73950256..8cc0f058aa477b6f12d5bcd5a79fc8f2d61c75cd 100644
--- a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc
+++ b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc
@@ -139,7 +139,7 @@ void AirframeComponentController::_rebootAfterStackUnwind(void)
QGC::SLEEP::usleep(500);
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
}
- qgcApp()->toolbox()->linkManager()->disconnectAll();
+ qgcApp()->toolbox()->linkManager()->disconnectAll(false /* disconnectAutoconnectLink */);
qgcApp()->restoreOverrideCursor();
}
diff --git a/src/HomePositionManager.cc b/src/HomePositionManager.cc
index 01f39b4ddcb20ce7d5289d32de9b9f6634728d56..f478c670b3173fa6d63dc1990cd9e9ee4d694b3e 100644
--- a/src/HomePositionManager.cc
+++ b/src/HomePositionManager.cc
@@ -50,14 +50,13 @@ HomePositionManager::HomePositionManager(QGCApplication* app)
, homeLon(8.549444)
, homeAlt(470.0)
{
-
+ qmlRegisterUncreatableType ("QGroundControl", 1, 0, "HomePositionManager", "Reference only");
}
void HomePositionManager::setToolbox(QGCToolbox *toolbox)
{
QGCTool::setToolbox(toolbox);
- qmlRegisterUncreatableType ("QGroundControl", 1, 0, "HomePositionManager", "Reference only");
_loadSettings();
}
diff --git a/src/QmlControls/DropButton.qml b/src/QmlControls/DropButton.qml
index b39cb29636706da2131ca2993aeaab8542b68553..281ff7ed8cc1f6a27e31e195a70a06ec406c6943 100644
--- a/src/QmlControls/DropButton.qml
+++ b/src/QmlControls/DropButton.qml
@@ -184,7 +184,7 @@ Item {
id: dropDownItem
visible: checked
- QGCCanvas {
+ Canvas {
id: arrowCanvas
anchors.fill: parent
diff --git a/src/QmlControls/QGCCanvas.qml b/src/QmlControls/QGCCanvas.qml
deleted file mode 100644
index c7f0a12d935606ef803012452333d4b7448b1e46..0000000000000000000000000000000000000000
--- a/src/QmlControls/QGCCanvas.qml
+++ /dev/null
@@ -1,19 +0,0 @@
-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()
- }
-}
diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir
index 0b96e795252fe5c083c87f8862025826f6dae4af..adad5682f0c06d1b27c94cbef7545cd06c13b6fd 100644
--- a/src/QmlControls/QGroundControl.Controls.qmldir
+++ b/src/QmlControls/QGroundControl.Controls.qmldir
@@ -9,7 +9,6 @@ QGCComboBox 1.0 QGCComboBox.qml
QGCColoredImage 1.0 QGCColoredImage.qml
QGCToolBarButton 1.0 QGCToolBarButton.qml
QGCMovableItem 1.0 QGCMovableItem.qml
-QGCCanvas 1.0 QGCCanvas.qml
SubMenuButton 1.0 SubMenuButton.qml
IndicatorButton 1.0 IndicatorButton.qml
diff --git a/src/QmlControls/QGroundControlQmlGlobal.cc b/src/QmlControls/QGroundControlQmlGlobal.cc
index 7563fe1b24851cf181fc2fa72a08246f2553a33f..6b38b01db0efc6d9473eca96c46d4e694a259b7a 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.cc
+++ b/src/QmlControls/QGroundControlQmlGlobal.cc
@@ -33,6 +33,8 @@ static const char* kQmlGlobalKeyName = "QGCQml";
QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCToolbox* toolbox, QObject* parent)
: QObject(parent)
+ , _multiVehicleManager(toolbox->multiVehicleManager())
+ , _linkManager(toolbox->linkManager())
, _homePositionManager(toolbox->homePositionManager())
, _flightMapSettings(toolbox->flightMapSettings())
{
@@ -70,25 +72,25 @@ bool QGroundControlQmlGlobal::loadBoolGlobalSetting (const QString& key, bool de
#ifdef QT_DEBUG
void QGroundControlQmlGlobal::_startMockLink(MockConfiguration* mockConfig)
{
- MockLink* mockLink = new MockLink(mockConfig);
-
LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
- linkManager->_addLink(mockLink);
- linkManager->connectLink(mockLink);
+ mockConfig->setDynamic(true);
+ linkManager->linkConfigurations()->append(mockConfig);
+
+ linkManager->createConnectedLink(mockConfig, false /* autoconnectLink */);
}
#endif
void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText)
{
#ifdef QT_DEBUG
- MockConfiguration mockConfig("PX4 MockLink");
+ MockConfiguration* mockConfig = new MockConfiguration("PX4 MockLink");
- mockConfig.setFirmwareType(MAV_AUTOPILOT_PX4);
- mockConfig.setVehicleType(MAV_TYPE_QUADROTOR);
- mockConfig.setSendStatusText(sendStatusText);
+ mockConfig->setFirmwareType(MAV_AUTOPILOT_PX4);
+ mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
+ mockConfig->setSendStatusText(sendStatusText);
- _startMockLink(&mockConfig);
+ _startMockLink(mockConfig);
#else
Q_UNUSED(sendStatusText);
#endif
@@ -97,13 +99,13 @@ void QGroundControlQmlGlobal::startPX4MockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText)
{
#ifdef QT_DEBUG
- MockConfiguration mockConfig("Generic MockLink");
+ MockConfiguration* mockConfig = new MockConfiguration("Generic MockLink");
- mockConfig.setFirmwareType(MAV_AUTOPILOT_GENERIC);
- mockConfig.setVehicleType(MAV_TYPE_QUADROTOR);
- mockConfig.setSendStatusText(sendStatusText);
+ mockConfig->setFirmwareType(MAV_AUTOPILOT_GENERIC);
+ mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
+ mockConfig->setSendStatusText(sendStatusText);
- _startMockLink(&mockConfig);
+ _startMockLink(mockConfig);
#else
Q_UNUSED(sendStatusText);
#endif
@@ -112,13 +114,13 @@ void QGroundControlQmlGlobal::startGenericMockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText)
{
#ifdef QT_DEBUG
- MockConfiguration mockConfig("APM ArduCopter MockLink");
+ MockConfiguration* mockConfig = new MockConfiguration("APM ArduCopter MockLink");
- mockConfig.setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
- mockConfig.setVehicleType(MAV_TYPE_QUADROTOR);
- mockConfig.setSendStatusText(sendStatusText);
+ mockConfig->setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
+ mockConfig->setVehicleType(MAV_TYPE_QUADROTOR);
+ mockConfig->setSendStatusText(sendStatusText);
- _startMockLink(&mockConfig);
+ _startMockLink(mockConfig);
#else
Q_UNUSED(sendStatusText);
#endif
@@ -127,13 +129,13 @@ void QGroundControlQmlGlobal::startAPMArduCopterMockLink(bool sendStatusText)
void QGroundControlQmlGlobal::startAPMArduPlaneMockLink(bool sendStatusText)
{
#ifdef QT_DEBUG
- MockConfiguration mockConfig("APM ArduPlane MockLink");
+ MockConfiguration* mockConfig = new MockConfiguration("APM ArduPlane MockLink");
- mockConfig.setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
- mockConfig.setVehicleType(MAV_TYPE_FIXED_WING);
- mockConfig.setSendStatusText(sendStatusText);
+ mockConfig->setFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
+ mockConfig->setVehicleType(MAV_TYPE_FIXED_WING);
+ mockConfig->setSendStatusText(sendStatusText);
- _startMockLink(&mockConfig);
+ _startMockLink(mockConfig);
#else
Q_UNUSED(sendStatusText);
#endif
@@ -144,12 +146,12 @@ void QGroundControlQmlGlobal::stopAllMockLinks(void)
#ifdef QT_DEBUG
LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
- QList links = linkManager->getLinks();
- for (int i=0; ilinks()->count(); i++) {
+ LinkInterface* link = linkManager->links()->value(i);
MockLink* mockLink = qobject_cast(link);
+
if (mockLink) {
- linkManager->disconnectLink(mockLink);
+ linkManager->disconnectLink(mockLink, false /* disconnectAutoconnectLink */);
}
}
#endif
diff --git a/src/QmlControls/QGroundControlQmlGlobal.h b/src/QmlControls/QGroundControlQmlGlobal.h
index eafc1454e051d9d04a2c25721eed476535604f27..269c3b89e4acc01a8d77145c0fae41cd4a941aa0 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.h
+++ b/src/QmlControls/QGroundControlQmlGlobal.h
@@ -31,6 +31,7 @@
#include "QGCApplication.h"
#include "MainWindow.h"
+#include "LinkManager.h"
#include "HomePositionManager.h"
#include "FlightMapSettings.h"
@@ -47,6 +48,8 @@ class QGroundControlQmlGlobal : public QObject
public:
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(FlightMapSettings* flightMapSettings READ flightMapSettings CONSTANT)
@@ -81,6 +84,8 @@ public:
// Property accesors
+ LinkManager* linkManager () { return _linkManager; }
+ MultiVehicleManager* multiVehicleManager () { return _multiVehicleManager; }
HomePositionManager* homePositionManager () { return _homePositionManager; }
FlightMapSettings* flightMapSettings () { return _flightMapSettings; }
@@ -124,6 +129,8 @@ private:
void _startMockLink(MockConfiguration* mockConfig);
#endif
+ MultiVehicleManager* _multiVehicleManager;
+ LinkManager* _linkManager;
HomePositionManager* _homePositionManager;
FlightMapSettings* _flightMapSettings;
};
diff --git a/src/QmlControls/QmlObjectListModel.cc b/src/QmlControls/QmlObjectListModel.cc
index 5ab27884440b5bdcf559c1df0ee4753a26edcb96..1e510c81f353190298fcc6db6b8ca8367183e6ea 100644
--- a/src/QmlControls/QmlObjectListModel.cc
+++ b/src/QmlControls/QmlObjectListModel.cc
@@ -197,11 +197,6 @@ int QmlObjectListModel::count(void) const
return rowCount();
}
-QObject* QmlObjectListModel::get(int index)
-{
- return _objectList[index];
-}
-
void QmlObjectListModel::setDirty(bool dirty)
{
_dirty = dirty;
diff --git a/src/QmlControls/QmlObjectListModel.h b/src/QmlControls/QmlObjectListModel.h
index 2e8d1bd8d8803f6a73894a6f2d41cc1e0cd58cf1..8e64d0f49b167ddf07254f3935f36721783c7576 100644
--- a/src/QmlControls/QmlObjectListModel.h
+++ b/src/QmlControls/QmlObjectListModel.h
@@ -34,14 +34,14 @@ public:
QmlObjectListModel(QObject* parent = NULL);
~QmlObjectListModel();
- Q_INVOKABLE QObject* get(int index);
-
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
/// a dirty property and dirtyChanged signal.
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
+ Q_INVOKABLE QObject* get(int index) { return _objectList[index]; }
+
// Property accessors
int count(void) const;
@@ -52,13 +52,14 @@ public:
void append(QObject* object);
void clear(void);
QObject* removeAt(int i);
+ QObject* removeOne(QObject* object) { return removeAt(indexOf(object)); }
void insert(int i, QObject* object);
QObject* operator[](int i);
const QObject* operator[](int i) const;
-
- template
- const QList& list(void) { return *((QList*)((void*)(&_objectList))); }
-
+ bool contains(QObject* object) { return _objectList.indexOf(object) != -1; }
+ int indexOf(QObject* object) { return _objectList.indexOf(object); }
+ template T value(int index) { return qobject_cast(_objectList[index]); }
+
signals:
void countChanged(int count);
void dirtyChanged(bool dirtyChanged);
diff --git a/src/QmlControls/ScreenTools.qml b/src/QmlControls/ScreenTools.qml
index 03863da4c667e2289ce35d988e81ee99bfeff091..ba0d959174f0bc74eb8c0378a850ca0029aa059b 100644
--- a/src/QmlControls/ScreenTools.qml
+++ b/src/QmlControls/ScreenTools.qml
@@ -47,9 +47,4 @@ Item {
property real fontWidth: contentWidth * (ScreenToolsController.testHighDPI ? 2 : 1)
property real fontHeight: contentHeight * (ScreenToolsController.testHighDPI ? 2 : 1)
}
-
- Connections {
- target: ScreenToolsController
- onRepaintRequested: repaintRequested()
- }
}
diff --git a/src/QmlControls/ScreenToolsController.cc b/src/QmlControls/ScreenToolsController.cc
index a20c8dad4bc50e41b52f8c26686a2ee899e8a620..9380bf7cf0052f8a50c430cecaa520675022eef1 100644
--- a/src/QmlControls/ScreenToolsController.cc
+++ b/src/QmlControls/ScreenToolsController.cc
@@ -43,15 +43,5 @@ const double ScreenToolsController::_largeFontPixelSizeRatio = 1.66;
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();
}
-
diff --git a/src/QmlControls/ScreenToolsController.h b/src/QmlControls/ScreenToolsController.h
index 004d1fd41ab09487115db2ef8654d63a7eed9949..6d8807f69f905918db0210de72a68467abb4b001 100644
--- a/src/QmlControls/ScreenToolsController.h
+++ b/src/QmlControls/ScreenToolsController.h
@@ -114,12 +114,6 @@ public:
bool testHighDPI () { return false; }
#endif
-signals:
- void repaintRequested();
-
-private slots:
- void _updateCanvas();
-
private:
static const double _defaultFontPixelSizeRatio;
static const double _smallFontPixelSizeRatio;
diff --git a/src/Vehicle/MultiVehicleManager.cc b/src/Vehicle/MultiVehicleManager.cc
index 0416ea6bafdd463e029f5955de969785cd606464..7e5cdbfa2406b9b1f19bffed3e22e07494e5fe83 100644
--- a/src/Vehicle/MultiVehicleManager.cc
+++ b/src/Vehicle/MultiVehicleManager.cc
@@ -57,33 +57,26 @@ void MultiVehicleManager::setToolbox(QGCToolbox *toolbox)
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType("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 (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 && 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;
- }
+ if (!getVehicleById(vehicleId)) {
+ qCDebug(MultiVehicleManagerLog) << "Adding new vehicle linkName:vehicleId:vehicleFirmwareType:vehicleType"
+ << link->getName()
+ << vehicleId
+ << vehicleFirmwareType
+ << vehicleType;
- 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) {
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);
_vehicles.append(vehicle);
@@ -92,22 +85,20 @@ bool MultiVehicleManager::notifyHeartbeatInfo(LinkInterface* link, int vehicleId
setActiveVehicle(vehicle);
}
-
- return true;
}
/// 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.
void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle)
{
- qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase1";
+ qCDebug(MultiVehicleManagerLog) << "_deleteVehiclePhase1" << vehicle;
- _vehicleBeingDeleted = vehicle;
+ _vehiclesBeingDeleted << vehicle;
// Remove from map
bool found = false;
for (int i=0; i<_vehicles.count(); i++) {
- if (_vehicles[i] == _vehicleBeingDeleted) {
+ if (_vehicles[i] == vehicle) {
_vehicles.removeAt(i);
found = true;
break;
@@ -136,9 +127,9 @@ void MultiVehicleManager::_deleteVehiclePhase1(Vehicle* vehicle)
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.
/// This means we can now clear the active vehicle property and delete the Vehicle for real.
@@ -159,7 +150,8 @@ void MultiVehicleManager::_deleteVehiclePhase2 (void)
}
}
- _vehicleBeingDeleted->deleteLater();
+ delete _vehiclesBeingDeleted[0];
+ _vehiclesBeingDeleted.removeAt(0);
}
void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle)
@@ -189,7 +181,7 @@ void MultiVehicleManager::setActiveVehicle(Vehicle* vehicle)
void MultiVehicleManager::_setActiveVehiclePhase2(void)
{
- qCDebug(MultiVehicleManagerLog) << "_setActiveVehiclePhase2";
+ qCDebug(MultiVehicleManagerLog) << "_setActiveVehiclePhase2 _vehicleBeingSetActive" << _vehicleBeingSetActive;
// Now we signal the new active vehicle
_activeVehicle = _vehicleBeingSetActive;
diff --git a/src/Vehicle/MultiVehicleManager.h b/src/Vehicle/MultiVehicleManager.h
index 0b85ee3a4bf88c2e1dab0df9985525177e6c9c8e..f5101df9daa70830057301412e439beb4bbfe243 100644
--- a/src/Vehicle/MultiVehicleManager.h
+++ b/src/Vehicle/MultiVehicleManager.h
@@ -58,14 +58,6 @@ public:
// 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);
UAS* activeUas(void) { return _activeVehicle ? _activeVehicle->uas() : NULL; }
@@ -98,6 +90,7 @@ private slots:
void _deleteVehiclePhase2(void);
void _setActiveVehiclePhase2(void);
void _autopilotParametersReadyChanged(bool parametersReady);
+ void _linkActive(LinkInterface* link, int vehicleId, int vehicleFirmwareType, int vehicleType);
private:
bool _vehicleExists(int vehicleId);
@@ -106,8 +99,8 @@ private:
bool _parameterReadyVehicleAvailable; ///< true: An active vehicle with ready parameters is available
Vehicle* _activeVehicle; ///< Currently active vehicle from a ui perspective
- Vehicle* _vehicleBeingDeleted; ///< Vehicle being deleted in queued phases
- Vehicle* _vehicleBeingSetActive; ///< Vehicle being set active in queued phases
+ QList _vehiclesBeingDeleted; ///< List of Vehicles being deleted in queued phases
+ Vehicle* _vehicleBeingSetActive; ///< Vehicle being set active in queued phases
QList _ignoreVehicleIds; ///< List of vehicle id for which we ignore further communication
diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc
index 339006dadac774bb75004ec8ed06d1b6070b35aa..938a90045b3d9a514d89251a79e6d6ba4afefd98 100644
--- a/src/Vehicle/Vehicle.cc
+++ b/src/Vehicle/Vehicle.cc
@@ -94,6 +94,8 @@ Vehicle::Vehicle(LinkInterface* link,
, _satelliteCount(-1)
, _satelliteLock(0)
, _updateCount(0)
+ , _rcRSSI(0)
+ , _rcRSSIstore(100.0)
, _missionManager(NULL)
, _missionManagerInitialRequestComplete(false)
, _parameterLoader(NULL)
@@ -106,6 +108,7 @@ Vehicle::Vehicle(LinkInterface* link,
, _autopilotPluginManager(autopilotPluginManager)
, _joystickManager(joystickManager)
, _flowImageIndex(0)
+ , _allLinksInactiveSent(false)
{
_addLink(link);
@@ -119,9 +122,10 @@ Vehicle::Vehicle(LinkInterface* link,
setLatitude(_uas->getLatitude());
setLongitude(_uas->getLongitude());
- connect(_uas, &UAS::latitudeChanged, this, &Vehicle::setLatitude);
- connect(_uas, &UAS::longitudeChanged, this, &Vehicle::setLongitude);
- connect(_uas, &UAS::imageReady, this, &Vehicle::_imageReady);
+ connect(_uas, &UAS::latitudeChanged, this, &Vehicle::setLatitude);
+ connect(_uas, &UAS::longitudeChanged, this, &Vehicle::setLongitude);
+ connect(_uas, &UAS::imageReady, this, &Vehicle::_imageReady);
+ connect(_uas, &UAS::remoteControlRSSIChanged, this, &Vehicle::_remoteControlRSSIChanged);
_firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType);
_autopilotPlugin = _autopilotPluginManager->newAutopilotPluginForVehicle(this);
@@ -186,6 +190,8 @@ Vehicle::Vehicle(LinkInterface* link,
Vehicle::~Vehicle()
{
+ qCDebug(VehicleLog) << "~Vehicle" << this;
+
delete _missionManager;
_missionManager = NULL;
@@ -285,38 +291,29 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message)
bool Vehicle::_containsLink(LinkInterface* link)
{
- foreach (SharedLinkInterface sharedLink, _links) {
- if (sharedLink.data() == link) {
- return true;
- }
- }
-
- return false;
+ return _links.contains(link);
}
void Vehicle::_addLink(LinkInterface* link)
{
if (!_containsLink(link)) {
- _links += qgcApp()->toolbox()->linkManager()->sharedPointerForLink(link);
+ _links += link;
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) << "link count:" << _links.count();
+ qCDebug(VehicleLog) << "_linkInactiveOrDeleted linkCount" << _links.count();
- for (int i=0; i<_links.count(); i++) {
- if (_links[i].data() == link) {
- _links.removeAt(i);
- break;
- }
- }
+ _links.removeOne(link);
- if (_links.count() == 0) {
- emit allLinksDisconnected(this);
+ if (_links.count() == 0 && !_allLinksInactiveSent) {
+ // 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)
void Vehicle::_sendMessage(mavlink_message_t message)
{
// Emit message on all links that are currently connected
- foreach (SharedLinkInterface sharedLink, _links) {
- LinkInterface* link = sharedLink.data();
- Q_ASSERT(link);
-
+ foreach (LinkInterface* link, _links) {
if (link->isConnected()) {
MAVLinkProtocol* mavlink = _mavlink;
@@ -350,17 +344,6 @@ void Vehicle::_sendMessage(mavlink_message_t message)
}
}
-QList Vehicle::links(void)
-{
- QList list;
-
- foreach (SharedLinkInterface sharedLink, _links) {
- list += sharedLink.data();
- }
-
- return list;
-}
-
void Vehicle::setLatitude(double latitude)
{
_coordinate.setLatitude(latitude);
@@ -1035,11 +1018,11 @@ void Vehicle::_parametersReady(bool parametersReady)
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();
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*)
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);
+ }
+}
diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h
index b41f86855868f4a02e9b1749f63a57542a0f8f56..9a844669e09a8c6ff5a8abfae0e118a25e4eb2a9 100644
--- a/src/Vehicle/Vehicle.h
+++ b/src/Vehicle/Vehicle.h
@@ -107,6 +107,7 @@ public:
Q_PROPERTY(bool joystickEnabled READ joystickEnabled WRITE setJoystickEnabled NOTIFY joystickEnabledChanged)
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
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
/// message. For example PX4 Flight Stack reserves the first 8 buttons to simulate rc switches.
@@ -166,8 +167,6 @@ public:
/// Provides access to the Firmware Plugin for this Vehicle
FirmwarePlugin* firmwarePlugin(void) { return _firmwarePlugin; }
- QList links(void);
-
int manualControlReservedButtonCount(void);
MissionManager* missionManager(void) { return _missionManager; }
@@ -245,6 +244,7 @@ public:
QString currentState () { return _currentState; }
int satelliteLock () { return _satelliteLock; }
unsigned int heartbeatTimeout () { return _currentHeartbeatTimeout; }
+ int rcRSSI () { return _rcRSSI; }
ParameterLoader* getParameterLoader(void);
@@ -253,7 +253,7 @@ public slots:
void setLongitude(double longitude);
signals:
- void allLinksDisconnected(Vehicle* vehicle);
+ void allLinksInactive(Vehicle* vehicle);
void coordinateChanged(QGeoCoordinate coordinate);
void coordinateValidChanged(bool coordinateValid);
void joystickModeChanged(int mode);
@@ -293,15 +293,17 @@ signals:
void currentStateChanged ();
void satelliteLockChanged ();
void flowImageIndexChanged ();
+ void rcRSSIChanged (int rcRSSI);
private slots:
void _mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message);
- void _linkDisconnected(LinkInterface* link);
+ void _linkInactiveOrDeleted(LinkInterface* link);
void _sendMessage(mavlink_message_t message);
void _sendMessageMultipleNext(void);
void _addNewMapTrajectoryPoint(void);
void _parametersReady(bool parametersReady);
void _communicationInactivityTimedOut(void);
+ void _remoteControlRSSIChanged(uint8_t rssi);
void _handleTextMessage (int newCount);
/** @brief Attitude from main autopilot / system state */
@@ -347,10 +349,7 @@ private:
AutoPilotPlugin* _autopilotPlugin;
MAVLinkProtocol* _mavlink;
- /// List of all links associated with this vehicle. We keep SharedLinkInterface objects
- /// which are QSharedPointer's in order to maintain reference counts across threads.
- /// This way Link deletion works correctly.
- QList _links;
+ QList _links;
JoystickMode_t _joystickMode;
bool _joystickEnabled;
@@ -394,6 +393,8 @@ private:
int _satelliteCount;
int _satelliteLock;
int _updateCount;
+ int _rcRSSI;
+ double _rcRSSIstore;
MissionManager* _missionManager;
bool _missionManagerInitialRequestComplete;
@@ -434,6 +435,8 @@ private:
int _flowImageIndex;
+ bool _allLinksInactiveSent; ///< true: allLinkInactive signal already sent one time
+
// Settings keys
static const char* _settingsGroup;
static const char* _joystickModeSettingsKey;
diff --git a/src/VehicleSetup/FirmwareUpgrade.qml b/src/VehicleSetup/FirmwareUpgrade.qml
index 617254df6ff2766c8f67f268949fb3d56abb8897..96a01a4719a10ee61ade9d6bff3ffcb4aeba91b7 100644
--- a/src/VehicleSetup/FirmwareUpgrade.qml
+++ b/src/VehicleSetup/FirmwareUpgrade.qml
@@ -26,12 +26,13 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
-import QGroundControl.Controls 1.0
-import QGroundControl.FactSystem 1.0
-import QGroundControl.FactControls 1.0
-import QGroundControl.Palette 1.0
-import QGroundControl.Controllers 1.0
-import QGroundControl.ScreenTools 1.0
+import QGroundControl 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.FactSystem 1.0
+import QGroundControl.FactControls 1.0
+import QGroundControl.Palette 1.0
+import QGroundControl.Controllers 1.0
+import QGroundControl.ScreenTools 1.0
QGCView {
id: qgcView
@@ -88,7 +89,7 @@ QGCView {
onBoardFound: {
if (initialBoardSearch) {
// 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)
} else {
statusTextArea.append(usbUnplugText.replace('{0}', controller.boardType))
diff --git a/src/VehicleSetup/FirmwareUpgradeController.cc b/src/VehicleSetup/FirmwareUpgradeController.cc
index eb1eb35bb5f14fbcc2536b1c897ee4c23537de5e..48b10e0d79b55eda03a45a30820c0d60025c4a45 100644
--- a/src/VehicleSetup/FirmwareUpgradeController.cc
+++ b/src/VehicleSetup/FirmwareUpgradeController.cc
@@ -68,13 +68,17 @@ FirmwareUpgradeController::FirmwareUpgradeController(void) :
connect(_threadController, &PX4FirmwareUpgradeThreadController::flashComplete, this, &FirmwareUpgradeController::_flashComplete);
connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &FirmwareUpgradeController::_updateProgress);
- connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDisconnected, this, &FirmwareUpgradeController::_linkDisconnected);
-
connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick);
}
+FirmwareUpgradeController::~FirmwareUpgradeController()
+{
+ qgcApp()->toolbox()->linkManager()->setConnectionsAllowed();
+}
+
void FirmwareUpgradeController::startBoardSearch(void)
{
+ qgcApp()->toolbox()->linkManager()->setConnectionsSuspended(tr("Connect not allowed during Firmware Upgrade."));
_bootloaderFound = false;
_startFlashWhenBootloaderFound = false;
_threadController->startFindBoardLoop();
@@ -556,17 +560,6 @@ void FirmwareUpgradeController::_appendStatusLog(const QString& text, bool criti
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)
{
_appendStatusLog(msg, false);
diff --git a/src/VehicleSetup/FirmwareUpgradeController.h b/src/VehicleSetup/FirmwareUpgradeController.h
index aec35f44d52ce6d84fddf22739531c0d2d53f2c3..d7f7c9d22d20d4fd6f7a4b08a8ea0d4d9730b362 100644
--- a/src/VehicleSetup/FirmwareUpgradeController.h
+++ b/src/VehicleSetup/FirmwareUpgradeController.h
@@ -104,7 +104,8 @@ public:
};
FirmwareUpgradeController(void);
-
+ ~FirmwareUpgradeController();
+
Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound)
Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound)
Q_PROPERTY(QString boardType MEMBER _foundBoardType NOTIFY boardFound)
@@ -115,9 +116,6 @@ public:
/// Progress bar for you know what
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
Q_INVOKABLE void startBoardSearch(void);
@@ -140,8 +138,6 @@ public:
QQuickItem* statusLog(void) { return _statusLog; }
void setStatusLog(QQuickItem* statusLog) { _statusLog = statusLog; }
- bool qgcConnections(void);
-
QString boardPort(void) { return _foundBoardInfo.portName(); }
QString boardDescription(void) { return _foundBoardInfo.description(); }
@@ -151,7 +147,6 @@ signals:
void boardGone(void);
void flashComplete(void);
void flashCancelled(void);
- void qgcConnectionsChanged(bool connections);
void error(void);
private slots:
@@ -170,7 +165,6 @@ private slots:
void _eraseStarted(void);
void _eraseComplete(void);
void _eraseProgressTick(void);
- void _linkDisconnected(LinkInterface* link);
private:
void _getFirmwareFile(FirmwareIdentifier firmwareId);
diff --git a/src/comm/LinkConfiguration.cc b/src/comm/LinkConfiguration.cc
index bf40204ca7f8a0ea1fa60eb6bf8a7040be1d4572..a3213d8a1173b6a0843ee4ce94c1a8e80e109289 100644
--- a/src/comm/LinkConfiguration.cc
+++ b/src/comm/LinkConfiguration.cc
@@ -42,19 +42,20 @@ This file is part of the QGROUNDCONTROL project
#define LINK_SETTING_ROOT "LinkConfigurations"
LinkConfiguration::LinkConfiguration(const QString& name)
- : _preferred(false)
+ : _link(NULL)
+ , _name(name)
, _dynamic(false)
{
- _link = NULL;
_name = name;
- Q_ASSERT(!_name.isEmpty());
+ if (_name.isEmpty()) {
+ qWarning() << "Internal error";
+ }
}
LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
{
- _link = copy->getLink();
+ _link = copy->link();
_name = copy->name();
- _preferred = copy->isPreferred();
_dynamic = copy->isDynamic();
Q_ASSERT(!_name.isEmpty());
}
@@ -62,9 +63,8 @@ LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
void LinkConfiguration::copyFrom(LinkConfiguration* source)
{
Q_ASSERT(source != NULL);
- _link = source->getLink();
+ _link = source->link();
_name = source->name();
- _preferred = source->isPreferred();
_dynamic = source->isDynamic();
}
@@ -138,3 +138,15 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc
}
return dupe;
}
+
+void LinkConfiguration::setName(const QString name)
+{
+ _name = name;
+ emit nameChanged(name);
+}
+
+void LinkConfiguration::setLink(LinkInterface* link)
+{
+ _link = link;
+ emit linkChanged(link);
+}
diff --git a/src/comm/LinkConfiguration.h b/src/comm/LinkConfiguration.h
index 8e59bad93834ea846ed9baba87355dddb5301f93..61018605207e61d1df67277ebb2b352e82b7f050 100644
--- a/src/comm/LinkConfiguration.h
+++ b/src/comm/LinkConfiguration.h
@@ -30,13 +30,26 @@ class LinkInterface;
/// Interface holding link specific settings.
-class LinkConfiguration
+class LinkConfiguration : public QObject
{
+ Q_OBJECT
+
public:
LinkConfiguration(const QString& name);
LinkConfiguration(LinkConfiguration* copy);
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
enum {
#ifndef __ios__
@@ -55,48 +68,6 @@ public:
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)
@@ -178,11 +149,14 @@ public:
*/
static LinkConfiguration* duplicateSettings(LinkConfiguration *source);
+signals:
+ void nameChanged(const QString& name);
+ void linkChanged(LinkInterface* link);
+
protected:
LinkInterface* _link; ///< Link currently using this configuration (if any)
private:
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).
};
diff --git a/src/comm/LinkInterface.h b/src/comm/LinkInterface.h
index 63ce51d784a697d7e233966e63939ae2f178ba2c..ffc6e615017146b08b486a9023ae9699c64d3068 100644
--- a/src/comm/LinkInterface.h
+++ b/src/comm/LinkInterface.h
@@ -57,6 +57,15 @@ class LinkInterface : public QThread
friend class LinkManager;
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)
* @return A pointer to the instance of LinkConfiguration if supported. NULL otherwise.
@@ -128,6 +137,7 @@ public:
/// @return true: "sh /etc/init.d/rc.usb" must be sent on link to start mavlink
virtual bool requiresUSBMavlinkStart(void) const { return false; }
+
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
@@ -148,6 +158,8 @@ public slots:
virtual void writeBytes(const char *bytes, qint64 length) = 0;
signals:
+ void autoconnectChanged(bool autoconnect);
+ void activeChanged(bool active);
/**
* @brief New data arrived
@@ -184,8 +196,10 @@ signals:
protected:
// Links are only created by LinkManager so constructor is not public
LinkInterface() :
- QThread(0),
- _mavlinkChannelSet(false)
+ QThread(0)
+ , _mavlinkChannelSet(false)
+ , _autoconnect(false)
+ , _active(false)
{
// Initialize everything for the data rate calculation buffers.
_inDataIndex = 0;
@@ -321,12 +335,7 @@ private:
**/
virtual bool _connect(void) = 0;
- /**
- * @brief Disconnect this interface logically
- *
- * @return True if connection could be terminated, false otherwise
- **/
- virtual bool _disconnect(void) = 0;
+ virtual void _disconnect(void) = 0;
/// Sets the mavlink channel to use for this link
void _setMavlinkChannel(uint8_t channel) { Q_ASSERT(!_mavlinkChannelSet); _mavlinkChannelSet = true; _mavlinkChannel = channel; }
@@ -351,6 +360,9 @@ private:
qint64 _outDataWriteTimes[_dataRateBufferSize]; // in ms
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 SharedLinkInterface;
diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc
index 9a8ef0ede6cfb524d2b3bb785042866b6b6ea477..5b43a7ab65a4b7fb7a9d60b2ae62b173da60082a 100644
--- a/src/comm/LinkManager.cc
+++ b/src/comm/LinkManager.cc
@@ -42,8 +42,17 @@ This file is part of the QGROUNDCONTROL project
#include "QGCMessageBox.h"
#include "QGCApplication.h"
#include "QGCApplication.h"
+#include "UDPLink.h"
+#include "TCPLink.h"
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)
: QGCTool(app)
@@ -51,21 +60,32 @@ LinkManager::LinkManager(QGCApplication* app)
, _configurationsLoaded(false)
, _connectionsSuspended(false)
, _mavlinkChannelsUsedBitMask(0)
- , _nullSharedLink(NULL)
, _mavlinkProtocol(NULL)
+ , _autoconnectUDPConfig(NULL)
+ , _autoconnectUDP(true)
+ , _autoconnectPixhawk(true)
+ , _autoconnect3DRRadio(true)
+ , _autoconnectPX4Flow(true)
+
{
+ qmlRegisterUncreatableType ("QGroundControl", 1, 0, "LinkManager", "Reference only");
+ qmlRegisterUncreatableType ("QGroundControl", 1, 0, "LinkConfiguration", "Reference only");
+ qmlRegisterUncreatableType ("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()
{
- // Clear configuration list
- while(_linkConfigurations.count()) {
- LinkConfiguration* pLink = _linkConfigurations.at(0);
- if(pLink) delete pLink;
- _linkConfigurations.removeAt(0);
+ if (anyActiveLinks()) {
+ qWarning() << "Why are there still active links?";
}
- Q_ASSERT_X(_links.count() == 0, "LinkManager", "LinkManager::_shutdown should have been called previously");
}
void LinkManager::setToolbox(QGCToolbox *toolbox)
@@ -73,14 +93,15 @@ void LinkManager::setToolbox(QGCToolbox *toolbox)
QGCTool::setToolbox(toolbox);
_mavlinkProtocol = _toolbox->mavlinkProtocol();
+ connect(_mavlinkProtocol, &MAVLinkProtocol::vehicleHeartbeatInfo, this, &LinkManager::_vehicleHeartbeatInfo);
#ifndef __ios__
- connect(&_portListTimer, &QTimer::timeout, this, &LinkManager::_updateConfigurationList);
+ connect(&_portListTimer, &QTimer::timeout, this, &LinkManager::_updateAutoConnectLinks);
_portListTimer.start(1000);
#endif
}
-LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
+LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config, bool autoconnectLink)
{
Q_ASSERT(config);
LinkInterface* pLink = NULL;
@@ -106,30 +127,36 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
#endif
}
if(pLink) {
+ pLink->setAutoconnect(autoconnectLink);
_addLink(pLink);
connectLink(pLink);
}
return pLink;
}
-LinkInterface* LinkManager::createConnectedLink(const QString& name)
+LinkInterface* LinkManager::createConnectedLink(const QString& name, bool autoconnectLink)
{
Q_ASSERT(name.isEmpty() == false);
for(int i = 0; i < _linkConfigurations.count(); i++) {
- LinkConfiguration* conf = _linkConfigurations.at(i);
+ LinkConfiguration* conf = _linkConfigurations.value(i);
if(conf && conf->name() == name)
- return createConnectedLink(conf);
+ return createConnectedLink(conf, autoconnectLink);
}
return NULL;
}
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
for (int i=0; i<32; i++) {
if (!(_mavlinkChannelsUsedBitMask && 1 << i)) {
@@ -140,11 +167,8 @@ void LinkManager::_addLink(LinkInterface* link)
}
}
- _links.append(QSharedPointer(link));
- _linkListMutex.unlock();
+ _links.append(link);
emit newLink(link);
- } else {
- _linkListMutex.unlock();
}
// MainWindow may be around when doing things like running unit tests
@@ -161,39 +185,12 @@ void LinkManager::_addLink(LinkInterface* link)
connect(link, &LinkInterface::disconnected, this, &LinkManager::_linkDisconnected);
}
-bool LinkManager::connectAll()
+void LinkManager::disconnectAll(bool disconnectAutoconnectLink)
{
- if (_connectionsSuspendedMsg()) {
- return false;
- }
-
- bool allConnected = true;
-
- foreach (SharedLinkInterface sharedLink, _links) {
- Q_ASSERT(sharedLink.data());
- if (!sharedLink.data()->_connect()) {
- allConnected = false;
- }
+ // Walk list in reverse order to preserve indices during delete
+ for (int i=_links.count()-1; i>=0; i--) {
+ disconnectLink(_links.value(i), disconnectAutoconnectLink);
}
-
- return allConnected;
-}
-
-bool LinkManager::disconnectAll()
-{
- bool allDisconnected = true;
-
- // Make a copy so the list is modified out from under us
- QList links = _links;
-
- foreach (SharedLinkInterface sharedLink, links) {
- Q_ASSERT(sharedLink.data());
- if (!disconnectLink(sharedLink.data())) {
- allDisconnected = false;
- }
- }
-
- return allDisconnected;
}
bool LinkManager::connectLink(LinkInterface* link)
@@ -204,68 +201,60 @@ bool LinkManager::connectLink(LinkInterface* link)
return false;
}
+ bool previousAnyConnectedLinks = anyConnectedLinks();
+ bool previousAnyNonAutoconnectConnectedLinks = anyNonAutoconnectConnectedLinks();
+
if (link->_connect()) {
+ if (!previousAnyConnectedLinks) {
+ emit anyConnectedLinksChanged(true);
+ }
+ if (!previousAnyNonAutoconnectConnectedLinks && anyNonAutoconnectConnectedLinks()) {
+ emit anyNonAutoconnectConnectedLinksChanged(true);
+ }
return true;
} else {
return false;
}
}
-bool LinkManager::disconnectLink(LinkInterface* link)
+bool LinkManager::disconnectLink(LinkInterface* link, bool disconnectAutoconnectLink)
{
Q_ASSERT(link);
- if (link->_disconnect()) {
+
+ if (disconnectAutoconnectLink || !link->autoconnect()) {
+ link->_disconnect();
LinkConfiguration* config = link->getLinkConfiguration();
if(config) {
config->setLink(NULL);
}
_deleteLink(link);
return true;
- } else {
- return false;
}
+
+ return false;
}
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
_mavlinkChannelsUsedBitMask &= ~(1 << link->getMavlinkChannel());
- bool found = false;
- for (int i=0; i<_links.count(); i++) {
- if (_links[i].data() == link) {
- _links.removeAt(i);
- found = true;
- break;
- }
- }
- Q_UNUSED(found);
- Q_ASSERT(found);
-
- _linkListMutex.unlock();
+ _links.removeOne(link);
+ delete link;
// Emit removal of link
emit linkDeleted(link);
}
-/**
- *
- */
-const QList LinkManager::getLinks()
-{
- QList 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
/// is returned;
bool LinkManager::_connectionsSuspendedMsg(void)
@@ -286,13 +275,6 @@ void LinkManager::setConnectionsSuspended(QString reason)
Q_ASSERT(!reason.isEmpty());
}
-void LinkManager::_shutdown(void)
-{
- while (_links.count() != 0) {
- disconnectLink(_links[0].data());
- }
-}
-
void LinkManager::_linkConnected(void)
{
emit linkConnected((LinkInterface*)sender());
@@ -303,33 +285,6 @@ void LinkManager::_linkDisconnected(void)
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 LinkManager::getLinkConfigurationList()
-{
- return _linkConfigurations;
-}
-
void LinkManager::suspendConfigurationUpdates(bool suspend)
{
_configUpdateSuspended = suspend;
@@ -339,30 +294,35 @@ void LinkManager::saveLinkConfigurationList()
{
QSettings settings;
settings.remove(LinkConfiguration::settingsRoot());
- int index = 0;
- foreach (LinkConfiguration* pLink, _linkConfigurations) {
- Q_ASSERT(pLink != NULL);
- if(!pLink->isDynamic())
- {
- QString root = LinkConfiguration::settingsRoot();
- root += QString("/Link%1").arg(index++);
- settings.setValue(root + "/name", pLink->name());
- settings.setValue(root + "/type", pLink->type());
- settings.setValue(root + "/preferred", pLink->isPreferred());
- // Have the instance save its own values
- pLink->saveSettings(settings, root);
+
+ for (int i=0; i<_linkConfigurations.count(); i++) {
+ LinkConfiguration* linkConfig = _linkConfigurations.value(i);
+
+ if (linkConfig) {
+ if(!linkConfig->isDynamic())
+ {
+ QString root = LinkConfiguration::settingsRoot();
+ root += QString("/Link%1").arg(i);
+ settings.setValue(root + "/name", linkConfig->name());
+ settings.setValue(root + "/type", linkConfig->type());
+ // Have the instance save its own values
+ linkConfig->saveSettings(settings, root);
+ }
+ } else {
+ qWarning() << "Internal error";
}
}
+
QString root(LinkConfiguration::settingsRoot());
- settings.setValue(root + "/count", index);
+ settings.setValue(root + "/count", _linkConfigurations.count());
emit linkConfigurationChanged();
}
void LinkManager::loadLinkConfigurationList()
{
- bool udpExists = false;
bool linksChanged = false;
QSettings settings;
+
// Is the group even there?
if(settings.contains(LinkConfiguration::settingsRoot() + "/count")) {
// Find out how many configurations we have
@@ -376,49 +336,33 @@ void LinkManager::loadLinkConfigurationList()
if(settings.contains(root + "/name")) {
QString name = settings.value(root + "/name").toString();
if(!name.isEmpty()) {
- bool preferred = false;
- if(settings.contains(root + "/preferred")) {
- preferred = settings.value(root + "/preferred").toBool();
- }
LinkConfiguration* pLink = NULL;
switch(type) {
#ifndef __ios__
case LinkConfiguration::TypeSerial:
pLink = (LinkConfiguration*)new SerialConfiguration(name);
- pLink->setPreferred(preferred);
break;
#endif
case LinkConfiguration::TypeUdp:
pLink = (LinkConfiguration*)new UDPConfiguration(name);
- pLink->setPreferred(preferred);
break;
case LinkConfiguration::TypeTcp:
pLink = (LinkConfiguration*)new TCPConfiguration(name);
- pLink->setPreferred(preferred);
break;
case LinkConfiguration::TypeLogReplay:
pLink = (LinkConfiguration*)new LogReplayLinkConfiguration(name);
- pLink->setPreferred(preferred);
break;
#ifdef QT_DEBUG
case LinkConfiguration::TypeMock:
pLink = (LinkConfiguration*)new MockConfiguration(name);
- pLink->setPreferred(false);
break;
#endif
}
if(pLink) {
// Have the instance load its own values
pLink->loadSettings(settings, root);
- addLinkConfiguration(pLink);
+ _linkConfigurations.append(pLink);
linksChanged = true;
- // Check for UDP links
- if(pLink->type() == LinkConfiguration::TypeUdp) {
- UDPConfiguration* uLink = dynamic_cast(pLink);
- if(uLink && uLink->localPort() == QGC_UDP_LOCAL_PORT) {
- udpExists = true;
- }
- }
}
} else {
qWarning() << "Link Configuration " << root << " has an empty name." ;
@@ -439,37 +383,32 @@ void LinkManager::loadLinkConfigurationList()
#ifdef QT_DEBUG
MockConfiguration* pMock = new MockConfiguration("Mock Link PX4");
pMock->setDynamic(true);
- addLinkConfiguration(pMock);
+ _linkConfigurations.append(pMock);
linksChanged = true;
#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) {
emit linkConfigurationChanged();
}
+
// Enable automatic Serial PX4/3DR Radio hunting
_configurationsLoaded = true;
}
#ifndef __ios__
-SerialConfiguration* LinkManager::_findSerialConfiguration(const QString& portName)
+SerialConfiguration* LinkManager::_autoconnectConfigurationsContainsPort(const QString& portName)
{
QString searchPort = portName.trimmed();
- foreach (LinkConfiguration* pLink, _linkConfigurations) {
- Q_ASSERT(pLink != NULL);
- if(pLink->type() == LinkConfiguration::TypeSerial) {
- SerialConfiguration* pSerial = dynamic_cast(pLink);
- if(pSerial->portName() == searchPort) {
- return pSerial;
+
+ for (int i=0; i<_autoconnectConfigurations.count(); i++) {
+ SerialConfiguration* linkConfig = _autoconnectConfigurations.value(i);
+
+ if (linkConfig) {
+ if (linkConfig->portName() == searchPort) {
+ return linkConfig;
}
+ } else {
+ qWarning() << "Internal error";
}
}
return NULL;
@@ -477,26 +416,34 @@ SerialConfiguration* LinkManager::_findSerialConfiguration(const QString& portNa
#endif
#ifndef __ios__
-void LinkManager::_updateConfigurationList(void)
+void LinkManager::_updateAutoConnectLinks(void)
{
- if (_configUpdateSuspended || !_configurationsLoaded) {
+ if (_connectionsSuspended || qgcApp()->runningUnitTests()) {
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;
QList portList = QGCSerialPortInfo::availablePorts();
+
// Iterate Comm Ports
foreach (QGCSerialPortInfo portInfo, portList) {
-#if 0
- // Too noisy for most logging, so turn on as needed
- qCDebug(LinkManagerLog) << "-----------------------------------------------------";
- qCDebug(LinkManagerLog) << "portName: " << portInfo.portName();
- qCDebug(LinkManagerLog) << "systemLocation: " << portInfo.systemLocation();
- qCDebug(LinkManagerLog) << "description: " << portInfo.description();
- qCDebug(LinkManagerLog) << "manufacturer: " << portInfo.manufacturer();
- qCDebug(LinkManagerLog) << "serialNumber: " << portInfo.serialNumber();
- qCDebug(LinkManagerLog) << "vendorIdentifier: " << portInfo.vendorIdentifier();
-#endif
+ qCDebug(LinkManagerVerboseLog) << "-----------------------------------------------------";
+ qCDebug(LinkManagerVerboseLog) << "portName: " << portInfo.portName();
+ qCDebug(LinkManagerVerboseLog) << "systemLocation: " << portInfo.systemLocation();
+ qCDebug(LinkManagerVerboseLog) << "description: " << portInfo.description();
+ qCDebug(LinkManagerVerboseLog) << "manufacturer: " << portInfo.manufacturer();
+ qCDebug(LinkManagerVerboseLog) << "serialNumber: " << portInfo.serialNumber();
+ qCDebug(LinkManagerVerboseLog) << "vendorIdentifier: " << portInfo.vendorIdentifier();
+ qCDebug(LinkManagerVerboseLog) << "productIdentifier: " << portInfo.productIdentifier();
+
// Save port name
currentPorts << portInfo.systemLocation();
@@ -508,76 +455,98 @@ void LinkManager::_updateConfigurationList(void)
continue;
}
- SerialConfiguration* pSerial = _findSerialConfiguration(portInfo.systemLocation());
- if (pSerial) {
- //-- If this port is configured make sure it has the preferred flag set
- if(!pSerial->isPreferred()) {
- pSerial->setPreferred(true);
- saveList = true;
- }
- } else {
+ if (!_autoconnectConfigurationsContainsPort(portInfo.systemLocation())) {
+ SerialConfiguration* pSerialConfig = NULL;
+
switch (boardType) {
case QGCSerialPortInfo::BoardTypePX4FMUV1:
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;
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;
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;
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:
qWarning() << "Internal error";
- break;
+ continue;
}
- pSerial->setBaud(boardType == QGCSerialPortInfo::BoardType3drRadio ? 57600 : 115200);
- pSerial->setDynamic(true);
- pSerial->setPreferred(true);
- pSerial->setPortName(portInfo.systemLocation());
- addLinkConfiguration(pSerial);
- saveList = true;
+ if (pSerialConfig) {
+ qCDebug(LinkManagerLog) << "New auto-connect port added: " << pSerialConfig->name() << portInfo.systemLocation();
+ pSerialConfig->setBaud(boardType == QGCSerialPortInfo::BoardType3drRadio ? 57600 : 115200);
+ pSerialConfig->setDynamic(true);
+ pSerialConfig->setPortName(portInfo.systemLocation());
+
+ _autoconnectConfigurations.append(pSerialConfig);
+
+ createConnectedLink(pSerialConfig, true /* persistenLink */);
+ }
}
}
}
// Now we go through the current configuration list and make sure any dynamic config has gone away
QList _confToDelete;
- foreach (LinkConfiguration* pLink, _linkConfigurations) {
- Q_ASSERT(pLink != NULL);
- // We only care about dynamic links
- if(pLink->isDynamic()) {
- if(pLink->type() == LinkConfiguration::TypeSerial) {
- // Don't mess with connected link. Let it deal with the disapearing device.
- if(pLink->getLink() == NULL) {
- SerialConfiguration* pSerial = dynamic_cast(pLink);
- if(!currentPorts.contains(pSerial->portName())) {
- _confToDelete.append(pSerial);
- }
- }
+ for (int i=0; i<_autoconnectConfigurations.count(); i++) {
+ SerialConfiguration* linkConfig = _autoconnectConfigurations.value(i);
+
+ if (linkConfig) {
+ if (!currentPorts.contains(linkConfig->portName())) {
+ _confToDelete.append(linkConfig);
}
+ } else {
+ qWarning() << "Internal error";
}
}
- // Now remove all links that are gone
- foreach (LinkConfiguration* pDelete, _confToDelete) {
- removeLinkConfiguration(pDelete);
- saveList = true;
- }
- // Save configuration list, which will also trigger a signal for the UI
- if(saveList) {
- saveLinkConfigurationList();
+
+ // Now disconnect/remove all links that are gone
+ foreach (LinkConfiguration* pDeleteConfig, _confToDelete) {
+ LinkInterface* link = pDeleteConfig->link();
+ if (link) {
+ disconnectLink(link, true /* disconnectAutoconnectLink */);
+ }
+ _autoconnectConfigurations.removeOne(pDeleteConfig);
+ delete pDeleteConfig;
}
}
#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(i);
+
+ if (link && link->isConnected()) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+bool LinkManager::anyNonAutoconnectConnectedLinks(void)
{
+ // FIXME: Should remove this duplication with anyConnectedLinks
bool found = false;
- foreach (SharedLinkInterface sharedLink, _links) {
- if (sharedLink.data() == link) {
+ for (int i=0; i<_links.count(); i++) {
+ LinkInterface* link = _links.value(i);
+
+ if (link && !link->autoconnect() && link->isConnected()) {
found = true;
break;
}
@@ -585,11 +554,13 @@ bool LinkManager::containsLink(LinkInterface* link)
return found;
}
-bool LinkManager::anyConnectedLinks(void)
+bool LinkManager::anyActiveLinks(void)
{
bool found = false;
- foreach (SharedLinkInterface sharedLink, _links) {
- if (sharedLink.data()->isConnected()) {
+ for (int i=0; i<_links.count(); i++) {
+ LinkInterface* link = _links.value(i);
+
+ if (link && link->active()) {
found = true;
break;
}
@@ -597,14 +568,117 @@ bool LinkManager::anyConnectedLinks(void)
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++) {
- if (_links[i].data() == link) {
- return _links[i];
+ LinkInterface* link = _links.value(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);
+ }
+
}
diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h
index 3063f50eb23ef7c86c458b6eca0444efd03bfb28..521efa6a95d0f608471af406ae2aafe3440de03c 100644
--- a/src/comm/LinkManager.h
+++ b/src/comm/LinkManager.h
@@ -35,23 +35,23 @@ This file is part of the PIXHAWK project
#include "LinkInterface.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
+#include "ProtocolInterface.h"
+#include "MAVLinkProtocol.h"
+#include "LogReplayLink.h"
+#include "QmlObjectListModel.h"
-// Links
#ifndef __ios__
-#include "SerialLink.h"
+ #include "SerialLink.h"
#endif
-#include "UDPLink.h"
-#include "TCPLink.h"
-#include "LogReplayLink.h"
#ifdef QT_DEBUG
-#include "MockLink.h"
+ #include "MockLink.h"
#endif
-#include "ProtocolInterface.h"
-#include "MAVLinkProtocol.h"
+class UDPConfiguration;
Q_DECLARE_LOGGING_CATEGORY(LinkManagerLog)
+Q_DECLARE_LOGGING_CATEGORY(LinkManagerVerboseLog)
class QGCApplication;
@@ -72,17 +72,36 @@ public:
LinkManager(QGCApplication* app);
~LinkManager();
- /*!
- Add a new link configuration setting to the list
- @param[in] link An instance of the link setting.
- */
- void addLinkConfiguration(LinkConfiguration* link);
+ Q_PROPERTY(bool anyActiveLinks READ anyActiveLinks NOTIFY anyActiveLinksChanged)
+ Q_PROPERTY(bool anyNonAutoconnectActiveLinks READ anyNonAutoconnectActiveLinks NOTIFY anyNonAutoconnectActiveLinksChanged)
+ Q_PROPERTY(bool anyConnectedLinks READ anyConnectedLinks NOTIFY anyConnectedLinksChanged)
+ Q_PROPERTY(bool anyNonAutoconnectConnectedLinks READ anyNonAutoconnectConnectedLinks NOTIFY anyNonAutoconnectConnectedLinksChanged)
+ 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
void loadLinkConfigurationList();
@@ -90,19 +109,9 @@ public:
/// Save list of link configurations from disk
void saveLinkConfigurationList();
- /// Get a list of the configured links. This is the list of configured links that can be used by QGC.
- const QList getLinkConfigurationList();
-
/// Suspend automatic confguration updates (during link maintenance for instance)
void suspendConfigurationUpdates(bool suspend);
- /// Returns list of all links
- const QList getLinks();
-
- // Returns list of all serial links
-#ifndef __ios__
- const QList getSerialLinks();
-#endif
/// Sets the flag to suspend the all new connections
/// @param reason User visible reason to suspend connections
void setConnectionsSuspended(QString reason);
@@ -112,68 +121,85 @@ public:
/// Creates, connects (and adds) a link based on the given configuration instance.
/// 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.
- LinkInterface* createConnectedLink(const QString& name);
-
- /// 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);
+ LinkInterface* createConnectedLink(const QString& name, bool persistenLink = false);
- /// Re-connects all existing links
- bool connectAll();
-
- /// Disconnects all existing links
- bool disconnectAll();
+ /// Disconnects all existing links, including persistent links.
+ /// @param disconnectAutoconnectLink See disconnectLink
+ void disconnectAll(bool disconnectAutoconnectLink);
/// Connect the specified link
bool connectLink(LinkInterface* link);
- /// Disconnect the specified link
- bool disconnectLink(LinkInterface* link);
-
- /// Returns true if there are any connected links
- bool anyConnectedLinks(void);
+ /// Disconnect the specified link.
+ /// @param disconnectAutoconnectLink
+ /// true: link is disconnected no matter what type
+ /// false: if autoconnect link, link is marked as inactive and linkInactive is signalled
+ /// 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
// here for unit test code.
void _deleteLink(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
virtual void setToolbox(QGCToolbox *toolbox);
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);
+
+ // Link has been deleted. You may not necessarily get a linkInactive before the link is deleted.
void linkDeleted(LinkInterface* link);
+
+ // Link has been connected, but no Vehicle seen on link yet.
void linkConnected(LinkInterface* link);
+
+ // Link disconnected, all vehicles on link should be gone as well.
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();
private slots:
void _linkConnected(void);
void _linkDisconnected(void);
+ void _vehicleHeartbeatInfo(LinkInterface* link, int vehicleId, int vehicleMavlinkVersion, int vehicleFirmwareType, int vehicleType);
private:
- virtual void _shutdown(void);
-
bool _connectionsSuspendedMsg(void);
- void _updateConfigurationList(void);
+ void _updateAutoConnectLinks(void);
+
#ifndef __ios__
- SerialConfiguration* _findSerialConfiguration(const QString& portName);
+ SerialConfiguration* _autoconnectConfigurationsContainsPort(const QString& portName);
#endif
- QList _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 _links;
-
- QMutex _linkListMutex; ///< Mutex for thread safe access to _links list
bool _configUpdateSuspended; ///< true: stop updating configuration list
bool _configurationsLoaded; ///< true: Link configurations have been loaded
@@ -183,10 +209,25 @@ private:
QTimer _portListTimer;
#endif
uint32_t _mavlinkChannelsUsedBitMask;
-
- SharedLinkInterface _nullSharedLink;
MAVLinkProtocol* _mavlinkProtocol;
+ QList _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
diff --git a/src/comm/LogReplayLink.cc b/src/comm/LogReplayLink.cc
index d5ac20cebffc2e36a45e1a89c6543bade06128cc..1ab9214f406fe69953d3407344555f59c2a7bda6 100644
--- a/src/comm/LogReplayLink.cc
+++ b/src/comm/LogReplayLink.cc
@@ -102,7 +102,7 @@ LogReplayLink::~LogReplayLink(void)
bool LogReplayLink::_connect(void)
{
// 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.");
return false;
}
@@ -115,7 +115,7 @@ bool LogReplayLink::_connect(void)
return true;
}
-bool LogReplayLink::_disconnect(void)
+void LogReplayLink::_disconnect(void)
{
if (_connected) {
quit();
@@ -123,7 +123,6 @@ bool LogReplayLink::_disconnect(void)
_connected = false;
emit disconnected();
}
- return true;
}
void LogReplayLink::run(void)
@@ -366,7 +365,6 @@ void LogReplayLink::_readNextLogEntry(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."));
#ifndef __mobile__
qgcApp()->toolbox()->mavlinkProtocol()->suspendLogForReplay(true);
diff --git a/src/comm/LogReplayLink.h b/src/comm/LogReplayLink.h
index 556c95c534ccab6c83fd40a84dc54b28f9ff0f44..b1cd2a9ed84d0d99fdc8f73a6f84866afe82b73f 100644
--- a/src/comm/LogReplayLink.h
+++ b/src/comm/LogReplayLink.h
@@ -33,6 +33,8 @@
class LogReplayLinkConfiguration : public LinkConfiguration
{
+ Q_OBJECT
+
public:
LogReplayLinkConfiguration(const QString& name);
LogReplayLinkConfiguration(LogReplayLinkConfiguration* copy);
@@ -130,7 +132,7 @@ private:
// Virtuals from LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
// Virtuals from QThread
virtual void run(void);
diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc
index 37cb0135eaeeafd996cfd0da557dac5cb70d793d..7d3f1211921c43801e27f2436e6cd63829a303d7 100644
--- a/src/comm/MAVLinkProtocol.cc
+++ b/src/comm/MAVLinkProtocol.cc
@@ -193,13 +193,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected)
Q_ASSERT(link);
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()) {
// Send command to start MAVLink
// XXX hacky but safe
@@ -210,17 +203,6 @@ void MAVLinkProtocol::_linkStatusChanged(LinkInterface* link, bool connected)
link->writeBytes(cmd, strlen(cmd));
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)
// 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
// since the link is closed.
- if (!_linkMgr->containsLink(link)) {
+ if (!_linkMgr->links()->contains(link)) {
return;
}
@@ -300,7 +282,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
{
mavlink_message_t msg;
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)
_startLogging();
#endif
- // Notify the vehicle manager of the heartbeat. This will create/update vehicles as needed.
mavlink_heartbeat_t heartbeat;
mavlink_msg_heartbeat_decode(&message, &heartbeat);
- if (!_multiVehicleManager->notifyHeartbeatInfo(link, message.sysid, heartbeat)) {
- continue;
- }
+ emit vehicleHeartbeatInfo(link, message.sysid, heartbeat.mavlink_version, heartbeat.autopilot, heartbeat.type);
}
// Increase receive counter
@@ -417,15 +396,13 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
// Multiplex message if enabled
if (m_multiplexingEnabled)
{
- // Get all links connected to this unit
- QList links = _linkMgr->getLinks();
-
// 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(i);
+
// Only forward this message to the other links,
// 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()
/**
* @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
- QList links = _linkMgr->getLinks();
-
- // Emit message on all links that are currently connected
- QList::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();
+ for (int i=0; i<_linkMgr->links()->count(); i++) {
+ LinkInterface* link = _linkMgr->links()->value(i);
+ _sendMessage(link, message);
}
}
@@ -478,7 +449,7 @@ void MAVLinkProtocol::sendMessage(mavlink_message_t message)
* @param link the link to send the message over
* @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
static uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
@@ -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 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
static uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
@@ -529,7 +500,7 @@ void MAVLinkProtocol::sendHeartbeat()
{
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);
- sendMessage(beat);
+ _sendMessage(beat);
}
if (m_authEnabled)
{
@@ -538,7 +509,7 @@ void MAVLinkProtocol::sendHeartbeat()
memset(&auth, 0, sizeof(auth));
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);
- sendMessage(msg);
+ _sendMessage(msg);
}
}
diff --git a/src/comm/MAVLinkProtocol.h b/src/comm/MAVLinkProtocol.h
index 5e0d1f7ae9414cb876422654cea1ecda1fef551d..b8b4b7564b16b26f788eeaefbf49089b3db4c98b 100644
--- a/src/comm/MAVLinkProtocol.h
+++ b/src/comm/MAVLinkProtocol.h
@@ -158,12 +158,6 @@ public slots:
void linkConnected(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 */
void setHeartbeatRate(int rate);
/** @brief Set the system id of this application */
@@ -238,6 +232,9 @@ protected:
int systemId;
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 */
void messageReceived(LinkInterface* link, mavlink_message_t message);
/** @brief Emitted if heartbeat emission mode is changed */
@@ -289,6 +286,9 @@ private slots:
private:
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__
bool _closeLogFile(void);
@@ -303,12 +303,7 @@ private:
static const char* _tempLogFileTemplate; ///< Template for temporary log file
static const char* _logFileExtension; ///< Extension for log files
#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 _connectedLinks;
-
+
QTimer _heartbeatTimer; ///< Timer to emit heartbeats
int _heartbeatRate; ///< Heartbeat rate, controls the timer interval
bool _heartbeatsEnabled; ///< Enabled/disable heartbeat emission
diff --git a/src/comm/MockLink.cc b/src/comm/MockLink.cc
index d265ee2615bd108c320c873fe3276ccc650ef63a..4ca7c4a50eac915a53db1046f5b1d4292f553307 100644
--- a/src/comm/MockLink.cc
+++ b/src/comm/MockLink.cc
@@ -98,6 +98,7 @@ MockLink::MockLink(MockConfiguration* config)
_firmwareType = config->firmwareType();
_vehicleType = config->vehicleType();
_sendStatusText = config->sendStatusText();
+ _config->setLink(this);
}
union px4_custom_mode px4_cm;
@@ -136,7 +137,7 @@ bool MockLink::_connect(void)
return true;
}
-bool MockLink::_disconnect(void)
+void MockLink::_disconnect(void)
{
if (_connected) {
_connected = false;
@@ -144,8 +145,6 @@ bool MockLink::_disconnect(void)
wait();
emit disconnected();
}
-
- return true;
}
void MockLink::run(void)
diff --git a/src/comm/MockLink.h b/src/comm/MockLink.h
index 25fac11fb7cb24eb48960836ce5c031f04331619..e643320eaa67a8416a7bac7600ebb83dfd34c2cc 100644
--- a/src/comm/MockLink.h
+++ b/src/comm/MockLink.h
@@ -37,6 +37,8 @@ Q_DECLARE_LOGGING_CATEGORY(MockLinkVerboseLog)
class MockConfiguration : public LinkConfiguration
{
+ Q_OBJECT
+
public:
MockConfiguration(const QString& name);
MockConfiguration(MockConfiguration* source);
@@ -146,7 +148,7 @@ private slots:
private:
// From LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
// QThread override
virtual void run(void);
diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc
index a19296ac1685b1e2cac2dfa126070295e6f23da5..b8f49107ef1a397e9d9b37d8b5b834ac06ed7ce7 100644
--- a/src/comm/SerialLink.cc
+++ b/src/comm/SerialLink.cc
@@ -124,7 +124,7 @@ void SerialLink::readBytes()
*
* @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/
-bool SerialLink::_disconnect(void)
+void SerialLink::_disconnect(void)
{
if (_port) {
_port->close();
@@ -135,7 +135,6 @@ bool SerialLink::_disconnect(void)
#ifdef __android__
qgcApp()->toolbox()->linkManager()->suspendConfigurationUpdates(false);
#endif
- return true;
}
/**
diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h
index 49baceaadd56478106a35316868f98011a735dc6..078fccf6980c35714d791f2419b84fdee25058f1 100644
--- a/src/comm/SerialLink.h
+++ b/src/comm/SerialLink.h
@@ -59,6 +59,8 @@ Q_DECLARE_LOGGING_CATEGORY(SerialLinkLog)
class SerialConfiguration : public LinkConfiguration
{
+ Q_OBJECT
+
public:
SerialConfiguration(const QString& name);
@@ -158,7 +160,7 @@ private:
// From LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
// Internal methods
void _emitLinkError(const QString& errorMsg);
diff --git a/src/comm/TCPLink.cc b/src/comm/TCPLink.cc
index c2d891926394c7a627a827019e06d002a23364a0..be821f19ed75ed3792f898ce4e1f428853247db6 100644
--- a/src/comm/TCPLink.cc
+++ b/src/comm/TCPLink.cc
@@ -124,18 +124,16 @@ void TCPLink::readBytes()
*
* @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/
-bool TCPLink::_disconnect(void)
+void TCPLink::_disconnect(void)
{
quit();
wait();
- if (_socket)
- {
+ if (_socket) {
_socketIsConnected = false;
_socket->deleteLater(); // Make sure delete happens on correct thread
_socket = NULL;
emit disconnected();
}
- return true;
}
/**
diff --git a/src/comm/TCPLink.h b/src/comm/TCPLink.h
index 2d0e5a52eef1ee511a36f5290671048187a2de03..87404c2f0000c5fb8e468798f4bf666b7b5a3601 100644
--- a/src/comm/TCPLink.h
+++ b/src/comm/TCPLink.h
@@ -52,6 +52,8 @@ class TCPLinkUnitTest;
class TCPConfiguration : public LinkConfiguration
{
+ Q_OBJECT
+
public:
/*!
@@ -164,7 +166,7 @@ private:
// From LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
bool _hardwareConnect();
void _restartConnection();
diff --git a/src/comm/UDPLink.cc b/src/comm/UDPLink.cc
index a393337e6e48843a0947e58390afa1b6d3ffdcfa..90d6140630b095879e5d06c2e6378222e59c4296 100644
--- a/src/comm/UDPLink.cc
+++ b/src/comm/UDPLink.cc
@@ -281,7 +281,7 @@ void UDPLink::readBytes()
*
* @return True if connection has been disconnected, false if connection couldn't be disconnected.
**/
-bool UDPLink::_disconnect(void)
+void UDPLink::_disconnect(void)
{
_running = false;
quit();
@@ -293,7 +293,6 @@ bool UDPLink::_disconnect(void)
emit disconnected();
}
_connectState = false;
- return true;
}
/**
diff --git a/src/comm/UDPLink.h b/src/comm/UDPLink.h
index d83058a91f79ced00fbcf9bd2c9b24038420f0e1..a934b9fd0a2001b14525a0ec24ebb8d3765a5592 100644
--- a/src/comm/UDPLink.h
+++ b/src/comm/UDPLink.h
@@ -52,6 +52,8 @@ This file is part of the QGROUNDCONTROL project
class UDPConfiguration : public LinkConfiguration
{
+ Q_OBJECT
+
public:
/*!
@@ -203,7 +205,7 @@ private:
// From LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
bool _hardwareConnect();
void _restartConnection();
diff --git a/src/comm/XbeeLink.cpp b/src/comm/XbeeLink.cpp
index de1f31a1bdaea47a0c9a81f672888f9a94fe7026..d365eb85d65f0b1bf60aeccf06c0ba63b9ad1eca 100644
--- a/src/comm/XbeeLink.cpp
+++ b/src/comm/XbeeLink.cpp
@@ -158,7 +158,7 @@ bool XbeeLink::_connect(void)
return true;
}
-bool XbeeLink::_disconnect(void)
+void XbeeLink::_disconnect(void)
{
if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect
@@ -170,7 +170,6 @@ bool XbeeLink::_disconnect(void)
this->m_connected = false;
emit disconnected();
- return true;
}
void XbeeLink::writeBytes(const char *bytes, qint64 length) // TO DO: delete the data array
diff --git a/src/comm/XbeeLink.h b/src/comm/XbeeLink.h
index 04bb62aa3504ef5cc9c54a764f0ab71585dbff3c..78048be7ddac2a10953497727eaed157b17797e3 100644
--- a/src/comm/XbeeLink.h
+++ b/src/comm/XbeeLink.h
@@ -67,7 +67,7 @@ protected:
private:
// From LinkInterface
virtual bool _connect(void);
- virtual bool _disconnect(void);
+ virtual void _disconnect(void);
bool hardwareConnect();
//void CALLTYPE portCallback(xbee_con *XbeeCon, xbee_pkt *XbeePkt);
diff --git a/src/qgcunittest/LinkManagerTest.cc b/src/qgcunittest/LinkManagerTest.cc
index 114dab7774f35475d545c73743ca561b2897236c..ad8861b4d5e11f2e8ef1fbedc7fd36ea80615b53 100644
--- a/src/qgcunittest/LinkManagerTest.cc
+++ b/src/qgcunittest/LinkManagerTest.cc
@@ -71,30 +71,29 @@ void LinkManagerTest::cleanup(void)
void LinkManagerTest::_add_test(void)
{
Q_ASSERT(_linkMgr);
- Q_ASSERT(_linkMgr->getLinks().count() == 0);
+ Q_ASSERT(_linkMgr->links()->count() == 0);
_connectMockLink();
- QList links = _linkMgr->getLinks();
- QCOMPARE(links.count(), 1);
- QCOMPARE(dynamic_cast(links[0]), _mockLink);
+ QCOMPARE(_linkMgr->links()->count(), 1);
+ QCOMPARE(_linkMgr->links()->value(0), _mockLink);
}
void LinkManagerTest::_delete_test(void)
{
Q_ASSERT(_linkMgr);
- Q_ASSERT(_linkMgr->getLinks().count() == 0);
+ Q_ASSERT(_linkMgr->links()->count() == 0);
_connectMockLink();
_disconnectMockLink();
- QCOMPARE(_linkMgr->getLinks().count(), 0);
+ QCOMPARE(_linkMgr->links()->count(), 0);
}
void LinkManagerTest::_addSignals_test(void)
{
Q_ASSERT(_linkMgr);
- Q_ASSERT(_linkMgr->getLinks().count() == 0);
+ Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink();
@@ -114,7 +113,7 @@ void LinkManagerTest::_addSignals_test(void)
void LinkManagerTest::_deleteSignals_test(void)
{
Q_ASSERT(_linkMgr);
- Q_ASSERT(_linkMgr->getLinks().count() == 0);
+ Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink();
diff --git a/src/qgcunittest/UnitTest.cc b/src/qgcunittest/UnitTest.cc
index b3f5b404c4cd9846ae96212c8eee14a9f04afd60..6b29e3f36741657645e894f4925e46fd2031f245 100644
--- a/src/qgcunittest/UnitTest.cc
+++ b/src/qgcunittest/UnitTest.cc
@@ -387,7 +387,7 @@ void UnitTest::_disconnectMockLink(void)
if (_mockLink) {
QSignalSpy linkSpy(_linkManager, SIGNAL(linkDeleted(LinkInterface*)));
- _linkManager->disconnectLink(_mockLink);
+ _linkManager->disconnectLink(_mockLink, false /* disconnectAutoconnectLink */);
// Wait for link to go away
linkSpy.wait(1000);
diff --git a/src/ui/MAVLinkSettingsWidget.cc b/src/ui/MAVLinkSettingsWidget.cc
index e1d2f3305992f386f157028051880f0b227fd1eb..5faa01f5e9ae2faaa5d0088cd130e22f12b37e45 100644
--- a/src/ui/MAVLinkSettingsWidget.cc
+++ b/src/ui/MAVLinkSettingsWidget.cc
@@ -141,12 +141,14 @@ void MAVLinkSettingsWidget::enableDroneOS(bool enable)
QString hostString = m_ui->droneOSComboBox->currentText();
//QString host = hostString.split(":").first();
+ LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();
+ UDPLink* firstUdp = NULL;
+
// Delete from all lists first
- UDPLink* firstUdp = NULL;
- QList links = qgcApp()->toolbox()->linkManager()->getLinks();
- foreach (LinkInterface* link, links)
- {
- UDPLink* udp = dynamic_cast(link);
+ for (int i=0; ilinks()->count(); i++) {
+ LinkInterface* link = linkMgr->links()->value(i);
+ UDPLink* udp = qobject_cast(link);
+
if (udp)
{
if (!firstUdp) firstUdp = udp;
diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc
index de6acff1ae3ff47bc3799d70d97f3be04cd813a4..592d37eb518c1425b9adf237ba55aba964280fb2 100644
--- a/src/ui/MainWindow.cc
+++ b/src/ui/MainWindow.cc
@@ -208,10 +208,6 @@ MainWindow::MainWindow()
connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
#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
if (_autoReconnect)
{
@@ -445,7 +441,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
QMessageBox::Yes | QMessageBox::Cancel,
QMessageBox::Cancel);
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
// 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.
@@ -456,11 +452,17 @@ void MainWindow::closeEvent(QCloseEvent *event)
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
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
// 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
// the MainWindow ends up getting deleted. Otherwise the Qml has a reference to MainWindow
@@ -649,11 +651,6 @@ void MainWindow::restoreLastUsedConnection()
}
}
-void MainWindow::_linkStateChange(LinkInterface*)
-{
- emit repaintCanvas();
-}
-
#ifdef QGC_MOUSE_ENABLED_LINUX
bool MainWindow::x11Event(XEvent *event)
{
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index 3ea0b300680c4e0d61497f761b5e19547ddcbefa..0772df024a91feb4770d0bc3a733253ff95e5329 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -159,8 +159,6 @@ signals:
void initStatusChanged(const QString& message, int alignment, const QColor &color);
/** 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);
- /** Emitted when any the Canvas elements within QML wudgets need updating */
- void repaintCanvas();
// Used for unit tests to know when the main window closes
void mainWindowClosed(void);
@@ -213,7 +211,6 @@ protected:
QTimer windowNameUpdateTimer;
private slots:
- void _linkStateChange(LinkInterface*);
void _closeWindow(void) { close(); }
void _vehicleAdded(Vehicle* vehicle);
diff --git a/src/ui/QGCLinkConfiguration.cc b/src/ui/QGCLinkConfiguration.cc
index 80ae6e9ec168da61c2499efc2f862519cd63e6f0..71c564a5dc73cd27587549a23027c04a39f79ab8 100644
--- a/src/ui/QGCLinkConfiguration.cc
+++ b/src/ui/QGCLinkConfiguration.cc
@@ -32,6 +32,8 @@ This file is part of the QGROUNDCONTROL project
#include "ui_QGCLinkConfiguration.h"
#include "QGCCommConfiguration.h"
#include "QGCMessageBox.h"
+#include "UDPLink.h"
+#include "TCPLink.h"
QGCLinkConfiguration::QGCLinkConfiguration(QWidget *parent) :
QWidget(parent),
@@ -69,14 +71,17 @@ void QGCLinkConfiguration::on_delLinkButton_clicked()
QMessageBox::Cancel);
if (button == QMessageBox::Yes) {
// Get link attached to this configuration (if any)
- LinkInterface* iface = config->getLink();
+ LinkInterface* iface = config->link();
if(iface) {
- // Disconnect it (if connected)
- qgcApp()->toolbox()->linkManager()->disconnectLink(iface);
+ qgcApp()->toolbox()->linkManager()->disconnectLink(iface, false /* disconnectAutoconnectLink */);
}
_viewModel->beginChange();
+
// Remove configuration
- qgcApp()->toolbox()->linkManager()->removeLinkConfiguration(config);
+ QmlObjectListModel* linkConfigurations = qgcApp()->toolbox()->linkManager()->linkConfigurations();
+ linkConfigurations->removeOne(config);
+ delete config;
+
// Save list
qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList();
_viewModel->endChange();
@@ -97,11 +102,11 @@ void QGCLinkConfiguration::on_connectLinkButton_clicked()
if(index.row() >= 0) {
LinkConfiguration* config = _viewModel->getConfiguration(index.row());
if(config) {
- LinkInterface* link = config->getLink();
+ LinkInterface* link = config->link();
if(link) {
// Disconnect Link
if (link->isConnected()) {
- qgcApp()->toolbox()->linkManager()->disconnectLink(link);
+ qgcApp()->toolbox()->linkManager()->disconnectLink(link, false /* disconnectAutoconnectLink */);
}
} else {
LinkInterface* link = qgcApp()->toolbox()->linkManager()->createConnectedLink(config);
@@ -186,7 +191,7 @@ void QGCLinkConfiguration::on_addLinkButton_clicked()
if(config) {
_fixUnnamed(config);
_viewModel->beginChange();
- qgcApp()->toolbox()->linkManager()->addLinkConfiguration(commDialog->getConfig());
+ qgcApp()->toolbox()->linkManager()->linkConfigurations()->append(commDialog->getConfig());
qgcApp()->toolbox()->linkManager()->saveLinkConfigurationList();
_viewModel->endChange();
}
@@ -240,7 +245,7 @@ void QGCLinkConfiguration::_updateButtons()
if(config->isDynamic()) {
deleteEnabled = false;
}
- LinkInterface* link = config->getLink();
+ LinkInterface* link = config->link();
if(link) {
_ui->connectLinkButton->setText("Disconnect");
} else {
@@ -261,16 +266,13 @@ LinkViewModel::LinkViewModel(QObject *parent) : QAbstractListModel(parent)
int LinkViewModel::rowCount( const QModelIndex & parent) const
{
Q_UNUSED(parent);
- QList cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList();
- int count = cfgList.count();
- return count;
+ return qgcApp()->toolbox()->linkManager()->linkConfigurations()->count();
}
QVariant LinkViewModel::data( const QModelIndex & index, int role) const
{
- QList cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList();
- if (role == Qt::DisplayRole && index.row() < cfgList.count()) {
- QString name(cfgList.at(index.row())->name());
+ if (role == Qt::DisplayRole && index.row() < rowCount()) {
+ QString name(qgcApp()->toolbox()->linkManager()->linkConfigurations()->value(index.row())->name());
return name;
}
return QVariant();
@@ -278,9 +280,8 @@ QVariant LinkViewModel::data( const QModelIndex & index, int role) const
LinkConfiguration* LinkViewModel::getConfiguration(int row)
{
- QList cfgList = qgcApp()->toolbox()->linkManager()->getLinkConfigurationList();
- if(row < cfgList.count()) {
- return cfgList.at(row);
+ if(row < rowCount()) {
+ return qgcApp()->toolbox()->linkManager()->linkConfigurations()->value(row);
}
return NULL;
}
diff --git a/src/ui/QGCMAVLinkInspector.cc b/src/ui/QGCMAVLinkInspector.cc
index 0ab169cd36aa50d8b86f1142098ee69a6f62f70b..56f4d2093e437a3d2ef839e897f9f7170fed2823 100644
--- a/src/ui/QGCMAVLinkInspector.cc
+++ b/src/ui/QGCMAVLinkInspector.cc
@@ -490,7 +490,10 @@ void QGCMAVLinkInspector::changeStreamInterval(int msgid, int interval)
mavlink_message_t msg;
mavlink_msg_request_data_stream_encode(_protocol->getSystemId(), _protocol->getComponentId(), &msg, &stream);
+#if 0
+ // FIXME: Is this really used?
_protocol->sendMessage(msg);
+#endif
}
void QGCMAVLinkInspector::rateTreeItemChanged(QTreeWidgetItem* paramItem, int column)
diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc
index 957a2e363ffb30e099b163fe9c7bbd45d393c13b..78332fcb59fdb781b8931be3423ec2a813c72f58 100644
--- a/src/ui/QGCMAVLinkLogPlayer.cc
+++ b/src/ui/QGCMAVLinkLogPlayer.cc
@@ -60,7 +60,7 @@ void QGCMAVLinkLogPlayer::_pause(void)
void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void)
{
// 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."));
return;
}
@@ -188,4 +188,4 @@ void QGCMAVLinkLogPlayer::_replayLinkDisconnected(void)
{
_enablePlaybackControls(false);
_replayLink = NULL;
-}
\ No newline at end of file
+}
diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml
index aea269f9fb82d90e9eff3d38b001f7ae3f9022ca..0555a46d870676e7febe0dd259d37540632a48b6 100644
--- a/src/ui/preferences/GeneralSettings.qml
+++ b/src/ui/preferences/GeneralSettings.qml
@@ -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
+ }
}
}
}
diff --git a/src/ui/toolbar/MainToolBar.qml b/src/ui/toolbar/MainToolBar.qml
index 577c5fba07dffb3ac71b7f2dd87bb76ea966c365..0b341755bc58b6185ad287a6b57fe16c940e4d02 100644
--- a/src/ui/toolbar/MainToolBar.qml
+++ b/src/ui/toolbar/MainToolBar.qml
@@ -31,6 +31,7 @@ import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
+import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
@@ -152,7 +153,7 @@ Rectangle {
}
function showMavStatus() {
- return (multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout === 0 && _controller.connectionCount > 0);
+ return (multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout === 0);
}
Component.onCompleted: {
@@ -250,7 +251,7 @@ Rectangle {
Item {
visible: showMavStatus() && !connectionStatus.visible
height: mainWindow.tbCellHeight
- width: (toolBar.width - viewRow.width - connectRow.width)
+ width: (toolBar.width - viewRow.width)
anchors.left: viewRow.right
anchors.leftMargin: mainWindow.tbSpacing * 2
anchors.verticalCenter: parent.verticalCenter
@@ -273,125 +274,6 @@ Rectangle {
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
Rectangle {
id: progressBar
diff --git a/src/ui/toolbar/MainToolBarController.cc b/src/ui/toolbar/MainToolBarController.cc
index 900e490670e5c3ddd74d65d98be7be76dafba20a..e7fa3e151b3ffb2e12fd3fb7430e7906fa5d9afd 100644
--- a/src/ui/toolbar/MainToolBarController.cc
+++ b/src/ui/toolbar/MainToolBarController.cc
@@ -43,24 +43,14 @@ MainToolBarController::MainToolBarController(QObject* parent)
: QObject(parent)
, _vehicle(NULL)
, _mav(NULL)
- , _connectionCount(0)
, _progressBarValue(0.0f)
- , _remoteRSSI(0)
- , _remoteRSSIstore(100.0)
, _telemetryRRSSI(0)
, _telemetryLRSSI(0)
, _rollDownMessages(0)
, _toolbarMessageVisible(false)
{
- emit configListChanged();
- emit connectionCountChanged(_connectionCount);
_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)
connect(qgcApp()->toolbox()->mavlinkProtocol(),
SIGNAL(radioStatusChanged(LinkInterface*, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)), this,
@@ -89,54 +79,6 @@ void MainToolBarController::onFlyView()
MainWindow::instance()->showFlyView();
}
-void MainToolBarController::onDisconnect(QString conf)
-{
- if(conf.isEmpty()) {
- // Disconnect Only Connected Link
- int connectedCount = 0;
- LinkInterface* connectedLink = NULL;
- QList 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 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)
{
Q_UNUSED(x);
@@ -177,7 +119,6 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle)
{
// Disconnect the previous one (if any)
if (_vehicle) {
- disconnect(_mav, &UASInterface::remoteControlRSSIChanged, this, &MainToolBarController::_remoteControlRSSIChanged);
disconnect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue);
_mav = NULL;
_vehicle = NULL;
@@ -188,109 +129,21 @@ void MainToolBarController::_activeVehicleChanged(Vehicle* vehicle)
{
_vehicle = vehicle;
_mav = vehicle->uas();
- connect(_mav, &UASInterface::remoteControlRSSIChanged, this, &MainToolBarController::_remoteControlRSSIChanged);
connect(_vehicle->autopilotPlugin(), &AutoPilotPlugin::parameterListProgress, this, &MainToolBarController::_setProgressBarValue);
}
}
-void MainToolBarController::_updateConfigurations()
-{
- QStringList tmpList;
- QList 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)
{
- // We only care if we haveone single connection
- if(_connectionCount == 1) {
- if((unsigned)_telemetryLRSSI != rssi) {
- // 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 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;
+ if((unsigned)_telemetryLRSSI != rssi) {
+ // According to the Silabs data sheet, the RSSI value is 0.5db per bit
+ _telemetryLRSSI = rssi >> 1;
emit telemetryLRSSIChanged(_telemetryLRSSI);
}
- if(_connectionCount != 1 && _remoteRSSI > 0) {
- _remoteRSSI = 0;
- emit remoteRSSIChanged(_remoteRSSI);
+ if((unsigned)_telemetryRRSSI != remrssi) {
+ // According to the Silabs data sheet, the RSSI value is 0.5db per bit
+ _telemetryRRSSI = remrssi >> 1;
+ emit telemetryRRSSIChanged(_telemetryRRSSI);
}
}
@@ -344,3 +197,8 @@ void MainToolBarController::showSettings(void)
{
MainWindow::instance()->showSettings();
}
+
+void MainToolBarController::manageLinks(void)
+{
+ MainWindow::instance()->manageLinks();
+}
diff --git a/src/ui/toolbar/MainToolBarController.h b/src/ui/toolbar/MainToolBarController.h
index eaf5d14a8396bc285bcf451221cc3fd98ed3401f..25e37f3af260fa5ae87fa8ec3ef16dfd43116e66 100644
--- a/src/ui/toolbar/MainToolBarController.h
+++ b/src/ui/toolbar/MainToolBarController.h
@@ -53,35 +53,24 @@ public:
Q_INVOKABLE void onSetupView();
Q_INVOKABLE void onPlanView();
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 onToolBarMessageClosed(void);
Q_INVOKABLE void showSettings(void);
+ Q_INVOKABLE void manageLinks(void);
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(int remoteRSSI READ remoteRSSI NOTIFY remoteRSSIChanged)
Q_PROPERTY(int telemetryRRSSI READ telemetryRRSSI NOTIFY telemetryRRSSIChanged)
Q_PROPERTY(int telemetryLRSSI READ telemetryLRSSI NOTIFY telemetryLRSSIChanged)
void viewStateChanged (const QString& key, bool value);
- int remoteRSSI () { return _remoteRSSI; }
int telemetryRRSSI () { return _telemetryRRSSI; }
int telemetryLRSSI () { return _telemetryLRSSI; }
- int connectionCount () { return _connectionCount; }
void showToolBarMessage(const QString& message);
signals:
- void connectionCountChanged (int count);
- void configListChanged ();
- void connectedListChanged (QStringList connectedList);
void progressBarValueChanged (float value);
- void remoteRSSIChanged (int value);
void telemetryRRSSIChanged (int value);
void telemetryLRSSIChanged (int value);
void heightChanged (double height);
@@ -91,26 +80,15 @@ signals:
private slots:
void _activeVehicleChanged (Vehicle* vehicle);
- void _updateConfigurations ();
- void _linkConnected (LinkInterface* link);
- void _linkDisconnected (LinkInterface* link);
void _leaveMessageView ();
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 _delayedShowToolBarMessage (void);
-private:
- void _updateConnection (LinkInterface *disconnectedLink = NULL);
-
private:
Vehicle* _vehicle;
UASInterface* _mav;
- QStringList _linkConfigurations;
- int _connectionCount;
- QStringList _connectedList;
float _progressBarValue;
- int _remoteRSSI;
double _remoteRSSIstore;
int _telemetryRRSSI;
int _telemetryLRSSI;
diff --git a/src/ui/toolbar/MainToolBarIndicators.qml b/src/ui/toolbar/MainToolBarIndicators.qml
index b819afbe36e9b6e0f15bea071c00cf4fa0ddb29c..18ea7045473aeb10f5d0827b1e77a9073017fab7 100644
--- a/src/ui/toolbar/MainToolBarIndicators.qml
+++ b/src/ui/toolbar/MainToolBarIndicators.qml
@@ -219,12 +219,12 @@ Row {
smooth: true
width: mainWindow.tbCellHeight * 0.65
height: mainWindow.tbCellHeight * 0.5
- opacity: _controller.remoteRSSI < 1 ? 0.5 : 1
+ opacity: activeVehicle.rcRSSI < 1 ? 0.5 : 1
anchors.verticalCenter: parent.verticalCenter
}
SignalStrength {
size: mainWindow.tbCellHeight * 0.5
- percent: _controller.remoteRSSI
+ percent: activeVehicle.rcRSSI
anchors.verticalCenter: parent.verticalCenter
}
}
@@ -284,10 +284,11 @@ Row {
//-------------------------------------------------------------------------
//-- Vehicle Selector
QGCButton {
- width: ScreenTools.defaultFontPixelSize * 12
- height: mainWindow.tbButtonWidth
- text: "Vehicle " + activeVehicle.id
- visible: vehicleMenuItems.length > 0
+ id: vehicleSelectorButton
+ width: ScreenTools.defaultFontPixelSize * 12
+ height: mainWindow.tbButtonWidth
+ text: "Vehicle " + activeVehicle.id
+ visible: QGroundControl.multiVehicleManager.vehicles.count > 1
anchors.verticalCenter: parent.verticalCenter
menu: vehicleMenu
@@ -331,7 +332,7 @@ Row {
Connections {
target: multiVehicleManager.vehicles
- onCountChanged: parent.updateVehicleMenu
+ onCountChanged: vehicleSelectorButton.updateVehicleMenu
}
}