1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-30 08:24:11 +01:00

Ground/Logging: Supports replay. Still needs a sexy widget to allow seeking (although seeking will be difficult since technically it depends on the entire state but we can probably ignore that). Also I think the interface for replay shoudln't be through a menu item but should be like any other connection. The way I implemented it (custom QIODevice that buffers the logfile and reads the timestamps) makes this pretty easy to do. I'm just not familiar enough with the connection manager to do this. This means currently if you're connected to device and start a replay you get updates from two places.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1705 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
peabody124 2010-09-21 19:28:01 +00:00 committed by peabody124
parent a56e757003
commit df0ed37d29
4 changed files with 149 additions and 12 deletions

View File

@ -1,9 +1,11 @@
#include "logfile.h" #include "logfile.h"
#include <QDebug> #include <QDebug>
#include <QtGlobal>
LogFile::LogFile(QObject *parent) : LogFile::LogFile(QObject *parent) :
QIODevice(parent) QIODevice(parent)
{ {
connect(&timer, SIGNAL(timeout()), this, SLOT(timerFired()));
} }
bool LogFile::open(OpenMode mode) { bool LogFile::open(OpenMode mode) {
@ -11,8 +13,6 @@ bool LogFile::open(OpenMode mode) {
// start a timer for playback // start a timer for playback
myTime.restart(); myTime.restart();
// TODO: support openning for read or write to determine playback or not
Q_ASSERT(mode == QIODevice::WriteOnly);
if(file.open(mode) == FALSE) if(file.open(mode) == FALSE)
{ {
qDebug() << "Unable to open " << file.fileName() << " for logging"; qDebug() << "Unable to open " << file.fileName() << " for logging";
@ -44,6 +44,47 @@ qint64 LogFile::writeData(const char * data, qint64 dataSize) {
if(written != -1) if(written != -1)
emit bytesWritten(written); emit bytesWritten(written);
//qDebug() << "Wrote " << dataSize << " bytes at " << timeStamp << " ms";
return dataSize; return dataSize;
} }
qint64 LogFile::readData(char * data, qint64 maxSize) {
qint64 toRead = qMin(maxSize,(qint64)dataBuffer.size());
memcpy(data,dataBuffer.data(),toRead);
dataBuffer.remove(0,toRead);
return toRead;
}
qint64 LogFile::bytesAvailable() const
{
return dataBuffer.size();
}
void LogFile::timerFired()
{
qint64 dataSize;
// TODO: support time rescaling and seeking
while (myTime.elapsed() > lastTimeStamp) {
file.read((char *) &dataSize, sizeof(dataSize));
dataBuffer.append(file.read(dataSize));
emit readyRead();
file.read((char *) &lastTimeStamp,sizeof(lastTimeStamp));
}
}
bool LogFile::startReplay() {
dataBuffer.clear();
myTime.restart();
file.read((char *) &lastTimeStamp,sizeof(lastTimeStamp));
timer.setInterval(10);
timer.start();
return true;
}
bool LogFile::stopReplay() {
timer.stop();
return true;
}

View File

@ -3,7 +3,9 @@
#include <QIODevice> #include <QIODevice>
#include <QTime> #include <QTime>
#include <QTimer>
#include <QDebug> #include <QDebug>
#include <QBuffer>
#include <uavobjects/uavobjectmanager.h> #include <uavobjects/uavobjectmanager.h>
class LogFile : public QIODevice class LogFile : public QIODevice
@ -11,20 +13,29 @@ class LogFile : public QIODevice
Q_OBJECT Q_OBJECT
public: public:
explicit LogFile(QObject *parent = 0); explicit LogFile(QObject *parent = 0);
qint64 bytesAvailable() { return 0; }; qint64 bytesAvailable() const;
qint64 bytesToWrite() { return file.bytesToWrite(); }; qint64 bytesToWrite() { return file.bytesToWrite(); };
bool open(OpenMode mode); bool open(OpenMode mode);
void setFileName(QString name) { file.setFileName(name); }; void setFileName(QString name) { file.setFileName(name); };
void close(); void close();
qint64 writeData(const char * data, qint64 dataSize); qint64 writeData(const char * data, qint64 dataSize);
qint64 readData(char * /*data*/, qint64 /*maxlen*/) {return 0; } qint64 readData(char * data, qint64 maxlen);
bool startReplay();
bool stopReplay();
public slots:
void timerFired();
signals: signals:
public slots: void readReady();
private:
protected: protected:
QByteArray dataBuffer;
QTimer timer;
QTime myTime; QTime myTime;
QFile file; QFile file;
qint32 lastTimeStamp;
}; };
#endif // LOGFILE_H #endif // LOGFILE_H

View File

@ -118,7 +118,6 @@ void LoggingThread::stopLogging()
quit(); quit();
} }
LoggingPlugin::LoggingPlugin() : state(IDLE) LoggingPlugin::LoggingPlugin() : state(IDLE)
{ {
// Do nothing // Do nothing
@ -141,6 +140,7 @@ bool LoggingPlugin::initialize(const QStringList& args, QString *errMsg)
Core::ActionManager* am = Core::ICore::instance()->actionManager(); Core::ActionManager* am = Core::ICore::instance()->actionManager();
Core::ActionContainer* ac = am->actionContainer(Core::Constants::M_FILE); Core::ActionContainer* ac = am->actionContainer(Core::Constants::M_FILE);
// Command to start logging
Core::Command* cmd = am->registerAction(new QAction(this), Core::Command* cmd = am->registerAction(new QAction(this),
"LoggingPlugin.Logging", "LoggingPlugin.Logging",
QList<int>() << QList<int>() <<
@ -154,6 +154,19 @@ bool LoggingPlugin::initialize(const QStringList& args, QString *errMsg)
connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging())); connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging()));
// Command to replay logging
Core::Command* cmd2 = am->registerAction(new QAction(this),
"LoggingPlugin.Playback",
QList<int>() <<
Core::Constants::C_GLOBAL_ID);
cmd2->setDefaultKeySequence(QKeySequence("Ctrl+R"));
cmd2->action()->setText("Replay...");
ac->appendGroup("Replay");
ac->addAction(cmd2, "Replay");
connect(cmd2->action(), SIGNAL(triggered(bool)), this, SLOT(toggleReplay()));
return true; return true;
} }
@ -171,19 +184,40 @@ void LoggingPlugin::toggleLogging()
connect(fd, SIGNAL(fileSelected(QString)), this, SLOT(startLogging(QString))); connect(fd, SIGNAL(fileSelected(QString)), this, SLOT(startLogging(QString)));
fd->exec(); fd->exec();
} }
else else if(state == LOGGING)
{ {
stopLogging(); stopLogging();
} }
} }
/**
* The action that is triggered by the menu item which opens the
* file and begins replay if successful
*/
void LoggingPlugin::toggleReplay()
{
if(state == IDLE)
{
QFileDialog * fd = new QFileDialog();
fd->setAcceptMode(QFileDialog::AcceptOpen);
fd->setNameFilter("OpenPilot Log (*.opl)");
connect(fd, SIGNAL(fileSelected(QString)), this, SLOT(startReplay(QString)));
fd->exec();
}
else if(state == REPLAY)
{
stopReplay();
}
}
/** /**
* Starts the logging thread to a certain file * Starts the logging thread to a certain file
*/ */
void LoggingPlugin::startLogging(QString file) void LoggingPlugin::startLogging(QString file)
{ {
qDebug() << "Logging to " << file; qDebug() << "Logging to " << file;
LoggingThread *loggingThread = new LoggingThread(); loggingThread = new LoggingThread();
if(loggingThread->openFile(file,this)) if(loggingThread->openFile(file,this))
{ {
connect(loggingThread,SIGNAL(finished()),this,SLOT(loggingStopped())); connect(loggingThread,SIGNAL(finished()),this,SLOT(loggingStopped()));
@ -196,6 +230,30 @@ void LoggingPlugin::startLogging(QString file)
} }
} }
/**
* Starts the logging thread replaying a certain file
*/
void LoggingPlugin::startReplay(QString file)
{
logFile = new LogFile;
logFile->setFileName(file);
if(logFile->open(QIODevice::ReadOnly)) {
qDebug() << "Replaying " << file;
state = REPLAY;
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
uavTalk = new UAVTalk(logFile, objManager);
logFile->startReplay();
} else {
QErrorMessage err;
err.showMessage("Unable to open file for replay");
err.exec();
}
}
/** /**
* Send the stop logging signal to the LoggingThread * Send the stop logging signal to the LoggingThread
*/ */
@ -204,14 +262,33 @@ void LoggingPlugin::stopLogging()
emit stopLoggingSignal(); emit stopLoggingSignal();
} }
/**
* Send the stop replay signal to the ReplayThread
*/
void LoggingPlugin::stopReplay()
{
logFile->stopReplay();
logFile->close();
free(uavTalk);
free(logFile);
uavTalk = 0;
logFile = 0;
state = IDLE;
}
/** /**
* Receive the logging stopped signal from the LoggingThread * Receive the logging stopped signal from the LoggingThread
* and change status to not logging * and change status to not logging
*/ */
void LoggingPlugin::loggingStopped() void LoggingPlugin::loggingStopped()
{ {
if(state == LOGGING)
state = IDLE; state = IDLE;
free(loggingThread);
loggingThread = NULL;
} }
void LoggingPlugin::extensionsInitialized() void LoggingPlugin::extensionsInitialized()
{ {
// Do nothing // Do nothing

View File

@ -70,15 +70,23 @@ public:
signals: signals:
void stopLoggingSignal(void); void stopLoggingSignal(void);
void stopReplaySignal(void);
protected: protected:
enum {IDLE, LOGGING} state; enum {IDLE, LOGGING, REPLAY} state;
LoggingThread * loggingThread; LoggingThread * loggingThread;
// These are used for replay, logging in its own thread
UAVTalk * uavTalk;
LogFile * logFile;
private slots: private slots:
void toggleLogging(); void toggleLogging();
void toggleReplay();
void startLogging(QString file); void startLogging(QString file);
void startReplay(QString file);
void stopLogging(); void stopLogging();
void stopReplay();
void loggingStopped(); void loggingStopped();
}; };
#endif /* LoggingPLUGIN_H_ */ #endif /* LoggingPLUGIN_H_ */