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:
parent
a56e757003
commit
df0ed37d29
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user