diff --git a/qgcunittest.pro b/qgcunittest.pro index d8612b2b1efdbd57d02d67461f26ab79bffadae4..5fe080ff42471815dc66c4ed95a32fd592e971fa 100644 --- a/qgcunittest.pro +++ b/qgcunittest.pro @@ -11,7 +11,7 @@ QT += network \ TEMPLATE = app -TARGET = tst_uasunittest +TARGET = qgcunittest BASEDIR = $$IN_PWD TESTDIR = $$BASEDIR/qgcunittest @@ -97,8 +97,7 @@ INCLUDEPATH += . \ $$BASEDIR/src/ui/ \ -SOURCES += $$TESTDIR/tst_uasunittest.cc \ - src/uas/UAS.cc \ +SOURCES += src/uas/UAS.cc \ src/comm/MAVLinkProtocol.cc \ src/uas/UASWaypointManager.cc \ src/Waypoint.cc \ @@ -111,6 +110,10 @@ SOURCES += $$TESTDIR/tst_uasunittest.cc \ src/comm/LinkManager.cc \ src/QGC.cc \ src/comm/SerialLink.cc \ + $$TESTDIR/SlugsMavUnitTest.cc \ + $$TESTDIR/testSuite.cc \ + $$TESTDIR/UASUnitTest.cc + HEADERS += src/uas/UASInterface.h \ src/uas/UAS.h \ @@ -129,6 +132,9 @@ HEADERS += src/uas/UASInterface.h \ src/QGC.h \ src/comm/SerialLinkInterface.h \ src/comm/SerialLink.h \ + $$TESTDIR//SlugsMavUnitTest.h \ + $$TESTDIR/AutoTest.h \ + $$TESTDIR/UASUnitTest.h diff --git a/qgcunittest/AutoTest.h b/qgcunittest/AutoTest.h new file mode 100755 index 0000000000000000000000000000000000000000..e353d3d30208a7ef9429f63f51c4dba41799bb7f --- /dev/null +++ b/qgcunittest/AutoTest.h @@ -0,0 +1,85 @@ +/** +* @author Rob Caldecott +* @note This was obtained from http://qtcreator.blogspot.com/2010/04/sample-multiple-unit-test-project.html +* +*/ + +#ifndef AUTOTEST_H +#define AUTOTEST_H + +#include +#include +#include +#include + +namespace AutoTest +{ + typedef QList TestList; + + inline TestList& testList() + { + static TestList list; + return list; + } + + inline bool findObject(QObject* object) + { + TestList& list = testList(); + if (list.contains(object)) + { + return true; + } + foreach (QObject* test, list) + { + if (test->objectName() == object->objectName()) + { + return true; + } + } + return false; + } + + inline void addTest(QObject* object) + { + TestList& list = testList(); + if (!findObject(object)) + { + list.append(object); + } + } + + inline int run(int argc, char *argv[]) + { + int ret = 0; + + foreach (QObject* test, testList()) + { + ret += QTest::qExec(test, argc, argv); + } + + return ret; + } +} + +template +class Test +{ +public: + QSharedPointer child; + + Test(const QString& name) : child(new T) + { + child->setObjectName(name); + AutoTest::addTest(child.data()); + } +}; + +#define DECLARE_TEST(className) static Test t(#className); + +#define TEST_MAIN \ + int main(int argc, char *argv[]) \ + { \ + return AutoTest::run(argc, argv); \ + } + +#endif // AUTOTEST_H diff --git a/qgcunittest/SlugsMavUnitTest.cc b/qgcunittest/SlugsMavUnitTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..0e15497019615cf68a0819f8898f5b85f842a80c --- /dev/null +++ b/qgcunittest/SlugsMavUnitTest.cc @@ -0,0 +1,20 @@ +#include "SlugsMavUnitTest.h" + +SlugsMavUnitTest::SlugsMavUnitTest() +{ +} + +void SlugsMavUnitTest::initTestCase() +{ + +} + +void SlugsMavUnitTest::cleanupTestCase() +{ + +} + +void SlugsMavUnitTest::first_test() +{ + QCOMPARE(1,2); +} diff --git a/qgcunittest/SlugsMavUnitTest.h b/qgcunittest/SlugsMavUnitTest.h new file mode 100644 index 0000000000000000000000000000000000000000..493e4a4c55a8f251b82d114e7e516f5b2eb65b76 --- /dev/null +++ b/qgcunittest/SlugsMavUnitTest.h @@ -0,0 +1,27 @@ +#ifndef SLUGSMAVUNITTEST_H +#define SLUGSMAVUNITTEST_H + +#include +#include +#include +#include "UAS.h" +#include "MAVLinkProtocol.h" +#include "UASInterface.h" +#include "AutoTest.h" + +class SlugsMavUnitTest : public QObject +{ + Q_OBJECT +public: + SlugsMavUnitTest(); +signals: + +private slots: + void initTestCase(); + void cleanupTestCase(); + void first_test(); +}; + +DECLARE_TEST(SlugsMavUnitTest) + +#endif // SLUGSMAVUNITTEST_H diff --git a/qgcunittest/UASUnitTest.cc b/qgcunittest/UASUnitTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..7aa85377bda8d35197933167ad631be5d1ece3f3 --- /dev/null +++ b/qgcunittest/UASUnitTest.cc @@ -0,0 +1,156 @@ +#include "UASUnitTest.h" + +UASUnitTest::UASUnitTest() +{ +} + +void UASUnitTest::initTestCase() +{ + mav= new MAVLinkProtocol(); + uas=new UAS(mav,UASID); +} + +void UASUnitTest::cleanupTestCase() +{ + delete uas; + delete mav; + +} + +void UASUnitTest::getUASID_test() +{ + // Test a default ID of zero is assigned + UAS* uas2 = new UAS(mav); + QCOMPARE(uas2->getUASID(), 0); + delete uas2; + + // Test that the chosen ID was assigned at construction + QCOMPARE(uas->getUASID(), UASID); + + // Make sure that no other ID was sert + QEXPECT_FAIL("", "When you set an ID it does not use the default ID of 0", Continue); + QCOMPARE(uas->getUASID(), 0); +} + +void UASUnitTest::getUASName_test() +{ + // Test that the name is build as MAV + ID + QCOMPARE(uas->getUASName(), "MAV 0" + QString::number(UASID)); + +} + +void UASUnitTest::getUpTime_test() +{ + UAS* uas2 = new UAS(mav); + // Test that the uptime starts at zero to a + // precision of seconds + QCOMPARE(floor(uas2->getUptime()/1000.0), 0.0); + + // Sleep for three seconds + QTest::qSleep(3000); + + // Test that the up time is computed correctly to a + // precision of seconds + QCOMPARE(floor(uas2->getUptime()/1000.0), 3.0); + + delete uas2; +} + +void UASUnitTest::getCommunicationStatus_test() +{ + // Verify that upon construction the Comm status is disconnected + QCOMPARE(uas->getCommunicationStatus(), static_cast(UASInterface::COMM_DISCONNECTED)); +} + +void UASUnitTest::filterVoltage_test() +{ + float verificar=uas->filterVoltage(0.4f); + // Verify that upon construction the Comm status is disconnected + QCOMPARE(verificar, 8.52f); +} +void UASUnitTest:: getAutopilotType_test() +{ + int verificar=uas->getAutopilotType(); + // Verify that upon construction the autopilot is set to -1 + QCOMPARE(verificar, -1); +} +void UASUnitTest::setAutopilotType_test() +{ + uas->setAutopilotType(2); + // Verify that the autopilot is set + QCOMPARE(uas->getAutopilotType(), 2); +} + +void UASUnitTest::getStatusForCode_test() +{ + QString state, desc; + state = ""; + desc = ""; + + uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); + QVERIFY(state == "UNINIT"); + + uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); + QVERIFY(state == "UNINIT"); + + uas->getStatusForCode(MAV_STATE_BOOT, state, desc); + QVERIFY(state == "BOOT"); + + uas->getStatusForCode(MAV_STATE_CALIBRATING, state, desc); + QVERIFY(state == "CALIBRATING"); + + uas->getStatusForCode(MAV_STATE_ACTIVE, state, desc); + QVERIFY(state == "ACTIVE"); + + uas->getStatusForCode(MAV_STATE_STANDBY, state, desc); + QVERIFY(state == "STANDBY"); + + uas->getStatusForCode(MAV_STATE_CRITICAL, state, desc); + QVERIFY(state == "CRITICAL"); + + uas->getStatusForCode(MAV_STATE_EMERGENCY, state, desc); + QVERIFY(state == "EMERGENCY"); + + uas->getStatusForCode(MAV_STATE_POWEROFF, state, desc); + QVERIFY(state == "SHUTDOWN"); + + uas->getStatusForCode(5325, state, desc); + QVERIFY(state == "UNKNOWN"); +} + + +void UASUnitTest::getLocalX_test() +{ + QCOMPARE(uas->getLocalX(), 0.0); +} +void UASUnitTest::getLocalY_test() +{ + QCOMPARE(uas->getLocalY(), 0.0); +} +void UASUnitTest::getLocalZ_test() +{ + QCOMPARE(uas->getLocalZ(), 0.0); +} +void UASUnitTest::getLatitude_test() +{ QCOMPARE(uas->getLatitude(), 0.0); +} +void UASUnitTest::getLongitude_test() +{ + QCOMPARE(uas->getLongitude(), 0.0); +} +void UASUnitTest::getAltitude_test() +{ + QCOMPARE(uas->getAltitude(), 0.0); +} +void UASUnitTest::getRoll_test() +{ + QCOMPARE(uas->getRoll(), 0.0); +} +void UASUnitTest::getPitch_test() +{ + QCOMPARE(uas->getPitch(), 0.0); +} +void UASUnitTest::getYaw_test() +{ + QCOMPARE(uas->getYaw(), 0.0); +} diff --git a/qgcunittest/UASUnitTest.h b/qgcunittest/UASUnitTest.h new file mode 100644 index 0000000000000000000000000000000000000000..67f1eb6d826276dee0858a9705e20f5a52332aa0 --- /dev/null +++ b/qgcunittest/UASUnitTest.h @@ -0,0 +1,50 @@ +#ifndef UASUNITTEST_H +#define UASUNITTEST_H + +#include +#include +#include +#include "UAS.h" +#include "MAVLinkProtocol.h" +#include "UASInterface.h" +#include "AutoTest.h" + +class UASUnitTest : public QObject +{ + Q_OBJECT +public: + #define UASID 50 + MAVLinkProtocol* mav; + UAS* uas; + UASUnitTest(); + +signals: + +private slots: + void initTestCase(); + void cleanupTestCase(); + void getUASID_test(); + void getUASName_test(); + void getUpTime_test(); + void getCommunicationStatus_test(); + void filterVoltage_test(); + void getAutopilotType_test(); + void setAutopilotType_test(); + void getStatusForCode_test(); + void getLocalX_test(); + void getLocalY_test(); + void getLocalZ_test(); + void getLatitude_test(); + void getLongitude_test(); + void getAltitude_test(); + void getRoll_test(); + void getPitch_test(); + void getYaw_test(); + +protected: + UAS *prueba; + +}; + +DECLARE_TEST(UASUnitTest) +#endif // UASUNITTEST_H diff --git a/qgcunittest/testSuite.cc b/qgcunittest/testSuite.cc new file mode 100755 index 0000000000000000000000000000000000000000..0489b2298661812b2fffb0e15dcaffd5b57d1173 --- /dev/null +++ b/qgcunittest/testSuite.cc @@ -0,0 +1,28 @@ +/** +* @author Rob Caldecott +* @note This was obtained from http://qtcreator.blogspot.com/2010/04/sample-multiple-unit-test-project.html +* +*/ + +#include "AutoTest.h" +#include + +#if 1 +// This is all you need to run all the tests +TEST_MAIN +#else +// Or supply your own main function +int main(int argc, char *argv[]) +{ + int failures = AutoTest::run(argc, argv); + if (failures == 0) + { + qDebug() << "ALL TESTS PASSED"; + } + else + { + qDebug() << failures << " TESTS FAILED!"; + } + return failures; +} +#endif diff --git a/src/MG.h b/src/MG.h index 2e82de2c0c956e42274002b2ca98c08328fc0a0d..9b76ef50cfa7d6a8d94ab1584fe8bb1390c2a088 100644 --- a/src/MG.h +++ b/src/MG.h @@ -41,7 +41,7 @@ This file is part of the PIXHAWK project namespace MG { - const static int MAX_FLIGHT_TIME = 60 * 60 * 24 * 365 * 2; + const static int MAX_FLIGHT_TIME = 60 * 60 * 24 * 21; class VERSION { diff --git a/src/QGC.h b/src/QGC.h index ebc390e7f621789af80d5e857c159ba20d314f17..7ece2f230415217e17e70a65c24c0907801315ed 100644 --- a/src/QGC.h +++ b/src/QGC.h @@ -20,7 +20,7 @@ namespace QGC quint64 groundTimeUsecs(); int applicationVersion(); - + const static int MAX_FLIGHT_TIME = 60 * 60 * 24 * 21; class SLEEP : public QThread { diff --git a/src/uas/SlugsMAV.h b/src/uas/SlugsMAV.h index 7acd1fdd9c5b85419b727f306ea7e9e1e3ce3056..7fd4a9870bd377899c98013050247482caacfb41 100644 --- a/src/uas/SlugsMAV.h +++ b/src/uas/SlugsMAV.h @@ -46,7 +46,6 @@ public slots: mavlink_pwm_commands_t* getPwmCommands(); #endif - signals: void slugsRawImu(int uasId, const mavlink_raw_imu_t& rawData); diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc index 112f319965fd81d43d14f9c480e9b8927da278d5..1d1e5eddfd2e176917a3ffac744f7b92c8a1638a 100644 --- a/src/uas/UAS.cc +++ b/src/uas/UAS.cc @@ -84,8 +84,8 @@ paramsOnceRequested(false) { color = UASInterface::getNextColor(); setBattery(LIPOLY, 3); - statusTimeout->setInterval(500); connect(statusTimeout, SIGNAL(timeout()), this, SLOT(updateState())); + statusTimeout->start(500); } UAS::~UAS() @@ -101,6 +101,14 @@ int UAS::getUASID() const void UAS::updateState() { + // Check if heartbeat timed out + quint64 heartbeatInterval = QGC::groundTimeUsecs() - lastHeartbeat; + if (heartbeatInterval > timeoutIntervalHeartbeat) + { + emit heartbeatTimeout(heartbeatInterval); + emit heartbeatTimeout(); + } + // Position lock is set by the MAVLink message handler // if no position lock is available, indicate an error if (positionLock) @@ -144,6 +152,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) switch (message.msgid) { case MAVLINK_MSG_ID_HEARTBEAT: + lastHeartbeat = QGC::groundTimeUsecs(); emit heartbeat(this); // Set new type if it has changed if (this->type != mavlink_msg_heartbeat_get_type(&message)) @@ -1317,6 +1326,12 @@ void UAS::setParameter(const int component, const QString& id, const float value } } +void UAS::setUASName(const QString& name) +{ + this->name = name; + emit nameChanged(name); +} + /** * Sets an action * diff --git a/src/uas/UAS.h b/src/uas/UAS.h index 8099960a3f8eeea9381d29dc2ad036ba3d4cb3d4..6f0ea89e3a8e46d4810390bfcd07479ead875b8e 100644 --- a/src/uas/UAS.h +++ b/src/uas/UAS.h @@ -152,6 +152,7 @@ protected: //COMMENTS FOR TEST UNIT double roll; double pitch; double yaw; + quint64 lastHeartbeat; ///< Time of the last heartbeat message QTimer* statusTimeout; ///< Timer for various status timeouts QMap* > parameters; ///< All parameters bool paramsOnceRequested; ///< If the parameter list has been read at least once @@ -174,7 +175,10 @@ public: void setAutopilotType(int apType) { autopilot = apType;} public slots: - /** @brief Sets an action **/ + + /** @brief Set a new name **/ + void setUASName(const QString& name); + /** @brief Executes an action **/ void setAction(MAV_ACTION action); /** @brief Launches the system **/ diff --git a/src/uas/UASInterface.h b/src/uas/UASInterface.h index 97b1f85a4dd1c24b7ba45be6ad69073e969b9a81..2d7df002bb2ceb10ded4ed4a19f45872b1a89ef6 100644 --- a/src/uas/UASInterface.h +++ b/src/uas/UASInterface.h @@ -92,7 +92,8 @@ public: COMM_CONNECTED = 2, /** The connection is closed **/ COMM_DISCONNECTING = 3, - COMM_FAIL = 4, ///< Communication link failed + COMM_FAIL = 4, + COMM_TIMEDOUT = 5///< Communication link failed }; @@ -162,6 +163,8 @@ public: public slots: + /** @brief Set a new name for the system */ + virtual void setUASName(const QString& name) = 0; /** @brief Sets an action **/ virtual void setAction(MAV_ACTION action) = 0; @@ -409,9 +412,18 @@ signals: */ void irUltraSoundLocalizationChanged(UASInterface* uas, int fix); + // ERROR AND STATUS SIGNALS + /** @brief Heartbeat timed out */ + void heartbeatTimeout(); + /** @brief Heartbeat timed out */ + void heartbeatTimeout(unsigned int ms); + /** @brief Name of system changed */ + void nameChanged(QString newName); +protected: - + // TIMEOUT CONSTANTS + static const unsigned int timeoutIntervalHeartbeat = 2000 * 1000; ///< Heartbeat timeout is 1.5 seconds }; diff --git a/src/uas/UASManager.cc b/src/uas/UASManager.cc index ceb9a2a417cc4d049801b2d2574715c3da52588a..68ef921ea2f0eb79b3b4df6927baf5f6c3d15327 100644 --- a/src/uas/UASManager.cc +++ b/src/uas/UASManager.cc @@ -58,7 +58,7 @@ UASManager* UASManager::instance() UASManager::UASManager() : activeUAS(NULL) { - systems = QMap(); + systems = QList(); start(QThread::LowPriority); } @@ -90,9 +90,9 @@ void UASManager::addUAS(UASInterface* uas) } // Only execute if there is no UAS at this index - if (!systems.contains(uas->getUASID())) + if (!systems.contains(uas)) { - systems.insert(uas->getUASID(), uas); + systems.append(uas); emit UASCreated(uas); } @@ -105,7 +105,7 @@ void UASManager::addUAS(UASInterface* uas) QList UASManager::getUASList() { - return systems.values(); + return systems; } UASInterface* UASManager::getActiveUAS() @@ -176,8 +176,18 @@ void UASManager::configureActiveUAS() UASInterface* UASManager::getUASForId(int id) { - // Return NULL pointer if UAS does not exist - return systems.value(id, NULL); + UASInterface* system = NULL; + + foreach(UASInterface* sys, systems) + { + if (sys->getUASID() == id) + { + system = sys; + } + } + + // Return NULL if not found + return system; } void UASManager::setActiveUAS(UASInterface* uas) @@ -195,6 +205,7 @@ void UASManager::setActiveUAS(UASInterface* uas) emit activeUASSet(uas); emit activeUASSet(uas->getUASID()); + emit activeUASSetListIndex(systems.indexOf(uas)); emit activeUASStatusChanged(uas, true); emit activeUASStatusChanged(uas->getUASID(), true); } diff --git a/src/uas/UASManager.h b/src/uas/UASManager.h index b4d97789df578036d4b7a56d914a673ced3a159a..00441ee7089ad402b3c8c7649200c5e34acf1e54 100644 --- a/src/uas/UASManager.h +++ b/src/uas/UASManager.h @@ -162,7 +162,7 @@ public slots: protected: UASManager(); - QMap systems; + QList systems; UASInterface* activeUAS; QMutex activeUASMutex; @@ -173,6 +173,8 @@ signals: /** @brief The UAS currently under main operator control changed */ void activeUASSet(int systemId); /** @brief The UAS currently under main operator control changed */ + void activeUASSetListIndex(int listIndex); + /** @brief The UAS currently under main operator control changed */ void activeUASStatusChanged(UASInterface* UAS, bool active); /** @brief The UAS currently under main operator control changed */ void activeUASStatusChanged(int systemId, bool active); diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index c1d160e965dd393ee5a5196a82015352c91937eb..48c99b065e9a1e2974c70f2496a36f36589b3327 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -436,10 +436,10 @@ void MainWindow::buildPxWidgets() if (!parametersDockWidget) { - parametersDockWidget = new QDockWidget(tr("Onboard Parameters"), this); + parametersDockWidget = new QDockWidget(tr("Calibration and Onboard Parameters"), this); parametersDockWidget->setWidget( new ParameterInterface(this) ); parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET"); - addToToolsMenu (parametersDockWidget, tr("Onboard Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea); + addToToolsMenu (parametersDockWidget, tr("Calibration and Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea); } if (!watchdogControlDockWidget) @@ -1099,7 +1099,7 @@ void MainWindow::showStatusMessage(const QString& status) void MainWindow::showCriticalMessage(const QString& title, const QString& message) { - QMessageBox msgBox(MainWindow::instance()); + QMessageBox msgBox(this); msgBox.setIcon(QMessageBox::Critical); msgBox.setText(title); msgBox.setInformativeText(message); @@ -1110,7 +1110,7 @@ void MainWindow::showCriticalMessage(const QString& title, const QString& messag void MainWindow::showInfoMessage(const QString& title, const QString& message) { - QMessageBox msgBox(MainWindow::instance()); + QMessageBox msgBox(this); msgBox.setIcon(QMessageBox::Information); msgBox.setText(title); msgBox.setInformativeText(message); @@ -1152,6 +1152,9 @@ void MainWindow::connectCommonActions() connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp())); connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits())); connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap())); + + // Custom widget actions + connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget())); } void MainWindow::connectPxActions() diff --git a/src/ui/ParameterInterface.cc b/src/ui/ParameterInterface.cc index d6a3a59aae206baa6f968cf0ec0641b2e79462f3..5a0f194ebf77684eb27ee9ae2c0464e0da01d209 100644 --- a/src/ui/ParameterInterface.cc +++ b/src/ui/ParameterInterface.cc @@ -46,10 +46,10 @@ ParameterInterface::ParameterInterface(QWidget *parent) : m_ui->setupUi(this); // Make sure the combo box is empty // because else indices get messed up - m_ui->vehicleComboBox->clear(); + //m_ui->vehicleComboBox->clear(); // Setup UI connections - connect(m_ui->vehicleComboBox, SIGNAL(activated(int)), this, SLOT(selectUAS(int))); + //connect(m_ui->vehicleComboBox, SIGNAL(activated(int)), this, SLOT(selectUAS(int))); // Get current MAV list QList systems = UASManager::instance()->getUASList(); @@ -62,6 +62,7 @@ ParameterInterface::ParameterInterface(QWidget *parent) : // Setup MAV connections connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*))); + connect(UASManager::instance(), SIGNAL(activeUASSetListIndex(int)), this, SLOT(selectUAS(int))); this->setVisible(false); } @@ -72,9 +73,8 @@ ParameterInterface::~ParameterInterface() void ParameterInterface::selectUAS(int index) { - // FIXME plus 2 shouldn't be there - m_ui->stackedWidget->setCurrentIndex(index+2); - m_ui->sensorSettings->setCurrentIndex(index+2); + m_ui->stackedWidget->setCurrentIndex(index); + m_ui->sensorSettings->setCurrentIndex(index); curr = index; } @@ -84,7 +84,7 @@ void ParameterInterface::selectUAS(int index) */ void ParameterInterface::addUAS(UASInterface* uas) { - m_ui->vehicleComboBox->addItem(uas->getUASName()); + //m_ui->vehicleComboBox->addItem(uas->getUASName()); QGCParamWidget* param = new QGCParamWidget(uas, this); paramWidgets->insert(uas->getUASID(), param); diff --git a/src/ui/ParameterInterface.ui b/src/ui/ParameterInterface.ui index 9faf772ee492c5fb7b9688a2a4e7fb215fe81a15..167f006418a0435594d69ad9d51a249b97d661d0 100644 --- a/src/ui/ParameterInterface.ui +++ b/src/ui/ParameterInterface.ui @@ -13,7 +13,7 @@ Form - + 5 @@ -23,17 +23,7 @@ 6 - - - - Vehicle - - - - - - - + Onboard Parameters @@ -45,26 +35,18 @@ - 0 + -1 - - - - - + - 0 + -1 - - - - diff --git a/src/ui/UASControl.ui b/src/ui/UASControl.ui index d1a6f6c8656bc2e549656c86f237230ac6566c64..e506dbc1622d82c1b45b68137983b7f91e2157f1 100644 --- a/src/ui/UASControl.ui +++ b/src/ui/UASControl.ui @@ -6,8 +6,8 @@ 0 0 - 222 - 172 + 200 + 150 @@ -18,8 +18,8 @@ - 222 - 172 + 200 + 150 @@ -34,8 +34,14 @@ Control widget to send basic control actions to the micro air vehicle - - + + + 4 + + + 6 + + Qt::Horizontal @@ -48,12 +54,12 @@ - + 0 - 0 + 10 @@ -67,140 +73,143 @@ - - + + - Qt::Horizontal + Qt::Vertical - 30 - 159 + 216 + 17 - - - - - 0 - 12 - - - - Activate Engine - - + + + + 6 + + + + + + 25 + 16 + + + + Start + + + + :/images/control/launch.svg:/images/control/launch.svg + + + + + + + + 25 + 16 + + + + Land + + + + :/images/control/land.svg:/images/control/land.svg + + + + + + + + 25 + 16 + + + + Halt + + + + :/images/actions/system-log-out.svg:/images/actions/system-log-out.svg + + + + - - - - - 40 - 12 - - - - Start - - - - :/images/control/launch.svg:/images/control/launch.svg - - - - - + + - 40 - 12 + 25 + 16 - - Land - - - - :/images/control/land.svg:/images/control/land.svg - - - + + - 40 - 12 + 25 + 16 - Halt + Set - :/images/actions/system-log-out.svg:/images/actions/system-log-out.svg + :/images/devices/network-wireless.svg:/images/devices/network-wireless.svg - - + + 0 - 12 - - - - - - - - - 40 - 12 + 10 - Set Mode + No actions executed so far - - - :/images/devices/network-wireless.svg:/images/devices/network-wireless.svg + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - + + + + Qt::Horizontal + + - 40 - 16 + 30 + 159 - - Set Origin - - - - :/images/actions/go-home.svg:/images/actions/go-home.svg - - + - - + + 0 - 12 + 30 - No actions executed so far - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Activate Engine diff --git a/src/ui/XMLCommProtocolWidget.cc b/src/ui/XMLCommProtocolWidget.cc index c2ea91ea47901f644dedbb4b0cad98b76160ff8f..e42a6a2689490701b9675f2bb3cb9e57d891a799 100644 --- a/src/ui/XMLCommProtocolWidget.cc +++ b/src/ui/XMLCommProtocolWidget.cc @@ -35,8 +35,9 @@ void XMLCommProtocolWidget::selectXMLFile() QSettings settings(QGC::COMPANYNAME, QGC::APPNAME); const QString mavlinkXML = "MAVLINK_XML_FILE"; QString dirPath = settings.value(mavlinkXML, QCoreApplication::applicationDirPath() + "../").toString(); + QFileInfo dir(dirPath); QFileDialog dialog; - dialog.setDirectory(dirPath); + dialog.setDirectory(dir.absoluteDir()); dialog.setFileMode(QFileDialog::AnyFile); dialog.setFilter(tr("MAVLink XML (*.xml)")); dialog.setViewMode(QFileDialog::Detail); @@ -100,7 +101,6 @@ void XMLCommProtocolWidget::selectOutputDirectory() QFileDialog dialog; dialog.setDirectory(dirPath); dialog.setFileMode(QFileDialog::Directory); - dialog.setFilter(tr("MAVLink XML (*.xml)")); dialog.setViewMode(QFileDialog::Detail); QStringList fileNames; if (dialog.exec()) diff --git a/src/ui/uas/UASControlWidget.cc b/src/ui/uas/UASControlWidget.cc index 9de5dd170b841cfb3cea9346ff9ffd1025e564c0..359c7a96f77aec305f0e8cb14269e501547af597 100644 --- a/src/ui/uas/UASControlWidget.cc +++ b/src/ui/uas/UASControlWidget.cc @@ -97,7 +97,7 @@ void UASControlWidget::setUAS(UASInterface* uas) disconnect(ui.liftoffButton, SIGNAL(clicked()), oldUAS, SLOT(launch())); disconnect(ui.landButton, SIGNAL(clicked()), oldUAS, SLOT(home())); disconnect(ui.shutdownButton, SIGNAL(clicked()), oldUAS, SLOT(shutdown())); - connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); + //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); disconnect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString))); disconnect(uas, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); } @@ -107,28 +107,28 @@ void UASControlWidget::setUAS(UASInterface* uas) connect(ui.liftoffButton, SIGNAL(clicked()), uas, SLOT(launch())); connect(ui.landButton, SIGNAL(clicked()), uas, SLOT(home())); connect(ui.shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown())); - connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); + //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString))); connect(uas, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); ui.controlStatusLabel->setText(tr("Connected to ") + uas->getUASName()); - // Check if additional controls should be loaded - UAS* mav = dynamic_cast(uas); - if (mav) - { - QPushButton* startRecButton = new QPushButton(tr("Record")); - connect(startRecButton, SIGNAL(clicked()), mav, SLOT(startDataRecording())); - ui.gridLayout->addWidget(startRecButton, 7, 1); - - QPushButton* pauseRecButton = new QPushButton(tr("Pause")); - connect(pauseRecButton, SIGNAL(clicked()), mav, SLOT(pauseDataRecording())); - ui.gridLayout->addWidget(pauseRecButton, 7, 3); - - QPushButton* stopRecButton = new QPushButton(tr("Stop")); - connect(stopRecButton, SIGNAL(clicked()), mav, SLOT(stopDataRecording())); - ui.gridLayout->addWidget(stopRecButton, 7, 4); - } +// // Check if additional controls should be loaded +// UAS* mav = dynamic_cast(uas); +// if (mav) +// { +// QPushButton* startRecButton = new QPushButton(tr("Record")); +// connect(startRecButton, SIGNAL(clicked()), mav, SLOT(startDataRecording())); +// ui.gridLayout->addWidget(startRecButton, 7, 1); + +// QPushButton* pauseRecButton = new QPushButton(tr("Pause")); +// connect(pauseRecButton, SIGNAL(clicked()), mav, SLOT(pauseDataRecording())); +// ui.gridLayout->addWidget(pauseRecButton, 7, 3); + +// QPushButton* stopRecButton = new QPushButton(tr("Stop")); +// connect(stopRecButton, SIGNAL(clicked()), mav, SLOT(stopDataRecording())); +// ui.gridLayout->addWidget(stopRecButton, 7, 4); +// } this->uas = uas->getUASID(); @@ -140,6 +140,19 @@ UASControlWidget::~UASControlWidget() } +void UASControlWidget::updateStatemachine() +{ + + if (engineOn) + { + ui.controlButton->setText(tr("Stop Engine")); + } + else + { + ui.controlButton->setText(tr("Activate Engine")); + } +} + /** * Set the background color based on the MAV color. If the MAV is selected as the * currently actively controlled system, the frame color is highlighted @@ -258,16 +271,20 @@ void UASControlWidget::cycleContextButton() if (!engineOn) { - ui.controlButton->setText(tr("Stop Engine")); mav->enable_motors(); - ui.lastActionLabel->setText(QString("Attempted to enable motors on %1").arg(mav->getUASName())); + ui.lastActionLabel->setText(QString("Enabled motors on %1").arg(mav->getUASName())); } else { - ui.controlButton->setText(tr("Activate Engine")); mav->disable_motors(); - ui.lastActionLabel->setText(QString("Attempted to disable motors on %1").arg(mav->getUASName())); + ui.lastActionLabel->setText(QString("Disabled motors on %1").arg(mav->getUASName())); } + // Update state now and in several intervals when MAV might have changed state + updateStatemachine(); + + QTimer::singleShot(50, this, SLOT(updateStatemachine())); + QTimer::singleShot(200, this, SLOT(updateStatemachine())); + //ui.controlButton->setText(tr("Force Landing")); //ui.controlButton->setText(tr("KILL VEHICLE")); } diff --git a/src/ui/uas/UASControlWidget.h b/src/ui/uas/UASControlWidget.h index d799516d4db9257ae43520eb29d83e52933d35ac..003e25e7b30a26b68e8dca7d50a40bd9ec9198e5 100644 --- a/src/ui/uas/UASControlWidget.h +++ b/src/ui/uas/UASControlWidget.h @@ -63,6 +63,8 @@ public slots: void updateMode(int uas,QString mode,QString description); /** @brief Update state */ void updateState(int state); + /** @brief Update internal state machine */ + void updateStatemachine(); protected slots: /** @brief Set the background color for the widget */ diff --git a/src/ui/uas/UASView.cc b/src/ui/uas/UASView.cc index d76b1c7cb9a0b39ad8bfd77dd35a1beddb77480c..1cfe737ebdeb3a3cd87633420dc242ea1e546317 100644 --- a/src/ui/uas/UASView.cc +++ b/src/ui/uas/UASView.cc @@ -32,6 +32,7 @@ This file is part of the PIXHAWK project #include #include #include +#include #include "QGC.h" #include "MG.h" @@ -43,7 +44,7 @@ This file is part of the PIXHAWK project UASView::UASView(UASInterface* uas, QWidget *parent) : QWidget(parent), startTime(0), - lastHeartbeat(0), + timeout(false), iconIsRed(true), timeRemaining(0), chargeLevel(0), @@ -63,7 +64,8 @@ UASView::UASView(UASInterface* uas, QWidget *parent) : alt(0), groundDistance(0), localFrame(false), - removeAction(new QAction("Remove this system", this)), + removeAction(new QAction("Delete this system", this)), + renameAction(new QAction("Rename..", this)), m_ui(new Ui::UASView) { m_ui->setupUi(this); @@ -79,7 +81,7 @@ UASView::UASView(UASInterface* uas, QWidget *parent) : connect(uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString,QString))); connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString))); connect(uas, SIGNAL(loadChanged(UASInterface*, double)), this, SLOT(updateLoad(UASInterface*, double))); - //connect(uas, SIGNAL(waypointUpdated(int,int,double,double,double,double,bool,bool)), this, SLOT(setWaypoint(int,int,double,double,double,double,bool,bool))); + connect(uas, SIGNAL(heartbeatTimeout()), this, SLOT(heartbeatTimeout())); connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int,int))); connect(&(uas->getWaypointManager()), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointUpdated(quint16))); connect(uas, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint))); @@ -99,7 +101,11 @@ UASView::UASView(UASInterface* uas, QWidget *parent) : // Allow to delete this widget connect(removeAction, SIGNAL(triggered()), this, SLOT(deleteLater())); + connect(renameAction, SIGNAL(triggered()), this, SLOT(rename())); connect(uas, SIGNAL(systemRemoved()), this, SLOT(deleteLater())); + + // Name changes + connect(uas, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString))); // Set static values @@ -138,6 +144,11 @@ UASView::~UASView() delete m_ui; } +void UASView::heartbeatTimeout() +{ + timeout = true; +} + /** * Set the background color based on the MAV color. If the MAV is selected as the * currently actively controlled system, the frame color is highlighted @@ -241,8 +252,13 @@ void UASView::receiveHeartbeat(UASInterface* uas) heartbeatColor = QColor(20, 200, 20); QString colorstyle("QGroupBox { border-radius: 5px; padding: 2px; margin: 2px; border: 0px; background-color: %1; }"); m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(heartbeatColor.name())); - lastHeartbeat = QGC::groundTimeUsecs(); - //m_ui->heartbeatIcon->setAutoFillBackground(true); + if (timeout) setBackgroundColor(); + timeout = false; +} + +void UASView::updateName(const QString& name) +{ + if (uas) m_ui->nameLabel->setText(uas->getUASName()); } /** @@ -400,11 +416,25 @@ void UASView::updateLoad(UASInterface* uas, double load) void UASView::contextMenuEvent (QContextMenuEvent* event) { - if (QGC::groundTimeUsecs() - lastHeartbeat > 1500000) + QMenu menu(this); + menu.addAction(renameAction); + if (timeout) { - QMenu menu(this); menu.addAction(removeAction); - menu.exec(event->globalPos()); + } + menu.exec(event->globalPos()); +} + +void UASView::rename() +{ + if (uas) + { + bool ok; + QString newName = QInputDialog::getText(this, tr("Rename System %1").arg(uas->getUASName()), + tr("System Name:"), QLineEdit::Normal, + uas->getUASName(), &ok); + + if (ok && !newName.isEmpty()) uas->setUASName(newName); } } @@ -480,7 +510,7 @@ void UASView::refresh() // Thrust m_ui->thrustBar->setValue(thrust * 100); - if(this->timeRemaining > 1 && this->timeRemaining < MG::MAX_FLIGHT_TIME) + if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME) { // Filter output to get a higher stability static double filterTime = static_cast(this->timeRemaining); @@ -513,41 +543,40 @@ void UASView::refresh() QString colorstyle("QGroupBox { border-radius: 5px; padding: 2px; margin: 2px; border: 0px; background-color: %1; }"); - if (QGC::groundTimeUsecs() - lastHeartbeat > 1500000) + if (timeout) { // CRITICAL CONDITION, NO HEARTBEAT + QString borderColor = "#FFFF00"; + if (isActive) + { + borderColor = "#FA4A4F"; + } + if (iconIsRed) { QColor warnColor(Qt::red); m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(warnColor.name())); - QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; background-color: %1; }").arg(warnColor.name()); + QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; border: 2px solid %1; background-color: %2; }").arg(borderColor, warnColor.name()); m_ui->uasViewFrame->setStyleSheet(style); } else { QColor warnColor(Qt::black); m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(warnColor.name())); - QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; background-color: %1; }").arg(warnColor.name()); + QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; border: 2px solid %1; background-color: %2; }").arg(borderColor, warnColor.name()); m_ui->uasViewFrame->setStyleSheet(style); } iconIsRed = !iconIsRed; } else { - // Break alert once everything is back to normal - if (!iconIsRed) - { - setBackgroundColor(); - iconIsRed = true; - } + // Fade heartbeat icon + // Make color darker + heartbeatColor = heartbeatColor.darker(150); - // Fade heartbeat icon - // Make color darker - heartbeatColor = heartbeatColor.darker(150); - - //m_ui->heartbeatIcon->setAutoFillBackground(true); - m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(heartbeatColor.name())); + //m_ui->heartbeatIcon->setAutoFillBackground(true); + m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(heartbeatColor.name())); } //setUpdatesEnabled(true); diff --git a/src/ui/uas/UASView.h b/src/ui/uas/UASView.h index 0f6ca11c125e9ba935f22b22b22baab291389ac2..1a62248c34dc101bb88c6c4b95b0004af12e5468 100644 --- a/src/ui/uas/UASView.h +++ b/src/ui/uas/UASView.h @@ -50,6 +50,8 @@ public: ~UASView(); public slots: + /** @brief Update the name of the system */ + void updateName(const QString& name); void receiveHeartbeat(UASInterface* uas); void updateThrust(UASInterface* uas, double thrust); void updateBattery(UASInterface* uas, double voltage, double percent, int seconds); @@ -74,15 +76,19 @@ public slots: void setUASasActive(bool); /** @brief Update the view if an UAS has been set to active */ void updateActiveUAS(UASInterface* uas, bool active); + /** @brief Set the widget into critical mode */ + void heartbeatTimeout(); /** @brief Set the background color for the widget */ void setBackgroundColor(); + /** @brief Bring up the dialog to rename the system */ + void rename(); protected: void changeEvent(QEvent *e); QTimer* refreshTimer; QColor heartbeatColor; quint64 startTime; - quint64 lastHeartbeat; + bool timeout; bool iconIsRed; int timeRemaining; float chargeLevel; @@ -103,6 +109,7 @@ protected: float groundDistance; bool localFrame; QAction* removeAction; + QAction* renameAction; static const int updateInterval = 300;