UASView.cc 22.7 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 95
    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)));
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(hilAction, SIGNAL(triggered(bool)), this, SLOT(showHILUi()));
122
    connect(selectAirframeAction, SIGNAL(triggered()), this, SLOT(selectAirframe()));
123
    connect(setBatterySpecsAction, SIGNAL(triggered()), this, SLOT(setBatterySpecs()));
124 125 126

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

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

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

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

152 153 154 155 156 157 158
    // 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
159 160 161
    m_ui->killButton->hide();
    m_ui->shutdownButton->hide();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

void UASView::receiveHeartbeat(UASInterface* uas)
{
280 281 282 283 284 285 286 287 288 289
    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;
    }
290 291 292 293 294
    timeout = false;
}

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

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

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

399
void UASView::updateGlobalPosition(UASInterface* uas, double lon, double lat, double alt, quint64 usec)
pixhawk's avatar
pixhawk committed
400
{
401 402
    Q_UNUSED(uas);
    Q_UNUSED(usec);
pixhawk's avatar
pixhawk committed
403 404 405
    this->lon = lon;
    this->lat = lat;
    this->alt = alt;
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 556 557 558 559
void UASView::showHILUi()
{
     MainWindow::instance()->showHILConfigurationWidget(uas);
}

560
void UASView::triggerUASDeletion()
561 562 563 564 565
{
    refreshTimer->stop();
    UASManager::instance()->removeUAS(uas);
}

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

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

620
        // Altitude
621 622
        if (groundDistance == 0 && alt != 0)
        {
623
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(alt, 6, 'f', 1, '0'));
624 625 626
        }
        else
        {
627
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(groundDistance, 6, 'f', 1, '0'));
628
        }
629

630
        // Speed
631 632
        QString speed("%1 m/s");
        m_ui->speedLabel->setText(speed.arg(totalSpeed, 4, 'f', 1, '0'));
pixhawk's avatar
pixhawk committed
633

634 635
        // Thrust
        m_ui->thrustBar->setValue(thrust * 100);
pixhawk's avatar
pixhawk committed
636

637 638
        if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME)
        {
639
            // Filter output to get a higher stability
640
            filterTime = static_cast<int>(this->timeRemaining);
641
            filterTime = 0.8 * filterTime + 0.2 * static_cast<int>(this->timeRemaining);
642 643 644
            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);
645 646 647 648

            QString timeText;
            timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
            m_ui->timeRemainingLabel->setText(timeText);
649 650 651
        }
        else
        {
652
            m_ui->timeRemainingLabel->setText(tr("Calc.."));
653 654 655 656 657 658
        }

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

        quint64 filterTime = uas->getUptime() / 1000;
659 660 661
        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);
pixhawk's avatar
pixhawk committed
662 663
        QString timeText;
        timeText = timeText.sprintf("%02d:%02d:%02d", hours, min, sec);
664
        m_ui->timeElapsedLabel->setText(timeText);
pixhawk's avatar
pixhawk committed
665
    }
666
    generalUpdateCount++;
pixhawk's avatar
pixhawk committed
667

668 669
    if (timeout)
    {
670
        // CRITICAL CONDITION, NO HEARTBEAT
671
        disconnected = true;
672

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

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

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