diff --git a/custom-example/qgroundcontrol.qrc b/custom-example/qgroundcontrol.qrc
index 0f249c9d16d..f93644c9a20 100644
--- a/custom-example/qgroundcontrol.qrc
+++ b/custom-example/qgroundcontrol.qrc
@@ -31,7 +31,7 @@
../src/FlightMap/MapItems/MapLineArrow.qml
../src/FlightMap/MapItems/SplitIndicator.qml
../src/UI/preferences/ADSBServerSettings.qml
- ../src/AirLink/AirLinkSettings.qml
+ ../src/Comms/AirLink/AirLinkSettings.qml
../src/AnalyzeView/AnalyzeView.qml
../src/UI/AppSettings.qml
../src/UI/preferences/BluetoothSettings.qml
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 61516930996..a8a9488e16d 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -31,7 +31,7 @@
src/FlightMap/MapItems/MapLineArrow.qml
src/FlightMap/MapItems/SplitIndicator.qml
src/UI/preferences/ADSBServerSettings.qml
- src/AirLink/AirLinkSettings.qml
+ src/Comms/AirLink/AirLinkSettings.qml
src/AnalyzeView/AnalyzeView.qml
src/UI/AppSettings.qml
src/UI/preferences/BluetoothSettings.qml
diff --git a/src/AirLink/AirLinkManager.cc b/src/AirLink/AirLinkManager.cc
deleted file mode 100644
index 76c38895810..00000000000
--- a/src/AirLink/AirLinkManager.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
- *
- * (c) 2009-2024 QGROUNDCONTROL PROJECT
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#include "AirLinkManager.h"
-#include "SettingsManager.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-const QString AirLinkManager::airlinkHost = "air-link.space";
-
-AirLinkManager::AirLinkManager(QGCApplication* app, QGCToolbox* toolbox)
- : QGCTool(app, toolbox)
-{
-}
-
-AirLinkManager::~AirLinkManager()
-{
-}
-
-void AirLinkManager::setToolbox(QGCToolbox* toolbox)
-{
- QGCTool::setToolbox(toolbox);
-}
-
-QStringList AirLinkManager::droneList() const
-{
- return _vehiclesFromServer.keys();
-}
-
-void AirLinkManager::updateDroneList(const QString &login, const QString &pass)
-{
- connectToAirLinkServer(login, pass);
-}
-
-bool AirLinkManager::isOnline(const QString &drone)
-{
- if (!_vehiclesFromServer.contains(drone)) {
- return false;
- } else {
- return _vehiclesFromServer[drone];
- }
-}
-
-void AirLinkManager::connectToAirLinkServer(const QString &login, const QString &pass)
-{
- QNetworkAccessManager *mngr = new QNetworkAccessManager(this);
-
- const QUrl url("https://air-link.space/api/gs/getModems");
- QNetworkRequest request(url);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- QJsonObject obj;
- obj["login"] = login;
- obj["password"] = pass;
- QJsonDocument doc(obj);
- QByteArray data = doc.toJson();
-
- _reply = mngr->post(request, data);
-
- QObject::connect(_reply, &QNetworkReply::finished, [this](){
- _processReplyAirlinkServer(*_reply);
- _reply->deleteLater();
- });
-
- mngr = nullptr;
- delete mngr;
-}
-
-void AirLinkManager::updateCredentials(const QString &login, const QString &pass)
-{
- _toolbox->settingsManager()->appSettings()->loginAirLink()->setRawValue(login);
- _toolbox->settingsManager()->appSettings()->passAirLink()->setRawValue(pass);
-}
-
-void AirLinkManager::_parseAnswer(const QByteArray &ba)
-{
- _vehiclesFromServer.clear();
- for (const auto &arr : QJsonDocument::fromJson(ba)["modems"].toArray()) {
- QString droneModem = arr.toObject()["name"].toString();
- bool isOnline = arr.toObject()["isOnline"].toBool();
- _vehiclesFromServer[droneModem] = isOnline;
- }
- emit droneListChanged();
-}
-
-void AirLinkManager::_processReplyAirlinkServer(QNetworkReply &reply)
-{
- QByteArray ba = reply.readAll();
-
- if (reply.error() == QNetworkReply::NoError) {
- if (!QJsonDocument::fromJson(ba)["modems"].toArray().isEmpty()) {
- _parseAnswer(ba);
- } else {
- qDebug() << "No airlink modems in answer";
- }
- } else {
- qDebug() << "Airlink auth - network error";
- }
-}
-
diff --git a/src/AirLink/AirLinkManager.h b/src/AirLink/AirLinkManager.h
deleted file mode 100644
index 0b18dcf1abf..00000000000
--- a/src/AirLink/AirLinkManager.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************************
- *
- * (c) 2009-2024 QGROUNDCONTROL PROJECT
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#pragma once
-
-#include "QGCToolbox.h"
-
-#include
-
-class AppSettings;
-class QGCApplication;
-class LinkInterface;
-class QNetworkReply;
-
-//-----------------------------------------------------------------------------
-class AirLinkManager : public QGCTool
-{
- Q_OBJECT
-
-public:
- Q_PROPERTY(QStringList droneList READ droneList NOTIFY droneListChanged)
- Q_INVOKABLE void updateDroneList(const QString &login, const QString &pass);
- Q_INVOKABLE bool isOnline(const QString &drone);
- Q_INVOKABLE void connectToAirLinkServer(const QString &login, const QString &pass);
- Q_INVOKABLE void updateCredentials(const QString &login, const QString &pass);
-
- explicit AirLinkManager(QGCApplication* app, QGCToolbox* toolbox);
- ~AirLinkManager() override;
-
- void setToolbox (QGCToolbox* toolbox) override;
- QStringList droneList() const;
-
- static const QString airlinkHost;
- static constexpr int airlinkPort = 10000;
-
-signals:
- void droneListChanged();
-
-private:
- void _parseAnswer (const QByteArray &ba);
- void _processReplyAirlinkServer (QNetworkReply &reply);
-
-private:
- QMap _vehiclesFromServer;
- QNetworkReply* _reply;
-};
diff --git a/src/AirLink/AirlinkLink.cc b/src/AirLink/AirlinkLink.cc
deleted file mode 100644
index 6d6ffff151f..00000000000
--- a/src/AirLink/AirlinkLink.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
- *
- * (c) 2009-2024 QGROUNDCONTROL PROJECT
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#include "AirlinkLink.h"
-#include "AirLinkManager.h"
-#include "QGCApplication.h"
-#include "AppSettings.h"
-#include "SettingsManager.h"
-#include "MAVLinkProtocol.h"
-
-#include
-#include
-#include
-
-
-AirlinkConfiguration::AirlinkConfiguration(const QString &name) : UDPConfiguration(name)
-{
-
-}
-
-AirlinkConfiguration::AirlinkConfiguration(AirlinkConfiguration *source) : UDPConfiguration(source)
-{
- _copyFrom(source);
-}
-
-AirlinkConfiguration::~AirlinkConfiguration()
-{
-}
-
-void AirlinkConfiguration::setUsername(QString username)
-{
- _username = username;
-}
-
-void AirlinkConfiguration::setPassword(QString password)
-{
- _password = password;
-}
-
-void AirlinkConfiguration::setModemName(QString modemName)
-{
- _modemName = modemName;
-}
-
-void AirlinkConfiguration::loadSettings(QSettings &settings, const QString &root)
-{
- AppSettings *appSettings = qgcApp()->toolbox()->settingsManager()->appSettings();
- settings.beginGroup(root);
- _username = settings.value(_usernameSettingsKey, appSettings->loginAirLink()->rawValueString()).toString();
- _password = settings.value(_passwordSettingsKey, appSettings->passAirLink()->rawValueString()).toString();
- _modemName = settings.value(_modemNameSettingsKey).toString();
- settings.endGroup();
-}
-
-void AirlinkConfiguration::saveSettings(QSettings &settings, const QString &root)
-{
- settings.beginGroup(root);
- settings.setValue(_usernameSettingsKey, _username);
- settings.setValue(_passwordSettingsKey, _password);
- settings.setValue(_modemNameSettingsKey, _modemName);
- settings.endGroup();
-}
-
-void AirlinkConfiguration::copyFrom(LinkConfiguration *source)
-{
- LinkConfiguration::copyFrom(source);
- auto* udpSource = qobject_cast(source);
- if (udpSource) {
- UDPConfiguration::copyFrom(source);
- }
- _copyFrom(source);
-}
-
-void AirlinkConfiguration::_copyFrom(LinkConfiguration *source)
-{
- auto* airlinkSource = qobject_cast(source);
- if (airlinkSource) {
- _username = airlinkSource->username();
- _password = airlinkSource->password();
- _modemName = airlinkSource->modemName();
- } else {
- qWarning() << "Internal error: cannot read AirlinkConfiguration from given source";
- }
-}
-
-
-AirlinkLink::AirlinkLink(SharedLinkConfigurationPtr &config) : UDPLink(config)
-{
- _configureUdpSettings();
-}
-
-AirlinkLink::~AirlinkLink()
-{
-}
-
-// bool AirlinkLink::isConnected() const
-// {
-// return UDPLink::isConnected();
-// }
-
-void AirlinkLink::disconnect()
-{
- _setConnectFlag(false);
- UDPLink::disconnect();
-}
-
-// void AirlinkLink::run()
-// {
-// UDPLink::run();
-// }
-
-bool AirlinkLink::_connect()
-{
- start(NormalPriority);
- QTimer *pendingTimer = new QTimer;
- connect(pendingTimer, &QTimer::timeout, [this, pendingTimer] {
- pendingTimer->setInterval(3000);
- if (_stillConnecting()) {
- qDebug() << "Connecting...";
- _sendLoginMsgToAirLink();
- } else {
- qDebug() << "Stopping...";
- pendingTimer->stop();
- pendingTimer->deleteLater();
- }
- });
- MAVLinkProtocol *mavlink = qgcApp()->toolbox()->mavlinkProtocol();
- auto conn = std::make_shared();
- *conn = connect(mavlink, &MAVLinkProtocol::messageReceived, [this, conn] (LinkInterface* linkSrc, mavlink_message_t message) {
- if (this != linkSrc || message.msgid != MAVLINK_MSG_ID_AIRLINK_AUTH_RESPONSE) {
- return;
- }
- mavlink_airlink_auth_response_t responseMsg;
- mavlink_msg_airlink_auth_response_decode(&message, &responseMsg);
- int answer = responseMsg.resp_type;
- if (answer != AIRLINK_AUTH_RESPONSE_TYPE::AIRLINK_AUTH_OK) {
- qDebug() << "Airlink auth failed";
- return;
- }
- qDebug() << "Connected successfully";
- QObject::disconnect(*conn);
- _setConnectFlag(false);
- });
- _setConnectFlag(true);
- pendingTimer->start(0);
- return true;
-}
-
-void AirlinkLink::_configureUdpSettings()
-{
- quint16 availablePort = 14550;
- QUdpSocket udpSocket;
- while (!udpSocket.bind(QHostAddress::LocalHost, availablePort))
- availablePort++;
- UDPConfiguration* udpConfig = dynamic_cast(UDPLink::m_config.get());
- udpConfig->addHost(AirLinkManager::airlinkHost, AirLinkManager::airlinkPort);
- udpConfig->setLocalPort(availablePort);
- udpConfig->setDynamic(false);
-}
-
-void AirlinkLink::_sendLoginMsgToAirLink()
-{
- __mavlink_airlink_auth_t auth;
- uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
- mavlink_message_t mavmsg;
- AirlinkConfiguration* config = dynamic_cast(m_config.get());
- QString login = config->modemName(); ///< Connect not to account but to specific modem
- QString pass = config->password();
-
- memset(&auth.login, 0, sizeof(auth.login));
- memset(&auth.password, 0, sizeof(auth.password));
- strcpy(auth.login, login.toUtf8().constData());
- strcpy(auth.password, pass.toUtf8().constData());
-
- mavlink_msg_airlink_auth_pack(0, 0, &mavmsg, auth.login, auth.password);
- uint16_t len = mavlink_msg_to_send_buffer(buffer, &mavmsg);
- if (!_stillConnecting()) {
- qDebug() << "Force exit from connection";
- return;
- }
- writeBytesThreadSafe((const char *)buffer, len);
-}
-
-bool AirlinkLink::_stillConnecting()
-{
- QMutexLocker locker(&_mutex);
- return _needToConnect;
-}
-
-void AirlinkLink::_setConnectFlag(bool connect)
-{
- QMutexLocker locker(&_mutex);
- _needToConnect = connect;
-}
diff --git a/src/AirLink/AirlinkLink.h b/src/AirLink/AirlinkLink.h
deleted file mode 100644
index 2291fbcedaa..00000000000
--- a/src/AirLink/AirlinkLink.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
- *
- * (c) 2009-2024 QGROUNDCONTROL PROJECT
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#pragma once
-
-#include
-
-#include "UDPLink.h"
-
-class AirlinkConfiguration : public UDPConfiguration
-{
- Q_OBJECT
-public:
- Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
- Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
- Q_PROPERTY(QString modemName READ modemName WRITE setModemName NOTIFY modemNameChanged)
-
- AirlinkConfiguration(const QString& name);
- AirlinkConfiguration(AirlinkConfiguration* source);
- ~AirlinkConfiguration();
-
- QString username () const { return _username; }
- QString password () const { return _password; }
- QString modemName() const { return _modemName; }
-
- void setUsername (QString username);
- void setPassword (QString password);
- void setModemName (QString modemName);
-
- /// LinkConfiguration overrides
- LinkType type (void) override { return LinkConfiguration::Airlink; }
- void loadSettings (QSettings& settings, const QString& root) override;
- void saveSettings (QSettings& settings, const QString& root) override;
- QString settingsURL (void) override { return "AirLinkSettings.qml"; }
- QString settingsTitle (void) override { return tr("Airlink Link Settings"); }
- void copyFrom (LinkConfiguration* source) override;
-
-
-signals:
- void usernameChanged (void);
- void passwordChanged (void);
- void modemNameChanged (void);
-
-private:
- void _copyFrom (LinkConfiguration *source);
-
-
- QString _username;
- QString _password;
- QString _modemName;
-
- const QString _usernameSettingsKey = "username";
- const QString _passwordSettingsKey = "password";
- const QString _modemNameSettingsKey = "modemName";
-};
-
-class AirlinkLink : public UDPLink
-{
- Q_OBJECT
-public:
- AirlinkLink(SharedLinkConfigurationPtr& config);
- virtual ~AirlinkLink();
-
- /// LinkInterface overrides
- // bool isConnected(void) const override;
- void disconnect (void) override;
-
- /// QThread overrides
- // void run(void) override;
-
-private:
- /// LinkInterface overrides
- bool _connect(void) override;
-
- void _configureUdpSettings();
- void _sendLoginMsgToAirLink();
- bool _stillConnecting();
- void _setConnectFlag(bool connect);
-
- QMutex _mutex;
- /// Access this varible only with _mutex locked
- bool _needToConnect {false};
-};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 93b769f7eea..f712e3393db 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -23,7 +23,6 @@ if(QGC_UTM_ADAPTER)
endif()
add_subdirectory(ADSB)
-add_subdirectory(AirLink)
add_subdirectory(AnalyzeView)
add_subdirectory(API)
add_subdirectory(Audio)
@@ -68,7 +67,6 @@ target_link_libraries(QGC
Qt6::Bluetooth
API
ADSB
- AirLink
AnalyzeView
Audio
AutoPilotPlugins
diff --git a/src/Comms/AirLink/AirLinkLink.cc b/src/Comms/AirLink/AirLinkLink.cc
new file mode 100644
index 00000000000..c4a93891e8d
--- /dev/null
+++ b/src/Comms/AirLink/AirLinkLink.cc
@@ -0,0 +1,216 @@
+/****************************************************************************
+ *
+ * (c) 2009-2024 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#include "AirLinkLink.h"
+#include "QGCApplication.h"
+#include "AppSettings.h"
+#include "SettingsManager.h"
+#include "MAVLinkProtocol.h"
+#include "QGCLoggingCategory.h"
+
+#include
+#include
+#include
+
+QGC_LOGGING_CATEGORY(AirLinkLinkLog, "qgc.AirLink.AirLinklink");
+
+AirLinkLink::AirLinkLink(SharedLinkConfigurationPtr &config)
+ : UDPLink(config)
+ , _AirLinkConfig(qobject_cast(config.get()))
+{
+ // qCDebug(AirLinkLinkLog) << Q_FUNC_INFO << this;
+
+ _configureUdpSettings();
+}
+
+AirLinkLink::~AirLinkLink()
+{
+ // qCDebug(AirLinkLinkLog) << Q_FUNC_INFO << this;
+}
+
+void AirLinkLink::disconnect()
+{
+ _setConnectFlag(false);
+ UDPLink::disconnect();
+}
+
+bool AirLinkLink::_connect()
+{
+ start(NormalPriority);
+
+ QTimer *const pendingTimer = new QTimer(this);
+ (void) connect(pendingTimer, &QTimer::timeout, this, [this, pendingTimer] {
+ pendingTimer->setInterval(3000);
+ if (_stillConnecting()) {
+ qCDebug(AirLinkLinkLog) << "Connecting...";
+ _sendLoginMsgToAirLink();
+ } else {
+ qCDebug(AirLinkLinkLog) << "Stopping...";
+ pendingTimer->stop();
+ pendingTimer->deleteLater();
+ }
+ });
+
+ MAVLinkProtocol *const mavlink = qgcApp()->toolbox()->mavlinkProtocol();
+ auto conn = std::make_shared();
+ *conn = connect(mavlink, &MAVLinkProtocol::messageReceived, this, [this, conn] (LinkInterface* linkSrc, mavlink_message_t message) {
+ if (this != linkSrc || message.msgid != MAVLINK_MSG_ID_AIRLINK_AUTH_RESPONSE) {
+ return;
+ }
+
+ mavlink_airlink_auth_response_t responseMsg;
+ mavlink_msg_airlink_auth_response_decode(&message, &responseMsg);
+ const int answer = responseMsg.resp_type;
+ if (answer != AIRLINK_AUTH_RESPONSE_TYPE::AIRLINK_AUTH_OK) {
+ qCDebug(AirLinkLinkLog) << "AirLink auth failed";
+ return;
+ }
+
+ qCDebug(AirLinkLinkLog) << "Connected successfully";
+ QObject::disconnect(*conn);
+ _setConnectFlag(false);
+ });
+
+ _setConnectFlag(true);
+ pendingTimer->start(0);
+
+ return true;
+}
+
+void AirLinkLink::_configureUdpSettings()
+{
+ quint16 availablePort = 14550;
+ QUdpSocket udpSocket;
+ while (!udpSocket.bind(QHostAddress::LocalHost, availablePort)) {
+ availablePort++;
+ }
+
+ UDPConfiguration *const udpConfig = dynamic_cast(UDPLink::_config.get());
+ udpConfig->addHost(_airLinkHost, _airLinkPort);
+ udpConfig->setLocalPort(availablePort);
+ udpConfig->setDynamic(false);
+}
+
+void AirLinkLink::_sendLoginMsgToAirLink()
+{
+ mavlink_airlink_auth_t auth;
+ uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
+ mavlink_message_t mavmsg;
+ const QString login = _AirLinkConfig->modemName(); ///< Connect not to account but to specific modem
+ const QString pass = _AirLinkConfig->password();
+
+ memset(&auth.login, 0, sizeof(auth.login));
+ memset(&auth.password, 0, sizeof(auth.password));
+ strcpy(auth.login, login.toUtf8().constData());
+ strcpy(auth.password, pass.toUtf8().constData());
+
+ (void) mavlink_msg_airlink_auth_pack(0, 0, &mavmsg, auth.login, auth.password);
+ const uint16_t len = mavlink_msg_to_send_buffer(buffer, &mavmsg);
+ if (!_stillConnecting()) {
+ qCDebug(AirLinkLinkLog) << "Force exit from connection";
+ return;
+ }
+
+ writeBytesThreadSafe((const char *)buffer, len);
+}
+
+bool AirLinkLink::_stillConnecting()
+{
+ QMutexLocker locker(&_mutex);
+ return _needToConnect;
+}
+
+void AirLinkLink::_setConnectFlag(bool connect)
+{
+ QMutexLocker locker(&_mutex);
+ _needToConnect = connect;
+}
+
+AirLinkConfiguration::AirLinkConfiguration(const QString &name)
+ : UDPConfiguration(name)
+{
+ // qCDebug(AirLinkLinkLog) << Q_FUNC_INFO << this;
+}
+
+AirLinkConfiguration::AirLinkConfiguration(const AirLinkConfiguration *source)
+ : UDPConfiguration(source)
+{
+ // qCDebug(AirLinkLinkLog) << Q_FUNC_INFO << this;
+
+ _copyFrom(source);
+}
+
+AirLinkConfiguration::~AirLinkConfiguration()
+{
+ // qCDebug(AirLinkLinkLog) << Q_FUNC_INFO << this;
+}
+
+void AirLinkConfiguration::setUsername(const QString &username)
+{
+ if (username != _username) {
+ _username = username;
+ emit usernameChanged();
+ }
+}
+
+void AirLinkConfiguration::setPassword(const QString &password)
+{
+ if (password != _password) {
+ _password = password;
+ emit passwordChanged();
+ }
+}
+
+void AirLinkConfiguration::setModemName(const QString &modemName)
+{
+ if (modemName != _modemName) {
+ _modemName = modemName;
+ modemNameChanged();
+ }
+}
+
+void AirLinkConfiguration::loadSettings(QSettings &settings, const QString &root)
+{
+ AppSettings *const appSettings = qgcApp()->toolbox()->settingsManager()->appSettings();
+ settings.beginGroup(root);
+ _username = settings.value(_usernameSettingsKey, appSettings->loginAirLink()->rawValueString()).toString();
+ _password = settings.value(_passwordSettingsKey, appSettings->passAirLink()->rawValueString()).toString();
+ _modemName = settings.value(_modemNameSettingsKey).toString();
+ settings.endGroup();
+}
+
+void AirLinkConfiguration::saveSettings(QSettings &settings, const QString &root)
+{
+ settings.beginGroup(root);
+ settings.setValue(_usernameSettingsKey, _username);
+ settings.setValue(_passwordSettingsKey, _password);
+ settings.setValue(_modemNameSettingsKey, _modemName);
+ settings.endGroup();
+}
+
+void AirLinkConfiguration::copyFrom(const LinkConfiguration *source)
+{
+ const UDPConfiguration *const udpSource = qobject_cast(source);
+ if (udpSource) {
+ UDPConfiguration::copyFrom(source);
+ }
+ _copyFrom(source);
+}
+
+void AirLinkConfiguration::_copyFrom(const LinkConfiguration *source)
+{
+ const AirLinkConfiguration *const AirLinkSource = qobject_cast(source);
+ if (AirLinkSource) {
+ _username = AirLinkSource->username();
+ _password = AirLinkSource->password();
+ _modemName = AirLinkSource->modemName();
+ } else {
+ qCWarning(AirLinkLinkLog) << "Internal error: cannot read AirLinkConfiguration from given source";
+ }
+}
diff --git a/src/Comms/AirLink/AirLinkLink.h b/src/Comms/AirLink/AirLinkLink.h
new file mode 100644
index 00000000000..f5380132599
--- /dev/null
+++ b/src/Comms/AirLink/AirLinkLink.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+ *
+ * (c) 2009-2024 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include
+#include
+
+#include "UDPLink.h"
+
+Q_DECLARE_LOGGING_CATEGORY(AirLinkLinkLog)
+
+class AirLinkConfiguration : public UDPConfiguration
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
+ Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
+ Q_PROPERTY(QString modemName READ modemName WRITE setModemName NOTIFY modemNameChanged)
+public:
+ AirLinkConfiguration(const QString &name);
+ AirLinkConfiguration(const AirLinkConfiguration *source);
+ ~AirLinkConfiguration();
+
+ QString username() const { return _username; }
+ QString password() const { return _password; }
+ QString modemName() const { return _modemName; }
+
+ void setUsername(const QString &username);
+ void setPassword(const QString &password);
+ void setModemName(const QString &modemName);
+
+ LinkType type() const override { return LinkConfiguration::AirLink; }
+ void loadSettings(QSettings& settings, const QString& root) override;
+ void saveSettings(QSettings& settings, const QString& root) override;
+ QString settingsURL() override { return "AirLinkSettings.qml"; }
+ QString settingsTitle() override { return tr("AirLink Link Settings"); }
+ void copyFrom(const LinkConfiguration *source) override;
+
+signals:
+ void usernameChanged();
+ void passwordChanged();
+ void modemNameChanged();
+
+private:
+ void _copyFrom(const LinkConfiguration *source);
+
+ QString _username;
+ QString _password;
+ QString _modemName;
+
+ const QString _usernameSettingsKey = QStringLiteral("username");
+ const QString _passwordSettingsKey = QStringLiteral("password");
+ const QString _modemNameSettingsKey = QStringLiteral("modemName");
+};
+
+class AirLinkLink : public UDPLink
+{
+ Q_OBJECT
+
+public:
+ AirLinkLink(SharedLinkConfigurationPtr &config);
+ ~AirLinkLink();
+
+ void disconnect() override;
+
+private:
+ bool _connect() override;
+
+ void _configureUdpSettings();
+ void _sendLoginMsgToAirLink();
+ bool _stillConnecting();
+ void _setConnectFlag(bool connect);
+
+ const AirLinkConfiguration *_AirLinkConfig = nullptr;
+ QMutex _mutex;
+ bool _needToConnect = false;
+
+ static constexpr const char *_airLinkHost = "air-link.space";
+ static constexpr int _airLinkPort = 10000;
+};
diff --git a/src/Comms/AirLink/AirLinkManager.cc b/src/Comms/AirLink/AirLinkManager.cc
new file mode 100644
index 00000000000..2ca336791e8
--- /dev/null
+++ b/src/Comms/AirLink/AirLinkManager.cc
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *
+ * (c) 2009-2024 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#include "AirLinkManager.h"
+#include "QGCApplication.h"
+#include "QGCToolbox.h"
+#include "SettingsManager.h"
+#include "QGCLoggingCategory.h"
+
+#include
+#include
+#include
+#include
+#include
+
+QGC_LOGGING_CATEGORY(AirLinkManagerLog, "qgc.airlink.airlinkmanager");
+
+Q_APPLICATION_STATIC(AirLinkManager, _airLinkManager);
+
+AirLinkManager::AirLinkManager(QObject *parent)
+ : QObject(parent)
+ , _mngr(new QNetworkAccessManager(this))
+{
+ // qCDebug(AirLinkManagerLog) << Q_FUNC_INFO << this;
+}
+
+AirLinkManager::~AirLinkManager()
+{
+ // qCDebug(AirLinkManagerLog) << Q_FUNC_INFO << this;
+}
+
+AirLinkManager *AirLinkManager::instance()
+{
+ return _airLinkManager();
+}
+
+bool AirLinkManager::isOnline(const QString &drone)
+{
+ if (!_vehiclesFromServer.contains(drone)) {
+ return false;
+ } else {
+ return _vehiclesFromServer[drone];
+ }
+}
+
+void AirLinkManager::updateCredentials(const QString &login, const QString &pass)
+{
+ qgcApp()->toolbox()->settingsManager()->appSettings()->loginAirLink()->setRawValue(login);
+ qgcApp()->toolbox()->settingsManager()->appSettings()->passAirLink()->setRawValue(pass);
+}
+
+void AirLinkManager::_connectToAirLinkServer(const QString &login, const QString &pass)
+{
+ const QUrl url("https://air-link.space/api/gs/getModems");
+ QNetworkRequest request(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ QJsonObject obj;
+ obj["login"] = login;
+ obj["password"] = pass;
+ QJsonDocument doc(obj);
+ const QByteArray data = doc.toJson();
+
+ QNetworkReply *const reply = _mngr->post(request, data);
+ (void) QObject::connect(reply, &QNetworkReply::finished, this, &AirLinkManager::_processReplyAirlinkServer);
+}
+
+void AirLinkManager::_processReplyAirlinkServer()
+{
+ QNetworkReply* const reply = qobject_cast(sender());
+ if (!reply) {
+ return;
+ }
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError) {
+ qCDebug(AirLinkManagerLog) << "Airlink auth - network error";
+ return;
+ }
+
+ const QByteArray ba = reply->readAll();
+
+ if (!QJsonDocument::fromJson(ba)["modems"].toArray().isEmpty()) {
+ _parseAnswer(ba);
+ } else {
+ qCDebug(AirLinkManagerLog) << "No airlink modems in answer";
+ }
+}
+
+void AirLinkManager::_parseAnswer(const QByteArray &ba)
+{
+ _vehiclesFromServer.clear();
+
+ for (const auto &arr : QJsonDocument::fromJson(ba)["modems"].toArray()) {
+ const QString droneModem = arr.toObject()["name"].toString();
+ const bool isOnline = arr.toObject()["isOnline"].toBool();
+ _vehiclesFromServer[droneModem] = isOnline;
+ }
+
+ emit droneListChanged();
+}
diff --git a/src/Comms/AirLink/AirLinkManager.h b/src/Comms/AirLink/AirLinkManager.h
new file mode 100644
index 00000000000..b125de011d6
--- /dev/null
+++ b/src/Comms/AirLink/AirLinkManager.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *
+ * (c) 2009-2024 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+class QNetworkAccessManager;
+
+Q_DECLARE_LOGGING_CATEGORY(AirLinkManagerLog)
+
+class AirLinkManager : public QObject
+{
+ Q_OBJECT
+ // QML_ELEMENT
+ // QML_SINGLETON
+
+ Q_PROPERTY(QStringList droneList READ droneList NOTIFY droneListChanged)
+
+public:
+ explicit AirLinkManager(QObject *parent = nullptr);
+ ~AirLinkManager();
+
+ /// Gets the singleton instance of AirLinkManager.
+ /// @return The singleton instance.
+ static AirLinkManager *instance();
+
+ Q_INVOKABLE void updateDroneList(const QString &login, const QString &pass) { _connectToAirLinkServer(login, pass); }
+ Q_INVOKABLE bool isOnline(const QString &drone);
+ Q_INVOKABLE void updateCredentials(const QString &login, const QString &pass);
+
+ QStringList droneList() const { return _vehiclesFromServer.keys(); }
+
+signals:
+ void droneListChanged();
+
+private slots:
+ void _processReplyAirlinkServer();
+
+private:
+ void _connectToAirLinkServer(const QString &login, const QString &pass);
+ void _parseAnswer(const QByteArray &ba);
+
+ QNetworkAccessManager *_mngr = nullptr;
+ QMap _vehiclesFromServer;
+};
diff --git a/src/AirLink/AirLinkSettings.qml b/src/Comms/AirLink/AirLinkSettings.qml
similarity index 68%
rename from src/AirLink/AirLinkSettings.qml
rename to src/Comms/AirLink/AirLinkSettings.qml
index 2b676f32e10..f660ef652c7 100644
--- a/src/AirLink/AirLinkSettings.qml
+++ b/src/Comms/AirLink/AirLinkSettings.qml
@@ -8,28 +8,23 @@
****************************************************************************/
-import QtMultimedia
import QtQuick
import QtQuick.Controls
-import QtQuick.Dialogs
import QtQuick.Layouts
-import QtLocation
-import QtPositioning
import QGroundControl
import QGroundControl.Controllers
import QGroundControl.Controls
import QGroundControl.FactControls
import QGroundControl.FactSystem
-import QGroundControl.Palette
import QGroundControl.ScreenTools
import QGroundControl.SettingsManager
ColumnLayout {
spacing: _rowSpacing
- property Fact _loginFact: QGroundControl.settingsManager.appSettings.loginAirLink
- property Fact _passFact: QGroundControl.settingsManager.appSettings.passAirLink
+ property Fact _loginFact: QGroundControl.settingsManager.appSettings.loginAirLink
+ property Fact _passFact: QGroundControl.settingsManager.appSettings.passAirLink
function saveSettings() {
// No need
@@ -44,10 +39,7 @@ ColumnLayout {
columnSpacing: _colSpacing
rowSpacing: _rowSpacing
- QGCLabel {
- text: qsTr("Login:")
- }
-
+ QGCLabel { text: qsTr("Login:") }
QGCTextField {
id: loginField
text: _loginFact.rawValue
@@ -56,11 +48,7 @@ ColumnLayout {
onTextChanged: subEditConfig.username = loginField.text
}
-
- QGCLabel {
- text: qsTr("Password:")
- }
-
+ QGCLabel { text: qsTr("Password:") }
QGCTextField {
id: passwordField
text: _passFact.rawValue
@@ -70,40 +58,41 @@ ColumnLayout {
onTextChanged: subEditConfig.password = passwordField.text
}
}
+
QGCLabel {
text: "Forgot Your AirLink Password?"
font.underline: true
Layout.columnSpan: 2
MouseArea {
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: Qt.openUrlExternally("https://air-link.space/forgot-pass")
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: Qt.openUrlExternally("https://air-link.space/forgot-pass")
}
}
RowLayout {
spacing: _colSpacing
+
QGCLabel {
- wrapMode: Text.WordWrap
- text: qsTr("Don't have an account?")
+ wrapMode: Text.WordWrap
+ text: qsTr("Don't have an account?")
}
+
QGCLabel {
- font.underline: true
- wrapMode: Text.WordWrap
- text: qsTr("Register")
+ font.underline: true
+ wrapMode: Text.WordWrap
+ text: qsTr("Register")
MouseArea {
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: Qt.openUrlExternally("https://air-link.space/registration")
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: Qt.openUrlExternally("https://air-link.space/registration")
}
}
}
- QGCLabel {
- text: qsTr("List of available devices")
- }
+ QGCLabel { text: qsTr("List of available devices") }
RowLayout {
QGCComboBox {
@@ -113,6 +102,7 @@ ColumnLayout {
subEditConfig.modemName = QGroundControl.airlinkManager.droneList[index]
updateConnectionName(subEditConfig.modemName)
}
+
Connections {
target: QGroundControl.airlinkManager
// model update does not trigger onActivated, so we catch first element manually
@@ -124,8 +114,9 @@ ColumnLayout {
}
}
}
+
QGCButton {
- text: qsTr("Refresh")
+ text: qsTr("Refresh")
onClicked: {
QGroundControl.airlinkManager.updateDroneList(loginField.text, passwordField.text)
refreshHint.visible = false
@@ -135,10 +126,10 @@ ColumnLayout {
}
QGCLabel {
- id: refreshHint
- Layout.fillWidth: true
- font.pointSize: ScreenTools.smallFontPointSize
- wrapMode: Text.WordWrap
- text: qsTr("Click \"Refresh\" to authorize")
+ id: refreshHint
+ Layout.fillWidth: true
+ font.pointSize: ScreenTools.smallFontPointSize
+ wrapMode: Text.WordWrap
+ text: qsTr("Click \"Refresh\" to authorize")
}
}
diff --git a/src/AirLink/CMakeLists.txt b/src/Comms/AirLink/CMakeLists.txt
similarity index 78%
rename from src/AirLink/CMakeLists.txt
rename to src/Comms/AirLink/CMakeLists.txt
index d77a0e6a492..aee8e678825 100644
--- a/src/AirLink/CMakeLists.txt
+++ b/src/Comms/AirLink/CMakeLists.txt
@@ -4,29 +4,26 @@ qt_add_library(AirLink STATIC)
option(QGC_AIRLINK_DISABLED "Enable airlink" ON)
if(NOT QGC_AIRLINK_DISABLED)
- find_package(Qt6 COMPONENTS Network REQUIRED)
+ find_package(Qt6 REQUIRED COMPONENTS Network QmlIntegration)
target_sources(AirLink
PRIVATE
- AirlinkLink.cc
- AirlinkLink.h
+ AirLinkLink.cc
+ AirLinkLink.h
AirLinkManager.cc
AirLinkManager.h
)
- add_custom_target(AirLinkQml
- SOURCES
- AirLinkSettings.qml
- )
-
target_link_libraries(AirLink
PRIVATE
Qt6::Network
+ QGC
Settings
+ Utilities
PUBLIC
Qt6::Core
+ Qt6::QmlIntegration
Comms
- QGC
)
target_include_directories(AirLink PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
@@ -39,23 +36,21 @@ if(NOT QGC_AIRLINK_DISABLED)
# OUTPUT_TARGETS AirLink_targets
# IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY}
# IMPORTS
- # QtMultimedia
# QtQuick
# QtQuick.Controls
- # QtQuick.Dialogs
# QtQuick.Layouts
- # QtLocation
- # QtPositioning
# QGroundControl
# QGroundControl.Controllers
# QGroundControl.Controls
# QGroundControl.FactControls
# QGroundControl.FactSystem
- # QGroundControl.Palette
# QGroundControl.ScreenTools
# QGroundControl.SettingsManager
# )
+
+ # cmake_print_variables(AirLink_targets)
+ # target_link_libraries(AirLink PRIVATE AirLinkplugin)
else()
target_compile_definitions(AirLink PUBLIC QGC_AIRLINK_DISABLED)
endif()
diff --git a/src/Comms/CMakeLists.txt b/src/Comms/CMakeLists.txt
index 05da3a7f48a..643d3973fa3 100644
--- a/src/Comms/CMakeLists.txt
+++ b/src/Comms/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(AirLink)
add_subdirectory(MockLink)
find_package(Qt6 REQUIRED COMPONENTS Core Network Qml Test Widgets)
@@ -23,13 +24,13 @@ target_link_libraries(Comms
PRIVATE
Qt6::Qml
Qt6::Test
- AirLink
MockLink
Settings
Vehicle
PUBLIC
Qt6::Core
Qt6::Network
+ AirLink
MAVLink
QGC
QmlControls
diff --git a/src/Comms/LinkConfiguration.cc b/src/Comms/LinkConfiguration.cc
index cfb4d46c62b..d65137c5951 100644
--- a/src/Comms/LinkConfiguration.cc
+++ b/src/Comms/LinkConfiguration.cc
@@ -21,7 +21,7 @@
#include "MockLink.h"
#endif
#ifndef QGC_AIRLINK_DISABLED
-#include "AirlinkLink.h"
+#include "AirLinkLink.h"
#endif
LinkConfiguration::LinkConfiguration(const QString &name, QObject *parent)
@@ -90,8 +90,8 @@ LinkConfiguration *LinkConfiguration::createSettings(int type, const QString &na
break;
#endif
#ifndef QGC_AIRLINK_DISABLED
- case Airlink:
- config = new AirlinkConfiguration(name);
+ case AirLink:
+ config = new AirLinkConfiguration(name);
break;
#endif
case TypeLast:
@@ -132,8 +132,8 @@ LinkConfiguration *LinkConfiguration::duplicateSettings(const LinkConfiguration
break;
#endif
#ifndef QGC_AIRLINK_DISABLED
- case Airlink:
- dupe = new AirlinkConfiguration(qobject_cast(source));
+ case AirLink:
+ dupe = new AirLinkConfiguration(qobject_cast(source));
break;
#endif
case TypeLast:
diff --git a/src/Comms/LinkConfiguration.h b/src/Comms/LinkConfiguration.h
index 0d644b6b65e..ef90c37e8e7 100644
--- a/src/Comms/LinkConfiguration.h
+++ b/src/Comms/LinkConfiguration.h
@@ -79,7 +79,7 @@ class LinkConfiguration : public QObject
TypeMock, ///< Mock Link for Unitesting
#endif
#ifndef QGC_AIRLINK_DISABLED
- Airlink,
+ AirLink,
#endif
TypeLogReplay,
TypeLast // Last type value (type >= TypeLast == invalid)
diff --git a/src/Comms/LinkManager.cc b/src/Comms/LinkManager.cc
index 790913f68d1..9261faad172 100644
--- a/src/Comms/LinkManager.cc
+++ b/src/Comms/LinkManager.cc
@@ -36,7 +36,7 @@
#endif
#ifndef QGC_AIRLINK_DISABLED
-#include "AirlinkLink.h"
+#include "AirLinkLink.h"
#endif
#ifdef QGC_ZEROCONF_ENABLED
@@ -140,8 +140,8 @@ bool LinkManager::createConnectedLink(SharedLinkConfigurationPtr &config)
break;
#endif
#ifndef QGC_AIRLINK_DISABLED
- case LinkConfiguration::Airlink:
- link = std::make_shared(config);
+ case LinkConfiguration::AirLink:
+ link = std::make_shared(config);
break;
#endif
case LinkConfiguration::TypeLast:
@@ -344,8 +344,8 @@ void LinkManager::loadLinkConfigurationList()
break;
#endif
#ifndef QGC_AIRLINK_DISABLED
- case LinkConfiguration::Airlink:
- link = new AirlinkConfiguration(name);
+ case LinkConfiguration::AirLink:
+ link = new AirLinkConfiguration(name);
break;
#endif
case LinkConfiguration::TypeLast:
diff --git a/src/QGCToolbox.cc b/src/QGCToolbox.cc
index 1614d88c802..63a67404b4e 100644
--- a/src/QGCToolbox.cc
+++ b/src/QGCToolbox.cc
@@ -19,18 +19,14 @@
#include "QGCCorePlugin.h"
#include "SettingsManager.h"
#include "QGCApplication.h"
-#ifndef QGC_AIRLINK_DISABLED
-#include "AirLinkManager.h"
+#ifdef QGC_UTM_ADAPTER
+#include "UTMSPManager.h"
#endif
#if defined(QGC_CUSTOM_BUILD)
#include CUSTOMHEADER
#endif
-#ifdef QGC_UTM_ADAPTER
-#include "UTMSPManager.h"
-#endif
-
QGCToolbox::QGCToolbox(QGCApplication* app)
: QObject(app)
{
@@ -46,11 +42,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_multiVehicleManager = new MultiVehicleManager (app, this);
_qgcPositionManager = new QGCPositionManager (app, this);
_videoManager = new VideoManager (app, this);
-
_mavlinkLogManager = new MAVLinkLogManager (app, this);
-#ifndef QGC_AIRLINK_DISABLED
- _airlinkManager = new AirLinkManager (app, this);
-#endif
#ifdef QGC_UTM_ADAPTER
_utmspManager = new UTMSPManager (app, this);
#endif
@@ -70,9 +62,6 @@ void QGCToolbox::setChildToolboxes(void)
_qgcPositionManager->setToolbox(this);
_videoManager->setToolbox(this);
_mavlinkLogManager->setToolbox(this);
-#ifndef QGC_AIRLINK_DISABLED
- _airlinkManager->setToolbox(this);
-#endif
#ifdef QGC_UTM_ADAPTER
_utmspManager->setToolbox(this);
#endif
diff --git a/src/QGCToolbox.h b/src/QGCToolbox.h
index acef3379d6a..1b0c60d55dc 100644
--- a/src/QGCToolbox.h
+++ b/src/QGCToolbox.h
@@ -24,9 +24,6 @@ class VideoManager;
class MAVLinkLogManager;
class QGCCorePlugin;
class SettingsManager;
-#ifndef QGC_AIRLINK_DISABLED
-class AirLinkManager;
-#endif
#ifdef QGC_UTM_ADAPTER
class UTMSPManager;
#endif
@@ -48,9 +45,6 @@ class QGCToolbox : public QObject {
MAVLinkLogManager* mavlinkLogManager () { return _mavlinkLogManager; }
QGCCorePlugin* corePlugin () { return _corePlugin; }
SettingsManager* settingsManager () { return _settingsManager; }
-#ifndef QGC_AIRLINK_DISABLED
- AirLinkManager* airlinkManager () { return _airlinkManager; }
-#endif
#ifdef QGC_UTM_ADAPTER
UTMSPManager* utmspManager () { return _utmspManager; }
#endif
@@ -69,12 +63,8 @@ class QGCToolbox : public QObject {
MAVLinkLogManager* _mavlinkLogManager = nullptr;
QGCCorePlugin* _corePlugin = nullptr;
SettingsManager* _settingsManager = nullptr;
-#ifndef QGC_AIRLINK_DISABLED
- AirLinkManager* _airlinkManager = nullptr;
-#endif
-
#ifdef QGC_UTM_ADAPTER
- UTMSPManager* _utmspManager = nullptr;
+ UTMSPManager* _utmspManager = nullptr;
#endif
friend class QGCApplication;
};
diff --git a/src/QmlControls/QGroundControlQmlGlobal.cc b/src/QmlControls/QGroundControlQmlGlobal.cc
index 89d4238f310..3cbcf021c6e 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.cc
+++ b/src/QmlControls/QGroundControlQmlGlobal.cc
@@ -25,6 +25,9 @@
#ifdef QT_DEBUG
#include "MockLink.h"
#endif
+#ifndef QGC_AIRLINK_DISABLED
+#include "AirLinkManager.h"
+#endif
#include
#include
@@ -36,6 +39,9 @@ QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCApplication* app, QGCToolbox
: QGCTool(app, toolbox)
, _mapEngineManager(QGCMapEngineManager::instance())
, _adsbVehicleManager(ADSBVehicleManager::instance())
+#ifndef QGC_AIRLINK_DISABLED
+ , _airlinkManager(AirLinkManager::instance())
+#endif
{
// We clear the parent on this object since we run into shutdown problems caused by hybrid qml app. Instead we let it leak on shutdown.
// setParent(nullptr);
@@ -89,9 +95,6 @@ void QGroundControlQmlGlobal::setToolbox(QGCToolbox* toolbox)
_gpsRtkFactGroup = GPSManager::instance()->gpsRtk()->gpsRtkFactGroup();
#endif
_globalPalette = new QGCPalette(this);
-#ifndef QGC_AIRLINK_DISABLED
- _airlinkManager = toolbox->airlinkManager();
-#endif
#ifdef QGC_UTM_ADAPTER
_utmspManager = toolbox->utmspManager();
#endif
diff --git a/src/QmlControls/QGroundControlQmlGlobal.h b/src/QmlControls/QGroundControlQmlGlobal.h
index e9e2b41d39c..8c4121a8d76 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.h
+++ b/src/QmlControls/QGroundControlQmlGlobal.h
@@ -185,11 +185,11 @@ class QGroundControlQmlGlobal : public QGCTool
static QGeoCoordinate flightMapPosition () { return _coord; }
static double flightMapZoom () { return _zoom; }
- AirLinkManager* airlinkManager () { return _airlinkManager; }
#ifndef QGC_AIRLINK_DISABLED
+ AirLinkManager* airlinkManager () { return _airlinkManager; }
bool airlinkSupported () { return true; }
#else
- bool airlinkSupported () { return false; }
+ bool airlinkSupported () { return false; }
#endif
#ifdef QGC_UTM_ADAPTER
@@ -257,10 +257,14 @@ class QGroundControlQmlGlobal : public QGCTool
void skipSetupPageChanged ();
private:
+ QGCMapEngineManager* _mapEngineManager = nullptr;
+ ADSBVehicleManager* _adsbVehicleManager = nullptr;
+#ifndef QGC_AIRLINK_DISABLED
+ AirLinkManager* _airlinkManager = nullptr;
+#endif
double _flightMapInitialZoom = 17.0;
LinkManager* _linkManager = nullptr;
MultiVehicleManager* _multiVehicleManager = nullptr;
- QGCMapEngineManager* _mapEngineManager = nullptr;
QGCPositionManager* _qgcPositionManager = nullptr;
MissionCommandTree* _missionCommandTree = nullptr;
VideoManager* _videoManager = nullptr;
@@ -271,8 +275,6 @@ class QGroundControlQmlGlobal : public QGCTool
#ifndef NO_SERIAL_LINK
FactGroup* _gpsRtkFactGroup = nullptr;
#endif
- AirLinkManager* _airlinkManager = nullptr;
- ADSBVehicleManager* _adsbVehicleManager = nullptr;
QGCPalette* _globalPalette = nullptr;
QmlUnitsConversion _unitsConversion;
#ifdef QGC_UTM_ADAPTER