From 6963097588817aede950eca2343d228655d67988 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 11:31:04 -0700 Subject: [PATCH 01/57] commit --- .../flightgear/Aircraft/EasyStar/easystar.xml | 4 +- src/comm/QGCFlightGearLink.cc | 101 ++++++++++++--- src/comm/QGCFlightGearLink.h | 15 +-- src/qgcunittest/FlightGearTest.cc | 85 +++++++++++++ src/qgcunittest/FlightGearTest.h | 58 +++++++++ src/ui/QGCHilConfiguration.ui | 4 +- src/ui/QGCHilFlightGearConfiguration.cc | 119 +++++++++++++++--- src/ui/QGCHilFlightGearConfiguration.h | 23 +++- src/ui/QGCHilFlightGearConfiguration.ui | 2 +- 9 files changed, 361 insertions(+), 50 deletions(-) create mode 100644 src/qgcunittest/FlightGearTest.cc create mode 100644 src/qgcunittest/FlightGearTest.h diff --git a/files/flightgear/Aircraft/EasyStar/easystar.xml b/files/flightgear/Aircraft/EasyStar/easystar.xml index 3477038fe..742c6cb63 100644 --- a/files/flightgear/Aircraft/EasyStar/easystar.xml +++ b/files/flightgear/Aircraft/EasyStar/easystar.xml @@ -91,7 +91,7 @@ 4.0 0 NONE - FIXED + 0 @@ -107,7 +107,7 @@ 4.0 0 NONE - FIXED + 0 diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index d0164958a..ac1539c92 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -40,11 +40,14 @@ This file is part of the QGROUNDCONTROL project #include #include "MainWindow.h" +// FlightGear process start and connection is quite fragile. Uncomment the define below to get higher level of debug output +// for tracking down problems. +#define DEBUG_FLIGHTGEAR_CONNECT + QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments, QString remoteHost, QHostAddress host, quint16 port) : socket(NULL), process(NULL), - terraSync(NULL), - flightGearVersion(0), + flightGearVersion(3), startupArguments(startupArguments), _sensorHilEnabled(true), barometerOffsetkPa(0.0f) @@ -58,7 +61,7 @@ QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments this->connectState = false; this->currentPort = 49000+mav->getUASID(); this->mav = mav; - this->name = tr("FlightGear Link (port:%1)").arg(port); + this->name = tr("FlightGear 3.0+ Link (port:%1)").arg(port); setRemoteHost(remoteHost); } @@ -74,6 +77,7 @@ QGCFlightGearLink::~QGCFlightGearLink() * @brief Runs the thread * **/ + void QGCFlightGearLink::run() { qDebug() << "STARTING FLIGHTGEAR LINK"; @@ -305,23 +309,23 @@ void QGCFlightGearLink::processError(QProcess::ProcessError err) switch(err) { case QProcess::FailedToStart: - MainWindow::instance()->showCriticalMessage(tr("FlightGear/TerraSync Failed to Start"), tr("Please check if the path and command is correct")); + MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("Please check if the path and command is correct")); break; case QProcess::Crashed: - MainWindow::instance()->showCriticalMessage(tr("FlightGear/TerraSync Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); + MainWindow::instance()->showCriticalMessage(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); break; case QProcess::Timedout: - MainWindow::instance()->showCriticalMessage(tr("FlightGear/TerraSync Start Timed Out"), tr("Please check if the path and command is correct")); + MainWindow::instance()->showCriticalMessage(tr("FlightGear Start Timed Out"), tr("Please check if the path and command is correct")); break; case QProcess::WriteError: - MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear/TerraSync"), tr("Please check if the path and command is correct")); + MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); break; case QProcess::ReadError: - MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear/TerraSync"), tr("Please check if the path and command is correct")); + MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); break; case QProcess::UnknownError: default: - MainWindow::instance()->showCriticalMessage(tr("FlightGear/TerraSync Error"), tr("Please check if the path and command is correct.")); + MainWindow::instance()->showCriticalMessage(tr("FlightGear Error"), tr("Please check if the path and command is correct.")); break; } } @@ -633,12 +637,6 @@ bool QGCFlightGearLink::disconnectSimulation() delete process; process = NULL; } - if (terraSync) - { - terraSync->close(); - delete terraSync; - terraSync = NULL; - } if (socket) { socket->close(); @@ -653,6 +651,79 @@ bool QGCFlightGearLink::disconnectSimulation() return !connectState; } +/// @brief Splits a space seperated set of command line arguments into a QStringList. +/// Quoted strings are allowed and handled correctly. +/// @param uiArgs Arguments to parse +/// @param argList Returned argument list +/// @return Returns false if the argument list has mistmatced quotes within in. + +bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) +{ + + // This is not as easy as it seams since some options can be quoted to preserve spaces within things like + // directories. There is likely some crazed regular expression which can do this. But after trying that + // route I gave up and instead here is the code which does it the hard way. Another thing to be aware of + // is that the QStringList passed to QProces::start is similar to what you would get in argv after the + // command line is processed. This means that quoted strings have the quotes removed before making it to argv. + + bool inQuotedString = false; + bool previousSpace = false; + QString currentArg; + for (int i=0; ishowCriticalMessage(tr("FlightGear Failed to Start"), tr("Mismatched quotes in specified command line options")); + return false; + } + if (!currentArg.isEmpty()) { + argList += currentArg; + currentArg.clear(); + } + } + } + } else if (chr == '\"') { + // Flip the state of being in a quoted string. Note that we specifically do not add the + // quote to the string. This replicates standards command line parsing behaviour. + if (chr == '\"') { + inQuotedString = !inQuotedString; + } + previousSpace = false; + } else { + // Flip the state of being in a quoted string + if (chr == '\"') { + inQuotedString = !inQuotedString; + } + previousSpace = false; + currentArg += chr; + } + } + // We should never end parsing on an unterminated quote + if (inQuotedString) { + return false; + } + + // Finish up last arg + if (!currentArg.isEmpty()) { + argList += currentArg; + currentArg.clear(); + } + + return true; +} + /** * @brief Connect the connection. * diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h index 603286b93..3409d312c 100644 --- a/src/comm/QGCFlightGearLink.h +++ b/src/comm/QGCFlightGearLink.h @@ -87,6 +87,8 @@ public: void sensorHilEnabled(bool sensorHilEnabled) { _sensorHilEnabled = sensorHilEnabled; } + + static bool parseUIArguments(QString uiArgs, QStringList& argList); void run(); @@ -130,8 +132,6 @@ public slots: bool connectSimulation(); bool disconnectSimulation(); - void printTerraSyncOutput(); - void printTerraSyncError(); void printFgfsOutput(); void printFgfsError(); void setStartupArguments(QString startupArguments); @@ -147,19 +147,8 @@ protected: QUdpSocket* socket; bool connectState; - quint64 bitsSentTotal; - quint64 bitsSentCurrent; - quint64 bitsSentMax; - quint64 bitsReceivedTotal; - quint64 bitsReceivedCurrent; - quint64 bitsReceivedMax; - quint64 connectionStartTime; - QMutex statisticsMutex; - QMutex dataMutex; - QTimer refreshTimer; UASInterface* mav; QProcess* process; - QProcess* terraSync; unsigned int flightGearVersion; QString startupArguments; bool _sensorHilEnabled; diff --git a/src/qgcunittest/FlightGearTest.cc b/src/qgcunittest/FlightGearTest.cc new file mode 100644 index 000000000..28b970501 --- /dev/null +++ b/src/qgcunittest/FlightGearTest.cc @@ -0,0 +1,85 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "FlightGearTest.h" +#include "QGCFlightGearLink.h" + +/// @file +/// @brief FlightGearUnitTest HIL Simulation class +/// +/// @author Don Gagne + +FlightGearUnitTest::FlightGearUnitTest(void) +{ + +} + +// Called before every test +void FlightGearUnitTest::init(void) +{ + // Nothing here yet +} + +// Called after every test +void FlightGearUnitTest::cleanup(void) +{ + // Nothing here yet +} + +/// @brief The QGCFlightGearLink::parseUIArguments method is fairly involved so we have a unit +// test for it. +void FlightGearUnitTest::_parseUIArguments_test(void) +{ + typedef struct { + const char* args; + const char* expectedListAsChar; + bool expectedReturn; + } ParseUIArgumentsTestCase_t; + + static const ParseUIArgumentsTestCase_t rgTestCases[] = { + { "foo", "foo", true }, + { "foo bar", "foo|bar", true }, + { "--foo --bar", "--foo|--bar", true }, + { "foo=bar", "foo=bar", true }, + { "foo=bar bar=baz", "foo=bar|bar=baz", true }, + { "foo=\"bar\"", "foo=bar", true }, + { "foo=\"bar\" bar=\"baz\"", "foo=bar|bar=baz", true }, + { "foo=\"b ar\"", "foo=b ar", true }, + { "foo=\"b ar\" bar=\"b az\"", "foo=b ar|bar=b az", true }, + { "foo\"", NULL, false }, + }; + + for (size_t i=0; iargs, returnedArgList); + QCOMPARE(actualReturn, testCase->expectedReturn); + if (actualReturn) { + QStringList expectedArgList = QString(testCase->expectedListAsChar).split("|"); + if (returnedArgList != expectedArgList) { + qDebug() << "About to fail: Returned" << returnedArgList << "Expected" << expectedArgList; + } + QVERIFY(returnedArgList == expectedArgList); + } + } +} diff --git a/src/qgcunittest/FlightGearTest.h b/src/qgcunittest/FlightGearTest.h new file mode 100644 index 000000000..898006c69 --- /dev/null +++ b/src/qgcunittest/FlightGearTest.h @@ -0,0 +1,58 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef TCPLINKTEST_H +#define TCPLINKTEST_H + +#include +#include +#include + +#include "AutoTest.h" +#include "TCPLink.h" +#include "MultiSignalSpy.h" + +/// @file +/// @brief FlightGear HIL Simulation unit tests +/// +/// @author Don Gagne + +class FlightGearUnitTest : public QObject +{ + Q_OBJECT + +public: + FlightGearUnitTest(void); + +private slots: + void init(void); + void cleanup(void); + + void _parseUIArguments_test(void); + +private: +}; + +DECLARE_TEST(FlightGearUnitTest) + +#endif diff --git a/src/ui/QGCHilConfiguration.ui b/src/ui/QGCHilConfiguration.ui index 1db3ec1b6..8da9ad667 100644 --- a/src/ui/QGCHilConfiguration.ui +++ b/src/ui/QGCHilConfiguration.ui @@ -39,7 +39,7 @@ - Flightgear + FlightGear 3.0+ @@ -69,7 +69,7 @@ - No simulator active.. + diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index 67f4eb21d..f1c5efea3 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -1,51 +1,127 @@ #include "QGCHilFlightGearConfiguration.h" -#include "ui_QGCHilFlightGearConfiguration.h" #include "MainWindow.h" -QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav,QWidget *parent) : +// Various settings groups and keys +const char* QGCHilFlightGearConfiguration::_settingsGroup = "QGC_HILCONFIG_FLIGHTGEAR"; +const char* QGCHilFlightGearConfiguration::_mavSettingsSubGroupFixedWing = "FIXED_WING"; +const char* QGCHilFlightGearConfiguration::_mavSettingsSubGroupQuadRotor = "QUADROTOR"; +const char* QGCHilFlightGearConfiguration::_aircraftKey = "AIRCRAFT"; +const char* QGCHilFlightGearConfiguration::_optionsKey = "OPTIONS"; +const char* QGCHilFlightGearConfiguration::_barometerOffsetKey = "BARO_OFFSET"; +const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SENSOR_HIL"; + +// Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into +// the QGCFlightGearLink code instead. +const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync --atlas=socket,out,1,localhost,5505,udp"; + +QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav, QWidget *parent) : QWidget(parent), - mav(mav), - ui(new Ui::QGCHilFlightGearConfiguration) -{ - ui->setupUi(this); + _mav(mav), + _mavSettingsSubGroup(NULL), + _resetOptionsAction(tr("Reset to default options"), this) - QStringList items = QStringList(); - if (mav->getSystemType() == MAV_TYPE_FIXED_WING) +{ + Q_ASSERT(_mav); + + _ui.setupUi(this); + + QStringList items; + if (_mav->getSystemType() == MAV_TYPE_FIXED_WING) { items << "EasyStar"; items << "Rascal110-JSBSim"; items << "c172p"; items << "YardStik"; items << "Malolo1"; + _mavSettingsSubGroup = _mavSettingsSubGroupFixedWing; } - else if (mav->getSystemType() == MAV_TYPE_QUADROTOR) + else if (_mav->getSystemType() == MAV_TYPE_QUADROTOR) { items << "arducopter"; + _mavSettingsSubGroup = _mavSettingsSubGroupQuadRotor; } else { + // FIXME: Should disable all input, won't work. Show error message in the status label thing. items << ""; } - ui->aircraftComboBox->addItems(items); + _ui.aircraftComboBox->addItems(items); + + QSettings settings; + settings.beginGroup(_settingsGroup); + settings.beginGroup(_mavSettingsSubGroup); + QString aircraft = settings.value(_aircraftKey).toString(); + QString options = settings.value(_optionsKey).toString(); + QString baroOffset = settings.value(_barometerOffsetKey).toString(); + bool sensorHil = settings.value(_sensorHilKey, QVariant(true)).toBool(); + settings.endGroup(); + settings.endGroup(); + + if (!aircraft.isEmpty()) { + int index = _ui.aircraftComboBox->findText(aircraft); + if (index != -1) { + _ui.aircraftComboBox->setCurrentIndex(index); + } + } + if (options.isEmpty()) { + options = _defaultOptions; + } + _ui.optionsPlainTextEdit->setPlainText(options); + _ui.barometerOffsetLineEdit->setText(baroOffset); + _ui.sensorHilCheckBox->setChecked(sensorHil); + + // Provide an option on the context menu to reset the option back to default + _ui.optionsPlainTextEdit->setContextMenuPolicy(Qt::CustomContextMenu); + bool success = connect(&_resetOptionsAction, SIGNAL(triggered()), this, SLOT(_setDefaultOptions())); + Q_ASSERT(success); + success = connect(_ui.optionsPlainTextEdit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(_showContextMenu(const QPoint &))); + Q_ASSERT(success); } QGCHilFlightGearConfiguration::~QGCHilFlightGearConfiguration() { - delete ui; + QString aircraft = _ui.aircraftComboBox->currentText(); + QString options = _ui.optionsPlainTextEdit->toPlainText(); + QString baroOffset = _ui.barometerOffsetLineEdit->text(); + bool sensorHil = _ui.sensorHilCheckBox->isChecked(); + + QSettings settings; + settings.beginGroup(_settingsGroup); + settings.beginGroup(_mavSettingsSubGroup); + + if (aircraft.isEmpty()) { + settings.remove(_aircraftKey); + } else { + settings.setValue(_aircraftKey, aircraft); + } + + if (options.isEmpty() || options == _defaultOptions) { + settings.remove(_optionsKey); + } else { + settings.setValue(_optionsKey, options); + } + + // Double QVariant is to convert from string to float. It will change to 0.0 if invalid. + settings.setValue(_barometerOffsetKey, QVariant(QVariant(baroOffset).toFloat())); + + settings.setValue(_sensorHilKey, QVariant(sensorHil)); + + settings.endGroup(); + settings.endGroup(); } void QGCHilFlightGearConfiguration::on_startButton_clicked() { //XXX check validity of inputs - QString options = ui->optionsPlainTextEdit->toPlainText(); - options.append(" --aircraft=" + ui->aircraftComboBox->currentText()); - mav->enableHilFlightGear(true, options, ui->sensorHilCheckBox->isChecked(), this); + QString options = _ui.optionsPlainTextEdit->toPlainText(); + options.append(" --aircraft=" + _ui.aircraftComboBox->currentText()); + _mav->enableHilFlightGear(true, options, _ui.sensorHilCheckBox->isChecked(), this); } void QGCHilFlightGearConfiguration::on_stopButton_clicked() { - mav->stopHil(); + _mav->stopHil(); } void QGCHilFlightGearConfiguration::on_barometerOffsetLineEdit_textChanged(const QString& baroOffset) @@ -53,3 +129,16 @@ void QGCHilFlightGearConfiguration::on_barometerOffsetLineEdit_textChanged(const emit barometerOffsetChanged(baroOffset.toFloat()); } +void QGCHilFlightGearConfiguration::_showContextMenu(const QPoint &pt) +{ + QMenu* menu = _ui.optionsPlainTextEdit->createStandardContextMenu(); + menu->addAction(&_resetOptionsAction); + menu->exec(_ui.optionsPlainTextEdit->mapToGlobal(pt)); + delete menu; +} + +void QGCHilFlightGearConfiguration::_setDefaultOptions(void) +{ + _ui.optionsPlainTextEdit->setPlainText(_defaultOptions); +} + diff --git a/src/ui/QGCHilFlightGearConfiguration.h b/src/ui/QGCHilFlightGearConfiguration.h index 7e0e48901..0b72996c6 100644 --- a/src/ui/QGCHilFlightGearConfiguration.h +++ b/src/ui/QGCHilFlightGearConfiguration.h @@ -7,6 +7,8 @@ #include "QGCFlightGearLink.h" #include "UAS.h" +#include "ui_QGCHilFlightGearConfiguration.h" + namespace Ui { class QGCHilFlightGearConfiguration; } @@ -20,16 +22,33 @@ public: ~QGCHilFlightGearConfiguration(); protected: - UAS* mav; private slots: void on_startButton_clicked(); void on_stopButton_clicked(); void on_barometerOffsetLineEdit_textChanged(const QString& baroOffset); + void _setDefaultOptions(void); + void _showContextMenu(const QPoint& pt); private: - Ui::QGCHilFlightGearConfiguration *ui; + Ui::QGCHilFlightGearConfiguration _ui; + UAS* _mav; /// mav associated with this ui + + static const char* _settingsGroup; /// Top level settings group + const char* _mavSettingsSubGroup; /// We maintain a settings sub group per mav type + + static const char* _mavSettingsSubGroupFixedWing; /// Subgroup if mav type is MAV_TYPE_FIXED_WING + static const char* _mavSettingsSubGroupQuadRotor; /// Subgroup is mav type is MAV_TYPE_QUADROTOR + static const char* _aircraftKey; /// Settings key for aircraft selection + static const char* _optionsKey; /// Settings key for FlightGear cmd line options + static const char* _barometerOffsetKey; /// Settings key for barometer offset + static const char* _sensorHilKey; /// Settings key for Sensor Hil checkbox + + static const char* _defaultOptions; /// Default set of FlightGEar command line options + + QAction _resetOptionsAction; /// Context menu item to reset options to default + signals: void barometerOffsetChanged(float barometerOffsetkPa); }; diff --git a/src/ui/QGCHilFlightGearConfiguration.ui b/src/ui/QGCHilFlightGearConfiguration.ui index c91f992ac..96bb40fca 100644 --- a/src/ui/QGCHilFlightGearConfiguration.ui +++ b/src/ui/QGCHilFlightGearConfiguration.ui @@ -68,7 +68,7 @@ - --roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-models --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --prop:/engines/engine/running=true + -- GitLab From 0f90f07977c9da6e8ae84da823ae7d8a178f1cb9 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 12:51:31 -0700 Subject: [PATCH 02/57] commit --- qgroundcontrol.pro | 6 +- src/comm/QGCFlightGearLink.cc | 610 +++++++++++++++++++++------------- src/comm/QGCFlightGearLink.h | 9 +- 3 files changed, 394 insertions(+), 231 deletions(-) diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 6475dc52f..328653986 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -187,7 +187,8 @@ DebugBuild { src/qgcunittest/MockUAS.h \ src/qgcunittest/MockQGCUASParamManager.h \ src/qgcunittest/MultiSignalSpy.h \ - src/qgcunittest/FlightModeConfigTest.h + src/qgcunittest/FlightModeConfigTest.h \ + src/qgcunittest/FlightGearTest.h SOURCES += \ src/qgcunittest/UASUnitTest.cc \ @@ -195,7 +196,8 @@ DebugBuild { src/qgcunittest/MockUAS.cc \ src/qgcunittest/MockQGCUASParamManager.cc \ src/qgcunittest/MultiSignalSpy.cc \ - src/qgcunittest/FlightModeConfigTest.cc + src/qgcunittest/FlightModeConfigTest.cc \ + src/qgcunittest/FlightGearTest.cc } # diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index ac1539c92..b8198a5ee 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -73,226 +73,86 @@ QGCFlightGearLink::~QGCFlightGearLink() } } -/** - * @brief Runs the thread - * - **/ - +/// @brief Runs the simulation thread. We do setup work here which needs to happen in the seperate thread. void QGCFlightGearLink::run() { - qDebug() << "STARTING FLIGHTGEAR LINK"; - - if (!mav) return; + Q_ASSERT(mav); + Q_ASSERT(!_fgProcessName.isEmpty()); + + // We communicate with FlightGear over a UDP socket socket = new QUdpSocket(this); + Q_CHECK_PTR(socket); socket->moveToThread(this); - connectState = socket->bind(host, port); - + // FIXME: How do we deal with a failed bind. Signal? + socket->bind(host, port); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); - - process = new QProcess(this); - process->moveToThread(this); - terraSync = new QProcess(this); - terraSync->moveToThread(this); - - connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); - connect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); - connect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); - connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); - + + + // Connect to the various HIL signals that we use to then send information across the UDP protocol to FlightGear. + connect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), + this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); + connect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), + mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); + connect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), + mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); + connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), + mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); + + // FIXME: Does this need to be called from the new thread + + // FIXME: Why the need for dynamic cast. Missing virtual in interface? + // Wait until we know we can actually start FlightGear? UAS* uas = dynamic_cast(mav); if (uas) { uas->startHil(); } - - //connect(&refreshTimer, SIGNAL(timeout()), this, SLOT(sendUAVUpdate())); + + // Start a new process to run FlightGear in + process = new QProcess(this); + Q_CHECK_PTR(process); + process->moveToThread(this); + // Catch process error - QObject::connect( process, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(processError(QProcess::ProcessError))); - QObject::connect( terraSync, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(processError(QProcess::ProcessError))); - // Start Flightgear - QStringList flightGearArguments; - QString processFgfs; - QString processTerraSync; - QString fgRoot; - QString fgScenery; - QString terraSyncScenery; - QString fgAircraft; - -#ifdef Q_OS_MACX - processFgfs = "/Applications/FlightGear.app/Contents/Resources/fgfs"; - processTerraSync = "/Applications/FlightGear.app/Contents/Resources/terrasync"; - //fgRoot = "/Applications/FlightGear.app/Contents/Resources/data"; - fgScenery = "/Applications/FlightGear.app/Contents/Resources/data/Scenery"; - terraSyncScenery = "/Applications/FlightGear.app/Contents/Resources/data/Scenery-TerraSync"; - // /Applications/FlightGear.app/Contents/Resources/data/Scenery: + // FIXME: What happens if you quit FG from app side? Shouldn't that be the norm, instead of exiting process? + connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); +#ifdef DEBUG_FLIGHTGEAR_CONNECT + connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(printFgfsOutput())); + connect(process, SIGNAL(readyReadStandardError()), this, SLOT(printFgfsError())); #endif - -#ifdef Q_OS_WIN32 - processFgfs = "C:\\Program Files (x86)\\FlightGear\\bin\\Win32\\fgfs"; - //fgRoot = "C:\\Program Files (x86)\\FlightGear\\data"; - fgScenery = "C:\\Program Files (x86)\\FlightGear\\data\\Scenery"; - terraSyncScenery = "C:\\Program Files (x86)\\FlightGear\\data\\Scenery-Terrasync"; -#endif - -#ifdef Q_OS_LINUX - processFgfs = "fgfs"; - //fgRoot = "/usr/share/flightgear"; - QString fgScenery1 = "/usr/share/flightgear/data/Scenery"; - QString fgScenery2 = "/usr/share/games/flightgear/Scenery"; // Ubuntu default location - fgScenery = ""; //Flightgear can also start with fgScenery = "" - if (QDir(fgScenery1).exists()) - fgScenery = fgScenery1; - else if (QDir(fgScenery2).exists()) - fgScenery = fgScenery2; - - - processTerraSync = "nice"; //according to http://wiki.flightgear.org/TerraSync, run with lower priority - terraSyncScenery = QDir::homePath() + "/.terrasync/Scenery"; //according to http://wiki.flightgear.org/TerraSync a separate directory is used -#endif - - fgAircraft = QApplication::applicationDirPath() + "/files/flightgear/Aircraft"; - - // Sanity checks - bool sane = true; -// QFileInfo executable(processFgfs); -// if (!executable.isExecutable()) -// { -// MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("FlightGear was not found at %1").arg(processFgfs)); -// sane = false; -// } - -// QFileInfo root(fgRoot); -// if (!root.isDir()) -// { -// MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("FlightGear data directory was not found at %1").arg(fgRoot)); -// sane = false; -// } - -// QFileInfo scenery(fgScenery); -// if (!scenery.isDir()) -// { -// MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("FlightGear scenery directory was not found at %1").arg(fgScenery)); -// sane = false; -// } - -// QFileInfo terraSyncExecutableInfo(processTerraSync); -// if (!terraSyncExecutableInfo.isExecutable()) -// { -// MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("TerraSync was not found at %1").arg(processTerraSync)); -// sane = false; -// } - - - if (!sane) return; - - // --atlas=socket,out,1,localhost,5505,udp - // terrasync -p 5505 -S -d /usr/local/share/TerraSync - - /*Prepare FlightGear Arguments */ - //flightGearArguments << QString("--fg-root=%1").arg(fgRoot); - flightGearArguments << QString("--fg-scenery=%1:%2").arg(fgScenery).arg(terraSyncScenery); //according to http://wiki.flightgear.org/TerraSync a separate directory is used - flightGearArguments << QString("--fg-aircraft=%1").arg(fgAircraft); - if (mav->getSystemType() == MAV_TYPE_QUADROTOR) - { - flightGearArguments << QString("--generic=socket,out,50,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(port); - flightGearArguments << QString("--generic=socket,in,50,127.0.0.1,%1,udp,qgroundcontrol-quadrotor").arg(currentPort); - } - else - { - flightGearArguments << QString("--generic=socket,out,50,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(port); - flightGearArguments << QString("--generic=socket,in,50,127.0.0.1,%1,udp,qgroundcontrol-fixed-wing").arg(currentPort); - } - flightGearArguments << "--atlas=socket,out,1,localhost,5505,udp"; -// flightGearArguments << "--in-air"; -// flightGearArguments << "--roll=0"; -// flightGearArguments << "--pitch=0"; -// flightGearArguments << "--vc=90"; -// flightGearArguments << "--heading=300"; -// flightGearArguments << "--timeofday=noon"; -// flightGearArguments << "--disable-hud-3d"; -// flightGearArguments << "--disable-fullscreen"; -// flightGearArguments << "--geometry=400x300"; -// flightGearArguments << "--disable-anti-alias-hud"; -// flightGearArguments << "--wind=0@0"; -// flightGearArguments << "--turbulence=0.0"; -// flightGearArguments << "--prop:/sim/frame-rate-throttle-hz=30"; -// flightGearArguments << "--control=mouse"; -// flightGearArguments << "--disable-intro-music"; -// flightGearArguments << "--disable-sound"; -// flightGearArguments << "--disable-random-objects"; -// flightGearArguments << "--disable-ai-models"; -// flightGearArguments << "--shading-flat"; -// flightGearArguments << "--fog-disable"; -// flightGearArguments << "--disable-specular-highlight"; -// //flightGearArguments << "--disable-skyblend"; -// flightGearArguments << "--disable-random-objects"; -// flightGearArguments << "--disable-panel"; -// //flightGearArguments << "--disable-horizon-effect"; -// flightGearArguments << "--disable-clouds"; -// flightGearArguments << "--fdm=jsb"; -// flightGearArguments << "--units-meters"; //XXX: check: the protocol xml has already a conversion from feet to m? -// flightGearArguments << "--notrim"; - - flightGearArguments += startupArguments.split(" "); - if (mav->getSystemType() == MAV_TYPE_QUADROTOR) - { - // Start all engines of the quad - flightGearArguments << "--prop:/engines/engine[0]/running=true"; - flightGearArguments << "--prop:/engines/engine[1]/running=true"; - flightGearArguments << "--prop:/engines/engine[2]/running=true"; - flightGearArguments << "--prop:/engines/engine[3]/running=true"; - } - else - { - flightGearArguments << "--prop:/engines/engine/running=true"; + + if (!_fgProcessWorkingDirPath.isEmpty()) { + process->setWorkingDirectory(_fgProcessWorkingDirPath); + qDebug() << "Working directory" << process->workingDirectory(); } - flightGearArguments << QString("--lat=%1").arg(UASManager::instance()->getHomeLatitude()); - flightGearArguments << QString("--lon=%1").arg(UASManager::instance()->getHomeLongitude()); - //The altitude is not set because an altitude not equal to the ground altitude leads to a non-zero default throttle in flightgear - //Without the altitude-setting the aircraft is positioned on the ground - //flightGearArguments << QString("--altitude=%1").arg(UASManager::instance()->getHomeAltitude()); - - // Add new argument with this: flightGearArguments << ""; - //flightGearArguments << QString("--aircraft=%2").arg(aircraft); - - /*Prepare TerraSync Arguments */ - QStringList terraSyncArguments; -#ifdef Q_OS_LINUX - terraSyncArguments << "terrasync"; + +#ifdef Q_OS_WIN32 + // On Windows we need to full qualify the location of the excecutable. The call to setWorkingDirectory only + // sets the process context, not the QProcess::start context. For some strange reason this is not the case on + // OSX. + QDir fgProcessFullyQualified(_fgProcessWorkingDirPath); + _fgProcessName = fgProcessFullyQualified.absoluteFilePath(_fgProcessName); #endif - terraSyncArguments << "-p"; - terraSyncArguments << "5505"; - terraSyncArguments << "-S"; - terraSyncArguments << "-d"; - terraSyncArguments << terraSyncScenery; //according to http://wiki.flightgear.org/TerraSync a separate directory is used - -#ifdef Q_OS_LINUX - /* Setting environment */ - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - process->setProcessEnvironment(env); - terraSync->setProcessEnvironment(env); + + // FIXME: Need to clean up this debug arg list stuff + QStringList debugArgList; + debugArgList << "--log-level=debug"; + //debugArgList += "--fg-scenery=" + fgSceneryPath + ""; + //debugArgList += "--fg-root=" + fgRootPath + ""; + + debugArgList += "--fg-root=\"c:\\Flight Gear\\data\""; + debugArgList += "--fg-scenery=\"c:\\Flight Gear\\data\\Scenery;c:\\Flight Gear\\scenery;C:\\Flight Gear\\terrasync\""; +#ifdef DEBUG_FLIGHTGEAR_CONNECT + qDebug() << "Starting FlightGear" << _fgProcessWorkingDirPath << _fgProcessName << _fgArgList; + qDebug() << "Debug args" << debugArgList; #endif -// connect (terraSync, SIGNAL(readyReadStandardOutput()), this, SLOT(printTerraSyncOutput())); -// connect (terraSync, SIGNAL(readyReadStandardError()), this, SLOT(printTerraSyncError())); - terraSync->start(processTerraSync, terraSyncArguments); -// qDebug() << "STARTING: " << processTerraSync << terraSyncArguments; - - process->start(processFgfs, flightGearArguments); -// connect (process, SIGNAL(readyReadStandardOutput()), this, SLOT(printFgfsOutput())); -// connect (process, SIGNAL(readyReadStandardError()), this, SLOT(printFgfsError())); - - - + + process->start(_fgProcessName, /*debugArgList*/ _fgArgList); + emit simulationConnected(connectState); if (connectState) { emit simulationConnected(); - connectionStartTime = QGC::groundTimeUsecs()/1000; } - qDebug() << "STARTING SIM"; - -// qDebug() << "STARTING: " << processFgfs << flightGearArguments; exec(); } @@ -731,34 +591,334 @@ bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) **/ bool QGCFlightGearLink::connectSimulation() { - + // We setup all the information we need to start FlightGear here such that if something goes + // wrong we can return false out of here. All of this happens on the main UI thread. Once we + // have that information setup we start the thread which will call run, which will in turn + // start the various FG processes on the seperate thread. + + // FixMe: Does returning false out of here leave in inconsistent state? + + qDebug() << "STARTING FLIGHTGEAR LINK"; + + // FIXME: !mav is failure isn't it? + if (!mav) { + return false; + } + + // FIXME: Pull previous information from settings + + QString fgAppName; + QString fgRootPath; // FlightGear root data directory as specified by --fg-root + bool fgRootDirOverride = false; // true: User has specified --fg-root from ui options + QString fgSceneryPath; // FlightGear scenery path as specified by --fg-scenery + bool fgSceneryDirOverride = false; // true: User has specified --fg-scenery from ui options + QDir fgAppDir; // Location of main FlightGear application + +#if defined Q_OS_MACX + // Mac installs will default to the /Applications folder 99% of the time. Anything other than + // that is pretty non-standard so we don't try to get fancy beyond hardcoding that path. + fgAppDir.setPath("/Applications"); + fgAppName = "FlightGear.app"; + _fgProcessName = "./fgfs.sh"; + _fgProcessWorkingDirPath = "/Applications/FlightGear.app/Contents/Resources/"; + fgRootPath = "/Applications/FlightGear.app/Contents/Resources/data/"; +#elif defined Q_OS_WIN32 + fgProcessName = "fgfs.exe"; + //fgProcessWorkingDir = "C:\\Program Files (x86)\\FlightGear\\bin\\Win32"; + + // Windows installs are not as easy to determine. Default installation is to + // C:\Program Files\FlightGear, but that can be easily changed. That also doesn't + // tell us whether the user is running 32 or 64 bit which will both be installed there. + // The preferences for the fgrun app will tell us which version they are using + // and where it is. That is stored in the $APPDATA\fliggear.org\fgrun.prefs file. This + // looks to be a more stable location and way to determine app location so we use that. + fgAppName = "fgfs.exe"; + const char* appdataEnv = "APPDATA"; + if (!qgetenv(appdataEnv).isEmpty()) { + QString fgrunPrefsFile = QDir(qgetenv(appdataEnv).constData()).absoluteFilePath("flightgear.org/fgrun.prefs"); + qDebug() << fgrunPrefsFile; + QFile file(fgrunPrefsFile); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + QString lookahead; // lookahead for continuation lines + while (!in.atEnd() || !lookahead.isEmpty()) { + QString line; + QRegExp regExp; + + // Prefs file has strange format where a line prepended with "+" is a continuation of the previous line. + // So do a lookahead to determine if we have a continuation or not. + + if (!lookahead.isEmpty()) { + line = lookahead; + lookahead.clear(); + } else { + line = in.readLine(); + } + + if (!in.atEnd()) { + lookahead = in.readLine(); + regExp.setPattern("^\\+(.*)"); + if (regExp.indexIn(lookahead) == 0) { + Q_ASSERT(regExp.captureCount() == 1); + line += regExp.cap(1); + lookahead.clear(); + } + } + + regExp.setPattern("^fg_exe:(.*)"); + if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { + QString fgExeLocationFullQualified = regExp.cap(1); + qDebug() << fgExeLocationFullQualified; + regExp.setPattern("(.*)\\\\fgfs.exe"); + if (regExp.indexIn(fgExeLocationFullQualified) == 0 && regExp.captureCount() == 1) { + fgAppDir.setPath(regExp.cap(1)); + fgProcessWorkingDirPath = fgAppDir.absolutePath(); + qDebug() << "fg_exe" << fgAppDir.absolutePath(); + } + continue; + } + + regExp.setPattern("^fg_root:(.*)"); + if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { + fgRootPath = QDir(regExp.cap(1)).absolutePath(); + qDebug() << "fg_root" << fgRootPath; + continue; + } + + regExp.setPattern("^fg_scenery:(.*)"); + if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { + // Scenery can contain multiple paths seperated by ';' so don't do QDir::absolutePath on it + fgSceneryPath = regExp.cap(1); + qDebug() << "fg_scenery" << fgSceneryPath; + continue; + } + } + } + } +#elif defined Q_OS_LINUX + // Linux installs to a location on the path so we don't need a directory to run the executable + fgAppName = "fgfs"; + fgProcessName = "fgfs"; + fgRootPath = "/usr/share/games/flightgear/"; // Default Ubuntu location as best guess +#else +#error Unknown OS build flavor +#endif + + // Validate the FlightGear application directory location. Linux runs from path so we don't validate on that OS. +#ifndef Q_OS_LINUX + Q_ASSERT(!fgAppName.isEmpty()); + QString fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); + while (!QFileInfo(fgAppFullyQualified).exists()) { + QMessageBox msgBox(QMessageBox::Critical, + tr("FlightGear application not found"), + tr("FlightGear application not found at: %1").arg(fgAppFullyQualified), + QMessageBox::Cancel, + MainWindow::instance()); + msgBox.setWindowModality(Qt::ApplicationModal); + msgBox.addButton(tr("I'll specify directory"), QMessageBox::ActionRole); + if (msgBox.exec() == QMessageBox::Cancel) { + return false; + } + + // Let the user pick the right directory + fgAppDir.setPath(QFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName)); + fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); + } +#endif + + // Split the space seperated command line arguments coming in from the ui into a QStringList since + // that is what QProcess::start needs. + QStringList uiArgList; + bool mismatchedQuotes = parseUIArguments(startupArguments, uiArgList); + if (!mismatchedQuotes) { + MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("Mismatched quotes in specified command line options")); + return false; + } + + // Add the user specified arguments to our argument list +#ifdef DEBUG_FLIGHTGEAR_CONNECT + qDebug() << "Split arguments" << uiArgList; +#endif + _fgArgList += uiArgList; + + // Add --fg-root command line arg. If --fg-root is specified from the ui we use that instead. + // We need to know what --fg-root is set to because we are going to use it to validate + // communication protocols. + if (startupArguments.contains("--fg-root=", Qt::CaseInsensitive)) { + // FIXME: Won't handle missing quotes + const char* regExpStr = "--fg-root=(.*)"; + int index = _fgArgList.indexOf(QRegExp(regExpStr, Qt::CaseInsensitive)); + Q_ASSERT(index != -1); + QString rootArg(_fgArgList[index]); + QRegExp regExp(regExpStr); + index = regExp.indexIn(rootArg); + Q_ASSERT(index != -1); + fgRootPath = regExp.cap(1); + qDebug() << "--fg-root override" << fgRootPath; + fgRootDirOverride = true; + } else { + _fgArgList += "--fg-root=" + fgRootPath; + } + + // Add --fg-scenery command line arg. If --fg-scenery is specified from the ui we use that instead. + // On Windows --fg-scenery is required on the command line otherwise FlightGear won't boot. + // FIXME: Use single routine for both overrides + if (startupArguments.contains("--fg-scenery=", Qt::CaseInsensitive)) { + // FIXME: Won't handle missing quotes + const char* regExpStr = "--fg-scenery=(.*)"; + int index = _fgArgList.indexOf(QRegExp(regExpStr, Qt::CaseInsensitive)); + Q_ASSERT(index != -1); + QString rootArg(_fgArgList[index]); + QRegExp regExp(regExpStr); + index = regExp.indexIn(rootArg); + Q_ASSERT(index != -1); + Q_ASSERT(regExp.captureCount() == 1); + fgSceneryPath = regExp.cap(1); + qDebug() << "--fg-scenery override" << fgSceneryPath; + fgSceneryDirOverride = true; + } else if (!fgSceneryPath.isEmpty()) { + _fgArgList += "--fg-scenery=" + fgSceneryPath; + } + +#ifdef Q_OS_WIN32 + // Windows won't start without an --fg-scenery set. We don't validate the directory in the path since + // it can be multiple paths. + if (fgSceneryPath.isEmpty()) { + QString errMsg; + if (fgSceneryDirOverride) { + errMsg = tr("--fg-scenery directory specified from ui option not found: %1").arg(fgSceneryPath); + } else { + errMsg = tr("Unable to automatically determine --fg-scenery directory location. You will need to specify --fg-scenery=directory as an additional command line parameter from ui."); + } + MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), errMsg); + return false; + } +#endif + + // Check that we have a good fgRootDir set before we use it to check communication protocol files. + if (fgRootPath.isEmpty() || !QFileInfo(fgRootPath).isDir()) { + QString errMsg; + if (fgRootDirOverride) { + errMsg = tr("--fg-root directory specified from ui option not found: %1").arg(fgRootPath); + } else if (fgRootPath.isEmpty()) { + errMsg = tr("Unable to automatically determine --fg-root directory location. You will need to specify --fg-root= as an additional command line parameter from ui."); + } else { + errMsg = tr("Unable to automatically determine --fg-root directory location. Attempted directory '%1', which does not exist. You will need to specify --fg-root= as an additional command line parameter from ui.").arg(fgRootPath); + } + MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), errMsg); + return false; + } + + // Setup and verify directory which contains QGC provided aircraft files + QString qgcAircraftDir(QApplication::applicationDirPath() + "/files/flightgear/Aircraft"); + if (!QFileInfo(qgcAircraftDir).isDir()) { + MainWindow::instance()->showCriticalMessage(tr("Incorrect QGroundControl installation"), tr("Aircraft directory is missing: '%1'.").arg(qgcAircraftDir)); + return false; + } + _fgArgList += "--fg-aircraft=" + qgcAircraftDir; + + // Setup protocol we will be using to communicate with FlightGear + QString fgProtocol(mav->getSystemType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); + QString fgProtocolArg("--generic=socket,%1,50,127.0.0.1,%2,udp,%3"); + _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); + _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); + + // Verify directory where FlightGear stores communicaton protocols. + QDir fgProtocolDir(fgRootPath); + if (!fgProtocolDir.cd("Protocol")) { + MainWindow::instance()->showCriticalMessage(tr("Incorrect FlightGear setup"), tr("Protocol directory is missing: '%1'. Command line parameter for --fg-root may be set incorrectly.").arg(fgProtocolDir.path())); + return false; + } + + // Verify directory which contains QGC provided FlightGear communication protocol files + QDir qgcProtocolDir(QApplication::applicationDirPath() + "/files/flightgear/Protocol/"); + if (!qgcProtocolDir.isReadable()) { + MainWindow::instance()->showCriticalMessage(tr("Incorrect QGroundControl installation"), tr("Protocol directory is missing (%1).").arg(qgcProtocolDir.path())); + return false; + } + + // Communication protocol must be in FlightGear protocol directory. There does not appear to be any way + // around this by specifying something on the FlightGear command line. FG code does direct append + // of protocol xml file to $FG_ROOT and $FG_ROOT only allows a single directory to be specified. + QString fgProtocolXmlFile = fgProtocol + ".xml"; + QString fgProtocolFileFullyQualified = fgProtocolDir.absoluteFilePath(fgProtocolXmlFile); + if (!QFileInfo(fgProtocolFileFullyQualified).exists()) { + QMessageBox msgBox(QMessageBox::Critical, + tr("FlightGear Failed to Start"), + tr("FlightGear Failed to Start. QGroundControl protocol (%1) not installed to FlightGear Protocol directory (%2)").arg(fgProtocolXmlFile).arg(fgProtocolDir.path()), + QMessageBox::Cancel, + MainWindow::instance()); + msgBox.setWindowModality(Qt::ApplicationModal); + msgBox.addButton(tr("Fix it for me"), QMessageBox::ActionRole); + if (msgBox.exec() == QMessageBox::Cancel) { + return false; + } + + // Make sure we can find the communication protocol file in QGC install before we attempt to copy to FlightGear + QString qgcProtocolFileFullyQualified = qgcProtocolDir.absoluteFilePath(fgProtocolXmlFile); + if (!QFileInfo(qgcProtocolFileFullyQualified).exists()) { + MainWindow::instance()->showCriticalMessage(tr("Incorrect QGroundControl installation"), tr("FlightGear protocol file missing: %1").arg(qgcProtocolFileFullyQualified)); + return false; + } + + // Now that we made it this far, we should be able to try to copy the protocol file to FlightGear. + bool succeeded = QFile::copy(qgcProtocolFileFullyQualified, fgProtocolFileFullyQualified); + if (!succeeded) { + MainWindow::instance()->showCriticalMessage(tr("Copy failed"), tr("Copy from (%1) to (%2) failed, possibly due to permissions issue. You will need to perform manually.").arg(qgcProtocolFileFullyQualified).arg(fgProtocolFileFullyQualified)); + +#ifdef Q_OS_WIN32 + QString copyCmd = QString("copy \"%1\" \"%2\"").arg(qgcProtocolFileFullyQualified).arg(fgProtocolFileFullyQualified); + copyCmd.replace("/", "\\"); +#else + QString copyCmd = QString("sudo cp %1 %2").arg(qgcProtocolFileFullyQualified).arg(fgProtocolFileFullyQualified); +#endif + + QMessageBox msgBox(QMessageBox::Critical, + tr("Copy failed"), +#ifdef Q_OS_WIN32 + tr("Try pasting the following command into a Command Prompt which was started with Run as Administrator: ") + copyCmd, +#else + tr("Try pasting the following command into a shell: ") + copyCmd, +#endif + QMessageBox::Cancel, + MainWindow::instance()); + msgBox.setWindowModality(Qt::ApplicationModal); + msgBox.addButton(tr("Copy to Clipboard"), QMessageBox::ActionRole); + if (msgBox.exec() != QMessageBox::Cancel) { + QApplication::clipboard()->setText(copyCmd); + } + return false; + } + } + + // Start the engines to save a startup step + if (mav->getSystemType() == MAV_TYPE_QUADROTOR) { + // Start all engines of the quad + _fgArgList << "--prop:/engines/engine[0]/running=true"; + _fgArgList << "--prop:/engines/engine[1]/running=true"; + _fgArgList << "--prop:/engines/engine[2]/running=true"; + _fgArgList << "--prop:/engines/engine[3]/running=true"; + } else { + _fgArgList << "--prop:/engines/engine/running=true"; + } + + // We start out at our home position + _fgArgList << QString("--lat=%1").arg(UASManager::instance()->getHomeLatitude()); + _fgArgList << QString("--lon=%1").arg(UASManager::instance()->getHomeLongitude()); + // The altitude is not set because an altitude not equal to the ground altitude leads to a non-zero default throttle in flightgear + // Without the altitude-setting the aircraft is positioned on the ground + //_fgArgList << QString("--altitude=%1").arg(UASManager::instance()->getHomeAltitude()); + +#ifdef DEBUG_FLIGHTGEAR_CONNECT + // This tell FlightGear to output highest debug level of log output. Handy for debuggin failures by looking at the FG + // log files. + _fgArgList << "--log-level=debug"; +#endif + start(HighPriority); return true; } -void QGCFlightGearLink::printTerraSyncOutput() -{ - qDebug() << "TerraSync stdout:"; - QByteArray byteArray = terraSync->readAllStandardOutput(); - QStringList strLines = QString(byteArray).split("\n"); - - foreach (QString line, strLines){ - qDebug() << line; - } -} - -void QGCFlightGearLink::printTerraSyncError() -{ - qDebug() << "TerraSync stderr:"; - - QByteArray byteArray = terraSync->readAllStandardError(); - QStringList strLines = QString(byteArray).split("\n"); - - foreach (QString line, strLines){ - qDebug() << line; - } -} - void QGCFlightGearLink::printFgfsOutput() { qDebug() << "fgfs stdout:"; diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h index 3409d312c..6f16a2f5d 100644 --- a/src/comm/QGCFlightGearLink.h +++ b/src/comm/QGCFlightGearLink.h @@ -155,10 +155,11 @@ protected: float barometerOffsetkPa; void setName(QString name); - -signals: - - + +private: + QString _fgProcessName; ///< FlightGear process to start + QString _fgProcessWorkingDirPath; ///< Working directory to start FG process in, empty for none + QStringList _fgArgList; ///< Arguments passed to FlightGear process }; #endif // QGCFLIGHTGEARLINK_H -- GitLab From fbfb093177d98c9f1f20411b5e41117bc70b1342 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 13:07:45 -0700 Subject: [PATCH 03/57] commit --- src/comm/QGCFlightGearLink.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index b8198a5ee..48cc01922 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -623,7 +623,7 @@ bool QGCFlightGearLink::connectSimulation() _fgProcessWorkingDirPath = "/Applications/FlightGear.app/Contents/Resources/"; fgRootPath = "/Applications/FlightGear.app/Contents/Resources/data/"; #elif defined Q_OS_WIN32 - fgProcessName = "fgfs.exe"; + _fgProcessName = "fgfs.exe"; //fgProcessWorkingDir = "C:\\Program Files (x86)\\FlightGear\\bin\\Win32"; // Windows installs are not as easy to determine. Default installation is to @@ -672,7 +672,7 @@ bool QGCFlightGearLink::connectSimulation() regExp.setPattern("(.*)\\\\fgfs.exe"); if (regExp.indexIn(fgExeLocationFullQualified) == 0 && regExp.captureCount() == 1) { fgAppDir.setPath(regExp.cap(1)); - fgProcessWorkingDirPath = fgAppDir.absolutePath(); + _fgProcessWorkingDirPath = fgAppDir.absolutePath(); qDebug() << "fg_exe" << fgAppDir.absolutePath(); } continue; -- GitLab From 07e1d07a07b067eb6c50f4b39f871253455dac6b Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 17:00:49 -0700 Subject: [PATCH 04/57] commit --- src/comm/QGCFlightGearLink.cc | 27 +++++++++---------------- src/ui/QGCHilFlightGearConfiguration.cc | 2 +- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 48cc01922..640cc5bdd 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -98,16 +98,6 @@ void QGCFlightGearLink::run() connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); - // FIXME: Does this need to be called from the new thread - - // FIXME: Why the need for dynamic cast. Missing virtual in interface? - // Wait until we know we can actually start FlightGear? - UAS* uas = dynamic_cast(mav); - if (uas) - { - uas->startHil(); - } - // Start a new process to run FlightGear in process = new QProcess(this); Q_CHECK_PTR(process); @@ -148,11 +138,10 @@ void QGCFlightGearLink::run() #endif process->start(_fgProcessName, /*debugArgList*/ _fgArgList); + connectState = true; emit simulationConnected(connectState); - if (connectState) { - emit simulationConnected(); - } + emit simulationConnected(); exec(); } @@ -257,13 +246,13 @@ void QGCFlightGearLink::updateControls(quint64 time, float rollAilerons, float p QString state("%1\t%2\t%3\t%4\t%5\n"); state = state.arg(rollAilerons).arg(pitchElevator).arg(yawRudder).arg(true).arg(throttle); writeBytes(state.toAscii().constData(), state.length()); -// qDebug() << "updated controls" << rollAilerons << pitchElevator << yawRudder << throttle; + //qDebug() << "Updated controls" << rollAilerons << pitchElevator << yawRudder << throttle; + //qDebug() << "Updated controls" << state; } else { qDebug() << "HIL: Got NaN values from the hardware: isnan output: roll: " << isnan(rollAilerons) << ", pitch: " << isnan(pitchElevator) << ", yaw: " << isnan(yawRudder) << ", throttle: " << isnan(throttle); } - //qDebug() << "Updated controls" << state; } void QGCFlightGearLink::writeBytes(const char* data, qint64 size) @@ -313,7 +302,7 @@ void QGCFlightGearLink::readBytes() // Print string QString state(b); -// qDebug() << "FG LINK GOT:" << state; + //qDebug() << "FG LINK GOT:" << state; QStringList values = state.split("\t"); @@ -508,6 +497,10 @@ bool QGCFlightGearLink::disconnectSimulation() emit simulationDisconnected(); emit simulationConnected(false); + + // Exit the thread + quit(); + return !connectState; } @@ -819,7 +812,7 @@ bool QGCFlightGearLink::connectSimulation() // Setup protocol we will be using to communicate with FlightGear QString fgProtocol(mav->getSystemType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); - QString fgProtocolArg("--generic=socket,%1,50,127.0.0.1,%2,udp,%3"); + QString fgProtocolArg("--generic=socket,%1,300,127.0.0.1,%2,udp,%3"); _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index f1c5efea3..44630ff6c 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -13,7 +13,7 @@ const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SEN // Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into // the QGCFlightGearLink code instead. -const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync --atlas=socket,out,1,localhost,5505,udp"; +const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav, QWidget *parent) : QWidget(parent), -- GitLab From bac63010ea487c2c50b363ab1004213a520ade93 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 17:13:45 -0700 Subject: [PATCH 05/57] commit --- src/comm/QGCFlightGearLink.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 640cc5bdd..e48c1d143 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -691,7 +691,7 @@ bool QGCFlightGearLink::connectSimulation() #elif defined Q_OS_LINUX // Linux installs to a location on the path so we don't need a directory to run the executable fgAppName = "fgfs"; - fgProcessName = "fgfs"; + _fgProcessName = "fgfs"; fgRootPath = "/usr/share/games/flightgear/"; // Default Ubuntu location as best guess #else #error Unknown OS build flavor @@ -786,6 +786,8 @@ bool QGCFlightGearLink::connectSimulation() MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), errMsg); return false; } +#else + Q_UNUSED(fgSceneryDirOverride); #endif // Check that we have a good fgRootDir set before we use it to check communication protocol files. -- GitLab From c8e57f74563033d018123b67b69eb62129552dd0 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 18:37:43 -0700 Subject: [PATCH 06/57] commit --- src/comm/QGCFlightGearLink.cc | 15 +++++++++------ src/comm/QGCFlightGearLink.h | 3 +++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index e48c1d143..198cf8dea 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -63,6 +63,9 @@ QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments this->mav = mav; this->name = tr("FlightGear 3.0+ Link (port:%1)").arg(port); setRemoteHost(remoteHost); + + // We need a mechanism so show error message from our FGLink thread on the UI thread. This signal connection will do that for us. + connect(this, SIGNAL(showCriticalMessageFromThread(const QString&, const QString&)), MainWindow::instance(), SLOT(showCriticalMessage(const QString&, const QString&))); } QGCFlightGearLink::~QGCFlightGearLink() @@ -158,23 +161,23 @@ void QGCFlightGearLink::processError(QProcess::ProcessError err) switch(err) { case QProcess::FailedToStart: - MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("Please check if the path and command is correct")); + emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), tr("Please check if the path and command is correct")); break; case QProcess::Crashed: - MainWindow::instance()->showCriticalMessage(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); + emit showCriticalMessageFromThread(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); break; case QProcess::Timedout: - MainWindow::instance()->showCriticalMessage(tr("FlightGear Start Timed Out"), tr("Please check if the path and command is correct")); + emit showCriticalMessageFromThread(tr("FlightGear Start Timed Out"), tr("Please check if the path and command is correct")); break; case QProcess::WriteError: - MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); + emit showCriticalMessageFromThread(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); break; case QProcess::ReadError: - MainWindow::instance()->showCriticalMessage(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); + emit showCriticalMessageFromThread(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); break; case QProcess::UnknownError: default: - MainWindow::instance()->showCriticalMessage(tr("FlightGear Error"), tr("Please check if the path and command is correct.")); + emit showCriticalMessageFromThread(tr("FlightGear Error"), tr("Please check if the path and command is correct.")); break; } } diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h index 6f16a2f5d..02dc11b94 100644 --- a/src/comm/QGCFlightGearLink.h +++ b/src/comm/QGCFlightGearLink.h @@ -91,6 +91,9 @@ public: static bool parseUIArguments(QString uiArgs, QStringList& argList); void run(); + +signals: + void showCriticalMessageFromThread(const QString& title, const QString& message); public slots: // void setAddress(QString address); -- GitLab From 976747b083d03b4da7cb47cb968c6251946778f0 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 18:52:36 -0700 Subject: [PATCH 07/57] commit --- src/comm/QGCFlightGearLink.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 198cf8dea..715648e22 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -127,20 +127,11 @@ void QGCFlightGearLink::run() _fgProcessName = fgProcessFullyQualified.absoluteFilePath(_fgProcessName); #endif - // FIXME: Need to clean up this debug arg list stuff - QStringList debugArgList; - debugArgList << "--log-level=debug"; - //debugArgList += "--fg-scenery=" + fgSceneryPath + ""; - //debugArgList += "--fg-root=" + fgRootPath + ""; - - debugArgList += "--fg-root=\"c:\\Flight Gear\\data\""; - debugArgList += "--fg-scenery=\"c:\\Flight Gear\\data\\Scenery;c:\\Flight Gear\\scenery;C:\\Flight Gear\\terrasync\""; #ifdef DEBUG_FLIGHTGEAR_CONNECT qDebug() << "Starting FlightGear" << _fgProcessWorkingDirPath << _fgProcessName << _fgArgList; - qDebug() << "Debug args" << debugArgList; #endif - process->start(_fgProcessName, /*debugArgList*/ _fgArgList); + process->start(_fgProcessName, _fgArgList); connectState = true; emit simulationConnected(connectState); -- GitLab From 60f3d724ac253913c6c65bc33412cd84d7be7319 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 20:23:43 -0700 Subject: [PATCH 08/57] commit --- src/comm/QGCFlightGearLink.cc | 6 +++--- src/ui/QGCHilFlightGearConfiguration.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 715648e22..15066acb5 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -42,7 +42,7 @@ This file is part of the QGROUNDCONTROL project // FlightGear process start and connection is quite fragile. Uncomment the define below to get higher level of debug output // for tracking down problems. -#define DEBUG_FLIGHTGEAR_CONNECT +//#define DEBUG_FLIGHTGEAR_CONNECT QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments, QString remoteHost, QHostAddress host, quint16 port) : socket(NULL), @@ -152,7 +152,7 @@ void QGCFlightGearLink::processError(QProcess::ProcessError err) switch(err) { case QProcess::FailedToStart: - emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), tr("Please check if the path and command is correct")); + emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), process->errorString()); break; case QProcess::Crashed: emit showCriticalMessageFromThread(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); @@ -808,7 +808,7 @@ bool QGCFlightGearLink::connectSimulation() // Setup protocol we will be using to communicate with FlightGear QString fgProtocol(mav->getSystemType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); - QString fgProtocolArg("--generic=socket,%1,300,127.0.0.1,%2,udp,%3"); + QString fgProtocolArg("--generic=socket,%1,50,127.0.0.1,%2,udp,%3"); _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index 44630ff6c..732a794e0 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -13,7 +13,7 @@ const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SEN // Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into // the QGCFlightGearLink code instead. -const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; +const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav, QWidget *parent) : QWidget(parent), -- GitLab From bbffbb828aa185c4fe8b15b1dc8e862b80ab31b8 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 21:33:04 -0700 Subject: [PATCH 09/57] commit --- src/ui/QGCHilFlightGearConfiguration.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index 732a794e0..8106c8be8 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -13,7 +13,7 @@ const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SEN // Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into // the QGCFlightGearLink code instead. -const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; +const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav, QWidget *parent) : QWidget(parent), -- GitLab From 1378b1b094e28d100e13951a41cc403dae5ca855 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 29 May 2014 22:18:37 -0700 Subject: [PATCH 10/57] Thomas changes --- src/comm/QGCFlightGearLink.cc | 2 +- src/ui/QGCHilFlightGearConfiguration.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 15066acb5..52e240f0c 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -808,7 +808,7 @@ bool QGCFlightGearLink::connectSimulation() // Setup protocol we will be using to communicate with FlightGear QString fgProtocol(mav->getSystemType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); - QString fgProtocolArg("--generic=socket,%1,50,127.0.0.1,%2,udp,%3"); + QString fgProtocolArg("--generic=socket,%1,300,127.0.0.1,%2,udp,%3"); _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index 8106c8be8..0488fbbd0 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -13,7 +13,7 @@ const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SEN // Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into // the QGCFlightGearLink code instead. -const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; +const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --control=mouse --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(UAS* mav, QWidget *parent) : QWidget(parent), -- GitLab From c8c3290ed6c7e61c367a8a7c32683a0d3e0292a2 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Wed, 4 Jun 2014 20:47:40 -0700 Subject: [PATCH 11/57] commit --- src/comm/QGCFlightGearLink.cc | 237 ++++++++++++++++++---------------- src/comm/QGCFlightGearLink.h | 19 +-- 2 files changed, 134 insertions(+), 122 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 52e240f0c..04cefb63a 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -40,17 +40,17 @@ This file is part of the QGROUNDCONTROL project #include #include "MainWindow.h" -// FlightGear process start and connection is quite fragile. Uncomment the define below to get higher level of debug output +// FlightGear _fgProcess start and connection is quite fragile. Uncomment the define below to get higher level of debug output // for tracking down problems. //#define DEBUG_FLIGHTGEAR_CONNECT QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments, QString remoteHost, QHostAddress host, quint16 port) : - socket(NULL), - process(NULL), flightGearVersion(3), startupArguments(startupArguments), _sensorHilEnabled(true), - barometerOffsetkPa(0.0f) + barometerOffsetkPa(0.0f), + _udpCommSocket(NULL), + _fgProcess(NULL) { // We're doing it wrong - because the Qt folks got the API wrong: // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ @@ -70,7 +70,7 @@ QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments QGCFlightGearLink::~QGCFlightGearLink() { //do not disconnect unless it is connected. - //disconnectSimulation will delete the memory that was allocated for proces, terraSync and socket + //disconnectSimulation will delete the memory that was allocated for proces, terraSync and _udpCommSocket if(connectState){ disconnectSimulation(); } @@ -82,13 +82,12 @@ void QGCFlightGearLink::run() Q_ASSERT(mav); Q_ASSERT(!_fgProcessName.isEmpty()); - // We communicate with FlightGear over a UDP socket - socket = new QUdpSocket(this); - Q_CHECK_PTR(socket); - socket->moveToThread(this); - // FIXME: How do we deal with a failed bind. Signal? - socket->bind(host, port); - QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); + // We communicate with FlightGear over a UDP _udpCommSocket + _udpCommSocket = new QUdpSocket(this); + Q_CHECK_PTR(_udpCommSocket); + _udpCommSocket->moveToThread(this); + _udpCommSocket->bind(host, port); + QObject::connect(_udpCommSocket, SIGNAL(readyRead()), this, SLOT(readBytes())); // Connect to the various HIL signals that we use to then send information across the UDP protocol to FlightGear. @@ -101,27 +100,25 @@ void QGCFlightGearLink::run() connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); - // Start a new process to run FlightGear in - process = new QProcess(this); - Q_CHECK_PTR(process); - process->moveToThread(this); + // Start a new QProcess to run FlightGear in + _fgProcess = new QProcess(this); + Q_CHECK_PTR(_fgProcess); + _fgProcess->moveToThread(this); - // Catch process error - // FIXME: What happens if you quit FG from app side? Shouldn't that be the norm, instead of exiting process? - connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); + connect(_fgProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #ifdef DEBUG_FLIGHTGEAR_CONNECT - connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(printFgfsOutput())); - connect(process, SIGNAL(readyReadStandardError()), this, SLOT(printFgfsError())); + connect(_fgProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(_printFgfsOutput())); + connect(_fgProcess, SIGNAL(readyReadStandardError()), this, SLOT(_printFgfsError())); #endif if (!_fgProcessWorkingDirPath.isEmpty()) { - process->setWorkingDirectory(_fgProcessWorkingDirPath); - qDebug() << "Working directory" << process->workingDirectory(); + _fgProcess->setWorkingDirectory(_fgProcessWorkingDirPath); + qDebug() << "Working directory" << _fgProcess->workingDirectory(); } #ifdef Q_OS_WIN32 // On Windows we need to full qualify the location of the excecutable. The call to setWorkingDirectory only - // sets the process context, not the QProcess::start context. For some strange reason this is not the case on + // sets the QProcess context, not the QProcess::start context. For some strange reason this is not the case on // OSX. QDir fgProcessFullyQualified(_fgProcessWorkingDirPath); _fgProcessName = fgProcessFullyQualified.absoluteFilePath(_fgProcessName); @@ -131,7 +128,7 @@ void QGCFlightGearLink::run() qDebug() << "Starting FlightGear" << _fgProcessWorkingDirPath << _fgProcessName << _fgArgList; #endif - process->start(_fgProcessName, _fgArgList); + _fgProcess->start(_fgProcessName, _fgArgList); connectState = true; emit simulationConnected(connectState); @@ -152,7 +149,7 @@ void QGCFlightGearLink::processError(QProcess::ProcessError err) switch(err) { case QProcess::FailedToStart: - emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), process->errorString()); + emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), _fgProcess->errorString()); break; case QProcess::Crashed: emit showCriticalMessageFromThread(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); @@ -272,7 +269,7 @@ void QGCFlightGearLink::writeBytes(const char* data, qint64 size) qDebug() << bytes; qDebug() << "ASCII:" << ascii; #endif - if (connectState && socket) socket->writeDatagram(data, size, currentHost, currentPort); + if (connectState && _udpCommSocket) _udpCommSocket->writeDatagram(data, size, currentHost, currentPort); } /** @@ -288,9 +285,9 @@ void QGCFlightGearLink::readBytes() QHostAddress sender; quint16 senderPort; - unsigned int s = socket->pendingDatagramSize(); + unsigned int s = _udpCommSocket->pendingDatagramSize(); if (s > maxLength) std::cerr << __FILE__ << __LINE__ << " UDP datagram overflow, allowed to read less bytes than datagram size" << std::endl; - socket->readDatagram(data, maxLength, &sender, &senderPort); + _udpCommSocket->readDatagram(data, maxLength, &sender, &senderPort); QByteArray b(data, s); @@ -457,7 +454,7 @@ void QGCFlightGearLink::readBytes() **/ qint64 QGCFlightGearLink::bytesAvailable() { - return socket->pendingDatagramSize(); + return _udpCommSocket->pendingDatagramSize(); } /** @@ -467,24 +464,24 @@ qint64 QGCFlightGearLink::bytesAvailable() **/ bool QGCFlightGearLink::disconnectSimulation() { - disconnect(process, SIGNAL(error(QProcess::ProcessError)), + disconnect(_fgProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); disconnect(mav, SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); disconnect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); disconnect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); disconnect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); - if (process) + if (_fgProcess) { - process->close(); - delete process; - process = NULL; + _fgProcess->close(); + delete _fgProcess; + _fgProcess = NULL; } - if (socket) + if (_udpCommSocket) { - socket->close(); - delete socket; - socket = NULL; + _udpCommSocket->close(); + delete _udpCommSocket; + _udpCommSocket = NULL; } connectState = false; @@ -500,12 +497,13 @@ bool QGCFlightGearLink::disconnectSimulation() /// @brief Splits a space seperated set of command line arguments into a QStringList. /// Quoted strings are allowed and handled correctly. -/// @param uiArgs Arguments to parse -/// @param argList Returned argument list +/// @param uiArgs Arguments to parse +/// @param argList Returned argument list /// @return Returns false if the argument list has mistmatced quotes within in. bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) { + // FYI: The only reason this routine is public is so that we can reference it from a unit test. // This is not as easy as it seams since some options can be quoted to preserve spaces within things like // directories. There is likely some crazed regular expression which can do this. But after trying that @@ -571,6 +569,26 @@ bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) return true; } +/// @brief Locates the specified argument in the argument list, returning the value for it. +/// @param uiArgList Argument list to search through +/// @param argLabel Argument label to search for +/// @param argValue Returned argument value if found +/// @return Returns true if argument found and argValue returned +bool QGCFlightGearLink::_findUIArgument(const QStringList& uiArgList, const QString& argLabel, QString& argValue) +{ + QString regExpStr = argLabel + "=(.*)"; + int index = uiArgList.indexOf(QRegExp(regExpStr, Qt::CaseInsensitive)); + if (index != -1) { + QRegExp regExp(regExpStr); + index = regExp.indexIn(uiArgList[index]); + Q_ASSERT(index != -1); + argValue = regExp.cap(1); + return true; + } else { + return false; + } +} + /** * @brief Connect the connection. * @@ -583,23 +601,17 @@ bool QGCFlightGearLink::connectSimulation() // have that information setup we start the thread which will call run, which will in turn // start the various FG processes on the seperate thread. - // FixMe: Does returning false out of here leave in inconsistent state? - - qDebug() << "STARTING FLIGHTGEAR LINK"; - - // FIXME: !mav is failure isn't it? if (!mav) { return false; } - // FIXME: Pull previous information from settings - - QString fgAppName; - QString fgRootPath; // FlightGear root data directory as specified by --fg-root - bool fgRootDirOverride = false; // true: User has specified --fg-root from ui options - QString fgSceneryPath; // FlightGear scenery path as specified by --fg-scenery - bool fgSceneryDirOverride = false; // true: User has specified --fg-scenery from ui options - QDir fgAppDir; // Location of main FlightGear application + QString fgAppName; + QString fgRootPath; // FlightGear root data directory as specified by --fg-root + QStringList fgRootPathProposedList; // Directories we will attempt to search for --fg-root + bool fgRootDirOverride = false; // true: User has specified --fg-root from ui options + QString fgSceneryPath; // FlightGear scenery path as specified by --fg-scenery + bool fgSceneryDirOverride = false; // true: User has specified --fg-scenery from ui options + QDir fgAppDir; // Location of main FlightGear application #if defined Q_OS_MACX // Mac installs will default to the /Applications folder 99% of the time. Anything other than @@ -608,10 +620,9 @@ bool QGCFlightGearLink::connectSimulation() fgAppName = "FlightGear.app"; _fgProcessName = "./fgfs.sh"; _fgProcessWorkingDirPath = "/Applications/FlightGear.app/Contents/Resources/"; - fgRootPath = "/Applications/FlightGear.app/Contents/Resources/data/"; + fgRootPathProposedList += "/Applications/FlightGear.app/Contents/Resources/data/"; #elif defined Q_OS_WIN32 _fgProcessName = "fgfs.exe"; - //fgProcessWorkingDir = "C:\\Program Files (x86)\\FlightGear\\bin\\Win32"; // Windows installs are not as easy to determine. Default installation is to // C:\Program Files\FlightGear, but that can be easily changed. That also doesn't @@ -667,8 +678,8 @@ bool QGCFlightGearLink::connectSimulation() regExp.setPattern("^fg_root:(.*)"); if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { - fgRootPath = QDir(regExp.cap(1)).absolutePath(); - qDebug() << "fg_root" << fgRootPath; + fgRootPathProposedList += QDir(regExp.cap(1)).absolutePath(); + qDebug() << "fg_root" << fgRootPathProposedList[0]; continue; } @@ -686,7 +697,8 @@ bool QGCFlightGearLink::connectSimulation() // Linux installs to a location on the path so we don't need a directory to run the executable fgAppName = "fgfs"; _fgProcessName = "fgfs"; - fgRootPath = "/usr/share/games/flightgear/"; // Default Ubuntu location as best guess + fgRootPathProposedList += "/usr/share/flightgear/data/"; // Default Archlinux location + fgRootPathProposedList += "/usr/share/games/flightgear/"; // Default Ubuntu location #else #error Unknown OS build flavor #endif @@ -708,7 +720,11 @@ bool QGCFlightGearLink::connectSimulation() } // Let the user pick the right directory - fgAppDir.setPath(QFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName)); + QString dirPath = QFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName); + if (dirPath.isEmpty()) { + return false; + } + fgAppDir.setPath(dirPath); fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); } #endif @@ -718,7 +734,7 @@ bool QGCFlightGearLink::connectSimulation() QStringList uiArgList; bool mismatchedQuotes = parseUIArguments(startupArguments, uiArgList); if (!mismatchedQuotes) { - MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), tr("Mismatched quotes in specified command line options")); + MainWindow::instance()->showCriticalMessage(tr("FlightGear settings"), tr("Mismatched quotes in specified command line options")); return false; } @@ -728,41 +744,50 @@ bool QGCFlightGearLink::connectSimulation() #endif _fgArgList += uiArgList; - // Add --fg-root command line arg. If --fg-root is specified from the ui we use that instead. - // We need to know what --fg-root is set to because we are going to use it to validate - // communication protocols. - if (startupArguments.contains("--fg-root=", Qt::CaseInsensitive)) { - // FIXME: Won't handle missing quotes - const char* regExpStr = "--fg-root=(.*)"; - int index = _fgArgList.indexOf(QRegExp(regExpStr, Qt::CaseInsensitive)); - Q_ASSERT(index != -1); - QString rootArg(_fgArgList[index]); - QRegExp regExp(regExpStr); - index = regExp.indexIn(rootArg); - Q_ASSERT(index != -1); - fgRootPath = regExp.cap(1); - qDebug() << "--fg-root override" << fgRootPath; - fgRootDirOverride = true; - } else { - _fgArgList += "--fg-root=" + fgRootPath; - } + // If we have an --fg-root coming in from the ui options that overrides any internal searching of + // proposed locations. + QString argValue; + fgRootDirOverride = _findUIArgument(_fgArgList, "--fg-root", argValue); + if (fgRootDirOverride) { + fgRootPathProposedList.clear(); + fgRootPathProposedList += argValue; + qDebug() << "--fg-root override" << argValue; + } + + // See if we can find an --fg-root directory from the proposed list. + Q_ASSERT(fgRootPath.isEmpty()); + for (int i=0; i as an additional command line parameter from ui."); + } + MainWindow::instance()->showCriticalMessage(tr("FlightGear settings"), errMsg); + return false; + } + + if (!fgRootDirOverride) { + _fgArgList += "--fg-root=" + fgRootPath; + } + // Add --fg-scenery command line arg. If --fg-scenery is specified from the ui we use that instead. // On Windows --fg-scenery is required on the command line otherwise FlightGear won't boot. - // FIXME: Use single routine for both overrides - if (startupArguments.contains("--fg-scenery=", Qt::CaseInsensitive)) { - // FIXME: Won't handle missing quotes - const char* regExpStr = "--fg-scenery=(.*)"; - int index = _fgArgList.indexOf(QRegExp(regExpStr, Qt::CaseInsensitive)); - Q_ASSERT(index != -1); - QString rootArg(_fgArgList[index]); - QRegExp regExp(regExpStr); - index = regExp.indexIn(rootArg); - Q_ASSERT(index != -1); - Q_ASSERT(regExp.captureCount() == 1); - fgSceneryPath = regExp.cap(1); - qDebug() << "--fg-scenery override" << fgSceneryPath; - fgSceneryDirOverride = true; + fgSceneryDirOverride = _findUIArgument(_fgArgList, "--fg-scenery", argValue); + if (fgSceneryDirOverride) { + fgSceneryPath = argValue; + qDebug() << "--fg-scenery override" << argValue; } else if (!fgSceneryPath.isEmpty()) { _fgArgList += "--fg-scenery=" + fgSceneryPath; } @@ -777,27 +802,13 @@ bool QGCFlightGearLink::connectSimulation() } else { errMsg = tr("Unable to automatically determine --fg-scenery directory location. You will need to specify --fg-scenery=directory as an additional command line parameter from ui."); } - MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), errMsg); + MainWindow::instance()->showCriticalMessage(tr("FlightGear settings"), errMsg); return false; } #else Q_UNUSED(fgSceneryDirOverride); #endif - // Check that we have a good fgRootDir set before we use it to check communication protocol files. - if (fgRootPath.isEmpty() || !QFileInfo(fgRootPath).isDir()) { - QString errMsg; - if (fgRootDirOverride) { - errMsg = tr("--fg-root directory specified from ui option not found: %1").arg(fgRootPath); - } else if (fgRootPath.isEmpty()) { - errMsg = tr("Unable to automatically determine --fg-root directory location. You will need to specify --fg-root= as an additional command line parameter from ui."); - } else { - errMsg = tr("Unable to automatically determine --fg-root directory location. Attempted directory '%1', which does not exist. You will need to specify --fg-root= as an additional command line parameter from ui.").arg(fgRootPath); - } - MainWindow::instance()->showCriticalMessage(tr("FlightGear Failed to Start"), errMsg); - return false; - } - // Setup and verify directory which contains QGC provided aircraft files QString qgcAircraftDir(QApplication::applicationDirPath() + "/files/flightgear/Aircraft"); if (!QFileInfo(qgcAircraftDir).isDir()) { @@ -808,7 +819,7 @@ bool QGCFlightGearLink::connectSimulation() // Setup protocol we will be using to communicate with FlightGear QString fgProtocol(mav->getSystemType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); - QString fgProtocolArg("--generic=socket,%1,300,127.0.0.1,%2,udp,%3"); + QString fgProtocolArg("--generic=_udpCommSocket,%1,300,127.0.0.1,%2,udp,%3"); _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); @@ -908,10 +919,10 @@ bool QGCFlightGearLink::connectSimulation() return true; } -void QGCFlightGearLink::printFgfsOutput() +void QGCFlightGearLink::_printFgfsOutput(void) { qDebug() << "fgfs stdout:"; - QByteArray byteArray = process->readAllStandardOutput(); + QByteArray byteArray = _fgProcess->readAllStandardOutput(); QStringList strLines = QString(byteArray).split("\n"); foreach (QString line, strLines){ @@ -919,11 +930,11 @@ void QGCFlightGearLink::printFgfsOutput() } } -void QGCFlightGearLink::printFgfsError() +void QGCFlightGearLink::_printFgfsError(void) { qDebug() << "fgfs stderr:"; - QByteArray byteArray = process->readAllStandardError(); + QByteArray byteArray = _fgProcess->readAllStandardError(); QStringList strLines = QString(byteArray).split("\n"); foreach (QString line, strLines){ diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h index 02dc11b94..a86de7326 100644 --- a/src/comm/QGCFlightGearLink.h +++ b/src/comm/QGCFlightGearLink.h @@ -47,7 +47,6 @@ This file is part of the QGROUNDCONTROL project class QGCFlightGearLink : public QGCHilLink { Q_OBJECT - //Q_INTERFACES(QGCFlightGearLinkInterface:LinkInterface) public: QGCFlightGearLink(UASInterface* mav, QString startupArguments, QString remoteHost=QString("127.0.0.1:49000"), QHostAddress host = QHostAddress::Any, quint16 port = 49005); @@ -103,10 +102,6 @@ public slots: /** @brief Send new control states to the simulation */ void updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode); void updateActuators(quint64 time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8); -// /** @brief Remove a host from broadcasting messages to */ -// void removeHost(const QString& host); - // void readPendingDatagrams(); - void processError(QProcess::ProcessError err); /** @brief Set the simulator version as text string */ void setVersion(const QString& version) { @@ -135,10 +130,9 @@ public slots: bool connectSimulation(); bool disconnectSimulation(); - void printFgfsOutput(); - void printFgfsError(); void setStartupArguments(QString startupArguments); void setBarometerOffset(float barometerOffsetkPa); + void processError(QProcess::ProcessError err); protected: QString name; @@ -147,11 +141,9 @@ protected: quint16 currentPort; quint16 port; int id; - QUdpSocket* socket; bool connectState; UASInterface* mav; - QProcess* process; unsigned int flightGearVersion; QString startupArguments; bool _sensorHilEnabled; @@ -159,10 +151,19 @@ protected: void setName(QString name); +private slots: + void _printFgfsOutput(void); + void _printFgfsError(void); + private: + static bool _findUIArgument(const QStringList& uiArgList, const QString& argLabel, QString& argValue); + QString _fgProcessName; ///< FlightGear process to start QString _fgProcessWorkingDirPath; ///< Working directory to start FG process in, empty for none QStringList _fgArgList; ///< Arguments passed to FlightGear process + + QUdpSocket* _udpCommSocket; ///< UDP communication sockect between FG and QGC + QProcess* _fgProcess; ///< FlightGear process }; #endif // QGCFLIGHTGEARLINK_H -- GitLab From dda783ff065c205d23bc63a864c82bb3cc00a851 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Fri, 6 Jun 2014 13:39:11 -0400 Subject: [PATCH 12/57] commit --- src/comm/QGCFlightGearLink.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 04cefb63a..80e3208f2 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -574,6 +574,7 @@ bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) /// @param argLabel Argument label to search for /// @param argValue Returned argument value if found /// @return Returns true if argument found and argValue returned + bool QGCFlightGearLink::_findUIArgument(const QStringList& uiArgList, const QString& argLabel, QString& argValue) { QString regExpStr = argLabel + "=(.*)"; @@ -703,8 +704,8 @@ bool QGCFlightGearLink::connectSimulation() #error Unknown OS build flavor #endif - // Validate the FlightGear application directory location. Linux runs from path so we don't validate on that OS. #ifndef Q_OS_LINUX + // Validate the FlightGear application directory location. Linux runs from path so we don't validate on that OS. Q_ASSERT(!fgAppName.isEmpty()); QString fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); while (!QFileInfo(fgAppFullyQualified).exists()) { @@ -744,7 +745,7 @@ bool QGCFlightGearLink::connectSimulation() #endif _fgArgList += uiArgList; - // If we have an --fg-root coming in from the ui options that overrides any internal searching of + // If we have an --fg-root coming in from the ui options, that setting overrides any internal searching of // proposed locations. QString argValue; fgRootDirOverride = _findUIArgument(_fgArgList, "--fg-root", argValue); -- GitLab From 1cad7af3aaf09107c3fc8a21d6328f8e71248af7 Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Wed, 11 Jun 2014 11:57:18 -0700 Subject: [PATCH 13/57] Removed mavlinkgen application as it has been unused and deprecated for many months. --- .gitignore | 1 - QGCExternalLibs.pri | 28 - README.md | 3 - src/apps/mavlinkgen/MAVLinkGen.cc | 88 -- src/apps/mavlinkgen/MAVLinkGen.h | 60 -- src/apps/mavlinkgen/README | 29 - .../deploy/mac_create_dmg_mavlinkgen.sh | 7 - .../deploy/mavlinkgen_installer.nsi | 35 - .../mavlinkgen/generator/MAVLinkXMLParser.cc | 754 ------------------ .../mavlinkgen/generator/MAVLinkXMLParser.h | 66 -- .../generator/MAVLinkXMLParserV10.cc | 148 ---- .../generator/MAVLinkXMLParserV10.h | 84 -- .../images/categories/applications-system.svg | 247 ------ .../mavlinkgen/images/status/folder-open.svg | 482 ----------- src/apps/mavlinkgen/license.txt | 195 ----- src/apps/mavlinkgen/main.cc | 46 -- src/apps/mavlinkgen/mavlinkgen.pri | 44 - src/apps/mavlinkgen/mavlinkgen.pro | 22 - src/apps/mavlinkgen/mavlinkgen.qrc | 6 - src/apps/mavlinkgen/msinttypes/inttypes.h | 305 ------- src/apps/mavlinkgen/msinttypes/stdint.h | 247 ------ src/apps/mavlinkgen/template/checksum.h | 139 ---- .../mavlinkgen/template/documentation.dox | 41 - .../mavlinkgen/template/mavlink_checksum.h | 183 ----- src/apps/mavlinkgen/template/mavlink_data.h | 21 - .../mavlinkgen/template/mavlink_options.h | 135 ---- .../mavlinkgen/template/mavlink_protocol.h | 423 ---------- src/apps/mavlinkgen/template/mavlink_types.h | 120 --- src/apps/mavlinkgen/template/protocol.h | 439 ---------- src/apps/mavlinkgen/ui/DomItem.cc | 47 -- src/apps/mavlinkgen/ui/DomItem.h | 24 - src/apps/mavlinkgen/ui/DomModel.cc | 195 ----- src/apps/mavlinkgen/ui/DomModel.h | 34 - src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.cc | 480 ----------- src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.h | 106 --- .../mavlinkgen/ui/XMLCommProtocolWidget.cc | 194 ----- .../mavlinkgen/ui/XMLCommProtocolWidget.h | 89 --- .../mavlinkgen/ui/XMLCommProtocolWidget.ui | 175 ---- 38 files changed, 5742 deletions(-) delete mode 100644 src/apps/mavlinkgen/MAVLinkGen.cc delete mode 100644 src/apps/mavlinkgen/MAVLinkGen.h delete mode 100644 src/apps/mavlinkgen/README delete mode 100644 src/apps/mavlinkgen/deploy/mac_create_dmg_mavlinkgen.sh delete mode 100644 src/apps/mavlinkgen/deploy/mavlinkgen_installer.nsi delete mode 100644 src/apps/mavlinkgen/generator/MAVLinkXMLParser.cc delete mode 100644 src/apps/mavlinkgen/generator/MAVLinkXMLParser.h delete mode 100644 src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.cc delete mode 100644 src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.h delete mode 100644 src/apps/mavlinkgen/images/categories/applications-system.svg delete mode 100644 src/apps/mavlinkgen/images/status/folder-open.svg delete mode 100644 src/apps/mavlinkgen/license.txt delete mode 100644 src/apps/mavlinkgen/main.cc delete mode 100644 src/apps/mavlinkgen/mavlinkgen.pri delete mode 100644 src/apps/mavlinkgen/mavlinkgen.pro delete mode 100644 src/apps/mavlinkgen/mavlinkgen.qrc delete mode 100644 src/apps/mavlinkgen/msinttypes/inttypes.h delete mode 100644 src/apps/mavlinkgen/msinttypes/stdint.h delete mode 100644 src/apps/mavlinkgen/template/checksum.h delete mode 100644 src/apps/mavlinkgen/template/documentation.dox delete mode 100644 src/apps/mavlinkgen/template/mavlink_checksum.h delete mode 100644 src/apps/mavlinkgen/template/mavlink_data.h delete mode 100644 src/apps/mavlinkgen/template/mavlink_options.h delete mode 100644 src/apps/mavlinkgen/template/mavlink_protocol.h delete mode 100644 src/apps/mavlinkgen/template/mavlink_types.h delete mode 100644 src/apps/mavlinkgen/template/protocol.h delete mode 100644 src/apps/mavlinkgen/ui/DomItem.cc delete mode 100644 src/apps/mavlinkgen/ui/DomItem.h delete mode 100644 src/apps/mavlinkgen/ui/DomModel.cc delete mode 100644 src/apps/mavlinkgen/ui/DomModel.h delete mode 100644 src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.cc delete mode 100644 src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.h delete mode 100644 src/apps/mavlinkgen/ui/XMLCommProtocolWidget.cc delete mode 100644 src/apps/mavlinkgen/ui/XMLCommProtocolWidget.h delete mode 100644 src/apps/mavlinkgen/ui/XMLCommProtocolWidget.ui diff --git a/.gitignore b/.gitignore index ee259ce1c..4f1e63458 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ tmp debug release /qgroundcontrol -mavlinkgen-build-desktop qgroundcontrol.xcodeproj/** doc/html doc/doxy.log diff --git a/QGCExternalLibs.pri b/QGCExternalLibs.pri index eaea69384..ce80c1a78 100644 --- a/QGCExternalLibs.pri +++ b/QGCExternalLibs.pri @@ -123,34 +123,6 @@ INCLUDEPATH += $$MAVLINKPATH INCLUDEPATH += $$MAVLINKPATH/common } -# -# [DEPRECATED] MAVLink generator UI. Provides a GUI interface for generating MAVLink dialects. -# Replaced by mavgenerator.py within the MAVLink project. -# -contains(DEFINES, ENABLE_MAVGEN) { - warning("Including support for MAVLink generator GUI (manual override from command line, CAUTION: deprecated)") -} else:infile(user_config.pri, DEFINES, ENABLE_MAVGEN) { - DEFINES += ENABLE_MAVGEN # infile doesn't automatically include everything in the specified file - warning("Including support for MAVLink generator GUI (manual override from user_config.pri, CAUTION: deprecated)") -} - -contains(DEFINES, ENABLE_MAVGEN) { - # Rename the macro to be consistent with other QGC feature existance macros. - DEFINES -= ENABLE_MAVGEN - DEFINES += QGC_MAVGEN_ENABLED - DEPENDPATH += \ - src/apps/mavlinkgen - - INCLUDEPATH += \ - src/apps/mavlinkgen \ - src/apps/mavlinkgen/ui \ - src/apps/mavlinkgen/generator - - include(src/apps/mavlinkgen/mavlinkgen.pri) -} else { - message("Skipping support for MAVLink generator GUI (deprecated, see README)") -} - # # [OPTIONAL] OpenSceneGraph # Allow the user to override OpenSceneGraph compilation through a DISABLE_OPEN_SCENE_GRAPH diff --git a/README.md b/README.md index 5771904be..07043d7fc 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,6 @@ The QUpgrade module relies on `libudev` on Linux platforms, so be sure to instal ### Specifying MAVLink dialects The MAVLink dialect compiled by default by QGC is for the ardupilotmega. This will happen if no other dialects are specified. Setting the `MAVLINK_CONF` variable sets the dialects, with more than one specified in a space-separated list. Note that doing this may result in compilation errors as certain dialects may conflict with each other! -### MAVLink dialect generator -An add-on is available for QGC that provides a UI for generating MAVLink dialects from within QGC. This feature has been deprecated since identical functionality now exists within the MAVLink project itself. Enable this functionality by specifying the `DEFINES` variable `ENABLE_MAVGEN`. - ### Opal-RT's RT-LAB simulator Integration with Opal-RT's RT-LAB simulator can be enabled on Windows by installing RT-LAB 7.2.4. This allows vehicles to be simulated in RT-LAB and communicate directly with QGC on the same computer as if the UAS was actually deployed. This support is enabled by default once the requisite RT-LAB software is installed. Disabling this can be done by adding `DISABLE_RTLAB` to the `DEFINES` variable. diff --git a/src/apps/mavlinkgen/MAVLinkGen.cc b/src/apps/mavlinkgen/MAVLinkGen.cc deleted file mode 100644 index 3d6e8f230..000000000 --- a/src/apps/mavlinkgen/MAVLinkGen.cc +++ /dev/null @@ -1,88 +0,0 @@ -/*===================================================================== - -PIXHAWK Micro Air Vehicle Flying Robotics Toolkit - -(c) 2009, 2010 PIXHAWK PROJECT - -This file is part of the PIXHAWK project - - PIXHAWK is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PIXHAWK is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PIXHAWK. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Implementation of class MAVLinkGen - * - * @author Lorenz Meier - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "MAVLinkGen.h" -#include "XMLCommProtocolWidget.h" - - -/** - * @brief Constructor for the main application. - * - * This constructor initializes and starts the whole application. It takes standard - * command-line parameters - * - * @param argc The number of command-line parameters - * @param argv The string array of parameters - **/ - -MAVLinkGen::MAVLinkGen(int &argc, char* argv[]) : QApplication(argc, argv) -{ - this->setApplicationName("MAVLink Generator"); - this->setApplicationVersion("v. 1.0.0 (Beta)"); - this->setOrganizationName(QLatin1String("MAVLink Consortium")); - this->setOrganizationDomain("http://qgroundcontrol.org/mavlink"); - - QSettings::setDefaultFormat(QSettings::IniFormat); - // Exit main application when last window is closed - connect(this, SIGNAL(lastWindowClosed()), this, SLOT(quit())); - - // Create main window - window = new QMainWindow(); - window->setCentralWidget(new XMLCommProtocolWidget(window)); - window->setWindowTitle(applicationName() + " " + applicationVersion()); - window->resize(qMax(950, static_cast(QApplication::desktop()->width()*0.7f)), qMax(600, static_cast(QApplication::desktop()->height()*0.8f))); - window->show(); -} - -/** - * @brief Destructor - * - **/ -MAVLinkGen::~MAVLinkGen() -{ - window->hide(); - delete window; -} - diff --git a/src/apps/mavlinkgen/MAVLinkGen.h b/src/apps/mavlinkgen/MAVLinkGen.h deleted file mode 100644 index 674346d75..000000000 --- a/src/apps/mavlinkgen/MAVLinkGen.h +++ /dev/null @@ -1,60 +0,0 @@ -/*===================================================================== - -PIXHAWK Micro Air Vehicle Flying Robotics Toolkit - -(c) 2009, 2010 PIXHAWK PROJECT - -This file is part of the PIXHAWK project - - PIXHAWK is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PIXHAWK is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PIXHAWK. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Definition of class MAVLinkGen - * - * @author Lorenz Meier - * - */ - - -#ifndef MAVLINKGEN_H -#define MAVLINKGEN_H - -#include -#include - -/** - * @brief The main application and management class. - * - * This class is started by the main method and provides - * the central management unit of the groundstation application. - * - **/ -class MAVLinkGen : public QApplication -{ - Q_OBJECT - -public: - MAVLinkGen(int &argc, char* argv[]); - ~MAVLinkGen(); - -protected: - QMainWindow* window; - -private: -}; - -#endif /* MAVLINKGEN_H */ diff --git a/src/apps/mavlinkgen/README b/src/apps/mavlinkgen/README deleted file mode 100644 index a0e372410..000000000 --- a/src/apps/mavlinkgen/README +++ /dev/null @@ -1,29 +0,0 @@ -Code Generator for the MAVLink Micro Air Vehicle Message Marshalling Library - -This is a code generator for the library for lightweight communication between -Micro Air Vehicles and/or ground control stations. -It serializes C-structs for serial channels and can be used with -any type of radio modem. - -********** -* NEWS * -********** - -MAVLink has been ported to Python and Java. MAVLinkGen will soon support the output of Python and Java code as well. - - - -For help, please visit the mailing list: http://groups.google.com/group/mavlink - -MAVLink is licensed under the terms of the Lesser General Public License of the Free Software Foundation (LGPL). - -MAVLink's reference implementation is done in the QGroundControl operator control unit. MAVLink is however not tied in any way to QGroundControl nor does it depend on it. Many other groundstations (APM Planner, HK GCS, Copter-GCS) support it and might be better suited for your application than QGC - check them out. - -Project: -http://qgroundcontrol.org/mavlink - -Files: -http://github.com/pixhawk/mavlinkgen -http://github.com/pixhawk/mavlink - -(c) 2009-2011 Lorenz Meier \ No newline at end of file diff --git a/src/apps/mavlinkgen/deploy/mac_create_dmg_mavlinkgen.sh b/src/apps/mavlinkgen/deploy/mac_create_dmg_mavlinkgen.sh deleted file mode 100644 index 8f2cb2780..000000000 --- a/src/apps/mavlinkgen/deploy/mac_create_dmg_mavlinkgen.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -cp -r ../../mavlinkgen-build-desktop/mavlinkgen.app . - -echo -e '\n\nStarting to create disk image. This may take a while..\n' -macdeployqt mavlinkgen.app -dmg -rm -rf mavlinkgen.app -echo -e '\n\n MAVLinkGen .DMG file is now ready for publishing\n' diff --git a/src/apps/mavlinkgen/deploy/mavlinkgen_installer.nsi b/src/apps/mavlinkgen/deploy/mavlinkgen_installer.nsi deleted file mode 100644 index 346cb3994..000000000 --- a/src/apps/mavlinkgen/deploy/mavlinkgen_installer.nsi +++ /dev/null @@ -1,35 +0,0 @@ -Name "MAVLink Generator" - -OutFile "mavlinkgen-installer-win32.exe" - -InstallDir $PROGRAMFILES\mavlinkgen - -Page license -Page directory -Page components -Page instfiles -UninstPage uninstConfirm -UninstPage instfiles - -LicenseData ..\license.txt - -Section "" - - SetOutPath $INSTDIR - File ..\release\*.* - WriteUninstaller $INSTDIR\mavlinkgen_uninstall.exe -SectionEnd - -Section "Uninstall" - Delete $INSTDIR\mavlinkgen_uninstall.exe - Delete $INSTDIR\*.* - RMDir $INSTDIR - Delete "$SMPROGRAMS\mavlinkgen\*.*" - RMDir "$SMPROGRAMS\mavlinkgen\" -SectionEnd - -Section "create Start Menu Shortcuts" - CreateDirectory "$SMPROGRAMS\MAVLink" - CreateShortCut "$SMPROGRAMS\MAVLink\Uninstall.lnk" "$INSTDIR\mavlinkgen_uninstall.exe" "" "$INSTDIR\mavlinkgen_uninstall.exe" 0 - CreateShortCut "$SMPROGRAMS\MAVLink\MAVLinkGen.lnk" "$INSTDIR\mavlinkgen.exe" "" "$INSTDIR\mavlinkgen.exe" 0 -SectionEnd \ No newline at end of file diff --git a/src/apps/mavlinkgen/generator/MAVLinkXMLParser.cc b/src/apps/mavlinkgen/generator/MAVLinkXMLParser.cc deleted file mode 100644 index 66769ae15..000000000 --- a/src/apps/mavlinkgen/generator/MAVLinkXMLParser.cc +++ /dev/null @@ -1,754 +0,0 @@ -/*===================================================================== - -QGroundControl Open Source Ground Control Station - -(c) 2009 - 2011 QGROUNDCONTROL PROJECT - -This file is part of the QGROUNDCONTROL project - - QGROUNDCONTROL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QGROUNDCONTROL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QGROUNDCONTROL. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Implementation of class MAVLinkXMLParser - * @author Lorenz Meier - */ - -#include -#include -#include -#include -#include -#include -#include -#include "MAVLinkXMLParser.h" - -#include - -MAVLinkXMLParser::MAVLinkXMLParser(QDomDocument* document, QString outputDirectory, QObject* parent) : QObject(parent), - doc(document), - outputDirName(outputDirectory), - fileName("") -{ -} - -MAVLinkXMLParser::MAVLinkXMLParser(QString document, QString outputDirectory, QObject* parent) : QObject(parent) -{ - doc = new QDomDocument(); - QFile file(document); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - const QString instanceText(QString::fromUtf8(file.readAll())); - doc->setContent(instanceText); - } - fileName = document; - outputDirName = outputDirectory; -} - -MAVLinkXMLParser::~MAVLinkXMLParser() -{ -} - -/** - * Generate C-code (C-89 compliant) out of the XML protocol specs. - */ -bool MAVLinkXMLParser::generate() -{ - // Process result - bool success = true; - - // Only generate if output dir is correctly set - if (outputDirName == "") - { - emit parseState(tr("ERROR: No output directory given.\nAbort.")); - return false; - } - - QString topLevelOutputDirName = outputDirName; - - // print out the element names of all elements that are direct children - // of the outermost element. - QDomElement docElem = doc->documentElement(); - QDomNode n = docElem;//.firstChild(); - QDomNode p = docElem; - - // Sanity check variables - QList* usedMessageIDs = new QList(); - QMap* usedMessageNames = new QMap(); - QMap* usedEnumNames = new QMap(); - - QList< QPair > cFiles; - QString lcmStructDefs = ""; - - QString pureFileName; - QString pureIncludeFileName; - - QFileInfo fInfo(this->fileName); - pureFileName = fInfo.baseName().split(".", QString::SkipEmptyParts).first(); - - // XML parsed and converted to C code. Now generating the files - outputDirName += QDir::separator() + pureFileName; - QDateTime now = QDateTime::currentDateTime().toUTC(); - QLocale loc(QLocale::English); - QString dateFormat = "dddd, MMMM d yyyy, hh:mm UTC"; - QString date = loc.toString(now, dateFormat); - QString includeLine = "#include \"%1\"\n"; - QString mainHeaderName = pureFileName + ".h"; - QString messagesDirName = ".";//"generated"; - QDir dir(outputDirName + "/" + messagesDirName); - - int mavlinkVersion = 0; - - // we need to gather the message lengths across multiple includes, - // which we can do via detecting recursion - static unsigned message_lengths[256]; - static int highest_message_id; - static int recursion_level; - - if (recursion_level == 0){ - highest_message_id = 0; - memset(message_lengths, 0, sizeof(message_lengths)); - } - - - // Start main header - QString mainHeader = QString("/** @file\n *\t@brief MAVLink comm protocol.\n *\t@see http://qgroundcontrol.org/mavlink/\n *\t Generated on %1\n */\n#ifndef " + pureFileName.toUpper() + "_H\n#define " + pureFileName.toUpper() + "_H\n\n").arg(date); // The main header includes all messages - // Mark all code as C code - mainHeader += "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"; - mainHeader += "\n#include \"../protocol.h\"\n"; - mainHeader += "\n#define MAVLINK_ENABLED_" + pureFileName.toUpper() + "\n\n"; - - QString enums; - - - // Run through root children - while(!n.isNull()) - { - // Each child is a message - QDomElement e = n.toElement(); // try to convert the node to an element. - if(!e.isNull()) - { - if (e.tagName() == "mavlink") - { - p = n; - n = n.firstChild(); - while (!n.isNull()) - { - e = n.toElement(); - if (!e.isNull()) - { - // Handle all include tags - if (e.tagName() == "include") - { - QString incFileName = e.text(); - // Load file - //QDomDocument includeDoc = QDomDocument(); - - // Prepend file path if it is a relative path and - // make it relative to opened file - QFileInfo fInfo(incFileName); - - QString incFilePath; - if (fInfo.isRelative()) - { - QFileInfo rInfo(this->fileName); - incFilePath = rInfo.absoluteDir().canonicalPath() + "/" + incFileName; - pureIncludeFileName = fInfo.baseName().split(".", QString::SkipEmptyParts).first(); - } - - QFile file(incFilePath); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - emit parseState(QString("Included messages from file: %1").arg(incFileName)); - // NEW MODE: CREATE INDIVIDUAL FOLDERS - // Create new output directory, parse included XML and generate C-code - MAVLinkXMLParser includeParser(incFilePath, topLevelOutputDirName, this); - connect(&includeParser, SIGNAL(parseState(QString)), this, SIGNAL(parseState(QString))); - // Generate and write - recursion_level++; - // Abort if inclusion fails - if (!includeParser.generate()) return false; - recursion_level--; - mainHeader += "\n#include \"../" + pureIncludeFileName + "/" + pureIncludeFileName + ".h\"\n"; - - - // OLD MODE: MERGE BOTH FILES - // const QString instanceText(QString::fromUtf8(file.readAll())); - // includeDoc.setContent(instanceText); - // // Get all messages - // QDomNode in = includeDoc.documentElement().firstChild(); - // QDomElement ie = in.toElement(); - // if (!ie.isNull()) - // { - // if (ie.tagName() == "messages" || ie.tagName() == "include") - // { - // QDomNode ref = n.parentNode().insertAfter(in, n); - // if (ref.isNull()) - // { - // emit parseState(QString("ERROR: Inclusion failed: XML syntax error in file %1. Wrong/misspelled XML?\nAbort.").arg(fileName)); - // return false; - // } - // } - // } - - emit parseState(QString("End of inclusion from file: %1").arg(incFileName)); - } - else - { - // Include file could not be opened - emit parseState(QString("ERROR: Failed including file: %1, file is not readable. Wrong/misspelled filename?\nAbort.").arg(fileName)); - return false; - } - - } - // Handle all enum tags - else if (e.tagName() == "version") - { - //QString fieldType = e.attribute("type", ""); - //QString fieldName = e.attribute("name", ""); - QString fieldText = e.text(); - - // Check if version has been previously set - if (mavlinkVersion != 0) - { - emit parseState(QString("ERROR: Protocol version tag set twice, please use it only once. First version was %1, second version is %2.\nAbort.").arg(mavlinkVersion).arg(fieldText)); - return false; - } - - bool ok; - int version = fieldText.toInt(&ok); - if (ok && (version > 0) && (version < 256)) - { - // Set MAVLink version - mavlinkVersion = version; - } - else - { - emit parseState(QString("ERROR: Reading version string failed: %1, string is not an integer number between 1 and 255.\nAbort.").arg(fieldText)); - return false; - } - } - // Handle all enum tags - else if (e.tagName() == "enums") - { - // One down into the enums list - p = n; - n = n.firstChild(); - while (!n.isNull()) - { - e = n.toElement(); - - QString currEnum; - QString currEnumEnd; - // Comment - QString comment; - - if(!e.isNull() && e.tagName() == "enum") - { - // Get enum name - QString enumName = e.attribute("name", "").toLower(); - if (enumName.size() == 0) - { - emit parseState(tr("ERROR: Missing required name=\"\" attribute for tag %2 near line %1\nAbort.").arg(QString::number(e.lineNumber()), e.tagName())); - return false; - } - else - { - // Sanity check: Accept only enum names not used previously - if (usedEnumNames->contains(enumName)) - { - emit parseState(tr("ERROR: Enum name %1 used twice, second occurence near line %2 of file %3\nAbort.").arg(enumName, QString::number(e.lineNumber()), fileName)); - return false; - } - else - { - usedEnumNames->insert(enumName, QString::number(e.lineNumber())); - } - - // Everything sane, starting with enum content - currEnum = "enum " + enumName.toUpper() + "\n{\n"; - currEnumEnd = QString("\t%1_ENUM_END\n};\n\n").arg(enumName.toUpper()); - - int nextEnumValue = 0; - - // Get the enum fields - QDomNode f = e.firstChild(); - while (!f.isNull()) - { - QDomElement e2 = f.toElement(); - if (!e2.isNull() && e2.tagName() == "entry") - { - QString fieldValue = e2.attribute("value", ""); - - // If value was given, use it, if not, use the enum iterator - // value. The iterator value gets reset by manual values - - QString fieldName = e2.attribute("name", ""); - if (fieldValue.length() == 0) - { - fieldValue = QString::number(nextEnumValue); - nextEnumValue++; - } - else - { - bool ok; - nextEnumValue = fieldValue.toInt(&ok) + 1; - if (!ok) - { - emit parseState(tr("ERROR: Enum entry %1 has not a valid number (%2) in the value field.\nAbort.").arg(fieldName, fieldValue)); - return false; - } - } - - // Add comment of field if there is one - QString fieldComment; - if (e2.text().length() > 0) - { - QString sep(" | "); - QDomNode pp = e2.firstChild(); - while (!pp.isNull()) - { - QDomElement pp2 = pp.toElement(); - if (pp2.isText() || pp2.isCDATASection()) - { - fieldComment += pp2.nodeValue() + sep; - } - else if (pp2.isElement()) - { - fieldComment += pp2.text() + sep; - } - pp = pp.nextSibling(); - } - fieldComment = fieldComment.replace("\n", " "); - fieldComment = " /* " + fieldComment.simplified() + " */"; - } - currEnum += "\t" + fieldName.toUpper() + "=" + fieldValue + "," + fieldComment + "\n"; - } - else if(!e2.isNull() && e2.tagName() == "description") - { - comment = " " + e2.text().replace("\n", " ") + comment; - } - f = f.nextSibling(); - } - } - // Add the last parsed enum - // Remove the last comma, as the last value has none - // ENUM END MARKER IS LAST ENTRY, COMMA REMOVAL NOT NEEDED - //int commaPosition = currEnum.lastIndexOf(","); - //currEnum.remove(commaPosition, 1); - - enums += "/** @brief " + comment + " */\n" + currEnum + currEnumEnd; - } // Element is non-zero and element name is - n = n.nextSibling(); - } // While through - // One up, back into the structure - n = p; - } - - // Handle all message tags - else if (e.tagName() == "messages") - { - p = n; - n = n.firstChild(); - while (!n.isNull()) - { - e = n.toElement(); - if(!e.isNull()) - { - //if (e.isNull()) continue; - // Get message name - QString messageName = e.attribute("name", "").toLower(); - if (messageName.size() == 0) - { - emit parseState(tr("ERROR: Missing required name=\"\" attribute for tag %2 near line %1\nAbort.").arg(QString::number(e.lineNumber()), e.tagName())); - return false; - } - else - { - // Get message id - bool ok; - int messageId = e.attribute("id", "-1").toInt(&ok, 10); - emit parseState(tr("Compiling message %1 \t(#%3) \tnear line %2").arg(messageName, QString::number(n.lineNumber()), QString::number(messageId))); - - // Sanity check: Accept only message IDs not used previously - if (usedMessageIDs->contains(messageId)) - { - emit parseState(tr("ERROR: Message ID %1 used twice, second occurence near line %2 of file %3\nAbort.").arg(QString::number(messageId), QString::number(e.lineNumber()), fileName)); - return false; - } - else - { - usedMessageIDs->append(messageId); - } - - // Sanity check: Accept only message names not used previously - if (usedMessageNames->contains(messageName)) - { - emit parseState(tr("ERROR: Message name %1 used twice, second occurence near line %2 of file %3\nAbort.").arg(messageName, QString::number(e.lineNumber()), fileName)); - return false; - } - else - { - usedMessageNames->insert(messageName, QString::number(e.lineNumber())); - } - - QString channelType("mavlink_channel_t"); - QString messageType("mavlink_message_t"); - - // Build up function call - QString commentContainer("/**\n * @brief Pack a %1 message\n * @param system_id ID of this system\n * @param component_id ID of this component (e.g. 200 for IMU)\n * @param msg The MAVLink message to compress the data into\n *\n%2 * @return length of the message in bytes (excluding serial stream start sign)\n */\n"); - QString commentPackChanContainer("/**\n * @brief Pack a %1 message\n * @param system_id ID of this system\n * @param component_id ID of this component (e.g. 200 for IMU)\n * @param chan The MAVLink channel this message was sent over\n * @param msg The MAVLink message to compress the data into\n%2 * @return length of the message in bytes (excluding serial stream start sign)\n */\n"); - QString commentSendContainer("/**\n * @brief Send a %1 message\n * @param chan MAVLink channel to send the message\n *\n%2 */\n"); - QString commentEncodeContainer("/**\n * @brief Encode a %1 struct into a message\n *\n * @param system_id ID of this system\n * @param component_id ID of this component (e.g. 200 for IMU)\n * @param msg The MAVLink message to compress the data into\n * @param %1 C-struct to read the message contents from\n */\n"); - QString commentDecodeContainer("/**\n * @brief Decode a %1 message into a struct\n *\n * @param msg The message to decode\n * @param %1 C-struct to decode the message contents into\n */\n"); - QString commentEntry(" * @param %1 %2\n"); - QString idDefine = QString("#define MAVLINK_MSG_ID_%1 %2").arg(messageName.toUpper(), QString::number(messageId)); - QString arrayDefines; - QString cStructName = QString("mavlink_%1_t").arg(messageName); - QString cStruct("typedef struct __%1 \n{\n%2\n} %1;"); - QString cStructLines; - QString encode("static inline uint16_t mavlink_msg_%1_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const %2* %1)\n{\n\treturn mavlink_msg_%1_pack(%3);\n}\n"); - - QString decode("static inline void mavlink_msg_%1_decode(const mavlink_message_t* msg, %2* %1)\n{\n%3}\n"); - QString pack("static inline uint16_t mavlink_msg_%1_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg%2)\n{\n\tuint16_t i = 0;\n\tmsg->msgid = MAVLINK_MSG_ID_%3;\n\n%4\n\treturn mavlink_finalize_message(msg, system_id, component_id, i);\n}\n\n"); - QString packChan("static inline uint16_t mavlink_msg_%1_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg%2)\n{\n\tuint16_t i = 0;\n\tmsg->msgid = MAVLINK_MSG_ID_%3;\n\n%4\n\treturn mavlink_finalize_message_chan(msg, system_id, component_id, chan, i);\n}\n\n"); - QString compactSend("#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS\n\nstatic inline void mavlink_msg_%3_send(%1 chan%5)\n{\n\t%2 msg;\n\tmavlink_msg_%3_pack_chan(mavlink_system.sysid, mavlink_system.compid, chan, &msg%4);\n\tmavlink_send_uart(chan, &msg);\n}\n\n#endif"); - //QString compactStructSend = "#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS\n\nstatic inline void mavlink_msg_%3_struct_send(%1 chan%5)\n{\n\t%2 msg;\n\tmavlink_msg_%3_encode(mavlink_system.sysid, mavlink_system.compid, &msg%4);\n\tmavlink_send_uart(chan, &msg);\n}\n\n#endif"; - QString unpacking; - QString prepends; - QString packParameters; - QString packArguments("system_id, component_id, msg"); - QString packLines; - QString decodeLines; - QString sendArguments; - QString commentLines; - unsigned message_length = 0; - - - // Get the message fields - QDomNode f = e.firstChild(); - while (!f.isNull()) - { - QDomElement e2 = f.toElement(); - if (!e2.isNull() && e2.tagName() == "field") - { - QString fieldType = e2.attribute("type", ""); - QString fieldName = e2.attribute("name", ""); - QString fieldText = e2.text(); - - QString unpackingCode; - QString unpackingComment = QString("/**\n * @brief Get field %1 from %2 message\n *\n * @return %3\n */\n").arg(fieldName, messageName, fieldText); - - // Send arguments do not work for the version field - if (!fieldType.contains("uint8_t_mavlink_version")) - { - // Send arguments are the same for integral types and arrays - sendArguments += ", " + fieldName; - commentLines += commentEntry.arg(fieldName, fieldText.replace("\n", " ")); - } - - // MAVLink version field - // this is a special field always containing the version define - if (fieldType.contains("uint8_t_mavlink_version")) - { - // Add field to C structure - cStructLines += QString("\t%1 %2; ///< %3\n").arg("uint8_t", fieldName, fieldText); - // Add pack line to message_xx_pack function - packLines += QString("\ti += put_uint8_t_by_index(%1, i, msg->payload); // %2\n").arg(mavlinkVersion).arg(fieldText); - // Add decode function for this type - decodeLines += QString("\t%1->%2 = mavlink_msg_%1_get_%2(msg);\n").arg(messageName, fieldName); - } - - // Array handling is different from simple types - else if (fieldType.startsWith("array")) - { - int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt(); - QString arrayType = fieldType.split("[").first(); - packParameters += QString(", const ") + QString("int8_t*") + " " + fieldName; - packArguments += ", " + messageName + "->" + fieldName; - - // Add field to C structure - cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg("int8_t", fieldName, QString::number(arrayLength), fieldText); - // Add pack line to message_xx_pack function - packLines += QString("\ti += put_%1_by_index(%2, %3, i, msg->payload); // %4\n").arg(arrayType, fieldName, QString::number(arrayLength), fieldText); - // Add decode function for this type - decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName); - arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength)); - } - else if (fieldType.startsWith("string")) - { - int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt(); - QString arrayType = fieldType.split("[").first(); - packParameters += QString(", const ") + QString("char*") + " " + fieldName; - packArguments += ", " + messageName + "->" + fieldName; - - // Add field to C structure - cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg("char", fieldName, QString::number(arrayLength), fieldText); - // Add pack line to message_xx_pack function - packLines += QString("\ti += put_%1_by_index(%2, %3, i, msg->payload); // %4\n").arg(arrayType, fieldName, QString::number(arrayLength), e2.text()); - // Add decode function for this type - decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName); - arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength)); - } - // Expand array handling to all valid mavlink data types - else if(fieldType.contains('[') && fieldType.contains(']')) - { - int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt(); - QString arrayType = fieldType.split("[").first(); - packParameters += QString(", const ") + arrayType + "* " + fieldName; - packArguments += ", " + messageName + "->" + fieldName; - - // Add field to C structure - cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg(arrayType, fieldName, QString::number(arrayLength), fieldText); - // Add pack line to message_xx_pack function - packLines += QString("\ti += put_array_by_index((const int8_t*)%1, sizeof(%2)*%3, i, msg->payload); // %4\n").arg(fieldName, arrayType, QString::number(arrayLength), fieldText); - // Add decode function for this type - decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName); - arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength)); - - unpackingCode = QString("\n\tmemcpy(r_data, msg->payload%1, sizeof(%2)*%3);\n\treturn sizeof(%2)*%3;").arg(prepends, arrayType, QString::number(arrayLength)); - - unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, %3* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, arrayType, unpackingCode); - // decodeLines += ""; - prepends += QString("+sizeof(%1)*%2").arg(arrayType, QString::number(arrayLength)); - - } - else - // Handle simple types like integers and floats - { - packParameters += ", " + fieldType + " " + fieldName; - packArguments += ", " + messageName + "->" + fieldName; - - // Add field to C structure - cStructLines += QString("\t%1 %2; ///< %3\n").arg(fieldType, fieldName, fieldText); - // Add pack line to message_xx_pack function - packLines += QString("\ti += put_%1_by_index(%2, i, msg->payload); // %3\n").arg(fieldType, fieldName, e2.text()); - // Add decode function for this type - decodeLines += QString("\t%1->%2 = mavlink_msg_%1_get_%2(msg);\n").arg(messageName, fieldName); - } - - - // message length calculation - unsigned element_multiplier = 1; - unsigned element_length = 0; - const struct - { - const char *prefix; - unsigned length; - } length_map[] = { - { "array", 1 }, - { "char", 1 }, - { "uint8", 1 }, - { "int8", 1 }, - { "uint16", 2 }, - { "int16", 2 }, - { "uint32", 4 }, - { "int32", 4 }, - { "uint64", 8 }, - { "int64", 8 }, - { "float", 4 }, - { "double", 8 }, - }; - if (fieldType.contains("[")) - { - element_multiplier = fieldType.split("[").at(1).split("]").first().toInt(); - } - for (unsigned i=0; iERROR: Unable to calculate length for %2 near line %1\nAbort.").arg(QString::number(e.lineNumber()), fieldType)); - } - message_length += element_length; - - // - // QString unpackingCode; - - if (fieldType == "uint8_t_mavlink_version") - { - unpackingCode = QString("\treturn (%1)(msg->payload%2)[0];").arg("uint8_t", prepends); - } - else if (fieldType == "uint8_t" || fieldType == "int8_t") - { - unpackingCode = QString("\treturn (%1)(msg->payload%2)[0];").arg(fieldType, prepends); - } - else if (fieldType == "uint16_t" || fieldType == "int16_t") - { - unpackingCode = QString("\tgeneric_16bit r;\n\tr.b[1] = (msg->payload%1)[0];\n\tr.b[0] = (msg->payload%1)[1];\n\treturn (%2)r.s;").arg(prepends).arg(fieldType); - } - else if (fieldType == "uint32_t" || fieldType == "int32_t") - { - unpackingCode = QString("\tgeneric_32bit r;\n\tr.b[3] = (msg->payload%1)[0];\n\tr.b[2] = (msg->payload%1)[1];\n\tr.b[1] = (msg->payload%1)[2];\n\tr.b[0] = (msg->payload%1)[3];\n\treturn (%2)r.i;").arg(prepends).arg(fieldType); - } - else if (fieldType == "float") - { - unpackingCode = QString("\tgeneric_32bit r;\n\tr.b[3] = (msg->payload%1)[0];\n\tr.b[2] = (msg->payload%1)[1];\n\tr.b[1] = (msg->payload%1)[2];\n\tr.b[0] = (msg->payload%1)[3];\n\treturn (%2)r.f;").arg(prepends).arg(fieldType); - } - else if (fieldType == "uint64_t" || fieldType == "int64_t") - { - unpackingCode = QString("\tgeneric_64bit r;\n\tr.b[7] = (msg->payload%1)[0];\n\tr.b[6] = (msg->payload%1)[1];\n\tr.b[5] = (msg->payload%1)[2];\n\tr.b[4] = (msg->payload%1)[3];\n\tr.b[3] = (msg->payload%1)[4];\n\tr.b[2] = (msg->payload%1)[5];\n\tr.b[1] = (msg->payload%1)[6];\n\tr.b[0] = (msg->payload%1)[7];\n\treturn (%2)r.ll;").arg(prepends).arg(fieldType); - } - else if (fieldType.startsWith("array")) - { - // fieldtype formatis string[n] where n is the number of bytes, extract n from field type string - unpackingCode = QString("\n\tmemcpy(r_data, msg->payload%1, %2);\n\treturn %2;").arg(prepends, fieldType.split("[").at(1).split("]").first()); - } - else if (fieldType.startsWith("string")) - { - // fieldtype formatis string[n] where n is the number of bytes, extract n from field type string - unpackingCode = QString("\n\tstrcpy(r_data, msg->payload%1, %2);\n\treturn %2;").arg(prepends, fieldType.split("[").at(1).split("]").first()); - } - - - // Generate the message decoding function - if (fieldType.contains("uint8_t_mavlink_version")) - { - unpacking += unpackingComment + QString("static inline %1 mavlink_msg_%2_get_%3(const mavlink_message_t* msg)\n{\n%4\n}\n\n").arg("uint8_t", messageName, fieldName, unpackingCode); - decodeLines += ""; - prepends += "+sizeof(uint8_t)"; - } - // Array handling is different from simple types - else if (fieldType.startsWith("array")) - { - unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, int8_t* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, unpackingCode); - decodeLines += ""; - QString arrayLength = QString(fieldType.split("[").at(1).split("]").first()); - prepends += "+" + arrayLength; - } - else if (fieldType.startsWith("string")) - { - unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, char* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, unpackingCode); - decodeLines += ""; - QString arrayLength = QString(fieldType.split("[").at(1).split("]").first()); - prepends += "+" + arrayLength; - } - else if(fieldType.contains('[') && fieldType.contains(']')) - { - // prevent this case from being caught in the following else - } - else - { - unpacking += unpackingComment + QString("static inline %1 mavlink_msg_%2_get_%3(const mavlink_message_t* msg)\n{\n%4\n}\n\n").arg(fieldType, messageName, fieldName, unpackingCode); - decodeLines += ""; - prepends += "+sizeof(" + e2.attribute("type", "void") + ")"; - } - } - f = f.nextSibling(); - } - - if (messageId > highest_message_id) - { - highest_message_id = messageId; - } - message_lengths[messageId] = message_length; - - cStruct = cStruct.arg(cStructName, cStructLines); - lcmStructDefs.append("\n").append(cStruct).append("\n"); - pack = pack.arg(messageName, packParameters, messageName.toUpper(), packLines); - packChan = packChan.arg(messageName, packParameters, messageName.toUpper(), packLines); - encode = encode.arg(messageName).arg(cStructName).arg(packArguments); - decode = decode.arg(messageName).arg(cStructName).arg(decodeLines); - compactSend = compactSend.arg(channelType, messageType, messageName, sendArguments, packParameters); - QString cFile = "// MESSAGE " + messageName.toUpper() + " PACKING\n\n" + idDefine + "\n\n" + cStruct + "\n\n" + arrayDefines + "\n\n" + commentContainer.arg(messageName.toLower(), commentLines) + pack + commentPackChanContainer.arg(messageName.toLower(), commentLines) + packChan + commentEncodeContainer.arg(messageName.toLower()) + encode + "\n" + commentSendContainer.arg(messageName.toLower(), commentLines) + compactSend + "\n" + "// MESSAGE " + messageName.toUpper() + " UNPACKING\n\n" + unpacking + commentDecodeContainer.arg(messageName.toLower()) + decode; - cFiles.append(qMakePair(QString("mavlink_msg_%1.h").arg(messageName), cFile)); - } // Check if tag = message - } // Check if e = NULL - n = n.nextSibling(); - } // While through - n = p; - - } // Check if tag = messages - } // Check if e = NULL - n = n.nextSibling(); - } // While through include and messages - // One up - current node = parent - n = p; - - } // Check if tag = mavlink - } // Check if e = NULL - n = n.nextSibling(); - } // While through root children - - // Add version to main header - - mainHeader += "// MAVLINK VERSION\n\n"; - mainHeader += QString("#ifndef MAVLINK_VERSION\n#define MAVLINK_VERSION %1\n#endif\n\n").arg(mavlinkVersion); - mainHeader += QString("#if (MAVLINK_VERSION == 0)\n#undef MAVLINK_VERSION\n#define MAVLINK_VERSION %1\n#endif\n\n").arg(mavlinkVersion); - - // Add enums to main header - - mainHeader += "// ENUM DEFINITIONS\n\n"; - mainHeader += enums; - mainHeader += "\n"; - - mainHeader += "// MESSAGE DEFINITIONS\n\n"; - // Create directory if it doesn't exist, report result in success - if (!dir.exists()) success = success && dir.mkpath(outputDirName + "/" + messagesDirName); - for (int i = 0; i < cFiles.size(); i++) - { - QFile rawFile(dir.filePath(cFiles.at(i).first)); - bool ok = rawFile.open(QIODevice::WriteOnly | QIODevice::Text); - success = success && ok; - rawFile.write(cFiles.at(i).second.toLatin1()); - rawFile.close(); - mainHeader += includeLine.arg(messagesDirName + "/" + cFiles.at(i).first); - } - - mainHeader += "\n\n// MESSAGE LENGTHS\n\n"; - mainHeader += "#undef MAVLINK_MESSAGE_LENGTHS\n"; - mainHeader += "#define MAVLINK_MESSAGE_LENGTHS { "; - for (int i=0; i - -This file is part of the QGROUNDCONTROL project - - QGROUNDCONTROL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QGROUNDCONTROL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QGROUNDCONTROL. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Definition of class MAVLinkXMLParser - * @author Lorenz Meier - */ - -#ifndef MAVLINKXMLPARSER_H -#define MAVLINKXMLPARSER_H - -#include -#include -#include - -/** - * @brief MAVLink micro air vehicle protocol generator - * - * MAVLink is a generic communication protocol for micro air vehicles. - * for more information, please see the official website. - * @ref http://pixhawk.ethz.ch/software/mavlink/ - **/ -class MAVLinkXMLParser : public QObject -{ - Q_OBJECT -public: - MAVLinkXMLParser(QDomDocument* document, QString outputDirectory, QObject* parent=0); - MAVLinkXMLParser(QString document, QString outputDirectory, QObject* parent=0); - ~MAVLinkXMLParser(); - -public slots: - /** @brief Parse XML and generate C files */ - bool generate(); - -signals: - /** @brief Status message on the parsing */ - void parseState(QString message); - -protected: - QDomDocument* doc; - QString outputDirName; - QString fileName; -}; - -#endif // MAVLINKXMLPARSER_H diff --git a/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.cc b/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.cc deleted file mode 100644 index 199be7a40..000000000 --- a/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.cc +++ /dev/null @@ -1,148 +0,0 @@ -/*===================================================================== - -QGroundControl Open Source Ground Control Station - -(c) 2009 - 2011 QGROUNDCONTROL PROJECT - -This file is part of the QGROUNDCONTROL project - - QGROUNDCONTROL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QGROUNDCONTROL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QGROUNDCONTROL. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Implementation of class MAVLinkXMLParserV10 - * @author Lorenz Meier - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "MAVLinkXMLParserV10.h" - -#include - -MAVLinkXMLParserV10::MAVLinkXMLParserV10(QDomDocument* document, QString outputDirectory, QObject* parent) : QObject(parent), -doc(document), -outputDirName(outputDirectory), -fileName("") -{ -} - -MAVLinkXMLParserV10::MAVLinkXMLParserV10(QString document, QString outputDirectory, QObject* parent) : QObject(parent) -{ - doc = new QDomDocument(); - QFile file(document); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - const QString instanceText(QString::fromUtf8(file.readAll())); - doc->setContent(instanceText); - } - fileName = document; - outputDirName = outputDirectory; -} - -MAVLinkXMLParserV10::~MAVLinkXMLParserV10() -{ -} - -void MAVLinkXMLParserV10::processError(QProcess::ProcessError err) -{ - switch(err) - { - case QProcess::FailedToStart: - emit parseState(tr("Generator failed to start. Please check if the path and command is correct.")); - break; - case QProcess::Crashed: - emit parseState("Generator crashed, This is a generator-related problem. Please upgrade MAVLink generator."); - break; - case QProcess::Timedout: - emit parseState(tr("Generator start timed out, please check if the path and command are correct")); - break; - case QProcess::WriteError: - emit parseState(tr("Could not communicate with generator. Please check if the path and command are correct")); - break; - case QProcess::ReadError: - emit parseState(tr("Could not communicate with generator. Please check if the path and command are correct")); - break; - case QProcess::UnknownError: - default: - emit parseState(tr("Generator error. Please check if the path and command is correct.")); - break; - } -} - -/** - * Generate C-code (C-89 compliant) out of the XML protocol specs. - */ -bool MAVLinkXMLParserV10::generate() -{ - emit parseState(tr("Generator ready.")); -#ifdef Q_OS_WIN - QString generatorCall("files/mavgen.exe"); -#endif -#if (defined Q_OS_MAC) || (defined Q_OS_LINUX) - QString generatorCall("python"); -#endif - QString lang("C"); - QString version("1.0"); - - QStringList arguments; -#if (defined Q_OS_MAC) || (defined Q_OS_LINUX) - // Script is only needed as argument if Python is used, the Py2Exe implicitely knows the script - arguments << QString("%1/libs/mavlink/share/pyshared/pymavlink/generator/mavgen.py").arg(QApplication::applicationDirPath()); -#endif - arguments << QString("--lang=%1").arg(lang); - arguments << QString("--output=%2").arg(outputDirName); - arguments << QString("%3").arg(fileName); - arguments << QString("--wire-protocol=%4").arg(version); - - qDebug() << "Attempted to start" << generatorCall << arguments; - process = new QProcess(this); - process->setProcessChannelMode(QProcess::SeparateChannels); - connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOut())); - connect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStdErr())); - process->start(generatorCall, arguments, QIODevice::ReadWrite); - QString output = QString(process->readAll()); - emit parseState(output); - // Print process status - emit parseState(QString("%1").arg(QString(process->readAllStandardError()))); - emit parseState(QString(process->readAllStandardOutput())); - - process->waitForFinished(20000); - - process->terminate(); - process->kill(); - return true;//result; -} - -void MAVLinkXMLParserV10::readStdOut() -{ - QString out(process->readAllStandardOutput()); - emit parseState(out); -} - -void MAVLinkXMLParserV10::readStdErr() -{ - QString out = QString("%1").arg(QString(process->readAllStandardError())); - emit parseState(out); -} diff --git a/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.h b/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.h deleted file mode 100644 index 05b65c68c..000000000 --- a/src/apps/mavlinkgen/generator/MAVLinkXMLParserV10.h +++ /dev/null @@ -1,84 +0,0 @@ -/*===================================================================== - -QGroundControl Open Source Ground Control Station - -(c) 2009, 2010 QGROUNDCONTROL PROJECT - -This file is part of the QGROUNDCONTROL project - - QGROUNDCONTROL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QGROUNDCONTROL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QGROUNDCONTROL. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Definition of class MAVLinkXMLParserV10 - * @author Lorenz Meier - */ - -#ifndef MAVLINKXMLPARSERV10_H -#define MAVLINKXMLPARSERV10_H - -#include -#include -#include -#include - -#include - -/** - * @brief MAVLink micro air vehicle protocol generator - * - * MAVLink is a generic communication protocol for micro air vehicles. - * for more information, please see the official website. - * @ref http://pixhawk.ethz.ch/software/mavlink/ - **/ -class MAVLinkXMLParserV10 : public QObject -{ - Q_OBJECT -public: - MAVLinkXMLParserV10(QDomDocument* document, QString outputDirectory, QObject* parent=0); - MAVLinkXMLParserV10(QString document, QString outputDirectory, QObject* parent=0); - ~MAVLinkXMLParserV10(); - -public slots: - /** @brief Parse XML and generate C files */ - bool generate(); - - /** @brief Handle process errors */ - void processError(QProcess::ProcessError err); - - /** @brief Redirect standard output */ - void readStdOut(); - /** @brief Redirect standard error output */ - void readStdErr(); - -signals: - /** @brief Status message on the parsing */ - void parseState(QString message); - -protected: -// /** @brief Accumulate the X.25 CRC by adding one char at a time. */ -// void crcAccumulate(uint8_t data, uint16_t *crcAccum); - -// /** @brief Initialize the buffer for the X.25 CRC */ -// void crcInit(uint16_t* crcAccum); - - QDomDocument* doc; - QString outputDirName; - QString fileName; - QProcess* process; -}; - -#endif // MAVLINKXMLPARSERV10_H diff --git a/src/apps/mavlinkgen/images/categories/applications-system.svg b/src/apps/mavlinkgen/images/categories/applications-system.svg deleted file mode 100644 index 9d767742d..000000000 --- a/src/apps/mavlinkgen/images/categories/applications-system.svg +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - System Applications - - - Jakub Steiner - - - http://jimmac.musichall.cz/ - - - system - applications - group - category - admin - root - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/apps/mavlinkgen/images/status/folder-open.svg b/src/apps/mavlinkgen/images/status/folder-open.svg deleted file mode 100644 index 237f6f254..000000000 --- a/src/apps/mavlinkgen/images/status/folder-open.svg +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Folder Icon Accept - 2005-01-31 - - - Jakub Steiner - - - - http://jimmac.musichall.cz - Active state - when files are being dragged to. - - - Novell, Inc. - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/apps/mavlinkgen/license.txt b/src/apps/mavlinkgen/license.txt deleted file mode 100644 index f90060e63..000000000 --- a/src/apps/mavlinkgen/license.txt +++ /dev/null @@ -1,195 +0,0 @@ -This software is published under GNU GENERAL PUBLIC LICENSE 3 - -TERMS AND CONDITIONS -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the Program. - -To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - -To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - - -1. Source Code. - -The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - -The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - -The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - - -2. Basic Permissions. - -All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. - -No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - - -4. Conveying Verbatim Copies. - -You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - - -5. Conveying Modified Source Versions. - -You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - - * a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - * b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. - * c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - * d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - - -6. Conveying Non-Source Forms. - -You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - - * a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - * b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. - * c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - * d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. - * e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - -The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - - -7. Additional Terms. - -“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - - * a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - * b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - * c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - * d) Limiting the use for publicity purposes of names of licensors or authors of the material; or - * e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - * f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - - -8. Termination. - -You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - - -9. Acceptance Not Required for Having Copies. - -You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - - -10. Automatic Licensing of Downstream Recipients. - -Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - - -11. Patents. - -A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - - -12. No Surrender of Others' Freedom. - -If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - - -13. Use with the GNU Affero General Public License. - -Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - - -14. Revised Versions of this License. - -The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - -Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - - -15. Disclaimer of Warranty. - -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - -16. Limitation of Liability. - -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - -17. Interpretation of Sections 15 and 16. - -If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. diff --git a/src/apps/mavlinkgen/main.cc b/src/apps/mavlinkgen/main.cc deleted file mode 100644 index 4a57b3690..000000000 --- a/src/apps/mavlinkgen/main.cc +++ /dev/null @@ -1,46 +0,0 @@ -/*===================================================================== - -PIXHAWK Micro Air Vehicle Flying Robotics Toolkit - -(c) 2009, 2010 PIXHAWK PROJECT - -This file is part of the PIXHAWK project - - PIXHAWK is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PIXHAWK is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PIXHAWK. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Main executable - * @author Lorenz Meier - * - */ - -#include -#include "MAVLinkGen.h" - -/** - * @brief Starts the application - * - * @param argc Number of commandline arguments - * @param argv Commandline arguments - * @return exit code, 0 for normal exit and !=0 for error cases - */ -int main(int argc, char *argv[]) -{ - - MAVLinkGen gen(argc, argv); - return gen.exec(); -} diff --git a/src/apps/mavlinkgen/mavlinkgen.pri b/src/apps/mavlinkgen/mavlinkgen.pri deleted file mode 100644 index a5ef920b5..000000000 --- a/src/apps/mavlinkgen/mavlinkgen.pri +++ /dev/null @@ -1,44 +0,0 @@ -# Third-party includes. -# if you include this file with the commands below into -# your Qt project, you can enable your application -# to generate MAVLink code easily. - -###### EXAMPLE BEGIN - -## Include MAVLink generator -#DEPENDPATH += \ -# src/apps/mavlinkgen -# -#INCLUDEPATH += \ -# src/apps/mavlinkgen -# src/apps/mavlinkgen/ui \ -# src/apps/mavlinkgen/generator -# -#include(src/apps/mavlinkgen/mavlinkgen.pri) - -###### EXAMPLE END - - - -INCLUDEPATH += .\ - ui \ - generator - -FORMS += ui/XMLCommProtocolWidget.ui - -HEADERS += \ - ui/XMLCommProtocolWidget.h \ - generator/MAVLinkXMLParser.h \ - generator/MAVLinkXMLParserV10.h \ - ui/DomItem.h \ - ui/DomModel.h \ - ui/QGCMAVLinkTextEdit.h -SOURCES += \ - ui/XMLCommProtocolWidget.cc \ - ui/DomItem.cc \ - ui/DomModel.cc \ - generator/MAVLinkXMLParser.cc \ - generator/MAVLinkXMLParserV10.cc \ - ui/QGCMAVLinkTextEdit.cc - -RESOURCES += mavlinkgen.qrc diff --git a/src/apps/mavlinkgen/mavlinkgen.pro b/src/apps/mavlinkgen/mavlinkgen.pro deleted file mode 100644 index 278695604..000000000 --- a/src/apps/mavlinkgen/mavlinkgen.pro +++ /dev/null @@ -1,22 +0,0 @@ -# MAVLink code generator -# generates code in several languages for MAVLink encoding/decoding - -QT += svg xml - -TEMPLATE = app -TARGET = mavlinkgen - -LANGUAGE = C++ - -# Widget files (can be included in third-party Qt applications) -include(mavlinkgen.pri) - -# Standalone files -HEADERS += MAVLinkGen.h -win32-msvc2008|win32-msvc2010 { -HEADERS += msinttypes/inttypes.h \ - msinttypes/stdint.h -INCLUDEPATH += msinttypes -} -SOURCES += main.cc \ - MAVLinkGen.cc diff --git a/src/apps/mavlinkgen/mavlinkgen.qrc b/src/apps/mavlinkgen/mavlinkgen.qrc deleted file mode 100644 index 9db933d56..000000000 --- a/src/apps/mavlinkgen/mavlinkgen.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - images/categories/applications-system.svg - images/status/folder-open.svg - - diff --git a/src/apps/mavlinkgen/msinttypes/inttypes.h b/src/apps/mavlinkgen/msinttypes/inttypes.h deleted file mode 100644 index 4b3828a21..000000000 --- a/src/apps/mavlinkgen/msinttypes/inttypes.h +++ /dev/null @@ -1,305 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include "stdint.h" - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - - -#endif // _MSC_INTTYPES_H_ ] diff --git a/src/apps/mavlinkgen/msinttypes/stdint.h b/src/apps/mavlinkgen/msinttypes/stdint.h deleted file mode 100644 index d02608a59..000000000 --- a/src/apps/mavlinkgen/msinttypes/stdint.h +++ /dev/null @@ -1,247 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus -extern "C" { -#endif -# include -#ifdef __cplusplus -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] diff --git a/src/apps/mavlinkgen/template/checksum.h b/src/apps/mavlinkgen/template/checksum.h deleted file mode 100644 index 07bab9102..000000000 --- a/src/apps/mavlinkgen/template/checksum.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CHECKSUM_H_ -#define _CHECKSUM_H_ - -#include "inttypes.h" - - -/** - * - * CALCULATE THE CHECKSUM - * - */ - -#define X25_INIT_CRC 0xffff -#define X25_VALIDATE_CRC 0xf0b8 - -/** - * @brief Accumulate the X.25 CRC by adding one char at a time. - * - * The checksum function adds the hash of one char at a time to the - * 16 bit checksum (uint16_t). - * - * @param data new char to hash - * @param crcAccum the already accumulated checksum - **/ -static inline void crc_accumulate(uint8_t data, uint16_t *crcAccum) -{ - /*Accumulate one byte of data into the CRC*/ - uint8_t tmp; - - tmp=data ^ (uint8_t)(*crcAccum &0xff); - tmp^= (tmp<<4); - *crcAccum = (*crcAccum>>8) ^ (tmp<<8) ^ (tmp <<3) ^ (tmp>>4); -// *crcAccum += data; // super simple to test -} - -/** - * @brief Initiliaze the buffer for the X.25 CRC - * - * @param crcAccum the 16 bit X.25 CRC - */ -static inline void crc_init(uint16_t* crcAccum) -{ - *crcAccum = X25_INIT_CRC; -} - - -/** - * @brief Calculates the X.25 checksum on a byte buffer - * - * @param pBuffer buffer containing the byte array to hash - * @param length length of the byte array - * @return the checksum over the buffer bytes - **/ -static inline uint16_t crc_calculate(uint8_t* pBuffer, int length) -{ - - // For a "message" of length bytes contained in the unsigned char array - // pointed to by pBuffer, calculate the CRC - // crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed - - uint16_t crcTmp; - //uint16_t tmp; - uint8_t* pTmp; - int i; - - pTmp=pBuffer; - - - /* init crcTmp */ - crc_init(&crcTmp); - - for (i = 0; i < length; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - /* This is currently not needed, as only the checksum over payload should be computed - tmp = crcTmp; - crcAccumulate((unsigned char)(~crcTmp & 0xff),&tmp); - crcAccumulate((unsigned char)((~crcTmp>>8)&0xff),&tmp); - *checkConst = tmp; - */ - return(crcTmp); -} - - -/** - * @brief Calculates the X.25 checksum on a msg buffer - * - * @param pMSG buffer containing the msg to hash - * @param length number of bytes to hash - * @return the checksum over the buffer bytes - **/ -static inline uint16_t crc_calculate_msg(mavlink_message_t* pMSG, int length) -{ - - // For a "message" of length bytes contained in the unsigned char array - // pointed to by pBuffer, calculate the CRC - // crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed - - uint16_t crcTmp; - //uint16_t tmp; - uint8_t* pTmp; - int i; - - pTmp=&pMSG->len; - - /* init crcTmp */ - crc_init(&crcTmp); - - for (i = 0; i < 5; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - pTmp=&pMSG->payload[0]; - for (; i < length; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - /* This is currently not needed, as only the checksum over payload should be computed - tmp = crcTmp; - crcAccumulate((unsigned char)(~crcTmp & 0xff),&tmp); - crcAccumulate((unsigned char)((~crcTmp>>8)&0xff),&tmp); - *checkConst = tmp; - */ - return(crcTmp); -} - - - - -#endif /* _CHECKSUM_H_ */ - -#ifdef __cplusplus -} -#endif diff --git a/src/apps/mavlinkgen/template/documentation.dox b/src/apps/mavlinkgen/template/documentation.dox deleted file mode 100644 index 49de0050e..000000000 --- a/src/apps/mavlinkgen/template/documentation.dox +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file - * @brief MAVLink communication protocol - * - * @author Lorenz Meier - * - */ - - -/** - * @mainpage MAVLink API Documentation - * - * @section intro_sec Introduction - * - * This API documentation covers the MAVLink - * protocol developed PIXHAWK project. - * In case you have generated this documentation locally, the most recent version (generated on every commit) - * is also publicly available on the internet. - * - * @sa http://pixhawk.ethz.ch/api/qgroundcontrol/ - Groundstation code base - * @sa http://pixhawk.ethz.ch/api/mavlink - (this) MAVLink communication protocol - * @sa http://pixhawk.ethz.ch/api/imu_autopilot/ - Flight board (ARM MCU) code base - * @sa http://pixhawk.ethz.ch/api/ai_vision - Computer Vision / AI API docs - * - * @section further_sec Further Information - * - * How to run our software and a general overview of the software architecture is documented in the project - * wiki pages. - * - * @sa http://pixhawk.ethz.ch/software/mavlink/ - MAVLink main documentation - * - * See the PIXHAWK website for more information. - * - * @section usage_sec Doxygen Usage - * - * You can exclude files from being parsed into this Doxygen documentation - * by adding them to the EXCLUDE list in the file in embedded/cmake/doc/api/doxy.config.in. - * - * - * - **/ diff --git a/src/apps/mavlinkgen/template/mavlink_checksum.h b/src/apps/mavlinkgen/template/mavlink_checksum.h deleted file mode 100644 index fdcee99d1..000000000 --- a/src/apps/mavlinkgen/template/mavlink_checksum.h +++ /dev/null @@ -1,183 +0,0 @@ -/** @file - * @brief MAVLink comm protocol checksum routines. - * @see http://qgroundcontrol.org/mavlink/ - * Edited on Monday, August 8 2011 - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CHECKSUM_H_ -#define _CHECKSUM_H_ - -#include "inttypes.h" - - -/** - * - * CALCULATE THE CHECKSUM - * - */ - -#define X25_INIT_CRC 0xffff -#define X25_VALIDATE_CRC 0xf0b8 - -/** - * @brief Accumulate the X.25 CRC by adding one char at a time. - * - * The checksum function adds the hash of one char at a time to the - * 16 bit checksum (uint16_t). - * - * @param data new char to hash - * @param crcAccum the already accumulated checksum - **/ -static inline void crc_accumulate(uint8_t data, uint16_t *crcAccum) -{ - /*Accumulate one byte of data into the CRC*/ - uint8_t tmp; - - tmp=data ^ (uint8_t)(*crcAccum &0xff); - tmp^= (tmp<<4); - *crcAccum = (*crcAccum>>8) ^ (tmp<<8) ^ (tmp <<3) ^ (tmp>>4); -// *crcAccum += data; // super simple to test -} - -/** - * @brief Initiliaze the buffer for the X.25 CRC - * - * @param crcAccum the 16 bit X.25 CRC - */ -static inline void crc_init(uint16_t* crcAccum) -{ - *crcAccum = X25_INIT_CRC; -} - -/** - * @brief Initiliaze the buffer for the X.25 CRC to a specified value - * - * @param crcAccum the 16 bit X.25 CRC - */ -static inline void crc_init2(uint16_t* crcAccum, uint16_t crcValue) -{ - *crcAccum = crcValue; -} - - - -/** - * @brief Calculates the X.25 checksum on a byte buffer - * - * @param pBuffer buffer containing the byte array to hash - * @param length length of the byte array - * @return the checksum over the buffer bytes - **/ -static inline uint16_t crc_calculate(uint8_t* pBuffer, int length) -{ - - // For a "message" of length bytes contained in the unsigned char array - // pointed to by pBuffer, calculate the CRC - // crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed - - uint16_t crcTmp; - //uint16_t tmp; - uint8_t* pTmp; - int i; - - pTmp=pBuffer; - - - /* init crcTmp */ - crc_init(&crcTmp); - - for (i = 0; i < length; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - /* This is currently not needed, as only the checksum over payload should be computed - tmp = crcTmp; - crcAccumulate((unsigned char)(~crcTmp & 0xff),&tmp); - crcAccumulate((unsigned char)((~crcTmp>>8)&0xff),&tmp); - *checkConst = tmp; - */ - return(crcTmp); -} - -/** - * @brief Calculates the X.25 checksum on a byte buffer - * - * @param pBuffer buffer containing the byte array to hash - * @param length length of the byte array - * @return the checksum over the buffer bytes - **/ -static inline uint16_t crc_calculate_mem(uint8_t *pBuffer, uint16_t *crcTmp, int length) -{ - - // For a "message" of length bytes contained in the unsigned char array - // pointed to by pBuffer, calculate the CRC - // crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed - - //uint16_t tmp; - //uint8_t* pTmp; - int i; - -// pTmp=pBuffer; - - for (i = 0; i < length; i++){ - crc_accumulate(*pBuffer++, crcTmp); - } - - return(*crcTmp); -} - - -/** - * @brief Calculates the X.25 checksum on a msg buffer - * - * @param pMSG buffer containing the msg to hash - * @param length number of bytes to hash - * @return the checksum over the buffer bytes - **/ -static inline uint16_t crc_calculate_msg(mavlink_message_t* pMSG, int length) -{ - - // For a "message" of length bytes contained in the unsigned char array - // pointed to by pBuffer, calculate the CRC - // crcCalculate(unsigned char* pBuffer, int length, unsigned short* checkConst) < not needed - - uint16_t crcTmp; - //uint16_t tmp; - uint8_t* pTmp; - int i; - - pTmp=&pMSG->len; - - /* init crcTmp */ - crc_init(&crcTmp); - - for (i = 0; i < 5; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - pTmp=&pMSG->payload[0]; - for (; i < length; i++){ - crc_accumulate(*pTmp++, &crcTmp); - } - - /* This is currently not needed, as only the checksum over payload should be computed - tmp = crcTmp; - crcAccumulate((unsigned char)(~crcTmp & 0xff),&tmp); - crcAccumulate((unsigned char)((~crcTmp>>8)&0xff),&tmp); - *checkConst = tmp; - */ - return(crcTmp); -} - - - - -#endif /* _CHECKSUM_H_ */ - -#ifdef __cplusplus -} -#endif diff --git a/src/apps/mavlinkgen/template/mavlink_data.h b/src/apps/mavlinkgen/template/mavlink_data.h deleted file mode 100644 index 17c88cc2a..000000000 --- a/src/apps/mavlinkgen/template/mavlink_data.h +++ /dev/null @@ -1,21 +0,0 @@ -/** @file - * @brief Main MAVLink comm protocol data. - * @see http://qgroundcontrol.org/mavlink/ - * Edited on Monday, August 8 2011 - */ - -#ifndef _ML_DATA_H_ -#define _ML_DATA_H_ - -#include "mavlink_types.h" - -#ifdef MAVLINK_CHECK_LENGTH -const uint8_t MAVLINK_CONST mavlink_msg_lengths[256] = MAVLINK_MESSAGE_LENGTHS; -#endif - -const uint8_t MAVLINK_CONST mavlink_msg_keys[256] = MAVLINK_MESSAGE_KEYS; - -mavlink_status_t m_mavlink_status[MAVLINK_COMM_NB]; -mavlink_message_t m_mavlink_message[MAVLINK_COMM_NB]; -mavlink_system_t mavlink_system; -#endif \ No newline at end of file diff --git a/src/apps/mavlinkgen/template/mavlink_options.h b/src/apps/mavlinkgen/template/mavlink_options.h deleted file mode 100644 index 550a85ae5..000000000 --- a/src/apps/mavlinkgen/template/mavlink_options.h +++ /dev/null @@ -1,135 +0,0 @@ -/** @file - * @brief MAVLink comm protocol option constants. - * @see http://qgroundcontrol.org/mavlink/ - * Edited on Monday, August 8 2011 - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ML_OPTIONS_H_ -#define _ML_OPTIONS_H_ - - -/** - * - * Receive message length check option. On receive verify the length field - * as soon as the message ID field is received. Requires a 256 byte const - * table. Comment out the define to leave out the table and code to check it. - * - */ -//#define MAVLINK_CHECK_LENGTH - -/** - * - * Receive message buffer option. This option should be used only when the - * side effects are understood but allows the underlying program access to - * the internal recieve buffer - eliminating the usual double buffering. It - * also REQUIRES changes in the return type of mavlink_parse_char so only - * enable if you make the changes required. Default DISABLED. - * - */ -//#define MAVLINK_STATIC_BUFFER - -/** - * - * Receive message buffers option. This option defines how many msg buffers - * mavlink will define, and thereby how many links it can support. A default - * will be supplied if the symbol is not pre-defined, dependant on the make - * envionment. The default is 16 for a recognised OS envionment and 1 - * otherwise. - * - */ -#if !((defined MAVLINK_COMM_NB) | (MAVLINK_COMM_NB < 1)) -#undef MAVLINK_COMM_NB - #if (defined linux) | (defined __linux) | (defined __MACH__) | (defined _WIN32) | (defined __APPLE__) - #define MAVLINK_COMM_NB 16 - #else - #define MAVLINK_COMM_NB 1 - #endif -#endif - - -/** - * - * Data relization option. This option controls inclusion of the file - * mavlink_data.h in the current compile unit - thus defining mavlink's - * variables. Default is ON (not defined) because typically mavlink.h is only - * included once in a system but if it was used in two files there would - * be duplicate variables at link time. Normal practice would be to define - * this symbol outside of this file as defining it here will cause missing - * symbols at link time. In other words in the first file to include mavlink.h - * do not define this sybol, then define this symbol in all other files before - * including mavlink.h - * - */ -//#define MAVLINK_NO_DATA -#ifdef MAVLINK_NO_DATA - #undef MAVLINK_DATA -#else - #define MAVLINK_DATA -#endif - -/** - * - * Custom data const data relization and access options. - * This define is placed in the form - * const uint8_t MAVLINK_CONST name[] = { ... }; - * for the keys table and (if applicable) lengths table to tell the compiler - * were to put the data. The access option is placed in the form - * variable = MAVLINK_CONST_READ( name[i] ); - * in order to allow custom read function's or accessors. - * By default MAVLINK_CONST is defined as nothing and MAVLINK_CONST_READ as - * MAVLINK_CONST_READ( a ) a - * These symbols are only defined if not already defined allowing this file - * to remain unchanged while the actual definitions are maintained in external - * files. - * - */ -#ifndef MAVLINK_CONST -#define MAVLINK_CONST -#endif -#ifndef MAVLINK_CONST_READ -#define MAVLINK_CONST_READ( a ) a -#endif - - -/** - * - * Convience functions. These are all in one send functions that are very - * easy to use. Just define the symbol MAVLINK_USE_CONVENIENCE_FUNCTIONS. - * These functions also support a buffer check, to ensure there is enough - * space in your comm buffer that the function would not block - it could - * also be used as the basis of a MUTEX. This is implemented in the send - * function as a macro with two arguments, first the comm chan number and - * the message length in the form - * MAVLINK_BUFFER_CHECK_START( chan, MAVLINK_MSG_ID_LEN ) - * followed by the function code and then - * MAVLINK_BUFFER_CHECK_START - * Note that there are no terminators on these statements to allow for - * code nesting or other constructs. Default value for both is empty. - * A sugested implementation is shown below and the symbols will be defined - * only if they are not allready. - * - * if ( serial_space( chan ) > len ) { // serial_space returns available space - * ..... code that creates message - * } - * - * #define MAVLINK_BUFFER_CHECK_START( c, l ) if ( serial_space( c ) > l ) { - * #define MAVLINK_BUFFER_CHECK_END } - * - */ -//#define MAVLINK_USE_CONVENIENCE_FUNCTIONS -#ifndef MAVLINK_BUFFER_CHECK_START -#define MAVLINK_BUFFER_CHECK_START( c, l ) ; -#endif -#ifndef MAVLINK_BUFFER_CHECK_END -#define MAVLINK_BUFFER_CHECK_END ; -#endif - -#endif /* _ML_OPTIONS_H_ */ - -#ifdef __cplusplus -} -#endif diff --git a/src/apps/mavlinkgen/template/mavlink_protocol.h b/src/apps/mavlinkgen/template/mavlink_protocol.h deleted file mode 100644 index 8cf62f115..000000000 --- a/src/apps/mavlinkgen/template/mavlink_protocol.h +++ /dev/null @@ -1,423 +0,0 @@ -/** @file - * @brief Main MAVLink comm protocol routines. - * @see http://qgroundcontrol.org/mavlink/ - * Edited on Monday, August 8 2011 - */ - -#ifndef _MAVLINK_PROTOCOL_H_ -#define _MAVLINK_PROTOCOL_H_ - -#include "mavlink_types.h" - -#include "mavlink_checksum.h" - -#ifdef MAVLINK_CHECK_LENGTH -extern const uint8_t MAVLINK_CONST mavlink_msg_lengths[256]; -#endif - -extern const uint8_t MAVLINK_CONST mavlink_msg_keys[256]; - -extern mavlink_status_t m_mavlink_status[MAVLINK_COMM_NB]; -extern mavlink_message_t m_mavlink_message[MAVLINK_COMM_NB]; -extern mavlink_system_t mavlink_system; - - -/** - * @brief Initialize the communication stack - * - * This function has to be called before using commParseBuffer() to initialize the different status registers. - * - * @return Will initialize the different buffers and status registers. - */ -static void mavlink_parse_state_initialize(mavlink_status_t* initStatus) -{ - if ((initStatus->parse_state <= MAVLINK_PARSE_STATE_UNINIT) || (initStatus->parse_state > MAVLINK_PARSE_STATE_GOT_CRC1)) - { - initStatus->ck_a = 0; - initStatus->ck_b = 0; - initStatus->msg_received = 0; - initStatus->buffer_overrun = 0; - initStatus->parse_error = 0; - initStatus->parse_state = MAVLINK_PARSE_STATE_UNINIT; - initStatus->packet_idx = 0; - initStatus->packet_rx_drop_count = 0; - initStatus->packet_rx_success_count = 0; - initStatus->current_rx_seq = 0; - initStatus->current_tx_seq = 0; - } -} - -static inline mavlink_status_t* mavlink_get_channel_status(uint8_t chan) -{ - - return &m_mavlink_status[chan]; -} - -/** - * @brief Finalize a MAVLink message with MAVLINK_COMM_0 as default channel - * - * This function calculates the checksum and sets length and aircraft id correctly. - * It assumes that the message id and the payload are already correctly set. - * - * @warning This function implicitely assumes the message is sent over channel zero. - * if the message is sent over a different channel it will reach the receiver - * without error, BUT the sequence number might be wrong due to the wrong - * channel sequence counter. This will result is wrongly reported excessive - * packet loss. Please use @see mavlink_{pack|encode}_headerless and then - * @see mavlink_finalize_message_chan before sending for a correct channel - * assignment. Please note that the mavlink_msg_xxx_pack and encode functions - * assign channel zero as default and thus induce possible loss counter errors.\ - * They have been left to ensure code compatibility. - * - * @see mavlink_finalize_message_chan - * @param msg Message to finalize - * @param system_id Id of the sending (this) system, 1-127 - * @param length Message length, usually just the counter incremented while packing the message - */ -static inline uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint16_t length) -{ - // This code part is the same for all messages; - uint8_t key; - msg->len = length; - msg->sysid = system_id; - msg->compid = component_id; - // One sequence number per component - msg->seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq; - mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq+1; - msg->ck = crc_calculate_msg(msg, length + MAVLINK_CORE_HEADER_LEN); - key = MAVLINK_CONST_READ( mavlink_msg_keys[msg->msgid] ); - crc_accumulate( key, &msg->ck ); /// include key in X25 checksum - - return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES; -} - -/** - * @brief Finalize a MAVLink message with channel assignment - * - * This function calculates the checksum and sets length and aircraft id correctly. - * It assumes that the message id and the payload are already correctly set. This function - * can also be used if the message header has already been written before (as in mavlink_msg_xxx_pack - * instead of mavlink_msg_xxx_pack_headerless), it just introduces little extra overhead. - * - * @param msg Message to finalize - * @param system_id Id of the sending (this) system, 1-127 - * @param length Message length, usually just the counter incremented while packing the message - */ -static inline uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint8_t chan, uint16_t length) -{ - // This code part is the same for all messages; - uint8_t key; - msg->len = length; - msg->sysid = system_id; - msg->compid = component_id; - // One sequence number per component - msg->seq = mavlink_get_channel_status(chan)->current_tx_seq; - mavlink_get_channel_status(chan)->current_tx_seq = mavlink_get_channel_status(chan)->current_tx_seq+1; - msg->ck = crc_calculate_msg(msg, length + MAVLINK_CORE_HEADER_LEN); - key = MAVLINK_CONST_READ( mavlink_msg_keys[msg->msgid] ); - crc_accumulate( key, &msg->ck ); /// include key in X25 checksum - - return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES; -} - -/** - * @brief Pack a message to send it over a serial byte stream - */ -static inline uint16_t mavlink_msg_to_send_buffer(uint8_t* buffer, const mavlink_message_t* msg) -{ - *(buffer+0) = MAVLINK_STX; ///< Start transmit -// memcpy((buffer+1), msg, msg->len + MAVLINK_CORE_HEADER_LEN); ///< Core header plus payload - memcpy((buffer+1), &msg->len, MAVLINK_CORE_HEADER_LEN); ///< Core header - memcpy((buffer+1+MAVLINK_CORE_HEADER_LEN), &msg->payload[0], msg->len); ///< payload - *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 1) = msg->ck_a; - *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 2) = msg->ck_b; - return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES; -// return 0; -} - -/** - * @brief Get the required buffer size for this message - */ -static inline uint16_t mavlink_msg_get_send_buffer_length(const mavlink_message_t* msg) -{ - return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES; -} - -union checksum_ { - uint16_t s; - uint8_t c[2]; -}; - -static inline void mavlink_start_checksum(mavlink_message_t* msg) -{ - crc_init(&msg->ck); -} - -static inline void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c) -{ - crc_accumulate(c, &msg->ck); -} - -/** - * This is a convenience function which handles the complete MAVLink parsing. - * the function will parse one byte at a time and return the complete packet once - * it could be successfully decoded. Checksum and other failures will be silently - * ignored. - * - * @param chan ID of the current channel. This allows to parse different channels with this function. - * a channel is not a physical message channel like a serial port, but a logic partition of - * the communication streams in this case. COMM_NB is the limit for the number of channels - * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows - * @param c The char to barse - * - * @param returnMsg NULL if no message could be decoded, the message data else - * @return 0 if no message could be decoded, 1 else - * - * A typical use scenario of this function call is: - * - * @code - * #include // For fixed-width uint8_t type - * - * mavlink_message_t msg; - * int chan = 0; - * - * - * while(serial.bytesAvailable > 0) - * { - * uint8_t byte = serial.getNextByte(); - * if (mavlink_parse_char(chan, byte, &msg)) - * { - * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); - * } - * } - * - * - * @endcode - */ -#ifdef MAVLINK_STATIC_BUFFER -static inline mavlink_message_t* mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) -#else -static inline int16_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) -#endif -{ - // Initializes only once, values keep unchanged after first initialization - mavlink_parse_state_initialize(mavlink_get_channel_status(chan)); - - mavlink_message_t* rxmsg = &m_mavlink_message[chan]; ///< The currently decoded message - mavlink_status_t* status = mavlink_get_channel_status(chan); ///< The current decode status - int bufferIndex = 0; - - status->msg_received = 0; - - switch (status->parse_state) - { - case MAVLINK_PARSE_STATE_UNINIT: - case MAVLINK_PARSE_STATE_IDLE: - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - break; - - case MAVLINK_PARSE_STATE_GOT_STX: - if (status->msg_received) - { - status->buffer_overrun++; - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - } - else - { - // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2 - rxmsg->len = c; - status->packet_idx = 0; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_LENGTH; - } - break; - - case MAVLINK_PARSE_STATE_GOT_LENGTH: - rxmsg->seq = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_SEQ; - break; - - case MAVLINK_PARSE_STATE_GOT_SEQ: - rxmsg->sysid = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_SYSID; - break; - - case MAVLINK_PARSE_STATE_GOT_SYSID: - rxmsg->compid = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPID; - break; - - case MAVLINK_PARSE_STATE_GOT_COMPID: - rxmsg->msgid = c; - mavlink_update_checksum(rxmsg, c); -#ifdef MAVLINK_CHECK_LENGTH - if (rxmsg->len != MAVLINK_CONST_READ( mavlink_msg_lengths[c] ) ) - { - status->parse_state = MAVLINK_PARSE_STATE_IDLE; // abort, not going to understand it anyway - break; - } else ; -#endif - if (rxmsg->len == 0) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD; - } - else - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID; - } - break; - - case MAVLINK_PARSE_STATE_GOT_MSGID: - rxmsg->payload[status->packet_idx++] = c; - mavlink_update_checksum(rxmsg, c); - if (status->packet_idx == rxmsg->len) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD; - mavlink_update_checksum(rxmsg, - MAVLINK_CONST_READ( mavlink_msg_keys[rxmsg->msgid] )); - } - break; - - case MAVLINK_PARSE_STATE_GOT_PAYLOAD: - if (c != rxmsg->ck_a) - { - // Check first checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - } - else - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1; - } - break; - - case MAVLINK_PARSE_STATE_GOT_CRC1: - if (c != rxmsg->ck_b) - {// Check second checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - } - else - { - // Successfully got message - status->msg_received = 1; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if ( r_message != NULL ) - memcpy(r_message, rxmsg, sizeof(mavlink_message_t)); - else ; - } - break; - } - - bufferIndex++; - // If a message has been sucessfully decoded, check index - if (status->msg_received == 1) - { - //while(status->current_seq != rxmsg->seq) - //{ - // status->packet_rx_drop_count++; - // status->current_seq++; - //} - status->current_rx_seq = rxmsg->seq; - // Initial condition: If no packet has been received so far, drop count is undefined - if (status->packet_rx_success_count == 0) status->packet_rx_drop_count = 0; - // Count this packet as received - status->packet_rx_success_count++; - } - - r_mavlink_status->current_rx_seq = status->current_rx_seq+1; - r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count; - r_mavlink_status->packet_rx_drop_count = status->parse_error; - status->parse_error = 0; -#ifdef MAVLINK_STATIC_BUFFER - if (status->msg_received == 1) - { - if ( r_message != NULL ) - return r_message; - else return rxmsg; - } else return NULL; -#else - if (status->msg_received == 1) - return 1; - else return 0; -#endif -} - -#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS - -// To make MAVLink work on your MCU, define a similar function - -/* - -#include "mavlink_types.h" - -void comm_send_ch(mavlink_channel_t chan, uint8_t ch) -{ - if (chan == MAVLINK_COMM_0) - { - uart0_transmit(ch); - } - if (chan == MAVLINK_COMM_1) - { - uart1_transmit(ch); - } -} - - -static inline void mavlink_send_msg(mavlink_channel_t chan, mavlink_message_t* msg) -{ - // ARM7 MCU board implementation - // Create pointer on message struct - // Send STX - comm_send_ch(chan, MAVLINK_STX); - comm_send_ch(chan, msg->len); - comm_send_ch(chan, msg->seq); - comm_send_ch(chan, msg->sysid); - comm_send_ch(chan, msg->compid); - comm_send_ch(chan, msg->msgid); - for(uint16_t i = 0; i < msg->len; i++) - { - comm_send_ch(chan, msg->payload[i]); - } - comm_send_ch(chan, msg->ck_a); - comm_send_ch(chan, msg->ck_b); -} - -static inline void mavlink_send_mem(mavlink_channel_t chan, (uint8_t *)mem, uint8_t num) -{ - // ARM7 MCU board implementation - // Create pointer on message struct - // Send STX - for(uint16_t i = 0; i < num; i++) - { - comm_send_ch( chan, mem[i] ); - } -} - */ -static inline void mavlink_send_uart(mavlink_channel_t chan, mavlink_message_t* msg); -static inline void mavlink_send_mem(mavlink_channel_t chan, uint8_t *mem, uint16_t num); -#define mavlink_send_msg( a, b ) mavlink_send_uart( a, b ) -#endif - -#endif /* _MAVLINK_PROTOCOL_H_ */ diff --git a/src/apps/mavlinkgen/template/mavlink_types.h b/src/apps/mavlinkgen/template/mavlink_types.h deleted file mode 100644 index 77b2e2409..000000000 --- a/src/apps/mavlinkgen/template/mavlink_types.h +++ /dev/null @@ -1,120 +0,0 @@ -/** @file - * @brief MAVLink comm protocol enumerations / structures / constants. - * @see http://qgroundcontrol.org/mavlink/ - * Edited on Monday, August 8 2011 - */ - -#ifndef MAVLINK_TYPES_H_ -#define MAVLINK_TYPES_H_ - -#include "inttypes.h" - -#define MAVLINK_STX 0xD5 ///< Packet start sign -#define MAVLINK_STX_LEN 1 ///< Length of start sign -#define MAVLINK_MAX_PAYLOAD_LEN 255 ///< Maximum payload length - -#define MAVLINK_CORE_HEADER_LEN 5 ///< Length of core header (of the comm. layer): message length (1 byte) + message sequence (1 byte) + message system id (1 byte) + message component id (1 byte) + message type id (1 byte) -#define MAVLINK_NUM_HEADER_BYTES (MAVLINK_CORE_HEADER_LEN + MAVLINK_STX_LEN) ///< Length of all header bytes, including core and checksum -#define MAVLINK_NUM_CHECKSUM_BYTES 2 -#define MAVLINK_NUM_NON_PAYLOAD_BYTES (MAVLINK_NUM_HEADER_BYTES + MAVLINK_NUM_CHECKSUM_BYTES) -#define MAVLINK_NUM_NON_STX_PAYLOAD_BYTES (MAVLINK_NUM_NON_PAYLOAD_BYTES - MAVLINK_STX_LEN) - -#define MAVLINK_MAX_PACKET_LEN (MAVLINK_MAX_PAYLOAD_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) ///< Maximum packet length -//#define MAVLINK_MAX_DATA_LEN MAVLINK_MAX_PACKET_LEN - MAVLINK_STX_LEN - -typedef struct __mavlink_system -{ - uint8_t sysid; ///< Used by the MAVLink message_xx_send() convenience function - uint8_t compid; ///< Used by the MAVLink message_xx_send() convenience function - uint8_t type; ///< Unused, can be used by user to store the system's type - uint8_t state; ///< Unused, can be used by user to store the system's state - uint8_t mode; ///< Unused, can be used by user to store the system's mode - uint8_t nav_mode; ///< Unused, can be used by user to store the system's navigation mode -} mavlink_system_t; - -typedef struct __mavlink_message -{ - union - { - uint16_t ck; ///< Checksum word - struct - { - uint8_t ck_a; ///< Checksum low byte - uint8_t ck_b; ///< Checksum high byte - }; - }; - uint8_t STX; ///< start of packet marker - uint8_t len; ///< Length of payload - uint8_t seq; ///< Sequence of packet - uint8_t sysid; ///< ID of message sender system/aircraft - uint8_t compid; ///< ID of the message sender component - uint8_t msgid; ///< ID of message in payload - uint8_t payload[MAVLINK_MAX_PAYLOAD_LEN]; ///< Payload data, ALIGNMENT IMPORTANT ON MCU -} mavlink_message_t; - -typedef struct __mavlink_header -{ - union - { - uint16_t ck; ///< Checksum word - struct - { - uint8_t ck_a; ///< Checksum low byte - uint8_t ck_b; ///< Checksum high byte - }; - }; - uint8_t STX; ///< start of packet marker - uint8_t len; ///< Length of payload - uint8_t seq; ///< Sequence of packet - uint8_t sysid; ///< ID of message sender system/aircraft - uint8_t compid; ///< ID of the message sender component - uint8_t msgid; ///< ID of message in payload -} mavlink_header_t; - -typedef enum -{ - MAVLINK_COMM_0, - MAVLINK_COMM_1, - MAVLINK_COMM_2, - MAVLINK_COMM_3, - MAVLINK_COMM_NB, - MAVLINK_COMM_NB_HIGH = 16 -} mavlink_channel_t; - -typedef enum -{ - MAVLINK_PARSE_STATE_UNINIT=0, - MAVLINK_PARSE_STATE_IDLE, - MAVLINK_PARSE_STATE_GOT_STX, - MAVLINK_PARSE_STATE_GOT_SEQ, - MAVLINK_PARSE_STATE_GOT_LENGTH, - MAVLINK_PARSE_STATE_GOT_SYSID, - MAVLINK_PARSE_STATE_GOT_COMPID, - MAVLINK_PARSE_STATE_GOT_MSGID, - MAVLINK_PARSE_STATE_GOT_PAYLOAD, - MAVLINK_PARSE_STATE_GOT_CRC1 -} mavlink_parse_state_t; ///< The state machine for the comm parser - -typedef struct __mavlink_status -{ - union - { - uint16_t ck; ///< Checksum word - struct - { - uint8_t ck_a; ///< Checksum low byte - uint8_t ck_b; ///< Checksum high byte - }; - }; - uint8_t msg_received; ///< Number of received messages - uint8_t buffer_overrun; ///< Number of buffer overruns - uint8_t parse_error; ///< Number of parse errors - mavlink_parse_state_t parse_state; ///< Parsing state machine - uint8_t packet_idx; ///< Index in current packet - uint8_t current_rx_seq; ///< Sequence number of last packet received - uint8_t current_tx_seq; ///< Sequence number of last packet sent - uint16_t packet_rx_success_count; ///< Received packets - uint16_t packet_rx_drop_count; ///< Number of packet drops -} mavlink_status_t; - -#endif /* MAVLINK_TYPES_H_ */ diff --git a/src/apps/mavlinkgen/template/protocol.h b/src/apps/mavlinkgen/template/protocol.h deleted file mode 100644 index a45993e69..000000000 --- a/src/apps/mavlinkgen/template/protocol.h +++ /dev/null @@ -1,439 +0,0 @@ -#ifndef _MAVLINK_PROTOCOL_H_ -#define _MAVLINK_PROTOCOL_H_ - -#include "string.h" -#include "mavlink_types.h" - -#include "checksum.h" - -/** - * @brief Initialize the communication stack - * - * This function has to be called before using commParseBuffer() to initialize the different status registers. - * - * @return Will initialize the different buffers and status registers. - */ -static void mavlink_parse_state_initialize(mavlink_status_t* initStatus) -{ - if ((initStatus->parse_state <= MAVLINK_PARSE_STATE_UNINIT) || (initStatus->parse_state > MAVLINK_PARSE_STATE_GOT_CRC1)) - { - initStatus->ck_a = 0; - initStatus->ck_b = 0; - initStatus->msg_received = 0; - initStatus->buffer_overrun = 0; - initStatus->parse_error = 0; - initStatus->parse_state = MAVLINK_PARSE_STATE_UNINIT; - initStatus->packet_idx = 0; - initStatus->packet_rx_drop_count = 0; - initStatus->packet_rx_success_count = 0; - initStatus->current_rx_seq = 0; - initStatus->current_tx_seq = 0; - } -} - -static inline mavlink_status_t* mavlink_get_channel_status(uint8_t chan) -{ -#if (defined linux) | (defined __linux) | (defined __MACH__) | (defined _WIN32) - static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NB_HIGH]; -#else - static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NB]; -#endif - - return &m_mavlink_status[chan]; -} - -/** - * @brief Finalize a MAVLink message with MAVLINK_COMM_0 as default channel - * - * This function calculates the checksum and sets length and aircraft id correctly. - * It assumes that the message id and the payload are already correctly set. - * - * @warning This function implicitely assumes the message is sent over channel zero. - * if the message is sent over a different channel it will reach the receiver - * without error, BUT the sequence number might be wrong due to the wrong - * channel sequence counter. This will result is wrongly reported excessive - * packet loss. Please use @see mavlink_{pack|encode}_headerless and then - * @see mavlink_finalize_message_chan before sending for a correct channel - * assignment. Please note that the mavlink_msg_xxx_pack and encode functions - * assign channel zero as default and thus induce possible loss counter errors.\ - * They have been left to ensure code compatibility. - * - * @see mavlink_finalize_message_chan - * @param msg Message to finalize - * @param system_id Id of the sending (this) system, 1-127 - * @param length Message length, usually just the counter incremented while packing the message - */ -static inline uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint16_t length) -{ - // This code part is the same for all messages; - uint16_t checksum; - msg->len = length; - msg->sysid = system_id; - msg->compid = component_id; - // One sequence number per component - msg->seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq; - mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq+1; -// checksum = crc_calculate((uint8_t*)((void*)msg), length + MAVLINK_CORE_HEADER_LEN); - checksum = crc_calculate_msg(msg, length + MAVLINK_CORE_HEADER_LEN); - msg->ck_a = (uint8_t)(checksum & 0xFF); ///< High byte - msg->ck_b = (uint8_t)(checksum >> 8); ///< Low byte - - return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES; -} - -/** - * @brief Finalize a MAVLink message with channel assignment - * - * This function calculates the checksum and sets length and aircraft id correctly. - * It assumes that the message id and the payload are already correctly set. This function - * can also be used if the message header has already been written before (as in mavlink_msg_xxx_pack - * instead of mavlink_msg_xxx_pack_headerless), it just introduces little extra overhead. - * - * @param msg Message to finalize - * @param system_id Id of the sending (this) system, 1-127 - * @param length Message length, usually just the counter incremented while packing the message - */ -static inline uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint8_t chan, uint16_t length) -{ - // This code part is the same for all messages; - uint16_t checksum; - msg->len = length; - msg->sysid = system_id; - msg->compid = component_id; - // One sequence number per component - msg->seq = mavlink_get_channel_status(chan)->current_tx_seq; - mavlink_get_channel_status(chan)->current_tx_seq = mavlink_get_channel_status(chan)->current_tx_seq+1; -// checksum = crc_calculate((uint8_t*)((void*)msg), length + MAVLINK_CORE_HEADER_LEN); - checksum = crc_calculate_msg(msg, length + MAVLINK_CORE_HEADER_LEN); - msg->ck_a = (uint8_t)(checksum & 0xFF); ///< High byte - msg->ck_b = (uint8_t)(checksum >> 8); ///< Low byte - - return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES; -} - -/** - * @brief Pack a message to send it over a serial byte stream - */ -static inline uint16_t mavlink_msg_to_send_buffer(uint8_t* buffer, const mavlink_message_t* msg) -{ - *(buffer+0) = MAVLINK_STX; ///< Start transmit -// memcpy((buffer+1), msg, msg->len + MAVLINK_CORE_HEADER_LEN); ///< Core header plus payload - memcpy((buffer+1), &msg->len, MAVLINK_CORE_HEADER_LEN); ///< Core header - memcpy((buffer+1+MAVLINK_CORE_HEADER_LEN), &msg->payload[0], msg->len); ///< payload - *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 1) = msg->ck_a; - *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 2) = msg->ck_b; - return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES; -// return 0; -} - -/** - * @brief Get the required buffer size for this message - */ -static inline uint16_t mavlink_msg_get_send_buffer_length(const mavlink_message_t* msg) -{ - return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES; -} - -union checksum_ { - uint16_t s; - uint8_t c[2]; -}; - -union __mavlink_bitfield { - uint8_t uint8; - int8_t int8; - uint16_t uint16; - int16_t int16; - uint32_t uint32; - int32_t int32; -}; - - -static inline void mavlink_start_checksum(mavlink_message_t* msg) -{ - union checksum_ ck; - crc_init(&(ck.s)); - msg->ck_a = ck.c[0]; - msg->ck_b = ck.c[1]; -} - -static inline void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c) -{ - union checksum_ ck; - ck.c[0] = msg->ck_a; - ck.c[1] = msg->ck_b; - crc_accumulate(c, &(ck.s)); - msg->ck_a = ck.c[0]; - msg->ck_b = ck.c[1]; -} - -/** - * This is a convenience function which handles the complete MAVLink parsing. - * the function will parse one byte at a time and return the complete packet once - * it could be successfully decoded. Checksum and other failures will be silently - * ignored. - * - * @param chan ID of the current channel. This allows to parse different channels with this function. - * a channel is not a physical message channel like a serial port, but a logic partition of - * the communication streams in this case. COMM_NB is the limit for the number of channels - * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows - * @param c The char to barse - * - * @param returnMsg NULL if no message could be decoded, the message data else - * @return 0 if no message could be decoded, 1 else - * - * A typical use scenario of this function call is: - * - * @code - * #include // For fixed-width uint8_t type - * - * mavlink_message_t msg; - * int chan = 0; - * - * - * while(serial.bytesAvailable > 0) - * { - * uint8_t byte = serial.getNextByte(); - * if (mavlink_parse_char(chan, byte, &msg)) - * { - * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); - * } - * } - * - * - * @endcode - */ -static inline uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) -{ -#if (defined linux) | (defined __linux) | (defined __MACH__) | (defined _WIN32) - static mavlink_message_t m_mavlink_message[MAVLINK_COMM_NB_HIGH]; -#elif defined(NB_MAVLINK_COMM) - static mavlink_message_t m_mavlink_message[NB_MAVLINK_COMM]; -#else - static mavlink_message_t m_mavlink_message[MAVLINK_COMM_NB]; -#endif - // Initializes only once, values keep unchanged after first initialization - mavlink_parse_state_initialize(mavlink_get_channel_status(chan)); - - mavlink_message_t* rxmsg = &m_mavlink_message[chan]; ///< The currently decoded message - mavlink_status_t* status = mavlink_get_channel_status(chan); ///< The current decode status - int bufferIndex = 0; - - status->msg_received = 0; - - switch (status->parse_state) - { - case MAVLINK_PARSE_STATE_UNINIT: - case MAVLINK_PARSE_STATE_IDLE: - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - break; - - case MAVLINK_PARSE_STATE_GOT_STX: - if (status->msg_received) - { - status->buffer_overrun++; - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - } - else - { - // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2 - rxmsg->len = c; - status->packet_idx = 0; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_LENGTH; - } - break; - - case MAVLINK_PARSE_STATE_GOT_LENGTH: - rxmsg->seq = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_SEQ; - break; - - case MAVLINK_PARSE_STATE_GOT_SEQ: - rxmsg->sysid = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_SYSID; - break; - - case MAVLINK_PARSE_STATE_GOT_SYSID: - rxmsg->compid = c; - mavlink_update_checksum(rxmsg, c); - status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPID; - break; - - case MAVLINK_PARSE_STATE_GOT_COMPID: - rxmsg->msgid = c; - mavlink_update_checksum(rxmsg, c); -#ifdef MAVLINK_CHECK_LENGTH - if (rxmsg->len != mavlink_msg_lengths[c] ) - status->parse_state = MAVLINK_PARSE_STATE_IDLE; // abort, not going to understand it anyway - else ; -#endif - if (rxmsg->len == 0) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD; - } - else - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID; - } - break; - - case MAVLINK_PARSE_STATE_GOT_MSGID: - rxmsg->payload[status->packet_idx++] = c; - mavlink_update_checksum(rxmsg, c); - if (status->packet_idx == rxmsg->len) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD; - } - break; - - case MAVLINK_PARSE_STATE_GOT_PAYLOAD: - if (c != rxmsg->ck_a) - { - // Check first checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - } - else - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1; - } - break; - - case MAVLINK_PARSE_STATE_GOT_CRC1: - if (c != rxmsg->ck_b) - {// Check second checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - } - else - { - // Successfully got message - status->msg_received = 1; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if ( r_message != NULL ) - { - memcpy(r_message, rxmsg, sizeof(mavlink_message_t)); - } - } - break; - } - - bufferIndex++; - // If a message has been sucessfully decoded, check index - if (status->msg_received == 1) - { - //while(status->current_seq != rxmsg->seq) - //{ - // status->packet_rx_drop_count++; - // status->current_seq++; - //} - status->current_rx_seq = rxmsg->seq; - // Initial condition: If no packet has been received so far, drop count is undefined - if (status->packet_rx_success_count == 0) status->packet_rx_drop_count = 0; - // Count this packet as received - status->packet_rx_success_count++; - } - - r_mavlink_status->current_rx_seq = status->current_rx_seq+1; - r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count; - r_mavlink_status->packet_rx_drop_count = status->parse_error; - status->parse_error = 0; - - // For future use - -// if (status->msg_received == 1) -// { -// if ( r_message != NULL ) -// { -// return r_message; -// } -// else -// { -// return rxmsg; -// } -// } -// else -// { -// return NULL; -// } - return status->msg_received; -} - -#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS - -// To make MAVLink work on your MCU, define a similar function - -/* - -#include "mavlink_types.h" - -void comm_send_ch(mavlink_channel_t chan, uint8_t ch) -{ - if (chan == MAVLINK_COMM_0) - { - uart0_transmit(ch); - } - if (chan == MAVLINK_COMM_1) - { - uart1_transmit(ch); - } -} - - -static inline void mavlink_send_msg(mavlink_channel_t chan, mavlink_message_t* msg) -{ - // ARM7 MCU board implementation - // Create pointer on message struct - // Send STX - comm_send_ch(chan, MAVLINK_STX); - comm_send_ch(chan, msg->len); - comm_send_ch(chan, msg->seq); - comm_send_ch(chan, msg->sysid); - comm_send_ch(chan, msg->compid); - comm_send_ch(chan, msg->msgid); - for(uint16_t i = 0; i < msg->len; i++) - { - comm_send_ch(chan, msg->payload[i]); - } - comm_send_ch(chan, msg->ck_a); - comm_send_ch(chan, msg->ck_b); -} - -static inline void mavlink_send_mem(mavlink_channel_t chan, (uint8_t *)mem, uint8_t num) -{ - // ARM7 MCU board implementation - // Create pointer on message struct - // Send STX - for(uint16_t i = 0; i < num; i++) - { - comm_send_ch( chan, mem[i] ); - } -} - */ -static inline void mavlink_send_uart(mavlink_channel_t chan, mavlink_message_t* msg); -static inline void mavlink_send_mem(mavlink_channel_t chan, (uint8_t *)mem, uint8_t num); -#define mavlink_send_msg( a, b ) mavlink_send_uart( a, b ) -#endif - -#endif /* _MAVLINK_PROTOCOL_H_ */ diff --git a/src/apps/mavlinkgen/ui/DomItem.cc b/src/apps/mavlinkgen/ui/DomItem.cc deleted file mode 100644 index df2c52bc8..000000000 --- a/src/apps/mavlinkgen/ui/DomItem.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include - -#include "DomItem.h" - -DomItem::DomItem(QDomNode &node, int row, DomItem *parent) -{ - domNode = node; - // Record the item's location within its parent. - rowNumber = row; - parentItem = parent; -} - -DomItem::~DomItem() -{ - QHash::iterator it; - for (it = childItems.begin(); it != childItems.end(); ++it) - delete it.value(); -} - -QDomNode DomItem::node() const -{ - return domNode; -} - -DomItem *DomItem::parent() -{ - return parentItem; -} - -DomItem *DomItem::child(int i) -{ - if (childItems.contains(i)) - return childItems[i]; - - if (i >= 0 && i < domNode.childNodes().count()) { - QDomNode childNode = domNode.childNodes().item(i); - DomItem *childItem = new DomItem(childNode, i, this); - childItems[i] = childItem; - return childItem; - } - return 0; -} - -int DomItem::row() -{ - return rowNumber; -} diff --git a/src/apps/mavlinkgen/ui/DomItem.h b/src/apps/mavlinkgen/ui/DomItem.h deleted file mode 100644 index 30432795f..000000000 --- a/src/apps/mavlinkgen/ui/DomItem.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DOMITEM_H -#define DOMITEM_H - -#include -#include - -class DomItem -{ -public: - DomItem(QDomNode &node, int row, DomItem *parent = 0); - ~DomItem(); - DomItem *child(int i); - DomItem *parent(); - QDomNode node() const; - int row(); - -private: - QDomNode domNode; - QHash childItems; - DomItem *parentItem; - int rowNumber; -}; - -#endif diff --git a/src/apps/mavlinkgen/ui/DomModel.cc b/src/apps/mavlinkgen/ui/DomModel.cc deleted file mode 100644 index 2271f9a51..000000000 --- a/src/apps/mavlinkgen/ui/DomModel.cc +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include - -#include "DomItem.h" -#include "DomModel.h" - -DomModel::DomModel(QDomDocument document, QObject *parent) - : QAbstractItemModel(parent), domDocument(document) -{ - rootItem = new DomItem(domDocument, 0); -} - -DomModel::~DomModel() -{ - delete rootItem; -} - -int DomModel::columnCount(const QModelIndex &/*parent*/) const -{ - return 3; -} - -QVariant DomModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (role != Qt::DisplayRole) - return QVariant(); - - DomItem *item = static_cast(index.internalPointer()); - - QDomNode node = item->node(); - QStringList attributes; - QDomNamedNodeMap attributeMap = node.attributes(); - - switch (index.column()) { - case 0: - { - if (node.nodeName() == "message") - { - for (int i = 0; i < attributeMap.count(); ++i) { - QDomNode attribute = attributeMap.item(i); - if (attribute.nodeName() == "name") return attribute.nodeValue(); - } - } - else if (node.nodeName() == "field") - { - for (int i = 0; i < attributeMap.count(); ++i) { - QDomNode attribute = attributeMap.item(i); - if (attribute.nodeName() == "name") return attribute.nodeValue(); - } - } - else if (node.nodeName() == "enum") - { - for (int i = 0; i < attributeMap.count(); ++i) { - QDomNode attribute = attributeMap.item(i); - if (attribute.nodeName() == "name") return attribute.nodeValue(); - } - } - else if (node.nodeName() == "entry") - { - for (int i = 0; i < attributeMap.count(); ++i) { - QDomNode attribute = attributeMap.item(i); - if (attribute.nodeName() == "name") return attribute.nodeValue(); - } - } - else if (node.nodeName() == "#text") - { - return node.nodeValue().split("\n").join(" "); - } - else - { - return node.nodeName(); - } - } - break; - case 1: - if (node.nodeName() == "description") - { - return node.nodeValue().split("\n").join(" "); - } - else - { - for (int i = 0; i < attributeMap.count(); ++i) { - QDomNode attribute = attributeMap.item(i); - - if (attribute.nodeName() == "id" || attribute.nodeName() == "index" || attribute.nodeName() == "value") - { - return QString("(# %1)").arg(attribute.nodeValue()); - } - else if (attribute.nodeName() == "type") - { - return attribute.nodeValue(); - } - } - } - break; -// case 2: -// { -//// if (node.nodeName() != "description") -//// { -//// for (int i = 0; i < attributeMap.count(); ++i) { -//// QDomNode attribute = attributeMap.item(i); -//// attributes << attribute.nodeName() + "=\"" -//// +attribute.nodeValue() + "\""; -//// } -//// return attributes.join(" "); -//// } -//// else -//// { -//// return node.nodeValue().split("\n").join(" "); -//// } -// } -// break; - } - // Return empty variant if no case applied - return QVariant(); -} - -Qt::ItemFlags DomModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return 0; - - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -QVariant DomModel::headerData(int section, Qt::Orientation orientation, - int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) { - case 0: - return tr("Name "); - case 1: - return tr("Value"); -// case 2: -// return tr("Description"); - default: - return QVariant(); - } - } - - return QVariant(); -} - -QModelIndex DomModel::index(int row, int column, const QModelIndex &parent) - const -{ - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - DomItem *parentItem; - - if (!parent.isValid()) - parentItem = rootItem; - else - parentItem = static_cast(parent.internalPointer()); - - DomItem *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); - else - return QModelIndex(); -} - -QModelIndex DomModel::parent(const QModelIndex &child) const -{ - if (!child.isValid()) - return QModelIndex(); - - DomItem *childItem = static_cast(child.internalPointer()); - DomItem *parentItem = childItem->parent(); - - if (!parentItem || parentItem == rootItem) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); -} - -int DomModel::rowCount(const QModelIndex &parent) const -{ - if (parent.column() > 0) - return 0; - - DomItem *parentItem; - - if (!parent.isValid()) - parentItem = rootItem; - else - parentItem = static_cast(parent.internalPointer()); - - return parentItem->node().childNodes().count(); -} diff --git a/src/apps/mavlinkgen/ui/DomModel.h b/src/apps/mavlinkgen/ui/DomModel.h deleted file mode 100644 index ae6bf6a74..000000000 --- a/src/apps/mavlinkgen/ui/DomModel.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef DOMMODEL_H -#define DOMMODEL_H - -#include -#include -#include -#include - -class DomItem; - -class DomModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - DomModel(QDomDocument document, QObject *parent = 0); - ~DomModel(); - - QVariant data(const QModelIndex &index, int role) const; - Qt::ItemFlags flags(const QModelIndex &index) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &child) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - -private: - QDomDocument domDocument; - DomItem *rootItem; -}; - -#endif diff --git a/src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.cc b/src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.cc deleted file mode 100644 index a199a3cb6..000000000 --- a/src/apps/mavlinkgen/ui/QGCMAVLinkTextEdit.cc +++ /dev/null @@ -1,480 +0,0 @@ -#include "QGCMAVLinkTextEdit.h" -#include -#include -#include -#include -#include -#include - -QGCMAVLinkTextEdit::QGCMAVLinkTextEdit(QWidget *parent) -: QTextEdit(parent) -{ - setViewportMargins(50, 0, 0, 0); - highlight = new XmlHighlighter(document()); - setLineWrapMode ( QTextEdit::NoWrap ); - setAcceptRichText ( false ); - connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(update())); - connect(this, SIGNAL(textChanged()), this, SLOT(update())); -} - - -bool QGCMAVLinkTextEdit::Conform() -{ - QString errorStr; - int errorLine, errorColumn; - QDomDocument doc; - return doc.setContent(text(),false, &errorStr, &errorLine, &errorColumn); -} - -QDomDocument QGCMAVLinkTextEdit::xml_document() -{ - QString errorStr; - int errorLine, errorColumn; - QDomDocument doc; - doc.setContent(text(),false, &errorStr, &errorLine, &errorColumn); - return doc; -} - - -void QGCMAVLinkTextEdit::setPlainText( const QString txt ) -{ - QString errorStr; - int errorLine, errorColumn; - QDomDocument doc; - if (!doc.setContent(txt,false, &errorStr, &errorLine, &errorColumn)) { - QTextEdit::setPlainText(txt); - } else { - QTextEdit::setPlainText(doc.toString(5)); - } -} - -bool QGCMAVLinkTextEdit::syntaxcheck() -{ - bool noError = true; - if (text().size() > 0 ) { - QString errorStr; - int errorLine, errorColumn; - QDomDocument doc; - if (!doc.setContent(text(),false, &errorStr, &errorLine, &errorColumn)) { - //////return doc.toString(5); - QMessageBox::critical(0, tr("Found xml error"),tr("Check line %1 column %2 on string \"%3\"!") - .arg(errorLine - 1) - .arg(errorColumn - 1) - .arg(errorStr)); - noError = false; - - // FIXME Mark line - if (errorLine >= 0 ) { - - } - } else { - QMessageBox::information(0, tr("XML valid."),tr("All tags are valid. Document size is %1 characters.").arg(text().size())); - setPlainText(doc.toString(5)); - } - } else { - QMessageBox::information(0, tr("XML not found!"),tr("Null size xml document!")); - noError = false; - } - return noError; -} - -void QGCMAVLinkTextEdit::contextMenuEvent ( QContextMenuEvent * e ) -{ - Q_UNUSED(e); - QMenu *RContext = createOwnStandardContextMenu(); - RContext->exec(QCursor::pos()); - delete RContext; -} - -QMenu *QGCMAVLinkTextEdit::createOwnStandardContextMenu() -{ - QMenu *TContext = createStandardContextMenu(); - TContext->addAction(QIcon(QString::fromUtf8(":/img/zoomin.png")),tr( "Zoom In" ), this , SLOT( zoomIn() ) ); - TContext->addAction(QIcon(QString::fromUtf8(":/img/zoomout.png")),tr( "Zoom Out" ), this , SLOT( zoomOut() ) ); - TContext->addAction(tr("Check xml syntax" ), this , SLOT( syntaxcheck() ) ); - return TContext; -} - -bool QGCMAVLinkTextEdit::event( QEvent *event ) -{ - if (event->type()==QEvent::Paint) { - QPainter p(this); - p.fillRect(0, 0, 50, height(), QColor("#636363")); - QFont workfont(font()); - QPen pen(QColor("#ffffff"),1); - p.setPen(pen); - p.setFont (workfont); - int contentsY = verticalScrollBar()->value(); - qreal pageBottom = contentsY+viewport()->height(); - int m_lineNumber(1); - const QFontMetrics fm=fontMetrics(); - const int ascent = fontMetrics().ascent() +1; - - for (QTextBlock block=document()->begin(); block.isValid(); block=block.next(), m_lineNumber++) { - QTextLayout *layout = block.layout(); - const QRectF boundingRect = layout->boundingRect(); - QPointF position = layout->position(); - if ( position.y() +boundingRect.height() < contentsY ) { - continue; - } - if ( position.y() > pageBottom ) { - break; - } - const QString txt = QString::number(m_lineNumber); - p.drawText(50-fm.width(txt)-2, qRound(position.y())-contentsY+ascent, txt); - - } - p.setPen(QPen(Qt::NoPen)); - } else if ( event->type() == QEvent::KeyPress ) { - QKeyEvent *ke = static_cast(event); - if ((ke->modifiers() & Qt::ControlModifier) && ke->key() == Qt::Key_Minus) { - QTextEdit::zoomOut(); - return true; - } - if ((ke->modifiers() & Qt::ControlModifier) && ke->key() == Qt::Key_Plus) { - QTextEdit::zoomIn(); - return true; - } - } - return QTextEdit::event(event); -} - - - - - - - - - - - - - - - -static const QColor DEFAULT_SYNTAX_CHAR = Qt::blue; -static const QColor DEFAULT_ELEMENT_NAME = Qt::darkRed; -static const QColor DEFAULT_COMMENT = Qt::darkGreen; -static const QColor DEFAULT_ATTRIBUTE_NAME = Qt::red; -static const QColor DEFAULT_ATTRIBUTE_VALUE = Qt::darkGreen; -static const QColor DEFAULT_ERROR = Qt::darkMagenta; -static const QColor DEFAULT_OTHER = Qt::black; - -// Regular expressions for parsing XML borrowed from: -// http://www.cs.sfu.ca/~cameron/REX.html -static const QString EXPR_COMMENT = "