UASView.cc 23.9 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11
/*=====================================================================
PIXHAWK Micro Air Vehicle Flying Robotics Toolkit

(c) 2009, 2010 PIXHAWK PROJECT  <http://pixhawk.ethz.ch>

This file is part of the PIXHAWK project

    PIXHAWK 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.
12

pixhawk's avatar
pixhawk committed
13 14 15 16
    PIXHAWK 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.
17

pixhawk's avatar
pixhawk committed
18 19
    You should have received a copy of the GNU General Public License
    along with PIXHAWK. If not, see <http://www.gnu.org/licenses/>.
20

pixhawk's avatar
pixhawk committed
21 22 23 24
======================================================================*/

/**
 * @file
pixhawk's avatar
pixhawk committed
25
 *   @brief Implementation of one airstrip
pixhawk's avatar
pixhawk committed
26 27 28 29 30 31 32 33
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <cmath>
#include <QDateTime>
#include <QDebug>
34
#include <QMenu>
35
#include <QInputDialog>
pixhawk's avatar
pixhawk committed
36

37
#include "QGC.h"
pixhawk's avatar
pixhawk committed
38 39
#include "UASManager.h"
#include "UASView.h"
40
#include "UASWaypointManager.h"
41
#include "MainWindow.h"
pixhawk's avatar
pixhawk committed
42 43 44
#include "ui_UASView.h"

UASView::UASView(UASInterface* uas, QWidget *parent) :
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
        QWidget(parent),
        startTime(0),
        timeout(false),
        iconIsRed(true),
        timeRemaining(0),
        chargeLevel(0),
        uas(uas),
        load(0),
        state("UNKNOWN"),
        stateDesc(tr("Unknown state")),
        mode("MAV_MODE_UNKNOWN"),
        thrust(0),
        isActive(false),
        x(0),
        y(0),
        z(0),
        totalSpeed(0),
        lat(0),
        lon(0),
        alt(0),
        groundDistance(0),
        localFrame(false),
67
        globalFrameKnown(false),
68 69 70
        removeAction(new QAction("Delete this system", this)),
        renameAction(new QAction("Rename..", this)),
        selectAction(new QAction("Control this system", this )),
71 72
        hilAction(new QAction("Enable Flightgear Hardware-in-the-Loop Simulation", this )),
        hilXAction(new QAction("Enable X-Plane Hardware-in-the-Loop Simulation", this )),
73 74
        selectAirframeAction(new QAction("Choose Airframe", this)),
        setBatterySpecsAction(new QAction("Set Battery Options", this)),
75
        lowPowerModeEnabled(true),
76 77
        generalUpdateCount(0),
        filterTime(0),
78 79 80 81 82
        m_ui(new Ui::UASView)
{
    // FIXME XXX
    lowPowerModeEnabled = MainWindow::instance()->lowPowerModeEnabled();

lm's avatar
lm committed
83
    hilAction->setCheckable(true);
84 85 86
    // Flightgear is not ready for prime time
    hilAction->setEnabled(false);
    hilXAction->setCheckable(true);
87

pixhawk's avatar
pixhawk committed
88
    m_ui->setupUi(this);
89

pixhawk's avatar
pixhawk committed
90
    // Setup communication
pixhawk's avatar
pixhawk committed
91
    //connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), this, SLOT(receiveValue(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
92 93 94 95 96 97 98
    connect(uas, SIGNAL(batteryChanged(UASInterface*, double, double, int)), this, SLOT(updateBattery(UASInterface*, double, double, int)));
    connect(uas, SIGNAL(heartbeat(UASInterface*)), this, SLOT(receiveHeartbeat(UASInterface*)));
    connect(uas, SIGNAL(thrustChanged(UASInterface*, double)), this, SLOT(updateThrust(UASInterface*, double)));
    connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(speedChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
    connect(uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString,QString)));
pixhawk's avatar
pixhawk committed
99
    connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
pixhawk's avatar
pixhawk committed
100
    connect(uas, SIGNAL(loadChanged(UASInterface*, double)), this, SLOT(updateLoad(UASInterface*, double)));
101
    connect(uas, SIGNAL(heartbeatTimeout(bool, unsigned int)), this, SLOT(heartbeatTimeout(bool, unsigned int)));
pixhawk's avatar
pixhawk committed
102
    connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int,int)));
pixhawk's avatar
pixhawk committed
103
    connect(uas->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointUpdated(quint16)));
pixhawk's avatar
pixhawk committed
104
    connect(uas, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint)));
105
    connect(UASManager::instance(), SIGNAL(activeUASStatusChanged(UASInterface*,bool)), this, SLOT(updateActiveUAS(UASInterface*,bool)));
106 107 108
    connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(showStatusText(int, int, int, QString)));
    connect(uas, SIGNAL(navModeChanged(int, int, QString)), this, SLOT(updateNavMode(int, int, QString)));

pixhawk's avatar
pixhawk committed
109
    // Setup UAS selection
110
    connect(m_ui->uasViewFrame, SIGNAL(clicked(bool)), this, SLOT(setUASasActive(bool)));
111

pixhawk's avatar
pixhawk committed
112 113 114 115
    // Setup user interaction
    connect(m_ui->liftoffButton, SIGNAL(clicked()), uas, SLOT(launch()));
    connect(m_ui->haltButton, SIGNAL(clicked()), uas, SLOT(halt()));
    connect(m_ui->continueButton, SIGNAL(clicked()), uas, SLOT(go()));
116
    connect(m_ui->landButton, SIGNAL(clicked()), uas, SLOT(land()));
pixhawk's avatar
pixhawk committed
117
    connect(m_ui->abortButton, SIGNAL(clicked()), uas, SLOT(emergencySTOP()));
pixhawk's avatar
pixhawk committed
118 119
    connect(m_ui->killButton, SIGNAL(clicked()), uas, SLOT(emergencyKILL()));
    connect(m_ui->shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown()));
120 121 122

    // Allow to delete this widget
    connect(removeAction, SIGNAL(triggered()), this, SLOT(deleteLater()));
123
    connect(renameAction, SIGNAL(triggered()), this, SLOT(rename()));
124
    connect(selectAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
lm's avatar
lm committed
125
    connect(hilAction, SIGNAL(triggered(bool)), uas, SLOT(enableHil(bool)));
126
    connect(hilXAction, SIGNAL(triggered(bool)), uas, SLOT(enableHil(bool)));
127
    connect(selectAirframeAction, SIGNAL(triggered()), this, SLOT(selectAirframe()));
128
    connect(setBatterySpecsAction, SIGNAL(triggered()), this, SLOT(setBatterySpecs()));
129
    connect(uas, SIGNAL(systemRemoved()), this, SLOT(deleteLater()));
130 131 132

    // Name changes
    connect(uas, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString)));
133

pixhawk's avatar
pixhawk committed
134
    // Set static values
135

pixhawk's avatar
pixhawk committed
136
    // Name
137 138
    if (uas->getUASName() == "")
    {
pixhawk's avatar
pixhawk committed
139
        m_ui->nameLabel->setText(tr("UAS") + QString::number(uas->getUASID()));
140 141 142
    }
    else
    {
pixhawk's avatar
pixhawk committed
143 144
        m_ui->nameLabel->setText(uas->getUASName());
    }
145

146
    setBackgroundColor();
147

pixhawk's avatar
pixhawk committed
148 149 150
    // Heartbeat fade
    refreshTimer = new QTimer(this);
    connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
151 152
    if (lowPowerModeEnabled)
    {
153
        refreshTimer->start(updateInterval*3);
154 155 156
    }
    else
    {
157 158
        refreshTimer->start(updateInterval);
    }
159 160 161 162 163

    // Hide kill and shutdown buttons per default
    m_ui->killButton->hide();
    m_ui->shutdownButton->hide();

164 165 166
    // Set state and mode
    updateMode(uas->getUASID(), uas->getShortMode(), "");
    updateState(uas, uas->getShortState(), "");
167
    setSystemType(uas, uas->getSystemType());
pixhawk's avatar
pixhawk committed
168 169 170 171 172
}

UASView::~UASView()
{
    delete m_ui;
173 174 175
    delete removeAction;
    delete renameAction;
    delete selectAction;
pixhawk's avatar
pixhawk committed
176 177
}

178
void UASView::heartbeatTimeout(bool timeout, unsigned int ms)
179
{
180 181
    Q_UNUSED(ms);
    this->timeout = timeout;
182
}
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

void UASView::updateNavMode(int uasid, int mode, const QString& text)
{
    Q_UNUSED(uasid);
    Q_UNUSED(mode);
    m_ui->navLabel->setText(text);
}

void UASView::showStatusText(int uasid, int componentid, int severity, QString text)
{
    Q_UNUSED(uasid);
    Q_UNUSED(componentid);
    Q_UNUSED(severity);
    //m_ui->statusTextLabel->setText(text);
    stateDesc = text;
}
199

200 201 202 203 204 205 206 207 208 209
/**
 * Set the background color based on the MAV color. If the MAV is selected as the
 * currently actively controlled system, the frame color is highlighted
 */
void UASView::setBackgroundColor()
{
    // UAS color
    QColor uasColor = uas->getColor();
    QString colorstyle;
    QString borderColor = "#4A4A4F";
210 211
    if (isActive)
    {
212 213
        borderColor = "#FA4A4F";
        uasColor = uasColor.darker(475);
214 215 216
    }
    else
    {
217 218
        uasColor = uasColor.darker(675);
    }
219
    colorstyle = colorstyle.sprintf("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; background-color: #%02X%02X%02X; border: 2px solid %s; }",
220 221 222 223 224
                                    uasColor.red(), uasColor.green(), uasColor.blue(), borderColor.toStdString().c_str());
    m_ui->uasViewFrame->setStyleSheet(colorstyle);
}

void UASView::setUASasActive(bool active)
pixhawk's avatar
pixhawk committed
225
{
226 227
    if (active)
    {
228 229 230 231 232 233
        UASManager::instance()->setActiveUAS(this->uas);
    }
}

void UASView::updateActiveUAS(UASInterface* uas, bool active)
{
234 235
    if (uas == this->uas)
    {
236 237 238
        this->isActive = active;
        setBackgroundColor();
    }
pixhawk's avatar
pixhawk committed
239 240
}

pixhawk's avatar
pixhawk committed
241 242
void UASView::updateMode(int sysId, QString status, QString description)
{
243
    Q_UNUSED(description);
244 245

    //int aa=this->uas->getUASID();
pixhawk's avatar
pixhawk committed
246
    if (sysId == this->uas->getUASID()) m_ui->modeLabel->setText(status);
247 248

    m_ui->modeLabel->setText(status);
pixhawk's avatar
pixhawk committed
249 250
}

pixhawk's avatar
pixhawk committed
251 252
void UASView::mouseDoubleClickEvent (QMouseEvent * event)
{
253
    Q_UNUSED(event);
pixhawk's avatar
pixhawk committed
254
    UASManager::instance()->setActiveUAS(uas);
255
    // qDebug() << __FILE__ << __LINE__ << "DOUBLECLICKED";
pixhawk's avatar
pixhawk committed
256 257 258 259
}

void UASView::enterEvent(QEvent* event)
{
260 261
    if (event->type() == QEvent::MouseMove)
    {
262
        emit uasInFocus(uas);
263 264
        if (uas != UASManager::instance()->getActiveUAS())
        {
265 266 267
            grabMouse(QCursor(Qt::PointingHandCursor));
        }
    }
268

269 270
    if (event->type() == QEvent::MouseButtonDblClick)
    {
271
        // qDebug() << __FILE__ << __LINE__ << "UAS CLICKED!";
272
    }
pixhawk's avatar
pixhawk committed
273 274 275 276
}

void UASView::leaveEvent(QEvent* event)
{
277 278
    if (event->type() == QEvent::MouseMove)
    {
279 280 281 282 283 284 285 286 287
        emit uasOutFocus(uas);
        releaseMouse();
    }
}

void UASView::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
288
    Q_UNUSED(event);
289
    refreshTimer->start(updateInterval*10);
290 291 292 293 294 295 296 297
}

void UASView::hideEvent(QHideEvent* event)
{
    // React only to internal (pre-display)
    // events
    Q_UNUSED(event);
    refreshTimer->stop();
pixhawk's avatar
pixhawk committed
298 299 300 301
}

void UASView::receiveHeartbeat(UASInterface* uas)
{
302
    Q_UNUSED(uas);
303
    heartbeatColor = QColor(20, 200, 20);
lm's avatar
lm committed
304
    QString colorstyle("QGroupBox { border-radius: 5px; padding: 2px; margin: 0px; border: 0px; background-color: %1; }");
305
    m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(heartbeatColor.name()));
306 307 308 309 310 311
    if (timeout) setBackgroundColor();
    timeout = false;
}

void UASView::updateName(const QString& name)
{
312
    if (uas) m_ui->nameLabel->setText(name);
pixhawk's avatar
pixhawk committed
313 314 315 316 317 318 319 320 321 322 323
}

/**
 * The current system type is represented through the system icon.
 *
 * @param uas Source system, has to be the same as this->uas
 * @param systemType type ID, following the MAVLink system type conventions
 * @see http://pixhawk.ethz.ch/software/mavlink
 */
void UASView::setSystemType(UASInterface* uas, unsigned int systemType)
{
324 325
    if (uas == this->uas)
    {
pixhawk's avatar
pixhawk committed
326
        // Set matching icon
327 328
        switch (systemType)
        {
329
        case MAV_TYPE_GENERIC:
330
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/generic.svg"));
pixhawk's avatar
pixhawk committed
331
            break;
332
        case MAV_TYPE_FIXED_WING:
333
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/fixed-wing.svg"));
pixhawk's avatar
pixhawk committed
334
            break;
335
        case MAV_TYPE_QUADROTOR:
336
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/quadrotor.svg"));
pixhawk's avatar
pixhawk committed
337
            break;
338
        case MAV_TYPE_COAXIAL:
339
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/coaxial.svg"));
pixhawk's avatar
pixhawk committed
340
            break;
341
        case MAV_TYPE_HELICOPTER:
342
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/helicopter.svg"));
pixhawk's avatar
pixhawk committed
343
            break;
344
        case MAV_TYPE_ANTENNA_TRACKER:
345
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/unknown.svg"));
lm's avatar
lm committed
346
            break;
347
        case MAV_TYPE_GCS: {
348 349
                // A groundstation is a special system type, update widget
                QString result;
lm's avatar
lm committed
350
                m_ui->nameLabel->setText(tr("GCS ") + result.sprintf("%03d", uas->getUASID()));
351 352 353 354 355 356 357 358 359 360 361 362
                m_ui->waypointLabel->setText("");
                m_ui->timeRemainingLabel->setText("Online:");
                m_ui->batteryBar->hide();
                m_ui->thrustBar->hide();
                m_ui->stateLabel->hide();
                m_ui->statusTextLabel->hide();
                m_ui->waypointLabel->hide();
                m_ui->liftoffButton->hide();
                m_ui->haltButton->hide();
                m_ui->landButton->hide();
                m_ui->shutdownButton->hide();
                m_ui->abortButton->hide();
363
                m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/groundstation.svg"));
364 365
            }
            break;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
        case MAV_TYPE_AIRSHIP:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/airship.svg"));
            break;
        case MAV_TYPE_FREE_BALLOON:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/free-balloon.svg"));
            break;
        case MAV_TYPE_ROCKET:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/rocket.svg"));
            break;
        case MAV_TYPE_GROUND_ROVER:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/ground-rover.svg"));
            break;
        case MAV_TYPE_SURFACE_BOAT:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/surface-boat.svg"));
            break;
        case MAV_TYPE_SUBMARINE:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/submarine.svg"));
            break;
        case MAV_TYPE_HEXAROTOR:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/hexarotor.svg"));
            break;
        case MAV_TYPE_OCTOROTOR:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/octorotor.svg"));
            break;
        case MAV_TYPE_TRICOPTER:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/tricopter.svg"));
            break;
        case MAV_TYPE_FLAPPING_WING:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/flapping-wing.svg"));
            break;
        case MAV_TYPE_KITE:
            m_ui->typeButton->setIcon(QIcon(":files/images/mavs/kite.svg"));
            break;
pixhawk's avatar
pixhawk committed
399
        default:
400
            m_ui->typeButton->setIcon(QIcon(":/files/images/mavs/unknown.svg"));
pixhawk's avatar
pixhawk committed
401 402 403 404 405 406 407
            break;
        }
    }
}

void UASView::updateLocalPosition(UASInterface* uas, double x, double y, double z, quint64 usec)
{
408
    Q_UNUSED(usec);
409 410 411 412
    Q_UNUSED(uas);
    this->x = x;
    this->y = y;
    this->z = z;
413
    localFrame = true;
pixhawk's avatar
pixhawk committed
414 415
}

416
void UASView::updateGlobalPosition(UASInterface* uas, double lon, double lat, double alt, quint64 usec)
pixhawk's avatar
pixhawk committed
417
{
418 419
    Q_UNUSED(uas);
    Q_UNUSED(usec);
pixhawk's avatar
pixhawk committed
420 421 422
    this->lon = lon;
    this->lat = lat;
    this->alt = alt;
423
    globalFrameKnown = true;
pixhawk's avatar
pixhawk committed
424 425 426 427
}

void UASView::updateSpeed(UASInterface*, double x, double y, double z, quint64 usec)
{
428
    Q_UNUSED(usec);
429
    totalSpeed = sqrt(x*x + y*y + z*z);
pixhawk's avatar
pixhawk committed
430 431
}

432 433 434 435 436
void UASView::currentWaypointUpdated(quint16 waypoint)
{
    m_ui->waypointLabel->setText(tr("WP") + QString::number(waypoint));
}

pixhawk's avatar
pixhawk committed
437 438
void UASView::setWaypoint(int uasId, int id, double x, double y, double z, double yaw, bool autocontinue, bool current)
{
439 440 441 442 443
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(z);
    Q_UNUSED(yaw);
    Q_UNUSED(autocontinue);
444 445 446 447
    if (uasId == this->uas->getUASID())
    {
        if (current)
        {
pixhawk's avatar
pixhawk committed
448 449 450 451 452 453 454
            m_ui->waypointLabel->setText(tr("WP") + QString::number(id));
        }
    }
}

void UASView::selectWaypoint(int uasId, int id)
{
455 456
    if (uasId == this->uas->getUASID())
    {
pixhawk's avatar
pixhawk committed
457 458 459 460 461 462
        m_ui->waypointLabel->setText(tr("WP") + QString::number(id));
    }
}

void UASView::updateThrust(UASInterface* uas, double thrust)
{
463 464
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
465
        this->thrust = thrust;
pixhawk's avatar
pixhawk committed
466 467 468 469 470
    }
}

void UASView::updateBattery(UASInterface* uas, double voltage, double percent, int seconds)
{
471
    Q_UNUSED(voltage);
472 473
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
474 475 476 477 478 479 480
        timeRemaining = seconds;
        chargeLevel = percent;
    }
}

void UASView::updateState(UASInterface* uas, QString uasState, QString stateDescription)
{
481 482
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
483 484 485 486 487 488 489
        state = uasState;
        stateDesc = stateDescription;
    }
}

void UASView::updateLoad(UASInterface* uas, double load)
{
490 491
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
492 493 494 495
        this->load = load;
    }
}

496 497
void UASView::contextMenuEvent (QContextMenuEvent* event)
{
498
    QMenu menu(this);
lm's avatar
lm committed
499 500
    menu.addAction(selectAction);
    menu.addSeparator();
501
    menu.addAction(renameAction);
502 503
    if (timeout)
    {
504
        menu.addAction(removeAction);
505
    }
506 507
    menu.addAction(hilXAction);
    // XXX Re-enable later menu.addAction(hilXAction);
508
    menu.addAction(selectAirframeAction);
509
    menu.addAction(setBatterySpecsAction);
510 511 512
    menu.exec(event->globalPos());
}

513 514
void UASView::setBatterySpecs()
{
515 516
    if (uas)
    {
517 518
        bool ok;
        QString newName = QInputDialog::getText(this, tr("Set Battery Specifications for %1").arg(uas->getUASName()),
519
                                                tr("Specs: (empty,warn,full), e.g. (9V,9.5V,12.6V) or just warn level in percent (e.g. 15%) to use estimate from MAV"), QLineEdit::Normal,
520 521 522 523 524 525
                                                uas->getBatterySpecs(), &ok);

        if (ok && !newName.isEmpty()) uas->setBatterySpecs(newName);
    }
}

526 527
void UASView::rename()
{
528 529
    if (uas)
    {
530 531 532 533 534 535
        bool ok;
        QString newName = QInputDialog::getText(this, tr("Rename System %1").arg(uas->getUASName()),
                                                tr("System Name:"), QLineEdit::Normal,
                                                uas->getUASName(), &ok);

        if (ok && !newName.isEmpty()) uas->setUASName(newName);
536 537 538
    }
}

539 540
void UASView::selectAirframe()
{
541 542
    if (uas)
    {
543 544 545
        // Get list of airframes from UAS
        QStringList airframes;
        airframes << "Generic"
546 547 548 549 550 551 552 553
                << "Multiplex Easystar"
                << "Multiplex Twinstar"
                << "Multiplex Merlin"
                << "Pixhawk Cheetah"
                << "Mikrokopter"
                << "Reaper"
                << "Predator"
                << "Coaxial"
554 555
                << "Pteryx"
                << "Asctec Firefly";
556 557 558 559

        bool ok;
        QString item = QInputDialog::getItem(this, tr("Select Airframe for %1").arg(uas->getUASName()),
                                             tr("Airframe"), airframes, uas->getAirframe(), false, &ok);
560 561
        if (ok && !item.isEmpty())
        {
562 563 564 565 566 567
            // Set this airframe as UAS airframe
            uas->setAirframe(airframes.indexOf(item));
        }
    }
}

pixhawk's avatar
pixhawk committed
568 569
void UASView::refresh()
{
570
    //setUpdatesEnabled(false);
571 572
    //setUpdatesEnabled(true);
    //repaint();
573
    //qDebug() << "UPDATING UAS WIDGET!" << uas->getUASName();
574 575


576 577 578
    quint64 lastupdate = 0;
    //// qDebug() << "UASVIEW update diff: " << MG::TIME::getGroundTimeNow() - lastupdate;
    lastupdate = QGC::groundTimeMilliseconds();
579

580 581
    if (generalUpdateCount == 4)
    {
582
#if (QGC_EVENTLOOP_DEBUG)
583
        // qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
584
#endif
585
        generalUpdateCount = 0;
586
        //// qDebug() << "UPDATING EVERYTHING";
587 588 589 590 591 592 593 594 595 596
        // State
        m_ui->stateLabel->setText(state);
        m_ui->statusTextLabel->setText(stateDesc);

        // Battery
        m_ui->batteryBar->setValue(static_cast<int>(this->chargeLevel));
        //m_ui->loadBar->setValue(static_cast<int>(this->load));
        m_ui->thrustBar->setValue(this->thrust);

        // Position
597 598 599 600 601 602 603
        // If global position is known, prefer it over local coordinates

        if (!globalFrameKnown && localFrame)
        {
            QString position;
            position = position.sprintf("%05.1f %05.1f %06.1f m", x, y, z);
            m_ui->positionLabel->setText(position);
604
        }
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

        if (globalFrameKnown)
        {
            QString globalPosition;
            QString latIndicator;
            if (lat > 0)
            {
                latIndicator = "N";
            }
            else
            {
                latIndicator = "S";
            }
            QString lonIndicator;
            if (lon > 0)
            {
                lonIndicator = "E";
            }
            else
            {
                lonIndicator = "W";
            }

            globalPosition = globalPosition.sprintf("%05.1f%s %05.1f%s %06.1f m", lon, lonIndicator.toStdString().c_str(), lat, latIndicator.toStdString().c_str(), alt);
            m_ui->positionLabel->setText(globalPosition);
630
        }
pixhawk's avatar
pixhawk committed
631

632
        // Altitude
633 634
        if (groundDistance == 0 && alt != 0)
        {
635
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(alt, 6, 'f', 1, '0'));
636 637 638
        }
        else
        {
639
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(groundDistance, 6, 'f', 1, '0'));
640
        }
641

642
        // Speed
643 644
        QString speed("%1 m/s");
        m_ui->speedLabel->setText(speed.arg(totalSpeed, 4, 'f', 1, '0'));
pixhawk's avatar
pixhawk committed
645

646 647
        // Thrust
        m_ui->thrustBar->setValue(thrust * 100);
pixhawk's avatar
pixhawk committed
648

649 650
        if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME)
        {
651
            // Filter output to get a higher stability
652
            filterTime = static_cast<int>(this->timeRemaining);
653 654 655 656 657 658 659 660
            filterTime = 0.8 * filterTime + 0.2 * static_cast<int>(this->timeRemaining);
            int sec = static_cast<int>(filterTime - static_cast<int>(filterTime / 60.0f) * 60);
            int min = static_cast<int>(filterTime / 60);
            int hours = static_cast<int>(filterTime - min * 60 - sec);

            QString timeText;
            timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
            m_ui->timeRemainingLabel->setText(timeText);
661 662 663
        }
        else
        {
664
            m_ui->timeRemainingLabel->setText(tr("Calc.."));
665 666 667 668 669 670 671
        }

        // Time Elapsed
        //QDateTime time = MG::TIME::msecToQDateTime(uas->getUptime());

        quint64 filterTime = uas->getUptime() / 1000;
        int sec = static_cast<int>(filterTime - static_cast<int>(filterTime / 60) * 60);
pixhawk's avatar
pixhawk committed
672 673 674 675
        int min = static_cast<int>(filterTime / 60);
        int hours = static_cast<int>(filterTime - min * 60 - sec);
        QString timeText;
        timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
676
        m_ui->timeElapsedLabel->setText(timeText);
pixhawk's avatar
pixhawk committed
677
    }
678
    generalUpdateCount++;
pixhawk's avatar
pixhawk committed
679

lm's avatar
lm committed
680
    QString colorstyle("QGroupBox { border-radius: 5px; padding: 2px; margin: 0px; border: 0px; background-color: %1; }");
681

682 683
    if (timeout)
    {
684 685
        // CRITICAL CONDITION, NO HEARTBEAT

686
        QString borderColor = "#FFFF00";
687 688
        if (isActive)
        {
689 690 691
            borderColor = "#FA4A4F";
        }

692 693
        if (iconIsRed)
        {
694 695
            QColor warnColor(Qt::red);
            m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(warnColor.name()));
696
            QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; border: 2px solid %1; background-color: %2; }").arg(borderColor, warnColor.name());
697
            m_ui->uasViewFrame->setStyleSheet(style);
698 699 700
        }
        else
        {
701 702
            QColor warnColor(Qt::black);
            m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(warnColor.name()));
703
            QString style = QString("QGroupBox { border-radius: 12px; padding: 0px; margin: 0px; border: 2px solid %1; background-color: %2; }").arg(borderColor, warnColor.name());
704
            m_ui->uasViewFrame->setStyleSheet(style);
LM's avatar
LM committed
705 706

            refreshTimer->setInterval(errorUpdateInterval);
707
            refreshTimer->start();
708 709
        }
        iconIsRed = !iconIsRed;
710 711 712
    }
    else
    {
713 714 715 716
        if (!lowPowerModeEnabled)
        {
            // Fade heartbeat icon
            // Make color darker
LM's avatar
LM committed
717
            heartbeatColor = heartbeatColor.darker(210);
718 719 720

            //m_ui->heartbeatIcon->setAutoFillBackground(true);
            m_ui->heartbeatIcon->setStyleSheet(colorstyle.arg(heartbeatColor.name()));
LM's avatar
LM committed
721
            refreshTimer->setInterval(updateInterval);
722
            refreshTimer->start();
723
        }
724
    }
725
    //setUpdatesEnabled(true);
726 727

    //setUpdatesEnabled(false);
pixhawk's avatar
pixhawk committed
728 729 730 731 732
}

void UASView::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
733 734
    switch (e->type())
    {
pixhawk's avatar
pixhawk committed
735 736 737 738 739 740 741
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}