1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-26 15:54:15 +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:
Philippe Renon 2017-05-15 20:19:16 +00:00 committed by Lalanne Laurent
commit 239aad83ba
8 changed files with 440 additions and 248 deletions

View File

@ -403,14 +403,14 @@ void loadFactoryDefaults(QSettings &settings, AppOptionValues &appOptionValues)
qDebug() << "Configuration file" << fileName << "was loaded."; 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 // Options like -D My/setting=test
QRegExp rx("([^=]+)=(.*)"); QRegExp rx("([^=]+)=(.*)");
for (int i = 0; i < argc; ++i) { for (int i = 0; i < arguments.size(); ++i) {
if (CONFIG_OPTION == QString(argv[i])) { if (CONFIG_OPTION == arguments[i]) {
if (rx.indexIn(argv[++i]) > -1) { if (rx.indexIn(arguments[++i]) > -1) {
QString key = rx.cap(1); QString key = rx.cap(1);
QString value = rx.cap(2); QString value = rx.cap(2);
qDebug() << "User setting" << key << "set to value" << value; 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; QElapsedTimer timer;
timer.start(); timer.start();
// low level init
systemInit();
// create application // create application
SharedTools::QtSingleApplication app(APP_NAME, argc, argv); SharedTools::QtSingleApplication app(APP_NAME, argc, argv);
@ -508,7 +505,7 @@ int main(int argc, char * *argv)
// override settings with command line provided values // 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 // take notice that the overridden values will be saved in the user settings and will continue to be effective
// in subsequent GCS runs // in subsequent GCS runs
overrideSettings(settings, argc, argv); overrideSettings(settings, app.arguments());
// initialize GCS locale // initialize GCS locale
// use the value defined by the General/Locale setting or default to system 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; delete splash;
} }
qDebug() << "main - main took" << timer.elapsed() << "ms"; qDebug() << "main - starting GCS took" << timer.elapsed() << "ms";
int ret = app.exec(); int ret = app.exec();
qDebug() << "main - GCS ran for" << timer.elapsed() << "ms"; 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(); logDeinit();
return ret; return ret;

View File

@ -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 "logfile.h"
#include <QDebug> #include <QDebug>
#include <QtGlobal> #include <QtGlobal>
LogFile::LogFile(QObject *parent) : LogFile::LogFile(QObject *parent) : QIODevice(parent),
QIODevice(parent), m_timer(this),
m_lastTimeStamp(0), m_previousTimeStamp(0),
m_nextTimeStamp(0),
m_lastPlayed(0), m_lastPlayed(0),
m_timeOffset(0), m_timeOffset(0),
m_playbackSpeed(1.0), m_playbackSpeed(1.0),
m_nextTimeStamp(0), paused(false),
m_useProvidedTimeStamp(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... // connection manager call...
return true; return true;
} }
qDebug() << "LogFile - open" << fileName();
if (m_file.open(mode) == false) { 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; return false;
} }
@ -49,11 +83,8 @@ bool LogFile::open(OpenMode mode)
void LogFile::close() void LogFile::close()
{ {
qDebug() << "LogFile - close" << fileName();
emit aboutToClose(); emit aboutToClose();
if (m_timer.isActive()) {
m_timer.stop();
}
m_file.close(); m_file.close();
QIODevice::close(); QIODevice::close();
} }
@ -64,14 +95,18 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
return 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 // 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 *)&timeStamp, sizeof(timeStamp));
m_file.write((char *)&dataSize, sizeof(dataSize)); m_file.write((char *)&dataSize, sizeof(dataSize));
qint64 written = m_file.write(data, dataSize); qint64 written = m_file.write(data, dataSize);
// flush (needed to avoid UAVTalk device full errors)
m_file.flush();
if (written != -1) { if (written != -1) {
emit bytesWritten(written); emit bytesWritten(written);
} }
@ -79,67 +114,83 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
return dataSize; return dataSize;
} }
qint64 LogFile::readData(char *data, qint64 maxSize) qint64 LogFile::readData(char *data, qint64 maxlen)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size());
memcpy(data, m_dataBuffer.data(), toRead); qint64 len = qMin(maxlen, (qint64)m_dataBuffer.size());
m_dataBuffer.remove(0, toRead);
return toRead; if (len) {
memcpy(data, m_dataBuffer.data(), len);
m_dataBuffer.remove(0, len);
}
return len;
} }
qint64 LogFile::bytesAvailable() const qint64 LogFile::bytesAvailable() const
{ {
return m_dataBuffer.size(); QMutexLocker locker(&m_mutex);
qint64 len = m_dataBuffer.size();
return len;
} }
void LogFile::timerFired() void LogFile::timerFired()
{ {
qint64 dataSize;
if (m_file.bytesAvailable() > 4) { if (m_file.bytesAvailable() > 4) {
int time; int time;
time = m_myTime.elapsed(); time = m_myTime.elapsed();
// TODO: going back in time will be a problem // 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); m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
// read data size
qint64 dataSize;
if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) { if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) {
qDebug() << "LogFile - end of log file reached";
stopReplay(); stopReplay();
return; return;
} }
m_file.read((char *)&dataSize, sizeof(dataSize)); m_file.read((char *)&dataSize, sizeof(dataSize));
// check size consistency
if (dataSize < 1 || dataSize > (1024 * 1024)) { 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(); stopReplay();
return; return;
} }
// read data
if (m_file.bytesAvailable() < dataSize) { if (m_file.bytesAvailable() < dataSize) {
qDebug() << "LogFile - end of log file reached";
stopReplay(); stopReplay();
return; return;
} }
QByteArray data = m_file.read(dataSize);
// make data available
m_mutex.lock(); m_mutex.lock();
m_dataBuffer.append(m_file.read(dataSize)); m_dataBuffer.append(data);
m_mutex.unlock(); m_mutex.unlock();
emit readyRead(); 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(); stopReplay();
return; 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 // some validity checks
if (m_lastTimeStamp < save // logfile goes back in time if ((m_nextTimeStamp < m_previousTimeStamp) // logfile goes back in time
|| (m_lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes) || ((m_nextTimeStamp - m_previousTimeStamp) > 60 * 60 * 1000)) { // gap of more than 60 minutes
qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << m_lastTimeStamp << " after " << save << "\n"; qWarning() << "LogFile - corrupted log file! Unlikely timestamp:" << m_nextTimeStamp << "after" << m_previousTimeStamp;
stopReplay(); stopReplay();
return; return;
} }
@ -148,37 +199,83 @@ void LogFile::timerFired()
time = m_myTime.elapsed(); time = m_myTime.elapsed();
} }
} else { } else {
qDebug() << "LogFile - end of log file reached";
stopReplay(); stopReplay();
} }
} }
bool LogFile::isPlaying() const
{
return m_file.isOpen() && m_timer.isActive();
}
bool LogFile::startReplay() bool LogFile::startReplay()
{ {
m_dataBuffer.clear(); if (!m_file.isOpen() || m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - startReplay";
m_myTime.restart(); m_myTime.restart();
m_timeOffset = 0; m_timeOffset = 0;
m_lastPlayed = 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.setInterval(10);
m_timer.start(); m_timer.start();
paused = false;
emit replayStarted(); emit replayStarted();
return true; return true;
} }
bool LogFile::stopReplay() bool LogFile::stopReplay()
{ {
close(); if (!m_file.isOpen() || !(m_timer.isActive() || paused)) {
return false;
}
qDebug() << "LogFile - stopReplay";
m_timer.stop();
paused = false;
emit replayFinished(); emit replayFinished();
return true; return true;
} }
void LogFile::pauseReplay() bool LogFile::pauseReplay()
{ {
if (!m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - pauseReplay";
m_timer.stop(); 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_timeOffset = m_myTime.elapsed();
m_timer.start(); m_timer.start();
paused = false;
// hack to notify UI that replay resumed
emit replayStarted();
return true;
} }

View File

@ -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 #ifndef LOGFILE_H
#define LOGFILE_H #define LOGFILE_H
#include "utils_global.h"
#include <QIODevice> #include <QIODevice>
#include <QTime> #include <QTime>
#include <QTimer> #include <QTimer>
@ -8,36 +34,45 @@
#include <QDebug> #include <QDebug>
#include <QBuffer> #include <QBuffer>
#include <QFile> #include <QFile>
#include "utils_global.h"
class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice {
Q_OBJECT Q_OBJECT
public: public:
explicit LogFile(QObject *parent = 0); 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 bytesAvailable() const;
qint64 bytesToWrite() const qint64 bytesToWrite() const
{ {
return m_file.bytesToWrite(); 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 writeData(const char *data, qint64 dataSize);
qint64 readData(char *data, qint64 maxlen); qint64 readData(char *data, qint64 maxlen);
bool startReplay();
bool stopReplay();
void useProvidedTimeStamp(bool useProvidedTimeStamp) void useProvidedTimeStamp(bool useProvidedTimeStamp)
{ {
m_useProvidedTimeStamp = useProvidedTimeStamp; m_useProvidedTimeStamp = useProvidedTimeStamp;
} }
void setNextTimeStamp(quint32 nextTimestamp) void setNextTimeStamp(quint32 providedTimestamp)
{ {
m_nextTimeStamp = nextTimestamp; m_providedTimeStamp = providedTimestamp;
} }
public slots: public slots:
@ -46,8 +81,10 @@ public slots:
m_playbackSpeed = val; m_playbackSpeed = val;
qDebug() << "Playback speed is now" << m_playbackSpeed; qDebug() << "Playback speed is now" << m_playbackSpeed;
}; };
void pauseReplay(); bool startReplay();
void resumeReplay(); bool stopReplay();
bool pauseReplay();
bool resumeReplay();
protected slots: protected slots:
void timerFired(); void timerFired();
@ -62,17 +99,20 @@ protected:
QTimer m_timer; QTimer m_timer;
QTime m_myTime; QTime m_myTime;
QFile m_file; QFile m_file;
qint32 m_lastTimeStamp; qint32 m_previousTimeStamp;
qint32 m_nextTimeStamp;
double m_lastPlayed; 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; int m_timeOffset;
double m_playbackSpeed; double m_playbackSpeed;
bool paused;
private: private:
quint32 m_nextTimeStamp;
bool m_useProvidedTimeStamp; bool m_useProvidedTimeStamp;
qint32 m_providedTimeStamp;
}; };
#endif // LOGFILE_H #endif // LOGFILE_H

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>536</width> <width>439</width>
<height>122</height> <height>122</height>
</rect> </rect>
</property> </property>
@ -29,15 +29,15 @@
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<item> <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"> <property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum> <enum>QLayout::SetNoConstraint</enum>
</property> </property>
<item> <item>
<widget class="QCommandLinkButton" name="playButton"> <widget class="QPushButton" name="playButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>30</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
@ -57,10 +57,10 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCommandLinkButton" name="pauseButton"> <widget class="QPushButton" name="pauseButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>30</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
@ -71,7 +71,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>Pause</string> <string notr="true">Pause</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../notify/res.qrc"> <iconset resource="../notify/res.qrc">
@ -79,6 +79,19 @@
</property> </property>
</widget> </widget>
</item> </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> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@ -88,8 +101,14 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="statusLabel"> <widget class="QLabel" name="statusLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text"> <property name="text">
<string>Idle</string> <string notr="true">&lt;Status&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -25,17 +25,15 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "logginggadgetwidget.h" #include "logginggadgetwidget.h"
#include "ui_logging.h" #include "ui_logging.h"
#include <QDebug>
#include <QStringList>
#include <QWidget>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QPushButton>
#include <loggingplugin.h> #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 = new Ui_Logging();
m_logging->setupUi(this); m_logging->setupUi(this);
@ -52,20 +50,42 @@ LoggingGadgetWidget::~LoggingGadgetWidget()
void LoggingGadgetWidget::setPlugin(LoggingPlugin *p) void LoggingGadgetWidget::setPlugin(LoggingPlugin *p)
{ {
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, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting);
connect(m_logging->playButton, SIGNAL(clicked()), scpPlugin, SLOT(startPlotting())); connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting);
connect(m_logging->pauseButton, SIGNAL(clicked()), p->getLogfile(), SLOT(pauseReplay()));
connect(m_logging->pauseButton, SIGNAL(clicked()), scpPlugin, SLOT(stopPlotting())); LogFile *logFile = loggingPlugin->getLogfile();
connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double))); connect(m_logging->playButton, &QPushButton::clicked, logFile, &LogFile::resumeReplay);
void pauseReplay(); connect(m_logging->pauseButton, &QPushButton::clicked, logFile, &LogFile::pauseReplay);
void resumeReplay(); 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(LoggingPlugin::State state)
void LoggingGadgetWidget::stateChanged(QString status)
{ {
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); m_logging->statusLabel->setText(status);
bool playing = loggingPlugin->getLogfile()->isPlaying();
m_logging->playButton->setEnabled(enabled && !playing);
m_logging->pauseButton->setEnabled(enabled && playing);
} }
/** /**

View File

@ -28,16 +28,17 @@
#ifndef LoggingGADGETWIDGET_H_ #ifndef LoggingGADGETWIDGET_H_
#define LoggingGADGETWIDGET_H_ #define LoggingGADGETWIDGET_H_
#include <QLabel> #include "loggingplugin.h"
#include "extensionsystem/pluginmanager.h" #include "extensionsystem/pluginmanager.h"
#include "scope/scopeplugin.h" #include "scope/scopeplugin.h"
#include "scope/scopegadgetfactory.h" #include "scope/scopegadgetfactory.h"
#include <QWidget>
class Ui_Logging; class Ui_Logging;
class LoggingPlugin;
class LoggingGadgetWidget : public QLabel { class LoggingGadgetWidget : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
@ -46,7 +47,7 @@ public:
void setPlugin(LoggingPlugin *p); void setPlugin(LoggingPlugin *p);
protected slots: protected slots:
void stateChanged(QString status); void stateChanged(LoggingPlugin::State state);
signals: signals:
void pause(); void pause();

View File

@ -2,7 +2,8 @@
****************************************************************************** ******************************************************************************
* *
* @file logging.cpp * @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 * @see The GNU Public License (GPL) Version 3
* @brief Import/Export Plugin * @brief Import/Export Plugin
* @addtogroup GCSPlugins GCS Plugins * @addtogroup GCSPlugins GCS Plugins
@ -28,7 +29,16 @@
*/ */
#include "loggingplugin.h" #include "loggingplugin.h"
#include "gcstelemetrystats.h"
#include "logginggadgetfactory.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 <QDebug>
#include <QtPlugin> #include <QtPlugin>
#include <QThread> #include <QThread>
@ -38,23 +48,16 @@
#include <QList> #include <QList>
#include <QErrorMessage> #include <QErrorMessage>
#include <QWriteLocker> #include <QWriteLocker>
#include <extensionsystem/pluginmanager.h>
#include <QKeySequence> #include <QKeySequence>
#include "uavobjectmanager.h"
LoggingConnection::LoggingConnection() :
LoggingConnection::LoggingConnection(LoggingPlugin *loggingPlugin) : m_deviceOpened(false), logFile()
loggingPlugin(loggingPlugin),
m_deviceOpened(false)
{} {}
LoggingConnection::~LoggingConnection() LoggingConnection::~LoggingConnection()
{}
void LoggingConnection::onEnumerationChanged()
{ {
emit availableDevChanged(this); // make sure to close device to kill timers appropriately
closeDevice("");
} }
QList <Core::IConnection::device> LoggingConnection::availableDevices() QList <Core::IConnection::device> LoggingConnection::availableDevices()
@ -70,39 +73,40 @@ QList <Core::IConnection::device> LoggingConnection::availableDevices()
QIODevice *LoggingConnection::openDevice(const QString &deviceName) QIODevice *LoggingConnection::openDevice(const QString &deviceName)
{ {
loggingPlugin->stopLogging();
closeDevice(deviceName); closeDevice(deviceName);
QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open file"), QString(""), tr("OpenPilot Log (*.opl)")); QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open file"), QString(""), tr("OpenPilot Log (*.opl)"));
if (!fileName.isNull()) { 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 &logFile;
} }
return NULL; 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) void LoggingConnection::closeDevice(const QString &deviceName)
{ {
Q_UNUSED(deviceName); Q_UNUSED(deviceName);
// we have to delete the serial connection we created
if (logFile.isOpen()) { if (logFile.isOpen()) {
logFile.close();
m_deviceOpened = false; 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() QString LoggingConnection::connectionName()
{ {
return QString("Logfile replay"); return QString("Logfile replay");
@ -113,10 +117,12 @@ QString LoggingConnection::shortName()
return QString("Logfile"); return QString("Logfile");
} }
LoggingThread::LoggingThread() : QThread(), uavTalk(0)
{}
LoggingThread::~LoggingThread() LoggingThread::~LoggingThread()
{ {
stopLogging(); delete uavTalk;
} }
/** /**
@ -125,7 +131,7 @@ LoggingThread::~LoggingThread()
* @param[in] file File name to write to * @param[in] file File name to write to
* @param[in] parent plugin * @param[in] parent plugin
*/ */
bool LoggingThread::openFile(QString file, LoggingPlugin *parent) bool LoggingThread::openFile(QString file)
{ {
logFile.setFileName(file); logFile.setFileName(file);
logFile.open(QIODevice::WriteOnly); logFile.open(QIODevice::WriteOnly);
@ -134,7 +140,6 @@ bool LoggingThread::openFile(QString file, LoggingPlugin *parent)
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
uavTalk = new UAVTalk(&logFile, objManager); uavTalk = new UAVTalk(&logFile, objManager);
connect(parent, SIGNAL(stopLoggingSignal()), this, SLOT(stopLogging()));
return true; return true;
}; };
@ -150,16 +155,24 @@ void LoggingThread::objectUpdated(UAVObject *obj)
QWriteLocker locker(&lock); QWriteLocker locker(&lock);
if (!uavTalk->sendObject(obj, false, false)) { 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 * Connect signals from all the objects updates to the write routine then
* run event loop * run event loop
*/ */
void LoggingThread::run() void LoggingThread::startLogging()
{ {
qDebug() << "LoggingThread - start logging";
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -171,33 +184,33 @@ void LoggingThread::run()
for (i = list.constBegin(); i != list.constEnd(); ++i) { for (i = list.constBegin(); i != list.constEnd(); ++i) {
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) { 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++; objects++;
// qDebug() << "Detected " << j[0];
} }
} }
GCSTelemetryStats *gcsStatsObj = GCSTelemetryStats::GetInstance(objManager); GCSTelemetryStats *gcsStatsObj = GCSTelemetryStats::GetInstance(objManager);
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData(); GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) { if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
qDebug() << "Logging: connected already, ask for all settings"; qDebug() << "LoggingThread - connected, ask for all settings";
retrieveSettings(); retrieveSettings();
} else { } else {
qDebug() << "Logging: not connected, do no ask for settings"; qDebug() << "LoggingThread - not connected, do not ask for settings";
} }
exec(); 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() void LoggingThread::stopLogging()
{ {
QWriteLocker locker(&lock); QWriteLocker locker(&lock);
qDebug() << "LoggingThread - stop logging";
// Disconnect all objects we registered with: // Disconnect all objects we registered with:
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -209,13 +222,16 @@ void LoggingThread::stopLogging()
for (i = list.constBegin(); i != list.constEnd(); ++i) { for (i = list.constBegin(); i != list.constEnd(); ++i) {
for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) { 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(); logFile.close();
qDebug() << "File closed";
quit(); quit();
// wait for thread to finish
wait();
} }
/** /**
@ -237,12 +253,10 @@ void LoggingThread::retrieveSettings()
} }
} }
// Start retrieving // Start retrieving
qDebug() << QString("Logging: retrieve settings objects from the autopilot (%1 objects)") qDebug() << "LoggingThread - retrieving" << queue.length() << "objects";
.arg(queue.length());
retrieveNextObject(); retrieveNextObject();
} }
/** /**
* Retrieve the next object in the queue * Retrieve the next object in the queue
*/ */
@ -250,13 +264,13 @@ void LoggingThread::retrieveNextObject()
{ {
// If queue is empty return // If queue is empty return
if (queue.isEmpty()) { if (queue.isEmpty()) {
qDebug() << "Logging: Object retrieval completed"; qDebug() << "LoggingThread - Object retrieval completed";
return; return;
} }
// Get next object from the queue // Get next object from the queue
UAVObject *obj = queue.dequeue(); UAVObject *obj = queue.dequeue();
// Connect to object // Connect to object
connect(obj, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); connect(obj, &UAVObject::transactionCompleted, this, &LoggingThread::transactionCompleted);
// Request update // Request update
obj->requestUpdate(); obj->requestUpdate();
} }
@ -278,31 +292,22 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success)
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) { if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
retrieveNextObject(); retrieveNextObject();
} else { } else {
qDebug() << "Logging: Object retrieval has been cancelled"; qDebug() << "LoggingThread - object retrieval has been cancelled";
queue.clear(); queue.clear();
} }
} }
/****************************************************************
Logging plugin
********************************/
LoggingPlugin::LoggingPlugin() : LoggingPlugin::LoggingPlugin() :
loggingCommand(NULL),
state(IDLE), state(IDLE),
loggingThread(NULL), loggingThread(NULL),
logConnection(new LoggingConnection(this)), logConnection(new LoggingConnection())
mf(NULL),
cmd(NULL)
{} {}
LoggingPlugin::~LoggingPlugin() LoggingPlugin::~LoggingPlugin()
{ {
delete loggingThread; stopLogging();
// logConnection will be auto released
// Don't delete it, the plugin manager will do it:
// delete logConnection;
} }
/** /**
@ -313,33 +318,32 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg)
Q_UNUSED(args); Q_UNUSED(args);
Q_UNUSED(errMsg); Q_UNUSED(errMsg);
loggingThread = NULL;
// Add Menu entry // Add Menu entry
Core::ActionManager *am = Core::ICore::instance()->actionManager(); Core::ActionManager *am = Core::ICore::instance()->actionManager();
Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS);
// Command to start logging // Command to start/stop logging
cmd = am->registerAction(new QAction(this), loggingCommand = am->registerAction(new QAction(this),
"LoggingPlugin.Logging", "LoggingPlugin.Logging",
QList<int>() << QList<int>() <<
Core::Constants::C_GLOBAL_ID); Core::Constants::C_GLOBAL_ID);
cmd->setDefaultKeySequence(QKeySequence("Ctrl+L")); loggingCommand->setDefaultKeySequence(QKeySequence("Ctrl+L"));
cmd->action()->setText(tr("Start logging..."));
ac->menu()->addSeparator(); ac->menu()->addSeparator();
ac->appendGroup("Logging"); 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);
LoggingGadgetFactory *mf = new LoggingGadgetFactory(this);
mf = new LoggingGadgetFactory(this);
addAutoReleasedObject(mf); addAutoReleasedObject(mf);
// Map signal from end of replay to replay stopped // Map signal from end of replay to replay stopped
connect(getLogfile(), SIGNAL(replayFinished()), this, SLOT(replayStopped())); connect(getLogfile(), &LogFile::replayFinished, this, &LoggingPlugin::replayStopped);
connect(getLogfile(), SIGNAL(replayStarted()), this, SLOT(replayStarted())); connect(getLogfile(), &LogFile::replayStarted, this, &LoggingPlugin::replayStarted);
// update state and command
loggingStopped();
return true; return true;
} }
@ -359,10 +363,8 @@ void LoggingPlugin::toggleLogging()
} }
startLogging(fileName); startLogging(fileName);
cmd->action()->setText(tr("Stop logging"));
} else if (state == LOGGING) { } else if (state == LOGGING) {
stopLogging(); stopLogging();
cmd->action()->setText(tr("Start logging..."));
} }
} }
@ -372,20 +374,19 @@ void LoggingPlugin::toggleLogging()
*/ */
void LoggingPlugin::startLogging(QString file) void LoggingPlugin::startLogging(QString file)
{ {
qDebug() << "Logging to " << file; // needed ?
// We have to delete the previous logging thread if is was still there! stopLogging();
if (loggingThread) { // Start logging thread
delete loggingThread;
}
loggingThread = new LoggingThread(); loggingThread = new LoggingThread();
if (loggingThread->openFile(file, this)) { if (loggingThread->openFile(file)) {
connect(loggingThread, SIGNAL(finished()), this, SLOT(loggingStopped())); connect(loggingThread, &LoggingThread::finished, this, &LoggingPlugin::loggingStopped);
state = LOGGING;
loggingThread->start(); loggingThread->start();
emit stateChanged("LOGGING"); loggingStarted();
} else { } else {
delete loggingThread;
loggingThread = NULL;
QErrorMessage err; QErrorMessage err;
err.showMessage("Unable to open file for logging"); err.showMessage(tr("Unable to open file for logging"));
err.exec(); err.exec();
} }
} }
@ -395,11 +396,24 @@ void LoggingPlugin::startLogging(QString file)
*/ */
void LoggingPlugin::stopLogging() 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 * Receive the logging stopped signal from the LoggingThread
@ -407,23 +421,11 @@ void LoggingPlugin::stopLogging()
*/ */
void LoggingPlugin::loggingStopped() void LoggingPlugin::loggingStopped()
{ {
loggingCommand->action()->setText(tr("Start logging..."));
if (state == LOGGING) { if (state == LOGGING) {
state = IDLE; 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() void LoggingPlugin::replayStarted()
{ {
if (state == LOGGING) {
stopLogging();
}
loggingCommand->action()->setEnabled(false);
state = REPLAY; 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() void LoggingPlugin::extensionsInitialized()
{ {
@ -445,6 +462,7 @@ void LoggingPlugin::shutdown()
{ {
// Do nothing // Do nothing
} }
/** /**
* @} * @}
* @} * @}

View File

@ -1,7 +1,8 @@
/** /**
****************************************************************************** ******************************************************************************
* @file loggingplugin.h * @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 * @see The GNU Public License (GPL) Version 3
* @addtogroup GCSPlugins GCS Plugins * @addtogroup GCSPlugins GCS Plugins
* @{ * @{
@ -29,34 +30,37 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/iconnection.h> #include <coreplugin/iconnection.h>
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include "uavobjectmanager.h"
#include "gcstelemetrystats.h"
#include <uavtalk/uavtalk.h>
#include <utils/logfile.h> #include <utils/logfile.h>
#include <QThread> #include <QThread>
#include <QQueue> #include <QQueue>
#include <QReadWriteLock> #include <QReadWriteLock>
class UAVObject;
class UAVDataObject;
class UAVTalk;
class LoggingPlugin; class LoggingPlugin;
class LoggingGadgetFactory; class LoggingGadgetFactory;
namespace Core {
class Command;
}
/** /**
* Define a connection via the IConnection interface * Define a connection via the IConnection interface
* Plugin will add a instance of this class to the pool, * Plugin will add a instance of this class to the pool,
* so the connection manager can use it. * so the connection manager can use it.
*/ */
class LoggingConnection class LoggingConnection : public Core::IConnection {
: public Core::IConnection {
Q_OBJECT Q_OBJECT
public: public:
LoggingConnection(LoggingPlugin *loggingPlugin); LoggingConnection();
virtual ~LoggingConnection(); virtual ~LoggingConnection();
virtual QList <Core::IConnection::device> availableDevices(); virtual QList <Core::IConnection::device> availableDevices();
virtual QIODevice *openDevice(const QString &deviceName); virtual QIODevice *openDevice(const QString &deviceName);
virtual void closeDevice(const QString &deviceName); virtual void closeDevice(const QString &deviceName);
@ -72,44 +76,36 @@ public:
return &logFile; return &logFile;
} }
private: private:
LogFile logFile;
LoggingPlugin *loggingPlugin;
protected slots:
void onEnumerationChanged();
void startReplay(QString file);
protected:
bool m_deviceOpened; bool m_deviceOpened;
LogFile logFile;
}; };
class LoggingThread : public QThread { class LoggingThread : public QThread {
Q_OBJECT Q_OBJECT
public: public:
LoggingThread();
virtual ~LoggingThread(); virtual ~LoggingThread();
bool openFile(QString file, LoggingPlugin *parent); bool openFile(QString file);
public slots:
void startLogging();
void stopLogging();
protected:
void run();
private slots: private slots:
void objectUpdated(UAVObject *obj); void objectUpdated(UAVObject *obj);
void transactionCompleted(UAVObject *obj, bool success); void transactionCompleted(UAVObject *obj, bool success);
public slots: private:
void stopLogging();
protected:
void run();
QReadWriteLock lock; QReadWriteLock lock;
QQueue<UAVDataObject *> queue;
LogFile logFile; LogFile logFile;
UAVTalk *uavTalk; UAVTalk *uavTalk;
private:
QQueue<UAVDataObject *> queue;
void retrieveSettings(); void retrieveSettings();
void retrieveNextObject(); void retrieveNextObject();
}; };
@ -121,6 +117,8 @@ class LoggingPlugin : public ExtensionSystem::IPlugin {
friend class LoggingConnection; friend class LoggingConnection;
public: public:
enum State { IDLE, LOGGING, REPLAY };
LoggingPlugin(); LoggingPlugin();
~LoggingPlugin(); ~LoggingPlugin();
@ -128,41 +126,34 @@ public:
bool initialize(const QStringList & arguments, QString *errorString); bool initialize(const QStringList & arguments, QString *errorString);
void shutdown(); void shutdown();
LoggingConnection *getLogConnection()
{
return logConnection;
};
LogFile *getLogfile() LogFile *getLogfile()
{ {
return logConnection->getLogfile(); return logConnection->getLogfile();
} }
void setLogMenuTitle(QString str);
State getState()
{
return state;
}
signals: signals:
void stopLoggingSignal(void); void stateChanged(State);
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;
private slots: private slots:
void toggleLogging(); void toggleLogging();
void startLogging(QString file); void startLogging(QString file);
void stopLogging(); void stopLogging();
void loggingStarted();
void loggingStopped(); void loggingStopped();
void replayStarted(); void replayStarted();
void replayStopped(); void replayStopped();
private: private:
LoggingGadgetFactory *mf; Core::Command *loggingCommand;
Core::Command *cmd; State state;
// These are used for replay, logging in its own thread
LoggingThread *loggingThread;
LoggingConnection *logConnection;
}; };
#endif /* LoggingPLUGIN_H_ */ #endif /* LoggingPLUGIN_H_ */
/** /**