From 548a0097ec5a3271ad18b40b01dc6f852c22c3a5 Mon Sep 17 00:00:00 2001 From: tstellanova Date: Fri, 2 Aug 2013 21:50:32 -0700 Subject: [PATCH] wip decoupling the UI (view) from the param data model --- qgroundcontrol.pro | 6 +- src/uas/QGCUASParamManager.cc | 1 + src/uas/QGCUASParamManager.h | 8 +- src/uas/UAS.cc | 3 + src/uas/UAS.h | 12 +++ src/uas/UASInterface.h | 6 ++ src/uas/UASParameterDataModel.cc | 26 ++++++ src/uas/UASParameterDataModel.h | 42 +++++++++ src/ui/QGCParamWidget.cc | 148 +++++++++++++++++-------------- src/ui/QGCParamWidget.h | 10 ++- 10 files changed, 189 insertions(+), 73 deletions(-) create mode 100644 src/uas/UASParameterDataModel.cc create mode 100644 src/uas/UASParameterDataModel.h diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 263586226..fd4df5e5b 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -468,7 +468,8 @@ HEADERS += src/MG.h \ src/ui/configuration/SerialSettingsDialog.h \ src/ui/configuration/terminalconsole.h \ src/ui/configuration/ApmHighlighter.h \ - src/ui/configuration/ApmFirmwareConfig.h + src/ui/configuration/ApmFirmwareConfig.h \ + src/uas/UASParameterDataModel.h # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::HEADERS += src/ui/map3D/QGCGoogleEarthView.h @@ -683,7 +684,8 @@ SOURCES += src/main.cc \ src/ui/configuration/console.cpp \ src/ui/configuration/SerialSettingsDialog.cc \ src/ui/configuration/ApmHighlighter.cc \ - src/ui/configuration/ApmFirmwareConfig.cc + src/ui/configuration/ApmFirmwareConfig.cc \ + src/uas/UASParameterDataModel.cc # Enable Google Earth only on Mac OS and Windows with Visual Studio compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += src/ui/map3D/QGCGoogleEarthView.cc diff --git a/src/uas/QGCUASParamManager.cc b/src/uas/QGCUASParamManager.cc index 6e137b632..7193bce82 100644 --- a/src/uas/QGCUASParamManager.cc +++ b/src/uas/QGCUASParamManager.cc @@ -12,6 +12,7 @@ QGCUASParamManager::QGCUASParamManager(UASInterface* uas, QWidget *parent) : retransmissionBurstRequestSize(5) { uas->setParamManager(this); + paramDataModel = uas->getParamDataModel(); } diff --git a/src/uas/QGCUASParamManager.h b/src/uas/QGCUASParamManager.h index 69dee9eb4..d7f8adf97 100644 --- a/src/uas/QGCUASParamManager.h +++ b/src/uas/QGCUASParamManager.h @@ -7,6 +7,7 @@ #include class UASInterface; +class UASParameterDataModel; class QGCUASParamManager : public QWidget { @@ -62,9 +63,14 @@ public slots: virtual void requestParameterList() = 0; protected: + + //Parameter data model UASInterface* mav; ///< The MAV this widget is controlling - QMap* > changedValues; ///< Changed values +// QMap* > changedValues; ///< Changed values QMap* > parameters; ///< All parameters + UASParameterDataModel* paramDataModel;///< Shared data model of parameters + + // Communications management QVector received; ///< Successfully received parameters QMap* > transmissionMissingPackets; ///< Missing packets QMap* > transmissionMissingWriteAckPackets; ///< Missing write ACK packets diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc index 8dd339550..8a8ef7539 100644 --- a/src/uas/UAS.cc +++ b/src/uas/UAS.cc @@ -131,6 +131,7 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), paramsOnceRequested(false), paramManager(NULL), + paramDataModel(NULL), simulation(0), @@ -151,6 +152,8 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), componentMulti[i] = false; } + paramDataModel->setUASID(this->getUASID()); + // Store a list of available actions for this UAS. // Basically everything exposted as a SLOT with no return value or arguments. diff --git a/src/uas/UAS.h b/src/uas/UAS.h index b1c027bd1..c8b9a604c 100644 --- a/src/uas/UAS.h +++ b/src/uas/UAS.h @@ -492,6 +492,7 @@ protected: //COMMENTS FOR TEST UNIT QMap* > parameters; ///< All parameters bool paramsOnceRequested; ///< If the parameter list has been read at least once QGCUASParamManager* paramManager; ///< Parameter manager class + UASParameterDataModel* paramDataModel; ///< The parameter data model for this UAS /// SIMULATION QGCHilLink* simulation; ///< Hardware in the loop simulation link @@ -519,10 +520,20 @@ public: QGCUASParamManager* getParamManager() const { return paramManager; } + + /** @brief Get reference to the parameter data model (same one shared with the parameter manager) **/ + UASParameterDataModel* getParamDataModel() { + return paramDataModel; + } + + /** @brief Get the HIL simulation */ QGCHilLink* getHILSimulation() const { return simulation; } + + + // TODO Will be removed /** @brief Set reference to the param manager **/ void setParamManager(QGCUASParamManager* manager) { @@ -949,6 +960,7 @@ protected: quint64 lastSendTimeSensors; QList actions; ///< A list of actions that this UAS can perform. + protected slots: /** @brief Write settings to disk */ void writeSettings(); diff --git a/src/uas/UASInterface.h b/src/uas/UASInterface.h index 37382e3eb..ed2aed28c 100644 --- a/src/uas/UASInterface.h +++ b/src/uas/UASInterface.h @@ -40,6 +40,7 @@ This file is part of the QGROUNDCONTROL project #include "LinkInterface.h" #include "ProtocolInterface.h" +#include "UASParameterDataModel.h" #include "UASWaypointManager.h" #include "QGCUASParamManager.h" #include "RadioCalibration/RadioCalibrationData.h" @@ -152,8 +153,13 @@ public: /** @brief Get reference to the waypoint manager **/ virtual UASWaypointManager* getWaypointManager(void) = 0; + + /** @brief Access the parameter data model for this UAS (sans widget). This is the same parameter data model used by the parameter manager. **/ + virtual UASParameterDataModel* getParamDataModel() = 0; + /** @brief Get reference to the param manager **/ virtual QGCUASParamManager* getParamManager() const = 0; + // TODO Will be removed /** @brief Set reference to the param manager **/ virtual void setParamManager(QGCUASParamManager* manager) = 0; diff --git a/src/uas/UASParameterDataModel.cc b/src/uas/UASParameterDataModel.cc new file mode 100644 index 000000000..8effd144c --- /dev/null +++ b/src/uas/UASParameterDataModel.cc @@ -0,0 +1,26 @@ +#include "UASParameterDataModel.h" + +#include + +UASParameterDataModel::UASParameterDataModel(QObject *parent) : + QObject(parent) +{ + + + + + +} + + +void UASParameterDataModel::setPendingParameter(int componentId, QString& key, QVariant &value) +{ + QMap *compPendingParams = pendingParameters.value(componentId); + //TODO insert blank map if necessary + if (NULL == compPendingParams) { + pendingParameters.insert(componentId,new QMap()); + compPendingParams = pendingParameters.value(componentId); + } + + compPendingParams->insert(key,value); +} diff --git a/src/uas/UASParameterDataModel.h b/src/uas/UASParameterDataModel.h new file mode 100644 index 000000000..5c1d67d48 --- /dev/null +++ b/src/uas/UASParameterDataModel.h @@ -0,0 +1,42 @@ +#ifndef UASPARAMETERDATAMODEL_H +#define UASPARAMETERDATAMODEL_H + +#include +#include +#include + +class UASParameterDataModel : public QObject +{ + Q_OBJECT +public: + explicit UASParameterDataModel(QObject *parent = 0); + + + /** @brief Write a new pending parameter value that may be eventually sent to the UAS */ + virtual void setPendingParameter(int componentId, QString& paramKey, QVariant& paramValue) = 0; + + QMap* > getPendingParameters() { + return pendingParameters; + } + + QMap* > getOnboardParameters() { + return onboardParameters; + } + + + void setUASID(int anId) { this->uasId = anId; } + +signals: + +public slots: + + +protected: + int uasId; ///< The UAS / MAV to which this data model pertains + QMap* > pendingParameters; ///< Changed values that have not yet been transmitted to the UAS, by component ID + QMap* > onboardParameters; ///< All parameters confirmed to be stored onboard the UAS, by component ID + + +}; + +#endif // UASPARAMETERDATAMODEL_H diff --git a/src/ui/QGCParamWidget.cc b/src/ui/QGCParamWidget.cc index 94e1697b5..abd1e913d 100644 --- a/src/ui/QGCParamWidget.cc +++ b/src/ui/QGCParamWidget.cc @@ -105,13 +105,13 @@ QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) : QPushButton* loadFileButton = new QPushButton(tr("Load File")); loadFileButton->setToolTip(tr("Load parameters from a file on this computer in the view. To write them to the aircraft, use transmit after loading them.")); loadFileButton->setWhatsThis(tr("Load parameters from a file on this computer in the view. To write them to the aircraft, use transmit after loading them.")); - connect(loadFileButton, SIGNAL(clicked()), this, SLOT(loadParameters())); + connect(loadFileButton, SIGNAL(clicked()), this, SLOT(loadParametersFromFile())); horizontalLayout->addWidget(loadFileButton, 3, 0); QPushButton* saveFileButton = new QPushButton(tr("Save File")); saveFileButton->setToolTip(tr("Save parameters in this view to a file on this computer.")); saveFileButton->setWhatsThis(tr("Save parameters in this view to a file on this computer.")); - connect(saveFileButton, SIGNAL(clicked()), this, SLOT(saveParameters())); + connect(saveFileButton, SIGNAL(clicked()), this, SLOT(saveParametersToFile())); horizontalLayout->addWidget(saveFileButton, 3, 1); QPushButton* readButton = new QPushButton(tr("Read (ROM)")); @@ -142,7 +142,7 @@ QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) : connect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(parameterItemChanged(QTreeWidgetItem*,int))); // New parameters from UAS - connect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(addParameter(int,int,int,int,QString,QVariant))); + connect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(receivedParameterUpdate(int,int,int,int,QString,QVariant))); // Connect retransmission guard connect(this, SIGNAL(requestParameter(int,QString)), uas, SLOT(requestParameter(int,QString))); @@ -335,10 +335,10 @@ void QGCParamWidget::addComponent(int uas, int component, QString componentName) if (!parameters.contains(component)) { parameters.insert(component, new QMap()); } - // Create map in changed parameters - if (!changedValues.contains(component)) { - changedValues.insert(component, new QMap()); - } +// // Create map in changed parameters +// if (!changedValues.contains(component)) { +// changedValues.insert(component, new QMap()); +// } } } @@ -347,9 +347,9 @@ void QGCParamWidget::addComponent(int uas, int component, QString componentName) * @param component id of the component * @param parameterName human friendly name of the parameter */ -void QGCParamWidget::addParameter(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value) +void QGCParamWidget::receivedParameterUpdate(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value) { - addParameter(uas, component, parameterName, value); + receivedParameterUpdate(uas, component, parameterName, value); // Missing packets list has to be instantiated for all components if (!transmissionMissingPackets.contains(component)) { @@ -494,7 +494,7 @@ void QGCParamWidget::addParameter(int uas, int component, int paramCount, int pa * @param component id of the component * @param parameterName human friendly name of the parameter */ -void QGCParamWidget::addParameter(int uas, int component, QString parameterName, QVariant value) +void QGCParamWidget::receivedParameterUpdate(int uas, int component, QString parameterName, QVariant value) { //qDebug() << "PARAM WIDGET GOT PARAM:" << value; Q_UNUSED(uas); @@ -636,8 +636,18 @@ void QGCParamWidget::addParameter(int uas, int component, QString parameterName, parameterItem->setToolTip(0, tooltipFormat); parameterItem->setToolTip(1, tooltipFormat); - //tree->update(); - if (changedValues.contains(component)) changedValues.value(component)->remove(parameterName); + //verify that the value requested by the user matches the set value + //if it doesn't match, leave the pending parameter in the pending list! + QMap *> changedValues = this->paramDataModel->getPendingParameters(); + if (changedValues.contains(component)) { + QMap *compReqVals = changedValues.value(component); + if ((NULL != compReqVals) && compReqVals->contains(parameterName)) { + QVariant reqVal = compReqVals->value(parameterName); + if (reqVal == value) { + compReqVals->remove(parameterName); + } + } + } } /** @@ -682,9 +692,14 @@ void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* current, int column) } // Parent is now top-level component int key = components->key(parent); + + //ensure we have a placeholder map for this component + QMap *> changedValues = this->paramDataModel->getPendingParameters(); if (!changedValues.contains(key)) { changedValues.insert(key, new QMap()); } + + //insert the changed value into the map QMap* map = changedValues.value(key, NULL); if (map) { QString str = current->data(0, Qt::DisplayRole).toString(); @@ -739,7 +754,7 @@ void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* current, int column) } } -void QGCParamWidget::saveParameters() +void QGCParamWidget::saveParametersToFile() { if (!mav) return; QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./parameters.txt", tr("Parameter File (*.txt)")); @@ -794,7 +809,47 @@ void QGCParamWidget::saveParameters() file.close(); } -void QGCParamWidget::loadParameters() + +void QGCParamWidget::loadedParameterForComponent(int componentId, QStringList& wpParams ) +{ + // Set parameter value + + QMap *> changedValues = this->paramDataModel->getPendingParameters(); + + // Create changed values data structure if necessary + if (!changedValues.contains(componentId)) { + changedValues.insert(componentId, new QMap()); + } + + // Add to changed values + if (changedValues.value(componentId)->contains(wpParams.at(2))) { + changedValues.value(componentId)->remove(wpParams.at(2)); + } + + switch (wpParams.at(4).toUInt()) + { + case (int)MAV_PARAM_TYPE_REAL32: + //receivedParameterUpdate(wpParams.at(0).toInt(), componentId, wpParams.at(2), wpParams.at(3).toFloat()); + changedValues.value(componentId)->insert(wpParams.at(2), wpParams.at(3).toFloat()); + setParameter(componentId, wpParams.at(2), wpParams.at(3).toFloat()); + break; + case (int)MAV_PARAM_TYPE_UINT32: + //receivedParameterUpdate(wpParams.at(0).toInt(), componentId, wpParams.at(2), wpParams.at(3).toUInt()); + changedValues.value(componentId)->insert(wpParams.at(2), wpParams.at(3).toUInt()); + setParameter(componentId, wpParams.at(2), QVariant(wpParams.at(3).toUInt())); + break; + case (int)MAV_PARAM_TYPE_INT32: + //receivedParameterUpdate(wpParams.at(0).toInt(), componentId, wpParams.at(2), wpParams.at(3).toInt()); + changedValues.value(componentId)->insert(wpParams.at(2), wpParams.at(3).toInt()); + setParameter(componentId, wpParams.at(2), QVariant(wpParams.at(3).toInt())); + break; + default: + qDebug() << "FAILED LOADING PARAM" << wpParams.at(2) << "NO KNOWN DATA TYPE"; + } + +} + +void QGCParamWidget::loadParametersFromFile() { if (!mav) return; QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Parameter file (*.txt)")); @@ -817,59 +872,18 @@ void QGCParamWidget::loadParameters() } bool changed = false; - int component = wpParams.at(1).toInt(); + int componentId = wpParams.at(1).toInt(); QString parameterName = wpParams.at(2); - if (!parameters.contains(component) || - fabs((static_cast(parameters.value(component)->value(parameterName, wpParams.at(3).toDouble()).toDouble())) - (wpParams.at(3).toDouble())) > 2.0f * FLT_EPSILON) { + if (!parameters.contains(componentId) || + fabs((static_cast(parameters.value(componentId)->value(parameterName, wpParams.at(3).toDouble()).toDouble())) - (wpParams.at(3).toDouble())) > 2.0f * FLT_EPSILON) { changed = true; qDebug() << "Changed" << parameterName << "VAL" << wpParams.at(3).toDouble(); } - // Set parameter value - - // Create changed values data structure if necessary - if (changed && !changedValues.contains(wpParams.at(1).toInt())) { - changedValues.insert(wpParams.at(1).toInt(), new QMap()); - } - - // Add to changed values - if (changed && changedValues.value(wpParams.at(1).toInt())->contains(wpParams.at(2))) { - changedValues.value(wpParams.at(1).toInt())->remove(wpParams.at(2)); - } - - switch (wpParams.at(4).toUInt()) - { - case (int)MAV_PARAM_TYPE_REAL32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toFloat()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toFloat()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toFloat()); - qDebug() << "FLOAT PARAM CHANGED"; - } - break; - case (int)MAV_PARAM_TYPE_UINT32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toUInt()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toUInt()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), QVariant(wpParams.at(3).toUInt())); - } - break; - case (int)MAV_PARAM_TYPE_INT32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toInt()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toInt()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), QVariant(wpParams.at(3).toInt())); - } - break; - default: - qDebug() << "FAILED LOADING PARAM" << wpParams.at(2) << "NO KNOWN DATA TYPE"; + if (changed) { + loadedParameterForComponent(componentId,wpParams); } - //qDebug() << "MARKING COMP" << wpParams.at(1).toInt() << "PARAM" << wpParams.at(2) << "VALUE" << (float)wpParams.at(3).toDouble() << "AS CHANGED"; - - // Mark in UI - - } } } @@ -1098,6 +1112,7 @@ void QGCParamWidget::setParameters() { // Iterate through all components, through all parameters and emit them int parametersSent = 0; + QMap*> changedValues = paramDataModel->getPendingParameters(); QMap*>::iterator i; for (i = changedValues.begin(); i != changedValues.end(); ++i) { // Iterate through the parameters of the component @@ -1144,16 +1159,17 @@ void QGCParamWidget::writeParameters() int changedParamCount = 0; QMap*>::iterator i; - for (i = changedValues.begin(); i != changedValues.end(); ++i) + QMap*> changedValues = paramDataModel->getPendingParameters(); + + for (i = changedValues.begin(); i != changedValues.end() , (0 == changedParamCount); ++i) { // Iterate through the parameters of the component QMap* comp = i.value(); + QMap::iterator j; + for (j = comp->begin(); j != comp->end(); ++j) { - QMap::iterator j; - for (j = comp->begin(); j != comp->end(); ++j) - { - changedParamCount++; - } + changedParamCount++; + break;//it only takes one changed param to warrant warning the user } } diff --git a/src/ui/QGCParamWidget.h b/src/ui/QGCParamWidget.h index f62227d01..5b48fffb2 100644 --- a/src/ui/QGCParamWidget.h +++ b/src/ui/QGCParamWidget.h @@ -71,9 +71,9 @@ public slots: /** @brief Add a component to the list */ void addComponent(int uas, int component, QString componentName); /** @brief Add a parameter to the list with retransmission / safety checks */ - void addParameter(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value); + void receivedParameterUpdate(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value); /** @brief Add a parameter to the list */ - void addParameter(int uas, int component, QString parameterName, QVariant value); + void receivedParameterUpdate(int uas, int component, QString parameterName, QVariant value); /** @brief Request list of parameters from MAV */ void requestParameterList(); /** @brief Request one single parameter */ @@ -92,9 +92,11 @@ public slots: void parameterItemChanged(QTreeWidgetItem* prev, int column); /** @brief Store parameters to a file */ - void saveParameters(); + void saveParametersToFile(); /** @brief Load parameters from a file */ - void loadParameters(); + void loadParametersFromFile(); + + void loadedParameterForComponent(int componentId, QStringList& wpParams ); /** @brief Check for missing parameters */ void retransmissionGuardTick(); -- 2.22.0