Skip to content
QGCParamWidget.cc 25.1 KiB
Newer Older
/*=====================================================================

QGroundControl Open Source Ground Control Station

pixhawk's avatar
pixhawk committed
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/
/**
 * @file
 *   @brief Implementation of class QGCParamWidget
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
 */
Lorenz Meier's avatar
Lorenz Meier committed
#include <cmath>
#include <float.h>
#include <QGridLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QFile>
#include <QTime>
#include <QSettings>
#include <QMessageBox>
LM's avatar
LM committed
#include <QApplication>
tstellanova's avatar
tstellanova committed
#include <QDebug>
pixhawk's avatar
pixhawk committed

Lorenz Meier's avatar
Lorenz Meier committed
#include "MainWindow.h"
#include "QGC.h"
tstellanova's avatar
tstellanova committed
#include "QGCParamWidget.h"
#include "UASInterface.h"
#include "UASParameterCommsMgr.h"
pixhawk's avatar
pixhawk committed

/**
 * @param uas MAV to set the parameters on
 * @param parent Parent widget
 */
pixhawk's avatar
pixhawk committed
QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) :
    QGCUASParamManager(uas, parent),
    componentItems(new QMap<int, QTreeWidgetItem*>())
pixhawk's avatar
pixhawk committed
{
lm's avatar
lm committed

pixhawk's avatar
pixhawk committed
    // Create tree widget
    tree = new QTreeWidget(this);
lm's avatar
lm committed
    statusLabel = new QLabel();
lm's avatar
lm committed
    statusLabel->setAutoFillBackground(true);
    tree->setColumnWidth(70, 30);
pixhawk's avatar
pixhawk committed

    // Set tree widget as widget onto this component
pixhawk's avatar
pixhawk committed
    //form->setAutoFillBackground(false);
    horizontalLayout = new QGridLayout(this);
    horizontalLayout->setHorizontalSpacing(6);
    horizontalLayout->setVerticalSpacing(6);
pixhawk's avatar
pixhawk committed
    horizontalLayout->setMargin(0);
    horizontalLayout->setSizeConstraint(QLayout::SetMinimumSize);
    //horizontalLayout->setSizeConstraint( QLayout::SetFixedSize );
pixhawk's avatar
pixhawk committed

lm's avatar
lm committed
    // Parameter tree
    horizontalLayout->addWidget(tree, 0, 0, 1, 3);
lm's avatar
lm committed

    // Status line
lm's avatar
lm committed
    statusLabel->setText(tr("Click refresh to download parameters"));
lm's avatar
lm committed
    horizontalLayout->addWidget(statusLabel, 1, 0, 1, 3);


    // BUTTONS
Jessica's avatar
Jessica committed
    QPushButton* refreshButton = new QPushButton(tr("Get"));
lm's avatar
lm committed
    refreshButton->setToolTip(tr("Load parameters currently in non-permanent memory of aircraft."));
    refreshButton->setWhatsThis(tr("Load parameters currently in non-permanent memory of aircraft."));
    connect(refreshButton, SIGNAL(clicked()), this, SLOT(requestAllParamsUpdate()));
lm's avatar
lm committed
    horizontalLayout->addWidget(refreshButton, 2, 0);
Jessica's avatar
Jessica committed
    QPushButton* setButton = new QPushButton(tr("Set"));
lm's avatar
lm committed
    setButton->setToolTip(tr("Set current parameters in non-permanent onboard memory"));
    setButton->setWhatsThis(tr("Set current parameters in non-permanent onboard memory"));
    connect(setButton, SIGNAL(clicked()), this, SLOT(setParameters()));
lm's avatar
lm committed
    horizontalLayout->addWidget(setButton, 2, 1);
    QPushButton* writeButton = new QPushButton(tr("Write (ROM)"));
lm's avatar
lm committed
    writeButton->setToolTip(tr("Copy current parameters in non-permanent memory of the aircraft to permanent memory. Transmit your parameters first to write these."));
    writeButton->setWhatsThis(tr("Copy current parameters in non-permanent memory of the aircraft to permanent memory. Transmit your parameters first to write these."));
    connect(writeButton, SIGNAL(clicked()), this, SLOT(writeParameters()));
lm's avatar
lm committed
    horizontalLayout->addWidget(writeButton, 2, 2);
    QPushButton* loadFileButton = new QPushButton(tr("Load File"));
lm's avatar
lm committed
    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(loadParametersFromFile()));
lm's avatar
lm committed
    horizontalLayout->addWidget(loadFileButton, 3, 0);

    QPushButton* saveFileButton = new QPushButton(tr("Save File"));
lm's avatar
lm committed
    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(saveParametersToFile()));
lm's avatar
lm committed
    horizontalLayout->addWidget(saveFileButton, 3, 1);

    QPushButton* readButton = new QPushButton(tr("Read (ROM)"));
    readButton->setToolTip(tr("Copy parameters from permanent memory to non-permanent current memory of aircraft. DOES NOT update the parameters in this view, click refresh after copying them to get them."));
    readButton->setWhatsThis(tr("Copy parameters from permanent memory to non-permanent current memory of aircraft. DOES NOT update the parameters in this view, click refresh after copying them to get them."));
    connect(readButton, SIGNAL(clicked()), this, SLOT(readParameters()));
    horizontalLayout->addWidget(readButton, 3, 2);
    // Set correct vertical scaling
    horizontalLayout->setRowStretch(0, 100);
    horizontalLayout->setRowStretch(1, 10);
    horizontalLayout->setRowStretch(2, 10);
    horizontalLayout->setRowStretch(3, 10);

pixhawk's avatar
pixhawk committed
    this->setLayout(horizontalLayout);

    // Set header
    QStringList headerItems;
    headerItems.append("Parameter");
    headerItems.append("Value");
    tree->setHeaderLabels(headerItems);
    tree->setColumnCount(2);
    tree->setExpandsOnDoubleClick(true);
    connect(this, SIGNAL(parameterChanged(int,QString,QVariant)), mav, SLOT(setParameter(int,QString,QVariant)));
    connect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(parameterItemChanged(QTreeWidgetItem*,int)));
lm's avatar
lm committed

    connect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(receivedParameterUpdate(int,int,int,int,QString,QVariant)));
tstellanova's avatar
tstellanova committed
//    connect(&retransmissionTimer, SIGNAL(timeout()), this, SLOT(retransmissionGuardTick()));
tstellanova's avatar
tstellanova committed
//    connect(this, SIGNAL(requestParameter(int,QString)), uas, SLOT(requestParameter(int,QString)));
//    connect(this, SIGNAL(requestParameter(int,int)), uas, SLOT(requestParameter(int,int)));

tstellanova's avatar
tstellanova committed
    if (uas) {
        requestAllParamsUpdate();
tstellanova's avatar
tstellanova committed
    }
lm's avatar
lm committed

tstellanova's avatar
tstellanova committed
void QGCParamWidget::addComponentItem( int compId, QString compName)
pixhawk's avatar
pixhawk committed
{
tstellanova's avatar
tstellanova committed
    if (componentItems->contains(compId)) {
pixhawk's avatar
pixhawk committed
        // Update existing
tstellanova's avatar
tstellanova committed
        componentItems->value(compId)->setData(0, Qt::DisplayRole, QString("%1 (#%2)").arg(compName).arg(compId));
        //components->value(component)->setData(1, Qt::DisplayRole, QString::number(component));
tstellanova's avatar
tstellanova committed
        componentItems->value(compId)->setFirstColumnSpanned(true);
pixhawk's avatar
pixhawk committed
        // Add new
tstellanova's avatar
tstellanova committed
        QStringList list(QString("%1 (#%2)").arg(compName).arg(compId));
pixhawk's avatar
pixhawk committed
        QTreeWidgetItem* comp = new QTreeWidgetItem(list);
lm's avatar
lm committed
        comp->setFirstColumnSpanned(true);
tstellanova's avatar
tstellanova committed
        componentItems->insert(compId, comp);
pixhawk's avatar
pixhawk committed
        // Create grouping and update maps
tstellanova's avatar
tstellanova committed
        paramGroups.insert(compId, new QMap<QString, QTreeWidgetItem*>());
pixhawk's avatar
pixhawk committed
        tree->addTopLevelItem(comp);
        tree->update();
    }
tstellanova's avatar
tstellanova committed
    //TODO it seems unlikely that the UI would know about a component before the data model...
    paramDataModel->addComponent(compId);
lm's avatar
lm committed
/**
 * @param uas System which has the component
 * @param component id of the component
 * @param parameterName human friendly name of the parameter
 */
tstellanova's avatar
tstellanova committed
//void QGCParamWidget::receivedParameterUpdate(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value)
//{

//    updateParameterDisplay(component, parameterName, value);

//    // Missing packets list has to be instantiated for all components
//    if (!transmissionMissingPackets.contains(component)) {
//        transmissionMissingPackets.insert(component, new QList<int>());
//    }

//    // List mode is different from single parameter transfers
//    if (transmissionListMode) {
//        // Only accept the list size once on the first packet from
//        // each component
//        if (!transmissionListSizeKnown.contains(component))
//        {
//            // Mark list size as known
//            transmissionListSizeKnown.insert(component, true);

//            // Mark all parameters as missing
//            for (int i = 0; i < paramCount; ++i)
//            {
//                if (!transmissionMissingPackets.value(component)->contains(i))
//                {
//                    transmissionMissingPackets.value(component)->append(i);
//                }
//            }

//            // There is only one transmission timeout for all components
//            // since components do not manage their transmission,
//            // the longest timeout is safe for all components.
//            quint64 thisTransmissionTimeout = QGC::groundTimeMilliseconds() + ((paramCount)*retransmissionTimeout);
//            if (thisTransmissionTimeout > transmissionTimeout)
//            {
//                transmissionTimeout = thisTransmissionTimeout;
//            }
//        }

//        // Start retransmission guard
//        // or reset timer
//        paramCommsMgr->setRetransmissionGuardEnabled(true); //TODO
//    }

//    // Mark this parameter as received in read list
//    int index = transmissionMissingPackets.value(component)->indexOf(paramId);
//    // If the MAV sent the parameter without request, it wont be in missing list
//    if (index != -1) transmissionMissingPackets.value(component)->removeAt(index);

//    bool justWritten = false;
//    bool writeMismatch = false;
//    //bool lastWritten = false;
//    // Mark this parameter as received in write ACK list
//    QMap<QString, QVariant>* map = transmissionMissingWriteAckPackets.value(component);
//    if (map && map->contains(parameterName))
//    {
//        justWritten = true;
//        QVariant newval = map->value(parameterName);
//        if (map->value(parameterName) != value)
//        {
//            writeMismatch = true;
//        }
//        map->remove(parameterName);
//    }

//    int missCount = 0;
//    foreach (int key, transmissionMissingPackets.keys())
//    {
//        missCount +=  transmissionMissingPackets.value(key)->count();
//    }

//    int missWriteCount = 0;
//    foreach (int key, transmissionMissingWriteAckPackets.keys())
//    {
//        missWriteCount += transmissionMissingWriteAckPackets.value(key)->count();
//    }

//    if (justWritten && !writeMismatch && missWriteCount == 0)
//    {
//        // Just wrote one and count went to 0 - this was the last missing write parameter
//        statusLabel->setText(tr("SUCCESS: WROTE ALL PARAMETERS"));
//        QPalette pal = statusLabel->palette();
//        pal.setColor(backgroundRole(), QGC::colorGreen);
//        statusLabel->setPalette(pal);
//    } else if (justWritten && !writeMismatch)
//    {
//        statusLabel->setText(tr("SUCCESS: Wrote %2 (#%1/%4): %3").arg(paramId+1).arg(parameterName).arg(value.toDouble()).arg(paramCount));
//        QPalette pal = statusLabel->palette();
//        pal.setColor(backgroundRole(), QGC::colorGreen);
//        statusLabel->setPalette(pal);
//    } else if (justWritten && writeMismatch)
//    {
//        // Mismatch, tell user
//        QPalette pal = statusLabel->palette();
//        pal.setColor(backgroundRole(), QGC::colorRed);
//        statusLabel->setPalette(pal);
//        statusLabel->setText(tr("FAILURE: Wrote %1: sent %2 != onboard %3").arg(parameterName).arg(map->value(parameterName).toDouble()).arg(value.toDouble()));
//    }
//    else
//    {
//        if (missCount > 0)
//        {
//            QPalette pal = statusLabel->palette();
//            pal.setColor(backgroundRole(), QGC::colorOrange);
//            statusLabel->setPalette(pal);
//        }
//        else
//        {
//            QPalette pal = statusLabel->palette();
//            pal.setColor(backgroundRole(), QGC::colorGreen);
//            statusLabel->setPalette(pal);
//        }
//        QString val = QString("%1").arg(value.toFloat(), 5, 'f', 1, QChar(' '));
//        //statusLabel->setText(tr("OK: %1 %2 #%3/%4, %5 miss").arg(parameterName).arg(val).arg(paramId+1).arg(paramCount).arg(missCount));
//        if (missCount == 0)
//        {
//            // Transmission done
//            QTime time = QTime::currentTime();
//            QString timeString = time.toString();
//            statusLabel->setText(tr("All received. (updated at %1)").arg(timeString));
//        }
//        else
//        {
//            // Transmission in progress
//            statusLabel->setText(tr("OK: %1 %2 (%3/%4)").arg(parameterName).arg(val).arg(paramCount-missCount).arg(paramCount));
//        }
//    }

//    // Check if last parameter was received
//    if (missCount == 0 && missWriteCount == 0)
//    {
//        this->transmissionActive = false;
//        this->transmissionListMode = false;
//        transmissionListSizeKnown.clear();
//        foreach (int key, transmissionMissingPackets.keys())
//        {
//            transmissionMissingPackets.value(key)->clear();
//        }

//        // Expand visual tree
//        tree->expandItem(tree->topLevelItem(0));
//    }
//}


void QGCParamWidget::handleParameterUpdate(int componentId, int paramCount, int paramId, const QString& paramName, QVariant value)
lm's avatar
lm committed
{
tstellanova's avatar
tstellanova committed
    Q_UNUSED(paramCount);
    Q_UNUSED(paramId);
    updateParameterDisplay(componentId, paramName, value);
}
tstellanova's avatar
tstellanova committed
void QGCParamWidget::handleParameterListUpToDate(int component)
{
    // Expand visual tree
    tree->expandItem(tree->topLevelItem(0));
lm's avatar
lm committed
}

tstellanova's avatar
tstellanova committed
void QGCParamWidget::updateParameterDisplay(int componentId, QString parameterName, QVariant value)
{
//    QString ptrStr;
//    ptrStr.sprintf("%8p", this);
//    qDebug() <<  "QGCParamWidget " << ptrStr << " got param" <<  parameterName;
    // Reference to item in tree
    QTreeWidgetItem* parameterItem = NULL;
pixhawk's avatar
pixhawk committed

    // Get component
    if (!componentItems->contains(componentId)) {
        QString componentName = tr("Component #%1").arg(componentId);
tstellanova's avatar
tstellanova committed
        addComponentItem(componentId, componentName);
pixhawk's avatar
pixhawk committed
    }
tstellanova's avatar
tstellanova committed
    //TODO this should be bubbling up from the model, not vice-versa, right?
//    // Replace value in data model
//    paramDataModel->handleParameterUpdate(componentId,parameterName,value);
pixhawk's avatar
pixhawk committed
    QString splitToken = "_";
    // Check if auto-grouping can work
lm's avatar
lm committed
    if (parameterName.contains(splitToken))
    {
pixhawk's avatar
pixhawk committed
        QString parent = parameterName.section(splitToken, 0, 0, QString::SectionSkipEmpty);
        QMap<QString, QTreeWidgetItem*>* compParamGroups = paramGroups.value(componentId);
        if (!compParamGroups->contains(parent))
        {
pixhawk's avatar
pixhawk committed
            // Insert group item
            QStringList glist;
            glist.append(parent);
            QTreeWidgetItem* item = new QTreeWidgetItem(glist);
            compParamGroups->insert(parent, item);
            componentItems->value(componentId)->addChild(item);

        // Append child to group
        bool found = false;
        QTreeWidgetItem* parentItem = compParamGroups->value(parent);
        for (int i = 0; i < parentItem->childCount(); i++) {
            QTreeWidgetItem* child = parentItem->child(i);
            QString key = child->data(0, Qt::DisplayRole).toString();
tstellanova's avatar
tstellanova committed
            if (key == parameterName)  {
                //qDebug() << "UPDATED CHILD";
                parameterItem = child;
tstellanova's avatar
tstellanova committed
                if (value.type() == QVariant::Char) {
                    parameterItem->setData(1, Qt::DisplayRole, value.toUInt());
                }
tstellanova's avatar
tstellanova committed
                else {
                    parameterItem->setData(1, Qt::DisplayRole, value);
                }
tstellanova's avatar
tstellanova committed
        if (!found) {
            // Insert parameter into map
            QStringList plist;
            plist.append(parameterName);
            // CREATE PARAMETER ITEM
            parameterItem = new QTreeWidgetItem(plist);
            // CONFIGURE PARAMETER ITEM
tstellanova's avatar
tstellanova committed
            if (value.type() == QVariant::Char) {
                parameterItem->setData(1, Qt::DisplayRole, value.toUInt());
            }
tstellanova's avatar
tstellanova committed
            else {
                parameterItem->setData(1, Qt::DisplayRole, value);
            }

            compParamGroups->value(parent)->addChild(parameterItem);
lm's avatar
lm committed
            parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable);
lm's avatar
lm committed
    }
tstellanova's avatar
tstellanova committed
    else  {
pixhawk's avatar
pixhawk committed
        bool found = false;
        QTreeWidgetItem* parent = componentItems->value(componentId);
tstellanova's avatar
tstellanova committed
        for (int i = 0; i < parent->childCount(); i++) {
pixhawk's avatar
pixhawk committed
            QTreeWidgetItem* child = parent->child(i);
            QString key = child->data(0, Qt::DisplayRole).toString();
tstellanova's avatar
tstellanova committed
            if (key == parameterName) {
pixhawk's avatar
pixhawk committed
                //qDebug() << "UPDATED CHILD";
                parameterItem = child;
                parameterItem->setData(1, Qt::DisplayRole, value);
pixhawk's avatar
pixhawk committed
                found = true;
            }
        }

tstellanova's avatar
tstellanova committed
        if (!found) {
            // Insert parameter into map
            QStringList plist;
            plist.append(parameterName);
            // CREATE PARAMETER ITEM
            parameterItem = new QTreeWidgetItem(plist);
            // CONFIGURE PARAMETER ITEM
            parameterItem->setData(1, Qt::DisplayRole, value);
            componentItems->value(componentId)->addChild(parameterItem);
lm's avatar
lm committed
            parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable);
pixhawk's avatar
pixhawk committed
        }
        //tree->expandAll();
    // Reset background color
    parameterItem->setBackground(1, Qt::NoBrush);
lm's avatar
lm committed
    // Add tooltip
    QString paramDesc = paramDataModel->getParamDescription(parameterName);
    QString tooltipFormat;
    if (paramDataModel->isParamDefaultKnown(parameterName)) {
        tooltipFormat = tr("Default: %1, %2");
        double paramDefValue = paramDataModel->getParamDefault(parameterName);
        tooltipFormat = tooltipFormat.arg(paramDefValue).arg(paramDesc);
    else {
        tooltipFormat = paramDesc;
    }
    parameterItem->setToolTip(0, tooltipFormat);
    parameterItem->setToolTip(1, tooltipFormat);
lm's avatar
lm committed

tstellanova's avatar
tstellanova committed
    //paramDataModel->handleParameterUpdate(componentId,parameterName,value);
lm's avatar
lm committed

void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* current, int column)
lm's avatar
lm committed
{
    if (current && column > 0) {
        QTreeWidgetItem* parent = current->parent();
        while (parent->parent() != NULL) {
            parent = parent->parent();
        }
        // Parent is now top-level component
        int componentId = componentItems->key(parent);
        QString key = current->data(0, Qt::DisplayRole).toString();
        QVariant value = current->data(1, Qt::DisplayRole);
        // Set parameter on changed list to be transmitted to MAV
        QPalette pal = statusLabel->palette();
        pal.setColor(backgroundRole(), QGC::colorOrange);
        statusLabel->setPalette(pal);
        statusLabel->setText(tr("Transmit pend. %1:%2: %3").arg(componentId).arg(key).arg(value.toFloat(), 5, 'f', 1, QChar(' ')));
        //qDebug() << "PARAM CHANGED: COMP:" << key << "KEY:" << str << "VALUE:" << value;
        // Changed values list
        bool changed = paramDataModel->addPendingIfParameterChanged(componentId,key,value);
        // If the value was numerically changed, display it differently
        if (changed) {
            current->setBackground(0, QBrush(QColor(QGC::colorOrange)));
            current->setBackground(1, QBrush(QColor(QGC::colorOrange)));

            //TODO this seems incorrect-- we're pre-updating the onboard value before we've received confirmation
            //paramDataModel->setOnboardParameterWithType(componentId,key,value);
void QGCParamWidget::saveParametersToFile()
    if (!mav) return;
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./parameters.txt", tr("Parameter File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QTextStream outstream(&file);
    paramDataModel->writeOnboardParametersToStream(outstream,mav->getUASName());

void QGCParamWidget::loadParametersFromFile()
    if (!mav) return;
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Parameter file (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QTextStream in(&file);
    paramDataModel->readUpdateParametersFromStream(in);
lm's avatar
lm committed
}

tstellanova's avatar
tstellanova committed
void QGCParamWidget::setParameterStatusMsg(const QString& msg)
tstellanova's avatar
tstellanova committed
    statusLabel->setText(msg);
}

void QGCParamWidget::requestAllParamsUpdate()
tstellanova's avatar
tstellanova committed
{
    if (!mav) {
        return;
tstellanova's avatar
tstellanova committed

    // Clear view and request param list
    clear();

    requestParameterList();
lm's avatar
lm committed

tstellanova's avatar
tstellanova committed

/**
 * Set all parameter in the parameter tree on the MAV
 */
void QGCParamWidget::setParameters()
{
tstellanova's avatar
tstellanova committed
    paramCommsMgr->sendPendingParameters();
tstellanova's avatar
tstellanova committed
 * Write the current onboard parameters from RAM into
 * permanent storage, e.g. EEPROM or harddisk
tstellanova's avatar
tstellanova committed
void QGCParamWidget::writeParameters()
tstellanova's avatar
tstellanova committed
    int changedParamCount = 0;

    QMap<int, QMap<QString, QVariant>*>::iterator i;
    QMap<int, QMap<QString, QVariant>*> changedValues = paramDataModel->getPendingParameters();

tstellanova's avatar
tstellanova committed
    for (i = changedValues.begin(); i != changedValues.end() , (0 == changedParamCount);  ++i) {
tstellanova's avatar
tstellanova committed
        // Iterate through the parameters of the component
tstellanova's avatar
tstellanova committed
        QMap<QString, QVariant>* compPending = i.value();
        changedParamCount += compPending->count();
tstellanova's avatar
tstellanova committed
    }
tstellanova's avatar
tstellanova committed
    if (changedParamCount > 0) {
tstellanova's avatar
tstellanova committed
        QMessageBox msgBox;
        msgBox.setText(tr("There are locally changed parameters. Please transmit them first (<TRANSMIT>) or update them with the onboard values (<REFRESH>) before storing onboard from RAM to ROM."));
        msgBox.exec();
    }
tstellanova's avatar
tstellanova committed
    else {
        paramCommsMgr->writeParamsToPersistentStorage();
/**
 * @param component the subsystem which has the parameter
 * @param parameterName name of the parameter, as delivered by the system
 * @param value value of the parameter
 */
void QGCParamWidget::setParameter(int component, QString parameterName, QVariant value)
    if (parameterName.isEmpty()) {
        return;
    }

    double dblValue = value.toDouble();

    if (paramDataModel->isValueLessThanParamMin(parameterName,dblValue)) {
        statusLabel->setText(tr("REJ. %1, %2 < min").arg(parameterName).arg(dblValue));
    if (paramDataModel->isValueGreaterThanParamMax(parameterName,dblValue)) {
        statusLabel->setText(tr("REJ. %1, %2 > max").arg(parameterName).arg(dblValue));
    QVariant onboardVal;
    paramDataModel->getOnboardParameterValue(component,parameterName,onboardVal);
    if (onboardVal == value) {
        statusLabel->setText(tr("REJ. %1 already %2").arg(parameterName).arg(dblValue));
    //int paramType = (int)onboardParameters.value(component)->value(parameterName).type();
    int paramType = (int)value.type();
    switch (paramType)
    case QVariant::Char:
    {
        QVariant fixedValue(QChar((unsigned char)value.toInt()));
        emit parameterChanged(component, parameterName, fixedValue);
        //qDebug() << "PARAM WIDGET SENT:" << fixedValue;
    }
        break;
    case QVariant::Int:
Lorenz Meier's avatar
Lorenz Meier committed
    {
        QVariant fixedValue(value.toInt());
        emit parameterChanged(component, parameterName, fixedValue);
        //qDebug() << "PARAM WIDGET SENT:" << fixedValue;
    }
        break;
    case QVariant::UInt:
Lorenz Meier's avatar
Lorenz Meier committed
    {
        QVariant fixedValue(value.toUInt());
        emit parameterChanged(component, parameterName, fixedValue);
        //qDebug() << "PARAM WIDGET SENT:" << fixedValue;
    }
        break;
    case QMetaType::Float:
Lorenz Meier's avatar
Lorenz Meier committed
    {
        QVariant fixedValue(value.toFloat());
        emit parameterChanged(component, parameterName, fixedValue);
        //qDebug() << "PARAM WIDGET SENT:" << fixedValue;
    }
        break;
    default:
        qCritical() << "ABORTED PARAM SEND, NO VALID QVARIANT TYPE";
        return;
    }

lm's avatar
lm committed
    // Wait for parameter to be written back
    // mark it therefore as missing
    if (!transmissionMissingWriteAckPackets.contains(component))
    {
        transmissionMissingWriteAckPackets.insert(component, new QMap<QString, QVariant>());
lm's avatar
lm committed
    }

    // Insert it in missing write ACK list
    transmissionMissingWriteAckPackets.value(component)->insert(parameterName, value);

    // Set timeouts
Lorenz Meier's avatar
Lorenz Meier committed
    if (transmissionActive)
    {
        transmissionTimeout += rewriteTimeout;
    }
    else
    {
        quint64 newTransmissionTimeout = QGC::groundTimeMilliseconds() + rewriteTimeout;
        if (newTransmissionTimeout > transmissionTimeout)
        {
            transmissionTimeout = newTransmissionTimeout;
        }
        transmissionActive = true;
lm's avatar
lm committed
    }
Lorenz Meier's avatar
Lorenz Meier committed

lm's avatar
lm committed
    // Enable guard / reset timeouts
tstellanova's avatar
tstellanova committed
    paramCommsMgr->setRetransmissionGuardEnabled(true); //TODO
void QGCParamWidget::readParameters()
{
    if (!mav) return;
    mav->readParametersFromStorage();
/**
 * Clear all data in the parameter widget
 */
pixhawk's avatar
pixhawk committed
void QGCParamWidget::clear()
{
    tree->clear();
    componentItems->clear();
pixhawk's avatar
pixhawk committed
}