mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-01 09:24:10 +01:00
Merged in filnet/librepilot/LP-517_uavtalk_logging_qt5_8_0 (pull request #423)
LP-517 uavtalk logging qt5 8 0 Approved-by: Lalanne Laurent <f5soh@free.fr> Approved-by: Alessio Morale <alessiomorale@gmail.com> Approved-by: Philippe Renon <philippe_renon@yahoo.fr> Approved-by: Brian Webb <webbbn@gmail.com>
This commit is contained in:
commit
239aad83ba
@ -403,14 +403,14 @@ void loadFactoryDefaults(QSettings &settings, AppOptionValues &appOptionValues)
|
||||
qDebug() << "Configuration file" << fileName << "was loaded.";
|
||||
}
|
||||
|
||||
void overrideSettings(QSettings &settings, int argc, char * *argv)
|
||||
void overrideSettings(QSettings &settings, const QStringList &arguments)
|
||||
{
|
||||
// Options like -D My/setting=test
|
||||
QRegExp rx("([^=]+)=(.*)");
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (CONFIG_OPTION == QString(argv[i])) {
|
||||
if (rx.indexIn(argv[++i]) > -1) {
|
||||
for (int i = 0; i < arguments.size(); ++i) {
|
||||
if (CONFIG_OPTION == arguments[i]) {
|
||||
if (rx.indexIn(arguments[++i]) > -1) {
|
||||
QString key = rx.cap(1);
|
||||
QString value = rx.cap(2);
|
||||
qDebug() << "User setting" << key << "set to value" << value;
|
||||
@ -443,15 +443,12 @@ void loadTranslators(QString language, QTranslator &translator, QTranslator &qtT
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * *argv)
|
||||
int runApplication(int argc, char * *argv)
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
|
||||
timer.start();
|
||||
|
||||
// low level init
|
||||
systemInit();
|
||||
|
||||
// create application
|
||||
SharedTools::QtSingleApplication app(APP_NAME, argc, argv);
|
||||
|
||||
@ -508,7 +505,7 @@ int main(int argc, char * *argv)
|
||||
// override settings with command line provided values
|
||||
// take notice that the overridden values will be saved in the user settings and will continue to be effective
|
||||
// in subsequent GCS runs
|
||||
overrideSettings(settings, argc, argv);
|
||||
overrideSettings(settings, app.arguments());
|
||||
|
||||
// initialize GCS locale
|
||||
// use the value defined by the General/Locale setting or default to system Locale.
|
||||
@ -625,12 +622,21 @@ int main(int argc, char * *argv)
|
||||
delete splash;
|
||||
}
|
||||
|
||||
qDebug() << "main - main took" << timer.elapsed() << "ms";
|
||||
|
||||
qDebug() << "main - starting GCS took" << timer.elapsed() << "ms";
|
||||
int ret = app.exec();
|
||||
|
||||
qDebug() << "main - GCS ran for" << timer.elapsed() << "ms";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char * *argv)
|
||||
{
|
||||
// low level init
|
||||
systemInit();
|
||||
|
||||
int ret = runApplication(argc, argv);
|
||||
|
||||
// close log file if needed
|
||||
logDeinit();
|
||||
|
||||
return ret;
|
||||
|
@ -1,17 +1,50 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file logfile.cpp
|
||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
|
||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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 "logfile.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
|
||||
LogFile::LogFile(QObject *parent) :
|
||||
QIODevice(parent),
|
||||
m_lastTimeStamp(0),
|
||||
LogFile::LogFile(QObject *parent) : QIODevice(parent),
|
||||
m_timer(this),
|
||||
m_previousTimeStamp(0),
|
||||
m_nextTimeStamp(0),
|
||||
m_lastPlayed(0),
|
||||
m_timeOffset(0),
|
||||
m_playbackSpeed(1.0),
|
||||
m_nextTimeStamp(0),
|
||||
m_useProvidedTimeStamp(false)
|
||||
paused(false),
|
||||
m_useProvidedTimeStamp(false),
|
||||
m_providedTimeStamp(0)
|
||||
{
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired()));
|
||||
connect(&m_timer, &QTimer::timeout, this, &LogFile::timerFired);
|
||||
}
|
||||
|
||||
bool LogFile::isSequential() const
|
||||
{
|
||||
// returning true fixes "UAVTalk - error : bad type" errors when replaying a log file
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,9 +63,10 @@ bool LogFile::open(OpenMode mode)
|
||||
// connection manager call...
|
||||
return true;
|
||||
}
|
||||
qDebug() << "LogFile - open" << fileName();
|
||||
|
||||
if (m_file.open(mode) == false) {
|
||||
qDebug() << "Unable to open " << m_file.fileName() << " for logging";
|
||||
qWarning() << "Unable to open " << m_file.fileName() << " for logging";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -49,11 +83,8 @@ bool LogFile::open(OpenMode mode)
|
||||
|
||||
void LogFile::close()
|
||||
{
|
||||
qDebug() << "LogFile - close" << fileName();
|
||||
emit aboutToClose();
|
||||
|
||||
if (m_timer.isActive()) {
|
||||
m_timer.stop();
|
||||
}
|
||||
m_file.close();
|
||||
QIODevice::close();
|
||||
}
|
||||
@ -64,14 +95,18 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
// If m_nextTimeStamp != -1 then use this timestamp instead of the timer
|
||||
// If needed, use provided timestamp instead of the GCS timer
|
||||
// This is used when saving logs from on-board logging
|
||||
quint32 timeStamp = m_useProvidedTimeStamp ? m_nextTimeStamp : m_myTime.elapsed();
|
||||
quint32 timeStamp = m_useProvidedTimeStamp ? m_providedTimeStamp : m_myTime.elapsed();
|
||||
|
||||
m_file.write((char *)&timeStamp, sizeof(timeStamp));
|
||||
m_file.write((char *)&dataSize, sizeof(dataSize));
|
||||
|
||||
qint64 written = m_file.write(data, dataSize);
|
||||
|
||||
// flush (needed to avoid UAVTalk device full errors)
|
||||
m_file.flush();
|
||||
|
||||
if (written != -1) {
|
||||
emit bytesWritten(written);
|
||||
}
|
||||
@ -79,67 +114,83 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
qint64 LogFile::readData(char *data, qint64 maxSize)
|
||||
qint64 LogFile::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size());
|
||||
|
||||
memcpy(data, m_dataBuffer.data(), toRead);
|
||||
m_dataBuffer.remove(0, toRead);
|
||||
return toRead;
|
||||
qint64 len = qMin(maxlen, (qint64)m_dataBuffer.size());
|
||||
|
||||
if (len) {
|
||||
memcpy(data, m_dataBuffer.data(), len);
|
||||
m_dataBuffer.remove(0, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
qint64 LogFile::bytesAvailable() const
|
||||
{
|
||||
return m_dataBuffer.size();
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
qint64 len = m_dataBuffer.size();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void LogFile::timerFired()
|
||||
{
|
||||
qint64 dataSize;
|
||||
|
||||
if (m_file.bytesAvailable() > 4) {
|
||||
int time;
|
||||
time = m_myTime.elapsed();
|
||||
|
||||
// TODO: going back in time will be a problem
|
||||
while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_lastTimeStamp)) {
|
||||
while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_nextTimeStamp)) {
|
||||
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
|
||||
|
||||
// read data size
|
||||
qint64 dataSize;
|
||||
if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) {
|
||||
qDebug() << "LogFile - end of log file reached";
|
||||
stopReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
m_file.read((char *)&dataSize, sizeof(dataSize));
|
||||
|
||||
// check size consistency
|
||||
if (dataSize < 1 || dataSize > (1024 * 1024)) {
|
||||
qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n";
|
||||
qWarning() << "LogFile - corrupted log file! Unlikely packet size:" << dataSize;
|
||||
stopReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
// read data
|
||||
if (m_file.bytesAvailable() < dataSize) {
|
||||
qDebug() << "LogFile - end of log file reached";
|
||||
stopReplay();
|
||||
return;
|
||||
}
|
||||
QByteArray data = m_file.read(dataSize);
|
||||
|
||||
// make data available
|
||||
m_mutex.lock();
|
||||
m_dataBuffer.append(m_file.read(dataSize));
|
||||
m_dataBuffer.append(data);
|
||||
m_mutex.unlock();
|
||||
|
||||
emit readyRead();
|
||||
|
||||
if (m_file.bytesAvailable() < (qint64)sizeof(m_lastTimeStamp)) {
|
||||
// read next timestamp
|
||||
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
||||
qDebug() << "LogFile - end of log file reached";
|
||||
stopReplay();
|
||||
return;
|
||||
}
|
||||
m_previousTimeStamp = m_nextTimeStamp;
|
||||
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
|
||||
|
||||
int save = m_lastTimeStamp;
|
||||
m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp));
|
||||
// some validity checks
|
||||
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";
|
||||
if ((m_nextTimeStamp < m_previousTimeStamp) // logfile goes back in time
|
||||
|| ((m_nextTimeStamp - m_previousTimeStamp) > 60 * 60 * 1000)) { // gap of more than 60 minutes
|
||||
qWarning() << "LogFile - corrupted log file! Unlikely timestamp:" << m_nextTimeStamp << "after" << m_previousTimeStamp;
|
||||
stopReplay();
|
||||
return;
|
||||
}
|
||||
@ -148,37 +199,83 @@ void LogFile::timerFired()
|
||||
time = m_myTime.elapsed();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "LogFile - end of log file reached";
|
||||
stopReplay();
|
||||
}
|
||||
}
|
||||
|
||||
bool LogFile::isPlaying() const
|
||||
{
|
||||
return m_file.isOpen() && m_timer.isActive();
|
||||
}
|
||||
|
||||
bool LogFile::startReplay()
|
||||
{
|
||||
m_dataBuffer.clear();
|
||||
if (!m_file.isOpen() || m_timer.isActive()) {
|
||||
return false;
|
||||
}
|
||||
qDebug() << "LogFile - startReplay";
|
||||
|
||||
m_myTime.restart();
|
||||
m_timeOffset = 0;
|
||||
m_lastPlayed = 0;
|
||||
m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp));
|
||||
m_previousTimeStamp = 0;
|
||||
m_nextTimeStamp = 0;
|
||||
m_dataBuffer.clear();
|
||||
|
||||
// read next timestamp
|
||||
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
|
||||
qWarning() << "LogFile - invalid log file!";
|
||||
return false;
|
||||
}
|
||||
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
|
||||
|
||||
m_timer.setInterval(10);
|
||||
m_timer.start();
|
||||
paused = false;
|
||||
|
||||
emit replayStarted();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogFile::stopReplay()
|
||||
{
|
||||
close();
|
||||
if (!m_file.isOpen() || !(m_timer.isActive() || paused)) {
|
||||
return false;
|
||||
}
|
||||
qDebug() << "LogFile - stopReplay";
|
||||
m_timer.stop();
|
||||
paused = false;
|
||||
|
||||
emit replayFinished();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogFile::pauseReplay()
|
||||
bool LogFile::pauseReplay()
|
||||
{
|
||||
if (!m_timer.isActive()) {
|
||||
return false;
|
||||
}
|
||||
qDebug() << "LogFile - pauseReplay";
|
||||
m_timer.stop();
|
||||
paused = true;
|
||||
|
||||
// hack to notify UI that replay paused
|
||||
emit replayStarted();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogFile::resumeReplay()
|
||||
bool LogFile::resumeReplay()
|
||||
{
|
||||
if (m_timer.isActive()) {
|
||||
return false;
|
||||
}
|
||||
qDebug() << "LogFile - resumeReplay";
|
||||
m_timeOffset = m_myTime.elapsed();
|
||||
m_timer.start();
|
||||
paused = false;
|
||||
|
||||
// hack to notify UI that replay resumed
|
||||
emit replayStarted();
|
||||
return true;
|
||||
}
|
||||
|
@ -1,6 +1,32 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file logfile.h
|
||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
|
||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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 LOGFILE_H
|
||||
#define LOGFILE_H
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
@ -8,36 +34,45 @@
|
||||
#include <QDebug>
|
||||
#include <QBuffer>
|
||||
#include <QFile>
|
||||
#include "utils_global.h"
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LogFile(QObject *parent = 0);
|
||||
|
||||
QString fileName() const
|
||||
{
|
||||
return m_file.fileName();
|
||||
};
|
||||
void setFileName(QString name)
|
||||
{
|
||||
m_file.setFileName(name);
|
||||
};
|
||||
|
||||
bool isSequential() const;
|
||||
|
||||
bool isPlaying() const;
|
||||
|
||||
bool open(OpenMode mode);
|
||||
void close();
|
||||
|
||||
qint64 bytesAvailable() const;
|
||||
qint64 bytesToWrite() const
|
||||
{
|
||||
return m_file.bytesToWrite();
|
||||
};
|
||||
bool open(OpenMode mode);
|
||||
void setFileName(QString name)
|
||||
{
|
||||
m_file.setFileName(name);
|
||||
};
|
||||
void close();
|
||||
|
||||
qint64 writeData(const char *data, qint64 dataSize);
|
||||
qint64 readData(char *data, qint64 maxlen);
|
||||
|
||||
bool startReplay();
|
||||
bool stopReplay();
|
||||
void useProvidedTimeStamp(bool useProvidedTimeStamp)
|
||||
{
|
||||
m_useProvidedTimeStamp = useProvidedTimeStamp;
|
||||
}
|
||||
|
||||
void setNextTimeStamp(quint32 nextTimestamp)
|
||||
void setNextTimeStamp(quint32 providedTimestamp)
|
||||
{
|
||||
m_nextTimeStamp = nextTimestamp;
|
||||
m_providedTimeStamp = providedTimestamp;
|
||||
}
|
||||
|
||||
public slots:
|
||||
@ -46,8 +81,10 @@ public slots:
|
||||
m_playbackSpeed = val;
|
||||
qDebug() << "Playback speed is now" << m_playbackSpeed;
|
||||
};
|
||||
void pauseReplay();
|
||||
void resumeReplay();
|
||||
bool startReplay();
|
||||
bool stopReplay();
|
||||
bool pauseReplay();
|
||||
bool resumeReplay();
|
||||
|
||||
protected slots:
|
||||
void timerFired();
|
||||
@ -62,17 +99,20 @@ protected:
|
||||
QTimer m_timer;
|
||||
QTime m_myTime;
|
||||
QFile m_file;
|
||||
qint32 m_lastTimeStamp;
|
||||
qint32 m_previousTimeStamp;
|
||||
qint32 m_nextTimeStamp;
|
||||
double m_lastPlayed;
|
||||
QMutex m_mutex;
|
||||
|
||||
// QMutex wants to be mutable
|
||||
// http://stackoverflow.com/questions/25521570/can-mutex-locking-function-be-marked-as-const
|
||||
mutable QMutex m_mutex;
|
||||
|
||||
int m_timeOffset;
|
||||
double m_playbackSpeed;
|
||||
bool paused;
|
||||
|
||||
private:
|
||||
quint32 m_nextTimeStamp;
|
||||
bool m_useProvidedTimeStamp;
|
||||
qint32 m_providedTimeStamp;
|
||||
};
|
||||
|
||||
#endif // LOGFILE_H
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>536</width>
|
||||
<width>439</width>
|
||||
<height>122</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -29,15 +29,15 @@
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,2,0,0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCommandLinkButton" name="playButton">
|
||||
<widget class="QPushButton" name="playButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>30</horstretch>
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
@ -57,10 +57,10 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCommandLinkButton" name="pauseButton">
|
||||
<widget class="QPushButton" name="pauseButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>30</horstretch>
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
@ -71,7 +71,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
<string notr="true">Pause</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../notify/res.qrc">
|
||||
@ -79,6 +79,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
@ -88,8 +101,14 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Idle</string>
|
||||
<string notr="true"><Status></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -25,17 +25,15 @@
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "logginggadgetwidget.h"
|
||||
|
||||
#include "ui_logging.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <loggingplugin.h>
|
||||
|
||||
LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QLabel(parent)
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
|
||||
LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), loggingPlugin(NULL)
|
||||
{
|
||||
m_logging = new Ui_Logging();
|
||||
m_logging->setupUi(this);
|
||||
@ -52,20 +50,42 @@ LoggingGadgetWidget::~LoggingGadgetWidget()
|
||||
void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
|
||||
{
|
||||
loggingPlugin = p;
|
||||
connect(p, SIGNAL(stateChanged(QString)), this, SLOT(stateChanged(QString)));
|
||||
connect(m_logging->playButton, SIGNAL(clicked()), p->getLogfile(), SLOT(resumeReplay()));
|
||||
connect(m_logging->playButton, SIGNAL(clicked()), scpPlugin, SLOT(startPlotting()));
|
||||
connect(m_logging->pauseButton, SIGNAL(clicked()), p->getLogfile(), SLOT(pauseReplay()));
|
||||
connect(m_logging->pauseButton, SIGNAL(clicked()), scpPlugin, SLOT(stopPlotting()));
|
||||
connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double)));
|
||||
void pauseReplay();
|
||||
void resumeReplay();
|
||||
|
||||
connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
|
||||
connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
|
||||
|
||||
LogFile *logFile = loggingPlugin->getLogfile();
|
||||
connect(m_logging->playButton, &QPushButton::clicked, logFile, &LogFile::resumeReplay);
|
||||
connect(m_logging->pauseButton, &QPushButton::clicked, logFile, &LogFile::pauseReplay);
|
||||
connect(m_logging->playbackSpeed, static_cast<void(QDoubleSpinBox::*) (double)>(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed);
|
||||
|
||||
connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged);
|
||||
|
||||
stateChanged(loggingPlugin->getState());
|
||||
}
|
||||
|
||||
|
||||
void LoggingGadgetWidget::stateChanged(QString status)
|
||||
void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state)
|
||||
{
|
||||
QString status;
|
||||
bool enabled = false;
|
||||
|
||||
switch (state) {
|
||||
case LoggingPlugin::IDLE:
|
||||
status = tr("Idle");
|
||||
break;
|
||||
case LoggingPlugin::LOGGING:
|
||||
status = tr("Logging");
|
||||
break;
|
||||
case LoggingPlugin::REPLAY:
|
||||
status = tr("Replaying");
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
m_logging->statusLabel->setText(status);
|
||||
|
||||
bool playing = loggingPlugin->getLogfile()->isPlaying();
|
||||
m_logging->playButton->setEnabled(enabled && !playing);
|
||||
m_logging->pauseButton->setEnabled(enabled && playing);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,16 +28,17 @@
|
||||
#ifndef LoggingGADGETWIDGET_H_
|
||||
#define LoggingGADGETWIDGET_H_
|
||||
|
||||
#include <QLabel>
|
||||
#include "loggingplugin.h"
|
||||
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "scope/scopeplugin.h"
|
||||
#include "scope/scopegadgetfactory.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class Ui_Logging;
|
||||
class LoggingPlugin;
|
||||
|
||||
class LoggingGadgetWidget : public QLabel {
|
||||
class LoggingGadgetWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -46,7 +47,7 @@ public:
|
||||
void setPlugin(LoggingPlugin *p);
|
||||
|
||||
protected slots:
|
||||
void stateChanged(QString status);
|
||||
void stateChanged(LoggingPlugin::State state);
|
||||
|
||||
signals:
|
||||
void pause();
|
||||
|
@ -2,7 +2,8 @@
|
||||
******************************************************************************
|
||||
*
|
||||
* @file logging.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
|
||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
* @brief Import/Export Plugin
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
@ -28,7 +29,16 @@
|
||||
*/
|
||||
|
||||
#include "loggingplugin.h"
|
||||
|
||||
#include "gcstelemetrystats.h"
|
||||
|
||||
#include "logginggadgetfactory.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include <uavtalk/uavtalk.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QtPlugin>
|
||||
#include <QThread>
|
||||
@ -38,23 +48,16 @@
|
||||
#include <QList>
|
||||
#include <QErrorMessage>
|
||||
#include <QWriteLocker>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <QKeySequence>
|
||||
#include "uavobjectmanager.h"
|
||||
|
||||
|
||||
LoggingConnection::LoggingConnection(LoggingPlugin *loggingPlugin) :
|
||||
loggingPlugin(loggingPlugin),
|
||||
m_deviceOpened(false)
|
||||
LoggingConnection::LoggingConnection() :
|
||||
m_deviceOpened(false), logFile()
|
||||
{}
|
||||
|
||||
LoggingConnection::~LoggingConnection()
|
||||
{}
|
||||
|
||||
void LoggingConnection::onEnumerationChanged()
|
||||
{
|
||||
emit availableDevChanged(this);
|
||||
// make sure to close device to kill timers appropriately
|
||||
closeDevice("");
|
||||
}
|
||||
|
||||
QList <Core::IConnection::device> LoggingConnection::availableDevices()
|
||||
@ -70,39 +73,40 @@ QList <Core::IConnection::device> LoggingConnection::availableDevices()
|
||||
|
||||
QIODevice *LoggingConnection::openDevice(const QString &deviceName)
|
||||
{
|
||||
loggingPlugin->stopLogging();
|
||||
closeDevice(deviceName);
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open file"), QString(""), tr("OpenPilot Log (*.opl)"));
|
||||
if (!fileName.isNull()) {
|
||||
startReplay(fileName);
|
||||
logFile.setFileName(fileName);
|
||||
if (logFile.open(QIODevice::ReadOnly)) {
|
||||
// call startReplay on correct thread to avoid error from LogFile's replay QTimer
|
||||
// you can't start or stop the timer from a thread other than the QTimer owner thread.
|
||||
// note that the LogFile IO device (and thus its owned QTimer) is moved to a dedicated thread by the TelemetryManager
|
||||
Qt::ConnectionType ct = (QApplication::instance()->thread() == logFile.thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
|
||||
QMetaObject::invokeMethod(&logFile, "startReplay", ct);
|
||||
m_deviceOpened = true;
|
||||
}
|
||||
return &logFile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LoggingConnection::startReplay(QString file)
|
||||
{
|
||||
logFile.setFileName(file);
|
||||
if (logFile.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "Replaying " << file;
|
||||
// state = REPLAY;
|
||||
logFile.startReplay();
|
||||
}
|
||||
}
|
||||
|
||||
void LoggingConnection::closeDevice(const QString &deviceName)
|
||||
{
|
||||
Q_UNUSED(deviceName);
|
||||
// we have to delete the serial connection we created
|
||||
|
||||
if (logFile.isOpen()) {
|
||||
logFile.close();
|
||||
m_deviceOpened = false;
|
||||
// call stoptReplay on correct thread to avoid error from LogFile's replay QTimer
|
||||
// you can't start or stop the timer from a thread other than the QTimer owner thread.
|
||||
// note that the LogFile IO device (and thus its owned QTimer) is moved to a dedicated thread by the TelemetryManager
|
||||
Qt::ConnectionType ct = (QApplication::instance()->thread() == logFile.thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
|
||||
QMetaObject::invokeMethod(&logFile, "stopReplay", ct);
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString LoggingConnection::connectionName()
|
||||
{
|
||||
return QString("Logfile replay");
|
||||
@ -113,10 +117,12 @@ QString LoggingConnection::shortName()
|
||||
return QString("Logfile");
|
||||
}
|
||||
|
||||
LoggingThread::LoggingThread() : QThread(), uavTalk(0)
|
||||
{}
|
||||
|
||||
LoggingThread::~LoggingThread()
|
||||
{
|
||||
stopLogging();
|
||||
delete uavTalk;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +131,7 @@ LoggingThread::~LoggingThread()
|
||||
* @param[in] file File name to write to
|
||||
* @param[in] parent plugin
|
||||
*/
|
||||
bool LoggingThread::openFile(QString file, LoggingPlugin *parent)
|
||||
bool LoggingThread::openFile(QString file)
|
||||
{
|
||||
logFile.setFileName(file);
|
||||
logFile.open(QIODevice::WriteOnly);
|
||||
@ -134,7 +140,6 @@ bool LoggingThread::openFile(QString file, LoggingPlugin *parent)
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
|
||||
uavTalk = new UAVTalk(&logFile, objManager);
|
||||
connect(parent, SIGNAL(stopLoggingSignal()), this, SLOT(stopLogging()));
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -150,16 +155,24 @@ void LoggingThread::objectUpdated(UAVObject *obj)
|
||||
QWriteLocker locker(&lock);
|
||||
|
||||
if (!uavTalk->sendObject(obj, false, false)) {
|
||||
qDebug() << "Error logging " << obj->getName();
|
||||
qDebug() << "LoggingThread - error logging" << obj->getName();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void LoggingThread::run()
|
||||
{
|
||||
startLogging();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect signals from all the objects updates to the write routine then
|
||||
* run event loop
|
||||
*/
|
||||
void LoggingThread::run()
|
||||
void LoggingThread::startLogging()
|
||||
{
|
||||
qDebug() << "LoggingThread - start logging";
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
|
||||
@ -171,33 +184,33 @@ void LoggingThread::run()
|
||||
|
||||
for (i = list.constBegin(); i != list.constEnd(); ++i) {
|
||||
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) {
|
||||
connect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *)));
|
||||
connect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated);
|
||||
objects++;
|
||||
// qDebug() << "Detected " << j[0];
|
||||
}
|
||||
}
|
||||
|
||||
GCSTelemetryStats *gcsStatsObj = GCSTelemetryStats::GetInstance(objManager);
|
||||
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
|
||||
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
|
||||
qDebug() << "Logging: connected already, ask for all settings";
|
||||
qDebug() << "LoggingThread - connected, ask for all settings";
|
||||
retrieveSettings();
|
||||
} else {
|
||||
qDebug() << "Logging: not connected, do no ask for settings";
|
||||
qDebug() << "LoggingThread - not connected, do not ask for settings";
|
||||
}
|
||||
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pass this command to the correct thread then close the file
|
||||
* Disconnect signals from all the objects, close the log file and stop
|
||||
* the event loop
|
||||
*/
|
||||
void LoggingThread::stopLogging()
|
||||
{
|
||||
QWriteLocker locker(&lock);
|
||||
|
||||
qDebug() << "LoggingThread - stop logging";
|
||||
|
||||
// Disconnect all objects we registered with:
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
@ -209,13 +222,16 @@ void LoggingThread::stopLogging()
|
||||
|
||||
for (i = list.constBegin(); i != list.constEnd(); ++i) {
|
||||
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) {
|
||||
disconnect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *)));
|
||||
disconnect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
logFile.close();
|
||||
qDebug() << "File closed";
|
||||
|
||||
quit();
|
||||
|
||||
// wait for thread to finish
|
||||
wait();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,12 +253,10 @@ void LoggingThread::retrieveSettings()
|
||||
}
|
||||
}
|
||||
// Start retrieving
|
||||
qDebug() << QString("Logging: retrieve settings objects from the autopilot (%1 objects)")
|
||||
.arg(queue.length());
|
||||
qDebug() << "LoggingThread - retrieving" << queue.length() << "objects";
|
||||
retrieveNextObject();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the next object in the queue
|
||||
*/
|
||||
@ -250,13 +264,13 @@ void LoggingThread::retrieveNextObject()
|
||||
{
|
||||
// If queue is empty return
|
||||
if (queue.isEmpty()) {
|
||||
qDebug() << "Logging: Object retrieval completed";
|
||||
qDebug() << "LoggingThread - Object retrieval completed";
|
||||
return;
|
||||
}
|
||||
// Get next object from the queue
|
||||
UAVObject *obj = queue.dequeue();
|
||||
// Connect to object
|
||||
connect(obj, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool)));
|
||||
connect(obj, &UAVObject::transactionCompleted, this, &LoggingThread::transactionCompleted);
|
||||
// Request update
|
||||
obj->requestUpdate();
|
||||
}
|
||||
@ -278,31 +292,22 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success)
|
||||
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
|
||||
retrieveNextObject();
|
||||
} else {
|
||||
qDebug() << "Logging: Object retrieval has been cancelled";
|
||||
qDebug() << "LoggingThread - object retrieval has been cancelled";
|
||||
queue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
Logging plugin
|
||||
********************************/
|
||||
|
||||
|
||||
LoggingPlugin::LoggingPlugin() :
|
||||
loggingCommand(NULL),
|
||||
state(IDLE),
|
||||
loggingThread(NULL),
|
||||
logConnection(new LoggingConnection(this)),
|
||||
mf(NULL),
|
||||
cmd(NULL)
|
||||
logConnection(new LoggingConnection())
|
||||
{}
|
||||
|
||||
LoggingPlugin::~LoggingPlugin()
|
||||
{
|
||||
delete loggingThread;
|
||||
|
||||
// Don't delete it, the plugin manager will do it:
|
||||
// delete logConnection;
|
||||
stopLogging();
|
||||
// logConnection will be auto released
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,33 +318,32 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg)
|
||||
Q_UNUSED(args);
|
||||
Q_UNUSED(errMsg);
|
||||
|
||||
loggingThread = NULL;
|
||||
|
||||
// Add Menu entry
|
||||
Core::ActionManager *am = Core::ICore::instance()->actionManager();
|
||||
Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS);
|
||||
|
||||
// Command to start logging
|
||||
cmd = am->registerAction(new QAction(this),
|
||||
// Command to start/stop logging
|
||||
loggingCommand = am->registerAction(new QAction(this),
|
||||
"LoggingPlugin.Logging",
|
||||
QList<int>() <<
|
||||
Core::Constants::C_GLOBAL_ID);
|
||||
cmd->setDefaultKeySequence(QKeySequence("Ctrl+L"));
|
||||
cmd->action()->setText(tr("Start logging..."));
|
||||
loggingCommand->setDefaultKeySequence(QKeySequence("Ctrl+L"));
|
||||
|
||||
ac->menu()->addSeparator();
|
||||
ac->appendGroup("Logging");
|
||||
ac->addAction(cmd, "Logging");
|
||||
ac->addAction(loggingCommand, "Logging");
|
||||
|
||||
connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging()));
|
||||
connect(loggingCommand->action(), &QAction::triggered, this, &LoggingPlugin::toggleLogging);
|
||||
|
||||
|
||||
mf = new LoggingGadgetFactory(this);
|
||||
LoggingGadgetFactory *mf = new LoggingGadgetFactory(this);
|
||||
addAutoReleasedObject(mf);
|
||||
|
||||
// Map signal from end of replay to replay stopped
|
||||
connect(getLogfile(), SIGNAL(replayFinished()), this, SLOT(replayStopped()));
|
||||
connect(getLogfile(), SIGNAL(replayStarted()), this, SLOT(replayStarted()));
|
||||
connect(getLogfile(), &LogFile::replayFinished, this, &LoggingPlugin::replayStopped);
|
||||
connect(getLogfile(), &LogFile::replayStarted, this, &LoggingPlugin::replayStarted);
|
||||
|
||||
// update state and command
|
||||
loggingStopped();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -359,10 +363,8 @@ void LoggingPlugin::toggleLogging()
|
||||
}
|
||||
|
||||
startLogging(fileName);
|
||||
cmd->action()->setText(tr("Stop logging"));
|
||||
} else if (state == LOGGING) {
|
||||
stopLogging();
|
||||
cmd->action()->setText(tr("Start logging..."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,20 +374,19 @@ void LoggingPlugin::toggleLogging()
|
||||
*/
|
||||
void LoggingPlugin::startLogging(QString file)
|
||||
{
|
||||
qDebug() << "Logging to " << file;
|
||||
// We have to delete the previous logging thread if is was still there!
|
||||
if (loggingThread) {
|
||||
delete loggingThread;
|
||||
}
|
||||
// needed ?
|
||||
stopLogging();
|
||||
// Start logging thread
|
||||
loggingThread = new LoggingThread();
|
||||
if (loggingThread->openFile(file, this)) {
|
||||
connect(loggingThread, SIGNAL(finished()), this, SLOT(loggingStopped()));
|
||||
state = LOGGING;
|
||||
if (loggingThread->openFile(file)) {
|
||||
connect(loggingThread, &LoggingThread::finished, this, &LoggingPlugin::loggingStopped);
|
||||
loggingThread->start();
|
||||
emit stateChanged("LOGGING");
|
||||
loggingStarted();
|
||||
} else {
|
||||
delete loggingThread;
|
||||
loggingThread = NULL;
|
||||
QErrorMessage err;
|
||||
err.showMessage("Unable to open file for logging");
|
||||
err.showMessage(tr("Unable to open file for logging"));
|
||||
err.exec();
|
||||
}
|
||||
}
|
||||
@ -395,11 +396,24 @@ void LoggingPlugin::startLogging(QString file)
|
||||
*/
|
||||
void LoggingPlugin::stopLogging()
|
||||
{
|
||||
emit stopLoggingSignal();
|
||||
if (!loggingThread) {
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(this, SIGNAL(stopLoggingSignal()), 0, 0);
|
||||
loggingThread->stopLogging();
|
||||
|
||||
delete loggingThread;
|
||||
loggingThread = NULL;
|
||||
}
|
||||
|
||||
void LoggingPlugin::loggingStarted()
|
||||
{
|
||||
loggingCommand->action()->setText(tr("Stop logging"));
|
||||
if (state == IDLE) {
|
||||
state = LOGGING;
|
||||
emit stateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive the logging stopped signal from the LoggingThread
|
||||
@ -407,23 +421,11 @@ void LoggingPlugin::stopLogging()
|
||||
*/
|
||||
void LoggingPlugin::loggingStopped()
|
||||
{
|
||||
loggingCommand->action()->setText(tr("Start logging..."));
|
||||
if (state == LOGGING) {
|
||||
state = IDLE;
|
||||
emit stateChanged(state);
|
||||
}
|
||||
|
||||
emit stateChanged("IDLE");
|
||||
|
||||
delete loggingThread;
|
||||
loggingThread = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Received the replay stopped signal from the LogFile
|
||||
*/
|
||||
void LoggingPlugin::replayStopped()
|
||||
{
|
||||
state = IDLE;
|
||||
emit stateChanged("IDLE");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,10 +433,25 @@ void LoggingPlugin::replayStopped()
|
||||
*/
|
||||
void LoggingPlugin::replayStarted()
|
||||
{
|
||||
if (state == LOGGING) {
|
||||
stopLogging();
|
||||
}
|
||||
loggingCommand->action()->setEnabled(false);
|
||||
state = REPLAY;
|
||||
emit stateChanged("REPLAY");
|
||||
emit stateChanged(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Received the replay stopped signal from the LogFile
|
||||
*/
|
||||
void LoggingPlugin::replayStopped()
|
||||
{
|
||||
loggingCommand->action()->setEnabled(true);
|
||||
if (state == REPLAY) {
|
||||
state = IDLE;
|
||||
emit stateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
void LoggingPlugin::extensionsInitialized()
|
||||
{
|
||||
@ -445,6 +462,7 @@ void LoggingPlugin::shutdown()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file loggingplugin.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
|
||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
@ -29,34 +30,37 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/iconnection.h>
|
||||
#include <extensionsystem/iplugin.h>
|
||||
#include "uavobjectmanager.h"
|
||||
#include "gcstelemetrystats.h"
|
||||
#include <uavtalk/uavtalk.h>
|
||||
#include <utils/logfile.h>
|
||||
|
||||
#include <QThread>
|
||||
#include <QQueue>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
class UAVObject;
|
||||
class UAVDataObject;
|
||||
class UAVTalk;
|
||||
class LoggingPlugin;
|
||||
class LoggingGadgetFactory;
|
||||
|
||||
namespace Core {
|
||||
class Command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a connection via the IConnection interface
|
||||
* Plugin will add a instance of this class to the pool,
|
||||
* so the connection manager can use it.
|
||||
*/
|
||||
class LoggingConnection
|
||||
: public Core::IConnection {
|
||||
class LoggingConnection : public Core::IConnection {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LoggingConnection(LoggingPlugin *loggingPlugin);
|
||||
LoggingConnection();
|
||||
virtual ~LoggingConnection();
|
||||
|
||||
virtual QList <Core::IConnection::device> availableDevices();
|
||||
|
||||
virtual QIODevice *openDevice(const QString &deviceName);
|
||||
virtual void closeDevice(const QString &deviceName);
|
||||
|
||||
@ -72,44 +76,36 @@ public:
|
||||
return &logFile;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
LogFile logFile;
|
||||
LoggingPlugin *loggingPlugin;
|
||||
|
||||
|
||||
protected slots:
|
||||
void onEnumerationChanged();
|
||||
void startReplay(QString file);
|
||||
|
||||
protected:
|
||||
bool m_deviceOpened;
|
||||
LogFile logFile;
|
||||
};
|
||||
|
||||
|
||||
class LoggingThread : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LoggingThread();
|
||||
virtual ~LoggingThread();
|
||||
|
||||
bool openFile(QString file, LoggingPlugin *parent);
|
||||
bool openFile(QString file);
|
||||
|
||||
public slots:
|
||||
void startLogging();
|
||||
void stopLogging();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private slots:
|
||||
void objectUpdated(UAVObject *obj);
|
||||
void transactionCompleted(UAVObject *obj, bool success);
|
||||
|
||||
public slots:
|
||||
void stopLogging();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
private:
|
||||
QReadWriteLock lock;
|
||||
QQueue<UAVDataObject *> queue;
|
||||
LogFile logFile;
|
||||
UAVTalk *uavTalk;
|
||||
|
||||
private:
|
||||
QQueue<UAVDataObject *> queue;
|
||||
|
||||
void retrieveSettings();
|
||||
void retrieveNextObject();
|
||||
};
|
||||
@ -121,6 +117,8 @@ class LoggingPlugin : public ExtensionSystem::IPlugin {
|
||||
friend class LoggingConnection;
|
||||
|
||||
public:
|
||||
enum State { IDLE, LOGGING, REPLAY };
|
||||
|
||||
LoggingPlugin();
|
||||
~LoggingPlugin();
|
||||
|
||||
@ -128,41 +126,34 @@ public:
|
||||
bool initialize(const QStringList & arguments, QString *errorString);
|
||||
void shutdown();
|
||||
|
||||
LoggingConnection *getLogConnection()
|
||||
{
|
||||
return logConnection;
|
||||
};
|
||||
LogFile *getLogfile()
|
||||
{
|
||||
return logConnection->getLogfile();
|
||||
}
|
||||
void setLogMenuTitle(QString str);
|
||||
|
||||
State getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
signals:
|
||||
void stopLoggingSignal(void);
|
||||
void stopReplaySignal(void);
|
||||
void stateChanged(QString);
|
||||
|
||||
|
||||
protected:
|
||||
enum { IDLE, LOGGING, REPLAY } state;
|
||||
LoggingThread *loggingThread;
|
||||
|
||||
// These are used for replay, logging in its own thread
|
||||
LoggingConnection *logConnection;
|
||||
void stateChanged(State);
|
||||
|
||||
private slots:
|
||||
void toggleLogging();
|
||||
void startLogging(QString file);
|
||||
void stopLogging();
|
||||
void loggingStarted();
|
||||
void loggingStopped();
|
||||
void replayStarted();
|
||||
void replayStopped();
|
||||
|
||||
private:
|
||||
LoggingGadgetFactory *mf;
|
||||
Core::Command *cmd;
|
||||
Core::Command *loggingCommand;
|
||||
State state;
|
||||
// These are used for replay, logging in its own thread
|
||||
LoggingThread *loggingThread;
|
||||
LoggingConnection *logConnection;
|
||||
};
|
||||
#endif /* LoggingPLUGIN_H_ */
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user