1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-07 22:54:14 +01:00
zedamota 6bcacb1630 OP356/GCS - Makes the dropbox show devices "friendly name". Type of connection and previous serial number accessible via tooltip.
Kind of hacky, we should refractor connectionManager but that can wait for after V1.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@3103 ebee16cc-31ac-478f-84a7-5cbb03baadba
2011-03-29 18:25:24 +00:00

469 lines
12 KiB
C++

/**
******************************************************************************
*
* @file logging.cpp
* @author 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
* @{
* @addtogroup Logging
* @{
*
*****************************************************************************/
/*
* 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 "loggingplugin.h"
#include "logginggadgetfactory.h"
#include <QDebug>
#include <QtPlugin>
#include <QThread>
#include <QStringList>
#include <QDir>
#include <QFileDialog>
#include <QList>
#include <QErrorMessage>
#include <QWriteLocker>
#include <extensionsystem/pluginmanager.h>
#include <QKeySequence>
#include "uavobjectmanager.h"
LoggingConnection::LoggingConnection()
{
}
LoggingConnection::~LoggingConnection()
{
}
void LoggingConnection::onEnumerationChanged()
{
emit availableDevChanged(this);
}
QList <Core::IConnection::device> LoggingConnection::availableDevices()
{
QList <device> list;
device d;
d.displayName="Logfile replay...";
d.name="Logfile replay...";
list <<d;
return list;
}
QIODevice* LoggingConnection::openDevice(const QString &deviceName)
{
Q_UNUSED(deviceName)
if (logFile.isOpen()){
logFile.close();
}
QFileDialog * fd = new QFileDialog();
fd->setAcceptMode(QFileDialog::AcceptOpen);
fd->setNameFilter("OpenPilot Log (*.opl)");
connect(fd, SIGNAL(fileSelected(QString)), this, SLOT(startReplay(QString)));
fd->exec();
return &logFile;
}
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;
}
}
QString LoggingConnection::connectionName()
{
return QString("Logfile replay");
}
QString LoggingConnection::shortName()
{
return QString("Logfile");
}
/**
* Sets the file to use for logging and takes the parent plugin
* to connect to stop logging signal
* @param[in] file File name to write to
* @param[in] parent plugin
*/
bool LoggingThread::openFile(QString file, LoggingPlugin * parent)
{
logFile.setFileName(file);
logFile.open(QIODevice::WriteOnly);
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
uavTalk = new UAVTalk(&logFile, objManager);
connect(parent,SIGNAL(stopLoggingSignal()),this,SLOT(stopLogging()));
return true;
};
/**
* Logs an object update to the file. Data format is the
* timestamp as a 32 bit uint counting ms from start of
* file writing (flight time will be embedded in stream),
* then object packet size, then the packed UAVObject.
*/
void LoggingThread::objectUpdated(UAVObject * obj)
{
QWriteLocker locker(&lock);
if(!uavTalk->sendObject(obj,false,false) )
qDebug() << "Error logging " << obj->getName();
};
/**
* Connect signals from all the objects updates to the write routine then
* run event loop
*/
void LoggingThread::run()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
QList< QList<UAVObject*> > list;
list = objManager->getObjects();
QList< QList<UAVObject*> >::const_iterator i;
QList<UAVObject*>::const_iterator j;
int objects = 0;
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*)));
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";
retrieveSettings();
} else {
qDebug() << "Logging: not connected, do no ask for settings";
}
exec();
}
/**
* Pass this command to the correct thread then close the file
*/
void LoggingThread::stopLogging()
{
QWriteLocker locker(&lock);
// Disconnect all objects we registered with:
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
QList< QList<UAVObject*> > list;
list = objManager->getObjects();
QList< QList<UAVObject*> >::const_iterator i;
QList<UAVObject*>::const_iterator j;
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*)));
}
}
logFile.close();
qDebug() << "File closed";
quit();
}
/**
* Initialize queue with settings objects to be retrieved.
*/
void LoggingThread::retrieveSettings()
{
// Clear object queue
queue.clear();
// Get all objects, add metaobjects, settings and data objects with OnChange update mode to the queue
// Get UAVObjectManager instance
ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objMngr = pm->getObject<UAVObjectManager>();
QList< QList<UAVDataObject*> > objs = objMngr->getDataObjects();
for (int n = 0; n < objs.length(); ++n)
{
UAVDataObject* obj = objs[n][0];
if ( obj->isSettings() )
{
queue.enqueue(obj);
}
}
// Start retrieving
qDebug() << tr("Logging: retrieve settings objects from the autopilot (%1 objects)")
.arg( queue.length());
retrieveNextObject();
}
/**
* Retrieve the next object in the queue
*/
void LoggingThread::retrieveNextObject()
{
// If queue is empty return
if ( queue.isEmpty() )
{
qDebug() << "Logging: 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)));
// Request update
obj->requestUpdate();
}
/**
* Called by the retrieved object when a transaction is completed.
*/
void LoggingThread::transactionCompleted(UAVObject* obj, bool success)
{
Q_UNUSED(success);
// Disconnect from sending object
obj->disconnect(this);
// Process next object if telemetry is still available
// Get stats objects
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
GCSTelemetryStats* gcsStatsObj = GCSTelemetryStats::GetInstance(objManager);
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
if ( gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED )
{
retrieveNextObject();
}
else
{
qDebug() << "Logging: Object retrieval has been cancelled";
queue.clear();
}
}
/****************************************************************
Logging plugin
********************************/
LoggingPlugin::LoggingPlugin() : state(IDLE)
{
logConnection = new LoggingConnection();
}
LoggingPlugin::~LoggingPlugin()
{
if (loggingThread)
delete loggingThread;
// Don't delete it, the plugin manager will do it:
//delete logConnection;
}
/**
* Add Logging plugin to File menu
*/
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),
"LoggingPlugin.Logging",
QList<int>() <<
Core::Constants::C_GLOBAL_ID);
cmd->setDefaultKeySequence(QKeySequence("Ctrl+L"));
cmd->action()->setText("Start logging...");
ac->menu()->addSeparator();
ac->appendGroup("Logging");
ac->addAction(cmd, "Logging");
connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging()));
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()));
return true;
}
/**
* The action that is triggered by the menu item which opens the
* file and begins logging if successful
*/
void LoggingPlugin::toggleLogging()
{
if(state == IDLE)
{
QString fileName = QFileDialog::getSaveFileName(NULL, tr("Start Log"),
tr("OP-%0.opl").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")),
tr("OpenPilot Log (*.opl)"));
if (fileName.isEmpty())
return;
startLogging(fileName);
cmd->action()->setText(tr("Stop logging"));
}
else if(state == LOGGING)
{
stopLogging();
cmd->action()->setText(tr("Start logging..."));
}
}
/**
* Starts the logging thread to a certain file
*/
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;
loggingThread = new LoggingThread();
if(loggingThread->openFile(file,this))
{
connect(loggingThread,SIGNAL(finished()),this,SLOT(loggingStopped()));
state = LOGGING;
loggingThread->start();
emit stateChanged("LOGGING");
} else {
QErrorMessage err;
err.showMessage("Unable to open file for logging");
err.exec();
}
}
/**
* Send the stop logging signal to the LoggingThread
*/
void LoggingPlugin::stopLogging()
{
emit stopLoggingSignal();
disconnect( this,SIGNAL(stopLoggingSignal()),0,0);
}
/**
* Receive the logging stopped signal from the LoggingThread
* and change status to not logging
*/
void LoggingPlugin::loggingStopped()
{
if(state == LOGGING)
state = IDLE;
emit stateChanged("IDLE");
free(loggingThread);
loggingThread = NULL;
}
/**
* Received the replay stopped signal from the LogFile
*/
void LoggingPlugin::replayStopped()
{
state = IDLE;
emit stateChanged("IDLE");
}
/**
* Received the replay started signal from the LogFile
*/
void LoggingPlugin::replayStarted()
{
state = REPLAY;
emit stateChanged("REPLAY");
}
void LoggingPlugin::extensionsInitialized()
{
addAutoReleasedObject(logConnection);
}
void LoggingPlugin::shutdown()
{
// Do nothing
}
Q_EXPORT_PLUGIN(LoggingPlugin)
/**
* @}
* @}
*/