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:
parent
787b43fa0b
commit
2387958422
@ -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 );
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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>
|
@ -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();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
#include "uavobjectutil/uavobjectutilmanager.h"
|
||||
#include "importsummary.h"
|
||||
|
||||
class UAVSettingsImportExportPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user