UASView.cc 22.5 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
#include "ui_UASView.h"
43
#include <QGCHilFlightGearConfiguration.h>
pixhawk's avatar
pixhawk committed
44 45

UASView::UASView(UASInterface* uas, QWidget *parent) :
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    QWidget(parent),
    uas(uas),
    startTime(0),
    timeout(false),
    iconIsRed(true),
    disconnected(false),
    timeRemaining(0),
    chargeLevel(0),
    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),
    globalFrameKnown(false),
    removeAction(new QAction(tr("Delete this system"), this)),
    renameAction(new QAction(tr("Rename.."), this)),
    selectAction(new QAction(tr("Control this system"), this)),
    hilAction(new QAction(tr("HIL - Hardware in the Loop"), this)),
    selectAirframeAction(new QAction(tr("Choose Airframe"), this)),
    setBatterySpecsAction(new QAction(tr("Set Battery Options"), this)),
    lowPowerModeEnabled(true),
    generalUpdateCount(0),
    filterTime(0),
    m_ui(new Ui::UASView)
80
{
81
    m_ui->setupUi(this);
82
    setToolTip(""); // Make sure the QGroupBox's tooltip doesn't seep through.
83

84 85 86
    // FIXME XXX
    lowPowerModeEnabled = MainWindow::instance()->lowPowerModeEnabled();

lm's avatar
lm committed
87
    hilAction->setCheckable(true);
88

pixhawk's avatar
pixhawk committed
89
    // Setup communication
pixhawk's avatar
pixhawk committed
90
    //connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), this, SLOT(receiveValue(int,QString,double,quint64)));
dongfang's avatar
dongfang committed
91
    connect(uas, SIGNAL(batteryChanged(UASInterface*, double, double, double, int)), this, SLOT(updateBattery(UASInterface*, double, double, double, int)));
pixhawk's avatar
pixhawk committed
92 93 94
    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)));
95
    connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,double,quint64)));
96
    connect(uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
pixhawk's avatar
pixhawk committed
97
    connect(uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString,QString)));
pixhawk's avatar
pixhawk committed
98
    connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
pixhawk's avatar
pixhawk committed
99
    connect(uas, SIGNAL(loadChanged(UASInterface*, double)), this, SLOT(updateLoad(UASInterface*, double)));
100
    connect(uas, SIGNAL(heartbeatTimeout(bool, unsigned int)), this, SLOT(heartbeatTimeout(bool, unsigned int)));
pixhawk's avatar
pixhawk committed
101
    connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int,int)));
pixhawk's avatar
pixhawk committed
102
    connect(uas->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointUpdated(quint16)));
pixhawk's avatar
pixhawk committed
103
    connect(uas, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint)));
104
    connect(UASManager::instance(), SIGNAL(activeUASStatusChanged(UASInterface*,bool)), this, SLOT(updateActiveUAS(UASInterface*,bool)));
105 106 107
    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
108 109 110 111
    // 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()));
112
    connect(m_ui->landButton, SIGNAL(clicked()), uas, SLOT(land()));
pixhawk's avatar
pixhawk committed
113
    connect(m_ui->abortButton, SIGNAL(clicked()), uas, SLOT(emergencySTOP()));
pixhawk's avatar
pixhawk committed
114 115
    connect(m_ui->killButton, SIGNAL(clicked()), uas, SLOT(emergencyKILL()));
    connect(m_ui->shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown()));
116

117 118
    // Allow deleting this widget
    connect(removeAction, SIGNAL(triggered()), this, SLOT(triggerUASDeletion()));
119
    connect(renameAction, SIGNAL(triggered()), this, SLOT(rename()));
120
    connect(selectAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
121
    connect(selectAirframeAction, SIGNAL(triggered()), this, SLOT(selectAirframe()));
122
    connect(setBatterySpecsAction, SIGNAL(triggered()), this, SLOT(setBatterySpecs()));
123 124 125

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

pixhawk's avatar
pixhawk committed
127
    // Set static values
128

pixhawk's avatar
pixhawk committed
129
    // Name
130 131
    if (uas->getUASName() == "")
    {
pixhawk's avatar
pixhawk committed
132
        m_ui->nameLabel->setText(tr("UAS") + QString::number(uas->getUASID()));
133 134 135
    }
    else
    {
pixhawk's avatar
pixhawk committed
136 137
        m_ui->nameLabel->setText(uas->getUASName());
    }
138

pixhawk's avatar
pixhawk committed
139 140 141
    // Heartbeat fade
    refreshTimer = new QTimer(this);
    connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
142 143
    if (lowPowerModeEnabled)
    {
144
        refreshTimer->start(updateInterval*3);
145 146 147
    }
    else
    {
148 149
        refreshTimer->start(updateInterval);
    }
150

151 152 153 154 155 156 157
    // Style some elements by default to the UAS' color.
    heartbeatColor = uas->getColor();
    QString colorstyle("QLabel { background-color: %1; }");
    m_ui->typeLabel->setStyleSheet(colorstyle.arg(heartbeatColor.name()));
    updateActiveUAS(uas, false);

    // Hide kill and shutdown buttons by default
158 159 160
    m_ui->killButton->hide();
    m_ui->shutdownButton->hide();

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

UASView::~UASView()
{
    delete m_ui;
}

172
void UASView::heartbeatTimeout(bool timeout, unsigned int ms)
173
{
174 175
    Q_UNUSED(ms);
    this->timeout = timeout;
176
}
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

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;
}
193

194
void UASView::setUASasActive(bool active)
pixhawk's avatar
pixhawk committed
195
{
196 197
    if (active)
    {
198 199 200 201 202 203
        UASManager::instance()->setActiveUAS(this->uas);
    }
}

void UASView::updateActiveUAS(UASInterface* uas, bool active)
{
204 205
    if (uas == this->uas)
    {
206
        this->isActive = active;
207 208 209 210 211 212 213 214
        if (active)
        {
            setStyleSheet("UASView { border-width: 3px}");
        }
        else
        {
            setStyleSheet(QString("UASView { border-color: %1}").arg(heartbeatColor.name()));
        }
215
    }
pixhawk's avatar
pixhawk committed
216 217
}

pixhawk's avatar
pixhawk committed
218 219
void UASView::updateMode(int sysId, QString status, QString description)
{
220
    Q_UNUSED(description);
221 222

    //int aa=this->uas->getUASID();
pixhawk's avatar
pixhawk committed
223
    if (sysId == this->uas->getUASID()) m_ui->modeLabel->setText(status);
224 225

    m_ui->modeLabel->setText(status);
pixhawk's avatar
pixhawk committed
226 227
}

pixhawk's avatar
pixhawk committed
228 229
void UASView::mouseDoubleClickEvent (QMouseEvent * event)
{
230
    Q_UNUSED(event);
pixhawk's avatar
pixhawk committed
231
    UASManager::instance()->setActiveUAS(uas);
232
    // qDebug() << __FILE__ << __LINE__ << "DOUBLECLICKED";
pixhawk's avatar
pixhawk committed
233 234 235 236
}

void UASView::enterEvent(QEvent* event)
{
237 238
    if (event->type() == QEvent::MouseMove)
    {
239
        emit uasInFocus(uas);
240 241
        if (uas != UASManager::instance()->getActiveUAS())
        {
242 243 244
            grabMouse(QCursor(Qt::PointingHandCursor));
        }
    }
245

246 247
    if (event->type() == QEvent::MouseButtonDblClick)
    {
248
        // qDebug() << __FILE__ << __LINE__ << "UAS CLICKED!";
249
    }
pixhawk's avatar
pixhawk committed
250 251 252 253
}

void UASView::leaveEvent(QEvent* event)
{
254 255
    if (event->type() == QEvent::MouseMove)
    {
256 257 258 259 260 261 262 263 264
        emit uasOutFocus(uas);
        releaseMouse();
    }
}

void UASView::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
265
    Q_UNUSED(event);
266
    refreshTimer->start(updateInterval*10);
267 268 269 270 271 272 273
}

void UASView::hideEvent(QHideEvent* event)
{
    // React only to internal (pre-display)
    // events
    Q_UNUSED(event);
274
   // refreshTimer->stop();
pixhawk's avatar
pixhawk committed
275 276 277 278
}

void UASView::receiveHeartbeat(UASInterface* uas)
{
279 280 281 282 283 284 285 286 287 288
    heartbeatColor = uas->getColor();
    QString colorstyle("QLabel { background-color: %1; }");
    m_ui->heartBeatLabel->setStyleSheet(colorstyle.arg(heartbeatColor.name()));

    // If we're returning from a disconnection, recolor things properly.
    if (disconnected)
    {
        updateActiveUAS(this->uas, this->isActive);
        disconnected = false;
    }
289 290 291 292 293
    timeout = false;
}

void UASView::updateName(const QString& name)
{
294
    if (uas) m_ui->nameLabel->setText(name);
pixhawk's avatar
pixhawk committed
295 296 297 298 299 300 301 302 303 304 305
}

/**
 * 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)
{
306 307
    if (uas == this->uas)
    {
pixhawk's avatar
pixhawk committed
308
        // Set matching icon
309 310
        switch (systemType)
        {
311
        case MAV_TYPE_GENERIC:
312
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/generic.svg"));
pixhawk's avatar
pixhawk committed
313
            break;
314
        case MAV_TYPE_FIXED_WING:
315
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/fixed-wing.svg"));
pixhawk's avatar
pixhawk committed
316
            break;
317
        case MAV_TYPE_QUADROTOR:
318
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/quadrotor.svg"));
pixhawk's avatar
pixhawk committed
319
            break;
320
        case MAV_TYPE_COAXIAL:
321
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/coaxial.svg"));
pixhawk's avatar
pixhawk committed
322
            break;
323
        case MAV_TYPE_HELICOPTER:
324
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/helicopter.svg"));
pixhawk's avatar
pixhawk committed
325
            break;
326
        case MAV_TYPE_ANTENNA_TRACKER:
327
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/unknown.svg"));
lm's avatar
lm committed
328
            break;
329
        case MAV_TYPE_GCS: {
330 331
                // A groundstation is a special system type, update widget
                QString result;
lm's avatar
lm committed
332
                m_ui->nameLabel->setText(tr("GCS ") + result.sprintf("%03d", uas->getUASID()));
333 334 335 336 337 338 339 340 341 342 343 344
                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();
345
                m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/groundstation.svg"));
346 347
            }
            break;
348
        case MAV_TYPE_AIRSHIP:
349
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/airship.svg"));
350 351
            break;
        case MAV_TYPE_FREE_BALLOON:
352
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/free-balloon.svg"));
353 354
            break;
        case MAV_TYPE_ROCKET:
355
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/rocket.svg"));
356 357
            break;
        case MAV_TYPE_GROUND_ROVER:
358
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/ground-rover.svg"));
359 360
            break;
        case MAV_TYPE_SURFACE_BOAT:
361
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/surface-boat.svg"));
362 363
            break;
        case MAV_TYPE_SUBMARINE:
364
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/submarine.svg"));
365 366
            break;
        case MAV_TYPE_HEXAROTOR:
367
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/hexarotor.svg"));
368 369
            break;
        case MAV_TYPE_OCTOROTOR:
370
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/octorotor.svg"));
371 372
            break;
        case MAV_TYPE_TRICOPTER:
373
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/tricopter.svg"));
374 375
            break;
        case MAV_TYPE_FLAPPING_WING:
376
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/flapping-wing.svg"));
377 378
            break;
        case MAV_TYPE_KITE:
379
            m_ui->typeLabel->setPixmap(QPixmap(":files/images/mavs/kite.svg"));
380
            break;
pixhawk's avatar
pixhawk committed
381
        default:
382
            m_ui->typeLabel->setPixmap(QPixmap(":/files/images/mavs/unknown.svg"));
pixhawk's avatar
pixhawk committed
383 384 385 386 387 388 389
            break;
        }
    }
}

void UASView::updateLocalPosition(UASInterface* uas, double x, double y, double z, quint64 usec)
{
390
    Q_UNUSED(usec);
391 392 393 394
    Q_UNUSED(uas);
    this->x = x;
    this->y = y;
    this->z = z;
395
    localFrame = true;
pixhawk's avatar
pixhawk committed
396 397
}

398
void UASView::updateGlobalPosition(UASInterface* uas, double lon, double lat, double altAMSL, double altWGS84, quint64 usec)
pixhawk's avatar
pixhawk committed
399
{
400 401
    Q_UNUSED(uas);
    Q_UNUSED(usec);
402
    Q_UNUSED(altAMSL);
pixhawk's avatar
pixhawk committed
403 404
    this->lon = lon;
    this->lat = lat;
405
    this->alt = altWGS84;
406
    globalFrameKnown = true;
pixhawk's avatar
pixhawk committed
407 408 409 410
}

void UASView::updateSpeed(UASInterface*, double x, double y, double z, quint64 usec)
{
411
    Q_UNUSED(usec);
412
    totalSpeed = sqrt(x*x + y*y + z*z);
pixhawk's avatar
pixhawk committed
413 414
}

415 416 417 418 419
void UASView::currentWaypointUpdated(quint16 waypoint)
{
    m_ui->waypointLabel->setText(tr("WP") + QString::number(waypoint));
}

pixhawk's avatar
pixhawk committed
420 421
void UASView::setWaypoint(int uasId, int id, double x, double y, double z, double yaw, bool autocontinue, bool current)
{
422 423 424 425 426
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(z);
    Q_UNUSED(yaw);
    Q_UNUSED(autocontinue);
427 428 429 430
    if (uasId == this->uas->getUASID())
    {
        if (current)
        {
pixhawk's avatar
pixhawk committed
431 432 433 434 435 436 437
            m_ui->waypointLabel->setText(tr("WP") + QString::number(id));
        }
    }
}

void UASView::selectWaypoint(int uasId, int id)
{
438 439
    if (uasId == this->uas->getUASID())
    {
pixhawk's avatar
pixhawk committed
440 441 442 443 444 445
        m_ui->waypointLabel->setText(tr("WP") + QString::number(id));
    }
}

void UASView::updateThrust(UASInterface* uas, double thrust)
{
446 447
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
448
        this->thrust = thrust;
pixhawk's avatar
pixhawk committed
449 450 451
    }
}

dongfang's avatar
dongfang committed
452
void UASView::updateBattery(UASInterface* uas, double voltage, double current, double percent, int seconds)
pixhawk's avatar
pixhawk committed
453
{
454
    Q_UNUSED(voltage);
dongfang's avatar
dongfang committed
455
    Q_UNUSED(current);
456 457
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
458 459 460 461 462 463 464
        timeRemaining = seconds;
        chargeLevel = percent;
    }
}

void UASView::updateState(UASInterface* uas, QString uasState, QString stateDescription)
{
465 466
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
467 468 469 470 471 472 473
        state = uasState;
        stateDesc = stateDescription;
    }
}

void UASView::updateLoad(UASInterface* uas, double load)
{
474 475
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
476 477 478 479
        this->load = load;
    }
}

480 481
void UASView::contextMenuEvent (QContextMenuEvent* event)
{
482
    QMenu menu(this);
lm's avatar
lm committed
483 484
    menu.addAction(selectAction);
    menu.addSeparator();
485
    menu.addAction(renameAction);
486 487
    if (timeout)
    {
488
        menu.addAction(removeAction);
489
    }
490
    menu.addAction(hilAction);
491
    menu.addAction(selectAirframeAction);
492
    menu.addAction(setBatterySpecsAction);
493 494 495
    menu.exec(event->globalPos());
}

496 497
void UASView::setBatterySpecs()
{
498 499
    if (uas)
    {
500 501
        bool ok;
        QString newName = QInputDialog::getText(this, tr("Set Battery Specifications for %1").arg(uas->getUASName()),
502
                                                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,
503 504 505 506 507 508
                                                uas->getBatterySpecs(), &ok);

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

509 510
void UASView::rename()
{
511 512
    if (uas)
    {
513 514 515 516 517 518
        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);
519 520 521
    }
}

522 523
void UASView::selectAirframe()
{
524 525
    if (uas)
    {
526 527 528
        // Get list of airframes from UAS
        QStringList airframes;
        airframes << "Generic"
529 530 531 532 533 534 535 536
                << "Multiplex Easystar"
                << "Multiplex Twinstar"
                << "Multiplex Merlin"
                << "Pixhawk Cheetah"
                << "Mikrokopter"
                << "Reaper"
                << "Predator"
                << "Coaxial"
537
                << "Pteryx"
Lorenz Meier's avatar
Lorenz Meier committed
538 539 540 541 542
                << "Tricopter"
                << "Asctec Firefly"
                << "X8 Flying Wing"
                << "Viper 2.0 Flying Wing"
                << "Cam Flyer Q Flying Wing";
543 544 545 546

        bool ok;
        QString item = QInputDialog::getItem(this, tr("Select Airframe for %1").arg(uas->getUASName()),
                                             tr("Airframe"), airframes, uas->getAirframe(), false, &ok);
547 548
        if (ok && !item.isEmpty())
        {
549 550 551 552 553 554
            // Set this airframe as UAS airframe
            uas->setAirframe(airframes.indexOf(item));
        }
    }
}

555
void UASView::triggerUASDeletion()
556 557 558 559 560
{
    refreshTimer->stop();
    UASManager::instance()->removeUAS(uas);
}

pixhawk's avatar
pixhawk committed
561 562
void UASView::refresh()
{
563 564
    if (generalUpdateCount == 4)
    {
565
#if (QGC_EVENTLOOP_DEBUG)
566
        // qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
567
#endif
568
        generalUpdateCount = 0;
569
        //// qDebug() << "UPDATING EVERYTHING";
570 571 572 573 574 575 576 577 578 579
        // 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
580 581 582 583 584 585 586
        // 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);
587
        }
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

        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);
613
        }
pixhawk's avatar
pixhawk committed
614

615
        // Altitude
616 617
        if (groundDistance == 0 && alt != 0)
        {
618
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(alt, 6, 'f', 1, '0'));
619 620 621
        }
        else
        {
622
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(groundDistance, 6, 'f', 1, '0'));
623
        }
624

625
        // Speed
626 627
        QString speed("%1 m/s");
        m_ui->speedLabel->setText(speed.arg(totalSpeed, 4, 'f', 1, '0'));
pixhawk's avatar
pixhawk committed
628

629 630
        // Thrust
        m_ui->thrustBar->setValue(thrust * 100);
pixhawk's avatar
pixhawk committed
631

treymarc's avatar
treymarc committed
632 633 634 635 636 637 638 639 640 641 642
        // Time Elapsed
        //QDateTime time = MG::TIME::msecToQDateTime(uas->getUptime());

       quint64 filterTime = uas->getUptime() / 1000;
       int hours = static_cast<int>(filterTime / 3600);
       int min = static_cast<int>((filterTime - 3600 * hours) / 60);
       int sec = static_cast<int>(filterTime - 60 * min - 3600 * hours);
       QString timeText;
       timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
       m_ui->timeElapsedLabel->setText(timeText);

643 644
        if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME)
        {
645
            // Filter output to get a higher stability
646
            filterTime = static_cast<int>(this->timeRemaining);
treymarc's avatar
treymarc committed
647 648 649 650
            // filterTime = 0.8 * filterTime + 0.2 * static_cast<int>(this->timeRemaining);
            hours = static_cast<int>(filterTime / 3600);
            min = static_cast<int>((filterTime - 3600 * hours) / 60);
            sec = static_cast<int>(filterTime - 60 * min - 3600 * hours);
651 652 653

            timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
            m_ui->timeRemainingLabel->setText(timeText);
654 655 656
        }
        else
        {
657
            m_ui->timeRemainingLabel->setText(tr("Calc.."));
658 659 660
        }


pixhawk's avatar
pixhawk committed
661
    }
662
    generalUpdateCount++;
pixhawk's avatar
pixhawk committed
663

664 665
    if (timeout)
    {
666
        // CRITICAL CONDITION, NO HEARTBEAT
667
        disconnected = true;
668

669
        QColor warnColor;
670 671
        if (iconIsRed)
        {
672
            warnColor = Qt::red;
673 674 675
        }
        else
        {
676
            warnColor = Qt::darkRed;
LM's avatar
LM committed
677
            refreshTimer->setInterval(errorUpdateInterval);
678
            refreshTimer->start();
679
        }
680 681
        QString style = QString("UASView {background-color: %1;}").arg(warnColor.name());
        this->setStyleSheet(style);
682
        iconIsRed = !iconIsRed;
683 684 685
    }
    else
    {
686 687
        // If we're not in low power mode, add the additional visual effect of
        // fading out the color of the heartbeat for this UAS.
688 689
        if (!lowPowerModeEnabled)
        {
690 691 692
            heartbeatColor = heartbeatColor.darker(110);
            QString colorstyle("QLabel {background-color: %1;}");
            m_ui->heartBeatLabel->setStyleSheet(colorstyle.arg(heartbeatColor.name()));
LM's avatar
LM committed
693
            refreshTimer->setInterval(updateInterval);
694
            refreshTimer->start();
695
        }
696
    }
pixhawk's avatar
pixhawk committed
697 698 699 700 701
}

void UASView::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
702 703
    switch (e->type())
    {
pixhawk's avatar
pixhawk committed
704 705 706 707 708 709 710
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
711 712 713 714 715

/**
 * Implement paintEvent() so that stylesheets work for our custom widget.
 */
void UASView::paintEvent(QPaintEvent *)
716 717 718 719 720 721
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}