UAS.cc 92.2 KB
Newer Older
1
/*===================================================================
pixhawk's avatar
pixhawk committed
2 3 4 5 6 7 8 9 10 11 12 13 14
======================================================================*/

/**
 * @file
 *   @brief Represents one unmanned aerial vehicle
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QList>
#include <QMessageBox>
#include <QTimer>
15
#include <QSettings>
pixhawk's avatar
pixhawk committed
16 17 18
#include <iostream>
#include <QDebug>
#include <cmath>
19
#include <qmath.h>
pixhawk's avatar
pixhawk committed
20 21 22
#include "UAS.h"
#include "LinkInterface.h"
#include "UASManager.h"
23
#include "QGC.h"
pixhawk's avatar
pixhawk committed
24
#include "GAudioOutput.h"
25
#include "MAVLinkProtocol.h"
pixhawk's avatar
pixhawk committed
26
#include "QGCMAVLink.h"
27 28
#include "LinkManager.h"
#include "SerialLink.h"
pixhawk's avatar
pixhawk committed
29

30
UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(),
LM's avatar
LM committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 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
uasId(id),
startTime(QGC::groundTimeMilliseconds()),
commStatus(COMM_DISCONNECTED),
name(""),
autopilot(-1),
links(new QList<LinkInterface*>()),
unknownPackets(),
mavlink(protocol),
waypointManager(*this),
thrustSum(0),
thrustMax(10),
startVoltage(0),
warnVoltage(9.5f),
warnLevelPercent(20.0f),
currentVoltage(12.0f),
lpVoltage(12.0f),
batteryRemainingEstimateEnabled(false),
mode(-1),
status(-1),
navMode(-1),
onboardTimeOffset(0),
controlRollManual(true),
controlPitchManual(true),
controlYawManual(true),
controlThrustManual(true),
manualRollAngle(0),
manualPitchAngle(0),
manualYawAngle(0),
manualThrust(0),
receiveDropRate(0),
sendDropRate(0),
lowBattAlarm(false),
positionLock(false),
localX(0.0),
localY(0.0),
localZ(0.0),
latitude(0.0),
longitude(0.0),
altitude(0.0),
roll(0.0),
pitch(0.0),
yaw(0.0),
statusTimeout(new QTimer(this)),
paramsOnceRequested(false),
airframe(0),
attitudeKnown(false),
LM's avatar
LM committed
77
paramManager(NULL),
LM's avatar
LM committed
78
attitudeStamped(false),
lm's avatar
lm committed
79 80
lastAttitude(0),
    simulation(new QGCFlightGearLink(this))
pixhawk's avatar
pixhawk committed
81
{
82
    color = UASInterface::getNextColor();
pixhawk's avatar
pixhawk committed
83
    setBattery(LIPOLY, 3);
84
    connect(statusTimeout, SIGNAL(timeout()), this, SLOT(updateState()));
85
    connect(this, SIGNAL(systemSpecsChanged(int)), this, SLOT(writeSettings()));
86
    statusTimeout->start(500);
87
    readSettings();
pixhawk's avatar
pixhawk committed
88 89 90 91
}

UAS::~UAS()
{
92
    writeSettings();
pixhawk's avatar
pixhawk committed
93
    delete links;
94
    links=NULL;
pixhawk's avatar
pixhawk committed
95 96
}

97 98 99 100 101
void UAS::writeSettings()
{
    QSettings settings;
    settings.beginGroup(QString("MAV%1").arg(uasId));
    settings.setValue("NAME", this->name);
102 103
    settings.setValue("AIRFRAME", this->airframe);
    settings.setValue("AP_TYPE", this->autopilot);
104
    settings.setValue("BATTERY_SPECS", getBatterySpecs());
105 106 107 108 109 110 111 112 113
    settings.endGroup();
    settings.sync();
}

void UAS::readSettings()
{
    QSettings settings;
    settings.beginGroup(QString("MAV%1").arg(uasId));
    this->name = settings.value("NAME", this->name).toString();
114 115
    this->airframe = settings.value("AIRFRAME", this->airframe).toInt();
    this->autopilot = settings.value("AP_TYPE", this->autopilot).toInt();
116
    if (settings.contains("BATTERY_SPECS")) {
117 118
        setBatterySpecs(settings.value("BATTERY_SPECS").toString());
    }
119 120 121
    settings.endGroup();
}

122
int UAS::getUASID() const
pixhawk's avatar
pixhawk committed
123 124 125 126
{
    return uasId;
}

127 128
void UAS::updateState()
{
129 130
    // Check if heartbeat timed out
    quint64 heartbeatInterval = QGC::groundTimeUsecs() - lastHeartbeat;
131 132
    if (heartbeatInterval > timeoutIntervalHeartbeat)
    {
133 134 135 136
        emit heartbeatTimeout(heartbeatInterval);
        emit heartbeatTimeout();
    }

137 138
    // Position lock is set by the MAVLink message handler
    // if no position lock is available, indicate an error
139 140
    if (positionLock)
    {
141
        positionLock = false;
142 143 144
    }
    else
    {
lm's avatar
lm committed
145
        if (((mode&MAV_MODE_FLAG_DECODE_POSITION_AUTO) || (mode&MAV_MODE_FLAG_DECODE_POSITION_GUIDED)) && positionLock)
146
        {
147 148 149 150 151
            GAudioOutput::instance()->notifyNegative();
        }
    }
}

pixhawk's avatar
pixhawk committed
152 153
void UAS::setSelected()
{
154
    if (UASManager::instance()->getActiveUAS() != this) {
155 156 157 158 159 160 161 162
        UASManager::instance()->setActiveUAS(this);
        emit systemSelected(true);
    }
}

bool UAS::getSelected() const
{
    return (UASManager::instance()->getActiveUAS() == this);
pixhawk's avatar
pixhawk committed
163 164
}

165 166
void UAS::receiveMessageNamedValue(const mavlink_message_t& message)
{
167 168
    if (message.msgid == MAVLINK_MSG_ID_NAMED_VALUE_FLOAT)
    {
pixhawk's avatar
pixhawk committed
169 170
        mavlink_named_value_float_t val;
        mavlink_msg_named_value_float_decode(&message, &val);
lm's avatar
lm committed
171 172
        QByteArray bytes(val.name, MAVLINK_MSG_NAMED_VALUE_FLOAT_FIELD_NAME_LEN);
        emit valueChanged(this->getUASID(), QString(bytes), tr("raw"), val.value, getUnixTime());
173 174 175
    }
    else if (message.msgid == MAVLINK_MSG_ID_NAMED_VALUE_INT)
    {
pixhawk's avatar
pixhawk committed
176 177
        mavlink_named_value_int_t val;
        mavlink_msg_named_value_int_decode(&message, &val);
lm's avatar
lm committed
178 179
        QByteArray bytes(val.name, MAVLINK_MSG_NAMED_VALUE_INT_FIELD_NAME_LEN);
        emit valueChanged(this->getUASID(), QString(bytes), tr("raw"), val.value, getUnixTime());
180 181 182
    }
}

pixhawk's avatar
pixhawk committed
183 184
void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message)
{
185
    if (!link) return;
186 187
    if (!links->contains(link))
    {
pixhawk's avatar
pixhawk committed
188
        addLink(link);
189
        //        qDebug() << __FILE__ << __LINE__ << "ADDED LINK!" << link->getName();
pixhawk's avatar
pixhawk committed
190
    }
191 192 193 194
    //    else
    //    {
    //        qDebug() << __FILE__ << __LINE__ << "DID NOT ADD LINK" << link->getName() << "ALREADY IN LIST";
    //    }
pixhawk's avatar
pixhawk committed
195

196
    //    qDebug() << "UAS RECEIVED from" << message.sysid << "component" << message.compid << "msg id" << message.msgid << "seq no" << message.seq;
pixhawk's avatar
pixhawk committed
197

LM's avatar
LM committed
198 199 200 201
    // Only accept messages from this system (condition 1)
    // and only then if a) attitudeStamped is disabled OR b) attitudeStamped is enabled
    // and we already got one attitude packet
    if (message.sysid == uasId && (!attitudeStamped || (attitudeStamped && (lastAttitude != 0)) || message.msgid == MAVLINK_MSG_ID_ATTITUDE))
202
    {
pixhawk's avatar
pixhawk committed
203 204
        QString uasState;
        QString stateDescription;
pixhawk's avatar
pixhawk committed
205

206 207
        switch (message.msgid)
        {
pixhawk's avatar
pixhawk committed
208
        case MAVLINK_MSG_ID_HEARTBEAT:
209
        {
210
            lastHeartbeat = QGC::groundTimeUsecs();
pixhawk's avatar
pixhawk committed
211
            emit heartbeat(this);
212 213
            mavlink_heartbeat_t state;
            mavlink_msg_heartbeat_decode(&message, &state);
pixhawk's avatar
pixhawk committed
214
            // Set new type if it has changed
215
            if (this->type != state.type)
216
            {
217
                this->type = state.type;
218 219 220 221
                if (airframe == 0)
                {
                    switch (type)
                    {
lm's avatar
lm committed
222
                    case MAV_TYPE_FIXED_WING:
223 224
                        setAirframe(UASInterface::QGC_AIRFRAME_EASYSTAR);
                        break;
lm's avatar
lm committed
225
                    case MAV_TYPE_QUADROTOR:
226 227 228 229 230 231 232
                        setAirframe(UASInterface::QGC_AIRFRAME_CHEETAH);
                        break;
                    default:
                        // Do nothing
                        break;
                    }
                }
233
                this->autopilot = state.autopilot;
pixhawk's avatar
pixhawk committed
234 235
                emit systemTypeSet(this, type);
            }
236

237 238 239 240 241 242
            QString audiostring = "System " + getUASName();
            QString stateAudio = "";
            QString modeAudio = "";
            QString navModeAudio = "";
            bool statechanged = false;
            bool modechanged = false;
LM's avatar
LM committed
243 244


245 246 247 248 249 250 251
            if (state.system_status != this->status)
            {
                statechanged = true;
                this->status = state.system_status;
                getStatusForCode((int)state.system_status, uasState, stateDescription);
                emit statusChanged(this, uasState, stateDescription);
                emit statusChanged(this->status);
252

253
                shortStateText = uasState;
254

255 256
                stateAudio = tr(" changed status to ") + uasState;
            }
lm's avatar
lm committed
257

258
            if (this->mode != static_cast<int>(state.base_mode))
259 260
            {
                modechanged = true;
261
                this->mode = static_cast<int>(state.base_mode);
262
                shortModeText = getShortModeTextFor(this->mode);
263

264
                emit modeChanged(this->getUASID(), shortModeText, "");
LM's avatar
LM committed
265

266 267
                modeAudio = " is now in " + shortModeText;
            }
LM's avatar
LM committed
268

269
            if (navMode != state.custom_mode)
270
            {
271 272
                emit navModeChanged(uasId, state.custom_mode, getNavModeText(state.custom_mode));
                navMode = state.custom_mode;
273 274
                navModeAudio = tr(" changed nav mode to ") + tr("FIXME");
            }
275

276 277 278 279 280 281 282 283 284 285 286
            // AUDIO
            if (modechanged && statechanged)
            {
                // Output both messages
                audiostring += modeAudio + " and " + stateAudio;
            }
            else if (modechanged || statechanged)
            {
                // Output the one message
                audiostring += modeAudio + stateAudio + navModeAudio;
            }
287

288 289 290 291 292 293 294
            if ((int)state.system_status == (int)MAV_STATE_CRITICAL || state.system_status == (int)MAV_STATE_EMERGENCY)
            {
                GAudioOutput::instance()->startEmergency();
            }
            else if (modechanged || statechanged)
            {
                GAudioOutput::instance()->stopEmergency();
295
                GAudioOutput::instance()->say(audiostring.toLower());
296
            }
lm's avatar
lm committed
297

298 299 300 301 302 303
            if (state.system_status == MAV_STATE_POWEROFF)
            {
                emit systemRemoved(this);
                emit systemRemoved();
            }
}
304

305 306 307 308 309 310 311 312 313 314
            break;
        case MAVLINK_MSG_ID_NAMED_VALUE_FLOAT:
        case MAVLINK_MSG_ID_NAMED_VALUE_INT:
            // Receive named value message
            receiveMessageNamedValue(message);
            break;
        case MAVLINK_MSG_ID_SYS_STATUS:
        {
                mavlink_sys_status_t state;
                mavlink_msg_sys_status_decode(&message, &state);
315

316
                emit loadChanged(this,state.load/10.0f);
lm's avatar
lm committed
317
                // FIXME REMOVE LATER emit valueChanged(uasId, "Load", "%", ((float)state.load)/10.0f, getUnixTime());
318

319
                currentVoltage = state.voltage_battery/1000.0f;
LM's avatar
LM committed
320 321 322
                lpVoltage = filterVoltage(currentVoltage);
                if (startVoltage == 0) startVoltage = currentVoltage;
                timeRemaining = calculateTimeRemaining();
323
                if (!batteryRemainingEstimateEnabled && chargeLevel != -1)
324
                {
325
                    chargeLevel = state.battery_remaining;
LM's avatar
LM committed
326 327 328
                }
                //qDebug() << "Voltage: " << currentVoltage << " Chargelevel: " << getChargeLevel() << " Time remaining " << timeRemaining;
                emit batteryChanged(this, lpVoltage, getChargeLevel(), timeRemaining);
329
                emit voltageChanged(message.sysid, state.voltage_battery/1000);
330

LM's avatar
LM committed
331
                // LOW BATTERY ALARM
332 333
                if (lpVoltage < warnVoltage)
                {
LM's avatar
LM committed
334
                    startLowBattAlarm();
335 336 337
                }
                else
                {
LM's avatar
LM committed
338 339
                    stopLowBattAlarm();
                }
340

LM's avatar
LM committed
341
                // COMMUNICATIONS DROP RATE
342 343
                // FIXME
                emit dropRateChanged(this->getUASID(), state.drop_rate_comm/10000.0f);
344
            }
LM's avatar
LM committed
345
            break;
346 347
        case MAVLINK_MSG_ID_RAW_IMU:
            {
LM's avatar
LM committed
348 349
                mavlink_raw_imu_t raw;
                mavlink_msg_raw_imu_decode(&message, &raw);
350
                quint64 time = getUnixTime(raw.time_usec);
LM's avatar
LM committed
351

lm's avatar
lm committed
352 353 354 355 356 357 358 359 360
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel x", "raw", static_cast<double>(raw.xacc), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel y", "raw", static_cast<double>(raw.yacc), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel z", "raw", static_cast<double>(raw.zacc), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro roll", "raw", static_cast<double>(raw.xgyro), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro pitch", "raw", static_cast<double>(raw.ygyro), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro yaw", "raw", static_cast<double>(raw.zgyro), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag x", "raw", static_cast<double>(raw.xmag), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag y", "raw", static_cast<double>(raw.ymag), time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag z", "raw", static_cast<double>(raw.zmag), time);
LM's avatar
LM committed
361 362
            }
            break;
363 364
        case MAVLINK_MSG_ID_SCALED_IMU:
            {
LM's avatar
LM committed
365 366
                mavlink_scaled_imu_t scaled;
                mavlink_msg_scaled_imu_decode(&message, &scaled);
367
                quint64 time = getUnixTime(scaled.time_boot_ms);
LM's avatar
LM committed
368

lm's avatar
lm committed
369 370 371 372 373 374 375 376 377
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel x", "g", scaled.xacc/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel y", "g", scaled.yacc/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "accel z", "g", scaled.zacc/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro roll", "rad/s", scaled.xgyro/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro pitch", "rad/s", scaled.ygyro/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gyro yaw", "rad/s", scaled.zgyro/1000.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag x", "uTesla", scaled.xmag/100.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag y", "uTesla", scaled.ymag/100.0f, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "mag z", "uTesla", scaled.zmag/100.0f, time);
LM's avatar
LM committed
378 379
            }
            break;
pixhawk's avatar
pixhawk committed
380
        case MAVLINK_MSG_ID_ATTITUDE:
LM's avatar
LM committed
381 382 383
            {
                mavlink_attitude_t attitude;
                mavlink_msg_attitude_decode(&message, &attitude);
384
                quint64 time = getUnixReferenceTime(attitude.time_boot_ms);
LM's avatar
LM committed
385
                lastAttitude = time;
LM's avatar
LM committed
386 387 388
                roll = QGC::limitAngleToPMPIf(attitude.roll);
                pitch = QGC::limitAngleToPMPIf(attitude.pitch);
                yaw = QGC::limitAngleToPMPIf(attitude.yaw);
lm's avatar
lm committed
389 390 391 392 393 394
                // FIXME REMOVE LATER emit valueChanged(uasId, "roll", "rad", roll, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "pitch", "rad", pitch, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "yaw", "rad", yaw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rollspeed", "rad/s", attitude.rollspeed, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "pitchspeed", "rad/s", attitude.pitchspeed, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "yawspeed", "rad/s", attitude.yawspeed, time);
LM's avatar
LM committed
395 396 397 398 399 400 401 402 403

                // Emit in angles

                // Convert yaw angle to compass value
                // in 0 - 360 deg range
                float compass = (yaw/M_PI)*180.0+360.0f;
                while (compass > 360.0f) {
                    compass -= 360.0f;
                }
lm's avatar
lm committed
404

LM's avatar
LM committed
405
                attitudeKnown = true;
lm's avatar
lm committed
406

lm's avatar
lm committed
407 408 409 410 411 412
                // FIXME REMOVE LATER emit valueChanged(uasId, "roll deg", "deg", (roll/M_PI)*180.0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "pitch deg", "deg", (pitch/M_PI)*180.0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "heading deg", "deg", compass, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rollspeed d/s", "deg/s", (attitude.rollspeed/M_PI)*180.0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "pitchspeed d/s", "deg/s", (attitude.pitchspeed/M_PI)*180.0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "yawspeed d/s", "deg/s", (attitude.yawspeed/M_PI)*180.0, time);
413

414
                emit attitudeChanged(this, roll, pitch, yaw, time);
LM's avatar
LM committed
415
                emit attitudeSpeedChanged(uasId, attitude.rollspeed, attitude.pitchspeed, attitude.yawspeed, time);
pixhawk's avatar
pixhawk committed
416
            }
LM's avatar
LM committed
417
            break;
lm's avatar
lm committed
418 419 420 421
        case MAVLINK_MSG_ID_HIL_CONTROLS:
            {
                mavlink_hil_controls_t hil;
                mavlink_msg_hil_controls_decode(&message, &hil);
422
                emit hilControlsChanged(hil.time_usec, hil.roll_ailerons, hil.pitch_elevator, hil.yaw_rudder, hil.throttle, hil.mode, hil.nav_mode);
lm's avatar
lm committed
423 424
            }
            break;
425 426
        case MAVLINK_MSG_ID_VFR_HUD:
            {
LM's avatar
LM committed
427 428 429 430
                mavlink_vfr_hud_t hud;
                mavlink_msg_vfr_hud_decode(&message, &hud);
                quint64 time = getUnixTime();
                // Display updated values
lm's avatar
lm committed
431 432 433 434 435 436
                // FIXME REMOVE LATER emit valueChanged(uasId, "airspeed", "m/s", hud.airspeed, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "groundspeed", "m/s", hud.groundspeed, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "altitude", "m", hud.alt, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "heading", "deg", hud.heading, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "climbrate", "m/s", hud.climb, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "throttle", "%", hud.throttle, time);
LM's avatar
LM committed
437 438
                emit thrustChanged(this, hud.throttle/100.0);

439 440
                if (!attitudeKnown)
                {
LM's avatar
LM committed
441 442 443
                    yaw = QGC::limitAngleToPMPId((((double)hud.heading-180.0)/360.0)*M_PI);
                    emit attitudeChanged(this, roll, pitch, yaw, time);
                }
lm's avatar
lm committed
444

LM's avatar
LM committed
445 446
                emit altitudeChanged(uasId, hud.alt);
                //yaw = (hud.heading-180.0f/360.0f)*M_PI;
LM's avatar
LM committed
447
                emit speedChanged(this, hud.airspeed, 0.0f, hud.climb, time);
LM's avatar
LM committed
448 449
            }
            break;
450 451
        case MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT:
            {
LM's avatar
LM committed
452 453 454 455
                mavlink_nav_controller_output_t nav;
                mavlink_msg_nav_controller_output_decode(&message, &nav);
                quint64 time = getUnixTime();
                // Update UI
lm's avatar
lm committed
456 457 458 459 460 461 462 463
                // FIXME REMOVE LATER emit valueChanged(uasId, "nav roll", "deg", nav.nav_roll, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "nav pitch", "deg", nav.nav_pitch, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "nav bearing", "deg", nav.nav_bearing, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "target bearing", "deg", nav.target_bearing, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "wp dist", "m", nav.wp_dist, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "alt err", "m", nav.alt_error, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "airspeed err", "m/s", nav.alt_error, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "xtrack err", "m", nav.xtrack_error, time);
LM's avatar
LM committed
464 465
            }
            break;
lm's avatar
lm committed
466
        case MAVLINK_MSG_ID_LOCAL_POSITION_NED:
lm's avatar
lm committed
467
            //std::cerr << std::endl;
pixhawk's avatar
pixhawk committed
468
            //std::cerr << "Decoded attitude message:" << " roll: " << std::dec << mavlink_msg_attitude_get_roll(message.payload) << " pitch: " << mavlink_msg_attitude_get_pitch(message.payload) << " yaw: " << mavlink_msg_attitude_get_yaw(message.payload) << std::endl;
LM's avatar
LM committed
469
            {
lm's avatar
lm committed
470 471
                mavlink_local_position_ned_t pos;
                mavlink_msg_local_position_ned_decode(&message, &pos);
472
                quint64 time = getUnixTime(pos.time_boot_ms);
LM's avatar
LM committed
473 474 475
                localX = pos.x;
                localY = pos.y;
                localZ = pos.z;
lm's avatar
lm committed
476 477 478 479 480 481
                // FIXME REMOVE LATER emit valueChanged(uasId, "x", "m", pos.x, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "y", "m", pos.y, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "z", "m", pos.z, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "x speed", "m/s", pos.vx, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "y speed", "m/s", pos.vy, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "z speed", "m/s", pos.vz, time);
LM's avatar
LM committed
482 483 484 485 486 487 488 489 490 491 492 493 494
                emit localPositionChanged(this, pos.x, pos.y, pos.z, time);
                emit speedChanged(this, pos.vx, pos.vy, pos.vz, time);

                //                qDebug()<<"Local Position = "<<pos.x<<" - "<<pos.y<<" - "<<pos.z;
                //                qDebug()<<"Speed Local Position = "<<pos.vx<<" - "<<pos.vy<<" - "<<pos.vz;

                //emit attitudeChanged(this, pos.roll, pos.pitch, pos.yaw, time);
                // Set internal state
                if (!positionLock) {
                    // If position was not locked before, notify positive
                    GAudioOutput::instance()->notifyPositive();
                }
                positionLock = true;
lm's avatar
lm committed
495
            }
LM's avatar
LM committed
496
            break;
497
        case MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
498 499
            //std::cerr << std::endl;
            //std::cerr << "Decoded attitude message:" << " roll: " << std::dec << mavlink_msg_attitude_get_roll(message.payload) << " pitch: " << mavlink_msg_attitude_get_pitch(message.payload) << " yaw: " << mavlink_msg_attitude_get_yaw(message.payload) << std::endl;
LM's avatar
LM committed
500 501 502 503 504 505 506 507 508 509
            {
                mavlink_global_position_int_t pos;
                mavlink_msg_global_position_int_decode(&message, &pos);
                quint64 time = getUnixTime();
                latitude = pos.lat/(double)1E7;
                longitude = pos.lon/(double)1E7;
                altitude = pos.alt/1000.0;
                speedX = pos.vx/100.0;
                speedY = pos.vy/100.0;
                speedZ = pos.vz/100.0;
lm's avatar
lm committed
510 511 512
                // FIXME REMOVE LATER emit valueChanged(uasId, "latitude", "deg", latitude, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "longitude", "deg", longitude, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "altitude", "m", altitude, time);
LM's avatar
LM committed
513
                double totalSpeed = sqrt(speedX*speedX + speedY*speedY + speedZ*speedZ);
lm's avatar
lm committed
514
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps speed", "m/s", totalSpeed, time);
LM's avatar
LM committed
515 516 517 518 519 520 521 522 523 524
                emit globalPositionChanged(this, latitude, longitude, altitude, time);
                emit speedChanged(this, speedX, speedY, speedZ, time);
                // Set internal state
                if (!positionLock) {
                    // If position was not locked before, notify positive
                    GAudioOutput::instance()->notifyPositive();
                }
                positionLock = true;
                //TODO fix this hack for forwarding of global position for patch antenna tracking
                forwardMessage(message);
525
            }
LM's avatar
LM committed
526
            break;
527 528
        case MAVLINK_MSG_ID_GPS_RAW_INT:
            {
LM's avatar
LM committed
529 530 531 532 533
                mavlink_gps_raw_int_t pos;
                mavlink_msg_gps_raw_int_decode(&message, &pos);

                // SANITY CHECK
                // only accept values in a realistic range
534 535
                // quint64 time = getUnixTime(pos.time_usec);
                quint64 time = getUnixTime(pos.time_usec);
LM's avatar
LM committed
536

lm's avatar
lm committed
537 538 539 540 541 542 543
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps latitude", "deg", pos.lat/(double)1E7, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps longitude", "deg", pos.lon/(double)1E7, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps speed", "m/s", pos.vel, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps eph", "m", pos.eph/(double)1E2, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps epv", "m", pos.eph/(double)1E2, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps fix", "raw", pos.fix_type, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "gps course", "raw", pos.cog, time);
LM's avatar
LM committed
544

LM's avatar
LM committed
545
                if (pos.fix_type > 2) {
LM's avatar
LM committed
546 547 548 549 550 551 552 553 554 555 556 557
                    emit globalPositionChanged(this, pos.lat/(double)1E7, pos.lon/(double)1E7, pos.alt/1000.0, time);
                    latitude = pos.lat/(double)1E7;
                    longitude = pos.lon/(double)1E7;
                    altitude = pos.alt/1000.0;
                    positionLock = true;

                    // Check for NaN
                    int alt = pos.alt;
                    if (alt != alt) {
                        alt = 0;
                        emit textMessageReceived(uasId, message.compid, 255, "GCS ERROR: RECEIVED NaN FOR ALTITUDE");
                    }
lm's avatar
lm committed
558
                    // FIXME REMOVE LATER emit valueChanged(uasId, "altitude", "m", pos.alt/(double)1E3, time);
LM's avatar
LM committed
559
                    // Smaller than threshold and not NaN
LM's avatar
LM committed
560 561 562 563

                    float vel = pos.vel/100.0f;

                    if (vel < 1000000 && !isnan(vel) && !isinf(vel)) {
lm's avatar
lm committed
564
                        // FIXME REMOVE LATER emit valueChanged(uasId, "speed", "m/s", vel, time);
LM's avatar
LM committed
565 566 567
                        //qDebug() << "GOT GPS RAW";
                        // emit speedChanged(this, (double)pos.v, 0.0, 0.0, time);
                    } else {
LM's avatar
LM committed
568
                        emit textMessageReceived(uasId, message.compid, 255, QString("GCS ERROR: RECEIVED INVALID SPEED OF %1 m/s").arg(vel));
LM's avatar
LM committed
569
                    }
lm's avatar
lm committed
570 571
                }
            }
LM's avatar
LM committed
572
            break;
573 574
        case MAVLINK_MSG_ID_GPS_STATUS:
            {
LM's avatar
LM committed
575 576
                mavlink_gps_status_t pos;
                mavlink_msg_gps_status_decode(&message, &pos);
577 578
                for(int i = 0; i < (int)pos.satellites_visible; i++)
                {
LM's avatar
LM committed
579 580
                    emit gpsSatelliteStatusChanged(uasId, (unsigned char)pos.satellite_prn[i], (unsigned char)pos.satellite_elevation[i], (unsigned char)pos.satellite_azimuth[i], (unsigned char)pos.satellite_snr[i], static_cast<bool>(pos.satellite_used[i]));
                }
581
            }
LM's avatar
LM committed
582
            break;
583
        case MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN:
584
            {
585 586
                mavlink_gps_global_origin_t pos;
                mavlink_msg_gps_global_origin_decode(&message, &pos);
LM's avatar
LM committed
587
                emit homePositionChanged(uasId, pos.latitude, pos.longitude, pos.altitude);
LM's avatar
LM committed
588 589
            }
            break;
590 591
        case MAVLINK_MSG_ID_RAW_PRESSURE:
            {
LM's avatar
LM committed
592 593
                mavlink_raw_pressure_t pressure;
                mavlink_msg_raw_pressure_decode(&message, &pressure);
594
                quint64 time = this->getUnixTime(pressure.time_usec);
lm's avatar
lm committed
595 596 597 598
                // FIXME REMOVE LATER emit valueChanged(uasId, "abs pressure", "raw", pressure.press_abs, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "diff pressure 1", "raw", pressure.press_diff1, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "diff pressure 2", "raw", pressure.press_diff2, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "temperature", "raw", pressure.temperature, time);
LM's avatar
LM committed
599 600
            }
            break;
601

602 603
        case MAVLINK_MSG_ID_SCALED_PRESSURE:
            {
LM's avatar
LM committed
604 605
                mavlink_scaled_pressure_t pressure;
                mavlink_msg_scaled_pressure_decode(&message, &pressure);
606
                quint64 time = this->getUnixTime(pressure.time_boot_ms);
lm's avatar
lm committed
607 608 609
                // FIXME REMOVE LATER emit valueChanged(uasId, "abs pressure", "hPa", pressure.press_abs, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "diff pressure", "hPa", pressure.press_diff, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "temperature", "C", pressure.temperature/100.0, time);
LM's avatar
LM committed
610 611
            }
            break;
612

613 614
        case MAVLINK_MSG_ID_RC_CHANNELS_RAW:
            {
LM's avatar
LM committed
615 616 617 618 619 620 621 622 623 624 625
                mavlink_rc_channels_raw_t channels;
                mavlink_msg_rc_channels_raw_decode(&message, &channels);
                emit remoteControlRSSIChanged(channels.rssi/255.0f);
                emit remoteControlChannelRawChanged(0, channels.chan1_raw);
                emit remoteControlChannelRawChanged(1, channels.chan2_raw);
                emit remoteControlChannelRawChanged(2, channels.chan3_raw);
                emit remoteControlChannelRawChanged(3, channels.chan4_raw);
                emit remoteControlChannelRawChanged(4, channels.chan5_raw);
                emit remoteControlChannelRawChanged(5, channels.chan6_raw);
                emit remoteControlChannelRawChanged(6, channels.chan7_raw);
                emit remoteControlChannelRawChanged(7, channels.chan8_raw);
626
                quint64 time = getUnixTime();
lm's avatar
lm committed
627 628 629 630 631 632 633 634
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #1", "us", channels.chan1_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #2", "us", channels.chan2_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #3", "us", channels.chan3_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #4", "us", channels.chan4_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #5", "us", channels.chan5_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #6", "us", channels.chan6_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #7", "us", channels.chan7_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "rc in #8", "us", channels.chan8_raw, time);
LM's avatar
LM committed
635 636
            }
            break;
637 638
        case MAVLINK_MSG_ID_RC_CHANNELS_SCALED:
            {
LM's avatar
LM committed
639 640 641 642 643 644 645 646 647 648 649
                mavlink_rc_channels_scaled_t channels;
                mavlink_msg_rc_channels_scaled_decode(&message, &channels);
                emit remoteControlRSSIChanged(channels.rssi/255.0f);
                emit remoteControlChannelScaledChanged(0, channels.chan1_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(1, channels.chan2_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(2, channels.chan3_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(3, channels.chan4_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(4, channels.chan5_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(5, channels.chan6_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(6, channels.chan7_scaled/10000.0f);
                emit remoteControlChannelScaledChanged(7, channels.chan8_scaled/10000.0f);
lm's avatar
lm committed
650
            }
LM's avatar
LM committed
651
            break;
652 653
        case MAVLINK_MSG_ID_PARAM_VALUE:
            {
LM's avatar
LM committed
654 655 656 657 658
                mavlink_param_value_t value;
                mavlink_msg_param_value_decode(&message, &value);
                QByteArray bytes((char*)value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
                QString parameterName = QString(bytes);
                int component = message.compid;
659 660
                mavlink_param_union_t val;
                val.param_float = value.param_value;
661
                val.type = value.param_type;
662 663 664 665 666 667 668 669

                // Convert to machine order if necessary
//#if MAVLINK_NEED_BYTE_SWAP
//   buffer[bindex]   = (b>>24)&0xff;
//   buffer[bindex+1] = (b>>16)&0xff;
//   buffer[bindex+2] = (b>>8)&0xff;
//   buffer[bindex+3] = (b & 0xff);
//#else
LM's avatar
LM committed
670 671

                // Insert component if necessary
672 673
                if (!parameters.contains(component))
                {
674
                    parameters.insert(component, new QMap<QString, QVariant>());
LM's avatar
LM committed
675
                }
676

LM's avatar
LM committed
677 678
                // Insert parameter into registry
                if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName);
679

680 681 682
                // Insert with correct type
                switch (value.param_type)
                {
683
                case MAVLINK_TYPE_FLOAT:
684 685 686 687
                    {
                    // Variant
                    QVariant param(val.param_float);
                    parameters.value(component)->insert(parameterName, param);
688
                    // Emit change
689 690 691 692
                    emit parameterChanged(uasId, message.compid, parameterName, param);
                    emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param);
                    qDebug() << "RECEIVED PARAM:" << param;
                }
693
                    break;
694
                case MAVLINK_TYPE_UINT32_T:
695 696 697 698
                    {
                    // Variant
                    QVariant param(val.param_uint32);
                    parameters.value(component)->insert(parameterName, param);
699
                    // Emit change
700 701 702 703
                    emit parameterChanged(uasId, message.compid, parameterName, param);
                    emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param);
                    qDebug() << "RECEIVED PARAM:" << param;
                }
704
                    break;
705
                case MAVLINK_TYPE_INT32_T:
706 707 708 709
                    {
                    // Variant
                    QVariant param(val.param_int32);
                    parameters.value(component)->insert(parameterName, param);
710
                    // Emit change
711 712 713 714
                    emit parameterChanged(uasId, message.compid, parameterName, param);
                    emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param);
                    qDebug() << "RECEIVED PARAM:" << param;
                }
715 716 717 718
                    break;
                default:
                    qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << value.param_type;
                }
LM's avatar
LM committed
719 720
            }
            break;
721 722 723
        case MAVLINK_MSG_ID_COMMAND_ACK:
            mavlink_command_ack_t ack;
            mavlink_msg_command_ack_decode(&message, &ack);
724 725
            if (ack.result == 1)
            {
726
                emit textMessageReceived(uasId, message.compid, 0, tr("SUCCESS: Executed CMD: %1").arg(ack.command));
727 728 729
            }
            else
            {
730
                emit textMessageReceived(uasId, message.compid, 0, tr("FAILURE: Rejected CMD: %1").arg(ack.command));
731 732
            }
            break;
pixhawk's avatar
pixhawk committed
733
        case MAVLINK_MSG_ID_DEBUG:
lm's avatar
lm committed
734
            // FIXME REMOVE LATER emit valueChanged(uasId, QString("debug ") + QString::number(mavlink_msg_debug_get_ind(&message)), "raw", mavlink_msg_debug_get_value(&message), MG::TIME::getGroundTimeNow());
pixhawk's avatar
pixhawk committed
735
            break;
LM's avatar
LM committed
736
        case MAVLINK_MSG_ID_ROLL_PITCH_YAW_THRUST_SETPOINT:
737
            {
LM's avatar
LM committed
738 739
                mavlink_roll_pitch_yaw_thrust_setpoint_t out;
                mavlink_msg_roll_pitch_yaw_thrust_setpoint_decode(&message, &out);
740
                quint64 time = getUnixTimeFromMs(out.time_boot_ms);
LM's avatar
LM committed
741
                emit attitudeThrustSetPointChanged(this, out.roll, out.pitch, out.yaw, out.thrust, time);
lm's avatar
lm committed
742 743 744 745
                // FIXME REMOVE LATER emit valueChanged(uasId, "att control roll", "rad", out.roll, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "att control pitch", "rad", out.pitch, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "att control yaw", "rad", out.yaw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "att control thrust", "0-1", out.thrust, time);
LM's avatar
LM committed
746 747
            }
            break;
lm's avatar
lm committed
748
        case MAVLINK_MSG_ID_MISSION_COUNT:
749
            {
lm's avatar
lm committed
750 751
                mavlink_mission_count_t wpc;
                mavlink_msg_mission_count_decode(&message, &wpc);
752 753
                if (wpc.target_system == mavlink->getSystemId() && wpc.target_component == mavlink->getComponentId())
                {
LM's avatar
LM committed
754 755
                    waypointManager.handleWaypointCount(message.sysid, message.compid, wpc.count);
                }
LM's avatar
LM committed
756 757 758 759
                else
                {
                    qDebug() << "Got waypoint message, but was not for me";
                }
pixhawk's avatar
pixhawk committed
760
            }
LM's avatar
LM committed
761
            break;
pixhawk's avatar
pixhawk committed
762

lm's avatar
lm committed
763
        case MAVLINK_MSG_ID_MISSION_ITEM:
764
            {
lm's avatar
lm committed
765 766
                mavlink_mission_item_t wp;
                mavlink_msg_mission_item_decode(&message, &wp);
LM's avatar
LM committed
767
                //qDebug() << "got waypoint (" << wp.seq << ") from ID " << message.sysid << " x=" << wp.x << " y=" << wp.y << " z=" << wp.z;
768 769
                if(wp.target_system == mavlink->getSystemId() && wp.target_component == mavlink->getComponentId())
                {
LM's avatar
LM committed
770 771
                    waypointManager.handleWaypoint(message.sysid, message.compid, &wp);
                }
LM's avatar
LM committed
772 773 774 775
                else
                {
                    qDebug() << "Got waypoint message, but was not for me";
                }
776
            }
LM's avatar
LM committed
777
            break;
pixhawk's avatar
pixhawk committed
778

lm's avatar
lm committed
779
        case MAVLINK_MSG_ID_MISSION_ACK:
780
            {
lm's avatar
lm committed
781 782
                mavlink_mission_ack_t wpa;
                mavlink_msg_mission_ack_decode(&message, &wpa);
783 784
                if(wpa.target_system == mavlink->getSystemId() && wpa.target_component == mavlink->getComponentId())
                {
LM's avatar
LM committed
785 786
                    waypointManager.handleWaypointAck(message.sysid, message.compid, &wpa);
                }
787
            }
LM's avatar
LM committed
788
            break;
789

lm's avatar
lm committed
790
        case MAVLINK_MSG_ID_MISSION_REQUEST:
791
            {
lm's avatar
lm committed
792 793
                mavlink_mission_request_t wpr;
                mavlink_msg_mission_request_decode(&message, &wpr);
794 795
                if(wpr.target_system == mavlink->getSystemId() && wpr.target_component == mavlink->getComponentId())
                {
LM's avatar
LM committed
796 797
                    waypointManager.handleWaypointRequest(message.sysid, message.compid, &wpr);
                }
LM's avatar
LM committed
798 799 800 801
                else
                {
                    qDebug() << "Got waypoint message, but was not for me";
                }
pixhawk's avatar
pixhawk committed
802
            }
LM's avatar
LM committed
803
            break;
pixhawk's avatar
pixhawk committed
804

lm's avatar
lm committed
805
        case MAVLINK_MSG_ID_MISSION_ITEM_REACHED:
806
            {
lm's avatar
lm committed
807 808
                mavlink_mission_item_reached_t wpr;
                mavlink_msg_mission_item_reached_decode(&message, &wpr);
LM's avatar
LM committed
809 810 811 812 813 814
                waypointManager.handleWaypointReached(message.sysid, message.compid, &wpr);
                QString text = QString("System %1 reached waypoint %2").arg(getUASName()).arg(wpr.seq);
                GAudioOutput::instance()->say(text);
                emit textMessageReceived(message.sysid, message.compid, 0, text);
            }
            break;
pixhawk's avatar
pixhawk committed
815

lm's avatar
lm committed
816
        case MAVLINK_MSG_ID_MISSION_CURRENT:
817
            {
lm's avatar
lm committed
818 819
                mavlink_mission_current_t wpc;
                mavlink_msg_mission_current_decode(&message, &wpc);
LM's avatar
LM committed
820 821 822
                waypointManager.handleWaypointCurrent(message.sysid, message.compid, &wpc);
            }
            break;
pixhawk's avatar
pixhawk committed
823

824 825
        case MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT:
            {
LM's avatar
LM committed
826 827 828 829 830
                mavlink_local_position_setpoint_t p;
                mavlink_msg_local_position_setpoint_decode(&message, &p);
                emit positionSetPointsChanged(uasId, p.x, p.y, p.z, p.yaw, QGC::groundTimeUsecs());
            }
            break;
831 832
        case MAVLINK_MSG_ID_SERVO_OUTPUT_RAW:
            {
LM's avatar
LM committed
833 834 835
                mavlink_servo_output_raw_t servos;
                mavlink_msg_servo_output_raw_decode(&message, &servos);
                quint64 time = getUnixTime();
lm's avatar
lm committed
836 837 838 839 840 841 842 843
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #1", "us", servos.servo1_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #2", "us", servos.servo2_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #3", "us", servos.servo3_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #4", "us", servos.servo4_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #5", "us", servos.servo5_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #6", "us", servos.servo6_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #7", "us", servos.servo7_raw, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "servo #8", "us", servos.servo8_raw, time);
LM's avatar
LM committed
844 845
            }
            break;
846 847 848 849 850

        case MAVLINK_MSG_ID_OPTICAL_FLOW:
            {
                mavlink_optical_flow_t flow;
                mavlink_msg_optical_flow_decode(&message, &flow);
lm's avatar
lm committed
851
                quint64 time = getUnixTime(flow.time_usec);
852

lm's avatar
lm committed
853 854 855 856
                // FIXME REMOVE LATER emit valueChanged(uasId, QString("opt_flow_%1.x").arg(flow.sensor_id), "Pixel", flow.flow_x, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, QString("opt_flow_%1.y").arg(flow.sensor_id), "Pixel", flow.flow_y, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, QString("opt_flow_%1.qual").arg(flow.sensor_id), "0-255", flow.quality, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, QString("opt_flow_%1.dist").arg(flow.sensor_id), "m", flow.ground_distance, time);
857 858
            }
            break;
859 860
        case MAVLINK_MSG_ID_STATUSTEXT:
            {
LM's avatar
LM committed
861 862
                QByteArray b;
                b.resize(MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN);
lm's avatar
lm committed
863
                mavlink_msg_statustext_get_text(&message, b.data());
LM's avatar
LM committed
864 865 866 867 868 869 870 871
                //b.append('\0');
                QString text = QString(b);
                int severity = mavlink_msg_statustext_get_severity(&message);
                //qDebug() << "RECEIVED STATUS:" << text;false
                //emit statusTextReceived(severity, text);
                emit textMessageReceived(uasId, message.compid, severity, text);
            }
            break;
872
#ifdef MAVLINK_ENABLED_PIXHAWK
873 874
        case MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE:
            {
LM's avatar
LM committed
875 876 877 878 879 880 881 882 883 884 885
                qDebug() << "RECIEVED ACK TO GET IMAGE";
                mavlink_data_transmission_handshake_t p;
                mavlink_msg_data_transmission_handshake_decode(&message, &p);
                imageSize = p.size;
                imagePackets = p.packets;
                imagePayload = p.payload;
                imageQuality = p.jpg_quality;
                imageType = p.type;
                imageStart = QGC::groundTimeMilliseconds();
            }
            break;
886

887 888
        case MAVLINK_MSG_ID_ENCAPSULATED_DATA:
            {
LM's avatar
LM committed
889 890 891 892 893 894 895 896 897 898 899
                mavlink_encapsulated_data_t img;
                mavlink_msg_encapsulated_data_decode(&message, &img);
                int seq = img.seqnr;
                int pos = seq * imagePayload;

                // Check if we have a valid transaction
                if (imagePackets == 0)
                {
                    // NO VALID TRANSACTION - ABORT
                    // Restart statemachine
                    imagePacketsArrived = 0;
900 901
                }

902 903
                for (int i = 0; i < imagePayload; ++i)
                {
LM's avatar
LM committed
904 905 906 907 908
                    if (pos <= imageSize) {
                        imageRecBuffer[pos] = img.data[i];
                    }
                    ++pos;
                }
909

LM's avatar
LM committed
910
                ++imagePacketsArrived;
911

LM's avatar
LM committed
912 913 914 915 916 917 918 919
                // emit signal if all packets arrived
                if ((imagePacketsArrived >= imagePackets))
                {
                    // Restart statemachine
                    imagePacketsArrived = 0;
                    emit imageReady(this);
                    qDebug() << "imageReady emitted. all packets arrived";
                }
920
            }
LM's avatar
LM committed
921
            break;
922
#endif
923
        case MAVLINK_MSG_ID_DEBUG_VECT:
924 925 926 927
        {
            mavlink_debug_vect_t vect;
            mavlink_msg_debug_vect_decode(&message, &vect);
            QString str((const char*)vect.name);
928
            quint64 time = getUnixTime(vect.time_usec);
lm's avatar
lm committed
929 930 931
            // FIXME REMOVE LATER emit valueChanged(uasId, str+".x", "raw", vect.x, time);
            // FIXME REMOVE LATER emit valueChanged(uasId, str+".y", "raw", vect.y, time);
            // FIXME REMOVE LATER emit valueChanged(uasId, str+".z", "raw", vect.z, time);
LM's avatar
LM committed
932 933
        }
        break;
lm's avatar
lm committed
934 935 936 937 938 939 940 941
//        case MAVLINK_MSG_ID_OBJECT_DETECTION_EVENT:
//        {
//            mavlink_object_detection_event_t event;
//            mavlink_msg_object_detection_event_decode(&message, &event);
//            QString str(event.name);
//            emit objectDetected(event.time, event.object_id, event.type, str, event.quality, event.bearing, event.distance);
//        }
//        break;
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
        // WILL BE ENABLED ONCE MESSAGE IS IN COMMON MESSAGE SET
//        case MAVLINK_MSG_ID_MEMORY_VECT:
//        {
//            mavlink_memory_vect_t vect;
//            mavlink_msg_memory_vect_decode(&message, &vect);
//            QString str("mem_%1");
//            quint64 time = getUnixTime(0);
//            int16_t *mem0 = (int16_t *)&vect.value[0];
//            uint16_t *mem1 = (uint16_t *)&vect.value[0];
//            int32_t *mem2 = (int32_t *)&vect.value[0];
//            // uint32_t *mem3 = (uint32_t *)&vect.value[0]; causes overload problem
//            float *mem4 = (float *)&vect.value[0];
//            if ( vect.ver == 0) vect.type = 0, vect.ver = 1; else ;
//            if ( vect.ver == 1)
//            {
//                switch (vect.type) {
//                default:
//                case 0:
//                    for (int i = 0; i < 16; i++)
lm's avatar
lm committed
961
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "i16", mem0[i], time);
962 963 964
//                    break;
//                case 1:
//                    for (int i = 0; i < 16; i++)
lm's avatar
lm committed
965
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "ui16", mem1[i], time);
966 967 968
//                    break;
//                case 2:
//                    for (int i = 0; i < 16; i++)
lm's avatar
lm committed
969
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "Q15", (float)mem0[i]/32767.0, time);
970 971 972
//                    break;
//                case 3:
//                    for (int i = 0; i < 16; i++)
lm's avatar
lm committed
973
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "1Q14", (float)mem0[i]/16383.0, time);
974 975 976
//                    break;
//                case 4:
//                    for (int i = 0; i < 8; i++)
lm's avatar
lm committed
977
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time);
978 979 980
//                    break;
//                case 5:
//                    for (int i = 0; i < 8; i++)
lm's avatar
lm committed
981
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time);
982 983 984
//                    break;
//                case 6:
//                    for (int i = 0; i < 8; i++)
lm's avatar
lm committed
985
//                        // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "float", mem4[i], time);
986 987 988 989 990
//                    break;
//                }
//            }
//        }
//        break;
lm's avatar
lm committed
991
#ifdef MAVLINK_ENABLED_UALBERTA
992 993
        case MAVLINK_MSG_ID_NAV_FILTER_BIAS:
            {
LM's avatar
LM committed
994 995 996
                mavlink_nav_filter_bias_t bias;
                mavlink_msg_nav_filter_bias_decode(&message, &bias);
                quint64 time = getUnixTime();
lm's avatar
lm committed
997 998 999 1000 1001 1002
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[0]", "raw", bias.accel_0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[1]", "raw", bias.accel_1, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[2]", "raw", bias.accel_2, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[0]", "raw", bias.gyro_0, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[1]", "raw", bias.gyro_1, time);
                // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[2]", "raw", bias.gyro_2, time);
LM's avatar
LM committed
1003 1004
            }
            break;
1005 1006
        case MAVLINK_MSG_ID_RADIO_CALIBRATION:
            {
LM's avatar
LM committed
1007 1008
                mavlink_radio_calibration_t radioMsg;
                mavlink_msg_radio_calibration_decode(&message, &radioMsg);
1009 1010 1011 1012 1013 1014
                QVector<uint16_t> aileron;
                QVector<uint16_t> elevator;
                QVector<uint16_t> rudder;
                QVector<uint16_t> gyro;
                QVector<uint16_t> pitch;
                QVector<uint16_t> throttle;
LM's avatar
LM committed
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033

                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_AILERON_LEN; ++i)
                    aileron << radioMsg.aileron[i];
                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_ELEVATOR_LEN; ++i)
                    elevator << radioMsg.elevator[i];
                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_RUDDER_LEN; ++i)
                    rudder << radioMsg.rudder[i];
                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_GYRO_LEN; ++i)
                    gyro << radioMsg.gyro[i];
                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_PITCH_LEN; ++i)
                    pitch << radioMsg.pitch[i];
                for (int i=0; i<MAVLINK_MSG_RADIO_CALIBRATION_FIELD_THROTTLE_LEN; ++i)
                    throttle << radioMsg.throttle[i];

                QPointer<RadioCalibrationData> radioData = new RadioCalibrationData(aileron, elevator, rudder, gyro, pitch, throttle);
                emit radioCalibrationReceived(radioData);
                delete radioData;
            }
            break;
1034

1035
#endif
LM's avatar
LM committed
1036
            // Messages to ignore
1037
        case MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT:
1038
            break;
1039 1040 1041 1042
        default:
            {
                if (!unknownPackets.contains(message.msgid))
                {
LM's avatar
LM committed
1043 1044 1045 1046 1047 1048 1049
                    unknownPackets.append(message.msgid);
                    QString errString = tr("UNABLE TO DECODE MESSAGE NUMBER %1").arg(message.msgid);
                    GAudioOutput::instance()->say(errString+tr(", please check console for details."));
                    emit textMessageReceived(uasId, message.compid, 255, errString);
                    std::cout << "Unable to decode message from system " << std::dec << static_cast<int>(message.sysid) << " with message id:" << static_cast<int>(message.msgid) << std::endl;
                    //qDebug() << std::cerr << "Unable to decode message from system " << std::dec << static_cast<int>(message.acid) << " with message id:" << static_cast<int>(message.msgid) << std::endl;
                }
lm's avatar
lm committed
1050
            }
LM's avatar
LM committed
1051
            break;
pixhawk's avatar
pixhawk committed
1052 1053 1054 1055
        }
    }
}

1056 1057 1058
void UAS::setHomePosition(double lat, double lon, double alt)
{
    // Send new home position to UAS
1059
    mavlink_set_gps_global_origin_t home;
1060 1061 1062 1063
    home.target_system = uasId;
    home.latitude = lat*1E7;
    home.longitude = lon*1E7;
    home.altitude = alt*1000;
1064
    qDebug() << "lat:" << home.latitude << " lon:" << home.longitude;
1065
    mavlink_message_t msg;
1066
    mavlink_msg_set_gps_global_origin_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &home);
1067 1068 1069
    sendMessage(msg);
}

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
void UAS::setLocalOriginAtCurrentGPSPosition()
{
    bool result = false;
    QMessageBox msgBox;
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setText("Setting new World Coordinate Frame Origin");
    msgBox.setInformativeText("Do you want to set a new origin? Waypoints defined in the local frame will be shifted in their physical location");
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Cancel);
    int ret = msgBox.exec();

    // Close the message box shortly after the click to prevent accidental clicks
    QTimer::singleShot(5000, &msgBox, SLOT(reject()));


1085 1086
    if (ret == QMessageBox::Yes)
    {
lm's avatar
lm committed
1087 1088 1089 1090 1091 1092 1093 1094 1095
        // FIXME MAVLINKV10PORTINGNEEDED
//        mavlink_message_t msg;
//        mavlink_msg_action_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), 0, MAV_ACTION_SET_ORIGIN);
//        // Send message twice to increase chance that it reaches its goal
//        sendMessage(msg);
//        // Wait 5 ms
//        MG::SLEEP::usleep(5000);
//        // Send again
//        sendMessage(msg);
1096 1097 1098 1099
        result = true;
    }
}

pixhawk's avatar
pixhawk committed
1100 1101
void UAS::setLocalPositionSetpoint(float x, float y, float z, float yaw)
{
1102
#ifdef MAVLINK_ENABLED_PIXHAWK
pixhawk's avatar
pixhawk committed
1103
    mavlink_message_t msg;
pixhawk's avatar
pixhawk committed
1104 1105
    mavlink_msg_position_control_setpoint_set_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, 0, x, y, z, yaw);
    sendMessage(msg);
1106
#else
lm's avatar
lm committed
1107 1108 1109 1110
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(z);
    Q_UNUSED(yaw);
1111
#endif
pixhawk's avatar
pixhawk committed
1112 1113
}

pixhawk's avatar
pixhawk committed
1114 1115
void UAS::setLocalPositionOffset(float x, float y, float z, float yaw)
{
lm's avatar
lm committed
1116
#ifdef MAVLINK_ENABLED_PIXHAWK
1117 1118 1119
    mavlink_message_t msg;
    mavlink_msg_position_control_offset_set_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, x, y, z, yaw);
    sendMessage(msg);
lm's avatar
lm committed
1120
#else
1121 1122 1123 1124
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(z);
    Q_UNUSED(yaw);
pixhawk's avatar
pixhawk committed
1125 1126 1127 1128
#endif
}

void UAS::startRadioControlCalibration()
lm's avatar
lm committed
1129
{
1130 1131
    mavlink_message_t msg;
    // Param 1: gyro cal, param 2: mag cal, param 3: pressure cal, Param 4: radio
1132
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, MAV_COMP_ID_IMU, MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0, 0, 0, 1);
1133
    sendMessage(msg);
lm's avatar
lm committed
1134 1135
}

1136
void UAS::startDataRecording()
lm's avatar
lm committed
1137
{
1138
    mavlink_message_t msg;
1139
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, MAV_CMD_DO_CONTROL_VIDEO, 1, -1, -1, -1, 2);
1140
    sendMessage(msg);
lm's avatar
lm committed
1141 1142 1143 1144
}

void UAS::stopDataRecording()
{
1145
    mavlink_message_t msg;
1146
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, MAV_CMD_DO_CONTROL_VIDEO, 1, -1, -1, -1, 0);
1147
    sendMessage(msg);
lm's avatar
lm committed
1148 1149
}

pixhawk's avatar
pixhawk committed
1150 1151
void UAS::startMagnetometerCalibration()
{
1152 1153
    mavlink_message_t msg;
    // Param 1: gyro cal, param 2: mag cal, param 3: pressure cal, Param 4: radio
1154
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, MAV_COMP_ID_IMU, MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0, 1, 0, 0);
1155
    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1156 1157 1158 1159
}

void UAS::startGyroscopeCalibration()
{
1160 1161
    mavlink_message_t msg;
    // Param 1: gyro cal, param 2: mag cal, param 3: pressure cal, Param 4: radio
1162
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, MAV_COMP_ID_IMU, MAV_CMD_PREFLIGHT_CALIBRATION, 1, 1, 0, 0, 0);
1163
    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1164 1165 1166 1167
}

void UAS::startPressureCalibration()
{
1168 1169
    mavlink_message_t msg;
    // Param 1: gyro cal, param 2: mag cal, param 3: pressure cal, Param 4: radio
1170
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, MAV_COMP_ID_IMU, MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0, 0, 1, 0);
1171
    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1172 1173
}

LM's avatar
LM committed
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
quint64 UAS::getUnixReferenceTime(quint64 time)
{
    // Same as getUnixTime, but does not react to attitudeStamped mode
    if (time == 0)
    {
        //        qDebug() << "XNEW time:" <<QGC::groundTimeMilliseconds();
        return QGC::groundTimeMilliseconds();
    }
    // Check if time is smaller than 40 years,
    // assuming no system without Unix timestamp
    // runs longer than 40 years continuously without
    // reboot. In worst case this will add/subtract the
    // communication delay between GCS and MAV,
    // it will never alter the timestamp in a safety
    // critical way.
    //
    // Calculation:
    // 40 years
    // 365 days
    // 24 hours
    // 60 minutes
    // 60 seconds
    // 1000 milliseconds
    // 1000 microseconds
#ifndef _MSC_VER
    else if (time < 1261440000000000LLU)
#else
        else if (time < 1261440000000000)
#endif
        {
        //        qDebug() << "GEN time:" << time/1000 + onboardTimeOffset;
        if (onboardTimeOffset == 0)
        {
            onboardTimeOffset = QGC::groundTimeMilliseconds() - time/1000;
        }
        return time/1000 + onboardTimeOffset;
    }
    else
    {
        // Time is not zero and larger than 40 years -> has to be
        // a Unix epoch timestamp. Do nothing.
        return time/1000;
    }
}

1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
/**
 * @warning If attitudeStamped is enabled, this function will not actually return the precise time stamp
 *          of this measurement augmented to UNIX time, but will MOVE the timestamp IN TIME to match
 *          the last measured attitude. There is no reason why one would want this, except for
 *          system setups where the onboard clock is not present or broken and datasets should
 *          be collected that are still roughly synchronized. PLEASE NOTE THAT ENABLING ATTITUDE STAMPED
 *          RUINS THE SCIENTIFIC NATURE OF THE CORRECT LOGGING FUNCTIONS OF QGROUNDCONTROL!
 */
quint64 UAS::getUnixTimeFromMs(quint64 time)
{
    return getUnixTime(time*1000);
}

LM's avatar
LM committed
1232 1233 1234 1235 1236 1237 1238 1239
/**
 * @warning If attitudeStamped is enabled, this function will not actually return the precise time stamp
 *          of this measurement augmented to UNIX time, but will MOVE the timestamp IN TIME to match
 *          the last measured attitude. There is no reason why one would want this, except for
 *          system setups where the onboard clock is not present or broken and datasets should
 *          be collected that are still roughly synchronized. PLEASE NOTE THAT ENABLING ATTITUDE STAMPED
 *          RUINS THE SCIENTIFIC NATURE OF THE CORRECT LOGGING FUNCTIONS OF QGROUNDCONTROL!
 */
1240 1241
quint64 UAS::getUnixTime(quint64 time)
{
LM's avatar
LM committed
1242 1243 1244 1245
    if (attitudeStamped)
    {
        return lastAttitude;
    }
1246 1247
    if (time == 0)
    {
LM's avatar
LM committed
1248
        //        qDebug() << "XNEW time:" <<QGC::groundTimeMilliseconds();
LM's avatar
LM committed
1249
        return QGC::groundTimeMilliseconds();
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
    }
    // Check if time is smaller than 40 years,
    // assuming no system without Unix timestamp
    // runs longer than 40 years continuously without
    // reboot. In worst case this will add/subtract the
    // communication delay between GCS and MAV,
    // it will never alter the timestamp in a safety
    // critical way.
    //
    // Calculation:
    // 40 years
    // 365 days
    // 24 hours
    // 60 minutes
    // 60 seconds
    // 1000 milliseconds
    // 1000 microseconds
1267
#ifndef _MSC_VER
1268
    else if (time < 1261440000000000LLU)
1269
#else
LM's avatar
LM committed
1270
        else if (time < 1261440000000000)
1271
#endif
LM's avatar
LM committed
1272 1273
        {
        //        qDebug() << "GEN time:" << time/1000 + onboardTimeOffset;
1274 1275
        if (onboardTimeOffset == 0)
        {
LM's avatar
LM committed
1276
            onboardTimeOffset = QGC::groundTimeMilliseconds() - time/1000;
1277
        }
1278
        return time/1000 + onboardTimeOffset;
1279 1280 1281
    }
    else
    {
1282 1283
        // Time is not zero and larger than 40 years -> has to be
        // a Unix epoch timestamp. Do nothing.
1284
        return time/1000;
1285 1286 1287
    }
}

1288 1289
QList<QString> UAS::getParameterNames(int component)
{
1290 1291
    if (parameters.contains(component))
    {
1292
        return parameters.value(component)->keys();
1293 1294 1295
    }
    else
    {
1296 1297 1298 1299 1300 1301 1302 1303 1304
        return QList<QString>();
    }
}

QList<int> UAS::getComponentIds()
{
    return parameters.keys();
}

pixhawk's avatar
pixhawk committed
1305
void UAS::setMode(int mode)
pixhawk's avatar
pixhawk committed
1306
{
1307
    if (mode >= (int)MAV_MODE_PREFLIGHT && mode < (int)MAV_MODE_ENUM_END)
1308
    {
1309
        //this->mode = mode; //no call assignament, update receive message from UAS
pixhawk's avatar
pixhawk committed
1310
        mavlink_message_t msg;
1311
        mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, (uint8_t)uasId, (uint8_t)mode, (uint16_t)navMode);
pixhawk's avatar
pixhawk committed
1312
        sendMessage(msg);
lm's avatar
lm committed
1313
        qDebug() << "SENDING REQUEST TO SET MODE TO SYSTEM" << uasId << ", REQUEST TO SET MODE " << (uint8_t)mode;
1314 1315 1316
    }
    else
    {
1317 1318
        qDebug() << "uas Mode not assign: " << mode;
    }
pixhawk's avatar
pixhawk committed
1319 1320 1321 1322 1323
}

void UAS::sendMessage(mavlink_message_t message)
{
    // Emit message on all links that are currently connected
1324 1325 1326 1327
    foreach (LinkInterface* link, *links)
    {
        if (link)
        {
1328
            sendMessage(link, message);
1329 1330 1331
        }
        else
        {
1332 1333 1334
            // Remove from list
            links->removeAt(links->indexOf(link));
        }
pixhawk's avatar
pixhawk committed
1335 1336 1337
    }
}

1338 1339 1340 1341
void UAS::forwardMessage(mavlink_message_t message)
{
    // Emit message on all links that are currently connected
    QList<LinkInterface*>link_list = LinkManager::instance()->getLinksForProtocol(mavlink);
1342

1343 1344 1345 1346
    foreach(LinkInterface* link, link_list)
    {
        if (link)
        {
1347
            SerialLink* serial = dynamic_cast<SerialLink*>(link);
1348 1349 1350 1351 1352 1353
            if(serial != 0)
            {
                for(int i=0; i<links->size(); i++)
                {
                    if(serial != links->at(i))
                    {
1354
                        qDebug()<<"Antenna tracking: Forwarding Over link: "<<serial->getName()<<" "<<serial;
1355 1356
                        sendMessage(serial, message);
                    }
1357 1358 1359 1360 1361 1362
                }
            }
        }
    }
}

pixhawk's avatar
pixhawk committed
1363 1364
void UAS::sendMessage(LinkInterface* link, mavlink_message_t message)
{
1365
    if(!link) return;
pixhawk's avatar
pixhawk committed
1366 1367 1368
    // Create buffer
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
    // Write message into buffer, prepending start sign
pixhawk's avatar
pixhawk committed
1369
    int len = mavlink_msg_to_send_buffer(buffer, &message);
lm's avatar
lm committed
1370 1371
    static uint8_t messageKeys[256] = MAVLINK_MESSAGE_CRCS;
    mavlink_finalize_message_chan(&message, mavlink->getSystemId(), mavlink->getComponentId(), link->getId(), message.len, messageKeys[message.msgid]);
pixhawk's avatar
pixhawk committed
1372
    // If link is connected
1373 1374
    if (link->isConnected())
    {
pixhawk's avatar
pixhawk committed
1375 1376 1377 1378 1379 1380 1381 1382
        // Send the portion of the buffer now occupied by the message
        link->writeBytes((const char*)buffer, len);
    }
}

/**
 * @param value battery voltage
 */
1383
float UAS::filterVoltage(float value) const
pixhawk's avatar
pixhawk committed
1384
{
1385
    return lpVoltage * 0.7f + value * 0.3f;
pixhawk's avatar
pixhawk committed
1386 1387
}

1388 1389
QString UAS::getNavModeText(int mode)
{
lm's avatar
lm committed
1390 1391
    if (autopilot == MAV_AUTOPILOT_PIXHAWK)
    {
1392 1393
    switch (mode)
    {
lm's avatar
lm committed
1394
    case 0:
1395
        return QString("PREFLIGHT");
1396 1397 1398 1399
        break;
    default:
        return QString("UNKNOWN");
    }
lm's avatar
lm committed
1400 1401 1402 1403 1404 1405 1406 1407 1408
    }
    else if (autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA)
    {
        return QString("UNKNOWN");
    }
    else if (autopilot == MAV_AUTOPILOT_OPENPILOT)
    {
        return QString("UNKNOWN");
    }
1409 1410
}

pixhawk's avatar
pixhawk committed
1411 1412
void UAS::getStatusForCode(int statusCode, QString& uasState, QString& stateDescription)
{
1413 1414
    switch (statusCode)
    {
lm's avatar
lm committed
1415
    case MAV_STATE_UNINIT:
pixhawk's avatar
pixhawk committed
1416
        uasState = tr("UNINIT");
1417
        stateDescription = tr("Unitialized, booting up.");
pixhawk's avatar
pixhawk committed
1418
        break;
lm's avatar
lm committed
1419
    case MAV_STATE_BOOT:
pixhawk's avatar
pixhawk committed
1420
        uasState = tr("BOOT");
1421
        stateDescription = tr("Booting system, please wait.");
pixhawk's avatar
pixhawk committed
1422
        break;
lm's avatar
lm committed
1423
    case MAV_STATE_CALIBRATING:
pixhawk's avatar
pixhawk committed
1424
        uasState = tr("CALIBRATING");
1425
        stateDescription = tr("Calibrating sensors, please wait.");
pixhawk's avatar
pixhawk committed
1426
        break;
lm's avatar
lm committed
1427
    case MAV_STATE_ACTIVE:
pixhawk's avatar
pixhawk committed
1428
        uasState = tr("ACTIVE");
1429
        stateDescription = tr("Active, normal operation.");
pixhawk's avatar
pixhawk committed
1430
        break;
lm's avatar
lm committed
1431 1432
    case MAV_STATE_STANDBY:
        uasState = tr("STANDBY");
1433
        stateDescription = tr("Standby mode, ready for liftoff.");
lm's avatar
lm committed
1434 1435
        break;
    case MAV_STATE_CRITICAL:
pixhawk's avatar
pixhawk committed
1436
        uasState = tr("CRITICAL");
1437
        stateDescription = tr("FAILURE: Continuing operation.");
pixhawk's avatar
pixhawk committed
1438
        break;
lm's avatar
lm committed
1439
    case MAV_STATE_EMERGENCY:
pixhawk's avatar
pixhawk committed
1440
        uasState = tr("EMERGENCY");
1441
        stateDescription = tr("EMERGENCY: Land Immediately!");
pixhawk's avatar
pixhawk committed
1442
        break;
James Goppert's avatar
James Goppert committed
1443
        //case MAV_STATE_HILSIM:
James Goppert's avatar
James Goppert committed
1444 1445 1446
        //uasState = tr("HIL SIM");
        //stateDescription = tr("HIL Simulation, Sensors read from SIM");
        //break;
1447

lm's avatar
lm committed
1448
    case MAV_STATE_POWEROFF:
pixhawk's avatar
pixhawk committed
1449
        uasState = tr("SHUTDOWN");
1450
        stateDescription = tr("Powering off system.");
pixhawk's avatar
pixhawk committed
1451
        break;
1452

lm's avatar
lm committed
1453
    default:
pixhawk's avatar
pixhawk committed
1454
        uasState = tr("UNKNOWN");
1455
        stateDescription = tr("Unknown system state");
pixhawk's avatar
pixhawk committed
1456 1457 1458 1459
        break;
    }
}

1460 1461
QImage UAS::getImage()
{
LM's avatar
LM committed
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
#ifdef MAVLINK_ENABLED_PIXHAWK

    qDebug() << "IMAGE TYPE:" << imageType;

    // RAW greyscale
    if (imageType == MAVLINK_DATA_STREAM_IMG_RAW8U)
    {
        // TODO FIXME Fabian
        // RAW hardcoded to 22x22
        int imgWidth = 22;
        int imgHeight = 22;
        int imgColors = 255;
        //const int headerSize = 15;

        // Construct PGM header
        QString header("P5\n%1 %2\n%3\n");
        header = header.arg(imgWidth).arg(imgHeight).arg(imgColors);

        QByteArray tmpImage(header.toStdString().c_str(), header.toStdString().size());
        tmpImage.append(imageRecBuffer);

        //qDebug() << "IMAGE SIZE:" << tmpImage.size() << "HEADER SIZE: (15):" << header.size() << "HEADER: " << header;

        if (imageRecBuffer.isNull())
        {
            qDebug()<< "could not convertToPGM()";
            return QImage();
        }

        if (!image.loadFromData(tmpImage, "PGM"))
        {
            qDebug()<< "could not create extracted image";
            return QImage();
        }

    }
    // BMP with header
    else if (imageType == MAVLINK_DATA_STREAM_IMG_BMP ||
             imageType == MAVLINK_DATA_STREAM_IMG_JPEG ||
             imageType == MAVLINK_DATA_STREAM_IMG_PGM ||
             imageType == MAVLINK_DATA_STREAM_IMG_PNG)
    {
       if (!image.loadFromData(imageRecBuffer))
        {
           qDebug() << "Loading data from image buffer failed!";
        }
    }
1509 1510
    // Restart statemachine
    imagePacketsArrived = 0;
LM's avatar
LM committed
1511
    //imageRecBuffer.clear();
1512
    return image;
1513 1514
#else
	return QImage();
LM's avatar
LM committed
1515
#endif
1516

1517 1518 1519 1520
}

void UAS::requestImage()
{
1521
#ifdef MAVLINK_ENABLED_PIXHAWK
1522 1523
    qDebug() << "trying to get an image from the uas...";

1524 1525 1526
    // check if there is already an image transmission going on
    if (imagePacketsArrived == 0)
    {
1527 1528 1529 1530
        mavlink_message_t msg;
        mavlink_msg_data_transmission_handshake_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, DATA_TYPE_JPEG_IMAGE, 0, 0, 0, 50);
        sendMessage(msg);
    }
1531
#endif
1532
}
pixhawk's avatar
pixhawk committed
1533 1534 1535 1536 1537 1538 1539 1540 1541


/* MANAGEMENT */

/*
 *
 * @return The uptime in milliseconds
 *
 **/
1542
quint64 UAS::getUptime() const
pixhawk's avatar
pixhawk committed
1543
{
1544 1545
    if(startTime == 0)
    {
pixhawk's avatar
pixhawk committed
1546
        return 0;
1547 1548 1549
    }
    else
    {
pixhawk's avatar
pixhawk committed
1550 1551 1552 1553
        return MG::TIME::getGroundTimeNow() - startTime;
    }
}

1554
int UAS::getCommunicationStatus() const
pixhawk's avatar
pixhawk committed
1555 1556 1557 1558
{
    return commStatus;
}

1559 1560 1561
void UAS::requestParameters()
{
    mavlink_message_t msg;
1562
    mavlink_msg_param_request_list_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), 25);
1563
    sendMessage(msg);
1564 1565
}

1566
void UAS::writeParametersToStorage()
1567
{
1568
    mavlink_message_t msg;
1569
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, MAV_CMD_PREFLIGHT_STORAGE, 1, 1, -1, -1, -1);
1570
    sendMessage(msg);
1571 1572 1573 1574
}

void UAS::readParametersFromStorage()
{
1575
    mavlink_message_t msg;
1576
    mavlink_msg_command_short_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, MAV_CMD_PREFLIGHT_STORAGE, 1, 0, -1, -1, -1);
1577
    sendMessage(msg);
lm's avatar
lm committed
1578 1579
}

1580
void UAS::enableAllDataTransmission(int rate)
lm's avatar
lm committed
1581 1582
{
    // Buffers to write data to
1583
    mavlink_message_t msg;
1584
    mavlink_request_data_stream_t stream;
lm's avatar
lm committed
1585 1586
    // Select the message to request from now on
    // 0 is a magic ID and will enable/disable the standard message set except for heartbeat
1587
    stream.req_stream_id = MAV_DATA_STREAM_ALL;
lm's avatar
lm committed
1588 1589
    // Select the update rate in Hz the message should be send
    // All messages will be send with their default rate
1590 1591
    // TODO: use 0 to turn off and get rid of enable/disable? will require
    //  a different magic flag for turning on defaults, possibly something really high like 1111 ?
lm's avatar
lm committed
1592 1593
    stream.req_message_rate = 0;
    // Start / stop the message
1594
    stream.start_stop = (rate) ? 1 : 0;
lm's avatar
lm committed
1595 1596 1597 1598 1599
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
1600
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1601 1602
    // Send message twice to increase chance of reception
    sendMessage(msg);
lm's avatar
lm committed
1603 1604 1605
    sendMessage(msg);
}

1606
void UAS::enableRawSensorDataTransmission(int rate)
lm's avatar
lm committed
1607 1608 1609
{
    // Buffers to write data to
    mavlink_message_t msg;
1610
    mavlink_request_data_stream_t stream;
lm's avatar
lm committed
1611
    // Select the message to request from now on
1612
    stream.req_stream_id = MAV_DATA_STREAM_RAW_SENSORS;
lm's avatar
lm committed
1613
    // Select the update rate in Hz the message should be send
1614
    stream.req_message_rate = rate;
lm's avatar
lm committed
1615
    // Start / stop the message
1616
    stream.start_stop = (rate) ? 1 : 0;
lm's avatar
lm committed
1617 1618 1619 1620 1621
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
1622
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1623 1624
    // Send message twice to increase chance of reception
    sendMessage(msg);
lm's avatar
lm committed
1625 1626 1627
    sendMessage(msg);
}

1628
void UAS::enableExtendedSystemStatusTransmission(int rate)
lm's avatar
lm committed
1629
{
1630 1631 1632 1633
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1634
    stream.req_stream_id = MAV_DATA_STREAM_EXTENDED_STATUS;
1635
    // Select the update rate in Hz the message should be send
1636
    stream.req_message_rate = rate;
1637
    // Start / stop the message
1638
    stream.start_stop = (rate) ? 1 : 0;
1639 1640 1641 1642 1643 1644
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1645 1646
    // Send message twice to increase chance of reception
    sendMessage(msg);
1647
    sendMessage(msg);
lm's avatar
lm committed
1648
}
1649

1650
void UAS::enableRCChannelDataTransmission(int rate)
lm's avatar
lm committed
1651
{
1652 1653 1654 1655 1656
#if defined(MAVLINK_ENABLED_UALBERTA_MESSAGES)
    mavlink_message_t msg;
    mavlink_msg_request_rc_channels_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, enabled);
    sendMessage(msg);
#else
1657 1658 1659
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1660
    stream.req_stream_id = MAV_DATA_STREAM_RC_CHANNELS;
1661
    // Select the update rate in Hz the message should be send
1662
    stream.req_message_rate = rate;
1663
    // Start / stop the message
1664
    stream.start_stop = (rate) ? 1 : 0;
1665 1666 1667 1668 1669 1670
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1671 1672
    // Send message twice to increase chance of reception
    sendMessage(msg);
1673
    sendMessage(msg);
1674
#endif
lm's avatar
lm committed
1675 1676
}

1677
void UAS::enableRawControllerDataTransmission(int rate)
lm's avatar
lm committed
1678
{
1679 1680 1681 1682
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1683
    stream.req_stream_id = MAV_DATA_STREAM_RAW_CONTROLLER;
1684
    // Select the update rate in Hz the message should be send
1685
    stream.req_message_rate = rate;
1686
    // Start / stop the message
1687
    stream.start_stop = (rate) ? 1 : 0;
1688 1689 1690 1691 1692 1693
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1694 1695
    // Send message twice to increase chance of reception
    sendMessage(msg);
1696
    sendMessage(msg);
lm's avatar
lm committed
1697 1698
}

lm's avatar
lm committed
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
//void UAS::enableRawSensorFusionTransmission(int rate)
//{
//    // Buffers to write data to
//    mavlink_message_t msg;
//    mavlink_request_data_stream_t stream;
//    // Select the message to request from now on
//    stream.req_stream_id = MAV_DATA_STREAM_RAW_SENSOR_FUSION;
//    // Select the update rate in Hz the message should be send
//    stream.req_message_rate = rate;
//    // Start / stop the message
//    stream.start_stop = (rate) ? 1 : 0;
//    // The system which should take this command
//    stream.target_system = uasId;
//    // The component / subsystem which should take this command
//    stream.target_component = 0;
//    // Encode and send the message
//    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
//}
1720

1721
void UAS::enablePositionTransmission(int rate)
pixhawk's avatar
pixhawk committed
1722 1723 1724 1725 1726
{
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1727
    stream.req_stream_id = MAV_DATA_STREAM_POSITION;
pixhawk's avatar
pixhawk committed
1728
    // Select the update rate in Hz the message should be send
1729
    stream.req_message_rate = rate;
pixhawk's avatar
pixhawk committed
1730
    // Start / stop the message
1731
    stream.start_stop = (rate) ? 1 : 0;
pixhawk's avatar
pixhawk committed
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
    // Send message twice to increase chance of reception
    sendMessage(msg);
    sendMessage(msg);
}

1743
void UAS::enableExtra1Transmission(int rate)
pixhawk's avatar
pixhawk committed
1744 1745 1746 1747 1748
{
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1749
    stream.req_stream_id = MAV_DATA_STREAM_EXTRA1;
pixhawk's avatar
pixhawk committed
1750
    // Select the update rate in Hz the message should be send
1751
    stream.req_message_rate = rate;
pixhawk's avatar
pixhawk committed
1752
    // Start / stop the message
1753
    stream.start_stop = (rate) ? 1 : 0;
pixhawk's avatar
pixhawk committed
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
    // Send message twice to increase chance of reception
    sendMessage(msg);
    sendMessage(msg);
}

1765
void UAS::enableExtra2Transmission(int rate)
pixhawk's avatar
pixhawk committed
1766 1767 1768 1769 1770
{
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1771
    stream.req_stream_id = MAV_DATA_STREAM_EXTRA2;
pixhawk's avatar
pixhawk committed
1772
    // Select the update rate in Hz the message should be send
1773
    stream.req_message_rate = rate;
pixhawk's avatar
pixhawk committed
1774
    // Start / stop the message
1775
    stream.start_stop = (rate) ? 1 : 0;
pixhawk's avatar
pixhawk committed
1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
    // Send message twice to increase chance of reception
    sendMessage(msg);
    sendMessage(msg);
}

1787
void UAS::enableExtra3Transmission(int rate)
pixhawk's avatar
pixhawk committed
1788 1789 1790 1791 1792
{
    // Buffers to write data to
    mavlink_message_t msg;
    mavlink_request_data_stream_t stream;
    // Select the message to request from now on
1793
    stream.req_stream_id = MAV_DATA_STREAM_EXTRA3;
pixhawk's avatar
pixhawk committed
1794
    // Select the update rate in Hz the message should be send
1795
    stream.req_message_rate = rate;
1796
    // Start / stop the message
1797
    stream.start_stop = (rate) ? 1 : 0;
1798 1799 1800 1801 1802 1803
    // The system which should take this command
    stream.target_system = uasId;
    // The component / subsystem which should take this command
    stream.target_component = 0;
    // Encode and send the message
    mavlink_msg_request_data_stream_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &stream);
1804 1805
    // Send message twice to increase chance of reception
    sendMessage(msg);
1806
    sendMessage(msg);
1807 1808
}

lm's avatar
lm committed
1809 1810 1811 1812 1813 1814 1815
/**
 * Set a parameter value onboard
 *
 * @param component The component to set the parameter
 * @param id Name of the parameter
 * @param value Parameter value
 */
1816
void UAS::setParameter(const int component, const QString& id, const QVariant& value)
lm's avatar
lm committed
1817
{
1818 1819
    if (!id.isNull())
    {
1820 1821
        mavlink_message_t msg;
        mavlink_param_set_t p;
1822 1823 1824 1825 1826 1827 1828
        mavlink_param_union_t union_value;

        // Assign correct value based on QVariant
        switch (value.type())
        {
        case QVariant::Int:
            union_value.param_int32 = value.toInt();
1829
            p.param_type = MAVLINK_TYPE_INT32_T;
1830 1831 1832
            break;
        case QVariant::UInt:
            union_value.param_uint32 = value.toUInt();
1833
            p.param_type = MAVLINK_TYPE_UINT32_T;
1834 1835 1836
            break;
        case QMetaType::Float:
            union_value.param_float = value.toFloat();
1837
            p.param_type = MAVLINK_TYPE_FLOAT;
1838 1839 1840 1841 1842 1843 1844
            break;
        default:
            qCritical() << "ABORTED PARAM SEND, NO VALID QVARIANT TYPE";
            return;
        }

        p.param_value = union_value.param_float;
1845 1846 1847
        p.target_system = (uint8_t)uasId;
        p.target_component = (uint8_t)component;

1848 1849
        qDebug() << "SENT PARAM:" << value;

1850
        // Copy string into buffer, ensuring not to exceed the buffer size
1851 1852
        for (unsigned int i = 0; i < sizeof(p.param_id); i++)
        {
1853
            // String characters
1854 1855
            if ((int)i < id.length() && i < (sizeof(p.param_id) - 1))
            {
1856 1857
                p.param_id[i] = id.toAscii()[i];
            }
LM's avatar
LM committed
1858 1859 1860 1861 1862
            //        // Null termination at end of string or end of buffer
            //        else if ((int)i == id.length() || i == (sizeof(p.param_id) - 1))
            //        {
            //            p.param_id[i] = '\0';
            //        }
1863
            // Zero fill
1864 1865
            else
            {
1866 1867
                p.param_id[i] = 0;
            }
lm's avatar
lm committed
1868
        }
1869 1870
        mavlink_msg_param_set_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &p);
        sendMessage(msg);
lm's avatar
lm committed
1871
    }
1872 1873
}

1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
void UAS::requestParameter(int component, int parameter)
{
    mavlink_message_t msg;
    mavlink_param_request_read_t read;
    read.param_index = parameter;
    read.target_system = uasId;
    read.target_component = component;
    mavlink_msg_param_request_read_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &read);
    sendMessage(msg);
    qDebug() << __FILE__ << __LINE__ << "REQUESTING PARAM RETRANSMISSION FROM COMPONENT" << component << "FOR PARAM ID" << parameter;
}

1886 1887 1888 1889
void UAS::setSystemType(int systemType)
{
    type = systemType;
    // If the airframe is still generic, change it to a close default type
1890 1891 1892 1893
    if (airframe == 0)
    {
        switch (systemType)
        {
lm's avatar
lm committed
1894
        case MAV_TYPE_FIXED_WING:
1895 1896
            airframe = QGC_AIRFRAME_EASYSTAR;
            break;
lm's avatar
lm committed
1897
        case MAV_TYPE_QUADROTOR:
1898 1899 1900 1901 1902 1903 1904
            airframe = QGC_AIRFRAME_MIKROKOPTER;
            break;
        }
    }
    emit systemSpecsChanged(uasId);
}

1905 1906 1907
void UAS::setUASName(const QString& name)
{
    this->name = name;
1908
    writeSettings();
1909
    emit nameChanged(name);
1910
    emit systemSpecsChanged(uasId);
1911 1912
}

lm's avatar
lm committed
1913 1914 1915
void UAS::executeCommand(MAV_CMD command)
{
    mavlink_message_t msg;
1916
    mavlink_command_short_t cmd;
1917 1918 1919 1920 1921 1922 1923 1924
    cmd.command = (uint8_t)command;
    cmd.confirmation = 0;
    cmd.param1 = 0.0f;
    cmd.param2 = 0.0f;
    cmd.param3 = 0.0f;
    cmd.param4 = 0.0f;
    cmd.target_system = uasId;
    cmd.target_component = 0;
1925
    mavlink_msg_command_short_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &cmd);
1926 1927 1928 1929 1930 1931
    sendMessage(msg);
}

void UAS::executeCommand(MAV_CMD command, int confirmation, float param1, float param2, float param3, float param4, int component)
{
    mavlink_message_t msg;
1932
    mavlink_command_short_t cmd;
1933 1934 1935 1936 1937 1938 1939 1940
    cmd.command = (uint8_t)command;
    cmd.confirmation = confirmation;
    cmd.param1 = param1;
    cmd.param2 = param2;
    cmd.param3 = param3;
    cmd.param4 = param4;
    cmd.target_system = uasId;
    cmd.target_component = component;
1941 1942 1943 1944 1945 1946 1947 1948
    mavlink_msg_command_short_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &cmd);
    sendMessage(msg);
}

void UAS::executeCommand(MAV_CMD command, int confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7, int component)
{
    mavlink_message_t msg;
    mavlink_command_long_t cmd;
1949 1950 1951 1952 1953 1954
    cmd.command = (uint8_t)command;
    cmd.confirmation = confirmation;
    cmd.param1 = param1;
    cmd.param2 = param2;
    cmd.param3 = param3;
    cmd.param4 = param4;
1955 1956 1957
    cmd.param5 = param5;
    cmd.param6 = param6;
    cmd.param7 = param7;
1958 1959
    cmd.target_system = uasId;
    cmd.target_component = component;
1960
    mavlink_msg_command_long_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &cmd);
lm's avatar
lm committed
1961 1962 1963
    sendMessage(msg);
}

pixhawk's avatar
pixhawk committed
1964
/**
lm's avatar
lm committed
1965
 * Launches the system
pixhawk's avatar
pixhawk committed
1966 1967 1968 1969
 *
 **/
void UAS::launch()
{
lm's avatar
lm committed
1970 1971 1972 1973 1974 1975 1976
    // FIXME MAVLINKV10PORTINGNEEDED
//    mavlink_message_t msg;
//    // TODO Replace MG System ID with static function call and allow to change ID in GUI
//    mavlink_msg_action_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), MAV_COMP_ID_IMU, (uint8_t)MAV_ACTION_TAKEOFF);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1977 1978 1979 1980 1981 1982
}

/**
 * Depending on the UAS, this might make the rotors of a helicopter spinning
 *
 **/
1983
void UAS::armSystem()
pixhawk's avatar
pixhawk committed
1984
{
1985
    mavlink_message_t msg;
1986
    mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode, navMode | MAV_MODE_FLAG_SAFETY_ARMED);
1987
    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1988 1989 1990 1991 1992 1993
}

/**
 * @warning Depending on the UAS, this might completely stop all motors.
 *
 **/
1994
void UAS::disarmSystem()
pixhawk's avatar
pixhawk committed
1995
{
1996
    mavlink_message_t msg;
1997
    mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode, navMode & !MAV_MODE_FLAG_SAFETY_ARMED);
1998
    sendMessage(msg);
pixhawk's avatar
pixhawk committed
1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
}

void UAS::setManualControlCommands(double roll, double pitch, double yaw, double thrust)
{
    // Scale values
    double rollPitchScaling = 0.2f;
    double yawScaling = 0.5f;
    double thrustScaling = 1.0f;

    manualRollAngle = roll * rollPitchScaling;
    manualPitchAngle = pitch * rollPitchScaling;
    manualYawAngle = yaw * yawScaling;
    manualThrust = thrust * thrustScaling;

lm's avatar
lm committed
2013
    if(mode == (int)MAV_MODE_MANUAL_ARMED)
2014
    {
2015 2016 2017 2018
        mavlink_message_t message;
        mavlink_msg_manual_control_pack(mavlink->getSystemId(), mavlink->getComponentId(), &message, this->uasId, (float)manualRollAngle, (float)manualPitchAngle, (float)manualYawAngle, (float)manualThrust, controlRollManual, controlPitchManual, controlYawManual, controlThrustManual);
        sendMessage(message);
        qDebug() << __FILE__ << __LINE__ << ": SENT MANUAL CONTROL MESSAGE: roll" << manualRollAngle << " pitch: " << manualPitchAngle << " yaw: " << manualYawAngle << " thrust: " << manualThrust;
pixhawk's avatar
pixhawk committed
2019

2020
        emit attitudeThrustSetPointChanged(this, roll, pitch, yaw, thrust, MG::TIME::getGroundTimeNow());
2021 2022 2023
    }
    else
    {
2024 2025
        qDebug() << "JOYSTICK/MANUAL CONTROL: IGNORING COMMANDS: Set mode to MANUAL to send joystick commands first";
    }
pixhawk's avatar
pixhawk committed
2026 2027
}

2028 2029 2030 2031 2032
int UAS::getSystemType()
{
    return this->type;
}

pixhawk's avatar
pixhawk committed
2033 2034
void UAS::receiveButton(int buttonIndex)
{
2035 2036
    switch (buttonIndex)
    {
pixhawk's avatar
pixhawk committed
2037
    case 0:
pixhawk's avatar
pixhawk committed
2038

pixhawk's avatar
pixhawk committed
2039 2040
        break;
    case 1:
pixhawk's avatar
pixhawk committed
2041

pixhawk's avatar
pixhawk committed
2042 2043 2044 2045 2046
        break;
    default:

        break;
    }
2047
    //    qDebug() << __FILE__ << __LINE__ << ": Received button clicked signal (button # is: " << buttonIndex << "), UNIMPLEMENTED IN MAVLINK!";
pixhawk's avatar
pixhawk committed
2048 2049 2050

}

2051

pixhawk's avatar
pixhawk committed
2052 2053 2054

void UAS::halt()
{
lm's avatar
lm committed
2055 2056 2057 2058 2059 2060 2061
    // FIXME MAVLINKV10PORTINGNEEDED
//    mavlink_message_t msg;
//    // TODO Replace MG System ID with static function call and allow to change ID in GUI
//    mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU, (int)MAV_ACTION_HALT);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
pixhawk's avatar
pixhawk committed
2062 2063 2064 2065
}

void UAS::go()
{
lm's avatar
lm committed
2066 2067 2068 2069 2070 2071 2072
    // FIXME MAVLINKV10PORTINGNEEDED
//    mavlink_message_t msg;
//    // TODO Replace MG System ID with static function call and allow to change ID in GUI
//    mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU,  (int)MAV_ACTION_CONTINUE);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
pixhawk's avatar
pixhawk committed
2073 2074 2075 2076 2077
}

/** Order the robot to return home / to land on the runway **/
void UAS::home()
{
lm's avatar
lm committed
2078 2079 2080 2081 2082 2083 2084
    // FIXME MAVLINKV10PORTINGNEEDED
//    mavlink_message_t msg;
//    // TODO Replace MG System ID with static function call and allow to change ID in GUI
//    mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU,  (int)MAV_ACTION_RETURN);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
pixhawk's avatar
pixhawk committed
2085 2086 2087 2088 2089 2090 2091 2092
}

/**
 * The MAV starts the emergency landing procedure. The behaviour depends on the onboard implementation
 * and might differ between systems.
 */
void UAS::emergencySTOP()
{
lm's avatar
lm committed
2093 2094 2095 2096 2097 2098 2099
//    mavlink_message_t msg;
//    // TODO Replace MG System ID with static function call and allow to change ID in GUI
//    // FIXME MAVLINKV10PORTINGNEEDED
//    //mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU, (int)MAV_ACTION_EMCY_LAND);
//    // Send message twice to increase chance of reception
//    sendMessage(msg);
//    sendMessage(msg);
pixhawk's avatar
pixhawk committed
2100 2101 2102
}

/**
lm's avatar
lm committed
2103
 * Shut down this mav - All onboard systems are immediately shut down (e.g. the main power line is cut).
pixhawk's avatar
pixhawk committed
2104 2105 2106 2107 2108 2109
 * @warning This might lead to a crash
 *
 * The command will not be executed until emergencyKILLConfirm is issues immediately afterwards
 */
bool UAS::emergencyKILL()
{
lm's avatar
lm committed
2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135
    // FIXME MAVLINKV10PORTINGNEEDED
//    bool result = false;
//    QMessageBox msgBox;
//    msgBox.setIcon(QMessageBox::Critical);
//    msgBox.setText("EMERGENCY: KILL ALL MOTORS ON UAS");
//    msgBox.setInformativeText("Do you want to cut power on all systems?");
//    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
//    msgBox.setDefaultButton(QMessageBox::Cancel);
//    int ret = msgBox.exec();

//    // Close the message box shortly after the click to prevent accidental clicks
//    QTimer::singleShot(5000, &msgBox, SLOT(reject()));


//    if (ret == QMessageBox::Yes)
//    {
//        mavlink_message_t msg;
//        // TODO Replace MG System ID with static function call and allow to change ID in GUI
//        mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU, (int)MAV_ACTION_EMCY_KILL);
//        // Send message twice to increase chance of reception
//        sendMessage(msg);
//        sendMessage(msg);
//        result = true;
//    }
//    return result;
    return false;
pixhawk's avatar
pixhawk committed
2136 2137
}

lm's avatar
lm committed
2138 2139 2140 2141 2142
void UAS::enableHil(bool enable)
{
    // Connect Flight Gear Link
    if (enable)
    {
2143
        startHil();
lm's avatar
lm committed
2144 2145 2146
    }
    else
    {
2147
        stopHil();
lm's avatar
lm committed
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
    }
}

/**
* @param time_us Timestamp (microseconds since UNIX epoch or microseconds since system boot)
* @param roll Roll angle (rad)
* @param pitch Pitch angle (rad)
* @param yaw Yaw angle (rad)
* @param rollspeed Roll angular speed (rad/s)
* @param pitchspeed Pitch angular speed (rad/s)
* @param yawspeed Yaw angular speed (rad/s)
* @param lat Latitude, expressed as * 1E7
* @param lon Longitude, expressed as * 1E7
* @param alt Altitude in meters, expressed as * 1000 (millimeters)
* @param vx Ground X Speed (Latitude), expressed as m/s * 100
* @param vy Ground Y Speed (Longitude), expressed as m/s * 100
* @param vz Ground Z Speed (Altitude), expressed as m/s * 100
* @param xacc X acceleration (mg)
* @param yacc Y acceleration (mg)
* @param zacc Z acceleration (mg)
*/
void UAS::sendHilState(uint64_t time_us, float roll, float pitch, float yaw, float rollspeed,
                    float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt,
                    int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc)
{
    mavlink_message_t msg;
    mavlink_msg_hil_state_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, time_us, roll, pitch, yaw, rollspeed, pitchspeed, yawspeed, lat, lon, alt, vx, vy, vz, xacc, yacc, zacc);
    sendMessage(msg);
}


2179 2180
void UAS::startHil()
{
lm's avatar
lm committed
2181 2182
    // Connect Flight Gear Link
    simulation->connectSimulation();
2183
    mavlink_message_t msg;
2184
    mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode, navMode | MAV_MODE_FLAG_HIL_ENABLED);
2185
    sendMessage(msg);
2186 2187
}

2188 2189
void UAS::stopHil()
{
lm's avatar
lm committed
2190
    simulation->disconnectSimulation();
2191
    mavlink_message_t msg;
2192
    mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode, navMode & !MAV_MODE_FLAG_HIL_ENABLED);
2193
    sendMessage(msg);
2194 2195 2196
}


pixhawk's avatar
pixhawk committed
2197 2198
void UAS::shutdown()
{
lm's avatar
lm committed
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224
    // FIXME MAVLINKV10PORTINGNEEDED
//    bool result = false;
//    QMessageBox msgBox;
//    msgBox.setIcon(QMessageBox::Critical);
//    msgBox.setText("Shutting down the UAS");
//    msgBox.setInformativeText("Do you want to shut down the onboard computer?");

//    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
//    msgBox.setDefaultButton(QMessageBox::Cancel);
//    int ret = msgBox.exec();

//    // Close the message box shortly after the click to prevent accidental clicks
//    QTimer::singleShot(5000, &msgBox, SLOT(reject()));

//    if (ret == QMessageBox::Yes)
//    {
//        // If the active UAS is set, execute command
//        mavlink_message_t msg;
//        // TODO Replace MG System ID with static function call and allow to change ID in GUI
//        mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU,(int)MAV_ACTION_SHUTDOWN);
//        // Send message twice to increase chance of reception
//        sendMessage(msg);
//        sendMessage(msg);

//        result = true;
//    }
pixhawk's avatar
pixhawk committed
2225 2226
}

2227 2228
void UAS::setTargetPosition(float x, float y, float z, float yaw)
{
2229
    mavlink_message_t msg;
lm's avatar
lm committed
2230
    mavlink_msg_set_local_position_setpoint_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, 0, MAV_FRAME_LOCAL_NED, x, y, z, yaw);
2231 2232 2233 2234

    // Send message twice to increase chance of reception
    sendMessage(msg);
    sendMessage(msg);
2235 2236
}

pixhawk's avatar
pixhawk committed
2237 2238 2239
/**
 * @return The name of this system as string in human-readable form
 */
2240
QString UAS::getUASName(void) const
pixhawk's avatar
pixhawk committed
2241 2242
{
    QString result;
2243 2244
    if (name == "")
    {
pixhawk's avatar
pixhawk committed
2245
        result = tr("MAV ") + result.sprintf("%03d", getUASID());
2246 2247 2248
    }
    else
    {
pixhawk's avatar
pixhawk committed
2249 2250 2251 2252 2253
        result = name;
    }
    return result;
}

2254 2255 2256 2257 2258
const QString& UAS::getShortState() const
{
    return shortStateText;
}

2259 2260 2261 2262 2263 2264 2265 2266
QString UAS::getShortModeTextFor(int id)
{
    QString mode;

    switch (id) {
    case (uint8_t)MAV_MODE_PREFLIGHT:
        mode = "PREFLIGHT";
        break;
lm's avatar
lm committed
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283
    case (uint8_t)MAV_MODE_MANUAL_ARMED:
        mode = "A|MANUAL";
        break;
    case (uint8_t)MAV_MODE_MANUAL_DISARMED:
        mode = "D|MANUAL";
        break;
    case (uint8_t)MAV_MODE_AUTO_ARMED:
        mode = "A|AUTO";
        break;
    case (uint8_t)MAV_MODE_AUTO_DISARMED:
        mode = "D|AUTO";
        break;
    case (uint8_t)MAV_MODE_GUIDED_ARMED:
        mode = "A|GUIDED";
        break;
    case (uint8_t)MAV_MODE_GUIDED_DISARMED:
        mode = "D|GUIDED";
2284
        break;
lm's avatar
lm committed
2285 2286
    case (uint8_t)MAV_MODE_STABILIZE_ARMED:
        mode = "A|STABILIZED";
2287
        break;
lm's avatar
lm committed
2288 2289
    case (uint8_t)MAV_MODE_STABILIZE_DISARMED:
        mode = "D|STABILIZED";
2290
        break;
lm's avatar
lm committed
2291 2292
    case (uint8_t)MAV_MODE_TEST_ARMED:
        mode = "A|TEST";
2293
        break;
lm's avatar
lm committed
2294 2295
    case (uint8_t)MAV_MODE_TEST_DISARMED:
        mode = "D|TEST";
2296 2297 2298 2299 2300 2301 2302 2303 2304
        break;
    default:
        mode = "UNKNOWN";
        break;
    }

    return mode;
}

2305 2306 2307 2308 2309
const QString& UAS::getShortMode() const
{
    return shortModeText;
}

pixhawk's avatar
pixhawk committed
2310 2311
void UAS::addLink(LinkInterface* link)
{
2312 2313
    if (!links->contains(link))
    {
pixhawk's avatar
pixhawk committed
2314
        links->append(link);
2315
        connect(link, SIGNAL(destroyed(QObject*)), this, SLOT(removeLink(QObject*)));
pixhawk's avatar
pixhawk committed
2316 2317 2318
    }
}

2319 2320 2321
void UAS::removeLink(QObject* object)
{
    LinkInterface* link = dynamic_cast<LinkInterface*>(object);
2322 2323
    if (link)
    {
2324 2325 2326 2327
        links->removeAt(links->indexOf(link));
    }
}

pixhawk's avatar
pixhawk committed
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342
/**
 * @brief Get the links associated with this robot
 *
 **/
QList<LinkInterface*>* UAS::getLinks()
{
    return links;
}



void UAS::setBattery(BatteryType type, int cells)
{
    this->batteryType = type;
    this->cells = cells;
2343 2344
    switch (batteryType)
    {
lm's avatar
lm committed
2345
    case NICD:
pixhawk's avatar
pixhawk committed
2346
        break;
lm's avatar
lm committed
2347
    case NIMH:
pixhawk's avatar
pixhawk committed
2348
        break;
lm's avatar
lm committed
2349
    case LIION:
pixhawk's avatar
pixhawk committed
2350
        break;
lm's avatar
lm committed
2351
    case LIPOLY:
pixhawk's avatar
pixhawk committed
2352 2353 2354
        fullVoltage = this->cells * UAS::lipoFull;
        emptyVoltage = this->cells * UAS::lipoEmpty;
        break;
lm's avatar
lm committed
2355
    case LIFE:
pixhawk's avatar
pixhawk committed
2356
        break;
lm's avatar
lm committed
2357
    case AGZN:
pixhawk's avatar
pixhawk committed
2358 2359 2360 2361
        break;
    }
}

2362 2363
void UAS::setBatterySpecs(const QString& specs)
{
2364 2365
    if (specs.length() == 0 || specs.contains("%"))
    {
2366
        batteryRemainingEstimateEnabled = false;
2367
        bool ok;
2368 2369 2370
        QString percent = specs;
        percent = percent.remove("%");
        float temp = percent.toFloat(&ok);
2371 2372
        if (ok)
        {
2373
            warnLevelPercent = temp;
2374 2375 2376
        }
        else
        {
2377 2378
            emit textMessageReceived(0, 0, 0, "Could not set battery options, format is wrong");
        }
2379 2380 2381
    }
    else
    {
2382 2383 2384 2385 2386
        batteryRemainingEstimateEnabled = true;
        QString stringList = specs;
        stringList = stringList.remove("V");
        stringList = stringList.remove("v");
        QStringList parts = stringList.split(",");
2387 2388
        if (parts.length() == 3)
        {
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399
            float temp;
            bool ok;
            // Get the empty voltage
            temp = parts.at(0).toFloat(&ok);
            if (ok) emptyVoltage = temp;
            // Get the warning voltage
            temp = parts.at(1).toFloat(&ok);
            if (ok) warnVoltage = temp;
            // Get the full voltage
            temp = parts.at(2).toFloat(&ok);
            if (ok) fullVoltage = temp;
2400 2401 2402
        }
        else
        {
2403 2404
            emit textMessageReceived(0, 0, 0, "Could not set battery options, format is wrong");
        }
2405 2406 2407 2408 2409
    }
}

QString UAS::getBatterySpecs()
{
2410 2411
    if (batteryRemainingEstimateEnabled)
    {
2412
        return QString("%1V,%2V,%3V").arg(emptyVoltage).arg(warnVoltage).arg(fullVoltage);
2413 2414 2415
    }
    else
    {
2416 2417
        return QString("%1%").arg(warnLevelPercent);
    }
2418 2419
}

pixhawk's avatar
pixhawk committed
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
int UAS::calculateTimeRemaining()
{
    quint64 dt = MG::TIME::getGroundTimeNow() - startTime;
    double seconds = dt / 1000.0f;
    double voltDifference = startVoltage - currentVoltage;
    if (voltDifference <= 0) voltDifference = 0.00000000001f;
    double dischargePerSecond = voltDifference / seconds;
    int remaining = static_cast<int>((currentVoltage - emptyVoltage) / dischargePerSecond);
    // Can never be below 0
    if (remaining < 0) remaining = 0;
    return remaining;
}

lm's avatar
lm committed
2433 2434 2435
/**
 * @return charge level in percent - 0 - 100
 */
2436
float UAS::getChargeLevel()
pixhawk's avatar
pixhawk committed
2437
{
2438 2439 2440 2441
    if (batteryRemainingEstimateEnabled)
    {
        if (lpVoltage < emptyVoltage)
        {
2442
            chargeLevel = 0.0f;
2443 2444 2445
        }
        else if (lpVoltage > fullVoltage)
        {
2446
            chargeLevel = 100.0f;
2447 2448 2449
        }
        else
        {
2450 2451
            chargeLevel = 100.0f * ((lpVoltage - emptyVoltage)/(fullVoltage - emptyVoltage));
        }
2452 2453
    }
    return chargeLevel;
pixhawk's avatar
pixhawk committed
2454 2455
}

lm's avatar
lm committed
2456 2457
void UAS::startLowBattAlarm()
{
2458 2459
    if (!lowBattAlarm)
    {
2460
        GAudioOutput::instance()->alert(tr("system %1 has low battery").arg(getUASName()));
2461
        QTimer::singleShot(2500, GAudioOutput::instance(), SLOT(startEmergency()));
lm's avatar
lm committed
2462 2463 2464 2465 2466 2467
        lowBattAlarm = true;
    }
}

void UAS::stopLowBattAlarm()
{
2468 2469
    if (lowBattAlarm)
    {
lm's avatar
lm committed
2470 2471 2472 2473
        GAudioOutput::instance()->stopEmergency();
        lowBattAlarm = false;
    }
}