UASView.cc 23 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
        QWidget(parent),
        startTime(0),
        timeout(false),
        iconIsRed(true),
50
        disconnected(false),
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        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),
69
        globalFrameKnown(false),
70 71 72
        removeAction(new QAction("Delete this system", this)),
        renameAction(new QAction("Rename..", this)),
        selectAction(new QAction("Control this system", this )),
73
        hilAction(new QAction("HIL - Hardware in the Loop", this )),
74 75
        selectAirframeAction(new QAction("Choose Airframe", this)),
        setBatterySpecsAction(new QAction("Set Battery Options", this)),
76
        lowPowerModeEnabled(true),
77 78
        generalUpdateCount(0),
        filterTime(0),
79 80 81 82 83
        m_ui(new Ui::UASView)
{
    // FIXME XXX
    lowPowerModeEnabled = MainWindow::instance()->lowPowerModeEnabled();

lm's avatar
lm committed
84
    hilAction->setCheckable(true);
85

pixhawk's avatar
pixhawk committed
86
    m_ui->setupUi(this);
87

pixhawk's avatar
pixhawk committed
88
    // Setup communication
pixhawk's avatar
pixhawk committed
89
    //connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), this, SLOT(receiveValue(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
90 91 92 93 94 95 96
    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
97
    connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
pixhawk's avatar
pixhawk committed
98
    connect(uas, SIGNAL(loadChanged(UASInterface*, double)), this, SLOT(updateLoad(UASInterface*, double)));
99
    connect(uas, SIGNAL(heartbeatTimeout(bool, unsigned int)), this, SLOT(heartbeatTimeout(bool, unsigned int)));
pixhawk's avatar
pixhawk committed
100
    connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int,int)));
pixhawk's avatar
pixhawk committed
101
    connect(uas->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointUpdated(quint16)));
pixhawk's avatar
pixhawk committed
102
    connect(uas, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint)));
103
    connect(UASManager::instance(), SIGNAL(activeUASStatusChanged(UASInterface*,bool)), this, SLOT(updateActiveUAS(UASInterface*,bool)));
104 105 106
    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
107
    // Setup UAS selection
108
    connect(this, SIGNAL(clicked(bool)), this, SLOT(setUASasActive(bool)));
109

pixhawk's avatar
pixhawk committed
110 111 112 113
    // 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()));
114
    connect(m_ui->landButton, SIGNAL(clicked()), uas, SLOT(land()));
pixhawk's avatar
pixhawk committed
115
    connect(m_ui->abortButton, SIGNAL(clicked()), uas, SLOT(emergencySTOP()));
pixhawk's avatar
pixhawk committed
116 117
    connect(m_ui->killButton, SIGNAL(clicked()), uas, SLOT(emergencyKILL()));
    connect(m_ui->shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown()));
118 119 120

    // Allow to delete this widget
    connect(removeAction, SIGNAL(triggered()), this, SLOT(deleteLater()));
121
    connect(renameAction, SIGNAL(triggered()), this, SLOT(rename()));
122
    connect(selectAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
123
    connect(hilAction, SIGNAL(triggered(bool)), this, SLOT(showHILUi()));
124
    connect(selectAirframeAction, SIGNAL(triggered()), this, SLOT(selectAirframe()));
125
    connect(setBatterySpecsAction, SIGNAL(triggered()), this, SLOT(setBatterySpecs()));
126
    connect(uas, SIGNAL(systemRemoved()), this, SLOT(deleteLater()));
127 128 129

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

pixhawk's avatar
pixhawk committed
131
    // Set static values
132

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

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

155 156 157 158 159 160 161
    // 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
162 163 164
    m_ui->killButton->hide();
    m_ui->shutdownButton->hide();

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

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

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

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

201
void UASView::setUASasActive(bool active)
pixhawk's avatar
pixhawk committed
202
{
203 204
    if (active)
    {
205 206 207 208 209 210
        UASManager::instance()->setActiveUAS(this->uas);
    }
}

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

pixhawk's avatar
pixhawk committed
225 226
void UASView::updateMode(int sysId, QString status, QString description)
{
227
    Q_UNUSED(description);
228 229

    //int aa=this->uas->getUASID();
pixhawk's avatar
pixhawk committed
230
    if (sysId == this->uas->getUASID()) m_ui->modeLabel->setText(status);
231 232

    m_ui->modeLabel->setText(status);
pixhawk's avatar
pixhawk committed
233 234
}

pixhawk's avatar
pixhawk committed
235 236
void UASView::mouseDoubleClickEvent (QMouseEvent * event)
{
237
    Q_UNUSED(event);
pixhawk's avatar
pixhawk committed
238
    UASManager::instance()->setActiveUAS(uas);
239
    // qDebug() << __FILE__ << __LINE__ << "DOUBLECLICKED";
pixhawk's avatar
pixhawk committed
240 241 242 243
}

void UASView::enterEvent(QEvent* event)
{
244 245
    if (event->type() == QEvent::MouseMove)
    {
246
        emit uasInFocus(uas);
247 248
        if (uas != UASManager::instance()->getActiveUAS())
        {
249 250 251
            grabMouse(QCursor(Qt::PointingHandCursor));
        }
    }
252

253 254
    if (event->type() == QEvent::MouseButtonDblClick)
    {
255
        // qDebug() << __FILE__ << __LINE__ << "UAS CLICKED!";
256
    }
pixhawk's avatar
pixhawk committed
257 258 259 260
}

void UASView::leaveEvent(QEvent* event)
{
261 262
    if (event->type() == QEvent::MouseMove)
    {
263 264 265 266 267 268 269 270 271
        emit uasOutFocus(uas);
        releaseMouse();
    }
}

void UASView::showEvent(QShowEvent* event)
{
    // React only to internal (pre-display)
    // events
272
    Q_UNUSED(event);
273
    refreshTimer->start(updateInterval*10);
274 275 276 277 278 279 280
}

void UASView::hideEvent(QHideEvent* event)
{
    // React only to internal (pre-display)
    // events
    Q_UNUSED(event);
281
   // refreshTimer->stop();
pixhawk's avatar
pixhawk committed
282 283 284 285
}

void UASView::receiveHeartbeat(UASInterface* uas)
{
286 287 288 289 290 291 292 293 294 295
    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;
    }
296 297 298 299 300
    timeout = false;
}

void UASView::updateName(const QString& name)
{
301
    if (uas) m_ui->nameLabel->setText(name);
pixhawk's avatar
pixhawk committed
302 303 304 305 306 307 308 309 310 311 312
}

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

void UASView::updateLocalPosition(UASInterface* uas, double x, double y, double z, quint64 usec)
{
397
    Q_UNUSED(usec);
398 399 400 401
    Q_UNUSED(uas);
    this->x = x;
    this->y = y;
    this->z = z;
402
    localFrame = true;
pixhawk's avatar
pixhawk committed
403 404
}

405
void UASView::updateGlobalPosition(UASInterface* uas, double lon, double lat, double alt, quint64 usec)
pixhawk's avatar
pixhawk committed
406
{
407 408
    Q_UNUSED(uas);
    Q_UNUSED(usec);
pixhawk's avatar
pixhawk committed
409 410 411
    this->lon = lon;
    this->lat = lat;
    this->alt = alt;
412
    globalFrameKnown = true;
pixhawk's avatar
pixhawk committed
413 414 415 416
}

void UASView::updateSpeed(UASInterface*, double x, double y, double z, quint64 usec)
{
417
    Q_UNUSED(usec);
418
    totalSpeed = sqrt(x*x + y*y + z*z);
pixhawk's avatar
pixhawk committed
419 420
}

421 422 423 424 425
void UASView::currentWaypointUpdated(quint16 waypoint)
{
    m_ui->waypointLabel->setText(tr("WP") + QString::number(waypoint));
}

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

void UASView::selectWaypoint(int uasId, int id)
{
444 445
    if (uasId == this->uas->getUASID())
    {
pixhawk's avatar
pixhawk committed
446 447 448 449 450 451
        m_ui->waypointLabel->setText(tr("WP") + QString::number(id));
    }
}

void UASView::updateThrust(UASInterface* uas, double thrust)
{
452 453
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
454
        this->thrust = thrust;
pixhawk's avatar
pixhawk committed
455 456 457 458 459
    }
}

void UASView::updateBattery(UASInterface* uas, double voltage, double percent, int seconds)
{
460
    Q_UNUSED(voltage);
461 462
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
463 464 465 466 467 468 469
        timeRemaining = seconds;
        chargeLevel = percent;
    }
}

void UASView::updateState(UASInterface* uas, QString uasState, QString stateDescription)
{
470 471
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
472 473 474 475 476 477 478
        state = uasState;
        stateDesc = stateDescription;
    }
}

void UASView::updateLoad(UASInterface* uas, double load)
{
479 480
    if (this->uas == uas)
    {
pixhawk's avatar
pixhawk committed
481 482 483 484
        this->load = load;
    }
}

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

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

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

514 515
void UASView::rename()
{
516 517
    if (uas)
    {
518 519 520 521 522 523
        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);
524 525 526
    }
}

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

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

560 561 562 563 564
void UASView::showHILUi()
{
     MainWindow::instance()->showHILConfigurationWidget(uas);
}

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


573 574
    if (generalUpdateCount == 4)
    {
575
#if (QGC_EVENTLOOP_DEBUG)
576
        // qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
577
#endif
578
        generalUpdateCount = 0;
579
        //// qDebug() << "UPDATING EVERYTHING";
580 581 582 583 584 585 586 587 588 589
        // 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
590 591 592 593 594 595 596
        // 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);
597
        }
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

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

625
        // Altitude
626 627
        if (groundDistance == 0 && alt != 0)
        {
628
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(alt, 6, 'f', 1, '0'));
629 630 631
        }
        else
        {
632
            m_ui->groundDistanceLabel->setText(QString("%1 m").arg(groundDistance, 6, 'f', 1, '0'));
633
        }
634

635
        // Speed
636 637
        QString speed("%1 m/s");
        m_ui->speedLabel->setText(speed.arg(totalSpeed, 4, 'f', 1, '0'));
pixhawk's avatar
pixhawk committed
638

639 640
        // Thrust
        m_ui->thrustBar->setValue(thrust * 100);
pixhawk's avatar
pixhawk committed
641

642 643
        if(this->timeRemaining > 1 && this->timeRemaining < QGC::MAX_FLIGHT_TIME)
        {
644
            // Filter output to get a higher stability
645
            filterTime = static_cast<int>(this->timeRemaining);
646 647 648 649 650 651 652 653
            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);
654 655 656
        }
        else
        {
657
            m_ui->timeRemainingLabel->setText(tr("Calc.."));
658 659 660 661 662 663 664
        }

        // 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
665 666 667 668
        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);
669
        m_ui->timeElapsedLabel->setText(timeText);
pixhawk's avatar
pixhawk committed
670
    }
671
    generalUpdateCount++;
pixhawk's avatar
pixhawk committed
672

673 674
    if (timeout)
    {
675
        // CRITICAL CONDITION, NO HEARTBEAT
676
        disconnected = true;
677

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

void UASView::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
711 712
    switch (e->type())
    {
pixhawk's avatar
pixhawk committed
713 714 715 716 717 718 719
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
720 721 722 723 724 725 726 727 728 729 730

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