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>
lm's avatar
lm committed
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"
Thomas Gubler's avatar
Thomas Gubler committed
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()));
lm's avatar
lm committed
119
    connect(renameAction, SIGNAL(triggered()), this, SLOT(rename()));
120
    connect(selectAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
Thomas Gubler's avatar
Thomas Gubler committed
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()));
lm's avatar
lm committed
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)
lm's avatar
lm committed
174
{
175
176
    Q_UNUSED(ms);
    this->timeout = timeout;
lm's avatar
lm committed
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;
}
lm's avatar
lm committed
194

pixhawk's avatar
pixhawk committed
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;
    }
lm's avatar
lm committed
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 altAMSL, double altWGS84, quint64 usec)
pixhawk's avatar
pixhawk committed
400
{
401
402
    Q_UNUSED(uas);
    Q_UNUSED(usec);
403
    Q_UNUSED(altAMSL);
pixhawk's avatar
pixhawk committed
404
405
    this->lon = lon;
    this->lat = lat;
406
    this->alt = altWGS84;
407
    globalFrameKnown = true;
pixhawk's avatar
pixhawk committed
408
409
410
411
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Thomas Gubler's avatar
Thomas Gubler committed
556
557
558
559
560
void UASView::showHILUi()
{
     MainWindow::instance()->showHILConfigurationWidget(uas);
}

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

pixhawk's avatar
pixhawk committed
567
568
void UASView::refresh()
{
569
570
    if (generalUpdateCount == 4)
    {
571
#if (QGC_EVENTLOOP_DEBUG)
572
        // qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
573
#endif
574
        generalUpdateCount = 0;
575
        //// qDebug() << "UPDATING EVERYTHING";
576
577
578
579
580
581
582
583
584
585
        // 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
586
587
588
589
590
591
592
        // 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);
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
618

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

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

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

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

treymarc's avatar
treymarc committed
638
639
640
641
642
643
644
645
646
647
648
        // 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);

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);
treymarc's avatar
treymarc committed
653
654
655
656
            // 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);
657
658
659

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


pixhawk's avatar
pixhawk committed
667
    }
668
    generalUpdateCount++;
pixhawk's avatar
pixhawk committed
669

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

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

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

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