Commit 5a2251ba authored by Gus Grubba's avatar Gus Grubba

Merge pull request #2533 from dogmaphobic/logHandling

Log handling
parents d8c45c77 776ee940
......@@ -356,6 +356,8 @@ HEADERS += \
src/VehicleSetup/JoystickConfigController.h \
src/ViewWidgets/CustomCommandWidget.h \
src/ViewWidgets/CustomCommandWidgetController.h \
src/ViewWidgets/LogDownload.h \
src/ViewWidgets/LogDownloadController.h \
src/ViewWidgets/ViewWidgetController.h \
}
......@@ -468,6 +470,8 @@ SOURCES += \
src/VehicleSetup/JoystickConfigController.cc \
src/ViewWidgets/CustomCommandWidget.cc \
src/ViewWidgets/CustomCommandWidgetController.cc \
src/ViewWidgets/LogDownload.cc \
src/ViewWidgets/LogDownloadController.cc \
src/ViewWidgets/ViewWidgetController.cc \
}
......
......@@ -11,6 +11,7 @@
<file alias="APMAirframeComponent.qml">src/AutoPilotPlugins/APM/APMAirframeComponent.qml</file>
<file alias="APMAirframeComponentSummary.qml">src/AutoPilotPlugins/APM/APMAirframeComponentSummary.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="LogDownload.qml">src/ViewWidgets/LogDownload.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="FlightModesComponent.qml">src/AutoPilotPlugins/PX4/FlightModesComponent.qml</file>
......
......@@ -95,6 +95,7 @@
#include "FlightDisplayViewController.h"
#include "VideoSurface.h"
#include "VideoReceiver.h"
#include "LogDownloadController.h"
#ifndef __ios__
#include "SerialLink.h"
......@@ -377,7 +378,7 @@ void QGCApplication::_initCommon(void)
qmlRegisterUncreatableType<JoystickManager> ("QGroundControl.JoystickManager", 1, 0, "JoystickManager", "Reference only");
qmlRegisterUncreatableType<Joystick> ("QGroundControl.JoystickManager", 1, 0, "Joystick", "Reference only");
qmlRegisterType<ParameterEditorController> ("QGroundControl.Controllers", 1, 0, "ParameterEditorController");
qmlRegisterType<ParameterEditorController> ("QGroundControl.Controllers", 1, 0, "ParameterEditorController");
qmlRegisterType<APMFlightModesComponentController> ("QGroundControl.Controllers", 1, 0, "APMFlightModesComponentController");
qmlRegisterType<FlightModesComponentController> ("QGroundControl.Controllers", 1, 0, "FlightModesComponentController");
qmlRegisterType<APMAirframeComponentController> ("QGroundControl.Controllers", 1, 0, "APMAirframeComponentController");
......@@ -396,6 +397,7 @@ void QGCApplication::_initCommon(void)
qmlRegisterType<CustomCommandWidgetController> ("QGroundControl.Controllers", 1, 0, "CustomCommandWidgetController");
qmlRegisterType<FirmwareUpgradeController> ("QGroundControl.Controllers", 1, 0, "FirmwareUpgradeController");
qmlRegisterType<JoystickConfigController> ("QGroundControl.Controllers", 1, 0, "JoystickConfigController");
qmlRegisterType<LogDownloadController> ("QGroundControl.Controllers", 1, 0, "LogDownloadController");
#endif
// Register Qml Singletons
......
......@@ -36,7 +36,6 @@ QGCDockWidget::QGCDockWidget(const QString& title, QAction* action, QWidget* par
if (action) {
setWindowTitle(title);
setWindowFlags(Qt::Tool);
loadSettings();
}
}
......@@ -55,11 +54,11 @@ void QGCDockWidget::loadSettings(void)
{
if (_action) {
QSettings settings;
settings.beginGroup(_settingsGroup);
if (settings.contains(_title)) {
restoreGeometry(settings.value(_title).toByteArray());
}
settings.endGroup();
}
}
......@@ -67,8 +66,8 @@ void QGCDockWidget::saveSettings(void)
{
if (_action) {
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(_title, saveGeometry());
settings.endGroup();
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#include "LogDownload.h"
LogDownload::LogDownload(const QString& title, QAction* action, QWidget *parent) :
QGCQmlWidgetHolder(title, action, parent)
{
Q_UNUSED(title);
Q_UNUSED(action);
setSource(QUrl::fromUserInput("qrc:/qml/LogDownload.qml"));
loadSettings();
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef LogDownload_H
#define LogDownload_H
#include "QGCQmlWidgetHolder.h"
class LogDownload : public QGCQmlWidgetHolder
{
Q_OBJECT
public:
LogDownload(const QString& title, QAction* action, QWidget *parent = 0);
};
#endif
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0
import QGroundControl.ScreenTools 1.0
QGCView {
viewPanel: panel
property real _margins: ScreenTools.defaultFontPixelHeight
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",").replace(/,,/g, ",");
}
LogDownloadController {
id: controller
factPanel: panel
onSelectionChanged: {
tableView.selection.clear()
for(var i = 0; i < controller.model.count; i++) {
var o = controller.model.get(i)
if (o && o.selected) {
tableView.selection.select(i, i)
}
}
}
}
QGCPalette { id: palette; colorGroupEnabled: enabled }
QGCViewPanel {
id: panel
anchors.fill: parent
TableView {
id: tableView
anchors.margins: _margins
anchors.left: parent.left
anchors.right: refreshButton.left
anchors.top: parent.top
anchors.bottom: parent.bottom
model: controller.model
selectionMode: SelectionMode.MultiSelection
TableViewColumn {
title: "Id"
width: ScreenTools.defaultFontPixelWidth * 4
horizontalAlignment: Text.AlignHCenter
delegate : Text {
horizontalAlignment: Text.AlignHCenter
text: {
var o = controller.model.get(styleData.row)
return o ? o.id : ""
}
}
}
TableViewColumn {
title: "Date"
width: ScreenTools.defaultFontPixelWidth * 30
horizontalAlignment: Text.AlignHCenter
delegate : Text {
text: {
var o = controller.model.get(styleData.row)
if (o) {
//-- Have we received this entry already?
if(controller.model.get(styleData.row).received) {
var d = controller.model.get(styleData.row).time
if(d.getUTCFullYear() < 1980)
return "Date Unknown"
else
return d.toLocaleString()
}
}
return ""
}
}
}
TableViewColumn {
title: "Size"
width: ScreenTools.defaultFontPixelWidth * 12
horizontalAlignment: Text.AlignHCenter
delegate : Text {
horizontalAlignment: Text.AlignRight
text: {
var o = controller.model.get(styleData.row)
return o ? numberWithCommas(o.size) : ""
}
}
}
TableViewColumn {
title: "Status"
width: ScreenTools.defaultFontPixelWidth * 18
horizontalAlignment: Text.AlignHCenter
delegate : Text {
horizontalAlignment: Text.AlignHCenter
text: {
var o = controller.model.get(styleData.row)
return o ? o.status : ""
}
}
}
}
QGCButton {
id: refreshButton
anchors.margins: _margins
anchors.top: parent.top
anchors.right: parent.right
enabled: !controller.requestingList && !controller.downloadingLogs
text: "Refresh"
onClicked: {
controller.refresh()
}
}
QGCButton {
id: downloadButton
anchors.margins: _margins
anchors.top: refreshButton.bottom
anchors.right: parent.right
enabled: !controller.requestingList && !controller.downloadingLogs && tableView.selection.count > 0
text: "Download"
onClicked: {
//-- Clear selection
for(var i = 0; i < controller.model.count; i++) {
var o = controller.model.get(i)
if (o) o.selected = false
}
//-- Flag selected log files
tableView.selection.forEach(function(rowIndex){
var o = controller.model.get(rowIndex)
if (o) o.selected = true
})
//-- Download them
controller.download()
}
}
QGCButton {
id: eraseAllButton
anchors.margins: _margins
anchors.top: downloadButton.bottom
anchors.right: parent.right
enabled: !controller.requestingList && !controller.downloadingLogs && controller.model.count > 0
text: "Erase All"
onClicked: {
eraseAllDialog.visible = true
}
MessageDialog {
id: eraseAllDialog
visible: false
icon: StandardIcon.Warning
standardButtons: StandardButton.Yes | StandardButton.No
title: "Delete All Log Files"
text: "All log files will be erased permanently. Is this really what you want?"
onYes: {
controller.eraseAll()
eraseAllDialog.visible = false
}
onNo: {
eraseAllDialog.visible = false
}
}
}
QGCButton {
id: cancelButton
anchors.margins: _margins
anchors.top: eraseAllButton.bottom
anchors.right: parent.right
text: "Cancel"
enabled: controller.requestingList || controller.downloadingLogs
onClicked: {
controller.cancel()
}
}
}
}
This diff is collapsed.
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef LogDownloadController_H
#define LogDownloadController_H
#include <QObject>
#include <QTimer>
#include <QAbstractListModel>
#include <memory>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
#include "FactPanelController.h"
class MultiVehicleManager;
class UASInterface;
class Vehicle;
class QGCLogEntry;
class LogDownloadData;
Q_DECLARE_LOGGING_CATEGORY(LogDownloadLog)
//-----------------------------------------------------------------------------
class QGCLogModel : public QAbstractListModel
{
Q_OBJECT
public:
enum QGCLogModelRoles {
ObjectRole = Qt::UserRole + 1
};
QGCLogModel(QObject *parent = 0);
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_INVOKABLE QGCLogEntry* get(int index);
int count (void) const;
void append (QGCLogEntry* entry);
void clear (void);
QGCLogEntry*operator[] (int i);
int rowCount (const QModelIndex & parent = QModelIndex()) const;
QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
signals:
void countChanged ();
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<QGCLogEntry*> _logEntries;
};
//-----------------------------------------------------------------------------
class QGCLogEntry : public QObject {
Q_OBJECT
Q_PROPERTY(uint id READ id CONSTANT)
Q_PROPERTY(QDateTime time READ time NOTIFY timeChanged)
Q_PROPERTY(uint size READ size NOTIFY sizeChanged)
Q_PROPERTY(bool received READ received NOTIFY receivedChanged)
Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged)
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
public:
QGCLogEntry(uint logId, const QDateTime& dateTime = QDateTime(), uint logSize = 0, bool received = false);
uint id () const { return _logID; }
uint size () const { return _logSize; }
QDateTime time () const { return _logTimeUTC; }
bool received () const { return _received; }
bool selected () const { return _selected; }
QString status () const { return _status; }
void setId (uint id_) { _logID = id_; }
void setSize (uint size_) { _logSize = size_; emit sizeChanged(); }
void setTime (QDateTime date_) { _logTimeUTC = date_; emit timeChanged(); }
void setReceived (bool rec_) { _received = rec_; emit receivedChanged(); }
void setSelected (bool sel_) { _selected = sel_; emit selectedChanged(); }
void setStatus (QString stat_) { _status = stat_; emit statusChanged(); }
signals:
void idChanged ();
void timeChanged ();
void sizeChanged ();
void receivedChanged ();
void selectedChanged ();
void statusChanged ();
private:
uint _logID;
uint _logSize;
QDateTime _logTimeUTC;
bool _received;
bool _selected;
QString _status;
};
//-----------------------------------------------------------------------------
class LogDownloadData {
public:
LogDownloadData(QGCLogEntry* entry);
QList<uint> offsets;
QFile file;
QString filename;
uint ID;
QTimer processDataTimer;
QGCLogEntry* entry;
uint written;
};
//-----------------------------------------------------------------------------
class LogDownloadController : public FactPanelController
{
Q_OBJECT
public:
LogDownloadController();
Q_PROPERTY(QGCLogModel* model READ model NOTIFY modelChanged)
Q_PROPERTY(bool requestingList READ requestingList NOTIFY requestingListChanged)
Q_PROPERTY(bool downloadingLogs READ downloadingLogs NOTIFY downloadingLogsChanged)
QGCLogModel* model () { return &_logEntriesModel; }
bool requestingList () { return _requestingLogEntries; }
bool downloadingLogs () { return _downloadingLogs; }
Q_INVOKABLE void refresh ();
Q_INVOKABLE void download ();
Q_INVOKABLE void eraseAll ();
Q_INVOKABLE void cancel ();
signals:
void requestingListChanged ();
void downloadingLogsChanged ();
void modelChanged ();
void selectionChanged ();
private slots:
void _setActiveVehicle (Vehicle* vehicle);
void _logEntry (UASInterface *uas, uint32_t time_utc, uint32_t size, uint16_t id, uint16_t num_logs, uint16_t last_log_num);
void _logData (UASInterface *uas, uint32_t ofs, uint16_t id, uint8_t count, const uint8_t *data);
void _processDownload ();
private:
bool _entriesComplete ();
bool _logComplete ();
void _findMissingEntries();
void _receivedAllEntries();
void _receivedAllData ();
void _resetSelection ();
void _findMissingData ();
void _requestLogList (uint32_t start = 0, uint32_t end = 0xFFFF);
void _requestLogData (uint8_t id, uint32_t offset = 0, uint32_t count = 0xFFFFFFFF);
bool _prepareLogDownload();
QGCLogEntry* _getNextSelected();
UASInterface* _uas;
LogDownloadData* _downloadData;
QTimer _timer;
QGCLogModel _logEntriesModel;
Vehicle* _vehicle;
bool _requestingLogEntries;
bool _downloadingLogs;
int _retries;
QString _downloadPath;
};
#endif
......@@ -961,6 +961,23 @@ void UAS::receiveMessage(mavlink_message_t message)
emit NavigationControllerDataChanged(this, p.nav_roll, p.nav_pitch, p.nav_bearing, p.target_bearing, p.wp_dist);
}
break;
case MAVLINK_MSG_ID_LOG_ENTRY:
{
mavlink_log_entry_t log;
mavlink_msg_log_entry_decode(&message, &log);
emit logEntry(this, log.time_utc, log.size, log.id, log.num_logs, log.last_log_num);
}
break;
case MAVLINK_MSG_ID_LOG_DATA:
{
mavlink_log_data_t log;
mavlink_msg_log_data_decode(&message, &log);
emit logData(this, log.ofs, log.id, log.count, log.data);
}
break;
default:
break;
}
......
......@@ -88,25 +88,25 @@ public:
static QColor getNextColor() {
/* Create color map */
static QList<QColor> colors = QList<QColor>()
<< QColor(231,72,28)
<< QColor(104,64,240)
<< QColor(203,254,121)
<< QColor(161,252,116)
<< QColor(232,33,47)
<< QColor(116,251,110)
<< QColor(234,38,107)
<< QColor(104,250,138)
<< QColor(231,72,28)
<< QColor(104,64,240)
<< QColor(203,254,121)
<< QColor(161,252,116)
<< QColor(232,33,47)
<< QColor(116,251,110)
<< QColor(234,38,107)
<< QColor(104,250,138)
<< QColor(235,43,165)
<< QColor(98,248,176)
<< QColor(236,48,221)
<< QColor(92,247,217)
<< QColor(98,248,176)
<< QColor(236,48,221)
<< QColor(92,247,217)
<< QColor(200,54,238)
<< QColor(87,231,246)
<< QColor(151,59,239)
<< QColor(81,183,244)
<< QColor(87,231,246)
<< QColor(151,59,239)
<< QColor(81,183,244)
<< QColor(75,133,243)
<< QColor(242,255,128)
<< QColor(230,126,23);
<< QColor(242,255,128)
<< QColor(230,126,23);
static int nextColor = -1;
if(nextColor == 18){//if at the end of the list
......@@ -139,10 +139,10 @@ public:
StartBusConfigActuators,
EndBusConfigActuators,
};
/// Starts the specified calibration
virtual void startCalibration(StartCalibrationType calType) = 0;
/// Ends any current calibration
virtual void stopCalibration(void) = 0;
......@@ -232,11 +232,11 @@ signals:
*
* Typically this is used to send lowlevel information like the battery voltage to the plotting facilities of
* the groundstation. The data here should be converted to human-readable values before being passed, so ideally
* SI units.
* SI units.
*
* @param uasId ID of this system
* @param name name of the value, e.g. "battery voltage"
* @param unit The units this variable is in as an abbreviation. For system-dependent (such as raw ADC values) use "raw", for bitfields use "bits", for true/false or on/off use "bool", for unitless values use "-".
* @param unit The units this variable is in as an abbreviation. For system-dependent (such as raw ADC values) use "raw", for bitfields use "bits", for true/false or on/off use "bool", for unitless values use "-".
* @param value the value that changed
* @param msec the timestamp of the message, in milliseconds
*/
......@@ -323,6 +323,10 @@ signals:
// HOME POSITION / ORIGIN CHANGES
void homePositionChanged(int uas, double lat, double lon, double alt);
// Log Download Signals
void logEntry (UASInterface* uas, uint32_t time_utc, uint32_t size, uint16_t id, uint16_t num_logs, uint16_t last_log_num);
void logData (UASInterface* uas, uint32_t ofs, uint16_t id, uint8_t count, const uint8_t* data);
protected:
// TIMEOUT CONSTANTS
......
......@@ -65,6 +65,7 @@ This file is part of the QGROUNDCONTROL project
#include "QGCDockWidget.h"
#include "UASInfoWidget.h"
#include "HILDockWidget.h"
#include "LogDownload.h"
#endif
#ifndef __ios__
......@@ -86,7 +87,8 @@ enum DockWidgetTypes {
STATUS_DETAILS,
INFO_VIEW,
HIL_CONFIG,
ANALYZE
ANALYZE,
LOG_DOWNLOAD
};
static const char *rgDockWidgetNames[] = {
......@@ -96,7 +98,8 @@ static const char *rgDockWidgetNames[] = {
"Status Details",
"Info View",
"HIL Config",
"Analyze"
"Analyze",
"Log Download"
};
#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
......@@ -358,6 +361,9 @@ bool MainWindow::_createInnerDockWidget(const QString& widgetName)
case ONBOARD_FILES:
widget = new QGCUASFileViewMulti(widgetName, action, this);
break;
case LOG_DOWNLOAD:
widget = new LogDownload(widgetName, action, this);
break;
case STATUS_DETAILS:
widget = new UASInfoWidget(widgetName, action, this);
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment