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

OP-369 Now the import operation provides a summary and lets the user selectively save the right objects. Also improved the saveToSD queue a great deal so that it can deal with failed save operations (on non-existent objects).

This commit is contained in:
elafargue 2011-06-04 13:06:12 +02:00
parent 787b43fa0b
commit 2387958422
8 changed files with 401 additions and 27 deletions

View File

@ -41,6 +41,11 @@
UAVObjectUtilManager::UAVObjectUtilManager()
{
mutex = new QMutex(QMutex::Recursive);
saveState = IDLE;
failureTimer.stop();
failureTimer.setSingleShot(true);
failureTimer.setInterval(1000);
connect(&failureTimer, SIGNAL(timeout()),this,SLOT(objectPersistenceOperationFailed()));
}
UAVObjectUtilManager::~UAVObjectUtilManager()
@ -70,15 +75,23 @@ UAVObjectManager* UAVObjectUtilManager::getObjectManager() {
// ******************************
// SD card saving
//
/*
Add a new object to save in the queue
*/
void UAVObjectUtilManager::saveObjectToSD(UAVObject *obj)
{
// Add to queue
queue.enqueue(obj);
qDebug() << "Enqueue object: " << obj->getName();
// If queue length is one, then start sending (call sendNextObject)
// Otherwise, do nothing, it's sending anyway
if (queue.length()==1)
saveNextObject();
}
void UAVObjectUtilManager::saveNextObject()
@ -92,6 +105,8 @@ void UAVObjectUtilManager::saveNextObject()
// Get next object from the queue
UAVObject* obj = queue.head();
qDebug() << "Request board to save object " << obj->getName();
ObjectPersistence* objper = dynamic_cast<ObjectPersistence*>( getObjectManager()->getObject(ObjectPersistence::NAME) );
connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool)));
connect(objper, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(objectPersistenceUpdated(UAVObject *)));
@ -106,6 +121,11 @@ void UAVObjectUtilManager::saveNextObject()
objper->setData(data);
objper->updated();
}
// Now: we are going to get two "objectUpdated" messages (one coming from GCS, one coming from Flight, which
// will confirm the object was properly received by both sides) and then one "transactionCompleted" indicating
// that the Flight side did not only receive the object but it did receive it without error. Last we will get
// a last "objectUpdated" message coming from flight side, where we'll get the results of the objectPersistence
// operation we asked for (saved, other).
}
/**
@ -121,14 +141,43 @@ void UAVObjectUtilManager::objectPersistenceTransactionCompleted(UAVObject* obj,
if(success) {
Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0);
Q_ASSERT(saveState == AWAITING_ACK);
// Two things can happen:
// Either the Object Save Request did actually go through, and then we should get in
// "AWAITING_COMPLETED" mode, or the Object Save Request did _not_ go through, for example
// because the object does not exist and then we will never get a subsequent update.
// For this reason, we will arm a 1 second timer to make provision for this and not block
// the queue:
saveState = AWAITING_COMPLETED;
disconnect(obj, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool)));
failureTimer.start(1000); // Create a timeout
} else if (!success) {
// Can be caused by timeout errors on sending. Send again.
qDebug() << "objectPersistenceTranscationCompleted (error)";
saveNextObject();
}
}
/**
* @brief Object persistence operation failed, i.e. we never got an update
* from the board saying "completed".
*/
void UAVObjectUtilManager::objectPersistenceOperationFailed()
{
qDebug() << "objectPersistenceOperationFailed";
if(saveState == AWAITING_COMPLETED) {
//TODO: some warning that this operation failed somehow
// We have to disconnect the object persistence 'updated' signal
// and ask to save the next object:
UAVObject *obj = getObjectManager()->getObject(ObjectPersistence::NAME);
obj->disconnect(this);
queue.dequeue(); // We can now remove the object, it failed anyway.
saveState = IDLE;
saveNextObject();
}
}
/**
* @brief Process the ObjectPersistence updated message to confirm the right object saved
* then requests next object be saved.
@ -136,8 +185,10 @@ void UAVObjectUtilManager::objectPersistenceTransactionCompleted(UAVObject* obj,
*/
void UAVObjectUtilManager::objectPersistenceUpdated(UAVObject * obj)
{
qDebug() << "objectPersistenceUpdated: " << obj->getField("Operation")->getValue().toString();
Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0);
if(saveState == AWAITING_COMPLETED) {
failureTimer.stop();
// Check flight is saying it completed. This is the only thing flight should do to trigger an update.
Q_ASSERT( obj->getField("Operation")->getValue().toString().compare(QString("Completed")) == 0 );

View File

@ -38,6 +38,7 @@
#include <QtGlobal>
#include <QObject>
#include <QTimer>
#include <QMutex>
#include <QQueue>
#include <QComboBox>
@ -72,11 +73,13 @@ private:
QQueue<UAVObject *> queue;
enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState;
void saveNextObject();
QTimer failureTimer;
private slots:
//void transactionCompleted(UAVObject *obj, bool success);
void objectPersistenceTransactionCompleted(UAVObject* obj, bool success);
void objectPersistenceUpdated(UAVObject * obj);
void objectPersistenceOperationFailed();
};

View File

@ -0,0 +1,120 @@
/**
******************************************************************************
*
* @file importsummary.cpp
* @author (C) 2011 The OpenPilot Team, http://www.openpilot.org
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup UAVSettingsImportExport UAVSettings Import/Export Plugin
* @{
* @brief UAVSettings Import/Export Plugin
*****************************************************************************/
/*
* 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 "importsummary.h"
ImportSummaryDialog::ImportSummaryDialog( QWidget *parent) :
QDialog(parent),
ui(new Ui::ImportSummaryDialog)
{
ui->setupUi(this);
setWindowTitle(tr("Import Summary"));
ui->importSummaryList->setColumnCount(3);
ui->importSummaryList->setRowCount(0);
QStringList header;
header.append("Save");
header.append("Name");
header.append("Status");
ui->importSummaryList->setHorizontalHeaderLabels(header);
ui->progressBar->setValue(0);
connect( ui->closeButton, SIGNAL(clicked()), this, SLOT(close()));
connect(ui->saveToFlash, SIGNAL(clicked()), this, SLOT(doTheSaving()));
}
ImportSummaryDialog::~ImportSummaryDialog()
{
delete ui;
}
/*
Adds a new line about a UAVObject along with its status
(whether it got saved OK or not)
*/
void ImportSummaryDialog::addLine(QString uavObjectName, bool status)
{
ui->importSummaryList->setRowCount(ui->importSummaryList->rowCount()+1);
int row = ui->importSummaryList->rowCount()-1;
ui->progressBar->setMaximum(row);
ui->importSummaryList->setCellWidget(row,0,new QCheckBox(ui->importSummaryList));
QTableWidgetItem *objName = new QTableWidgetItem(uavObjectName);
ui->importSummaryList->setItem(row, 1, objName);
QCheckBox *box = dynamic_cast<QCheckBox*>(ui->importSummaryList->cellWidget(row,0));
if (status) {
ui->importSummaryList->setItem(row,2,new QTableWidgetItem("OK"));
box->setChecked(true);
} else {
ui->importSummaryList->setItem(row,2,new QTableWidgetItem("Mismatch"));
box->setChecked(false);
box->setEnabled(false);
}
this->repaint();
this->showEvent(NULL);
}
/*
Saves every checked UAVObjet in the list to Flash
*/
void ImportSummaryDialog::doTheSaving()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVObjectUtilManager *utilManager = pm->getObject<UAVObjectUtilManager>();
for(int i=0; i < ui->importSummaryList->rowCount(); i++) {
QString uavObjectName = ui->importSummaryList->item(i,1)->text();
QCheckBox *box = dynamic_cast<QCheckBox*>(ui->importSummaryList->cellWidget(i,0));
if (box->isChecked()) {
UAVObject* obj = objManager->getObject(uavObjectName);
utilManager->saveObjectToSD(obj);
ui->progressBar->setValue(i);
this->repaint();
}
}
}
void ImportSummaryDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void ImportSummaryDialog::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
ui->importSummaryList->resizeColumnsToContents();
int width = ui->importSummaryList->width()-(ui->importSummaryList->columnWidth(0)+
ui->importSummaryList->columnWidth(2));
ui->importSummaryList->setColumnWidth(1,width-15);
}

View File

@ -0,0 +1,66 @@
/**
******************************************************************************
*
* @file importsummary.h
* @author (C) 2011 The OpenPilot Team, http://www.openpilot.org
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup UAVSettingsImportExport UAVSettings Import/Export Plugin
* @{
* @brief UAVSettings Import/Export Plugin
*****************************************************************************/
/*
* 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 IMPORTSUMMARY_H
#define IMPORTSUMMARY_H
#include <QDialog>
#include <QCheckBox>
#include "ui_importsummarydialog.h"
#include "uavdataobject.h"
#include "uavobjectmanager.h"
#include "extensionsystem/pluginmanager.h"
#include "uavobjectutil/uavobjectutilmanager.h"
namespace Ui {
class ImportSummaryDialog;
}
class ImportSummaryDialog : public QDialog
{
Q_OBJECT
public:
ImportSummaryDialog(QWidget *parent=0);
~ImportSummaryDialog();
void addLine(QString objectName, bool status);
protected:
void showEvent(QShowEvent *event);
void changeEvent(QEvent *e);
private:
Ui::ImportSummaryDialog *ui;
private slots:
void doTheSaving();
};
#endif // IMPORTSUMMARY_H

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImportSummaryDialog</class>
<widget class="QDialog" name="ImportSummaryDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>UAV Settings import summary</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="importSummaryList">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>10</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<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="QPushButton" name="pushButton_3">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../coreplugin/core.qrc">
<normaloff>:/core/images/helpicon.svg</normaloff>:/core/images/helpicon.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="saveToFlash">
<property name="toolTip">
<string>Save all settings checked above to persistent board storage,
then close the dialog.</string>
</property>
<property name="text">
<string>Save to Board Flash/SD</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="toolTip">
<string>Close this dialog without saving to persistent storage</string>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../coreplugin/core.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -37,6 +37,7 @@
#include <QtPlugin>
#include <QStringList>
#include <QDebug>
#include <QCheckBox>
// for menu item
#include <coreplugin/coreconstants.h>
@ -135,9 +136,14 @@ void UAVSettingsImportExportPlugin::importUAVSettings()
return;
}
// We are now ok: setup the import summary dialog & update it as we
// go along.
ImportSummaryDialog swui;
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVObjectUtilManager *utilManager = pm->getObject<UAVObjectUtilManager>();
swui.show();
QDomNode node = root.firstChild();
while (!node.isNull()) {
QDomElement e = node.toElement();
@ -145,17 +151,17 @@ void UAVSettingsImportExportPlugin::importUAVSettings()
// - Read each object
QString uavObjectName = e.attribute("name");
uint uavObjectID = e.attribute("id").toUInt(NULL,16);
// Sanity Check:
UAVObject* obj = objManager->getObject(uavObjectName);
if (uavObjectID != obj->getObjID()) {
qDebug() << "Mismatch for Object " << uavObjectName << uavObjectID << " - " << obj->getObjID();
QMessageBox msgBox;
msgBox.setText(tr("File Object Mismatch: aborting."));
msgBox.setInformativeText(tr("Found a mismatch between file object definition and current object definition."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
return;
if (obj == NULL) {
// This object is unknown!
qDebug() << "Object Unknown:" << uavObjectName << uavObjectID;
swui.addLine(uavObjectName, false);
} else if(uavObjectID != obj->getObjID()) {
qDebug() << "Mismatch for Object " << uavObjectName << uavObjectID << " - " << obj->getObjID();
swui.addLine(uavObjectName, false);
} else {
// - Update each field
// - Issue and "updated" command
@ -178,15 +184,14 @@ void UAVSettingsImportExportPlugin::importUAVSettings()
field = field.nextSibling();
}
obj->updated();
utilManager->saveObjectToSD(obj);
swui.addLine(uavObjectName, true);
}
}
node = node.nextSibling();
}
QMessageBox msgBox;
msgBox.setText(tr("Settings restored."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
swui.exec();
}

View File

@ -29,6 +29,7 @@
#include <extensionsystem/iplugin.h>
#include "uavobjectutil/uavobjectutilmanager.h"
#include "importsummary.h"
class UAVSettingsImportExportPlugin : public ExtensionSystem::IPlugin
{

View File

@ -1,13 +1,18 @@
TEMPLATE = lib
QT += xml
TARGET = UAVSettingsImportExport
include(../../openpilotgcsplugin.pri)
include(uavsettingsimportexport_dependencies.pri)
HEADERS += uavsettingsimportexport.h
SOURCES += uavsettingsimportexport.cpp
OTHER_FILES += uavsettingsimportexport.pluginspec
TEMPLATE = lib
QT += xml
TARGET = UAVSettingsImportExport
include(../../openpilotgcsplugin.pri)
include(uavsettingsimportexport_dependencies.pri)
HEADERS += uavsettingsimportexport.h \
importsummary.h
SOURCES += uavsettingsimportexport.cpp \
importsummary.cpp
OTHER_FILES += uavsettingsimportexport.pluginspec
FORMS += \
importsummarydialog.ui