From 94348cb74ac192e2d477fa3743cf3e9fbb9c3b08 Mon Sep 17 00:00:00 2001
From: pixhawk <pixhawk@student.ethz.ch>
Date: Sat, 8 Jan 2011 18:23:08 +0100
Subject: [PATCH] Added not yet working version of logging / log replay, fixed
 ALL bugs in main window, enabled full persistence in main window and serial
 link.

---
 qgroundcontrol.pro                  |   9 ++-
 src/QGC.h                           |  31 ++++++++++
 src/comm/MAVLinkProtocol.cc         |  18 ++++--
 src/comm/MAVLinkProtocol.h          |   7 ++-
 src/comm/MAVLinkSimulationLink.cc   |   6 +-
 src/comm/SerialLink.cc              | 113 ++++++++++++++++++++++++++++++++----
 src/comm/SerialLink.h               |   8 +++
 src/comm/SerialLinkInterface.h      |   3 +
 src/comm/UDPLink.cc                 |   2 +-
 src/uas/UAS.cc                      |  12 ++--
 src/uas/UASWaypointManager.cc       |  11 ++--
 src/ui/CommConfigurationWindow.cc   |   6 +-
 src/ui/DebugConsole.cc              |  86 ++++++++++++++++++++++++++-
 src/ui/DebugConsole.h               |   3 +
 src/ui/DebugConsole.ui              |  97 +++++++++++++++++++++++++------
 src/ui/HDDisplay.cc                 |   1 +
 src/ui/MAVLinkSettingsWidget.cc     |  59 +++++++++++++++++++
 src/ui/MAVLinkSettingsWidget.h      |   6 ++
 src/ui/MAVLinkSettingsWidget.ui     |  62 +++++++++++++++-----
 src/ui/MainWindow.cc                |  79 +++++++++++++++++--------
 src/ui/MainWindow.h                 |   6 ++
 src/ui/MainWindow.ui                |  38 +++++++++++-
 src/ui/QGCMAVLinkLogPlayer.cc       | 113 ++++++++++++++++++++++++++++++++++++
 src/ui/QGCMAVLinkLogPlayer.h        |  54 +++++++++++++++++
 src/ui/QGCMAVLinkLogPlayer.ui       | 111 +++++++++++++++++++++++++++++++++++
 src/ui/SerialConfigurationWindow.cc |  29 +++++----
 src/ui/linechart/LinechartWidget.cc |  36 +++++++-----
 src/ui/linechart/LinechartWidget.h  |   1 +
 src/ui/uas/UASControlWidget.cc      |   2 +
 src/ui/uas/UASListWidget.cc         |   1 +
 30 files changed, 881 insertions(+), 129 deletions(-)
 create mode 100644 src/ui/QGCMAVLinkLogPlayer.cc
 create mode 100644 src/ui/QGCMAVLinkLogPlayer.h
 create mode 100644 src/ui/QGCMAVLinkLogPlayer.ui

diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index bcbcd69..81789c5 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -153,7 +153,8 @@ FORMS += src/ui/MainWindow.ui \
     src/ui/uas/QGCUnconnectedInfoWidget.ui \
     src/ui/designer/QGCToolWidget.ui \
     src/ui/designer/QGCParamSlider.ui \
-    src/ui/designer/QGCActionButton.ui
+    src/ui/designer/QGCActionButton.ui \
+    src/ui/QGCMAVLinkLogPlayer.ui
 
 INCLUDEPATH += src \
     src/ui \
@@ -259,7 +260,8 @@ HEADERS += src/MG.h \
     src/ui/designer/QGCToolWidget.h \
     src/ui/designer/QGCParamSlider.h \
     src/ui/designer/QGCActionButton.h \
-    src/ui/designer/QGCToolWidgetItem.h
+    src/ui/designer/QGCToolWidgetItem.h \
+    src/ui/QGCMAVLinkLogPlayer.h
 
 # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler
 macx|win32-msvc2008: {
@@ -380,7 +382,8 @@ SOURCES += src/main.cc \
     src/ui/designer/QGCToolWidget.cc \
     src/ui/designer/QGCParamSlider.cc \
     src/ui/designer/QGCActionButton.cc \
-    src/ui/designer/QGCToolWidgetItem.cc
+    src/ui/designer/QGCToolWidgetItem.cc \
+    src/ui/QGCMAVLinkLogPlayer.cc
 
 macx|win32-msvc2008: {
     SOURCES += src/ui/map3D/QGCGoogleEarthView.cc
diff --git a/src/QGC.h b/src/QGC.h
index 44305dd..3b1d2fd 100644
--- a/src/QGC.h
+++ b/src/QGC.h
@@ -3,6 +3,7 @@
 
 #include <QDateTime>
 #include <QColor>
+#include <QThread>
 
 namespace QGC
 {
@@ -20,6 +21,36 @@ namespace QGC
     const QString APPNAME = "QGROUNDCONTROL";
     const QString COMPANYNAME = "OPENMAV";
     const int APPLICATIONVERSION = 80; // 0.8.0
+
+    class SLEEP : public QThread
+    {
+    public:
+        /**
+         * @brief Set a thread to sleep for seconds
+         * @param s time in seconds to sleep
+         **/
+        static void sleep(unsigned long s)
+        {
+            QThread::sleep(s);
+        }
+        /**
+         * @brief Set a thread to sleep for milliseconds
+         * @param ms time in milliseconds to sleep
+         **/
+        static void msleep(unsigned long ms)
+        {
+            QThread::msleep(ms);
+        }
+        /**
+         * @brief Set a thread to sleep for microseconds
+         * @param us time in microseconds to sleep
+         **/
+        static void usleep(unsigned long us)
+        {
+            QThread::usleep(us);
+        }
+    };
+
 }
 
 #define QGC_EVENTLOOP_DEBUG 0
diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc
index 64fd625..1f68942 100644
--- a/src/comm/MAVLinkProtocol.cc
+++ b/src/comm/MAVLinkProtocol.cc
@@ -59,7 +59,7 @@ MAVLinkProtocol::MAVLinkProtocol() :
         heartbeatRate(MAVLINK_HEARTBEAT_DEFAULT_RATE),
         m_heartbeatsEnabled(false),
         m_loggingEnabled(false),
-        m_logfile(NULL),
+        m_logfile(new QFile(QCoreApplication::applicationDirPath()+"/mavlink.log")),
         m_enable_version_check(true),
         versionMismatchIgnore(false)
 {
@@ -99,7 +99,7 @@ void MAVLinkProtocol::run()
 
 QString MAVLinkProtocol::getLogfileName()
 {
-    return QCoreApplication::applicationDirPath()+"/mavlink.log";
+    return m_logfile->fileName();
 }
 
 /**
@@ -391,21 +391,27 @@ void MAVLinkProtocol::enableLogging(bool enabled)
 {
     if (enabled && !m_loggingEnabled)
     {
-       m_logfile = new QFile(getLogfileName());
+       if (m_logfile->isOpen()) m_logfile->close();
        m_logfile->open(QIODevice::WriteOnly | QIODevice::Append);
     }
-    else
+    else if (!enabled)
     {
        m_logfile->close();
-       delete m_logfile;
-       m_logfile = NULL;
     }
     m_loggingEnabled = enabled;
+    emit loggingChanged(enabled);
+}
+
+void MAVLinkProtocol::setLogfileName(const QString& filename)
+{
+    m_logfile->close();
+    m_logfile->setFileName(filename);
 }
 
 void MAVLinkProtocol::enableVersionCheck(bool enabled)
 {
     m_enable_version_check = enabled;
+    emit versionCheckChanged(enabled);
 }
 
 bool MAVLinkProtocol::heartbeatsEnabled(void)
diff --git a/src/comm/MAVLinkProtocol.h b/src/comm/MAVLinkProtocol.h
index 76171e2..af1ba18 100644
--- a/src/comm/MAVLinkProtocol.h
+++ b/src/comm/MAVLinkProtocol.h
@@ -70,8 +70,10 @@ public:
     bool loggingEnabled(void);
     /** @brief Get protocol version check state */
     bool versionCheckEnabled(void);
+    /** @brief Get the protocol version */
+    int getVersion() { return MAVLINK_VERSION; }
     /** @brief Get the name of the packet log file */
-    static QString getLogfileName();
+    QString getLogfileName();
 
 public slots:
     /** @brief Receive bytes from a communication interface */
@@ -89,6 +91,9 @@ public slots:
     /** @brief Enable/disable binary packet logging */
     void enableLogging(bool enabled);
 
+    /** @brief Set log file name */
+    void setLogfileName(const QString& filename);
+
     /** @brief Enable / disable version check */
     void enableVersionCheck(bool enabled);
 
diff --git a/src/comm/MAVLinkSimulationLink.cc b/src/comm/MAVLinkSimulationLink.cc
index a8043d8..4fb6edc 100644
--- a/src/comm/MAVLinkSimulationLink.cc
+++ b/src/comm/MAVLinkSimulationLink.cc
@@ -97,8 +97,8 @@ MAVLinkSimulationLink::MAVLinkSimulationLink(QString readFile, QString writeFile
     LinkManager::instance()->add(this);
 
     // Open packet log
-    mavlinkLogFile = new QFile(MAVLinkProtocol::getLogfileName());
-    mavlinkLogFile->open(QIODevice::ReadOnly);
+    mavlinkLogFile = new QFile();
+    //mavlinkLogFile->open(QIODevice::ReadOnly);
 }
 
 MAVLinkSimulationLink::~MAVLinkSimulationLink()
@@ -141,7 +141,7 @@ void MAVLinkSimulationLink::run()
             }
             last = MG::TIME::getGroundTimeNow();
         }
-        MG::SLEEP::msleep(2);
+        MG::SLEEP::msleep(3);
 
     }
 }
diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc
index ee320e7..c59aad2 100644
--- a/src/comm/SerialLink.cc
+++ b/src/comm/SerialLink.cc
@@ -108,8 +108,9 @@ void SerialLink::loadSettings()
         setPortName(settings.value("SERIALLINK_COMM_PORT").toString());
         setBaudRateType(settings.value("SERIALLINK_COMM_BAUD").toInt());
         setParityType(settings.value("SERIALLINK_COMM_PARITY").toInt());
-        setStopBitsType(settings.value("SERIALLINK_COMM_STOPBITS").toInt());
-        setDataBitsType(settings.value("SERIALLINK_COMM_DATABITS").toInt());
+        setStopBits(settings.value("SERIALLINK_COMM_STOPBITS").toInt());
+        setDataBits(settings.value("SERIALLINK_COMM_DATABITS").toInt());
+        setFlowType(settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt());
     }
 }
 
@@ -120,8 +121,9 @@ void SerialLink::writeSettings()
     settings.setValue("SERIALLINK_COMM_PORT", this->porthandle);
     settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
     settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
-    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBitsType());
-    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBitsType());
+    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
+    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
+    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
     settings.sync();
 }
 
@@ -316,10 +318,10 @@ bool SerialLink::hardwareConnect()
     {
         emit connected();
         emit connected(true);
-
-        writeSettings();
     }
 
+    writeSettings();
+
     return connectionUp;
 }
 
@@ -531,6 +533,48 @@ int SerialLink::getStopBitsType()
     return stopBits;
 }
 
+int SerialLink::getDataBits()
+{
+    int ret;
+    switch (dataBits)
+    {
+    case DATA_5:
+        ret = 5;
+        break;
+    case DATA_6:
+        ret = 6;
+        break;
+    case DATA_7:
+        ret = 7;
+        break;
+    case DATA_8:
+        ret = 8;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+int SerialLink::getStopBits()
+{
+    int ret;
+    switch (stopBits)
+    {
+    case STOP_1:
+        ret = 1;
+        break;
+    case STOP_2:
+        ret = 2;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
 bool SerialLink::setPortName(QString portName)
 {
     if(portName.trimmed().length() > 0)
@@ -845,8 +889,7 @@ bool SerialLink::setParityType(int parity)
 }
 
 
-// FIXME Works not as anticipated by user!
-bool SerialLink::setDataBitsType(int dataBits)
+bool SerialLink::setDataBits(int dataBits)
 {
     bool accepted = true;
 
@@ -879,12 +922,12 @@ bool SerialLink::setDataBitsType(int dataBits)
     return accepted;
 }
 
-// FIXME WORKS NOT AS ANTICIPATED BY USER!
-bool SerialLink::setStopBitsType(int stopBits)
+bool SerialLink::setStopBits(int stopBits)
 {
     bool reconnect = false;
     bool accepted = true;
-    if(isConnected()) {
+    if(isConnected())
+    {
         disconnect();
         reconnect = true;
     }
@@ -907,3 +950,51 @@ bool SerialLink::setStopBitsType(int stopBits)
     if(reconnect) connect();
     return accepted;
 }
+
+bool SerialLink::setDataBitsType(int dataBits)
+{
+    bool reconnect = false;
+    bool accepted = false;
+
+    if (isConnected())
+    {
+        disconnect();
+        reconnect = true;
+    }
+
+    if (dataBits >= (int)DATA_5 && dataBits <= (int)DATA_8)
+    {
+        DataBitsType newBits = (DataBitsType) dataBits;
+
+        port->setDataBits(newBits);
+        if(reconnect)
+        {
+            connect();
+        }
+        accepted = true;
+    }
+
+    return accepted;
+}
+
+bool SerialLink::setStopBitsType(int stopBits)
+{
+    bool reconnect = false;
+    bool accepted = false;
+    if(isConnected())
+    {
+        disconnect();
+        reconnect = true;
+    }
+
+    if (stopBits >= (int)STOP_1 && dataBits <= (int)STOP_2)
+    {
+        StopBitsType newBits = (StopBitsType) stopBits;
+
+        port->setStopBits(newBits);
+        accepted = true;
+    }
+
+    if(reconnect) connect();
+    return accepted;
+}
diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h
index 3bac202..b352ad9 100644
--- a/src/comm/SerialLink.h
+++ b/src/comm/SerialLink.h
@@ -74,6 +74,10 @@ public:
      */
     QString getName();
     int getBaudRate();
+    int getDataBits();
+    int getStopBits();
+
+    // ENUM values
     int getBaudRateType();
     int getFlowType();
     int getParityType();
@@ -103,6 +107,10 @@ public:
 public slots:
     bool setPortName(QString portName);
     bool setBaudRate(int rate);
+    bool setDataBits(int dataBits);
+    bool setStopBits(int stopBits);
+
+    // Set ENUM values
     bool setBaudRateType(int rateIndex);
     bool setFlowType(int flow);
     bool setParityType(int parity);
diff --git a/src/comm/SerialLinkInterface.h b/src/comm/SerialLinkInterface.h
index 49b5335..ff16a66 100644
--- a/src/comm/SerialLinkInterface.h
+++ b/src/comm/SerialLinkInterface.h
@@ -43,6 +43,9 @@ class SerialLinkInterface : public LinkInterface {
 public:
 	virtual QString getPortName() = 0;
 	virtual int getBaudRate() = 0;
+        virtual int getDataBits() = 0;
+        virtual int getStopBits() = 0;
+
 	virtual int getBaudRateType() = 0;
 	virtual int getFlowType() = 0;
 	virtual int getParityType() = 0;
diff --git a/src/comm/UDPLink.cc b/src/comm/UDPLink.cc
index 0574c1e..5fcc271 100644
--- a/src/comm/UDPLink.cc
+++ b/src/comm/UDPLink.cc
@@ -49,7 +49,7 @@ UDPLink::UDPLink(QHostAddress host, quint16 port)
 
     // Set unique ID and add link to the list of links
     this->id = getNextLinkId();
-    this->name = tr("UDP link ") + QString::number(getId());
+    this->name = tr("UDP Link (port:%1)").arg(14550);
     LinkManager::instance()->add(this);
 }
 
diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc
index 6887ead..7640a07 100644
--- a/src/uas/UAS.cc
+++ b/src/uas/UAS.cc
@@ -663,12 +663,12 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message)
                 mavlink_nav_filter_bias_t bias;
                 mavlink_msg_nav_filter_bias_decode(&message, &bias);
                 quint64 time = MG::TIME::getGroundTimeNow();
-                emit valueChanged(uasId, "b_f[0]", bias.accel_0, time);
-                emit valueChanged(uasId, "b_f[1]", bias.accel_1, time);
-                emit valueChanged(uasId, "b_f[2]", bias.accel_2, time);
-                emit valueChanged(uasId, "b_w[0]", bias.gyro_0, time);
-                emit valueChanged(uasId, "b_w[1]", bias.gyro_1, time);
-                emit valueChanged(uasId, "b_w[2]", bias.gyro_2, time);
+                emit valueChanged(uasId, "b_f[0]", "raw", bias.accel_0, time);
+                emit valueChanged(uasId, "b_f[1]", "raw", bias.accel_1, time);
+                emit valueChanged(uasId, "b_f[2]", "raw", bias.accel_2, time);
+                emit valueChanged(uasId, "b_w[0]", "raw", bias.gyro_0, time);
+                emit valueChanged(uasId, "b_w[1]", "raw", bias.gyro_1, time);
+                emit valueChanged(uasId, "b_w[2]", "raw", bias.gyro_2, time);
             }
             break;
        case MAVLINK_MSG_ID_RADIO_CALIBRATION:
diff --git a/src/uas/UASWaypointManager.cc b/src/uas/UASWaypointManager.cc
index 0b03967..0c3581e 100644
--- a/src/uas/UASWaypointManager.cc
+++ b/src/uas/UASWaypointManager.cc
@@ -55,6 +55,7 @@ void UASWaypointManager::timeout()
     {
         protocol_timer.start(PROTOCOL_TIMEOUT_MS);
         current_retries--;
+        emit updateStatusString(tr("Timeout, retrying (retries left: %1)").arg(current_retries));
         qDebug() << "Timeout, retrying (retries left:" << current_retries << ")";
         if (current_state == WP_GETLIST)
         {
@@ -517,7 +518,7 @@ void UASWaypointManager::sendWaypointClearAll()
     wpca.target_system = uas.getUASID();
     wpca.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
 
-    emit updateStatusString(QString("clearing waypoint list..."));
+    emit updateStatusString(QString("Clearing waypoint list..."));
 
     mavlink_msg_waypoint_clear_all_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpca);
     uas.sendMessage(message);
@@ -554,7 +555,7 @@ void UASWaypointManager::sendWaypointCount()
     wpc.count = current_count;
 
     qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
-    emit updateStatusString(QString("start transmitting waypoints..."));
+    emit updateStatusString(QString("Starting to transmit waypoints..."));
 
     mavlink_msg_waypoint_count_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpc);
     uas.sendMessage(message);
@@ -571,7 +572,7 @@ void UASWaypointManager::sendWaypointRequestList()
     wprl.target_system = uas.getUASID();
     wprl.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
 
-    emit updateStatusString(QString("requesting waypoint list..."));
+    emit updateStatusString(QString("Requesting waypoint list..."));
 
     mavlink_msg_waypoint_request_list_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wprl);
     uas.sendMessage(message);
@@ -591,7 +592,7 @@ void UASWaypointManager::sendWaypointRequest(quint16 seq)
     wpr.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
     wpr.seq = seq;
 
-    emit updateStatusString(QString("retrieving waypoint ID %1 of %2 total").arg(wpr.seq).arg(current_count));
+    emit updateStatusString(QString("Retrieving waypoint ID %1 of %2 total").arg(wpr.seq).arg(current_count));
 
     mavlink_msg_waypoint_request_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpr);
     uas.sendMessage(message);
@@ -612,7 +613,7 @@ void UASWaypointManager::sendWaypoint(quint16 seq)
         wp->target_system = uas.getUASID();
         wp->target_component = MAV_COMP_ID_WAYPOINTPLANNER;
 
-        emit updateStatusString(QString("sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count));
+        emit updateStatusString(QString("Sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count));
 
         mavlink_msg_waypoint_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, wp);
         uas.sendMessage(message);
diff --git a/src/ui/CommConfigurationWindow.cc b/src/ui/CommConfigurationWindow.cc
index 33e57ba..484290d 100644
--- a/src/ui/CommConfigurationWindow.cc
+++ b/src/ui/CommConfigurationWindow.cc
@@ -106,7 +106,7 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn
         QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, ui.linkGroupBox);
         layout->addWidget(conf);
         ui.linkGroupBox->setLayout(layout);
-        ui.linkGroupBox->setTitle(tr("serial link"));
+        ui.linkGroupBox->setTitle(tr("Serial Link"));
         //ui.linkGroupBox->setTitle(link->getName());
         //connect(link, SIGNAL(nameChanged(QString)), ui.linkGroupBox, SLOT(setTitle(QString)));
     }
@@ -142,13 +142,13 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn
 
     // Open details pane for MAVLink if necessary
     MAVLinkProtocol* mavlink = dynamic_cast<MAVLinkProtocol*>(protocol);
-    if(mavlink != 0)
+    if (mavlink != 0)
     {
         QWidget* conf = new MAVLinkSettingsWidget(mavlink, this);
         QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, ui.protocolGroupBox);
         layout->addWidget(conf);
         ui.protocolGroupBox->setLayout(layout);
-        ui.protocolGroupBox->setTitle(protocol->getName());
+        ui.protocolGroupBox->setTitle(protocol->getName()+" (Global Settings)");
     }
     else
     {
diff --git a/src/ui/DebugConsole.cc b/src/ui/DebugConsole.cc
index f5af15c..a808812 100644
--- a/src/ui/DebugConsole.cc
+++ b/src/ui/DebugConsole.cc
@@ -105,6 +105,8 @@ DebugConsole::DebugConsole(QWidget *parent) :
     connect(m_ui->holdButton, SIGNAL(toggled(bool)), this, SLOT(hold(bool)));
     // Connect connect button
     connect(m_ui->connectButton, SIGNAL(clicked()), this, SLOT(handleConnectButton()));
+    // Connect the special chars combo box
+    connect(m_ui->specialComboBox, SIGNAL(activated(QString)), this, SLOT(appendSpecialSymbol(QString)));
 
     this->setVisible(false);
 }
@@ -327,8 +329,78 @@ void DebugConsole::receiveBytes(LinkInterface* link, QByteArray bytes)
     }
 }
 
+QByteArray DebugConsole::symbolNameToBytes(const QString& text)
+{
+    QByteArray b;
+    if (text == "LF")
+    {
+        b.append(static_cast<char>(0x0A));
+    }
+    else if (text == "FF")
+    {
+        b.append(static_cast<char>(0x0C));
+    }
+    else if (text == "CR")
+    {
+        b.append(static_cast<char>(0x0D));
+    }
+    else if (text == "CR+LF")
+    {
+        b.append(static_cast<char>(0x0D));
+        b.append(static_cast<char>(0x0A));
+    }
+    else if (text == "TAB")
+    {
+        b.append(static_cast<char>(0x09));
+    }
+    else if (text == "NUL")
+    {
+        b.append(static_cast<char>(0x00));
+    }
+    else if (text == "ESC")
+    {
+        b.append(static_cast<char>(0x1B));
+    }
+    else if (text == "~")
+    {
+        b.append(static_cast<char>(0x7E));
+    }
+    else if (text == "<Space>")
+    {
+        b.append(static_cast<char>(0x20));
+    }
+    return b;
+}
+
+void DebugConsole::appendSpecialSymbol(const QString& text)
+{
+    QString line = m_ui->sendText->text();
+    QByteArray symbols = symbolNameToBytes(text);
+    // The text is appended to the enter field
+    if (convertToAscii)
+    {
+        line.append(symbols);
+    }
+    else
+    {
+
+        for (int i = 0; i < symbols.size(); i++)
+        {
+            QString add(" 0x%1");
+            line.append(add.arg(static_cast<char>(symbols.at(i)), 2, 16, QChar('0')));
+        }
+    }
+    m_ui->sendText->setText(line);
+}
+
 void DebugConsole::sendBytes()
 {
+    if (!currLink->isConnected())
+    {
+        m_ui->sentText->setText(tr("Nothing sent. The link %1 is unconnected. Please connect first.").arg(currLink->getName()));
+        return;
+    }
+
     QByteArray transmit;
     QString feedback;
     bool ok = true;
@@ -382,8 +454,16 @@ void DebugConsole::sendBytes()
     if (ok && m_ui->sendText->text().toLatin1().size() > 0)
     {
         // Transmit only if conversion succeeded
-        currLink->writeBytes(transmit, transmit.size());
-        m_ui->sentText->setText(tr("Sent: ") + feedback);
+//        int transmitted =
+                currLink->writeBytes(transmit, transmit.size());
+//        if (transmit.size() == transmitted)
+//        {
+            m_ui->sentText->setText(tr("Sent: ") + feedback);
+//        }
+//        else
+//        {
+//            m_ui->sentText->setText(tr("Error during sending: Transmitted only %1 bytes instead of %2.").arg(transmitted, transmit.size()));
+//        }
     }
     else if (m_ui->sendText->text().toLatin1().size() > 0)
     {
@@ -403,6 +483,8 @@ void DebugConsole::hexModeEnabled(bool mode)
 {
     convertToAscii = !mode;
     m_ui->receiveText->clear();
+    m_ui->sendText->clear();
+    m_ui->sentText->clear();
 }
 
 /**
diff --git a/src/ui/DebugConsole.h b/src/ui/DebugConsole.h
index e3622ee..be064fe 100644
--- a/src/ui/DebugConsole.h
+++ b/src/ui/DebugConsole.h
@@ -83,6 +83,8 @@ public slots:
     void setAutoHold(bool hold);
     /** @brief Receive plain text message to output to the user */
     void receiveTextMessage(int id, int component, int severity, QString text);
+    /** @brief Append a special symbol */
+    void appendSpecialSymbol(const QString& text);
 
     protected slots:
     /** @brief Draw information overlay */
@@ -92,6 +94,7 @@ public slots:
 
 protected:
     void changeEvent(QEvent *e);
+    QByteArray symbolNameToBytes(const QString& symbol);
 
     QList<LinkInterface*> links;
     LinkInterface* currLink;
diff --git a/src/ui/DebugConsole.ui b/src/ui/DebugConsole.ui
index 6a32b3e..e22d2f2 100644
--- a/src/ui/DebugConsole.ui
+++ b/src/ui/DebugConsole.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>463</width>
-    <height>159</height>
+    <width>447</width>
+    <height>181</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -106,25 +106,75 @@
      </property>
     </widget>
    </item>
-   <item row="3" column="0">
-    <widget class="QLineEdit" name="sendText">
-     <property name="minimumSize">
-      <size>
-       <width>80</width>
-       <height>0</height>
-      </size>
-     </property>
-     <property name="toolTip">
-      <string>Type the bytes to send here, use 0xAA format for HEX (Check HEX checkbox above)</string>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="1">
-    <layout class="QHBoxLayout" name="horizontalLayout" stretch="10,10,10,0">
+   <item row="4" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,10,10,10,0">
      <property name="spacing">
       <number>5</number>
      </property>
      <item>
+      <widget class="QComboBox" name="specialComboBox">
+       <property name="maxVisibleItems">
+        <number>10</number>
+       </property>
+       <property name="sizeAdjustPolicy">
+        <enum>QComboBox::AdjustToContentsOnFirstShow</enum>
+       </property>
+       <property name="minimumContentsLength">
+        <number>1</number>
+       </property>
+       <item>
+        <property name="text">
+         <string>Add..</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>CR+LF</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>LF</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>FF</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>CR</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>TAB</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>NUL</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>ESC</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>~</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>&lt;Space&gt;</string>
+        </property>
+       </item>
+      </widget>
+     </item>
+     <item>
       <widget class="QPushButton" name="transmitButton">
        <property name="toolTip">
         <string>Send the ASCII text or HEX values over the link</string>
@@ -164,6 +214,19 @@
      </item>
     </layout>
    </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QLineEdit" name="sendText">
+     <property name="minimumSize">
+      <size>
+       <width>80</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="toolTip">
+      <string>Type the bytes to send here, use 0xAA format for HEX (Check HEX checkbox above)</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources>
diff --git a/src/ui/HDDisplay.cc b/src/ui/HDDisplay.cc
index dc17eee..8705466 100644
--- a/src/ui/HDDisplay.cc
+++ b/src/ui/HDDisplay.cc
@@ -812,6 +812,7 @@ float HDDisplay::refLineWidthToPen(float line)
 void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec)
 {
     Q_UNUSED(uasId);
+    Q_UNUSED(unit);
     // Update mean
     const float oldMean = valuesMean.value(name, 0.0f);
     const int meanCount = valuesCount.value(name, 0);
diff --git a/src/ui/MAVLinkSettingsWidget.cc b/src/ui/MAVLinkSettingsWidget.cc
index 054ff10..7cb49ec 100644
--- a/src/ui/MAVLinkSettingsWidget.cc
+++ b/src/ui/MAVLinkSettingsWidget.cc
@@ -27,6 +27,11 @@ This file is part of the QGROUNDCONTROL project
  *   @author Lorenz Meier <mail@qgroundcontrol.org>
  */
 
+#include <QFileInfo>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QDesktopServices>
+
 #include "MAVLinkSettingsWidget.h"
 #include "ui_MAVLinkSettingsWidget.h"
 
@@ -37,6 +42,8 @@ MAVLinkSettingsWidget::MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget
 {
     m_ui->setupUi(this);
 
+    m_ui->gridLayout->setAlignment(Qt::AlignTop);
+
     // Initialize state
     m_ui->heartbeatCheckBox->setChecked(protocol->heartbeatsEnabled());
     m_ui->loggingCheckBox->setChecked(protocol->loggingEnabled());
@@ -49,7 +56,59 @@ MAVLinkSettingsWidget::MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget
     connect(m_ui->loggingCheckBox, SIGNAL(toggled(bool)), protocol, SLOT(enableLogging(bool)));
     connect(protocol, SIGNAL(versionCheckChanged(bool)), m_ui->versionCheckBox, SLOT(setChecked(bool)));
     connect(m_ui->versionCheckBox, SIGNAL(toggled(bool)), protocol, SLOT(enableVersionCheck(bool)));
+    connect(m_ui->logFileButton, SIGNAL(clicked()), this, SLOT(chooseLogfileName()));
+
+    // Update values
+    m_ui->versionLabel->setText(tr("MAVLINK_VERSION: %1").arg(protocol->getVersion()));
+    updateLogfileName(protocol->getLogfileName());
+
+    // Connect visibility updates
+    connect(protocol, SIGNAL(versionCheckChanged(bool)), m_ui->versionLabel, SLOT(setVisible(bool)));
+    m_ui->versionLabel->setVisible(protocol->versionCheckEnabled());
+    //connect(m_ui->versionCheckBox, SIGNAL(toggled(bool)), m_ui->versionSpacer, SLOT(setVisible(bool)));
+    //connect(m_ui->loggingCheckBox, SIGNAL(toggled(bool)), m_ui->logFileSpacer, SLOT(setVisible(bool)));
+    connect(protocol, SIGNAL(loggingChanged(bool)), m_ui->logFileLabel, SLOT(setVisible(bool)));
+    m_ui->logFileLabel->setVisible(protocol->loggingEnabled());
+    connect(protocol, SIGNAL(loggingChanged(bool)), m_ui->logFileButton, SLOT(setVisible(bool)));
+    m_ui->logFileButton->setVisible(protocol->loggingEnabled());
+
+    // Update settings
+    m_ui->loggingCheckBox->setChecked(protocol->loggingEnabled());
+    m_ui->heartbeatCheckBox->setChecked(protocol->heartbeatsEnabled());
+    m_ui->versionCheckBox->setChecked(protocol->versionCheckEnabled());
+}
 
+void MAVLinkSettingsWidget::updateLogfileName(const QString& fileName)
+{
+    QFileInfo file(fileName);
+    m_ui->logFileLabel->setText(file.fileName());
+}
+
+void MAVLinkSettingsWidget::chooseLogfileName()
+{
+    QString fileName = QFileDialog::getSaveFileName(this, tr("Specify MAVLink log file name"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("MAVLink Logfile (*.mavlink);;"));
+
+    if (!fileName.endsWith(".mavlink"))
+    {
+        fileName.append(".mavlink");
+    }
+
+    QFileInfo file(fileName);
+    if (file.exists() && !file.isWritable())
+    {
+        QMessageBox msgBox;
+        msgBox.setIcon(QMessageBox::Critical);
+        msgBox.setText(tr("The selected logfile is not writable"));
+        msgBox.setInformativeText(tr("Please make sure that the file %1 is writable or select a different file").arg(fileName));
+        msgBox.setStandardButtons(QMessageBox::Ok);
+        msgBox.setDefaultButton(QMessageBox::Ok);
+        msgBox.exec();
+    }
+    else
+    {
+        updateLogfileName(fileName);
+        protocol->setLogfileName(fileName);
+    }
 }
 
 MAVLinkSettingsWidget::~MAVLinkSettingsWidget()
diff --git a/src/ui/MAVLinkSettingsWidget.h b/src/ui/MAVLinkSettingsWidget.h
index 0941b2b..c6f28c7 100644
--- a/src/ui/MAVLinkSettingsWidget.h
+++ b/src/ui/MAVLinkSettingsWidget.h
@@ -15,6 +15,12 @@ public:
     MAVLinkSettingsWidget(MAVLinkProtocol* protocol, QWidget *parent = 0);
     ~MAVLinkSettingsWidget();
 
+public slots:
+    /** @brief Update the log file name display */
+    void updateLogfileName(const QString& fileName);
+    /** @brief Start the file select dialog for the log file */
+    void chooseLogfileName();
+
 protected:
     MAVLinkProtocol* protocol;
     void changeEvent(QEvent *e);
diff --git a/src/ui/MAVLinkSettingsWidget.ui b/src/ui/MAVLinkSettingsWidget.ui
index c24aadd..5f96e68 100644
--- a/src/ui/MAVLinkSettingsWidget.ui
+++ b/src/ui/MAVLinkSettingsWidget.ui
@@ -6,51 +6,85 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>267</width>
-    <height>123</height>
+    <width>361</width>
+    <height>145</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="margin">
-    <number>6</number>
-   </property>
-   <item>
+  <layout class="QGridLayout" name="gridLayout" columnstretch="1,100,1">
+   <item row="0" column="0" colspan="3">
     <widget class="QCheckBox" name="heartbeatCheckBox">
      <property name="text">
       <string>Emit heartbeat</string>
      </property>
     </widget>
    </item>
-   <item>
+   <item row="1" column="0" colspan="3">
     <widget class="QCheckBox" name="loggingCheckBox">
      <property name="text">
       <string>Log all MAVLink packets</string>
      </property>
     </widget>
    </item>
-   <item>
+   <item row="3" column="0">
+    <spacer name="logFileSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::MinimumExpanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>8</width>
+       <height>0</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="4" column="0" colspan="3">
     <widget class="QCheckBox" name="versionCheckBox">
      <property name="text">
       <string>Only accept MAVs with same protocol version</string>
      </property>
     </widget>
    </item>
-   <item>
-    <spacer name="verticalSpacer">
+   <item row="5" column="0">
+    <spacer name="versionSpacer">
      <property name="orientation">
-      <enum>Qt::Vertical</enum>
+      <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
-       <width>20</width>
-       <height>84</height>
+       <width>8</width>
+       <height>0</height>
       </size>
      </property>
     </spacer>
    </item>
+   <item row="5" column="1" colspan="2">
+    <widget class="QLabel" name="versionLabel">
+     <property name="text">
+      <string>MAVLINK_VERSION: </string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="QLabel" name="logFileLabel">
+     <property name="text">
+      <string>Logfile name</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="2">
+    <widget class="QPushButton" name="logFileButton">
+     <property name="text">
+      <string>Select..</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc
index 58df251..874da1a 100644
--- a/src/ui/MainWindow.cc
+++ b/src/ui/MainWindow.cc
@@ -27,6 +27,7 @@
 #include "JoystickWidget.h"
 #include "GAudioOutput.h"
 #include "QGCToolWidget.h"
+#include "QGCMAVLinkLogPlayer.h"
 
 #ifdef QGC_OSG_ENABLED
 #include "Q3DWidgetFactory.h"
@@ -65,6 +66,7 @@ MainWindow::MainWindow(QWidget *parent):
         toolsMenuActions(),
         currentView(VIEW_ENGINEER),
         aboutToCloseFlag(false),
+        changingViewsFlag(false),
         settings()
 {
     // Get current settings
@@ -128,6 +130,8 @@ MainWindow::MainWindow(QWidget *parent):
     // Setup user interface
     ui.setupUi(this);
 
+    setVisible(false);
+
     // Bind together the perspective actions
     QActionGroup* perspectives = new QActionGroup(ui.menuPerspectives);
     perspectives->addAction(ui.actionEngineersView);
@@ -145,7 +149,6 @@ MainWindow::MainWindow(QWidget *parent):
     // The pilot view is not available on startup
     ui.actionPilotsView->setEnabled(false);
 
-
     buildCommonWidgets();
 
     connectCommonWidgets();
@@ -154,9 +157,6 @@ MainWindow::MainWindow(QWidget *parent):
 
     configureWindowName();
 
-    // Add status bar
-    //setStatusBar(createStatusBar());
-
     // Set the application style (not the same as a style sheet)
     // Set the style to Plastique
     qApp->setStyle("plastique");
@@ -205,6 +205,8 @@ MainWindow::MainWindow(QWidget *parent):
         this->addLink(link);
     }
 
+    connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));
+
     // Enable and update view
     presentView();
 }
@@ -234,6 +236,7 @@ void MainWindow::buildCommonWidgets()
     if (!controlDockWidget)
     {
         controlDockWidget = new QDockWidget(tr("Control"), this);
+        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
         controlDockWidget->setWidget( new UASControlWidget(this) );
         addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget()), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
     }
@@ -242,6 +245,7 @@ void MainWindow::buildCommonWidgets()
     {
         listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
         listDockWidget->setWidget( new UASListWidget(this) );
+        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
         addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget()), MENU_UAS_LIST, Qt::RightDockWidgetArea);
     }
 
@@ -249,6 +253,7 @@ void MainWindow::buildCommonWidgets()
     {
         waypointsDockWidget = new QDockWidget(tr("Waypoint List"), this);
         waypointsDockWidget->setWidget( new WaypointList(this, NULL) );
+        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
         addToToolsMenu (waypointsDockWidget, tr("Waypoints List"), SLOT(showToolWidget()), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
     }
 
@@ -263,9 +268,18 @@ void MainWindow::buildCommonWidgets()
     {
         debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
         debugConsoleDockWidget->setWidget( new DebugConsole(this) );
+        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
         addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget()), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
     }
 
+    if (!logPlayerDockWidget)
+    {
+        logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
+        logPlayerDockWidget->setWidget( new QGCMAVLinkLogPlayer(mavlink, this) );
+        logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
+        addToToolsMenu(logPlayerDockWidget, tr("MAVLink Log Replay"), SLOT(showToolWidget()), MENU_MAVLINK_LOG_PLAYER, Qt::RightDockWidgetArea);
+    }
+
     // Center widgets
     if (!mapWidget)
     {
@@ -376,6 +390,7 @@ void MainWindow::buildPxWidgets()
     {
         hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
         hsiDockWidget->setWidget( new HSIDisplay(this) );
+        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
         addToToolsMenu (hsiDockWidget, tr("HSI"), SLOT(showToolWidget()), MENU_HSI, Qt::BottomDockWidgetArea);
     }
 
@@ -383,6 +398,7 @@ void MainWindow::buildPxWidgets()
     {
         headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
         headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
+        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
         addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget()), MENU_HDD_1, Qt::RightDockWidgetArea);
     }
 
@@ -390,6 +406,7 @@ void MainWindow::buildPxWidgets()
     {
         headDown2DockWidget = new QDockWidget(tr("Payload Status"), this);
         headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Payload Status", this) );
+        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
         addToToolsMenu (headDown2DockWidget, tr("Payload Status"), SLOT(showToolWidget()), MENU_HDD_2, Qt::RightDockWidgetArea);
     }
 
@@ -397,6 +414,7 @@ void MainWindow::buildPxWidgets()
     {
         rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
         rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
+        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
         addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
     }
 
@@ -404,6 +422,7 @@ void MainWindow::buildPxWidgets()
     {
         headUpDockWidget = new QDockWidget(tr("HUD"), this);
         headUpDockWidget->setWidget( new HUD(320, 240, this));
+        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
         addToToolsMenu (headUpDockWidget, tr("Control Indicator"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
     }
 
@@ -525,10 +544,12 @@ void MainWindow::showCentralWidget()
 
         // uncheck all central widget actions
         QHashIterator<int, QAction*> i(toolsMenuActions);
-        while (i.hasNext()) {
+        while (i.hasNext())
+        {
             i.next();
-            qDebug() << "shCW" << i.key() << "read";
-            if (i.value() && i.value()->data().toInt() > 255){
+            //qDebug() << "shCW" << i.key() << "read";
+            if (i.value() && i.value()->data().toInt() > 255)
+            {
                 i.value()->setChecked(false);
 
                 // update the settings
@@ -538,7 +559,7 @@ void MainWindow::showCentralWidget()
         }
 
         // check the current action
-        qDebug() << senderAction->text();
+        //qDebug() << senderAction->text();
         senderAction->setChecked(true);
 
         // update the central widget
@@ -547,7 +568,6 @@ void MainWindow::showCentralWidget()
         // store the selected central widget
         chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
         settings.setValue(chKey,true);
-        settings.sync();
 
         presentView();
     }
@@ -584,7 +604,7 @@ void MainWindow::addToToolsMenu ( QWidget* widget,
     // populate the Hashes
     toolsMenuActions[tool] = tempAction;
     dockWidgets[tool] = widget;
-    qDebug() << widget;
+    //qDebug() << widget;
 
     posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
 
@@ -649,7 +669,7 @@ void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
     Qt::DockWidgetArea tempLocation;
     QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
 
-    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,widget,view), false).toBool();
+    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
 
     if (tempWidget)
     {
@@ -708,16 +728,11 @@ void MainWindow::closeEvent(QCloseEvent *event)
     QMainWindow::closeEvent(event);
 }
 
-/**
- * Stores the visibility setting of each widget. This method
- * will only change the settings if the application is not
- * about to close.
- */
+
 void MainWindow::updateVisibilitySettings (bool vis)
 {
-    if (!aboutToCloseFlag)
+    if (!aboutToCloseFlag && !changingViewsFlag)
     {
-
         QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
 
         if (temp)
@@ -730,7 +745,6 @@ void MainWindow::updateVisibilitySettings (bool vis)
                 {
                     QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                     settings.setValue(chKey,vis);
-                    settings.sync();
                     toolsMenuActions[i.key()]->setChecked(vis);
                     break;
                 }
@@ -781,7 +795,7 @@ void MainWindow::connectCommonWidgets()
 
 void MainWindow::createCustomWidget()
 {
-    qDebug() << "ADDING CUSTOM WIDGET";
+    //qDebug() << "ADDING CUSTOM WIDGET";
     QGCToolWidget* tool = new QGCToolWidget(this);
     QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
     dock->setWidget(tool);
@@ -1028,6 +1042,7 @@ void MainWindow::connectCommonActions()
 
     // Connect internal actions
     connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
+    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
 
     // Unmanned System controls
     connect(ui.actionLiftoff, SIGNAL(triggered()), UASManager::instance(), SLOT(launchActiveUAS()));
@@ -1132,6 +1147,8 @@ void MainWindow::addLink(LinkInterface *link)
     CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
     ui.menuNetwork->addAction(commWidget->getAction());
 
+    //qDebug() << "ADDING LINK:" << link->getName() << "ACTION IS: " << commWidget->getAction();
+
     // Special case for simulationlink
     MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
     if (sim)
@@ -1141,6 +1158,13 @@ void MainWindow::addLink(LinkInterface *link)
     }
 }
 
+void MainWindow::setActiveUAS(UASInterface* uas)
+{
+    // Enable and rename menu
+    ui.menuUnmanned_System->setTitle(uas->getUASName());
+    if (!ui.menuUnmanned_System->isEnabled()) ui.menuUnmanned_System->setEnabled(true);
+}
+
 void MainWindow::UASCreated(UASInterface* uas)
 {
 
@@ -1269,7 +1293,7 @@ void MainWindow::UASCreated(UASInterface* uas)
         // the currently active UAS
         if (UASManager::instance()->getActiveUAS() == uas)
         {
-            qDebug() << "UPDATING THE VIEW SINCE THIS IS THE FIRST CONNECTED SYSTEM";
+            //qDebug() << "UPDATING THE VIEW SINCE THIS IS THE FIRST CONNECTED SYSTEM";
 
             // Load last view if setting is present
             if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
@@ -1292,6 +1316,8 @@ void MainWindow::UASCreated(UASInterface* uas)
         }
 
     }
+
+    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
 }
 
 /**
@@ -1313,16 +1339,17 @@ void MainWindow::clearView()
 
         if (temp)
         {
+            //qDebug() << "TOOL:" << chKey << "IS:" << temp->isChecked();
             settings.setValue(chKey,temp->isChecked());
         }
         else
         {
+            //qDebug() << "TOOL:" << chKey << "IS DEFAULT AND UNCHECKED";
             settings.setValue(chKey,false);
         }
     }
 
-    settings.sync();
-
+    changingViewsFlag = true;
     // Remove all dock widgets from main window
     QObjectList childList( this->children() );
 
@@ -1341,6 +1368,7 @@ void MainWindow::clearView()
             // Is there a way to unset a widget from QDockWidget?
         }
     }
+    changingViewsFlag = false;
 }
 
 void MainWindow::loadEngineerView()
@@ -1490,6 +1518,9 @@ void MainWindow::presentView()
     // HEAD DOWN 2
     showTheWidget(MENU_HDD_2, currentView);
 
+    // MAVLINK LOG PLAYER
+    showTheWidget(MENU_MAVLINK_LOG_PLAYER, currentView);
+
     this->show();
 
 }
@@ -1500,7 +1531,7 @@ void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SE
     QWidget* tempWidget = dockWidgets[centralWidget];
 
     tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
-    qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
+    //qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
     if (toolsMenuActions[centralWidget])
     {
         toolsMenuActions[centralWidget]->setChecked(tempVisible);
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index 43a0230..6241646 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -104,6 +104,9 @@ public slots:
     void addLink();
     void addLink(LinkInterface* link);
     void configure();
+    /** @brief Set the currently controlled UAS */
+    void setActiveUAS(UASInterface* uas);
+    /** @brief Add a new UAS */
     void UASCreated(UASInterface* uas);
     void startVideoCapture();
     void stopVideoCapture();
@@ -208,6 +211,7 @@ protected:
       MENU_SLUGS_PID,
       MENU_SLUGS_HIL,
       MENU_SLUGS_CAMERA,
+      MENU_MAVLINK_LOG_PLAYER,
       CENTRAL_SEPARATOR= 255, // do not change
       CENTRAL_LINECHART,
       CENTRAL_PROTOCOL,
@@ -297,6 +301,7 @@ protected:
     /** @brief Keeps track of the current view */
     VIEW_SECTIONS currentView;
     bool aboutToCloseFlag;
+    bool changingViewsFlag;
 
     void clearView();
 
@@ -360,6 +365,7 @@ protected:
     QPointer<QDockWidget> watchdogControlDockWidget;
 
     QPointer<QDockWidget> headUpDockWidget;
+    QPointer<QDockWidget> logPlayerDockWidget;
 
     QPointer<QDockWidget> hsiDockWidget;
     QPointer<QDockWidget> rcViewDockWidget;
diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui
index 2b904d9..e904558 100644
--- a/src/ui/MainWindow.ui
+++ b/src/ui/MainWindow.ui
@@ -49,23 +49,30 @@
     <addaction name="actionNewCustomWidget"/>
     <addaction name="actionMuteAudioOutput"/>
     <addaction name="actionSimulate"/>
+    <addaction name="actionPreferences"/>
     <addaction name="separator"/>
     <addaction name="actionReloadStyle"/>
     <addaction name="actionExit"/>
    </widget>
    <widget class="QMenu" name="menuNetwork">
     <property name="title">
-     <string>Network</string>
+     <string>Communication</string>
     </property>
     <addaction name="actionAdd_Link"/>
     <addaction name="separator"/>
    </widget>
    <widget class="QMenu" name="menuConnected_Systems">
+    <property name="enabled">
+     <bool>false</bool>
+    </property>
     <property name="title">
      <string>Select System</string>
     </property>
    </widget>
    <widget class="QMenu" name="menuUnmanned_System">
+    <property name="enabled">
+     <bool>false</bool>
+    </property>
     <property name="title">
      <string>Unmanned System</string>
     </property>
@@ -76,8 +83,6 @@
     <addaction name="actionLand"/>
     <addaction name="actionEmergency_Land"/>
     <addaction name="actionEmergency_Kill"/>
-    <addaction name="separator"/>
-    <addaction name="actionConfiguration"/>
    </widget>
    <widget class="QMenu" name="menuTools">
     <property name="title">
@@ -124,6 +129,9 @@
    </property>
   </action>
   <action name="actionLiftoff">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
    <property name="icon">
     <iconset resource="../../mavground.qrc">
      <normaloff>:/images/control/launch.svg</normaloff>
@@ -143,6 +151,10 @@
    </property>
   </action>
   <action name="actionEmergency_Land">
+   <property name="icon">
+    <iconset resource="../../mavground.qrc">
+     <normaloff>:/images/actions/process-stop.svg</normaloff>:/images/actions/process-stop.svg</iconset>
+   </property>
    <property name="text">
     <string>Emergency Land</string>
    </property>
@@ -151,6 +163,10 @@
    </property>
   </action>
   <action name="actionEmergency_Kill">
+   <property name="icon">
+    <iconset resource="../../mavground.qrc">
+     <normaloff>:/images/actions/process-stop.svg</normaloff>:/images/actions/process-stop.svg</iconset>
+   </property>
    <property name="text">
     <string>Kill UAS</string>
    </property>
@@ -312,6 +328,10 @@
    </property>
   </action>
   <action name="actionNewCustomWidget">
+   <property name="icon">
+    <iconset resource="../../mavground.qrc">
+     <normaloff>:/images/apps/utilities-system-monitor.svg</normaloff>:/images/apps/utilities-system-monitor.svg</iconset>
+   </property>
    <property name="text">
     <string>New Custom Widget</string>
    </property>
@@ -332,6 +352,18 @@
     <string>Mute Audio Output</string>
    </property>
   </action>
+  <action name="actionPreferences">
+   <property name="icon">
+    <iconset resource="../../mavground.qrc">
+     <normaloff>:/images/categories/preferences-system.svg</normaloff>:/images/categories/preferences-system.svg</iconset>
+   </property>
+   <property name="text">
+    <string>Preferences</string>
+   </property>
+   <property name="toolTip">
+    <string>QGroundControl global settings</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources>
diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc
new file mode 100644
index 0000000..ceccd9c
--- /dev/null
+++ b/src/ui/QGCMAVLinkLogPlayer.cc
@@ -0,0 +1,113 @@
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QDesktopServices>
+
+#include "QGCMAVLinkLogPlayer.h"
+#include "ui_QGCMAVLinkLogPlayer.h"
+
+QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(MAVLinkProtocol* mavlink, QWidget *parent) :
+    QWidget(parent),
+    lineCounter(0),
+    totalLines(0),
+    startTime(0),
+    endTime(0),
+    currentTime(0),
+    mavlink(mavlink),
+    ui(new Ui::QGCMAVLinkLogPlayer)
+{
+    ui->setupUi(this);
+    ui->gridLayout->setAlignment(Qt::AlignTop);
+
+    // Setup buttons
+    connect(ui->selectFileButton, SIGNAL(clicked()), this, SLOT(selectLogFile()));
+    connect(ui->pauseButton, SIGNAL(clicked()), this, SLOT(pause()));
+    connect(ui->playButton, SIGNAL(clicked()), this, SLOT(play()));
+
+}
+
+QGCMAVLinkLogPlayer::~QGCMAVLinkLogPlayer()
+{
+    delete ui;
+}
+
+void QGCMAVLinkLogPlayer::play()
+{
+    if (logFile.isOpen())
+    {
+        ui->pauseButton->setChecked(false);
+    }
+    else
+    {
+        ui->playButton->setChecked(false);
+        QMessageBox msgBox;
+        msgBox.setIcon(QMessageBox::Information);
+        msgBox.setText(tr("No logfile selected"));
+        msgBox.setInformativeText(tr("Please select first a MAVLink log file before playing it."));
+        msgBox.setStandardButtons(QMessageBox::Ok);
+        msgBox.setDefaultButton(QMessageBox::Ok);
+        msgBox.exec();
+    }
+}
+
+void QGCMAVLinkLogPlayer::pause()
+{
+    ui->playButton->setChecked(false);
+}
+
+void QGCMAVLinkLogPlayer::selectLogFile()
+{
+    QString fileName = QFileDialog::getOpenFileName(this, tr("Specify MAVLink log file name"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("MAVLink Logfile (*.mavlink);;"));
+
+    loadLogFile(fileName);
+}
+
+void QGCMAVLinkLogPlayer::loadLogFile(const QString& file)
+{
+    logFile.setFileName(file);
+
+    if (!logFile.open(QFile::ReadOnly))
+    {
+        QMessageBox msgBox;
+        msgBox.setIcon(QMessageBox::Critical);
+        msgBox.setText(tr("The selected logfile is unreadable"));
+        msgBox.setInformativeText(tr("Please make sure that the file %1 is readable or select a different file").arg(file));
+        msgBox.setStandardButtons(QMessageBox::Ok);
+        msgBox.setDefaultButton(QMessageBox::Ok);
+        msgBox.exec();
+        logFile.setFileName("");
+    }
+    else
+    {
+        ui->logFileNameLabel->setText(tr("%1").arg(file));
+    }
+}
+
+/**
+ * This function is the "mainloop" of the log player, reading one line
+ * and adjusting the mainloop timer to read the next line in time.
+ * It might not perfectly match the timing of the log file,
+ * but it will never induce a static drift into the log file replay.
+ * For scientific logging, the use of onboard timestamps and the log
+ * functionality of the line chart plot is recommended.
+ */
+void QGCMAVLinkLogPlayer::readLine()
+{
+
+    // Ui update: Only every 20 messages
+    // to prevent flickering and high CPU load
+
+    // Update status label
+    // Update progress bar
+}
+
+void QGCMAVLinkLogPlayer::changeEvent(QEvent *e)
+{
+    QWidget::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
diff --git a/src/ui/QGCMAVLinkLogPlayer.h b/src/ui/QGCMAVLinkLogPlayer.h
new file mode 100644
index 0000000..17454fd
--- /dev/null
+++ b/src/ui/QGCMAVLinkLogPlayer.h
@@ -0,0 +1,54 @@
+#ifndef QGCMAVLINKLOGPLAYER_H
+#define QGCMAVLINKLOGPLAYER_H
+
+#include <QWidget>
+#include <QFile>
+
+#include "MAVLinkProtocol.h"
+
+namespace Ui {
+    class QGCMAVLinkLogPlayer;
+}
+
+/**
+ * @brief Replays MAVLink log files
+ *
+ * This class allows to replay MAVLink logs at varying speeds.
+ * captured flights can be replayed, shown to others and analyzed
+ * in-depth later on.
+ */
+class QGCMAVLinkLogPlayer : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit QGCMAVLinkLogPlayer(MAVLinkProtocol* mavlink, QWidget *parent = 0);
+    ~QGCMAVLinkLogPlayer();
+
+public slots:
+    /** @brief Replay the logfile */
+    void play();
+    /** @brief Pause the logfile */
+    void pause();
+    /** @brief Select logfile */
+    void selectLogFile();
+    /** @brief Load log file */
+    void loadLogFile(const QString& file);
+
+protected:
+    int lineCounter;
+    int totalLines;
+    quint64 startTime;
+    quint64 endTime;
+    quint64 currentTime;
+    MAVLinkProtocol* mavlink;
+    QFile logFile;
+    QTimer loopTimer;
+    void changeEvent(QEvent *e);
+    void readLine();
+
+private:
+    Ui::QGCMAVLinkLogPlayer *ui;
+};
+
+#endif // QGCMAVLINKLOGPLAYER_H
diff --git a/src/ui/QGCMAVLinkLogPlayer.ui b/src/ui/QGCMAVLinkLogPlayer.ui
new file mode 100644
index 0000000..d035c04
--- /dev/null
+++ b/src/ui/QGCMAVLinkLogPlayer.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QGCMAVLinkLogPlayer</class>
+ <widget class="QWidget" name="QGCMAVLinkLogPlayer">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>407</width>
+    <height>144</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout" columnstretch="1,10,10,1,1,0">
+   <property name="horizontalSpacing">
+    <number>12</number>
+   </property>
+   <item row="0" column="0" colspan="3">
+    <widget class="QLabel" name="logFileNameLabel">
+     <property name="text">
+      <string>Please choose logfile</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="3" colspan="3">
+    <widget class="QPushButton" name="selectFileButton">
+     <property name="text">
+      <string>Select File</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1" colspan="5">
+    <widget class="QSlider" name="speedSlider">
+     <property name="minimum">
+      <number>1</number>
+     </property>
+     <property name="maximum">
+      <number>100</number>
+     </property>
+     <property name="value">
+      <number>50</number>
+     </property>
+     <property name="sliderPosition">
+      <number>50</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="3">
+    <widget class="QLabel" name="logStatsLabel">
+     <property name="text">
+      <string>No logfile selected..</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="5">
+    <widget class="QToolButton" name="pauseButton">
+     <property name="text">
+      <string>...</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../../mavground.qrc">
+       <normaloff>:/images/actions/media-playback-pause.svg</normaloff>:/images/actions/media-playback-pause.svg</iconset>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="checked">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0" colspan="6">
+    <widget class="QProgressBar" name="progressBar">
+     <property name="value">
+      <number>0</number>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="speedLabel">
+     <property name="text">
+      <string>Speed</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="4">
+    <widget class="QToolButton" name="playButton">
+     <property name="text">
+      <string>...</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../../mavground.qrc">
+       <normaloff>:/images/actions/media-playback-start.svg</normaloff>:/images/actions/media-playback-start.svg</iconset>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../mavground.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc
index 11bd3dd..f7305bc 100644
--- a/src/ui/SerialConfigurationWindow.cc
+++ b/src/ui/SerialConfigurationWindow.cc
@@ -239,12 +239,17 @@ userConfigured(false)
 
         // Setup the user interface according to link type
         ui.setupUi(this);
+        //this->setVisible(false);
+        //this->hide();
 
         // Create action to open this menu
         // Create configuration action for this link
         // Connect the current UAS
         action = new QAction(QIcon(":/images/devices/network-wireless.svg"), "", link);
         setLinkName(link->getName());
+
+        setupPortList();
+
         connect(action, SIGNAL(triggered()), this, SLOT(configureCommunication()));
 
         // Make sure that a change in the link name will be reflected in the UI
@@ -258,10 +263,8 @@ userConfigured(false)
         connect(ui.parNone, SIGNAL(toggled(bool)), this, SLOT(setParityNone()));
         connect(ui.parOdd, SIGNAL(toggled(bool)), this, SLOT(setParityOdd()));
         connect(ui.parEven, SIGNAL(toggled(bool)), this, SLOT(setParityEven()));
-        connect(ui.dataBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setDataBitsType(int)));
-        connect(ui.stopBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setStopBitsType(int)));
-
-        setupPortList();
+        connect(ui.dataBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setDataBits(int)));
+        connect(ui.stopBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setStopBits(int)));
 
         //connect(this->link, SIGNAL(connected(bool)), this, SLOT());
         ui.portName->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
@@ -299,8 +302,8 @@ userConfigured(false)
 
         ui.baudRate->setCurrentIndex(this->link->getBaudRateType());
 
-        ui.dataBitsSpinBox->setValue(this->link->getDataBitsType() + 5);
-        ui.stopBitsSpinBox->setValue(this->link->getStopBitsType() + 1);
+        ui.dataBitsSpinBox->setValue(this->link->getDataBits());
+        ui.stopBitsSpinBox->setValue(this->link->getStopBits());
 
         portCheckTimer = new QTimer(this);
         portCheckTimer->setInterval(1000);
@@ -308,7 +311,7 @@ userConfigured(false)
 
         // Display the widget
         this->window()->setWindowTitle(tr("Serial Communication Settings"));
-        this->show();
+        //this->show();
     }
     else
     {
@@ -323,18 +326,14 @@ SerialConfigurationWindow::~SerialConfigurationWindow() {
 
 void SerialConfigurationWindow::showEvent(QShowEvent* event)
 {
-    if (event->isAccepted())
-    {
-        portCheckTimer->start();
-    }
+    Q_UNUSED(event);
+    portCheckTimer->start();
 }
 
 void SerialConfigurationWindow::hideEvent(QHideEvent* event)
 {
-    if (event->isAccepted())
-    {
-        portCheckTimer->stop();
-    }
+    Q_UNUSED(event);
+    portCheckTimer->stop();
 }
 
 QAction* SerialConfigurationWindow::getAction()
diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc
index d04bb0e..ba1b496 100644
--- a/src/ui/linechart/LinechartWidget.cc
+++ b/src/ui/linechart/LinechartWidget.cc
@@ -119,8 +119,7 @@ updateTimer(new QTimer())
     curvesWidgetLayout->addWidget(value, labelRow, 3);
 
     // Unit
-    label->setText("Unit");
-    curvesWidgetLayout->addWidget(new QLabel(tr("Unit")), labelRow, 4);
+    //curvesWidgetLayout->addWidget(new QLabel(tr("Unit")), labelRow, 4);
 
     // Mean
     mean = new QLabel(this);
@@ -216,9 +215,8 @@ void LinechartWidget::createLayout()
     connect(logButton, SIGNAL(clicked()), this, SLOT(startLogging()));
 
     // Ground time button
-    QToolButton* timeButton = new QToolButton(this);
+    QCheckBox* timeButton = new QCheckBox(this);
     timeButton->setText(tr("Ground Time"));
-    timeButton->setCheckable(true);
     timeButton->setToolTip(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time."));
     timeButton->setWhatsThis(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time."));
     bool gTimeDefault = true;
@@ -228,6 +226,13 @@ void LinechartWidget::createLayout()
     layout->setColumnStretch(4, 0);
     connect(timeButton, SIGNAL(clicked(bool)), activePlot, SLOT(enforceGroundTime(bool)));
 
+    unitsCheckBox = new QCheckBox(this);
+    unitsCheckBox->setText(tr("Show units"));
+    unitsCheckBox->setChecked(true);
+    unitsCheckBox->setToolTip(tr("Enable unit display in curve list"));
+    unitsCheckBox->setWhatsThis(tr("Enable unit display in curve list"));
+    layout->addWidget(unitsCheckBox, 1, 5);
+
     // Create the scroll bar
     //scrollbar = new QScrollBar(Qt::Horizontal, ui.diagramGroupBox);
     //scrollbar->setMinimum(MIN_TIME_SCROLLBAR_VALUE);
@@ -241,7 +246,7 @@ void LinechartWidget::createLayout()
 
     // Add scroll bar to layout and make sure it gets all available space
     //layout->addWidget(scrollbar, 1, 5);
-    layout->setColumnStretch(5, 10);
+    //layout->setColumnStretch(5, 10);
 
     ui.diagramGroupBox->setLayout(layout);
 
@@ -254,8 +259,8 @@ void LinechartWidget::createLayout()
     // FIXME
 
     // Connect notifications from the plot to the user interface
-    connect(activePlot, SIGNAL(curveAdded(QString)), this, SLOT(addCurve(QString)));
-    connect(activePlot, SIGNAL(curveRemoved(QString)), this, SLOT(removeCurve(QString)));
+    //connect(activePlot, SIGNAL(curveAdded(QString)), this, SLOT(addCurve(QString)));
+    //connect(activePlot, SIGNAL(curveRemoved(QString)), this, SLOT(removeCurve(QString)));
 
     // Scrollbar
 
@@ -313,7 +318,7 @@ void LinechartWidget::appendData(int uasId, const QString& curve, const QString&
         // Make sure the curve will be created if it does not yet exist
         if(!label)
         {
-            qDebug() << "ADDING CURVE IN APPENDDATE DOUBLE";
+            //qDebug() << "ADDING CURVE IN APPENDDATE DOUBLE";
             addCurve(curve, unit);
         }
     }
@@ -594,8 +599,8 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit)
     value = new QLabel(this);
     value->setNum(0.00);
     value->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}"));
-    value->setToolTip(tr("Current value of ") + curve);
-    value->setWhatsThis(tr("Current value of ") + curve);
+    value->setToolTip(tr("Current value of %1 in %2 units").arg(curve, unit));
+    value->setWhatsThis(tr("Current value of %1 in %2 units").arg(curve, unit));
     curveLabels->insert(curve+unit, value);
     curvesWidgetLayout->addWidget(value, labelRow, 3);
 
@@ -603,17 +608,18 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit)
     unitLabel = new QLabel(this);
     unitLabel->setText(unit);
     unitLabel->setStyleSheet(QString("QLabel {color: %1;}").arg("#AAAAAA"));
-    qDebug() << "UNIT" << unit;
+    //qDebug() << "UNIT" << unit;
     unitLabel->setToolTip(tr("Unit of ") + curve);
     unitLabel->setWhatsThis(tr("Unit of ") + curve);
     curvesWidgetLayout->addWidget(unitLabel, labelRow, 4);
+    connect(unitsCheckBox, SIGNAL(clicked(bool)), unitLabel, SLOT(setVisible(bool)));
 
     // Mean
     mean = new QLabel(this);
     mean->setNum(0.00);
     mean->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}"));
-    mean->setToolTip(tr("Arithmetic mean of ") + curve);
-    mean->setWhatsThis(tr("Arithmetic mean of ") + curve);
+    mean->setToolTip(tr("Arithmetic mean of %1 in %2 units").arg(curve, unit));
+    mean->setWhatsThis(tr("Arithmetic mean of %1 in %2 units").arg(curve, unit));
     curveMeans->insert(curve+unit, mean);
     curvesWidgetLayout->addWidget(mean, labelRow, 5);
 
@@ -627,8 +633,8 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit)
     variance = new QLabel(this);
     variance->setNum(0.00);
     variance->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}"));
-    variance->setToolTip(tr("Variance of ") + curve);
-    variance->setWhatsThis(tr("Variance of ") + curve);
+    variance->setToolTip(tr("Variance of %1 in (%2)^2 units").arg(curve, unit));
+    variance->setWhatsThis(tr("Variance of %1 in (%2)^2 units").arg(curve, unit));
     curveVariances->insert(curve+unit, variance);
     curvesWidgetLayout->addWidget(variance, labelRow, 6);
 
diff --git a/src/ui/linechart/LinechartWidget.h b/src/ui/linechart/LinechartWidget.h
index af76a4b..d7ebb4b 100644
--- a/src/ui/linechart/LinechartWidget.h
+++ b/src/ui/linechart/LinechartWidget.h
@@ -132,6 +132,7 @@ protected:
     QToolButton* scalingLinearButton;
     QToolButton* scalingLogButton;
     QToolButton* logButton;
+    QPointer<QCheckBox> unitsCheckBox;
 
     QFile* logFile;
     unsigned int logindex;
diff --git a/src/ui/uas/UASControlWidget.cc b/src/ui/uas/UASControlWidget.cc
index 842c150..9de5dd1 100644
--- a/src/ui/uas/UASControlWidget.cc
+++ b/src/ui/uas/UASControlWidget.cc
@@ -84,6 +84,8 @@ engineOn(false)
     connect(ui.setModeButton, SIGNAL(clicked()), this, SLOT(transmitMode()));
 
     ui.modeComboBox->setCurrentIndex(0);
+
+    ui.gridLayout->setAlignment(Qt::AlignTop);
 }
 
 void UASControlWidget::setUAS(UASInterface* uas)
diff --git a/src/ui/uas/UASListWidget.cc b/src/ui/uas/UASListWidget.cc
index 498c3ff..e8a4f4e 100644
--- a/src/ui/uas/UASListWidget.cc
+++ b/src/ui/uas/UASListWidget.cc
@@ -52,6 +52,7 @@ UASListWidget::UASListWidget(QWidget *parent) : QWidget(parent), m_ui(new Ui::UA
     listLayout = new QVBoxLayout(this);
     listLayout->setAlignment(Qt::AlignTop);
     this->setLayout(listLayout);
+    setObjectName("UNMANNED_SYSTEMS_LIST");
 
     // Construct initial widget
     uWidget = new QGCUnconnectedInfoWidget(this);