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