diff --git a/ground/openpilotgcs/src/plugins/logging/logfile.cpp b/ground/openpilotgcs/src/libs/utils/logfile.cpp similarity index 51% rename from ground/openpilotgcs/src/plugins/logging/logfile.cpp rename to ground/openpilotgcs/src/libs/utils/logfile.cpp index 2b1647139..4c20b413f 100644 --- a/ground/openpilotgcs/src/plugins/logging/logfile.cpp +++ b/ground/openpilotgcs/src/libs/utils/logfile.cpp @@ -4,12 +4,14 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent), - lastTimeStamp(0), - lastPlayed(0), - timeOffset(0), - playbackSpeed(1.0) + m_lastTimeStamp(0), + m_lastPlayed(0), + m_timeOffset(0), + m_playbackSpeed(1.0), + m_nextTimeStamp(0), + m_useProvidedTimeStamp(false) { - connect(&timer, SIGNAL(timeout()), this, SLOT(timerFired())); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired())); } /** @@ -20,8 +22,8 @@ LogFile::LogFile(QObject *parent) : bool LogFile::open(OpenMode mode) { // start a timer for playback - myTime.restart(); - if (file.isOpen()) { + m_myTime.restart(); + if (m_file.isOpen()) { // We end up here when doing a replay, because the connection // manager will also try to open the QIODevice, even though we just // opened it after selecting the file, which happens before the @@ -29,8 +31,8 @@ bool LogFile::open(OpenMode mode) return true; } - if (file.open(mode) == false) { - qDebug() << "Unable to open " << file.fileName() << " for logging"; + if (m_file.open(mode) == false) { + qDebug() << "Unable to open " << m_file.fileName() << " for logging"; return false; } @@ -49,25 +51,27 @@ void LogFile::close() { emit aboutToClose(); - if (timer.isActive()) { - timer.stop(); + if (m_timer.isActive()) { + m_timer.stop(); } - file.close(); + m_file.close(); QIODevice::close(); } qint64 LogFile::writeData(const char *data, qint64 dataSize) { - if (!file.isWritable()) { + if (!m_file.isWritable()) { return dataSize; } - quint32 timeStamp = myTime.elapsed(); + // If m_nextTimeStamp != -1 then use this timestamp instead of the timer + // This is used when saving logs from on-board logging + quint32 timeStamp = m_useProvidedTimeStamp ? m_nextTimeStamp : m_myTime.elapsed(); - file.write((char *)&timeStamp, sizeof(timeStamp)); - file.write((char *)&dataSize, sizeof(dataSize)); + m_file.write((char *)&timeStamp, sizeof(timeStamp)); + m_file.write((char *)&dataSize, sizeof(dataSize)); - qint64 written = file.write(data, dataSize); + qint64 written = m_file.write(data, dataSize); if (written != -1) { emit bytesWritten(written); } @@ -77,36 +81,36 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize) qint64 LogFile::readData(char *data, qint64 maxSize) { - QMutexLocker locker(&mutex); - qint64 toRead = qMin(maxSize, (qint64)dataBuffer.size()); + QMutexLocker locker(&m_mutex); + qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size()); - memcpy(data, dataBuffer.data(), toRead); - dataBuffer.remove(0, toRead); + memcpy(data, m_dataBuffer.data(), toRead); + m_dataBuffer.remove(0, toRead); return toRead; } qint64 LogFile::bytesAvailable() const { - return dataBuffer.size(); + return m_dataBuffer.size(); } void LogFile::timerFired() { qint64 dataSize; - if (file.bytesAvailable() > 4) { + if (m_file.bytesAvailable() > 4) { int time; - time = myTime.elapsed(); + time = m_myTime.elapsed(); // TODO: going back in time will be a problem - while ((lastPlayed + ((time - timeOffset) * playbackSpeed) > lastTimeStamp)) { - lastPlayed += ((time - timeOffset) * playbackSpeed); - if (file.bytesAvailable() < sizeof(dataSize)) { + while ((m_lastPlayed + ((time - m_timeOffset) * m_playbackSpeed) > m_lastTimeStamp)) { + m_lastPlayed += ((time - m_timeOffset) * m_playbackSpeed); + if (m_file.bytesAvailable() < sizeof(dataSize)) { stopReplay(); return; } - file.read((char *)&dataSize, sizeof(dataSize)); + m_file.read((char *)&dataSize, sizeof(dataSize)); if (dataSize < 1 || dataSize > (1024 * 1024)) { qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n"; @@ -114,34 +118,34 @@ void LogFile::timerFired() return; } - if (file.bytesAvailable() < dataSize) { + if (m_file.bytesAvailable() < dataSize) { stopReplay(); return; } - mutex.lock(); - dataBuffer.append(file.read(dataSize)); - mutex.unlock(); + m_mutex.lock(); + m_dataBuffer.append(m_file.read(dataSize)); + m_mutex.unlock(); emit readyRead(); - if (file.bytesAvailable() < sizeof(lastTimeStamp)) { + if (m_file.bytesAvailable() < sizeof(m_lastTimeStamp)) { stopReplay(); return; } - int save = lastTimeStamp; - file.read((char *)&lastTimeStamp, sizeof(lastTimeStamp)); + int save = m_lastTimeStamp; + m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); // some validity checks - if (lastTimeStamp < save // logfile goes back in time - || (lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes) - qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << lastTimeStamp << " after " << save << "\n"; + if (m_lastTimeStamp < save // logfile goes back in time + || (m_lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes) + qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << m_lastTimeStamp << " after " << save << "\n"; stopReplay(); return; } - timeOffset = time; - time = myTime.elapsed(); + m_timeOffset = time; + time = m_myTime.elapsed(); } } else { stopReplay(); @@ -150,13 +154,13 @@ void LogFile::timerFired() bool LogFile::startReplay() { - dataBuffer.clear(); - myTime.restart(); - timeOffset = 0; - lastPlayed = 0; - file.read((char *)&lastTimeStamp, sizeof(lastTimeStamp)); - timer.setInterval(10); - timer.start(); + m_dataBuffer.clear(); + m_myTime.restart(); + m_timeOffset = 0; + m_lastPlayed = 0; + m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); + m_timer.setInterval(10); + m_timer.start(); emit replayStarted(); return true; } @@ -170,11 +174,11 @@ bool LogFile::stopReplay() void LogFile::pauseReplay() { - timer.stop(); + m_timer.stop(); } void LogFile::resumeReplay() { - timeOffset = myTime.elapsed(); - timer.start(); + m_timeOffset = m_myTime.elapsed(); + m_timer.start(); } diff --git a/ground/openpilotgcs/src/plugins/logging/logfile.h b/ground/openpilotgcs/src/libs/utils/logfile.h similarity index 51% rename from ground/openpilotgcs/src/plugins/logging/logfile.h rename to ground/openpilotgcs/src/libs/utils/logfile.h index ae936a7c4..26e0f86ca 100644 --- a/ground/openpilotgcs/src/plugins/logging/logfile.h +++ b/ground/openpilotgcs/src/libs/utils/logfile.h @@ -7,22 +7,22 @@ #include #include #include -#include "uavobjectmanager.h" -#include +#include +#include "utils_global.h" -class LogFile : public QIODevice { +class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { Q_OBJECT public: explicit LogFile(QObject *parent = 0); qint64 bytesAvailable() const; qint64 bytesToWrite() { - return file.bytesToWrite(); + return m_file.bytesToWrite(); }; bool open(OpenMode mode); void setFileName(QString name) { - file.setFileName(name); + m_file.setFileName(name); }; void close(); qint64 writeData(const char *data, qint64 dataSize); @@ -30,12 +30,21 @@ public: bool startReplay(); bool stopReplay(); + void useProvidedTimeStamp(bool useProvidedTimeStamp) + { + m_useProvidedTimeStamp = useProvidedTimeStamp; + } + + void setNextTimeStamp(quint32 nextTimestamp) + { + m_nextTimeStamp = nextTimestamp; + } public slots: void setReplaySpeed(double val) { - playbackSpeed = val; - qDebug() << "Playback speed is now" << playbackSpeed; + m_playbackSpeed = val; + qDebug() << "Playback speed is now" << m_playbackSpeed; }; void pauseReplay(); void resumeReplay(); @@ -49,17 +58,21 @@ signals: void replayFinished(); protected: - QByteArray dataBuffer; - QTimer timer; - QTime myTime; - QFile file; - qint32 lastTimeStamp; - qint32 lastPlayed; - QMutex mutex; + QByteArray m_dataBuffer; + QTimer m_timer; + QTime m_myTime; + QFile m_file; + qint32 m_lastTimeStamp; + qint32 m_lastPlayed; + QMutex m_mutex; - int timeOffset; - double playbackSpeed; + int m_timeOffset; + double m_playbackSpeed; + +private: + quint32 m_nextTimeStamp; + bool m_useProvidedTimeStamp; }; #endif // LOGFILE_H diff --git a/ground/openpilotgcs/src/libs/utils/utils.pro b/ground/openpilotgcs/src/libs/utils/utils.pro index 202751020..311212891 100644 --- a/ground/openpilotgcs/src/libs/utils/utils.pro +++ b/ground/openpilotgcs/src/libs/utils/utils.pro @@ -54,7 +54,8 @@ SOURCES += reloadpromptutils.cpp \ mytabwidget.cpp \ cachedsvgitem.cpp \ svgimageprovider.cpp \ - hostosinfo.cpp + hostosinfo.cpp \ + logfile.cpp SOURCES += xmlconfig.cpp @@ -111,7 +112,8 @@ HEADERS += utils_global.h \ mytabwidget.h \ cachedsvgitem.h \ svgimageprovider.h \ - hostosinfo.h + hostosinfo.h \ + logfile.h HEADERS += xmlconfig.h diff --git a/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec b/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec new file mode 100644 index 000000000..8baef7f37 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec @@ -0,0 +1,10 @@ + + The OpenPilot Project + (C) 2013 OpenPilot Project + The GNU Public License (GPL) Version 3 + A plugin to manage flight side logs, viewing and downloading. + http://www.openpilot.org + + + + diff --git a/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml b/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml new file mode 100644 index 000000000..9f33efebd --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml @@ -0,0 +1,189 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +import org.openpilot 1.0 + +import "functions.js" as Functions + +Rectangle { + width: 600 + height: 400 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + border.width: 1 + radius: 4 + ColumnLayout { + anchors.margins: 10 + anchors.fill: parent + Text { + Layout.fillWidth: true + text: "" + qsTr("Log entries") + "" + font.pixelSize: 12 + } + TableView { + Layout.fillWidth: true + Layout.fillHeight: true + model: logManager.logEntries + + itemDelegate: Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: styleData.value + } + + TableViewColumn { + role: "Flight"; title: qsTr("Flight"); width: 50; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: styleData.value + 1 + } + + } + TableViewColumn { + role: "FlightTime"; title: qsTr("Time"); width: 80; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: Functions.millisToTime(styleData.value) + } + } + TableViewColumn { + role: "Type"; title: "Type"; width: 50; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: { + switch(styleData.value) { + case 0 : text: qsTr("Empty"); break; + case 1 : text: qsTr("Text"); break; + case 2 : text: qsTr("UAVO"); break; + default: text: qsTr("Unknown"); break; + } + } + } + + } + TableViewColumn { role: "LogString"; title: qsTr("Data"); width: 280} + } + + RowLayout { + anchors.margins: 10 + spacing: 10 + ColumnLayout { + spacing: 10 + Text { + id: totalFlights + font.pixelSize: 12 + text: "" + qsTr("Flights recorded: ") + "" + (logStatus.Flight + 1) + } + Text { + id: totalEntries + font.pixelSize: 12 + text: "" + qsTr("Entries logged (free): ") + "" + + logStatus.UsedSlots + " (" + logStatus.FreeSlots + ")" + } + } + Rectangle { + Layout.fillWidth: true + } + ColumnLayout { + spacing: 10 + RowLayout { + Rectangle { + Layout.fillWidth: true + } + Text { + font.pixelSize: 12 + text: "" + qsTr("Flight to download:") + "" + } + + ComboBox { + id: flightCombo + enabled: !logManager.disableControls + model: logManager.flightEntries + } + } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Rectangle { + Layout.fillWidth: true + } + Button { + text: qsTr("Download logs") + enabled: !logManager.disableControls + activeFocusOnPress: true + onClicked: logManager.retrieveLogs(flightCombo.currentIndex - 1) + } + } + } + } + } + } + + RowLayout { + Layout.fillWidth: true + height: 40 + Button { + id: exportButton + enabled: !logManager.disableControls && !logManager.disableExport + text: qsTr("Export...") + activeFocusOnPress: true + onClicked: logManager.exportLogs() + } + CheckBox { + id: exportRelativeTimeCB + enabled: !logManager.disableControls && !logManager.disableExport + text: qsTr("Adjust timestamps") + activeFocusOnPress: true + checked: logManager.adjustExportedTimestamps + onCheckedChanged: logManager.setAdjustExportedTimestamps(checked) + } + + Button { + id: clearButton + enabled: !logManager.disableControls + text: qsTr("Clear all logs") + activeFocusOnPress: true + onClicked: logManager.clearAllLogs() + } + Rectangle { + Layout.fillWidth: true + } + Button { + id: cancelButton + enabled: logManager.disableControls + text: qsTr("Cancel") + activeFocusOnPress: true + onClicked: logManager.cancelExportLogs() + } + Button { + id: okButton + enabled: !logManager.disableControls + text: qsTr("OK") + isDefault: true + activeFocusOnPress: true + onClicked: dialog.close() + } + } + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc b/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc new file mode 100644 index 000000000..4283127f5 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc @@ -0,0 +1,6 @@ + + + FlightLogDialog.qml + functions.js + + diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro b/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro new file mode 100644 index 000000000..dfae3248b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro @@ -0,0 +1,25 @@ +TEMPLATE = lib +TARGET = FlightLog + +QT += qml quick + +include(../../openpilotgcsplugin.pri) +include(../../plugins/coreplugin/coreplugin.pri) +include(../../plugins/uavobjects/uavobjects.pri) +include(../../plugins/uavtalk/uavtalk.pri) + +HEADERS += flightlogplugin.h \ + flightlogmanager.h \ + flightlogdialog.h +SOURCES += flightlogplugin.cpp \ + flightlogmanager.cpp \ + flightlogdialog.cpp + +OTHER_FILES += Flightlog.pluginspec \ + FlightLogDialog.qml \ + functions.js + +FORMS += + +RESOURCES += \ + flightLog.qrc diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp new file mode 100644 index 000000000..65f04f575 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * + * @file flightlogdialog.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogDialog + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "flightlogdialog.h" + +#include + +#include +#include +#include +#include + +#include "flightlogmanager.h" + +FlightLogDialog::FlightLogDialog(QWidget *parent, FlightLogManager *flightLogManager) : + QDialog(parent) +{ + qmlRegisterType("org.openpilot", 1, 0, "DebugLogEntry"); + + setWindowIcon(QIcon(":/core/images/openpilot_logo_32.png")); + setWindowTitle(tr("Manage flight side logs")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setMinimumSize(600, 400); + + QQuickView *view = new QQuickView(); + view->rootContext()->setContextProperty("dialog", this); + view->rootContext()->setContextProperty("logStatus", flightLogManager->flightLogStatus()); + view->rootContext()->setContextProperty("logManager", flightLogManager); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->setSource(QUrl("qrc:/flightlog/FlightLogDialog.qml")); + + QWidget *container = QWidget::createWindowContainer(view); + container->setMinimumSize(600, 400); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QVBoxLayout *lay = new QVBoxLayout(); + lay->setContentsMargins(0, 0, 0, 0); + setLayout(lay); + layout()->addWidget(container); +} + +FlightLogDialog::~FlightLogDialog() +{} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h new file mode 100644 index 000000000..d1b2fd18e --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h @@ -0,0 +1,15 @@ +#ifndef FLIGHTLOGDIALOG_H +#define FLIGHTLOGDIALOG_H + +#include +#include "flightlogmanager.h" + +class FlightLogDialog : public QDialog { + Q_OBJECT + +public: + explicit FlightLogDialog(QWidget *parent, FlightLogManager *flightLogManager); + ~FlightLogDialog(); +}; + +#endif // FLIGHTLOGDIALOG_H diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp new file mode 100644 index 000000000..04bd822a4 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp @@ -0,0 +1,311 @@ +/** + ****************************************************************************** + * + * @file flightlogmanager.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogManager + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "flightlogmanager.h" +#include "extensionsystem/pluginmanager.h" + +#include +#include + +#include "debuglogcontrol.h" +#include "uavobjecthelper.h" +#include "uavtalk/uavtalk.h" +#include "utils/logfile.h" + +FlightLogManager::FlightLogManager(QObject *parent) : + QObject(parent), m_disableControls(false), + m_disableExport(true), m_cancelDownload(false), + m_adjustExportedTimestamps(true) +{ + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + + m_objectManager = pm->getObject(); + Q_ASSERT(m_objectManager); + + m_flightLogControl = DebugLogControl::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogControl); + + m_flightLogStatus = DebugLogStatus::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogStatus); + connect(m_flightLogStatus, SIGNAL(FlightChanged(quint16)), this, SLOT(updateFlightEntries(quint16))); + + m_flightLogEntry = DebugLogEntry::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogEntry); + + updateFlightEntries(m_flightLogStatus->getFlight()); +} + +FlightLogManager::~FlightLogManager() +{ + while (!m_logEntries.isEmpty()) { + delete m_logEntries.takeFirst(); + } +} + +void addLogEntries(QQmlListProperty *list, ExtendedDebugLogEntry *entry) +{ + Q_UNUSED(list); + Q_UNUSED(entry); +} + +int countLogEntries(QQmlListProperty *list) +{ + return static_cast< QList *>(list->data)->size(); +} + +ExtendedDebugLogEntry *logEntryAt(QQmlListProperty *list, int index) +{ + return static_cast< QList *>(list->data)->at(index); +} + +void clearLogEntries(QQmlListProperty *list) +{ + return static_cast< QList *>(list->data)->clear(); +} + +QQmlListProperty FlightLogManager::logEntries() +{ + return QQmlListProperty(this, &m_logEntries, &addLogEntries, &countLogEntries, &logEntryAt, &clearLogEntries); +} + +QStringList FlightLogManager::flightEntries() +{ + return m_flightEntries; +} + +void FlightLogManager::clearAllLogs() +{ + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Clear on flight side + UAVObjectUpdaterHelper updateHelper; + + m_flightLogControl->setFlight(0); + m_flightLogControl->setEntry(0); + m_flightLogControl->setOperation(DebugLogControl::OPERATION_FORMATFLASH); + if (updateHelper.doObjectAndWait(m_flightLogControl, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS) { + // Then empty locally + clearLogList(); + } + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::clearLogList() +{ + QList tmpList(m_logEntries); + m_logEntries.clear(); + + emit logEntriesChanged(); + setDisableExport(true); + + while (!tmpList.isEmpty()) { + delete tmpList.takeFirst(); + } +} + +void FlightLogManager::retrieveLogs(int flightToRetrieve) +{ + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + m_cancelDownload = false; + UAVObjectUpdaterHelper updateHelper; + UAVObjectRequestHelper requestHelper; + + clearLogList(); + + // Set up what to retrieve + int startFlight = (flightToRetrieve == -1) ? 0 : flightToRetrieve; + int endFlight = (flightToRetrieve == -1) ? m_flightLogStatus->getFlight() : flightToRetrieve; + + // Prepare to send request for event retrieval + m_flightLogControl->setOperation(DebugLogControl::OPERATION_RETRIEVE); + for (int flight = startFlight; flight <= endFlight; flight++) { + m_flightLogControl->setFlight(flight); + bool gotLast = false; + int entry = 0; + while (!gotLast) { + // Send request for loading flight entry on flight side and wait for ack/nack + m_flightLogControl->setEntry(entry); + + if (updateHelper.doObjectAndWait(m_flightLogControl, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS && + requestHelper.doObjectAndWait(m_flightLogEntry, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS) { + if (m_flightLogEntry->getType() != DebugLogEntry::TYPE_EMPTY) { + // Ok, we retrieved the entry, and it was the correct one. clone it and add it to the list + ExtendedDebugLogEntry *logEntry = new ExtendedDebugLogEntry(); + logEntry->setData(m_flightLogEntry->getData(), m_objectManager); + m_logEntries << logEntry; + + // Increment to get next entry from flight side + entry++; + } else { + // We are done, not more entries on this flight + gotLast = true; + } + } else { + // We failed for some reason + break; + } + if (m_cancelDownload) { + break; + } + } + if (m_cancelDownload) { + break; + } + } + + if (m_cancelDownload) { + clearLogList(); + m_cancelDownload = false; + } + + emit logEntriesChanged(); + setDisableExport(m_logEntries.count() == 0); + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::exportLogs() +{ + if(m_logEntries.isEmpty()) { + return; + } + + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + + QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save Log"), + tr("OP-%0.opl").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")), + tr("OpenPilot Log (*.opl)")); + if (!fileName.isEmpty()) { + // Loop and create a new file for each flight. + fileName = fileName.replace(QString(".opl"), QString("%1.opl")); + int currentEntry = 0; + int currentFlight = 0; + quint32 adjustedBaseTime = 0; + // Continue until all entries are exported + while(currentEntry < m_logEntries.count()) { + + if (m_adjustExportedTimestamps) { + adjustedBaseTime = m_logEntries[currentEntry]->getFlightTime(); + } + + // Get current flight + currentFlight = m_logEntries[currentEntry]->getFlight(); + + LogFile logFile; + logFile.useProvidedTimeStamp(true); + + // Set the file name to contain flight number + logFile.setFileName(fileName.arg(tr("_flight-%1").arg(currentFlight + 1))); + logFile.open(QIODevice::WriteOnly); + UAVTalk uavTalk(&logFile, m_objectManager); + + // Export entries until no more available or flight changes + while(currentEntry < m_logEntries.count() && m_logEntries[currentEntry]->getFlight() == currentFlight) { + ExtendedDebugLogEntry* entry = m_logEntries[currentEntry]; + + // Only log uavobjects + if (entry->getType() == ExtendedDebugLogEntry::TYPE_UAVOBJECT) { + // Set timestamp that should be logged for this entry + logFile.setNextTimeStamp(entry->getFlightTime() - adjustedBaseTime); + + // Use UAVTalk to log complete message to file + uavTalk.sendObject(entry->uavObject(), false, false); + qDebug() << entry->getFlightTime() - adjustedBaseTime << "=" << entry->toStringBrief(); + } + currentEntry++; + } + + logFile.close(); + } + + } + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::cancelExportLogs() +{ + m_cancelDownload = true; +} + +void FlightLogManager::updateFlightEntries(quint16 currentFlight) +{ + Q_UNUSED(currentFlight); + + int flights = m_flightLogStatus->getFlight(); + if (m_flightEntries.count() == 0 || (m_flightEntries.count() - 1 != flights)) { + m_flightEntries.clear(); + + m_flightEntries << tr("All"); + for(int i = 0; i <= flights; i++) { + m_flightEntries << QString::number(i + 1); + } + + emit flightEntriesChanged(); + } +} + +ExtendedDebugLogEntry::ExtendedDebugLogEntry() : DebugLogEntry(), + m_object(0) +{} + +ExtendedDebugLogEntry::~ExtendedDebugLogEntry() +{ + if (m_object) { + delete m_object; + m_object = 0; + } +} + +QString ExtendedDebugLogEntry::getLogString() +{ + if (getType() == DebugLogEntry::TYPE_TEXT) { + return QString((const char *)getData().Data); + } else if (getType() == DebugLogEntry::TYPE_UAVOBJECT) { + return m_object->toString().replace("\n", " ").replace("\t", " "); + } else { + return ""; + } +} + +void ExtendedDebugLogEntry::setData(const DebugLogEntry::DataFields &data, UAVObjectManager *objectManager) +{ + DebugLogEntry::setData(data); + if (getType() == DebugLogEntry::TYPE_UAVOBJECT) { + UAVDataObject *object = (UAVDataObject *)objectManager->getObject(getObjectID(), getInstanceID()); + Q_ASSERT(object); + m_object = object->clone(getInstanceID()); + m_object->unpack(getData().Data); + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h new file mode 100644 index 000000000..eb5915d07 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h @@ -0,0 +1,162 @@ +/** + ****************************************************************************** + * + * @file flightlogmanager.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogManager + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FLIGHTLOGMANAGER_H +#define FLIGHTLOGMANAGER_H + +#include +#include +#include +#include + +#include "uavobjectmanager.h" +#include "debuglogentry.h" +#include "debuglogstatus.h" +#include "debuglogcontrol.h" + +class ExtendedDebugLogEntry : public DebugLogEntry { + Q_OBJECT Q_PROPERTY(QString LogString READ getLogString WRITE setLogString NOTIFY LogStringUpdated) + +public: + explicit ExtendedDebugLogEntry(); + ~ExtendedDebugLogEntry(); + + QString getLogString(); + UAVDataObject *uavObject() + { + return m_object; + } + + void setData(const DataFields& data, UAVObjectManager *objectManager); + +public slots: + void setLogString(QString arg) + { + Q_UNUSED(arg); + } + +signals: + void LogStringUpdated(QString arg); + +private: + UAVDataObject *m_object; +}; + +class FlightLogManager : public QObject { + Q_OBJECT Q_PROPERTY(DebugLogStatus *flightLogStatus READ flightLogStatus) + Q_PROPERTY(QQmlListProperty logEntries READ logEntries NOTIFY logEntriesChanged) + Q_PROPERTY(QStringList flightEntries READ flightEntries NOTIFY flightEntriesChanged) + Q_PROPERTY(bool disableControls READ disableControls WRITE setDisableControls NOTIFY disableControlsChanged) + Q_PROPERTY(bool disableExport READ disableExport WRITE setDisableExport NOTIFY disableExportChanged) + Q_PROPERTY(bool adjustExportedTimestamps READ adjustExportedTimestamps WRITE setAdjustExportedTimestamps NOTIFY adjustExportedTimestampsChanged) + +public: + explicit FlightLogManager(QObject *parent = 0); + ~FlightLogManager(); + + QQmlListProperty logEntries(); + QStringList flightEntries(); + + DebugLogStatus *flightLogStatus() const + { + return m_flightLogStatus; + } + + bool disableControls() const + { + return m_disableControls; + } + + bool disableExport() const + { + return m_disableExport; + } + + void clearLogList(); + + bool adjustExportedTimestamps() const + { + return m_adjustExportedTimestamps; + } + +signals: + void logEntriesChanged(); + void flightEntriesChanged(); + void disableControlsChanged(bool arg); + void disableExportChanged(bool arg); + + void adjustExportedTimestampsChanged(bool arg); + +public slots: + void clearAllLogs(); + void retrieveLogs(int flightToRetrieve = -1); + void exportLogs(); + void cancelExportLogs(); + + void setDisableControls(bool arg) + { + if (m_disableControls != arg) { + m_disableControls = arg; + emit disableControlsChanged(arg); + } + } + + void setDisableExport(bool arg) + { + if (m_disableExport != arg) { + m_disableExport = arg; + emit disableExportChanged(arg); + } + } + + void setAdjustExportedTimestamps(bool arg) + { + if (m_adjustExportedTimestamps != arg) { + m_adjustExportedTimestamps = arg; + emit adjustExportedTimestampsChanged(arg); + } + } + +private slots: + void updateFlightEntries(quint16 currentFlight); + +private: + UAVObjectManager *m_objectManager; + DebugLogControl *m_flightLogControl; + DebugLogStatus *m_flightLogStatus; + DebugLogEntry *m_flightLogEntry; + QList m_logEntries; + QStringList m_flightEntries; + + static const int UAVTALK_TIMEOUT = 4000; + bool m_disableControls; + bool m_disableExport; + bool m_cancelDownload; + bool m_adjustExportedTimestamps; +}; + +#endif // FLIGHTLOGMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp new file mode 100644 index 000000000..5b8e9def6 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * + * @file flightlogplugin.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @brief A plugin to view and download flight side logs. + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "flightlogplugin.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "flightlogdialog.h" + +FlightLogPlugin::FlightLogPlugin() : m_logDialog(0) +{} + +FlightLogPlugin::~FlightLogPlugin() +{ + shutdown(); +} + +bool FlightLogPlugin::initialize(const QStringList & args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + // Add Menu entry + Core::ActionManager *am = Core::ICore::instance()->actionManager(); + Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); + + Core::Command *cmd = am->registerAction(new QAction(this), + "FlightLogPlugin.ShowFlightLogDialog", + QList() << + Core::Constants::C_GLOBAL_ID); + cmd->setDefaultKeySequence(QKeySequence("Ctrl+F")); + cmd->action()->setText(tr("Manage flight side logs...")); + + Core::ModeManager::instance()->addAction(cmd, 1); + + ac->menu()->addSeparator(); + ac->appendGroup("FlightLogs"); + ac->addAction(cmd, "FlightLogs"); + + connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(ShowLogManagementDialog())); + return true; +} + +void FlightLogPlugin::ShowLogManagementDialog() +{ + if (!m_logDialog) { + m_logDialog = new FlightLogDialog(0, new FlightLogManager()); + connect(m_logDialog, SIGNAL(finished(int)), this, SLOT(LogManagementDialogClosed())); + m_logDialog->show(); + } +} + +void FlightLogPlugin::LogManagementDialogClosed() +{ + if (m_logDialog) { + m_logDialog->deleteLater(); + m_logDialog = 0; + } +} + +void FlightLogPlugin::extensionsInitialized() +{} + +void FlightLogPlugin::shutdown() +{ + if (m_logDialog) { + m_logDialog->close(); + LogManagementDialogClosed(); + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h new file mode 100644 index 000000000..81194272c --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * + * @file flightlogplugin.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @brief A plugin to view and download flight side logs. + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FLIGHTLOGPLUGIN_H_ +#define FLIGHTLOGPLUGIN_H_ + +#include +#include "flightlogmanager.h" +#include "flightlogdialog.h" + +class FlightLogPlugin : public ExtensionSystem::IPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "OpenPilot.FlightLog") + +public: + FlightLogPlugin(); + ~FlightLogPlugin(); + + void extensionsInitialized(); + bool initialize(const QStringList & arguments, QString *errorString); + void shutdown(); + +private slots: + void ShowLogManagementDialog(); + void LogManagementDialogClosed(); + +private: + FlightLogDialog *m_logDialog; +}; + +#endif /* FLIGHTLOGPLUGIN_H_ */ diff --git a/ground/openpilotgcs/src/plugins/flightlog/functions.js b/ground/openpilotgcs/src/plugins/flightlog/functions.js new file mode 100644 index 000000000..47884432b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/functions.js @@ -0,0 +1,20 @@ +.pragma library + +function millisToTime(ms) { + var secs = Math.floor(ms / 1000); + var msleft = ms % 1000; + var hours = Math.floor(secs / (60 * 60)); + var divisor_for_minutes = secs % (60 * 60); + var minutes = Math.floor(divisor_for_minutes / 60); + var divisor_for_seconds = divisor_for_minutes % 60; + var seconds = Math.ceil(divisor_for_seconds); + return pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + ":" + pad(msleft, 3); +} + +function pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = '0' + str; + } + return str; +} diff --git a/ground/openpilotgcs/src/plugins/logging/logging.pro b/ground/openpilotgcs/src/plugins/logging/logging.pro index 8d10d54a3..5514f4034 100644 --- a/ground/openpilotgcs/src/plugins/logging/logging.pro +++ b/ground/openpilotgcs/src/plugins/logging/logging.pro @@ -1,25 +1,22 @@ TEMPLATE = lib + TARGET = LoggingGadget DEFINES += LOGGING_LIBRARY QT += svg + include(../../openpilotgcsplugin.pri) include(logging_dependencies.pri) HEADERS += loggingplugin.h \ - logfile.h \ logginggadgetwidget.h \ logginggadget.h \ logginggadgetfactory.h -# logginggadgetconfiguration.h -# logginggadgetoptionspage.h SOURCES += loggingplugin.cpp \ - logfile.cpp \ logginggadgetwidget.cpp \ logginggadget.cpp \ logginggadgetfactory.cpp -# logginggadgetconfiguration.cpp \ -# logginggadgetoptionspage.cpp + OTHER_FILES += LoggingGadget.pluginspec + FORMS += logging.ui -# logginggadgetwidget.ui \ -# loggingdialog.ui + diff --git a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp index fc88cbe98..74239e5c6 100644 --- a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp @@ -323,7 +323,7 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg) QList() << Core::Constants::C_GLOBAL_ID); cmd->setDefaultKeySequence(QKeySequence("Ctrl+L")); - cmd->action()->setText("Start logging..."); + cmd->action()->setText(tr("Start logging...")); ac->menu()->addSeparator(); ac->appendGroup("Logging"); diff --git a/ground/openpilotgcs/src/plugins/logging/loggingplugin.h b/ground/openpilotgcs/src/plugins/logging/loggingplugin.h index ed697714e..7c2ed7406 100644 --- a/ground/openpilotgcs/src/plugins/logging/loggingplugin.h +++ b/ground/openpilotgcs/src/plugins/logging/loggingplugin.h @@ -35,7 +35,7 @@ #include "uavobjectmanager.h" #include "gcstelemetrystats.h" #include -#include +#include #include #include diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index f8c68a1bb..c09d5567d 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -244,3 +244,10 @@ plugin_setupwizard.depends += plugin_config plugin_setupwizard.depends += plugin_uploader SUBDIRS += plugin_setupwizard +# Flight Logs plugin +plugin_flightlog.subdir = flightlog +plugin_flightlog.depends = plugin_coreplugin +plugin_flightlog.depends += plugin_uavobjects +plugin_flightlog.depends += plugin_uavtalk +SUBDIRS += plugin_flightlog + diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp new file mode 100644 index 000000000..25ff5f805 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * + * @file uavobjecthelper.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup UAVObjectHelper + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "uavobjecthelper.h" +#include + +AbstractUAVObjectHelper::AbstractUAVObjectHelper(QObject *parent) : + QObject(parent), m_transactionResult(false), m_transactionCompleted(false) +{} + +AbstractUAVObjectHelper::Result AbstractUAVObjectHelper::doObjectAndWait(UAVObject *object, int timeout) +{ + // Lock, we can't call this twice from different threads + QMutexLocker locker(&m_mutex); + + m_object = object; + + // Reset variables + m_transactionResult = false; + m_transactionCompleted = false; + + // Create timer and connect it, connect object tx completed to local slot + QTimer timeoutTimer; + timeoutTimer.setSingleShot(true); + connect(&timeoutTimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); + connect(object, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); + + // Start timeout timer + timeoutTimer.start(timeout); + + // Call the actual implementation in concrete subclass + doObjectAndWaitImpl(); + + // Wait if not completed + if (!m_transactionCompleted) { + m_eventLoop.exec(); + } + timeoutTimer.stop(); + + // Disconnect + disconnect(object, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); + disconnect(&timeoutTimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); + + // Return result + if (!m_transactionCompleted) { + return TIMEOUT; + } else { + return m_transactionResult ? SUCCESS : FAIL; + } +} + +void AbstractUAVObjectHelper::transactionCompleted(UAVObject *object, bool success) +{ + Q_UNUSED(object) + + // Set variables and quit event loop + m_transactionResult = success; + m_transactionCompleted = true; + m_eventLoop.quit(); +} + +UAVObjectUpdaterHelper::UAVObjectUpdaterHelper(QObject *parent) : AbstractUAVObjectHelper(parent) +{} + +void UAVObjectUpdaterHelper::doObjectAndWaitImpl() +{ + m_object->updated(); +} + +UAVObjectRequestHelper::UAVObjectRequestHelper(QObject *parent) : AbstractUAVObjectHelper(parent) +{} + +void UAVObjectRequestHelper::doObjectAndWaitImpl() +{ + m_object->requestUpdate(); +} diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h new file mode 100644 index 000000000..bf2739e09 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h @@ -0,0 +1,78 @@ +/** + ****************************************************************************** + * + * @file uavobjecthelper.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup UAVObjectHelper + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UAVOBJECTHELPER_H +#define UAVOBJECTHELPER_H + +#include +#include +#include +#include + +#include "uavobject.h" + +class UAVOBJECTS_EXPORT AbstractUAVObjectHelper : public QObject { + Q_OBJECT +public: + explicit AbstractUAVObjectHelper(QObject *parent = 0); + + enum Result { SUCCESS, FAIL, TIMEOUT }; + Result doObjectAndWait(UAVObject *object, int timeout); + +protected: + virtual void doObjectAndWaitImpl() = 0; + UAVObject *m_object; + +private slots: + void transactionCompleted(UAVObject *object, bool success); + +private: + QMutex m_mutex; + QEventLoop m_eventLoop; + bool m_transactionResult; + bool m_transactionCompleted; +}; + +class UAVOBJECTS_EXPORT UAVObjectUpdaterHelper : public AbstractUAVObjectHelper { + Q_OBJECT +public: + explicit UAVObjectUpdaterHelper(QObject *parent = 0); + +protected: + virtual void doObjectAndWaitImpl(); +}; + +class UAVOBJECTS_EXPORT UAVObjectRequestHelper : public AbstractUAVObjectHelper { + Q_OBJECT +public: + explicit UAVObjectRequestHelper(QObject *parent = 0); + +protected: + virtual void doObjectAndWaitImpl(); +}; + +#endif // UAVOBJECTHELPER_H diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro b/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro index 00cd3c29d..d1b002994 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro @@ -11,14 +11,16 @@ HEADERS += uavobjects_global.h \ uavdataobject.h \ uavobjectfield.h \ uavobjectsinit.h \ - uavobjectsplugin.h + uavobjectsplugin.h \ + uavobjecthelper.h SOURCES += uavobject.cpp \ uavmetaobject.cpp \ uavobjectmanager.cpp \ uavdataobject.cpp \ uavobjectfield.cpp \ - uavobjectsplugin.cpp + uavobjectsplugin.cpp \ + uavobjecthelper.cpp OTHER_FILES += UAVObjects.pluginspec