MAVLinkProtocol.cc 20.6 KB
Newer Older
1
/*===================================================================
pixhawk's avatar
pixhawk committed
2 3 4 5
======================================================================*/

/**
 * @file
pixhawk's avatar
pixhawk committed
6 7
 *   @brief Implementation of class MAVLinkProtocol
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
pixhawk's avatar
pixhawk committed
8 9 10 11 12 13 14
 */

#include <inttypes.h>
#include <iostream>

#include <QDebug>
#include <QTime>
lm's avatar
lm committed
15
#include <QApplication>
pixhawk's avatar
pixhawk committed
16
#include <QMessageBox>
17 18
#include <QSettings>
#include <QDesktopServices>
pixhawk's avatar
pixhawk committed
19 20 21 22 23 24

#include "MAVLinkProtocol.h"
#include "UASInterface.h"
#include "UASManager.h"
#include "UASInterface.h"
#include "UAS.h"
25 26
#include "SlugsMAV.h"
#include "PxQuadMAV.h"
27
#include "ArduPilotMegaMAV.h"
pixhawk's avatar
pixhawk committed
28 29
#include "configuration.h"
#include "LinkManager.h"
30 31
#include "QGCMAVLink.h"
#include "QGCMAVLinkUASFactory.h"
32
#include "QGC.h"
pixhawk's avatar
pixhawk committed
33

34

pixhawk's avatar
pixhawk committed
35 36 37 38 39
/**
 * The default constructor will create a new MAVLink object sending heartbeats at
 * the MAVLINK_HEARTBEAT_DEFAULT_RATE to all connected links.
 */
MAVLinkProtocol::MAVLinkProtocol() :
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    heartbeatTimer(new QTimer(this)),
    heartbeatRate(MAVLINK_HEARTBEAT_DEFAULT_RATE),
    m_heartbeatsEnabled(false),
    m_multiplexingEnabled(false),
    m_authEnabled(false),
    m_loggingEnabled(false),
    m_logfile(NULL),
    m_enable_version_check(true),
    m_paramRetransmissionTimeout(350),
    m_paramRewriteTimeout(500),
    m_paramGuardEnabled(true),
    m_actionGuardEnabled(false),
    m_actionRetransmissionTimeout(100),
    versionMismatchIgnore(false),
    systemId(QGC::defaultSystemId)
pixhawk's avatar
pixhawk committed
55
{
56
    m_authKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
57 58
    loadSettings();
    //start(QThread::LowPriority);
pixhawk's avatar
pixhawk committed
59 60 61
    // Start heartbeat timer, emitting a heartbeat at the configured rate
    connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeat()));
    heartbeatTimer->start(1000/heartbeatRate);
lm's avatar
lm committed
62 63
    totalReceiveCounter = 0;
    totalLossCounter = 0;
64 65
    currReceiveCounter = 0;
    currLossCounter = 0;
66 67 68 69
    for (int i = 0; i < 256; i++)
    {
        for (int j = 0; j < 256; j++)
        {
lm's avatar
lm committed
70 71 72
            lastIndex[i][j] = -1;
        }
    }
lm's avatar
lm committed
73 74

    emit versionCheckChanged(m_enable_version_check);
pixhawk's avatar
pixhawk committed
75 76
}

77 78 79 80 81 82
void MAVLinkProtocol::loadSettings()
{
    // Load defaults from settings
    QSettings settings;
    settings.sync();
    settings.beginGroup("QGC_MAVLINK_PROTOCOL");
83
    enableHeartbeats(settings.value("HEARTBEATS_ENABLED", m_heartbeatsEnabled).toBool());
84 85
    enableVersionCheck(settings.value("VERSION_CHECK_ENABLED", m_enable_version_check).toBool());
    enableMultiplexing(settings.value("MULTIPLEXING_ENABLED", m_multiplexingEnabled).toBool());
86 87

    // Only set logfile if there is a name present in settings
88 89
    if (settings.contains("LOGFILE_NAME") && m_logfile == NULL)
    {
90
        m_logfile = new QFile(settings.value("LOGFILE_NAME").toString());
91 92 93
    }
    else if (m_logfile == NULL)
    {
94 95
        m_logfile = new QFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/qgroundcontrol_packetlog.mavlink");
    }
96 97
    // Enable logging
    enableLogging(settings.value("LOGGING_ENABLED", m_loggingEnabled).toBool());
98 99 100

    // Only set system id if it was valid
    int temp = settings.value("GCS_SYSTEM_ID", systemId).toInt();
101 102
    if (temp > 0 && temp < 256)
    {
103 104
        systemId = temp;
    }
105

106 107 108 109
    // Set auth key
    m_authKey = settings.value("GCS_AUTH_KEY", m_authKey).toString();
    enableAuth(settings.value("GCS_AUTH_ENABLED", m_authEnabled).toBool());

110 111 112 113 114 115 116
    // Parameter interface settings
    bool ok;
    temp = settings.value("PARAMETER_RETRANSMISSION_TIMEOUT", m_paramRetransmissionTimeout).toInt(&ok);
    if (ok) m_paramRetransmissionTimeout = temp;
    temp = settings.value("PARAMETER_REWRITE_TIMEOUT", m_paramRewriteTimeout).toInt(&ok);
    if (ok) m_paramRewriteTimeout = temp;
    m_paramGuardEnabled = settings.value("PARAMETER_TRANSMISSION_GUARD_ENABLED", m_paramGuardEnabled).toBool();
117 118 119 120 121 122 123 124 125 126
    settings.endGroup();
}

void MAVLinkProtocol::storeSettings()
{
    // Store settings
    QSettings settings;
    settings.beginGroup("QGC_MAVLINK_PROTOCOL");
    settings.setValue("HEARTBEATS_ENABLED", m_heartbeatsEnabled);
    settings.setValue("LOGGING_ENABLED", m_loggingEnabled);
127 128
    settings.setValue("VERSION_CHECK_ENABLED", m_enable_version_check);
    settings.setValue("MULTIPLEXING_ENABLED", m_multiplexingEnabled);
129
    settings.setValue("GCS_SYSTEM_ID", systemId);
130 131
    settings.setValue("GCS_AUTH_KEY", m_authKey);
    settings.setValue("GCS_AUTH_ENABLED", m_authEnabled);
132 133
    if (m_logfile)
    {
134 135 136
        // Logfile exists, store the name
        settings.setValue("LOGFILE_NAME", m_logfile->fileName());
    }
137 138 139 140
    // Parameter interface settings
    settings.setValue("PARAMETER_RETRANSMISSION_TIMEOUT", m_paramRetransmissionTimeout);
    settings.setValue("PARAMETER_REWRITE_TIMEOUT", m_paramRewriteTimeout);
    settings.setValue("PARAMETER_TRANSMISSION_GUARD_ENABLED", m_paramGuardEnabled);
141 142 143 144 145
    settings.endGroup();
    settings.sync();
    //qDebug() << "Storing settings!";
}

pixhawk's avatar
pixhawk committed
146 147
MAVLinkProtocol::~MAVLinkProtocol()
{
148
    storeSettings();
149 150 151 152
    if (m_logfile)
    {
        if (m_logfile->isOpen())
        {
153 154 155
            m_logfile->flush();
            m_logfile->close();
        }
pixhawk's avatar
pixhawk committed
156
        delete m_logfile;
157
        m_logfile = NULL;
pixhawk's avatar
pixhawk committed
158
    }
pixhawk's avatar
pixhawk committed
159 160
}

pixhawk's avatar
pixhawk committed
161 162
QString MAVLinkProtocol::getLogfileName()
{
163 164
    if (m_logfile)
    {
165
        return m_logfile->fileName();
166 167 168
    }
    else
    {
169
        return QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/qgroundcontrol_packetlog.mavlink";
170
    }
pixhawk's avatar
pixhawk committed
171 172
}

pixhawk's avatar
pixhawk committed
173 174 175 176 177 178 179 180
/**
 * The bytes are copied by calling the LinkInterface::readBytes() method.
 * This method parses all incoming bytes and constructs a MAVLink packet.
 * It can handle multiple links in parallel, as each link has it's own buffer/
 * parsing state machine.
 * @param link The interface to read from
 * @see LinkInterface
 **/
181
void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
pixhawk's avatar
pixhawk committed
182
{
183
//    receiveMutex.lock();
pixhawk's avatar
pixhawk committed
184 185
    mavlink_message_t message;
    mavlink_status_t status;
186

187
    for (int position = 0; position < b.size(); position++) {
188
        unsigned int decodeState = mavlink_parse_char(link->getId(), (uint8_t)(b.at(position)), &message, &status);
pixhawk's avatar
pixhawk committed
189

190 191
        if (decodeState == 1)
        {
LM's avatar
LM committed
192 193 194 195 196 197 198 199
//#ifdef MAVLINK_MESSAGE_LENGTHS
//	    const uint8_t message_lengths[] = MAVLINK_MESSAGE_LENGTHS;
//	    if (message.msgid >= sizeof(message_lengths) ||
//		message.len != message_lengths[message.msgid]) {
//                    qDebug() << "MAVLink message " << message.msgid << " length incorrect (was " << message.len << " expected " << message_lengths[message.msgid] << ")";
//		    continue;
//	    }
//#endif
200
#ifdef QGC_PROTOBUF_ENABLED
LM's avatar
LM committed
201

202 203
            if (message.msgid == MAVLINK_MSG_ID_EXTENDED_MESSAGE)
            {
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
                mavlink_extended_message_t extended_message;

                extended_message.base_msg = message;

                // read extended header
                uint8_t* payload = reinterpret_cast<uint8_t*>(message.payload64);
                memcpy(&extended_message.extended_payload_len, payload + 3, 4);

                const uint8_t* extended_payload = reinterpret_cast<const uint8_t*>(b.constData()) + MAVLINK_NUM_NON_PAYLOAD_BYTES + MAVLINK_EXTENDED_HEADER_LEN;

                // copy extended payload data
                memcpy(extended_message.extended_payload, extended_payload, extended_message.extended_payload_len);

                if (protobufManager.cacheFragment(extended_message))
                {
                    std::tr1::shared_ptr<google::protobuf::Message> protobuf_msg;

                    if (protobufManager.getMessage(protobuf_msg))
                    {
                        emit extendedMessageReceived(link, protobuf_msg);
                    }
                }
226 227 228 229

                position += extended_message.extended_payload_len;

                continue;
230 231 232
            }
#endif

pixhawk's avatar
pixhawk committed
233
            // Log data
234 235
            if (m_loggingEnabled && m_logfile)
            {
lm's avatar
lm committed
236
                const int len = MAVLINK_MAX_PACKET_LEN+sizeof(quint64);
237 238
                uint8_t buf[len];
                quint64 time = QGC::groundTimeUsecs();
239
                memcpy(buf, (void*)&time, sizeof(quint64));
240
                // Write message to buffer
241
                mavlink_msg_to_send_buffer(buf+sizeof(quint64), &message);
242
                QByteArray b((const char*)buf, len);
243 244
                if(m_logfile->write(b) < static_cast<qint64>(MAVLINK_MAX_PACKET_LEN+sizeof(quint64)))
                {
245 246 247 248
                    emit protocolStatusMessage(tr("MAVLink Logging failed"), tr("Could not write to file %1, disabling logging.").arg(m_logfile->fileName()));
                    // Stop logging
                    enableLogging(false);
                }
pixhawk's avatar
pixhawk committed
249 250
            }

pixhawk's avatar
pixhawk committed
251 252 253
            // ORDER MATTERS HERE!
            // If the matching UAS object does not yet exist, it has to be created
            // before emitting the packetReceived signal
254

pixhawk's avatar
pixhawk committed
255 256 257
            UASInterface* uas = UASManager::instance()->getUASForId(message.sysid);

            // Check and (if necessary) create UAS object
258 259
            if (uas == NULL && message.msgid == MAVLINK_MSG_ID_HEARTBEAT)
            {
pixhawk's avatar
pixhawk committed
260 261 262 263 264 265
                // ORDER MATTERS HERE!
                // The UAS object has first to be created and connected,
                // only then the rest of the application can be made aware
                // of its existence, as it only then can send and receive
                // it's first messages.

pixhawk's avatar
pixhawk committed
266
                // Check if the UAS has the same id like this system
267 268
                if (message.sysid == getSystemId())
                {
269
                    emit protocolStatusMessage(tr("SYSTEM ID CONFLICT!"), tr("Warning: A second system is using the same system id (%1)").arg(getSystemId()));
270 271
                }

272 273 274 275
                // Create a new UAS based on the heartbeat received
                // Todo dynamically load plugin at run-time for MAV
                // WIKISEARCH:AUTOPILOT_TYPE_INSTANTIATION

pixhawk's avatar
pixhawk committed
276
                // First create new UAS object
277 278
                // Decode heartbeat message
                mavlink_heartbeat_t heartbeat;
pixhawk's avatar
pixhawk committed
279 280
                // Reset version field to 0
                heartbeat.mavlink_version = 0;
281
                mavlink_msg_heartbeat_decode(&message, &heartbeat);
pixhawk's avatar
pixhawk committed
282 283

                // Check if the UAS has a different protocol version
284 285
                if (m_enable_version_check && (heartbeat.mavlink_version != MAVLINK_VERSION))
                {
pixhawk's avatar
pixhawk committed
286
                    // Bring up dialog to inform user
287 288
                    if (!versionMismatchIgnore)
                    {
289
                        emit protocolStatusMessage(tr("The MAVLink protocol version on the MAV and QGroundControl mismatch!"),
290
                                                   tr("It is unsafe to use different MAVLink versions. QGroundControl therefore refuses to connect to system %1, which sends MAVLink version %2 (QGroundControl uses version %3).").arg(message.sysid).arg(heartbeat.mavlink_version).arg(MAVLINK_VERSION));
291 292
                        versionMismatchIgnore = true;
                    }
pixhawk's avatar
pixhawk committed
293 294 295 296 297

                    // Ignore this message and continue gracefully
                    continue;
                }

298 299
                // Create a new UAS object
                uas = QGCMAVLinkUASFactory::createUAS(this, link, message.sysid, &heartbeat);
pixhawk's avatar
pixhawk committed
300
            }
301 302

            // Only count message if UAS exists for this message
303 304
            if (uas != NULL)
            {
305 306 307 308
                // Increase receive counter
                totalReceiveCounter++;
                currReceiveCounter++;
                // Update last packet index
309 310
                if (lastIndex[message.sysid][message.compid] == -1)
                {
311
                    lastIndex[message.sysid][message.compid] = message.seq;
312 313 314
                }
                else
                {
315 316 317
                    uint8_t expectedIndex = lastIndex[message.sysid][message.compid];
                    // Now increase to the expected index
                    expectedIndex++;
318

319 320
                    //qDebug() << "SYSID" << message.sysid << "COMPID" << message.compid << "MSGID" << message.msgid << "EXPECTED INDEX:" << expectedIndex << "SEQ" << message.seq;
                    while(expectedIndex != message.seq)
321
                    {
322
                        expectedIndex++;
323 324
                        totalLossCounter++;
                        currLossCounter++;
325
                        //qDebug() << "COUNTING ONE DROP!";
326
                    }
327 328 329

                    // Set new lastindex
                    lastIndex[message.sysid][message.compid] = message.seq;
330 331 332 333 334 335 336 337 338
                }
                //            if (lastIndex.contains(message.sysid))
                //            {
                //                QMap<int, int>* lastCompIndex = lastIndex.value(message.sysid);
                //                if (lastCompIndex->contains(message.compid))
                //                while (lastCompIndex->value(message.compid, 0)+1 )
                //            }
                //if ()

339 340
                // Update on every 32th packet
                if (totalReceiveCounter % 32 == 0)
341
                {
342 343 344 345 346 347 348
                    // Calculate new loss ratio
                    // Receive loss
                    float receiveLoss = (double)currLossCounter/(double)(currReceiveCounter+currLossCounter);
                    receiveLoss *= 100.0f;
                    // qDebug() << "LOSSCHANGED" << receiveLoss;
                    currLossCounter = 0;
                    currReceiveCounter = 0;
pixhawk's avatar
pixhawk committed
349
                    emit receiveLossChanged(message.sysid, receiveLoss);
Mariano Lizarraga's avatar
Mariano Lizarraga committed
350
                    //qDebug() << "LOSSCHANGED" << message.sysid<<" "<<receiveLoss;
lm's avatar
lm committed
351 352
                }

353 354 355 356
                // The packet is emitted as a whole, as it is only 255 - 261 bytes short
                // kind of inefficient, but no issue for a groundstation pc.
                // It buys as reentrancy for the whole code over all threads
                emit messageReceived(link, message);
357 358

                // Multiplex message if enabled
359 360
                if (m_multiplexingEnabled)
                {
361 362 363 364
                    // Get all links connected to this unit
                    QList<LinkInterface*> links = LinkManager::instance()->getLinksForProtocol(this);

                    // Emit message on all links that are currently connected
365 366
                    foreach (LinkInterface* currLink, links)
                    {
367 368 369 370 371
                        // Only forward this message to the other links,
                        // not the link the message was received on
                        if (currLink != link) sendMessage(currLink, message);
                    }
                }
372
            }
pixhawk's avatar
pixhawk committed
373 374
        }
    }
375
//    receiveMutex.unlock();
pixhawk's avatar
pixhawk committed
376 377 378 379 380 381 382 383 384 385
}

/**
 * @return The name of this protocol
 **/
QString MAVLinkProtocol::getName()
{
    return QString(tr("MAVLink protocol"));
}

386
/** @return System id of this application */
387
int MAVLinkProtocol::getSystemId()
388
{
389 390 391 392 393 394
    return systemId;
}

void MAVLinkProtocol::setSystemId(int id)
{
    systemId = id;
395 396 397
}

/** @return Component id of this application */
398
int MAVLinkProtocol::getComponentId()
399
{
400
    return QGC::defaultComponentId;
401 402
}

pixhawk's avatar
pixhawk committed
403 404 405 406 407 408 409 410 411 412
/**
 * @param message message to send
 */
void MAVLinkProtocol::sendMessage(mavlink_message_t message)
{
    // Get all links connected to this unit
    QList<LinkInterface*> links = LinkManager::instance()->getLinksForProtocol(this);

    // Emit message on all links that are currently connected
    QList<LinkInterface*>::iterator i;
413 414
    for (i = links.begin(); i != links.end(); ++i)
    {
pixhawk's avatar
pixhawk committed
415
        sendMessage(*i, message);
416
        //qDebug() << __FILE__ << __LINE__ << "SENT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size();
pixhawk's avatar
pixhawk committed
417 418 419 420 421 422 423 424 425 426 427
    }
}

/**
 * @param link the link to send the message over
 * @param message message to send
 */
void MAVLinkProtocol::sendMessage(LinkInterface* link, mavlink_message_t message)
{
    // Create buffer
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
428
    // Rewriting header to ensure correct link ID is set
lm's avatar
lm committed
429 430
    static uint8_t messageKeys[256] = MAVLINK_MESSAGE_CRCS;
    if (link->getId() != 0) mavlink_finalize_message_chan(&message, this->getSystemId(), this->getComponentId(), link->getId(), message.len, messageKeys[message.msgid]);
pixhawk's avatar
pixhawk committed
431
    // Write message into buffer, prepending start sign
pixhawk's avatar
pixhawk committed
432
    int len = mavlink_msg_to_send_buffer(buffer, &message);
pixhawk's avatar
pixhawk committed
433
    // If link is connected
434 435
    if (link->isConnected())
    {
pixhawk's avatar
pixhawk committed
436 437 438 439 440 441 442 443 444 445 446 447
        // Send the portion of the buffer now occupied by the message
        link->writeBytes((const char*)buffer, len);
    }
}

/**
 * The heartbeat is sent out of order and does not reset the
 * periodic heartbeat emission. It will be just sent in addition.
 * @return mavlink_message_t heartbeat message sent on serial link
 */
void MAVLinkProtocol::sendHeartbeat()
{
448
    if (m_heartbeatsEnabled) {
pixhawk's avatar
pixhawk committed
449
        mavlink_message_t beat;
lm's avatar
lm committed
450
        mavlink_msg_heartbeat_pack(getSystemId(), getComponentId(),&beat, MAV_TYPE_GCS, MAV_AUTOPILOT_INVALID, MAV_MODE_MANUAL_ARMED, 0, MAV_STATE_ACTIVE);
pixhawk's avatar
pixhawk committed
451 452
        sendMessage(beat);
    }
James Goppert's avatar
James Goppert committed
453 454 455 456 457 458 459 460
    if (m_authEnabled) {
        mavlink_message_t msg;
        mavlink_auth_key_t auth;
        if (m_authKey.length() != MAVLINK_MSG_AUTH_KEY_FIELD_KEY_LEN) m_authKey.resize(MAVLINK_MSG_AUTH_KEY_FIELD_KEY_LEN);
        strcpy(auth.key, m_authKey.toStdString().c_str());
        mavlink_msg_auth_key_encode(getSystemId(), getComponentId(), &msg, &auth);
        sendMessage(msg);
    }
pixhawk's avatar
pixhawk committed
461 462 463 464 465 466 467 468 469
}

/** @param enabled true to enable heartbeats emission at heartbeatRate, false to disable */
void MAVLinkProtocol::enableHeartbeats(bool enabled)
{
    m_heartbeatsEnabled = enabled;
    emit heartbeatChanged(enabled);
}

470 471 472 473 474 475 476 477 478
void MAVLinkProtocol::enableMultiplexing(bool enabled)
{
    bool changed = false;
    if (enabled != m_multiplexingEnabled) changed = true;

    m_multiplexingEnabled = enabled;
    if (changed) emit multiplexingChanged(m_multiplexingEnabled);
}

479 480 481 482
void MAVLinkProtocol::enableAuth(bool enable)
{
    bool changed = false;
    m_authEnabled = enable;
483
    if (m_authEnabled != enable) {
484 485 486 487 488
        changed = true;
    }
    if (changed) emit authChanged(m_authEnabled);
}

489 490
void MAVLinkProtocol::enableParamGuard(bool enabled)
{
491
    if (enabled != m_paramGuardEnabled) {
492 493 494 495 496
        m_paramGuardEnabled = enabled;
        emit paramGuardChanged(m_paramGuardEnabled);
    }
}

497 498
void MAVLinkProtocol::enableActionGuard(bool enabled)
{
499
    if (enabled != m_actionGuardEnabled) {
500 501 502 503 504
        m_actionGuardEnabled = enabled;
        emit actionGuardChanged(m_actionGuardEnabled);
    }
}

505 506
void MAVLinkProtocol::setParamRetransmissionTimeout(int ms)
{
507
    if (ms != m_paramRetransmissionTimeout) {
508 509 510 511 512 513 514
        m_paramRetransmissionTimeout = ms;
        emit paramRetransmissionTimeoutChanged(m_paramRetransmissionTimeout);
    }
}

void MAVLinkProtocol::setParamRewriteTimeout(int ms)
{
515
    if (ms != m_paramRewriteTimeout) {
516 517 518 519 520
        m_paramRewriteTimeout = ms;
        emit paramRewriteTimeoutChanged(m_paramRewriteTimeout);
    }
}

521 522
void MAVLinkProtocol::setActionRetransmissionTimeout(int ms)
{
523
    if (ms != m_actionRetransmissionTimeout) {
524 525 526 527 528
        m_actionRetransmissionTimeout = ms;
        emit actionRetransmissionTimeoutChanged(m_actionRetransmissionTimeout);
    }
}

lm's avatar
lm committed
529 530
void MAVLinkProtocol::enableLogging(bool enabled)
{
531 532 533
    bool changed = false;
    if (enabled != m_loggingEnabled) changed = true;

534 535 536 537
    if (enabled)
    {
        if (m_logfile && m_logfile->isOpen())
        {
538 539 540
            m_logfile->flush();
            m_logfile->close();
        }
541 542 543 544 545

        if (m_logfile)
        {
            if (!m_logfile->open(QIODevice::WriteOnly | QIODevice::Append))
            {
546 547
                emit protocolStatusMessage(tr("Opening MAVLink logfile for writing failed"), tr("MAVLink cannot log to the file %1, please choose a different file. Stopping logging.").arg(m_logfile->fileName()));
                m_loggingEnabled = false;
548
            }
549
        }
550 551 552 553 554 555 556 557 558 559 560
        else
        {
            emit protocolStatusMessage(tr("Opening MAVLink logfile for writing failed"), tr("MAVLink cannot start logging, no logfile selected."));
        }
    }
    else if (!enabled)
    {
        if (m_logfile)
        {
            if (m_logfile->isOpen())
            {
561 562 563
                m_logfile->flush();
                m_logfile->close();
            }
564
        }
lm's avatar
lm committed
565 566
    }
    m_loggingEnabled = enabled;
567
    if (changed) emit loggingChanged(enabled);
568 569 570 571
}

void MAVLinkProtocol::setLogfileName(const QString& filename)
{
572 573
    if (!m_logfile)
    {
574
        m_logfile = new QFile(filename);
575 576 577
    }
    else
    {
578 579 580
        m_logfile->flush();
        m_logfile->close();
    }
581
    m_logfile->setFileName(filename);
582
    enableLogging(m_loggingEnabled);
lm's avatar
lm committed
583 584
}

lm's avatar
lm committed
585 586 587
void MAVLinkProtocol::enableVersionCheck(bool enabled)
{
    m_enable_version_check = enabled;
588
    emit versionCheckChanged(enabled);
lm's avatar
lm committed
589 590
}

pixhawk's avatar
pixhawk committed
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
/**
 * The default rate is 1 Hertz.
 *
 * @param rate heartbeat rate in hertz (times per second)
 */
void MAVLinkProtocol::setHeartbeatRate(int rate)
{
    heartbeatRate = rate;
    heartbeatTimer->setInterval(1000/heartbeatRate);
}

/** @return heartbeat rate in Hertz */
int MAVLinkProtocol::getHeartbeatRate()
{
    return heartbeatRate;
}