QGCParamWidget.cc 21.1 KB
Newer Older
1 2 3 4
/*=====================================================================

QGroundControl Open Source Ground Control Station

pixhawk's avatar
pixhawk committed
5
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

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>
 */

29 30
#include <QGridLayout>
#include <QPushButton>
31 32
#include <QFileDialog>
#include <QFile>
pixhawk's avatar
pixhawk committed
33 34 35 36

#include "QGCParamWidget.h"
#include "UASInterface.h"
#include <QDebug>
37
#include "QGC.h"
pixhawk's avatar
pixhawk committed
38

39 40 41 42
/**
 * @param uas MAV to set the parameters on
 * @param parent Parent widget
 */
pixhawk's avatar
pixhawk committed
43
QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) :
44
        QWidget(parent),
lm's avatar
lm committed
45

46
        mav(uas),
lm's avatar
lm committed
47
        components(new QMap<int, QTreeWidgetItem*>()),
pixhawk's avatar
pixhawk committed
48
        paramGroups(),
49
        changedValues(),
lm's avatar
lm committed
50 51 52 53
        parameters(),
        transmissionListMode(false),
        transmissionActive(false),
        transmissionStarted(0)
pixhawk's avatar
pixhawk committed
54 55 56
{
    // Create tree widget
    tree = new QTreeWidget(this);
lm's avatar
lm committed
57
    statusLabel = new QLabel();
58
    tree->setColumnWidth(0, 150);
pixhawk's avatar
pixhawk committed
59 60

    // Set tree widget as widget onto this component
61
    QGridLayout* horizontalLayout;
pixhawk's avatar
pixhawk committed
62
    //form->setAutoFillBackground(false);
63 64
    horizontalLayout = new QGridLayout(this);
    horizontalLayout->setSpacing(6);
pixhawk's avatar
pixhawk committed
65 66 67
    horizontalLayout->setMargin(0);
    horizontalLayout->setSizeConstraint(QLayout::SetMinimumSize);

lm's avatar
lm committed
68
    // Parameter tree
69
    horizontalLayout->addWidget(tree, 0, 0, 1, 3);
lm's avatar
lm committed
70 71 72 73 74 75 76

    // Status line
    statusLabel->setText(tr("Click read to get parameters"));
    horizontalLayout->addWidget(statusLabel, 1, 0, 1, 3);


    // BUTTONS
77
    QPushButton* refreshButton = new QPushButton(tr("Refresh"));
78 79
    refreshButton->setToolTip(tr("Load parameters currently in non-permanent memory of aircraft."));
    refreshButton->setWhatsThis(tr("Load parameters currently in non-permanent memory of aircraft."));
80
    connect(refreshButton, SIGNAL(clicked()), this, SLOT(requestParameterList()));
lm's avatar
lm committed
81
    horizontalLayout->addWidget(refreshButton, 2, 0);
82

83
    QPushButton* setButton = new QPushButton(tr("Transmit"));
84 85
    setButton->setToolTip(tr("Set current parameters in non-permanent onboard memory"));
    setButton->setWhatsThis(tr("Set current parameters in non-permanent onboard memory"));
86
    connect(setButton, SIGNAL(clicked()), this, SLOT(setParameters()));
lm's avatar
lm committed
87
    horizontalLayout->addWidget(setButton, 2, 1);
88

89
    QPushButton* writeButton = new QPushButton(tr("Write (ROM)"));
90 91
    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."));
92
    connect(writeButton, SIGNAL(clicked()), this, SLOT(writeParameters()));
lm's avatar
lm committed
93
    horizontalLayout->addWidget(writeButton, 2, 2);
94

95
    QPushButton* loadFileButton = new QPushButton(tr("Load File"));
96 97
    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."));
98
    connect(loadFileButton, SIGNAL(clicked()), this, SLOT(loadParameters()));
lm's avatar
lm committed
99
    horizontalLayout->addWidget(loadFileButton, 3, 0);
100 101

    QPushButton* saveFileButton = new QPushButton(tr("Save File"));
102 103
    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."));
104
    connect(saveFileButton, SIGNAL(clicked()), this, SLOT(saveParameters()));
lm's avatar
lm committed
105 106 107 108 109 110 111
    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);
112

113
    // Set layout
pixhawk's avatar
pixhawk committed
114 115 116 117 118 119 120 121
    this->setLayout(horizontalLayout);

    // Set header
    QStringList headerItems;
    headerItems.append("Parameter");
    headerItems.append("Value");
    tree->setHeaderLabels(headerItems);
    tree->setColumnCount(2);
122
    tree->setExpandsOnDoubleClick(true);
123 124 125

    // Connect signals/slots
    connect(this, SIGNAL(parameterChanged(int,QString,float)), mav, SLOT(setParameter(int,QString,float)));
126
    connect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(parameterItemChanged(QTreeWidgetItem*,int)));
lm's avatar
lm committed
127

128
    // New parameters from UAS
lm's avatar
lm committed
129
    connect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,float)), this, SLOT(addParameter(int,int,int,int,QString,float)));
pixhawk's avatar
pixhawk committed
130 131
}

132 133 134 135
/**
 * @return The MAV of this widget. Unless the MAV object has been destroyed, this
 *         pointer is never zero.
 */
pixhawk's avatar
pixhawk committed
136 137 138 139 140 141 142 143 144 145 146
UASInterface* QGCParamWidget::getUAS()
{
    return mav;
}

/**
 *
 * @param uas System which has the component
 * @param component id of the component
 * @param componentName human friendly name of the component
 */
147
void QGCParamWidget::addComponent(int uas, int component, QString componentName)
pixhawk's avatar
pixhawk committed
148
{
149
    Q_UNUSED(uas);
pixhawk's avatar
pixhawk committed
150
    if (components->contains(component))
pixhawk's avatar
pixhawk committed
151
    {
pixhawk's avatar
pixhawk committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165
        // Update existing
        components->value(component)->setData(0, Qt::DisplayRole, componentName);
        components->value(component)->setData(1, Qt::DisplayRole, QString::number(component));
    }
    else
    {
        // Add new
        QStringList list;
        list.append(componentName);
        list.append(QString::number(component));
        QTreeWidgetItem* comp = new QTreeWidgetItem(list);
        components->insert(component, comp);
        // Create grouping and update maps
        paramGroups.insert(component, new QMap<QString, QTreeWidgetItem*>());
pixhawk's avatar
pixhawk committed
166 167
        tree->addTopLevelItem(comp);
        tree->update();
168 169 170 171 172 173 174 175 176 177
        // Create map in parameters
        if (!parameters.contains(component))
        {
            parameters.insert(component, new QMap<QString, float>());
        }
        // Create map in changed parameters
        if (!changedValues.contains(component))
        {
            changedValues.insert(component, new QMap<QString, float>());
        }
pixhawk's avatar
pixhawk committed
178 179 180
    }
}

lm's avatar
lm committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
/**
 * @param uas System which has the component
 * @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, float value)
{
    addParameter(uas, component, parameterName, value);

    // 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))
        {
            // If this was the first packet to announce the list size
            // set all packets not received yet as missing to enforce
            // retransmission until full list is received
            if (!transmissionMissingPackets.contains(component))
            {
                transmissionMissingPackets.insert(component, new QList<int>());
            }

            for (int i = 0; i < paramCount; ++i)
            {
                if (!transmissionMissingPackets.value(component)->contains(i))
                {
                    transmissionMissingPackets.value(component)->append(i);
                }
            }
            transmissionListSizeKnown.insert(component, true);
        }
    }

    // Mark this parameter as received
    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);

221 222 223 224 225 226 227
    int missCount = 0;
    foreach (int key, transmissionMissingPackets.keys())
    {
        missCount +=  transmissionMissingPackets.value(key)->count();
    }

    statusLabel->setText(tr("Got Param (#%1 of %5) %2: %3 (%4 missing)").arg(paramId+1).arg(parameterName).arg(value).arg(missCount).arg(paramCount));
lm's avatar
lm committed
228 229

    // Check if last parameter was received
230
    if (missCount == 0)
lm's avatar
lm committed
231 232 233 234 235 236 237 238 239 240 241
    {
        this->transmissionActive = false;
        this->transmissionListMode = false;
        transmissionListSizeKnown.clear();
        foreach (int key, transmissionMissingPackets.keys())
        {
            transmissionMissingPackets.value(key)->clear();
        }
    }
}

242 243 244 245 246 247
/**
 * @param uas System which has the component
 * @param component id of the component
 * @param parameterName human friendly name of the parameter
 */
void QGCParamWidget::addParameter(int uas, int component, QString parameterName, float value)
pixhawk's avatar
pixhawk committed
248
{
249
    Q_UNUSED(uas);
250
    // Reference to item in tree
251
    QTreeWidgetItem* parameterItem = NULL;
pixhawk's avatar
pixhawk committed
252 253 254 255

    // Get component
    if (!components->contains(component))
    {
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
        QString componentName;
        switch (component)
        {
        case MAV_COMP_ID_CAMERA:
            componentName = tr("Camera (#%1)").arg(component);
            break;
        case MAV_COMP_ID_IMU:
            componentName = tr("IMU (#%1)").arg(component);
            break;
        default:
            componentName = tr("Component #").arg(component);
            break;
        }

        addComponent(uas, component, componentName);
pixhawk's avatar
pixhawk committed
271
    }
272

273 274 275 276 277 278 279
    // Replace value in map

    // FIXME
    if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName);
    parameters.value(component)->insert(parameterName, value);


pixhawk's avatar
pixhawk committed
280 281 282
    QString splitToken = "_";
    // Check if auto-grouping can work
    if (parameterName.contains(splitToken))
283
    {
pixhawk's avatar
pixhawk committed
284 285 286
        QString parent = parameterName.section(splitToken, 0, 0, QString::SectionSkipEmpty);
        QMap<QString, QTreeWidgetItem*>* compParamGroups = paramGroups.value(component);
        if (!compParamGroups->contains(parent))
287
        {
pixhawk's avatar
pixhawk committed
288 289 290 291 292 293
            // Insert group item
            QStringList glist;
            glist.append(parent);
            QTreeWidgetItem* item = new QTreeWidgetItem(glist);
            compParamGroups->insert(parent, item);
            components->value(component)->addChild(item);
294
        }
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

        // 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();
            if (key == parameterName)
            {
                //qDebug() << "UPDATED CHILD";
                parameterItem = child;
                parameterItem->setData(1, Qt::DisplayRole, value);
                found = true;
            }
        }

        if (!found)
        {
            // Insert parameter into map
            QStringList plist;
            plist.append(parameterName);
            plist.append(QString::number(value));
318
            // CREATE PARAMETER ITEM
319
            parameterItem = new QTreeWidgetItem(plist);
320
            // CONFIGURE PARAMETER ITEM
321 322

            compParamGroups->value(parent)->addChild(parameterItem);
lm's avatar
lm committed
323
            parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable);
324
        }
325
    }
pixhawk's avatar
pixhawk committed
326
    else
327
    {
pixhawk's avatar
pixhawk committed
328 329 330 331 332 333 334 335 336
        bool found = false;
        QTreeWidgetItem* parent = components->value(component);
        for (int i = 0; i < parent->childCount(); i++)
        {
            QTreeWidgetItem* child = parent->child(i);
            QString key = child->data(0, Qt::DisplayRole).toString();
            if (key == parameterName)
            {
                //qDebug() << "UPDATED CHILD";
337 338
                parameterItem = child;
                parameterItem->setData(1, Qt::DisplayRole, value);
pixhawk's avatar
pixhawk committed
339 340 341 342 343 344
                found = true;
            }
        }

        if (!found)
        {
345 346 347 348
            // Insert parameter into map
            QStringList plist;
            plist.append(parameterName);
            plist.append(QString::number(value));
349
            // CREATE PARAMETER ITEM
350
            parameterItem = new QTreeWidgetItem(plist);
351
            // CONFIGURE PARAMETER ITEM
352

lm's avatar
lm committed
353 354
            components->value(component)->addChild(parameterItem);
            parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable);
pixhawk's avatar
pixhawk committed
355
        }
356
        //tree->expandAll();
357
    }
358
    // Reset background color
359 360 361
    parameterItem->setBackground(0, QBrush(QColor(0, 0, 0)));
    parameterItem->setBackground(1, Qt::NoBrush);
    //tree->update();
pixhawk's avatar
pixhawk committed
362
    if (changedValues.contains(component)) changedValues.value(component)->remove(parameterName);
pixhawk's avatar
pixhawk committed
363 364
}

365 366 367 368
/**
 * Send a request to deliver the list of onboard parameters
 * to the MAV.
 */
369 370
void QGCParamWidget::requestParameterList()
{
lm's avatar
lm committed
371
    // Clear view and request param list
372
    clear();
373
    parameters.clear();
lm's avatar
lm committed
374
    received.clear();
lm's avatar
lm committed
375 376 377 378 379 380 381 382 383
    // Clear transmission state
    transmissionListMode = true;
    transmissionListSizeKnown.clear();
    foreach (int key, transmissionMissingPackets.keys())
    {
        transmissionMissingPackets.value(key)->clear();
    }
    transmissionActive = true;
    transmissionStarted = QGC::groundTimeUsecs();
lm's avatar
lm committed
384
    mav->requestParameters();
385 386
}

387
void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* current, int column)
lm's avatar
lm committed
388
{
389
    if (current && column > 0)
lm's avatar
lm committed
390
    {
391 392 393 394 395 396 397 398 399 400 401 402 403
        QTreeWidgetItem* parent = current->parent();
        while (parent->parent() != NULL)
        {
            parent = parent->parent();
        }
        // Parent is now top-level component
        int key = components->key(parent);
        if (!changedValues.contains(key))
        {
            changedValues.insert(key, new QMap<QString, float>());
        }
        QMap<QString, float>* map = changedValues.value(key, NULL);
        if (map)
lm's avatar
lm committed
404
        {
405 406 407
            bool ok;
            QString str = current->data(0, Qt::DisplayRole).toString();
            float value = current->data(1, Qt::DisplayRole).toDouble(&ok);
lm's avatar
lm committed
408
            // Set parameter on changed list to be transmitted to MAV
409
            if (ok)
lm's avatar
lm committed
410
            {
411 412
                if (ok)
                {
lm's avatar
lm committed
413 414
                    statusLabel->setText(tr("Changed Param %1:%2: %3").arg(key).arg(str).arg(value));
                    //qDebug() << "PARAM CHANGED: COMP:" << key << "KEY:" << str << "VALUE:" << value;
415
                    // Changed values list
416
                    if (map->contains(str)) map->remove(str);
417
                    map->insert(str, value);
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460

                    // Check if the value was numerically changed
                    if (!parameters.value(key)->contains(str) || parameters.value(key)->value(str, 0.0f) != value)
                    {
                        current->setBackground(0, QBrush(QColor(QGC::colorGreen)));
                        current->setBackground(1, QBrush(QColor(QGC::colorGreen)));
                    }

                    // All parameters list
                    if (parameters.value(key)->contains(str)) parameters.value(key)->remove(str);
                    parameters.value(key)->insert(str, value);
                }
            }
        }
    }
}

void QGCParamWidget::saveParameters()
{    
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./parameters.txt", tr("Parameter File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return;
    }

    QTextStream in(&file);

    in << "# Onboard parameters for system " << mav->getUASName() << "\n";
    in << "#\n";
    in << "# MAV ID  COMPONENT ID  PARAM NAME  VALUE (FLOAT)\n";

    // Iterate through all components, through all parameters and emit them
    QMap<int, QMap<QString, float>*>::iterator i;
    for (i = parameters.begin(); i != parameters.end(); ++i)
    {
        // Iterate through the parameters of the component
        int compid = i.key();
        QMap<QString, float>* comp = i.value();
        {
            QMap<QString, float>::iterator j;
            for (j = comp->begin(); j != comp->end(); ++j)
            {
461
                QString paramValue("%1");
lm's avatar
lm committed
462
                paramValue = paramValue.arg(j.value(), 25, 'g', 12);
463
                in << mav->getUASID() << "\t" << compid << "\t" << j.key() << "\t" << paramValue << "\n";
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
                in.flush();
            }
        }
    }
    file.close();
}

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

    // Clear list
    clear();

    QTextStream in(&file);
    while (!in.atEnd())
    {
        QString line = in.readLine();
        if (!line.startsWith("#"))
        {
            QStringList wpParams = line.split("\t");
            if (wpParams.size() == 4)
            {
                // Only load parameters for right mav
                if (mav->getUASID() == wpParams.at(0).toInt())
                {
pixhawk's avatar
pixhawk committed
493

lm's avatar
lm committed
494 495 496 497 498 499 500 501 502
                    bool changed = false;
                    int component = wpParams.at(1).toInt();
                    QString parameterName = wpParams.at(2);
                    if (!parameters.contains(component) || parameters.value(component)->value(parameterName, 0.0f) != (float)wpParams.at(3).toDouble())
                    {
                        changed = true;
                    }

                    // Set parameter value
503
                    addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toDouble());
lm's avatar
lm committed
504 505

                    if (changed)
506
                    {
lm's avatar
lm committed
507 508
                        // Create changed values data structure if necessary
                        if (!changedValues.contains(wpParams.at(1).toInt()))
509
                        {
lm's avatar
lm committed
510
                            changedValues.insert(wpParams.at(1).toInt(), new QMap<QString, float>());
511 512
                        }

lm's avatar
lm committed
513 514 515 516 517 518 519 520
                        // Add to changed values
                        if (changedValues.value(wpParams.at(1).toInt())->contains(wpParams.at(2)))
                        {
                            changedValues.value(wpParams.at(1).toInt())->remove(wpParams.at(2));
                        }

                        changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), (float)wpParams.at(3).toDouble());

521
                        //qDebug() << "MARKING COMP" << wpParams.at(1).toInt() << "PARAM" << wpParams.at(2) << "VALUE" << (float)wpParams.at(3).toDouble() << "AS CHANGED";
lm's avatar
lm committed
522 523

                        // Mark in UI
pixhawk's avatar
pixhawk committed
524

pixhawk's avatar
pixhawk committed
525

526
                    }
527
                }
lm's avatar
lm committed
528 529
            }
        }
530
    }
531 532
    file.close();

lm's avatar
lm committed
533 534
}

535

536 537 538 539 540 541 542
/**
 * @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, float value)
{
543
    emit parameterChanged(component, parameterName, value);
544

545 546
}

547 548 549
/**
 * Set all parameter in the parameter tree on the MAV
 */
550 551
void QGCParamWidget::setParameters()
{
552
    // Iterate through all components, through all parameters and emit them
553
    int parametersSent = 0;
554 555 556 557 558 559 560 561 562 563
    QMap<int, QMap<QString, float>*>::iterator i;
    for (i = changedValues.begin(); i != changedValues.end(); ++i)
    {
        // Iterate through the parameters of the component
        int compid = i.key();
        QMap<QString, float>* comp = i.value();
        {
            QMap<QString, float>::iterator j;
            for (j = comp->begin(); j != comp->end(); ++j)
            {
564
                setParameter(compid, j.key(), j.value());
565
                parametersSent++;
566 567 568 569
            }
        }
    }

570 571 572 573 574 575 576 577 578 579
    // Update stats label
    if (parametersSent == 0)
    {
        statusLabel->setText(tr("No transmission: No changed values."));
    }
    else
    {
        statusLabel->setText(tr("Transmitting %1 parameters.").arg(parametersSent));
    }

lm's avatar
lm committed
580
    changedValues.clear();
581 582
}

583 584 585 586
/**
 * Write the current onboard parameters from RAM into
 * permanent storage, e.g. EEPROM or harddisk
 */
587 588
void QGCParamWidget::writeParameters()
{
589 590 591 592 593 594
    mav->writeParametersToStorage();
}

void QGCParamWidget::readParameters()
{
    mav->readParametersFromStorage();
595 596
}

597 598 599
/**
 * Clear all data in the parameter widget
 */
pixhawk's avatar
pixhawk committed
600 601 602
void QGCParamWidget::clear()
{
    tree->clear();
lm's avatar
lm committed
603
    components->clear();
pixhawk's avatar
pixhawk committed
604
}