Commit dedb0c51 authored by Valentin Platzgummer's avatar Valentin Platzgummer

nemo interface moved to wima planer

parent 529f7da8
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -273,7 +273,6 @@ FlightMap { ...@@ -273,7 +273,6 @@ FlightMap {
MapItemView { MapItemView {
id: tileView id: tileView
property bool _enable: wimaController.enableWimaController.value property bool _enable: wimaController.enableWimaController.value
&& wimaController.enableSnake.value
property bool valid: wimaController.snakeTileCenterPoints.length property bool valid: wimaController.snakeTileCenterPoints.length
=== wimaController.nemoProgress.length === wimaController.nemoProgress.length
model: _enable ? wimaController.snakeTiles : 0 model: _enable ? wimaController.snakeTiles : 0
......
...@@ -46,7 +46,6 @@ Item { ...@@ -46,7 +46,6 @@ Item {
// Use Settings to store menu appearance through different sessions. // Use Settings to store menu appearance through different sessions.
Settings { Settings {
property alias snakeHeaderChecker: snakeHeader.checked
property alias missionHeaderChecker: missionHeader.checked property alias missionHeaderChecker: missionHeader.checked
property alias navigateHeaderChecker: navigateHeader.checked property alias navigateHeaderChecker: navigateHeader.checked
property alias vehicleHeaderChecker: vehicleHeader.checked property alias vehicleHeaderChecker: vehicleHeader.checked
...@@ -98,7 +97,6 @@ Item { ...@@ -98,7 +97,6 @@ Item {
property var enableWimaFact: wimaController.enableWimaController property var enableWimaFact: wimaController.enableWimaController
property bool enableWimaBoolean: enableWimaFact.value property bool enableWimaBoolean: enableWimaFact.value
property var enableSnakeFact: wimaController.enableSnake
onAccept: { onAccept: {
if (enableWimaBoolean) { if (enableWimaBoolean) {
...@@ -108,7 +106,6 @@ Item { ...@@ -108,7 +106,6 @@ Item {
} else { } else {
enableWimaFact.value = true enableWimaFact.value = true
enableWimaMouseArea.enabled = false enableWimaMouseArea.enabled = false
enableSnakeCheckBox.checkedState = false;
timer.stop() timer.stop()
} }
} }
...@@ -176,56 +173,6 @@ Item { ...@@ -176,56 +173,6 @@ Item {
id: mainColumn id: mainColumn
spacing: ScreenTools.defaultFontPixelHeight * 0.3 spacing: ScreenTools.defaultFontPixelHeight * 0.3
SectionHeader{
id: snakeHeader
text: qsTr("Snake Settings")
}
Column {
visible: snakeHeader.checked
spacing: ScreenTools.defaultFontPixelHeight * 0.5
FactCheckBox {
id: enableSnakeCheckBox
text: wimaController.enableSnake.value ?
qsTr("Disable Snake")
: qsTr("Enable Snake")
fact: wimaController.enableSnake
}
// Spacer
Item {
height: 1
}
// Snake status and settings column.
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
visible: wimaController.enableSnake.value
// Snake connection status.
QGCLabel {
property int index: wimaController.nemoStatus
property string statusString: wimaController.nemoStatusString
text: "Status: " + statusString
Layout.fillWidth: true
}
// Snake calculation status.
QGCLabel {
property bool _calcInProgress: wimaController.snakeCalcInProgress
text: _calcInProgress === true ?
qsTr("Calculation: In Progress")
: qsTr("Calculation: Idle")
Layout.fillWidth: true
}
}
}
SectionHeader{ SectionHeader{
id: missionHeader id: missionHeader
......
...@@ -143,7 +143,7 @@ Rectangle { ...@@ -143,7 +143,7 @@ Rectangle {
model: len model: len
delegate: QGCRadioButton { delegate: QGCRadioButton {
checked: index === variantRepeater.variant checked: index === variantRepeater.variant
text: variantRepeater.names[index] text: variantRepeater.names[index] ? variantRepeater.names[index]: ""
onCheckedChanged: { onCheckedChanged: {
if (checked){ if (checked){
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* *
****************************************************************************/ ****************************************************************************/
/** /**
* @file * @file
* @brief Implementation of class QGCApplication * @brief Implementation of class QGCApplication
...@@ -16,15 +15,15 @@ ...@@ -16,15 +15,15 @@
* *
*/ */
#include <QAction>
#include <QDesktopWidget>
#include <QFile> #include <QFile>
#include <QFlags> #include <QFlags>
#include <QPixmap>
#include <QDesktopWidget>
#include <QPainter> #include <QPainter>
#include <QStyleFactory> #include <QPixmap>
#include <QAction>
#include <QStringListModel>
#include <QRegularExpression> #include <QRegularExpression>
#include <QStringListModel>
#include <QStyleFactory>
#ifdef QGC_ENABLE_BLUETOOTH #ifdef QGC_ENABLE_BLUETOOTH
#include <QBluetoothLocalDevice> #include <QBluetoothLocalDevice>
...@@ -34,78 +33,79 @@ ...@@ -34,78 +33,79 @@
#include "VideoStreaming.h" #include "VideoStreaming.h"
#include "QGC.h" #include "AppMessages.h"
#include "QGCApplication.h"
#include "AudioOutput.h" #include "AudioOutput.h"
#include "AutoPilotPlugin.h"
#include "CameraCalc.h"
#include "CmdLineOptParser.h" #include "CmdLineOptParser.h"
#include "UDPLink.h" #include "CoordinateVector.h"
#include "LinkManager.h"
#include "UASMessageHandler.h"
#include "QGCTemporaryFile.h"
#include "QGCPalette.h"
#include "QGCMapPalette.h"
#include "QGCLoggingCategory.h"
#include "ViewWidgetController.h"
#include "ParameterEditorController.h"
#include "CustomCommandWidgetController.h" #include "CustomCommandWidgetController.h"
#include "ESP8266ComponentController.h" #include "ESP8266ComponentController.h"
#include "ScreenToolsController.h" #include "EditPositionDialogController.h"
#include "QGCFileDialogController.h" #include "FactValueSliderListModel.h"
#include "RCChannelMonitorController.h" #include "FirmwareImage.h"
#include "SyslinkComponentController.h"
#include "AutoPilotPlugin.h"
#include "VehicleComponent.h"
#include "FirmwarePluginManager.h" #include "FirmwarePluginManager.h"
#include "MultiVehicleManager.h" #include "FlightMapSettings.h"
#include "Vehicle.h" #include "FollowMe.h"
#include "JoystickConfigController.h" #include "JoystickConfigController.h"
#include "JoystickManager.h" #include "JoystickManager.h"
#include "QmlObjectListModel.h" #include "LinkManager.h"
#include "QGCGeoBoundingCube.h" #include "LogDownloadController.h"
#include "MissionCommandTree.h"
#include "MissionManager.h" #include "MissionManager.h"
#include "QGroundControlQmlGlobal.h" #include "MultiVehicleManager.h"
#include "FlightMapSettings.h" #include "ParameterEditorController.h"
#include "CoordinateVector.h" #include "ParameterManager.h"
#include "PlanMasterController.h" #include "PlanMasterController.h"
#include "Wima/WimaController.h"
#include "Wima/WimaBridge.h"
#include "Wima/WimaPlaner.h"
#include "VideoManager.h"
#include "VideoSurface.h"
#include "VideoReceiver.h"
#include "LogDownloadController.h"
#include "ValuesWidgetController.h"
#include "AppMessages.h"
#include "SimulatedPosition.h"
#include "PositionManager.h" #include "PositionManager.h"
#include "FollowMe.h" #include "QGC.h"
#include "MissionCommandTree.h" #include "QGCApplication.h"
#include "QGCMapPolygon.h" #include "QGCCameraManager.h"
#include "QGCCorePlugin.h"
#include "QGCFileDialogController.h"
#include "QGCFileDownload.h"
#include "QGCGeoBoundingCube.h"
#include "QGCLoggingCategory.h"
#include "QGCMapCircle.h" #include "QGCMapCircle.h"
#include "ParameterManager.h" #include "QGCMapPalette.h"
#include "QGCMapPolygon.h"
#include "QGCPalette.h"
#include "QGCTemporaryFile.h"
#include "QGroundControlQmlGlobal.h"
#include "QmlObjectListModel.h"
#include "RCChannelMonitorController.h"
#include "ScreenToolsController.h"
#include "SettingsManager.h" #include "SettingsManager.h"
#include "QGCCorePlugin.h"
#include "QGCCameraManager.h"
#include "CameraCalc.h"
#include "VisualMissionItem.h"
#include "EditPositionDialogController.h"
#include "FactValueSliderListModel.h"
#include "ShapeFileHelper.h" #include "ShapeFileHelper.h"
#include "QGCFileDownload.h" #include "SimulatedPosition.h"
#include "FirmwareImage.h" #include "SyslinkComponentController.h"
#include "UASMessageHandler.h"
#include "UDPLink.h"
#include "ValuesWidgetController.h"
#include "Vehicle.h"
#include "VehicleComponent.h"
#include "VideoManager.h"
#include "VideoReceiver.h"
#include "VideoSurface.h"
#include "ViewWidgetController.h"
#include "VisualMissionItem.h"
#include "Wima/Snake/NemoInterface.h"
#include "Wima/WimaBridge.h"
#include "Wima/WimaController.h"
#include "Wima/WimaPlaner.h"
#ifndef NO_SERIAL_LINK #ifndef NO_SERIAL_LINK
#include "SerialLink.h" #include "SerialLink.h"
#endif #endif
#ifndef __mobile__ #ifndef __mobile__
#include "QGCQFileDialog.h"
#include "QGCMessageBox.h"
#include "FirmwareUpgradeController.h" #include "FirmwareUpgradeController.h"
#include "MainWindow.h" #include "GPS/GPSManager.h"
#include "GeoTagController.h" #include "GeoTagController.h"
#include "MainWindow.h"
#include "MavlinkConsoleController.h" #include "MavlinkConsoleController.h"
#include "GPS/GPSManager.h" #include "QGCMessageBox.h"
#include "QGCQFileDialog.h"
#endif #endif
#ifdef QGC_RTLAB_ENABLED #ifdef QGC_RTLAB_ENABLED
...@@ -114,765 +114,842 @@ ...@@ -114,765 +114,842 @@
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
#ifndef __mobile__ #ifndef __mobile__
#include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#endif #endif
#endif #endif
#include "QGCMapEngine.h" #include "QGCMapEngine.h"
QGCApplication* QGCApplication::_app = nullptr; QGCApplication *QGCApplication::_app = nullptr;
const char* QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot"; const char *QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot";
const char* QGCApplication::_settingsVersionKey = "SettingsVersion"; const char *QGCApplication::_settingsVersionKey = "SettingsVersion";
const char* QGCApplication::_darkStyleFile = ":/res/styles/style-dark.css"; const char *QGCApplication::_darkStyleFile = ":/res/styles/style-dark.css";
const char* QGCApplication::_lightStyleFile = ":/res/styles/style-light.css"; const char *QGCApplication::_lightStyleFile = ":/res/styles/style-light.css";
// Mavlink status structures for entire app // Mavlink status structures for entire app
mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS]; mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
// Qml Singleton factories // Qml Singleton factories
static QObject* screenToolsControllerSingletonFactory(QQmlEngine*, QJSEngine*) static QObject *screenToolsControllerSingletonFactory(QQmlEngine *,
{ QJSEngine *) {
ScreenToolsController* screenToolsController = new ScreenToolsController; ScreenToolsController *screenToolsController = new ScreenToolsController;
return screenToolsController; return screenToolsController;
} }
static QObject* qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine*, QJSEngine*) static QObject *qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine *,
{ QJSEngine *) {
// We create this object as a QGCTool even though it isn't in the toolbox // We create this object as a QGCTool even though it isn't in the toolbox
QGroundControlQmlGlobal* qmlGlobal = new QGroundControlQmlGlobal(qgcApp(), qgcApp()->toolbox()); QGroundControlQmlGlobal *qmlGlobal =
qmlGlobal->setToolbox(qgcApp()->toolbox()); new QGroundControlQmlGlobal(qgcApp(), qgcApp()->toolbox());
qmlGlobal->setToolbox(qgcApp()->toolbox());
return qmlGlobal; return qmlGlobal;
} }
static QObject* shapeFileHelperSingletonFactory(QQmlEngine*, QJSEngine*) static QObject *shapeFileHelperSingletonFactory(QQmlEngine *, QJSEngine *) {
{ return new ShapeFileHelper;
return new ShapeFileHelper;
} }
QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) QGCApplication::QGCApplication(int &argc, char *argv[], bool unitTesting)
#ifdef __mobile__ #ifdef __mobile__
: QGuiApplication (argc, argv) : QGuiApplication(argc, argv), _qmlAppEngine(nullptr)
, _qmlAppEngine (nullptr)
#else #else
: QApplication (argc, argv) : QApplication(argc, argv)
#endif #endif
, _runningUnitTests (unitTesting) ,
, _logOutput (false) _runningUnitTests(unitTesting), _logOutput(false), _fakeMobile(false),
, _fakeMobile (false) _settingsUpgraded(false), _majorVersion(0), _minorVersion(0),
, _settingsUpgraded (false) _buildVersion(0), _currentVersionDownload(nullptr),
, _majorVersion (0) _gpsRtkFactGroup(nullptr), _toolbox(nullptr), _bluetoothAvailable(false) {
, _minorVersion (0) _app = this;
, _buildVersion (0)
, _currentVersionDownload (nullptr) QLocale locale = QLocale::system();
, _gpsRtkFactGroup (nullptr) //-- Some forced locales for testing
, _toolbox (nullptr) // QLocale locale = QLocale(QLocale::German);
, _bluetoothAvailable (false) // QLocale locale = QLocale(QLocale::French);
{ // QLocale locale = QLocale(QLocale::Chinese);
_app = this; #if defined(__macos__)
locale = QLocale(locale.name());
QLocale locale = QLocale::system();
//-- Some forced locales for testing
//QLocale locale = QLocale(QLocale::German);
//QLocale locale = QLocale(QLocale::French);
//QLocale locale = QLocale(QLocale::Chinese);
#if defined (__macos__)
locale = QLocale(locale.name());
#endif #endif
qDebug() << "System reported locale:" << locale << locale.name(); qDebug() << "System reported locale:" << locale << locale.name();
//-- Our localization //-- Our localization
if(_QGCTranslator.load(locale, "qgc_", "", ":/localization")) if (_QGCTranslator.load(locale, "qgc_", "", ":/localization"))
_app->installTranslator(&_QGCTranslator); _app->installTranslator(&_QGCTranslator);
// This prevents usage of QQuickWidget to fail since it doesn't support native widget siblings // This prevents usage of QQuickWidget to fail since it doesn't support
// native widget siblings
#ifndef __android__ #ifndef __android__
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#endif #endif
// Setup for network proxy support // Setup for network proxy support
QNetworkProxyFactory::setUseSystemConfiguration(true); QNetworkProxyFactory::setUseSystemConfiguration(true);
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
#ifndef __mobile__ #ifndef __mobile__
if (!_runningUnitTests) { if (!_runningUnitTests) {
if (getuid() == 0) { if (getuid() == 0) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setInformativeText(tr("You are running %1 as root. " msgBox.setInformativeText(
"You should not do this since it will cause other issues with %1. " tr("You are running %1 as root. "
"%1 will now exit. " "You should not do this since it will cause other issues with %1. "
"If you are having serial port issues on Ubuntu, execute the following commands to fix most issues:\n" "%1 will now exit. "
"sudo usermod -a -G dialout $USER\n" "If you are having serial port issues on Ubuntu, execute the "
"sudo apt-get remove modemmanager").arg(qgcApp()->applicationName())); "following commands to fix most issues:\n"
msgBox.setStandardButtons(QMessageBox::Ok); "sudo usermod -a -G dialout $USER\n"
msgBox.setDefaultButton(QMessageBox::Ok); "sudo apt-get remove modemmanager")
msgBox.exec(); .arg(qgcApp()->applicationName()));
_exit(0); msgBox.setStandardButtons(QMessageBox::Ok);
} msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
_exit(0);
}
// Determine if we have the correct permissions to access USB serial devices // Determine if we have the correct permissions to access USB serial devices
QFile permFile("/etc/group"); QFile permFile("/etc/group");
if(permFile.open(QIODevice::ReadOnly)) { if (permFile.open(QIODevice::ReadOnly)) {
while(!permFile.atEnd()) { while (!permFile.atEnd()) {
QString line = permFile.readLine(); QString line = permFile.readLine();
if (line.contains("dialout") && !line.contains(getenv("USER"))) { if (line.contains("dialout") && !line.contains(getenv("USER"))) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setInformativeText("The current user does not have the correct permissions to access serial devices. " msgBox.setInformativeText(
"You should also remove modemmanager since it also interferes. " "The current user does not have the correct permissions to "
"If you are using Ubuntu, execute the following commands to fix these issues:\n" "access serial devices. "
"sudo usermod -a -G dialout $USER\n" "You should also remove modemmanager since it also interferes. "
"sudo apt-get remove modemmanager"); "If you are using Ubuntu, execute the following commands to fix "
msgBox.setStandardButtons(QMessageBox::Ok); "these issues:\n"
msgBox.setDefaultButton(QMessageBox::Ok); "sudo usermod -a -G dialout $USER\n"
msgBox.exec(); "sudo apt-get remove modemmanager");
break; msgBox.setStandardButtons(QMessageBox::Ok);
} msgBox.setDefaultButton(QMessageBox::Ok);
} msgBox.exec();
permFile.close(); break;
} }
}
permFile.close();
} }
}
#endif #endif
#endif #endif
// Parse command line options // Parse command line options
bool fClearSettingsOptions = false; // Clear stored settings bool fClearSettingsOptions = false; // Clear stored settings
bool fClearCache = false; // Clear parameter/airframe caches bool fClearCache = false; // Clear parameter/airframe caches
bool logging = false; // Turn on logging bool logging = false; // Turn on logging
QString loggingOptions; QString loggingOptions;
CmdLineOpt_t rgCmdLineOptions[] = { CmdLineOpt_t rgCmdLineOptions[] = {
{ "--clear-settings", &fClearSettingsOptions, nullptr }, {"--clear-settings", &fClearSettingsOptions, nullptr},
{ "--clear-cache", &fClearCache, nullptr }, {"--clear-cache", &fClearCache, nullptr},
{ "--logging", &logging, &loggingOptions }, {"--logging", &logging, &loggingOptions},
{ "--fake-mobile", &_fakeMobile, nullptr }, {"--fake-mobile", &_fakeMobile, nullptr},
{ "--log-output", &_logOutput, nullptr }, {"--log-output", &_logOutput, nullptr},
// Add additional command line option flags here // Add additional command line option flags here
}; };
ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false); ParseCmdLineOptions(argc, argv, rgCmdLineOptions,
sizeof(rgCmdLineOptions) / sizeof(rgCmdLineOptions[0]),
// Set up timer for delayed missing fact display false);
_missingParamsDelayedDisplayTimer.setSingleShot(true);
_missingParamsDelayedDisplayTimer.setInterval(_missingParamsDelayedDisplayTimerTimeout); // Set up timer for delayed missing fact display
connect(&_missingParamsDelayedDisplayTimer, &QTimer::timeout, this, &QGCApplication::_missingParamsDisplay); _missingParamsDelayedDisplayTimer.setSingleShot(true);
_missingParamsDelayedDisplayTimer.setInterval(
// Set application information _missingParamsDelayedDisplayTimerTimeout);
if (_runningUnitTests) { connect(&_missingParamsDelayedDisplayTimer, &QTimer::timeout, this,
// We don't want unit tests to use the same QSettings space as the normal app. So we tweak the app &QGCApplication::_missingParamsDisplay);
// name. Also we want to run unit tests with clean settings every time.
setApplicationName(QString("%1_unittest").arg(QGC_APPLICATION_NAME)); // Set application information
} else { if (_runningUnitTests) {
setApplicationName(QGC_APPLICATION_NAME); // We don't want unit tests to use the same QSettings space as the normal
} // app. So we tweak the app name. Also we want to run unit tests with clean
setOrganizationName(QGC_ORG_NAME); // settings every time.
setOrganizationDomain(QGC_ORG_DOMAIN); setApplicationName(QString("%1_unittest").arg(QGC_APPLICATION_NAME));
} else {
this->setApplicationVersion(QString(GIT_VERSION)); setApplicationName(QGC_APPLICATION_NAME);
}
// Set settings format setOrganizationName(QGC_ORG_NAME);
QSettings::setDefaultFormat(QSettings::IniFormat); setOrganizationDomain(QGC_ORG_DOMAIN);
QSettings settings;
qDebug() << "Settings location" << settings.fileName() << "Is writable?:" << settings.isWritable(); this->setApplicationVersion(QString(GIT_VERSION));
// Set settings format
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings;
qDebug() << "Settings location" << settings.fileName()
<< "Is writable?:" << settings.isWritable();
#ifdef UNITTEST_BUILD #ifdef UNITTEST_BUILD
if (!settings.isWritable()) { if (!settings.isWritable()) {
qWarning() << "Setings location is not writable"; qWarning() << "Setings location is not writable";
} }
#endif #endif
// The setting will delete all settings on this boot // The setting will delete all settings on this boot
fClearSettingsOptions |= settings.contains(_deleteAllSettingsKey); fClearSettingsOptions |= settings.contains(_deleteAllSettingsKey);
if (_runningUnitTests) { if (_runningUnitTests) {
// Unit tests run with clean settings // Unit tests run with clean settings
fClearSettingsOptions = true; fClearSettingsOptions = true;
} }
if (fClearSettingsOptions) { if (fClearSettingsOptions) {
// User requested settings to be cleared on command line // User requested settings to be cleared on command line
settings.clear();
// Clear parameter cache
QDir paramDir(ParameterManager::parameterCacheDir());
paramDir.removeRecursively();
paramDir.mkpath(paramDir.absolutePath());
} else {
// Determine if upgrade message for settings version bump is required. Check
// and clear must happen before toolbox is started since that will write
// some settings.
if (settings.contains(_settingsVersionKey)) {
if (settings.value(_settingsVersionKey).toInt() != QGC_SETTINGS_VERSION) {
settings.clear(); settings.clear();
_settingsUpgraded = true;
// Clear parameter cache }
QDir paramDir(ParameterManager::parameterCacheDir()); } else if (settings.allKeys().count()) {
paramDir.removeRecursively(); // Settings version key is missing and there are settings. This is an
paramDir.mkpath(paramDir.absolutePath()); // upgrade scenario.
} else { settings.clear();
// Determine if upgrade message for settings version bump is required. Check and clear must happen before toolbox is started since _settingsUpgraded = true;
// that will write some settings.
if (settings.contains(_settingsVersionKey)) {
if (settings.value(_settingsVersionKey).toInt() != QGC_SETTINGS_VERSION) {
settings.clear();
_settingsUpgraded = true;
}
} else if (settings.allKeys().count()) {
// Settings version key is missing and there are settings. This is an upgrade scenario.
settings.clear();
_settingsUpgraded = true;
}
}
settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
if (fClearCache) {
QDir dir(ParameterManager::parameterCacheDir());
dir.removeRecursively();
QFile airframe(cachedAirframeMetaDataFile());
airframe.remove();
QFile parameter(cachedParameterMetaDataFile());
parameter.remove();
} }
}
// Set up our logging filters settings.setValue(_settingsVersionKey, QGC_SETTINGS_VERSION);
QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(loggingOptions);
if (fClearCache) {
// Initialize Bluetooth QDir dir(ParameterManager::parameterCacheDir());
dir.removeRecursively();
QFile airframe(cachedAirframeMetaDataFile());
airframe.remove();
QFile parameter(cachedParameterMetaDataFile());
parameter.remove();
}
// Set up our logging filters
QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(
loggingOptions);
// Initialize Bluetooth
#ifdef QGC_ENABLE_BLUETOOTHsubPolylines #ifdef QGC_ENABLE_BLUETOOTHsubPolylines
QBluetoothLocalDevice localDevice; QBluetoothLocalDevice localDevice;
if (localDevice.isValid()) if (localDevice.isValid()) {
{ _bluetoothAvailable = true;
_bluetoothAvailable = true; }
}
#endif #endif
// Gstreamer debug settings // Gstreamer debug settings
#if defined(__ios__) || defined(__android__) #if defined(__ios__) || defined(__android__)
// Initialize Video Streaming // Initialize Video Streaming
initializeVideoStreaming(argc, argv, nullptr, nullptr); initializeVideoStreaming(argc, argv, nullptr, nullptr);
#else #else
QString savePath, gstDebugLevel; QString savePath, gstDebugLevel;
if (settings.contains(AppSettings::savePathName)) { if (settings.contains(AppSettings::savePathName)) {
savePath = settings.value(AppSettings::savePathName).toString(); savePath = settings.value(AppSettings::savePathName).toString();
} }
if(savePath.isEmpty()) { if (savePath.isEmpty()) {
savePath = "/tmp"; savePath = "/tmp";
} }
savePath = savePath + "/Logs/gst"; savePath = savePath + "/Logs/gst";
if (!QDir(savePath).exists()) { if (!QDir(savePath).exists()) {
QDir().mkpath(savePath); QDir().mkpath(savePath);
} }
if (settings.contains(AppSettings::gstDebugLevelName)) { if (settings.contains(AppSettings::gstDebugLevelName)) {
gstDebugLevel = "*:" + settings.value(AppSettings::gstDebugLevelName).toString(); gstDebugLevel =
} "*:" + settings.value(AppSettings::gstDebugLevelName).toString();
// Initialize Video Streaming }
initializeVideoStreaming(argc, argv, savePath.toUtf8().data(), gstDebugLevel.toUtf8().data()); // Initialize Video Streaming
initializeVideoStreaming(argc, argv, savePath.toUtf8().data(),
gstDebugLevel.toUtf8().data());
#endif #endif
_toolbox = new QGCToolbox(this); _toolbox = new QGCToolbox(this);
_toolbox->setChildToolboxes(); _toolbox->setChildToolboxes();
#ifndef __mobile__ #ifndef __mobile__
_gpsRtkFactGroup = new GPSRTKFactGroup(this); _gpsRtkFactGroup = new GPSRTKFactGroup(this);
GPSManager *gpsManager = _toolbox->gpsManager(); GPSManager *gpsManager = _toolbox->gpsManager();
if (gpsManager) { if (gpsManager) {
connect(gpsManager, &GPSManager::onConnect, this, &QGCApplication::_onGPSConnect); connect(gpsManager, &GPSManager::onConnect, this,
connect(gpsManager, &GPSManager::onDisconnect, this, &QGCApplication::_onGPSDisconnect); &QGCApplication::_onGPSConnect);
connect(gpsManager, &GPSManager::surveyInStatus, this, &QGCApplication::_gpsSurveyInStatus); connect(gpsManager, &GPSManager::onDisconnect, this,
connect(gpsManager, &GPSManager::satelliteUpdate, this, &QGCApplication::_gpsNumSatellites); &QGCApplication::_onGPSDisconnect);
} connect(gpsManager, &GPSManager::surveyInStatus, this,
&QGCApplication::_gpsSurveyInStatus);
connect(gpsManager, &GPSManager::satelliteUpdate, this,
&QGCApplication::_gpsNumSatellites);
}
#endif /* __mobile__ */ #endif /* __mobile__ */
_checkForNewVersion(); _checkForNewVersion();
} }
void QGCApplication::_shutdown(void) void QGCApplication::_shutdown(void) {
{ // This code is specifically not in the destructor since the application
// This code is specifically not in the destructor since the application object may not be available in the destructor. // object may not be available in the destructor. This cause problems for
// This cause problems for deleting object like settings which are in the toolbox which may have qml references. By // deleting object like settings which are in the toolbox which may have qml
// moving them here and having main.cc call this prior to deleting the app object we make sure app object is still // references. By moving them here and having main.cc call this prior to
// around while these things are shutting down. // deleting the app object we make sure app object is still around while these
// things are shutting down.
#ifndef __mobile__ #ifndef __mobile__
MainWindow* mainWindow = MainWindow::instance(); MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) { if (mainWindow) {
delete mainWindow; delete mainWindow;
} }
#endif #endif
shutdownVideoStreaming(); shutdownVideoStreaming();
delete _toolbox; delete _toolbox;
} }
QGCApplication::~QGCApplication() QGCApplication::~QGCApplication() {
{ // Place shutdown code in _shutdown
// Place shutdown code in _shutdown _app = nullptr;
_app = nullptr; }
}
void QGCApplication::_initCommon(void) {
void QGCApplication::_initCommon(void) static const char *kRefOnly = "Reference only";
{ static const char *kQGCControllers = "QGroundControl.Controllers";
static const char* kRefOnly = "Reference only"; static const char *kQGCVehicle = "QGroundControl.Vehicle";
static const char* kQGCControllers = "QGroundControl.Controllers";
static const char* kQGCVehicle = "QGroundControl.Vehicle"; QSettings settings;
QSettings settings; // Register our Qml objects
// Register our Qml objects qmlRegisterType<QGCPalette>("QGroundControl.Palette", 1, 0, "QGCPalette");
qmlRegisterType<QGCMapPalette>("QGroundControl.Palette", 1, 0,
qmlRegisterType<QGCPalette> ("QGroundControl.Palette", 1, 0, "QGCPalette"); "QGCMapPalette");
qmlRegisterType<QGCMapPalette> ("QGroundControl.Palette", 1, 0, "QGCMapPalette");
qmlRegisterUncreatableType<Vehicle>(kQGCVehicle, 1, 0, "Vehicle", kRefOnly);
qmlRegisterUncreatableType<Vehicle> (kQGCVehicle, 1, 0, "Vehicle", kRefOnly); qmlRegisterUncreatableType<MissionItem>(kQGCVehicle, 1, 0, "MissionItem",
qmlRegisterUncreatableType<MissionItem> (kQGCVehicle, 1, 0, "MissionItem", kRefOnly); kRefOnly);
qmlRegisterUncreatableType<MissionManager> (kQGCVehicle, 1, 0, "MissionManager", kRefOnly); qmlRegisterUncreatableType<MissionManager>(kQGCVehicle, 1, 0,
qmlRegisterUncreatableType<ParameterManager> (kQGCVehicle, 1, 0, "ParameterManager", kRefOnly); "MissionManager", kRefOnly);
qmlRegisterUncreatableType<QGCCameraManager> (kQGCVehicle, 1, 0, "QGCCameraManager", kRefOnly); qmlRegisterUncreatableType<ParameterManager>(kQGCVehicle, 1, 0,
qmlRegisterUncreatableType<QGCCameraControl> (kQGCVehicle, 1, 0, "QGCCameraControl", kRefOnly); "ParameterManager", kRefOnly);
qmlRegisterUncreatableType<QGCVideoStreamInfo> (kQGCVehicle, 1, 0, "QGCVideoStreamInfo", kRefOnly); qmlRegisterUncreatableType<QGCCameraManager>(kQGCVehicle, 1, 0,
qmlRegisterUncreatableType<LinkInterface> (kQGCVehicle, 1, 0, "LinkInterface", kRefOnly); "QGCCameraManager", kRefOnly);
qmlRegisterUncreatableType<MissionController> (kQGCControllers, 1, 0, "MissionController", kRefOnly); qmlRegisterUncreatableType<QGCCameraControl>(kQGCVehicle, 1, 0,
qmlRegisterUncreatableType<GeoFenceController> (kQGCControllers, 1, 0, "GeoFenceController", kRefOnly); "QGCCameraControl", kRefOnly);
qmlRegisterUncreatableType<RallyPointController>(kQGCControllers, 1, 0, "RallyPointController", kRefOnly); qmlRegisterUncreatableType<QGCVideoStreamInfo>(
qmlRegisterUncreatableType<VisualMissionItem> (kQGCControllers, 1, 0, "VisualMissionItem", kRefOnly); kQGCVehicle, 1, 0, "QGCVideoStreamInfo", kRefOnly);
qmlRegisterUncreatableType<LinkInterface>(kQGCVehicle, 1, 0, "LinkInterface",
kRefOnly);
qmlRegisterUncreatableType<CoordinateVector> ("QGroundControl", 1, 0, "CoordinateVector", kRefOnly); qmlRegisterUncreatableType<MissionController>(kQGCControllers, 1, 0,
qmlRegisterUncreatableType<QmlObjectListModel> ("QGroundControl", 1, 0, "QmlObjectListModel", kRefOnly); "MissionController", kRefOnly);
qmlRegisterUncreatableType<MissionCommandTree> ("QGroundControl", 1, 0, "MissionCommandTree", kRefOnly); qmlRegisterUncreatableType<GeoFenceController>(
qmlRegisterUncreatableType<CameraCalc> ("QGroundControl", 1, 0, "CameraCalc", kRefOnly); kQGCControllers, 1, 0, "GeoFenceController", kRefOnly);
qmlRegisterUncreatableType<RallyPointController>(
qmlRegisterUncreatableType<AutoPilotPlugin> ("QGroundControl.AutoPilotPlugin", 1, 0, "AutoPilotPlugin", kRefOnly); kQGCControllers, 1, 0, "RallyPointController", kRefOnly);
qmlRegisterUncreatableType<VehicleComponent> ("QGroundControl.AutoPilotPlugin", 1, 0, "VehicleComponent", kRefOnly); qmlRegisterUncreatableType<VisualMissionItem>(kQGCControllers, 1, 0,
qmlRegisterUncreatableType<JoystickManager> ("QGroundControl.JoystickManager", 1, 0, "JoystickManager", kRefOnly); "VisualMissionItem", kRefOnly);
qmlRegisterUncreatableType<Joystick> ("QGroundControl.JoystickManager", 1, 0, "Joystick", kRefOnly);
qmlRegisterUncreatableType<QGCPositionManager> ("QGroundControl.QGCPositionManager", 1, 0, "QGCPositionManager", kRefOnly); qmlRegisterUncreatableType<CoordinateVector>("QGroundControl", 1, 0,
qmlRegisterUncreatableType<FactValueSliderListModel>("QGroundControl.FactControls", 1, 0, "FactValueSliderListModel", kRefOnly); "CoordinateVector", kRefOnly);
qmlRegisterUncreatableType<QmlObjectListModel>(
qmlRegisterUncreatableType<QGCMapPolygon> ("QGroundControl.FlightMap", 1, 0, "QGCMapPolygon", kRefOnly); "QGroundControl", 1, 0, "QmlObjectListModel", kRefOnly);
qmlRegisterUncreatableType<MissionCommandTree>(
qmlRegisterUncreatableType<QGCGeoBoundingCube> ("QGroundControl.FlightMap", 1, 0, "QGCGeoBoundingCube", kRefOnly); "QGroundControl", 1, 0, "MissionCommandTree", kRefOnly);
qmlRegisterUncreatableType<CameraCalc>("QGroundControl", 1, 0, "CameraCalc",
qmlRegisterType<QGCMapCircle> ("QGroundControl.FlightMap", 1, 0, "QGCMapCircle"); kRefOnly);
qmlRegisterType<ParameterEditorController> (kQGCControllers, 1, 0, "ParameterEditorController"); qmlRegisterUncreatableType<AutoPilotPlugin>(
qmlRegisterType<ESP8266ComponentController> (kQGCControllers, 1, 0, "ESP8266ComponentController"); "QGroundControl.AutoPilotPlugin", 1, 0, "AutoPilotPlugin", kRefOnly);
qmlRegisterType<ScreenToolsController> (kQGCControllers, 1, 0, "ScreenToolsController"); qmlRegisterUncreatableType<VehicleComponent>(
qmlRegisterType<PlanMasterController> (kQGCControllers, 1, 0, "PlanMasterController"); "QGroundControl.AutoPilotPlugin", 1, 0, "VehicleComponent", kRefOnly);
qmlRegisterType<ValuesWidgetController> (kQGCControllers, 1, 0, "ValuesWidgetController"); qmlRegisterUncreatableType<JoystickManager>(
qmlRegisterType<QGCFileDialogController> (kQGCControllers, 1, 0, "QGCFileDialogController"); "QGroundControl.JoystickManager", 1, 0, "JoystickManager", kRefOnly);
qmlRegisterType<RCChannelMonitorController> (kQGCControllers, 1, 0, "RCChannelMonitorController"); qmlRegisterUncreatableType<Joystick>("QGroundControl.JoystickManager", 1, 0,
qmlRegisterType<JoystickConfigController> (kQGCControllers, 1, 0, "JoystickConfigController"); "Joystick", kRefOnly);
qmlRegisterType<LogDownloadController> (kQGCControllers, 1, 0, "LogDownloadController"); qmlRegisterUncreatableType<QGCPositionManager>(
qmlRegisterType<SyslinkComponentController> (kQGCControllers, 1, 0, "SyslinkComponentController"); "QGroundControl.QGCPositionManager", 1, 0, "QGCPositionManager",
qmlRegisterType<EditPositionDialogController> (kQGCControllers, 1, 0, "EditPositionDialogController"); kRefOnly);
qmlRegisterUncreatableType<FactValueSliderListModel>(
"QGroundControl.FactControls", 1, 0, "FactValueSliderListModel",
kRefOnly);
qmlRegisterUncreatableType<QGCMapPolygon>("QGroundControl.FlightMap", 1, 0,
"QGCMapPolygon", kRefOnly);
qmlRegisterUncreatableType<QGCGeoBoundingCube>(
"QGroundControl.FlightMap", 1, 0, "QGCGeoBoundingCube", kRefOnly);
qmlRegisterType<QGCMapCircle>("QGroundControl.FlightMap", 1, 0,
"QGCMapCircle");
qmlRegisterType<ParameterEditorController>(kQGCControllers, 1, 0,
"ParameterEditorController");
qmlRegisterType<ESP8266ComponentController>(kQGCControllers, 1, 0,
"ESP8266ComponentController");
qmlRegisterType<ScreenToolsController>(kQGCControllers, 1, 0,
"ScreenToolsController");
qmlRegisterType<PlanMasterController>(kQGCControllers, 1, 0,
"PlanMasterController");
qmlRegisterType<ValuesWidgetController>(kQGCControllers, 1, 0,
"ValuesWidgetController");
qmlRegisterType<QGCFileDialogController>(kQGCControllers, 1, 0,
"QGCFileDialogController");
qmlRegisterType<RCChannelMonitorController>(kQGCControllers, 1, 0,
"RCChannelMonitorController");
qmlRegisterType<JoystickConfigController>(kQGCControllers, 1, 0,
"JoystickConfigController");
qmlRegisterType<LogDownloadController>(kQGCControllers, 1, 0,
"LogDownloadController");
qmlRegisterType<SyslinkComponentController>(kQGCControllers, 1, 0,
"SyslinkComponentController");
qmlRegisterType<EditPositionDialogController>(kQGCControllers, 1, 0,
"EditPositionDialogController");
#ifndef __mobile__ #ifndef __mobile__
qmlRegisterType<ViewWidgetController> (kQGCControllers, 1, 0, "ViewWidgetController"); qmlRegisterType<ViewWidgetController>(kQGCControllers, 1, 0,
qmlRegisterType<CustomCommandWidgetController> (kQGCControllers, 1, 0, "CustomCommandWidgetController"); "ViewWidgetController");
qmlRegisterType<CustomCommandWidgetController>(
kQGCControllers, 1, 0, "CustomCommandWidgetController");
#ifndef NO_SERIAL_LINK #ifndef NO_SERIAL_LINK
qmlRegisterType<FirmwareUpgradeController> (kQGCControllers, 1, 0, "FirmwareUpgradeController"); qmlRegisterType<FirmwareUpgradeController>(kQGCControllers, 1, 0,
"FirmwareUpgradeController");
#endif #endif
qmlRegisterType<GeoTagController> (kQGCControllers, 1, 0, "GeoTagController"); qmlRegisterType<GeoTagController>(kQGCControllers, 1, 0, "GeoTagController");
qmlRegisterType<MavlinkConsoleController> (kQGCControllers, 1, 0, "MavlinkConsoleController"); qmlRegisterType<MavlinkConsoleController>(kQGCControllers, 1, 0,
"MavlinkConsoleController");
#endif #endif
// Wima // Wima
qmlRegisterType<WimaController> ("Wima", 1, 0, "WimaController"); qmlRegisterType<WimaController>("Wima", 1, 0, "WimaController");
qmlRegisterType<WimaPlaner> ("Wima", 1, 0, "WimaPlaner"); qmlRegisterType<WimaPlaner>("Wima", 1, 0, "WimaPlaner");
qmlRegisterType<WimaBridge> ("Wima", 1, 0, "WimaBridge"); qmlRegisterType<WimaBridge>("Wima", 1, 0, "WimaBridge");
qmlRegisterType<NemoInterface>("Wima", 1, 0, "NemoInterface");
// Register Qml Singletons
// Register Qml Singletons qmlRegisterSingletonType<QGroundControlQmlGlobal>(
qmlRegisterSingletonType<QGroundControlQmlGlobal> ("QGroundControl", 1, 0, "QGroundControl", qgroundcontrolQmlGlobalSingletonFactory); "QGroundControl", 1, 0, "QGroundControl",
qmlRegisterSingletonType<ScreenToolsController> ("QGroundControl.ScreenToolsController", 1, 0, "ScreenToolsController", screenToolsControllerSingletonFactory); qgroundcontrolQmlGlobalSingletonFactory);
qmlRegisterSingletonType<ShapeFileHelper> ("QGroundControl.ShapeFileHelper", 1, 0, "ShapeFileHelper", shapeFileHelperSingletonFactory); qmlRegisterSingletonType<ScreenToolsController>(
"QGroundControl.ScreenToolsController", 1, 0, "ScreenToolsController",
screenToolsControllerSingletonFactory);
qmlRegisterSingletonType<ShapeFileHelper>("QGroundControl.ShapeFileHelper", 1,
0, "ShapeFileHelper",
shapeFileHelperSingletonFactory);
} }
bool QGCApplication::_initForNormalAppBoot(void) bool QGCApplication::_initForNormalAppBoot(void) {
{ QSettings settings;
QSettings settings;
_loadCurrentStyleSheet(); _loadCurrentStyleSheet();
// Exit main application when last window is closed // Exit main application when last window is closed
connect(this, &QGCApplication::lastWindowClosed, this, QGCApplication::quit); connect(this, &QGCApplication::lastWindowClosed, this, QGCApplication::quit);
#ifdef __mobile__ #ifdef __mobile__
_qmlAppEngine = toolbox()->corePlugin()->createRootWindow(this); _qmlAppEngine = toolbox()->corePlugin()->createRootWindow(this);
#else #else
// Start the user interface // Start the user interface
MainWindow* mainWindow = MainWindow::_create(); MainWindow *mainWindow = MainWindow::_create();
Q_CHECK_PTR(mainWindow); Q_CHECK_PTR(mainWindow);
#endif #endif
// Now that main window is up check for lost log files // Now that main window is up check for lost log files
connect(this, &QGCApplication::checkForLostLogFiles, toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles); connect(this, &QGCApplication::checkForLostLogFiles,
emit checkForLostLogFiles(); toolbox()->mavlinkProtocol(), &MAVLinkProtocol::checkForLostLogFiles);
emit checkForLostLogFiles();
// Load known link configurations // Load known link configurations
toolbox()->linkManager()->loadLinkConfigurationList(); toolbox()->linkManager()->loadLinkConfigurationList();
// Probe for joysticks // Probe for joysticks
toolbox()->joystickManager()->init(); toolbox()->joystickManager()->init();
if (_settingsUpgraded) { if (_settingsUpgraded) {
showMessage(QString(tr("The format for %1 saved settings has been modified. " showMessage(
"Your saved settings have been reset to defaults.")).arg(applicationName())); QString(tr("The format for %1 saved settings has been modified. "
} "Your saved settings have been reset to defaults."))
.arg(applicationName()));
}
// Connect links with flag AutoconnectLink // Connect links with flag AutoconnectLink
toolbox()->linkManager()->startAutoConnectedLinks(); toolbox()->linkManager()->startAutoConnectedLinks();
if (getQGCMapEngine()->wasCacheReset()) { if (getQGCMapEngine()->wasCacheReset()) {
showMessage(tr("The Offline Map Cache database has been upgraded. " showMessage(tr("The Offline Map Cache database has been upgraded. "
"Your old map cache sets have been reset.")); "Your old map cache sets have been reset."));
} }
settings.sync(); settings.sync();
return true; return true;
} }
bool QGCApplication::_initForUnitTests(void) bool QGCApplication::_initForUnitTests(void) { return true; }
{
return true;
}
void QGCApplication::deleteAllSettingsNextBoot(void) void QGCApplication::deleteAllSettingsNextBoot(void) {
{ QSettings settings;
QSettings settings; settings.setValue(_deleteAllSettingsKey, true);
settings.setValue(_deleteAllSettingsKey, true);
} }
void QGCApplication::clearDeleteAllSettingsNextBoot(void) void QGCApplication::clearDeleteAllSettingsNextBoot(void) {
{ QSettings settings;
QSettings settings; settings.remove(_deleteAllSettingsKey);
settings.remove(_deleteAllSettingsKey);
} }
/// @brief Returns the QGCApplication object singleton. /// @brief Returns the QGCApplication object singleton.
QGCApplication* qgcApp(void) QGCApplication *qgcApp(void) { return QGCApplication::_app; }
{
return QGCApplication::_app;
}
void QGCApplication::informationMessageBoxOnMainThread(const QString& title, const QString& msg) void QGCApplication::informationMessageBoxOnMainThread(const QString &title,
{ const QString &msg) {
Q_UNUSED(title); Q_UNUSED(title);
showMessage(msg); showMessage(msg);
} }
void QGCApplication::warningMessageBoxOnMainThread(const QString& title, const QString& msg) void QGCApplication::warningMessageBoxOnMainThread(const QString &title,
{ const QString &msg) {
#ifdef __mobile__ #ifdef __mobile__
Q_UNUSED(title) Q_UNUSED(title)
showMessage(msg); showMessage(msg);
#else #else
QGCMessageBox::warning(title, msg); QGCMessageBox::warning(title, msg);
#endif #endif
} }
void QGCApplication::criticalMessageBoxOnMainThread(const QString& title, const QString& msg) void QGCApplication::criticalMessageBoxOnMainThread(const QString &title,
{ const QString &msg) {
#ifdef __mobile__ #ifdef __mobile__
Q_UNUSED(title) Q_UNUSED(title)
showMessage(msg); showMessage(msg);
#else #else
QGCMessageBox::critical(title, msg); QGCMessageBox::critical(title, msg);
#endif #endif
} }
void QGCApplication::saveTelemetryLogOnMainThread(QString tempLogfile) void QGCApplication::saveTelemetryLogOnMainThread(QString tempLogfile) {
{ // The vehicle is gone now and we are shutting down so we need to use a
// The vehicle is gone now and we are shutting down so we need to use a message box for errors to hold shutdown and show the error // message box for errors to hold shutdown and show the error
if (_checkTelemetrySavePath(true /* useMessageBox */)) { if (_checkTelemetrySavePath(true /* useMessageBox */)) {
QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath(); QString saveDirPath =
QDir saveDir(saveDirPath); _toolbox->settingsManager()->appSettings()->telemetrySavePath();
QDir saveDir(saveDirPath);
QString nameFormat("%1%2.%3");
QString dtFormat("yyyy-MM-dd hh-mm-ss");
int tryIndex = 1;
QString saveFileName = nameFormat.arg(
QDateTime::currentDateTime().toString(dtFormat)).arg("").arg(toolbox()->settingsManager()->appSettings()->telemetryFileExtension);
while (saveDir.exists(saveFileName)) {
saveFileName = nameFormat.arg(
QDateTime::currentDateTime().toString(dtFormat)).arg(QStringLiteral(".%1").arg(tryIndex++)).arg(toolbox()->settingsManager()->appSettings()->telemetryFileExtension);
}
QString saveFilePath = saveDir.absoluteFilePath(saveFileName);
QFile tempFile(tempLogfile); QString nameFormat("%1%2.%3");
if (!tempFile.copy(saveFilePath)) { QString dtFormat("yyyy-MM-dd hh-mm-ss");
QString error = tr("Unable to save telemetry log. Error copying telemetry to '%1': '%2'.").arg(saveFilePath).arg(tempFile.errorString());
int tryIndex = 1;
QString saveFileName =
nameFormat.arg(QDateTime::currentDateTime().toString(dtFormat))
.arg("")
.arg(toolbox()
->settingsManager()
->appSettings()
->telemetryFileExtension);
while (saveDir.exists(saveFileName)) {
saveFileName =
nameFormat.arg(QDateTime::currentDateTime().toString(dtFormat))
.arg(QStringLiteral(".%1").arg(tryIndex++))
.arg(toolbox()
->settingsManager()
->appSettings()
->telemetryFileExtension);
}
QString saveFilePath = saveDir.absoluteFilePath(saveFileName);
QFile tempFile(tempLogfile);
if (!tempFile.copy(saveFilePath)) {
QString error = tr("Unable to save telemetry log. Error copying "
"telemetry to '%1': '%2'.")
.arg(saveFilePath)
.arg(tempFile.errorString());
#ifndef __mobile__ #ifndef __mobile__
QGCMessageBox::warning(tr("Telemetry Save Error"), error); QGCMessageBox::warning(tr("Telemetry Save Error"), error);
#else #else
showMessage(error); showMessage(error);
#endif #endif
}
} }
QFile::remove(tempLogfile); }
QFile::remove(tempLogfile);
} }
void QGCApplication::checkTelemetrySavePathOnMainThread(void) void QGCApplication::checkTelemetrySavePathOnMainThread(void) {
{ // This is called with an active vehicle so don't pop message boxes which
// This is called with an active vehicle so don't pop message boxes which holds ui thread // holds ui thread
_checkTelemetrySavePath(false /* useMessageBox */); _checkTelemetrySavePath(false /* useMessageBox */);
} }
bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox) bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox) {
{ QString errorTitle = tr("Telemetry save error");
QString errorTitle = tr("Telemetry save error");
QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath(); QString saveDirPath =
if (saveDirPath.isEmpty()) { _toolbox->settingsManager()->appSettings()->telemetrySavePath();
QString error = tr("Unable to save telemetry log. Application save directory is not set."); if (saveDirPath.isEmpty()) {
QString error = tr(
"Unable to save telemetry log. Application save directory is not set.");
#ifndef __mobile__ #ifndef __mobile__
if (useMessageBox) { if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error); QGCMessageBox::warning(errorTitle, error);
} else { } else {
#endif #endif
Q_UNUSED(useMessageBox); Q_UNUSED(useMessageBox);
showMessage(error); showMessage(error);
#ifndef __mobile__ #ifndef __mobile__
}
#endif
return false;
} }
#endif
return false;
}
QDir saveDir(saveDirPath); QDir saveDir(saveDirPath);
if (!saveDir.exists()) { if (!saveDir.exists()) {
QString error = tr("Unable to save telemetry log. Telemetry save directory \"%1\" does not exist.").arg(saveDirPath); QString error = tr("Unable to save telemetry log. Telemetry save directory "
"\"%1\" does not exist.")
.arg(saveDirPath);
#ifndef __mobile__ #ifndef __mobile__
if (useMessageBox) { if (useMessageBox) {
QGCMessageBox::warning(errorTitle, error); QGCMessageBox::warning(errorTitle, error);
} else { } else {
#endif #endif
showMessage(error); showMessage(error);
#ifndef __mobile__ #ifndef __mobile__
}
#endif
return false;
} }
#endif
return false;
}
return true; return true;
} }
void QGCApplication::_loadCurrentStyleSheet(void) void QGCApplication::_loadCurrentStyleSheet(void) {
{
#ifndef __mobile__ #ifndef __mobile__
bool success = true; bool success = true;
QString styles; QString styles;
// The dark style sheet is the master. Any other selected style sheet just overrides // The dark style sheet is the master. Any other selected style sheet just
// the colors of the master sheet. // overrides the colors of the master sheet.
QFile masterStyleSheet(_darkStyleFile); QFile masterStyleSheet(_darkStyleFile);
if (masterStyleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) { if (masterStyleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
styles = masterStyleSheet.readAll(); styles = masterStyleSheet.readAll();
} else {
qDebug() << "Unable to load master dark style sheet";
success = false;
}
if (success && !_toolbox->settingsManager()
->appSettings()
->indoorPalette()
->rawValue()
.toBool()) {
// Load the slave light stylesheet.
QFile styleSheet(_lightStyleFile);
if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
styles += styleSheet.readAll();
} else { } else {
qDebug() << "Unable to load master dark style sheet"; qWarning() << "Unable to load slave light sheet:";
success = false; success = false;
} }
}
if (success && !_toolbox->settingsManager()->appSettings()->indoorPalette()->rawValue().toBool()) { setStyleSheet(styles);
// Load the slave light stylesheet.
QFile styleSheet(_lightStyleFile);
if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text)) {
styles += styleSheet.readAll();
} else {
qWarning() << "Unable to load slave light sheet:";
success = false;
}
}
setStyleSheet(styles);
if (!success) { if (!success) {
// Fall back to plastique if we can't load our own // Fall back to plastique if we can't load our own
setStyle("plastique"); setStyle("plastique");
} }
#endif #endif
} }
void QGCApplication::reportMissingParameter(int componentId, const QString& name) void QGCApplication::reportMissingParameter(int componentId,
{ const QString &name) {
_missingParams += QString("%1:%2").arg(componentId).arg(name); _missingParams += QString("%1:%2").arg(componentId).arg(name);
_missingParamsDelayedDisplayTimer.start(); _missingParamsDelayedDisplayTimer.start();
} }
/// Called when the delay timer fires to show the missing parameters warning /// Called when the delay timer fires to show the missing parameters warning
void QGCApplication::_missingParamsDisplay(void) void QGCApplication::_missingParamsDisplay(void) {
{ if (_missingParams.count()) {
if (_missingParams.count()) { QString params;
QString params; foreach (const QString &name, _missingParams) {
foreach (const QString &name, _missingParams) { if (params.isEmpty()) {
if (params.isEmpty()) { params += name;
params += name; } else {
} else { params += QString(", %1").arg(name);
params += QString(", %1").arg(name); }
}
}
_missingParams.clear();
showMessage(tr("Parameters are missing from firmware. You may be running a version of firmware QGC does not work correctly with or your firmware has a bug in it. Missing params: %1").arg(params));
} }
_missingParams.clear();
showMessage(tr("Parameters are missing from firmware. You may be running a "
"version of firmware QGC does not work correctly with or "
"your firmware has a bug in it. Missing params: %1")
.arg(params));
}
} }
QObject* QGCApplication::_rootQmlObject() QObject *QGCApplication::_rootQmlObject() {
{
#ifdef __mobile__ #ifdef __mobile__
if(_qmlAppEngine && _qmlAppEngine->rootObjects().size()) if (_qmlAppEngine && _qmlAppEngine->rootObjects().size())
return _qmlAppEngine->rootObjects()[0]; return _qmlAppEngine->rootObjects()[0];
return nullptr; return nullptr;
#else #else
MainWindow * mainWindow = MainWindow::instance(); MainWindow *mainWindow = MainWindow::instance();
if (mainWindow) { if (mainWindow) {
return mainWindow->rootQmlObject(); return mainWindow->rootQmlObject();
} else if (runningUnitTests()){ } else if (runningUnitTests()) {
// Unit test can run without a main window // Unit test can run without a main window
return nullptr; return nullptr;
} else { } else {
qWarning() << "Why is MainWindow missing?"; qWarning() << "Why is MainWindow missing?";
return nullptr; return nullptr;
} }
#endif #endif
} }
void QGCApplication::showMessage(const QString &message) {
// PreArm messages are handled by Vehicle and shown in Map
if (message.startsWith(QStringLiteral("PreArm")) ||
message.startsWith(QStringLiteral("preflight"), Qt::CaseInsensitive)) {
return;
}
void QGCApplication::showMessage(const QString& message) QObject *rootQmlObject = _rootQmlObject();
{
// PreArm messages are handled by Vehicle and shown in Map
if (message.startsWith(QStringLiteral("PreArm")) || message.startsWith(QStringLiteral("preflight"), Qt::CaseInsensitive)) {
return;
}
QObject* rootQmlObject = _rootQmlObject();
if (rootQmlObject) { if (rootQmlObject) {
QVariant varReturn; QVariant varReturn;
QVariant varMessage = QVariant::fromValue(message); QVariant varMessage = QVariant::fromValue(message);
QMetaObject::invokeMethod(_rootQmlObject(), "showMessage", Q_RETURN_ARG(QVariant, varReturn), Q_ARG(QVariant, varMessage)); QMetaObject::invokeMethod(_rootQmlObject(), "showMessage",
Q_RETURN_ARG(QVariant, varReturn),
Q_ARG(QVariant, varMessage));
#ifndef __mobile__ #ifndef __mobile__
} else if (runningUnitTests()){ } else if (runningUnitTests()) {
// Unit test can run without a main window which will lead to no root qml object. Use QGCMessageBox instead // Unit test can run without a main window which will lead to no root qml
QGCMessageBox::information("Unit Test", message); // object. Use QGCMessageBox instead
QGCMessageBox::information("Unit Test", message);
#endif #endif
} else { } else {
qWarning() << "Internal error"; qWarning() << "Internal error";
} }
} }
void QGCApplication::showSetupView(void) void QGCApplication::showSetupView(void) {
{ if (_rootQmlObject()) {
if(_rootQmlObject()) { QMetaObject::invokeMethod(_rootQmlObject(), "showSetupView");
QMetaObject::invokeMethod(_rootQmlObject(), "showSetupView"); }
}
} }
void QGCApplication::qmlAttemptWindowClose(void) void QGCApplication::qmlAttemptWindowClose(void) {
{ if (_rootQmlObject()) {
if(_rootQmlObject()) { QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose");
QMetaObject::invokeMethod(_rootQmlObject(), "attemptWindowClose"); }
}
} }
bool QGCApplication::isInternetAvailable() bool QGCApplication::isInternetAvailable() {
{ return getQGCMapEngine()->isInternetActive();
return getQGCMapEngine()->isInternetActive();
} }
void QGCApplication::_checkForNewVersion(void) void QGCApplication::_checkForNewVersion(void) {
{
#ifndef __mobile__ #ifndef __mobile__
if (!_runningUnitTests) { if (!_runningUnitTests) {
if (_parseVersionText(applicationVersion(), _majorVersion, _minorVersion, _buildVersion)) { if (_parseVersionText(applicationVersion(), _majorVersion, _minorVersion,
QString versionCheckFile = toolbox()->corePlugin()->stableVersionCheckFileUrl(); _buildVersion)) {
if (!versionCheckFile.isEmpty()) { QString versionCheckFile =
_currentVersionDownload = new QGCFileDownload(this); toolbox()->corePlugin()->stableVersionCheckFileUrl();
connect(_currentVersionDownload, &QGCFileDownload::downloadFinished, this, &QGCApplication::_currentVersionDownloadFinished); if (!versionCheckFile.isEmpty()) {
connect(_currentVersionDownload, &QGCFileDownload::error, this, &QGCApplication::_currentVersionDownloadError); _currentVersionDownload = new QGCFileDownload(this);
_currentVersionDownload->download(versionCheckFile); connect(_currentVersionDownload, &QGCFileDownload::downloadFinished,
} this, &QGCApplication::_currentVersionDownloadFinished);
} connect(_currentVersionDownload, &QGCFileDownload::error, this,
&QGCApplication::_currentVersionDownloadError);
_currentVersionDownload->download(versionCheckFile);
}
} }
}
#endif #endif
} }
void QGCApplication::_currentVersionDownloadFinished(QString remoteFile, QString localFile) void QGCApplication::_currentVersionDownloadFinished(QString remoteFile,
{ QString localFile) {
Q_UNUSED(remoteFile); Q_UNUSED(remoteFile);
#ifdef __mobile__ #ifdef __mobile__
Q_UNUSED(localFile); Q_UNUSED(localFile);
#else #else
QFile versionFile(localFile); QFile versionFile(localFile);
if (versionFile.open(QIODevice::ReadOnly)) { if (versionFile.open(QIODevice::ReadOnly)) {
QTextStream textStream(&versionFile); QTextStream textStream(&versionFile);
QString version = textStream.readLine(); QString version = textStream.readLine();
qDebug() << version; qDebug() << version;
int majorVersion, minorVersion, buildVersion; int majorVersion, minorVersion, buildVersion;
if (_parseVersionText(version, majorVersion, minorVersion, buildVersion)) { if (_parseVersionText(version, majorVersion, minorVersion, buildVersion)) {
if (_majorVersion < majorVersion || if (_majorVersion < majorVersion ||
(_majorVersion == majorVersion && _minorVersion < minorVersion) || (_majorVersion == majorVersion && _minorVersion < minorVersion) ||
(_majorVersion == majorVersion && _minorVersion == minorVersion && _buildVersion < buildVersion)) { (_majorVersion == majorVersion && _minorVersion == minorVersion &&
QGCMessageBox::information(tr("New Version Available"), tr("There is a newer version of %1 available. You can download it from %2.").arg(applicationName()).arg(toolbox()->corePlugin()->stableDownloadLocation())); _buildVersion < buildVersion)) {
} QGCMessageBox::information(
} tr("New Version Available"),
tr("There is a newer version of %1 available. You can download it "
"from %2.")
.arg(applicationName())
.arg(toolbox()->corePlugin()->stableDownloadLocation()));
}
} }
}
_currentVersionDownload->deleteLater(); _currentVersionDownload->deleteLater();
#endif #endif
} }
void QGCApplication::_currentVersionDownloadError(QString errorMsg) void QGCApplication::_currentVersionDownloadError(QString errorMsg) {
{ Q_UNUSED(errorMsg);
Q_UNUSED(errorMsg); _currentVersionDownload->deleteLater();
_currentVersionDownload->deleteLater();
} }
bool QGCApplication::_parseVersionText(const QString& versionString, int& majorVersion, int& minorVersion, int& buildVersion) bool QGCApplication::_parseVersionText(const QString &versionString,
{ int &majorVersion, int &minorVersion,
QRegularExpression regExp("v(\\d+)\\.(\\d+)\\.(\\d+)"); int &buildVersion) {
QRegularExpressionMatch match = regExp.match(versionString); QRegularExpression regExp("v(\\d+)\\.(\\d+)\\.(\\d+)");
if (match.hasMatch() && match.lastCapturedIndex() == 3) { QRegularExpressionMatch match = regExp.match(versionString);
majorVersion = match.captured(1).toInt(); if (match.hasMatch() && match.lastCapturedIndex() == 3) {
minorVersion = match.captured(2).toInt(); majorVersion = match.captured(1).toInt();
buildVersion = match.captured(3).toInt(); minorVersion = match.captured(2).toInt();
return true; buildVersion = match.captured(3).toInt();
} return true;
}
return false; return false;
} }
void QGCApplication::_onGPSConnect() {
void QGCApplication::_onGPSConnect() _gpsRtkFactGroup->connected()->setRawValue(true);
{
_gpsRtkFactGroup->connected()->setRawValue(true);
} }
void QGCApplication::_onGPSDisconnect() void QGCApplication::_onGPSDisconnect() {
{ _gpsRtkFactGroup->connected()->setRawValue(false);
_gpsRtkFactGroup->connected()->setRawValue(false);
} }
void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM, double latitude, double longitude, float altitude, bool valid, bool active) void QGCApplication::_gpsSurveyInStatus(float duration, float accuracyMM,
{ double latitude, double longitude,
_gpsRtkFactGroup->currentDuration()->setRawValue(duration); float altitude, bool valid,
_gpsRtkFactGroup->currentAccuracy()->setRawValue(accuracyMM/1000.0); bool active) {
_gpsRtkFactGroup->currentLatitude()->setRawValue(latitude); _gpsRtkFactGroup->currentDuration()->setRawValue(duration);
_gpsRtkFactGroup->currentLongitude()->setRawValue(longitude); _gpsRtkFactGroup->currentAccuracy()->setRawValue(accuracyMM / 1000.0);
_gpsRtkFactGroup->currentAltitude()->setRawValue(altitude); _gpsRtkFactGroup->currentLatitude()->setRawValue(latitude);
_gpsRtkFactGroup->valid()->setRawValue(valid); _gpsRtkFactGroup->currentLongitude()->setRawValue(longitude);
_gpsRtkFactGroup->active()->setRawValue(active); _gpsRtkFactGroup->currentAltitude()->setRawValue(altitude);
_gpsRtkFactGroup->valid()->setRawValue(valid);
_gpsRtkFactGroup->active()->setRawValue(active);
} }
void QGCApplication::_gpsNumSatellites(int numSatellites) void QGCApplication::_gpsNumSatellites(int numSatellites) {
{ _gpsRtkFactGroup->numSatellites()->setRawValue(numSatellites);
_gpsRtkFactGroup->numSatellites()->setRawValue(numSatellites);
} }
QString QGCApplication::cachedParameterMetaDataFile(void) QString QGCApplication::cachedParameterMetaDataFile(void) {
{ QSettings settings;
QSettings settings; QDir parameterDir = QFileInfo(settings.fileName()).dir();
QDir parameterDir = QFileInfo(settings.fileName()).dir(); return parameterDir.filePath(QStringLiteral("ParameterFactMetaData.xml"));
return parameterDir.filePath(QStringLiteral("ParameterFactMetaData.xml"));
} }
QString QGCApplication::cachedAirframeMetaDataFile(void) QString QGCApplication::cachedAirframeMetaDataFile(void) {
{ QSettings settings;
QSettings settings; QDir airframeDir = QFileInfo(settings.fileName()).dir();
QDir airframeDir = QFileInfo(settings.fileName()).dir(); return airframeDir.filePath(QStringLiteral("PX4AirframeFactMetaData.xml"));
return airframeDir.filePath(QStringLiteral("PX4AirframeFactMetaData.xml"));
} }
...@@ -146,6 +146,8 @@ QmlObjectListModel *WimaMeasurementArea::tiles() { ...@@ -146,6 +146,8 @@ QmlObjectListModel *WimaMeasurementArea::tiles() {
return &this->_tileData.tiles; return &this->_tileData.tiles;
} }
QVector<int> WimaMeasurementArea::progress() { return this->_progress; }
const QmlObjectListModel *WimaMeasurementArea::tiles() const { const QmlObjectListModel *WimaMeasurementArea::tiles() const {
return &this->_tileData.tiles; return &this->_tileData.tiles;
} }
...@@ -226,6 +228,17 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json, ...@@ -226,6 +228,17 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
return false; return false;
} }
} }
bool WimaMeasurementArea::setProgress(const QVector<int> &p) {
if (!_calculating) {
if (p.size() == this->tiles()->count() && this->_progress != p) {
this->_progress = p;
emit progressChanged();
return true;
}
}
return false;
}
//! //!
//! \brief WimaMeasurementArea::doUpdate //! \brief WimaMeasurementArea::doUpdate
//! \pre WimaMeasurementArea::deferUpdate must be called first, don't call //! \pre WimaMeasurementArea::deferUpdate must be called first, don't call
...@@ -312,6 +325,8 @@ void WimaMeasurementArea::deferUpdate() { ...@@ -312,6 +325,8 @@ void WimaMeasurementArea::deferUpdate() {
this->_timer.stop(); this->_timer.stop();
} }
if (this->_tileData.size() > 0) { if (this->_tileData.size() > 0) {
this->_progress.clear();
emit this->progressChanged();
this->_tileData.clear(); this->_tileData.clear();
emit this->tilesChanged(); emit this->tilesChanged();
} }
......
...@@ -41,6 +41,7 @@ public: ...@@ -41,6 +41,7 @@ public:
Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT) Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT)
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged) Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged) Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
// Overrides from WimaPolygon // Overrides from WimaPolygon
QString mapVisualQML(void) const; QString mapVisualQML(void) const;
...@@ -53,6 +54,7 @@ public: ...@@ -53,6 +54,7 @@ public:
Fact *minTransectLength(); Fact *minTransectLength();
Fact *showTiles(); Fact *showTiles();
QmlObjectListModel *tiles(); QmlObjectListModel *tiles();
QVector<int> progress();
const QmlObjectListModel *tiles() const; const QmlObjectListModel *tiles() const;
const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate
const TileData &tileData() const; const TileData &tileData() const;
...@@ -80,8 +82,10 @@ public: ...@@ -80,8 +82,10 @@ public:
signals: signals:
void tilesChanged(); void tilesChanged();
void maxTilesChanged(); void maxTilesChanged();
void progressChanged();
public slots: public slots:
bool setProgress(const QVector<int> &p);
private slots: private slots:
void doUpdate(); void doUpdate();
...@@ -108,4 +112,6 @@ private: ...@@ -108,4 +112,6 @@ private:
TileData _tileData; TileData _tileData;
QFutureWatcher<DataPtr> _watcher; QFutureWatcher<DataPtr> _watcher;
bool _calculating; bool _calculating;
QVector<int> _progress;
}; };
...@@ -45,13 +45,21 @@ public: ...@@ -45,13 +45,21 @@ public:
void stop(); void stop();
void setTileData(const TileData &tileData); void setTileData(const TileData &tileData);
bool hasTileData(const TileData &tileData) const; bool hasTileData(const TileData &tileData) const;
void setAutoPublish(bool ap);
void setHoldProgress(bool hp);
NemoInterface::NemoStatus status(); bool holdProgress();
void publishTileData();
NemoInterface::STATUS status();
QVector<int> progress(); QVector<int> progress();
bool running();
private: private:
bool doTopicServiceSetup(); bool doTopicServiceSetup();
void loop(); void loop();
static STATUS heartbeatToStatus(
const ros_bridge::messages::nemo_msgs::heartbeat::Heartbeat &hb);
//! //!
//! \brief Publishes tilesENU //! \brief Publishes tilesENU
//! \pre this->tilesENUMutex must be locked //! \pre this->tilesENUMutex must be locked
...@@ -69,25 +77,41 @@ private: ...@@ -69,25 +77,41 @@ private:
QGeoCoordinate ENUOrigin; QGeoCoordinate ENUOrigin;
mutable std::shared_timed_mutex ENUOriginMutex; mutable std::shared_timed_mutex ENUOriginMutex;
QNemoProgress qProgress; QNemoProgress qProgress;
QNemoProgress qProgressHolded;
mutable std::shared_timed_mutex progressMutex; mutable std::shared_timed_mutex progressMutex;
QNemoHeartbeat heartbeat; NemoInterface::STATUS status_;
TimePoint nextTimeout; TimePoint nextTimeout;
mutable std::shared_timed_mutex heartbeatMutex; mutable std::shared_timed_mutex statusMutex;
// Not protected data. // Not protected data.
TileData tileData; TileData tileData;
// Internals // Internals
bool running; std::atomic_bool running_;
std::atomic_bool holdProgress_;
std::atomic_bool topicServiceSetupDone; std::atomic_bool topicServiceSetupDone;
ROSBridgePtr pRosBridge; ROSBridgePtr pRosBridge;
QTimer loopTimer; QTimer loopTimer;
NemoInterface *parent; NemoInterface *parent;
}; };
using StatusMap = std::map<NemoInterface::STATUS, QString>;
StatusMap statusMap{
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::NOT_CONNECTED, "Not Connected"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::HEARTBEAT_DETECTED, "Heartbeat Detected"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::TIMEOUT, "Timeout"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::INVALID_HEARTBEAT, "Error"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::WEBSOCKET_DETECTED, "Websocket Detected")};
NemoInterface::Impl::Impl(NemoInterface *p) NemoInterface::Impl::Impl(NemoInterface *p)
: nextTimeout(TimePoint::max()), running(false), : status_(STATUS::NOT_CONNECTED), nextTimeout(TimePoint::max()),
topicServiceSetupDone(false), parent(p) { running_(false), holdProgress_(false), topicServiceSetupDone(false),
parent(p) {
// ROS Bridge. // ROS Bridge.
WimaSettings *wimaSettings = WimaSettings *wimaSettings =
...@@ -117,9 +141,15 @@ NemoInterface::Impl::Impl(NemoInterface *p) ...@@ -117,9 +141,15 @@ NemoInterface::Impl::Impl(NemoInterface *p)
this->loopTimer.start(EVENT_TIMER_INTERVAL); this->loopTimer.start(EVENT_TIMER_INTERVAL);
} }
void NemoInterface::Impl::start() { this->running = true; } void NemoInterface::Impl::start() {
this->running_ = true;
emit this->parent->runningChanged();
}
void NemoInterface::Impl::stop() { this->running = false; } void NemoInterface::Impl::stop() {
this->running_ = false;
emit this->parent->runningChanged();
}
void NemoInterface::Impl::setTileData(const TileData &tileData) { void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->tileData = tileData; this->tileData = tileData;
...@@ -135,7 +165,6 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) { ...@@ -135,7 +165,6 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->ENUOrigin = tile->coordinateList().first(); this->ENUOrigin = tile->coordinateList().first();
const auto &origin = this->ENUOrigin; const auto &origin = this->ENUOrigin;
this->tilesENU.polygons().clear(); this->tilesENU.polygons().clear();
bool error = false;
for (int i = 0; i < tileData.tiles.count(); ++i) { for (int i = 0; i < tileData.tiles.count(); ++i) {
obj = tileData.tiles.get(i); obj = tileData.tiles.get(i);
tile = qobject_cast<const SnakeTile *>(obj); tile = qobject_cast<const SnakeTile *>(obj);
...@@ -145,16 +174,9 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) { ...@@ -145,16 +174,9 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->tilesENU.polygons().push_back(std::move(tileENU)); this->tilesENU.polygons().push_back(std::move(tileENU));
} else { } else {
qWarning() << "NemoInterface::Impl::setTileData(): nullptr."; qWarning() << "NemoInterface::Impl::setTileData(): nullptr.";
error = true;
break; break;
} }
} }
if (!error && this->running && this->topicServiceSetupDone) {
this->publishENUOrigin();
this->publishTilesENU();
} else {
qWarning() << "NemoInterface::Impl::setTileData(): first tile empty.";
}
} else { } else {
qWarning() << "NemoInterface::Impl::setTileData(): nullptr."; qWarning() << "NemoInterface::Impl::setTileData(): nullptr.";
} }
...@@ -166,20 +188,52 @@ bool NemoInterface::Impl::hasTileData(const TileData &tileData) const { ...@@ -166,20 +188,52 @@ bool NemoInterface::Impl::hasTileData(const TileData &tileData) const {
return this->tileData == tileData; return this->tileData == tileData;
} }
NemoInterface::NemoStatus NemoInterface::Impl::status() { void NemoInterface::Impl::setHoldProgress(bool hp) {
SharedLock lk(this->heartbeatMutex); if (this->holdProgress_ != hp) {
return NemoInterface::NemoStatus(heartbeat.status()); this->holdProgress_ = hp;
emit this->parent->holdProgressChanged();
if (!this->holdProgress_) {
UniqueLock lk(this->progressMutex);
if (this->qProgress != this->qProgressHolded) {
this->qProgressHolded = this->qProgress;
lk.unlock();
emit this->parent->progressChanged();
}
}
}
}
bool NemoInterface::Impl::holdProgress() { return this->holdProgress_.load(); }
void NemoInterface::Impl::publishTileData() {
std::lock(this->ENUOriginMutex, this->tilesENUMutex);
UniqueLock lk1(this->ENUOriginMutex, std::adopt_lock);
UniqueLock lk2(this->tilesENUMutex, std::adopt_lock);
if (this->tilesENU.polygons().size() > 0 && this->running_ &&
this->topicServiceSetupDone) {
this->publishENUOrigin();
this->publishTilesENU();
}
}
NemoInterface::STATUS NemoInterface::Impl::status() {
SharedLock lk(this->statusMutex);
return status_;
} }
QVector<int> NemoInterface::Impl::progress() { QVector<int> NemoInterface::Impl::progress() {
SharedLock lk(this->progressMutex); SharedLock lk(this->progressMutex);
return this->qProgress.progress(); return this->qProgressHolded.progress();
} }
bool NemoInterface::Impl::running() { return this->running_.load(); }
bool NemoInterface::Impl::doTopicServiceSetup() { bool NemoInterface::Impl::doTopicServiceSetup() {
using namespace ros_bridge::messages; using namespace ros_bridge::messages;
// Publish snake tiles. // snake tiles.
{ {
SharedLock lk(this->tilesENUMutex); SharedLock lk(this->tilesENUMutex);
...@@ -188,16 +242,14 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -188,16 +242,14 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
this->pRosBridge->advertiseTopic( this->pRosBridge->advertiseTopic(
"/snake/tiles", "/snake/tiles",
jsk_recognition_msgs::polygon_array::messageType().c_str()); jsk_recognition_msgs::polygon_array::messageType().c_str());
this->publishTilesENU();
} }
// Publish snake origin. // snake origin.
{ {
SharedLock lk(this->ENUOriginMutex); SharedLock lk(this->ENUOriginMutex);
this->pRosBridge->advertiseTopic( this->pRosBridge->advertiseTopic(
"/snake/origin", geographic_msgs::geo_point::messageType().c_str()); "/snake/origin", geographic_msgs::geo_point::messageType().c_str());
this->publishENUOrigin();
} }
// Subscribe nemo progress. // Subscribe nemo progress.
...@@ -211,35 +263,23 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -211,35 +263,23 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
UniqueLock lk3(this->ENUOriginMutex, std::adopt_lock); UniqueLock lk3(this->ENUOriginMutex, std::adopt_lock);
int requiredSize = this->tilesENU.polygons().size(); int requiredSize = this->tilesENU.polygons().size();
auto hold = this->holdProgress_.load();
auto &progressMsg = this->qProgress; auto &progressMsg = this->qProgress;
if (!nemo_msgs::progress::fromJson(*pDoc, progressMsg) || if (!nemo_msgs::progress::fromJson(*pDoc, progressMsg) ||
progressMsg.progress().size() != progressMsg.progress().size() !=
requiredSize) { // Some error occured. requiredSize) { // Some error occured.
progressMsg.progress().clear(); progressMsg.progress().clear();
qgcApp()->showMessage("Invalid progress message received.");
// Publish snake origin. } else if (!hold) {
JsonDocUPtr jOrigin( this->qProgressHolded = this->qProgress;
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
bool ret = geographic_msgs::geo_point::toJson(
this->ENUOrigin, *jOrigin, jOrigin->GetAllocator());
Q_ASSERT(ret);
(void)ret;
this->pRosBridge->publish(std::move(jOrigin), "/snake/origin");
// Publish snake tiles.
JsonDocUPtr jSnakeTiles(
std::make_unique<rapidjson::Document>(rapidjson::kObjectType));
ret = jsk_recognition_msgs::polygon_array::toJson(
this->tilesENU, *jSnakeTiles, jSnakeTiles->GetAllocator());
Q_ASSERT(ret);
(void)ret;
this->pRosBridge->publish(std::move(jSnakeTiles), "/snake/tiles");
} }
lk1.unlock(); lk1.unlock();
lk2.unlock(); lk2.unlock();
lk3.unlock(); lk3.unlock();
emit this->parent->progressChanged(); if (!hold) {
emit this->parent->progressChanged();
}
}); });
// Subscribe /nemo/heartbeat. // Subscribe /nemo/heartbeat.
...@@ -247,13 +287,16 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -247,13 +287,16 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
"/nemo/heartbeat", "/nemo/heartbeat",
/* callback */ [this](JsonDocUPtr pDoc) { /* callback */ [this](JsonDocUPtr pDoc) {
// auto start = std::chrono::high_resolution_clock::now(); // auto start = std::chrono::high_resolution_clock::now();
UniqueLock lk(this->heartbeatMutex); nemo_msgs::heartbeat::Heartbeat heartbeatMsg;
UniqueLock lk(this->statusMutex);
auto &heartbeatMsg = this->heartbeat;
if (!nemo_msgs::heartbeat::fromJson(*pDoc, heartbeatMsg)) { if (!nemo_msgs::heartbeat::fromJson(*pDoc, heartbeatMsg)) {
heartbeatMsg.setStatus(integral(NemoStatus::InvalidHeartbeat)); status_ = STATUS::INVALID_HEARTBEAT;
this->nextTimeout = TimePoint::max();
} else { } else {
status_ = heartbeatToStatus(heartbeatMsg);
}
if (status_ == STATUS::INVALID_HEARTBEAT) {
this->nextTimeout = TimePoint::max();
} else if (status_ == STATUS::HEARTBEAT_DETECTED) {
this->nextTimeout = this->nextTimeout =
std::chrono::high_resolution_clock::now() + timeoutInterval; std::chrono::high_resolution_clock::now() + timeoutInterval;
} }
...@@ -309,20 +352,29 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -309,20 +352,29 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
} }
void NemoInterface::Impl::loop() { void NemoInterface::Impl::loop() {
// Check ROS Bridge status and do setup if necessary. // Check ROS Bridge status and do setup if necessary.
if (this->running) { if (this->running_) {
if (!this->pRosBridge->isRunning()) { if (!this->pRosBridge->isRunning()) {
this->pRosBridge->start(); this->pRosBridge->start();
} else if (this->pRosBridge->isRunning() && this->pRosBridge->connected() && } else if (this->pRosBridge->isRunning() && this->pRosBridge->connected() &&
!this->topicServiceSetupDone) { !this->topicServiceSetupDone) {
if (this->doTopicServiceSetup()) if (this->doTopicServiceSetup()) {
this->topicServiceSetupDone = true; this->topicServiceSetupDone = true;
UniqueLock lk(this->statusMutex);
this->status_ = STATUS::WEBSOCKET_DETECTED;
lk.unlock();
emit this->parent->statusChanged();
}
} else if (this->pRosBridge->isRunning() && } else if (this->pRosBridge->isRunning() &&
!this->pRosBridge->connected() && this->topicServiceSetupDone) { !this->pRosBridge->connected() && this->topicServiceSetupDone) {
this->pRosBridge->reset(); this->pRosBridge->reset();
this->pRosBridge->start(); this->pRosBridge->start();
this->topicServiceSetupDone = false; this->topicServiceSetupDone = false;
UniqueLock lk(this->statusMutex);
this->status_ = STATUS::TIMEOUT;
lk.unlock();
emit this->parent->statusChanged();
} }
} else if (this->pRosBridge->isRunning()) { } else if (this->pRosBridge->isRunning()) {
this->pRosBridge->reset(); this->pRosBridge->reset();
...@@ -330,17 +382,29 @@ void NemoInterface::Impl::loop() { ...@@ -330,17 +382,29 @@ void NemoInterface::Impl::loop() {
} }
// Check if heartbeat timeout occured. // Check if heartbeat timeout occured.
if (this->running && this->topicServiceSetupDone) { if (this->running_ && this->topicServiceSetupDone) {
UniqueLock lk(this->heartbeatMutex); UniqueLock lk(this->statusMutex);
if (this->nextTimeout != TimePoint::max() && if (this->nextTimeout != TimePoint::max() &&
this->nextTimeout < std::chrono::high_resolution_clock::now()) { this->nextTimeout < std::chrono::high_resolution_clock::now()) {
this->heartbeat.setStatus(integral(NemoStatus::Timeout)); if (this->pRosBridge->isRunning() && this->pRosBridge->connected()) {
this->status_ = STATUS::WEBSOCKET_DETECTED;
} else {
this->status_ = STATUS::TIMEOUT;
}
lk.unlock(); lk.unlock();
emit this->parent->statusChanged(); emit this->parent->statusChanged();
} }
} }
} }
NemoInterface::STATUS NemoInterface::Impl::heartbeatToStatus(
const ros_bridge::messages::nemo_msgs::heartbeat::Heartbeat &hb) {
if (STATUS(hb.status()) == STATUS::HEARTBEAT_DETECTED)
return STATUS::HEARTBEAT_DETECTED;
else
return STATUS::INVALID_HEARTBEAT;
}
void NemoInterface::Impl::publishTilesENU() { void NemoInterface::Impl::publishTilesENU() {
using namespace ros_bridge::messages; using namespace ros_bridge::messages;
JsonDocUPtr jSnakeTiles( JsonDocUPtr jSnakeTiles(
...@@ -374,7 +438,13 @@ void NemoInterface::start() { this->pImpl->start(); } ...@@ -374,7 +438,13 @@ void NemoInterface::start() { this->pImpl->start(); }
void NemoInterface::stop() { this->pImpl->stop(); } void NemoInterface::stop() { this->pImpl->stop(); }
void NemoInterface::publishTileData(const TileData &tileData) { void NemoInterface::publishTileData() { this->pImpl->publishTileData(); }
void NemoInterface::requestProgress() {
qWarning() << "NemoInterface::requestProgress(): dummy.";
}
void NemoInterface::setTileData(const TileData &tileData) {
this->pImpl->setTileData(tileData); this->pImpl->setTileData(tileData);
} }
...@@ -382,8 +452,26 @@ bool NemoInterface::hasTileData(const TileData &tileData) const { ...@@ -382,8 +452,26 @@ bool NemoInterface::hasTileData(const TileData &tileData) const {
return this->pImpl->hasTileData(tileData); return this->pImpl->hasTileData(tileData);
} }
NemoInterface::NemoStatus NemoInterface::status() const { void NemoInterface::setHoldProgress(bool hp) {
this->pImpl->setHoldProgress(hp);
}
int NemoInterface::status() const { return integral(this->pImpl->status()); }
NemoInterface::STATUS NemoInterface::statusEnum() const {
return this->pImpl->status(); return this->pImpl->status();
} }
QString NemoInterface::statusString() const {
return statusMap.at(this->pImpl->status());
}
QVector<int> NemoInterface::progress() const { return this->pImpl->progress(); } QVector<int> NemoInterface::progress() const { return this->pImpl->progress(); }
QString NemoInterface::editorQml() {
return QStringLiteral("NemoInterface.qml");
}
bool NemoInterface::running() { return this->pImpl->running(); }
bool NemoInterface::holdProgress() { return this->pImpl->holdProgress(); }
...@@ -13,28 +13,48 @@ class NemoInterface : public QObject { ...@@ -13,28 +13,48 @@ class NemoInterface : public QObject {
using PImpl = std::unique_ptr<Impl>; using PImpl = std::unique_ptr<Impl>;
public: public:
enum class NemoStatus { enum class STATUS {
NotConnected = 0, NOT_CONNECTED = 0,
Connected = 1, HEARTBEAT_DETECTED = 1,
Timeout = -1, WEBSOCKET_DETECTED = 2,
InvalidHeartbeat = -2 TIMEOUT = -1,
INVALID_HEARTBEAT = -2
}; };
explicit NemoInterface(QObject *parent = nullptr); explicit NemoInterface(QObject *parent = nullptr);
~NemoInterface() override; ~NemoInterface() override;
void start(); Q_PROPERTY(int status READ status NOTIFY statusChanged)
void stop(); Q_PROPERTY(QString statusString READ statusString NOTIFY statusChanged)
Q_PROPERTY(QVector<int> progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString editorQml READ editorQml CONSTANT)
Q_PROPERTY(bool running READ running NOTIFY runningChanged)
Q_PROPERTY(bool holdProgress READ holdProgress WRITE setHoldProgress NOTIFY
holdProgressChanged)
void publishTileData(const TileData &tileData); Q_INVOKABLE void start();
Q_INVOKABLE void stop();
Q_INVOKABLE void publishTileData();
Q_INVOKABLE void requestProgress();
void setTileData(const TileData &tileData);
bool hasTileData(const TileData &tileData) const; bool hasTileData(const TileData &tileData) const;
void setAutoPublish(bool ap);
void setHoldProgress(bool hp);
NemoStatus status() const; int status() const;
STATUS statusEnum() const;
QString statusString() const;
QVector<int> progress() const; QVector<int> progress() const;
QString editorQml();
bool running();
bool holdProgress();
signals: signals:
void statusChanged(); void statusChanged();
void progressChanged(); void progressChanged();
void runningChanged();
void holdProgressChanged();
private: private:
PImpl pImpl; PImpl pImpl;
......
...@@ -58,9 +58,8 @@ WimaController::WimaController(QObject *parent) ...@@ -58,9 +58,8 @@ WimaController::WimaController(QObject *parent)
_areaInterface(&_measurementArea, &_serviceArea, &_corridor, _areaInterface(&_measurementArea, &_serviceArea, &_corridor,
&_joinedArea), &_joinedArea),
_WMSettings(), _defaultWM(_WMSettings, _areaInterface), _WMSettings(), _defaultWM(_WMSettings, _areaInterface),
_snakeWM(_WMSettings, _areaInterface),
_rtlWM(_WMSettings, _areaInterface), _rtlWM(_WMSettings, _areaInterface),
_currentWM(&_defaultWM), _WMList{&_defaultWM, &_snakeWM, &_rtlWM}, _currentWM(&_defaultWM), _WMList{&_defaultWM, &_rtlWM},
_metaDataMap(FactMetaData::createMapFromJsonFile( _metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)), QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)),
_enableWimaController(settingsGroup, _enableWimaController(settingsGroup,
...@@ -78,7 +77,6 @@ WimaController::WimaController(QObject *parent) ...@@ -78,7 +77,6 @@ WimaController::WimaController(QObject *parent)
_arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]), _arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]),
_altitude(settingsGroup, _metaDataMap[altitudeName]), _altitude(settingsGroup, _metaDataMap[altitudeName]),
_lowBatteryHandlingTriggered(false), _measurementPathLength(-1), _lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
_nemoInterface(this),
_batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) { _batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {
// Set up facts for waypoint manager. // Set up facts for waypoint manager.
...@@ -97,14 +95,6 @@ WimaController::WimaController(QObject *parent) ...@@ -97,14 +95,6 @@ WimaController::WimaController(QObject *parent)
connect(&_altitude, &Fact::rawValueChanged, this, connect(&_altitude, &Fact::rawValueChanged, this,
&WimaController::_updateAltitude); &WimaController::_updateAltitude);
// Nemo stuff.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
// Init waypoint managers. // Init waypoint managers.
bool value; bool value;
size_t overlap = _overlapWaypoints.rawValue().toUInt(&value); size_t overlap = _overlapWaypoints.rawValue().toUInt(&value);
...@@ -124,35 +114,6 @@ WimaController::WimaController(QObject *parent) ...@@ -124,35 +114,6 @@ WimaController::WimaController(QObject *parent)
connect(&_eventTimer, &QTimer::timeout, this, connect(&_eventTimer, &QTimer::timeout, this,
&WimaController::_eventTimerHandler); &WimaController::_eventTimerHandler);
_eventTimer.start(EVENT_TIMER_INTERVAL); _eventTimer.start(EVENT_TIMER_INTERVAL);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
// Enable/disable snake.
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_enableSnakeChangedHandler);
_enableSnakeChangedHandler();
connect(&_enableWimaController, &Fact::rawValueChanged, [this] {
if (!this->_enableWimaController.rawValue().toBool()) {
this->_enableSnake.setCookedValue(QVariant(false));
}
});
// Snake Waypoint Manager.
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_switchToSnakeWaypointManager);
_switchToSnakeWaypointManager(_enableSnake.rawValue());
// Routing
connect(&_routingThread, &RoutingThread::result, this,
&WimaController::_storeRoute);
connect(&_routingThread, &RoutingThread::calculatingChanged, this,
&WimaController::snakeCalcInProgressChanged);
} }
PlanMasterController *WimaController::masterController() { PlanMasterController *WimaController::masterController() {
...@@ -226,17 +187,13 @@ double WimaController::phaseDuration() const { ...@@ -226,17 +187,13 @@ double WimaController::phaseDuration() const {
} }
int WimaController::nemoStatus() const { int WimaController::nemoStatus() const {
return integral(_nemoInterface.status()); return integral(NemoInterface::STATUS::NOT_CONNECTED);
} }
QString WimaController::nemoStatusString() const { QString WimaController::nemoStatusString() const {
return _nemoStatusMap.at(nemoStatus()); return _nemoStatusMap.at(nemoStatus());
} }
bool WimaController::snakeCalcInProgress() const {
return _routingThread.calculating();
}
void WimaController::setMasterController(PlanMasterController *masterC) { void WimaController::setMasterController(PlanMasterController *masterC) {
_masterController = masterC; _masterController = masterC;
_WMSettings.setMasterController(masterC); _WMSettings.setMasterController(masterC);
...@@ -390,7 +347,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) { ...@@ -390,7 +347,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
// reset visual items // reset visual items
_areas.clear(); _areas.clear();
_defaultWM.clear(); _defaultWM.clear();
_snakeWM.clear();
_measurementArea = WimaMeasurementAreaData(); _measurementArea = WimaMeasurementAreaData();
_serviceArea = WimaServiceAreaData(); _serviceArea = WimaServiceAreaData();
_corridor = WimaCorridorData(); _corridor = WimaCorridorData();
...@@ -463,9 +419,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) { ...@@ -463,9 +419,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
emit visualItemsChanged(); emit visualItemsChanged();
emit snakeTilesChanged(); emit snakeTilesChanged();
// Copy raw transects.
this->_rawTransects = planData->transects();
// Copy missionItems. // Copy missionItems.
auto tempMissionItems = planData->missionItems(); auto tempMissionItems = planData->missionItems();
if (tempMissionItems.size() < 1) { if (tempMissionItems.size() < 1) {
...@@ -474,7 +427,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) { ...@@ -474,7 +427,6 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
} }
for (auto *item : tempMissionItems) { for (auto *item : tempMissionItems) {
_snakeWM.push_back(item->coordinate());
_defaultWM.push_back(item->coordinate()); _defaultWM.push_back(item->coordinate());
} }
_WMSettings.setHomePosition(QGeoCoordinate( _WMSettings.setHomePosition(QGeoCoordinate(
...@@ -484,36 +436,14 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) { ...@@ -484,36 +436,14 @@ bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
Q_ASSERT(false); Q_ASSERT(false);
return false; return false;
} }
if (!_snakeWM.reset()) {
Q_ASSERT(false);
return false;
}
if (_currentWM == &_defaultWM || _currentWM == &_snakeWM) { if (_currentWM == &_defaultWM) {
emit missionItemsChanged(); emit missionItemsChanged();
emit currentMissionItemsChanged(); emit currentMissionItemsChanged();
emit waypointPathChanged(); emit waypointPathChanged();
emit currentWaypointPathChanged(); emit currentWaypointPathChanged();
} }
// Publish tiles, set progress if necessary.
if (!this->_nemoInterface.hasTileData(this->_measurementArea.tileData())) {
if (_enableSnake.rawValue().toBool()) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
this->_measurementArea.progress() =
QVector<int>(this->_measurementArea.tiles()->count(), 0);
emit nemoProgressChanged();
} else if (this->_enableSnake.rawValue().toBool()) {
const auto progress = this->_nemoInterface.progress();
if (progress.size() == this->_measurementArea.tiles()->count()) {
this->_measurementArea.progress() = std::move(progress);
emit nemoProgressChanged();
this->_updateRoute();
}
}
_planDataValid = true; _planDataValid = true;
return true; return true;
} }
...@@ -790,226 +720,3 @@ void WimaController::_initSmartRTL() { ...@@ -790,226 +720,3 @@ void WimaController::_initSmartRTL() {
&WimaController::_initSmartRTL); &WimaController::_initSmartRTL);
} }
} }
void WimaController::_storeRoute(RoutingThread::PtrRoutingData data) {
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now();
#endif
// Copy waypoints to waypoint manager.
_snakeWM.clear();
if (data->solutionVector.size() > 0 &&
data->solutionVector.front().size() > 0) {
// Store route.
const auto &transectsENU = data->transects;
const auto &solution = data->solutionVector.front();
const auto &route = solution.front();
const auto &path = route.path;
const auto &info = route.info;
// Find index of first waypoint.
std::size_t idxFirst = 0;
const auto &infoFirst = info.front();
const auto &firstTransect = transectsENU[infoFirst.index];
const auto &firstWaypoint =
infoFirst.reversed ? firstTransect.back() : firstTransect.front();
double th = 0.001;
for (std::size_t i = 0; i < path.size(); ++i) {
auto dist = bg::distance(path[i], firstWaypoint);
if (dist < th) {
idxFirst = i;
break;
}
}
// Find index of last waypoint.
std::size_t idxLast = path.size() - 1;
const auto &infoLast = info.back();
const auto &lastTransect = transectsENU[infoLast.index];
const auto &lastWaypoint =
infoLast.reversed ? lastTransect.front() : lastTransect.back();
for (long i = path.size() - 1; i >= 0; --i) {
auto dist = bg::distance(path[i], lastWaypoint);
if (dist < th) {
idxLast = i;
break;
}
}
// Convert to geo coordinates and append to waypoint manager.
const auto &ori = this->_origin;
for (std::size_t i = idxFirst; i <= idxLast; ++i) {
auto &vertex = path[i];
QGeoCoordinate c;
snake::fromENU(ori, vertex, c);
_snakeWM.push_back(c);
}
// Do update.
this->_snakeWM.update(); // this can take a while (ca. 200ms)
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
#ifdef SNAKE_SHOW_TIME
auto end = std::chrono::high_resolution_clock::now();
std::cout << "WimaController::_threadFinishedHandler(): waypoints: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< " ms" << std::endl;
#endif
}
void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
if (variant.value<bool>()) {
_switchWaypointManager(_snakeWM);
} else {
_switchWaypointManager(_defaultWM);
}
}
void WimaController::_progressChangedHandler() {
const auto progress = this->_nemoInterface.progress();
if (this->_measurementArea.tiles()->count() == progress.size()) {
this->_measurementArea.progress() = std::move(progress);
emit nemoProgressChanged();
this->_updateRoute();
} else if (_planDataValid) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
}
void WimaController::_enableSnakeChangedHandler() {
if (this->_enableSnake.rawValue().toBool()) {
qDebug() << "WimaController: enabling snake.";
_switchWaypointManager(_snakeWM);
this->_nemoInterface.start();
if (_planDataValid) {
if (!this->_nemoInterface.hasTileData(
this->_measurementArea.tileData())) {
this->_nemoInterface.publishTileData(this->_measurementArea.tileData());
}
}
} else {
qDebug() << "WimaController: disabling snake.";
_switchWaypointManager(_defaultWM);
this->_nemoInterface.stop();
}
}
void WimaController::_updateRoute() {
// precondtion
if (_planDataValid && this->_joinedArea.coordinateList().size() > 0) {
const auto progress = this->_nemoInterface.progress();
const auto *tiles = this->_measurementArea.tiles();
// precondtion
if (tiles->count() > 0 && progress.size() == tiles->count() &&
this->_rawTransects.size() > 0 &&
this->_joinedArea.coordinateList().size() > 0) {
// Fetch tiles and convert to ENU.
this->_origin = this->_joinedArea.coordinateList().first();
this->_origin.setAltitude(0);
const auto &origin = this->_origin;
auto pTiles = std::make_shared<std::vector<snake::FPolygon>>();
std::size_t numTiles = 0;
for (int i = 0; i < progress.size(); ++i) {
if (progress[i] == 100) {
++numTiles;
const auto *obj = tiles->get(i);
const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
snake::FPolygon t;
snake::areaToEnu(origin, tile->coordinateList(), t);
pTiles->push_back(std::move(t));
} else {
return;
}
}
}
if (numTiles > 0) {
// Fetch safe area and convert to ENU.
RoutingParameter par;
auto safeArea = this->_joinedArea.coordinateList();
for (auto &v : safeArea) {
v.setAltitude(0);
}
auto &safeAreaENU = par.safeArea;
snake::areaToEnu(origin, safeArea, safeAreaENU);
const auto &depot = this->_serviceArea.depot();
snake::FPoint depotENU;
snake::toENU(origin, depot, depotENU);
// Fetch geo transects and convert to ENU.
const auto &geoTransects = this->_rawTransects;
auto pUnclippedTransects = std::make_shared<snake::Transects>();
for (auto &geoTransect : geoTransects) {
snake::FLineString t;
for (auto &geoVertex : geoTransect) {
snake::FPoint v;
snake::toENU(origin, geoVertex, v);
t.push_back(v);
}
pUnclippedTransects->push_back(t);
}
std::size_t minLength = 1; // meter
qWarning() << "using minLength dummy lkjfdslooij";
auto generator = [depotENU, pUnclippedTransects, pTiles,
minLength](snake::Transects &transects) -> bool {
// Convert transects to clipper path.
vector<ClipperLib::Path> transectsClipper;
for (const auto &t : *pUnclippedTransects) {
ClipperLib::Path path;
for (const auto &v : t) {
ClipperLib::IntPoint c{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)};
path.push_back(c);
}
transectsClipper.push_back(std::move(path));
}
// Add transects to clipper.
ClipperLib::Clipper clipper;
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
// Add tiles to clipper.
vector<ClipperLib::Path> tilesClipper;
for (const auto &t : *pTiles) {
ClipperLib::Path path;
for (const auto &v : t.outer()) {
path.push_back(ClipperLib::IntPoint{
static_cast<ClipperLib::cInt>(v.get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(v.get<1>() * CLIPPER_SCALE)});
}
tilesClipper.push_back(std::move(path));
}
clipper.AddPaths(tilesClipper, ClipperLib::ptClip, true);
// Clip transects.
ClipperLib::PolyTree clippedTransecs;
clipper.Execute(ClipperLib::ctDifference, clippedTransecs,
ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Extract transects from PolyTree and convert them to
// BoostLineString
transects.push_back(snake::FLineString{depotENU});
for (const auto &child : clippedTransecs.Childs) {
snake::FLineString transect;
for (const auto &v : child->Contour) {
snake::FPoint c{static_cast<double>(v.X) / CLIPPER_SCALE,
static_cast<double>(v.Y) / CLIPPER_SCALE};
transect.push_back(c);
}
if (bg::length(transect) >= minLength) {
transects.push_back(std::move(transect));
}
}
if (transects.size() > 1) {
return true;
} else {
return false;
}
}; // generator
this->_routingThread.route(par, generator);
} else {
this->_storeRoute(RoutingThread::PtrRoutingData(new RoutingData()));
}
}
}
}
...@@ -67,12 +67,9 @@ public: ...@@ -67,12 +67,9 @@ public:
double phaseDuration READ phaseDuration NOTIFY phaseDurationChanged) double phaseDuration READ phaseDuration NOTIFY phaseDurationChanged)
// Snake // Snake
Q_PROPERTY(Fact *enableSnake READ enableSnake CONSTANT)
Q_PROPERTY(int nemoStatus READ nemoStatus NOTIFY nemoStatusChanged) Q_PROPERTY(int nemoStatus READ nemoStatus NOTIFY nemoStatusChanged)
Q_PROPERTY(QString nemoStatusString READ nemoStatusString NOTIFY Q_PROPERTY(QString nemoStatusString READ nemoStatusString NOTIFY
nemoStatusStringChanged) nemoStatusStringChanged)
Q_PROPERTY(bool snakeCalcInProgress READ snakeCalcInProgress NOTIFY
snakeCalcInProgressChanged)
Q_PROPERTY( Q_PROPERTY(
QmlObjectListModel *snakeTiles READ snakeTiles NOTIFY snakeTilesChanged) QmlObjectListModel *snakeTiles READ snakeTiles NOTIFY snakeTilesChanged)
Q_PROPERTY(QVariantList snakeTileCenterPoints READ snakeTileCenterPoints Q_PROPERTY(QVariantList snakeTileCenterPoints READ snakeTileCenterPoints
...@@ -102,15 +99,12 @@ public: ...@@ -102,15 +99,12 @@ public:
Fact *flightSpeed(void); Fact *flightSpeed(void);
Fact *arrivalReturnSpeed(void); Fact *arrivalReturnSpeed(void);
Fact *altitude(void); Fact *altitude(void);
// Snake settings facts.
Fact *enableSnake(void) { return &_enableSnake; }
// Snake data. // Snake data.
QmlObjectListModel *snakeTiles(void); QmlObjectListModel *snakeTiles(void);
QVariantList snakeTileCenterPoints(void); QVariantList snakeTileCenterPoints(void);
QVector<int> nemoProgress(void); QVector<int> nemoProgress(void);
int nemoStatus(void) const; int nemoStatus(void) const;
QString nemoStatusString(void) const; QString nemoStatusString(void) const;
bool snakeCalcInProgress(void) const;
bool uploadOverrideRequired(void) const; bool uploadOverrideRequired(void) const;
bool vehicleHasLowBattery(void) const; bool vehicleHasLowBattery(void) const;
...@@ -153,8 +147,6 @@ public: ...@@ -153,8 +147,6 @@ public:
static const char *flightSpeedName; static const char *flightSpeedName;
static const char *arrivalReturnSpeedName; static const char *arrivalReturnSpeedName;
static const char *altitudeName; static const char *altitudeName;
static const char *snakeLineDistanceName;
static const char *snakeMinTransectLengthName;
signals: signals:
// Controllers. // Controllers.
...@@ -176,7 +168,6 @@ signals: ...@@ -176,7 +168,6 @@ signals:
void phaseDistanceChanged(void); void phaseDistanceChanged(void);
void phaseDurationChanged(void); void phaseDurationChanged(void);
// Snake. // Snake.
void snakeCalcInProgressChanged(void);
void snakeTilesChanged(void); void snakeTilesChanged(void);
void nemoProgressChanged(void); void nemoProgressChanged(void);
void nemoStatusChanged(void); void nemoStatusChanged(void);
...@@ -207,12 +198,7 @@ private slots: ...@@ -207,12 +198,7 @@ private slots:
void _initSmartRTL(); void _initSmartRTL();
void _smartRTLCleanUp(bool flying); void _smartRTLCleanUp(bool flying);
// Snake. // Snake.
void _storeRoute(RoutingThread::PtrRoutingData data);
void _switchWaypointManager(WaypointManager::ManagerBase &manager); void _switchWaypointManager(WaypointManager::ManagerBase &manager);
void _switchToSnakeWaypointManager(QVariant variant);
void _progressChangedHandler();
void _enableSnakeChangedHandler();
void _updateRoute();
// Periodic tasks. // Periodic tasks.
void _eventTimerHandler(void); void _eventTimerHandler(void);
...@@ -234,7 +220,6 @@ private: ...@@ -234,7 +220,6 @@ private:
WaypointManager::AreaInterface _areaInterface; WaypointManager::AreaInterface _areaInterface;
WaypointManager::Settings _WMSettings; // Waypoint Manager Settings WaypointManager::Settings _WMSettings; // Waypoint Manager Settings
WaypointManager::DefaultManager _defaultWM; WaypointManager::DefaultManager _defaultWM;
WaypointManager::DefaultManager _snakeWM;
WaypointManager::RTLManager _rtlWM; WaypointManager::RTLManager _rtlWM;
WaypointManager::ManagerBase *_currentWM; WaypointManager::ManagerBase *_currentWM;
using ManagerList = QList<WaypointManager::ManagerBase *>; using ManagerList = QList<WaypointManager::ManagerBase *>;
...@@ -262,7 +247,6 @@ private: ...@@ -262,7 +247,6 @@ private:
SettingsFact _flightSpeed; // mission flight speed SettingsFact _flightSpeed; // mission flight speed
SettingsFact _arrivalReturnSpeed; // arrival and return path speed SettingsFact _arrivalReturnSpeed; // arrival and return path speed
SettingsFact _altitude; // mission altitude SettingsFact _altitude; // mission altitude
SettingsFact _enableSnake; // Enable Snake (see snake.h)
// Smart RTL. // Smart RTL.
QTimer _smartRTLTimer; QTimer _smartRTLTimer;
...@@ -271,13 +255,8 @@ private: ...@@ -271,13 +255,8 @@ private:
// Waypoint statistics. // Waypoint statistics.
double _measurementPathLength; // the lenght of the phase in meters double _measurementPathLength; // the lenght of the phase in meters
// Snake
QList<QList<QGeoCoordinate>> _rawTransects;
NemoInterface _nemoInterface;
using StatusMap = std::map<int, QString>; using StatusMap = std::map<int, QString>;
static StatusMap _nemoStatusMap; static StatusMap _nemoStatusMap;
RoutingThread _routingThread;
QGeoCoordinate _origin;
// Periodic tasks. // Periodic tasks.
QTimer _eventTimer; QTimer _eventTimer;
......
...@@ -25,7 +25,8 @@ WimaPlaner::WimaPlaner(QObject *parent) ...@@ -25,7 +25,8 @@ WimaPlaner::WimaPlaner(QObject *parent)
_currentAreaIndex(-1), _wimaBridge(nullptr), _mAreaChanged(true), _currentAreaIndex(-1), _wimaBridge(nullptr), _mAreaChanged(true),
_sAreaChanged(true), _corridorChanged(true), _joinedArea(this), _sAreaChanged(true), _corridorChanged(true), _joinedArea(this),
_arrivalPathLength(0), _returnPathLength(0), _TSComplexItem(nullptr), _arrivalPathLength(0), _returnPathLength(0), _TSComplexItem(nullptr),
_surveyChanged(true), _synchronized(false), _needsUpdate(true) { _surveyChanged(true), _synchronized(false), _needsUpdate(true),
_nemoInterface(this) {
connect(this, &WimaPlaner::currentPolygonIndexChanged, this, connect(this, &WimaPlaner::currentPolygonIndexChanged, this,
&WimaPlaner::updatePolygonInteractivity); &WimaPlaner::updatePolygonInteractivity);
...@@ -33,10 +34,14 @@ WimaPlaner::WimaPlaner(QObject *parent) ...@@ -33,10 +34,14 @@ WimaPlaner::WimaPlaner(QObject *parent)
this->_mAreaChanged = true; this->_mAreaChanged = true;
this->setNeedsUpdate(true); this->setNeedsUpdate(true);
}); });
connect(&this->_measurementArea, &WimaMeasurementArea::tilesChanged, [this] {
this->_nemoInterface.setTileData(this->_measurementArea.tileData());
});
connect(&this->_serviceArea, &WimaArea::pathChanged, [this] { connect(&this->_serviceArea, &WimaArea::pathChanged, [this] {
this->_sAreaChanged = true; this->_sAreaChanged = true;
this->setNeedsUpdate(true); this->setNeedsUpdate(true);
}); });
connect(&this->_serviceArea, &WimaServiceArea::depotChanged, [this] { connect(&this->_serviceArea, &WimaServiceArea::depotChanged, [this] {
this->_sAreaChanged = true; this->_sAreaChanged = true;
this->setNeedsUpdate(true); this->setNeedsUpdate(true);
...@@ -52,6 +57,11 @@ WimaPlaner::WimaPlaner(QObject *parent) ...@@ -52,6 +57,11 @@ WimaPlaner::WimaPlaner(QObject *parent)
_autoLoadTimer.setSingleShot(true); _autoLoadTimer.setSingleShot(true);
_autoLoadTimer.start(300); _autoLoadTimer.start(300);
#endif #endif
// NemoInterface
connect(&this->_nemoInterface, &NemoInterface::progressChanged, [this] {
this->_measurementArea.setProgress(this->_nemoInterface.progress());
});
} }
PlanMasterController *WimaPlaner::masterController() { PlanMasterController *WimaPlaner::masterController() {
...@@ -95,6 +105,8 @@ QGeoCoordinate WimaPlaner::joinedAreaCenter() const { ...@@ -95,6 +105,8 @@ QGeoCoordinate WimaPlaner::joinedAreaCenter() const {
WimaBridge *WimaPlaner::wimaBridge() { return _wimaBridge; } WimaBridge *WimaPlaner::wimaBridge() { return _wimaBridge; }
NemoInterface *WimaPlaner::nemoInterface() { return &_nemoInterface; }
void WimaPlaner::setMasterController(PlanMasterController *masterC) { void WimaPlaner::setMasterController(PlanMasterController *masterC) {
_masterController = masterC; _masterController = masterC;
emit masterControllerChanged(); emit masterControllerChanged();
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "Geometry/WimaServiceAreaData.h" #include "Geometry/WimaServiceAreaData.h"
#include "WimaPlanData.h" #include "WimaPlanData.h"
#include "Snake/NemoInterface.h"
#include "JsonHelper.h" #include "JsonHelper.h"
class MissionController; class MissionController;
...@@ -45,6 +47,7 @@ public: ...@@ -45,6 +47,7 @@ public:
Q_PROPERTY(QGeoCoordinate joinedAreaCenter READ joinedAreaCenter CONSTANT) Q_PROPERTY(QGeoCoordinate joinedAreaCenter READ joinedAreaCenter CONSTANT)
Q_PROPERTY(WimaBridge *wimaBridge READ wimaBridge WRITE setWimaBridge NOTIFY Q_PROPERTY(WimaBridge *wimaBridge READ wimaBridge WRITE setWimaBridge NOTIFY
wimaBridgeChanged) wimaBridgeChanged)
Q_PROPERTY(NemoInterface *nemoInterface READ nemoInterface CONSTANT)
Q_PROPERTY(bool synchronized READ synchronized NOTIFY synchronizedChanged) Q_PROPERTY(bool synchronized READ synchronized NOTIFY synchronizedChanged)
Q_PROPERTY(bool needsUpdate READ needsUpdate NOTIFY needsUpdateChanged) Q_PROPERTY(bool needsUpdate READ needsUpdate NOTIFY needsUpdateChanged)
...@@ -59,6 +62,7 @@ public: ...@@ -59,6 +62,7 @@ public:
QString fileExtension(void) const; QString fileExtension(void) const;
QGeoCoordinate joinedAreaCenter(void) const; QGeoCoordinate joinedAreaCenter(void) const;
WimaBridge *wimaBridge(void); WimaBridge *wimaBridge(void);
NemoInterface *nemoInterface(void);
bool synchronized(); bool synchronized();
bool needsUpdate(); bool needsUpdate();
...@@ -161,4 +165,6 @@ private: ...@@ -161,4 +165,6 @@ private:
QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents QTimer _autoLoadTimer; // timer to auto load mission after some time, prevents
// seg. faults // seg. faults
#endif #endif
NemoInterface _nemoInterface;
}; };
...@@ -110,25 +110,39 @@ Item { ...@@ -110,25 +110,39 @@ Item {
// Add Snake tiles to the map // Add Snake tiles to the map
Component { Component {
id: tileComponent id: tileComponent
MapPolygon { MapPolygon{
color: "transparent"
opacity: 1
border.color: "black"
border.width: 1
path: [] path: []
opacity: 0.6
z: 2
} }
} }
Repeater { Repeater {
id: progressRepeater
property bool enable: areaItem.showTiles.value property bool enable: areaItem.showTiles.value
model: enable ? areaItem.tiles : 0 model: enable ? areaItem.tiles : 0
function getColor(i) {
var progress = areaItem.progress[i]
if (progress < 25)
return "transparent"
if (progress < 50)
return "orange"
if (progress < 75)
return "yellow"
if (progress < 100)
return "greenyellow"
return "limegreen"
}
Item{ Item{
property var _tileComponent property var _tileComponent
function addVisuals() { function addVisuals() {
_tileComponent = tileComponent.createObject(map) _tileComponent = tileComponent.createObject(map)
map.addMapItem(_tileComponent) map.addMapItem(_tileComponent)
_tileComponent.path = object.path _tileComponent.path = object.path
_tileComponent.color = progressRepeater.getColor(index)
} }
function removeVisuals() { function removeVisuals() {
......
...@@ -155,7 +155,7 @@ Rectangle { ...@@ -155,7 +155,7 @@ Rectangle {
anchors.left: logoRow.right anchors.left: logoRow.right
anchors.right: uploadButton.visible ? uploadButton.left : parent.right anchors.right: uploadButton.visible ? uploadButton.left : parent.right
columnSpacing: 0 columnSpacing: 0
columns: 3 columns: 4
GridLayout { GridLayout {
columns: 8 columns: 8
...@@ -252,7 +252,7 @@ Rectangle { ...@@ -252,7 +252,7 @@ Rectangle {
rowSpacing: _rowSpacing rowSpacing: _rowSpacing
columnSpacing: _labelToValueSpacing columnSpacing: _labelToValueSpacing
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: _batteryInfoAvailable // visible: _batteryInfoAvailable
QGCLabel { QGCLabel {
text: qsTr("Battery") text: qsTr("Battery")
...@@ -268,7 +268,7 @@ Rectangle { ...@@ -268,7 +268,7 @@ Rectangle {
} }
Item { width: 1; height: 1 } Item { width: 1; height: 1 }
/* /*
FIXME: Swap point display is currently hidden since the code which calcs it doesn't work correctly FIXME: Swap point display is currently hidden since the code which calcs it doesn't work correctly
QGCLabel { text: qsTr("Swap waypoint:"); font.pointSize: _dataFontSize; } QGCLabel { text: qsTr("Swap waypoint:"); font.pointSize: _dataFontSize; }
QGCLabel { QGCLabel {
...@@ -278,6 +278,72 @@ Rectangle { ...@@ -278,6 +278,72 @@ Rectangle {
} }
*/ */
} }
GridLayout {
columns: 3
rowSpacing: _rowSpacing
columnSpacing: _labelToValueSpacing
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
QGCLabel {
text: qsTr("ROS")
Layout.columnSpan: 3
font.pointSize: ScreenTools.smallFontPointSize
}
QGCCheckBox {
id: enableCheckbox
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: qsTr("Enable")
checked: nemo ? nemo.running : false
onCheckedChanged: {
if (nemo){
if (checked){
nemo.start()
} else {
nemo.stop()
}
checked = Qt.binding(function(){return nemo.running})
}
}
Layout.minimumWidth: _mediumValueWidth
}
QGCLabel {
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: nemo ? nemo.statusString : ""
font.pointSize: _dataFontSize
Layout.minimumWidth: _mediumValueWidth
visible: enableCheckbox.checked
Layout.columnSpan: 2
}
QGCCheckBox {
property var nemo: wimaPlaner ? wimaPlaner.nemoInterface : undefined
text: qsTr("Lock Progress")
checked: nemo ? nemo.lockProgress : false
visible: enableCheckbox.checked
onCheckedChanged: {
if (nemo){
if (checked){
nemo.lockProgress = true
} else {
nemo.lockProgress = false
}
checked = Qt.binding(function(){return nemo.lockProgress})
}
}
Layout.minimumWidth: _mediumValueWidth
}
}
} }
QGCButton { QGCButton {
......
...@@ -54,6 +54,7 @@ QGCView { ...@@ -54,6 +54,7 @@ QGCView {
property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
property var _wimaPlaner: wimaPlaner property var _wimaPlaner: wimaPlaner
property var _nemo: wimaPlaner.nemoInterface
property var _planMasterController: masterController property var _planMasterController: masterController
property var _missionController: _planMasterController.missionController property var _missionController: _planMasterController.missionController
property var _visualItems: _missionController.visualItems property var _visualItems: _missionController.visualItems
...@@ -702,6 +703,10 @@ QGCView { ...@@ -702,6 +703,10 @@ QGCView {
name: qsTr("Update"), name: qsTr("Update"),
iconSource: "/res/calculator.png" iconSource: "/res/calculator.png"
}, },
{
name: qsTr("Publish"),
iconSource: "/res/calculator.png"
},
{ {
name: qsTr("Center"), name: qsTr("Center"),
iconSource: "/qmlimages/MapCenter.svg", iconSource: "/qmlimages/MapCenter.svg",
...@@ -731,10 +736,13 @@ QGCView { ...@@ -731,10 +736,13 @@ QGCView {
case 4: case 4:
wimaPlaner.update(); wimaPlaner.update();
break break
case 6: case 5:
editorMap.zoomLevel += 0.5 _nemo.publishTileData();
break break
case 7: case 7:
editorMap.zoomLevel += 0.5
break
case 8:
editorMap.zoomLevel -= 0.5 editorMap.zoomLevel -= 0.5
break break
} }
......
...@@ -4,61 +4,72 @@ ...@@ -4,61 +4,72 @@
#include <vector> #include <vector>
namespace ros_bridge { namespace ros_bridge {
//! @brief Namespace containing classes and methodes ros message generation. //! @brief Namespace containing classes and methodes ros message generation.
namespace messages { namespace messages {
//! @brief Namespace containing classes and methodes for geometry_msgs generation. //! @brief Namespace containing classes and methodes for geometry_msgs
//! generation.
namespace nemo_msgs { namespace nemo_msgs {
//! @brief Namespace containing methodes for geometry_msgs/Point32 message generation. //! @brief Namespace containing methodes for geometry_msgs/Point32 message
//! generation.
namespace progress { namespace progress {
std::string messageType(); std::string messageType();
//! @brief C++ representation of nemo_msgs/Progress message //! @brief C++ representation of nemo_msgs/Progress message
template <class IntType = long, template <class, class...> class ContainterType = std::vector> template <class IntType = long,
class GenericProgress{ template <class, class...> class ContainterType = std::vector>
class GenericProgress {
public: public:
GenericProgress() {} GenericProgress() {}
GenericProgress(const ContainterType<IntType> &progress) : _progress(progress){} GenericProgress(const ContainterType<IntType> &progress)
GenericProgress(const GenericProgress &p) : _progress(p.progress()){} : _progress(progress) {}
GenericProgress(const GenericProgress &p) : _progress(p.progress()) {}
virtual const ContainterType<IntType> &progress(void) const {
return _progress;
}
virtual ContainterType<IntType> &progress(void) { return _progress; }
virtual const ContainterType<IntType> &progress(void) const {return _progress;} bool operator==(const GenericProgress &other) const {
virtual ContainterType<IntType> &progress(void) {return _progress;} return this->_progress == other._progress;
}
bool operator!=(const GenericProgress &other) const {
return !this->operator==(other);
}
protected: protected:
ContainterType<IntType> _progress; ContainterType<IntType> _progress;
}; };
typedef GenericProgress<> Progress; typedef GenericProgress<> Progress;
template <class ProgressType> template <class ProgressType>
bool toJson(const ProgressType &p, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) bool toJson(const ProgressType &p, rapidjson::Value &value,
{ rapidjson::Document::AllocatorType &allocator) {
rapidjson::Value jProgress(rapidjson::kArrayType); rapidjson::Value jProgress(rapidjson::kArrayType);
for(unsigned long i=0; i < std::uint64_t(p.progress().size()); ++i){ for (unsigned long i = 0; i < std::uint64_t(p.progress().size()); ++i) {
jProgress.PushBack(rapidjson::Value().SetInt(std::int32_t(p.progress()[i])), allocator); jProgress.PushBack(rapidjson::Value().SetInt(std::int32_t(p.progress()[i])),
} allocator);
value.AddMember("progress", jProgress, allocator); }
return true; value.AddMember("progress", jProgress, allocator);
return true;
} }
template <class ProgressType> template <class ProgressType>
bool fromJson(const rapidjson::Value &value, ProgressType &p) bool fromJson(const rapidjson::Value &value, ProgressType &p) {
{ if (!value.HasMember("progress") || !value["progress"].IsArray()) {
if (!value.HasMember("progress") || !value["progress"].IsArray()){ assert(false);
assert(false); return false;
return false; }
}
const auto& jsonProgress = value["progress"]; const auto &jsonProgress = value["progress"];
unsigned long sz = jsonProgress.Size(); unsigned long sz = jsonProgress.Size();
p.progress().clear(); p.progress().clear();
p.progress().reserve(sz); p.progress().reserve(sz);
for (unsigned long i=0; i < sz; ++i) for (unsigned long i = 0; i < sz; ++i)
p.progress().push_back(std::int32_t(jsonProgress[i].GetInt())); p.progress().push_back(std::int32_t(jsonProgress[i].GetInt()));
return true; return true;
} }
} // namespace progress } // namespace progress
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment