Commit 61f64e1c authored by Lorenz Meier's avatar Lorenz Meier

Merge branch 'master' of github.com:mavlink/qgroundcontrol into thread_test

parents 769e6952 72dd2b00
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QSettings> #include <QSettings>
#include <QDesktopServices> #include <QDesktopServices>
#include <QtEndian>
#include "MAVLinkProtocol.h" #include "MAVLinkProtocol.h"
#include "UASInterface.h" #include "UASInterface.h"
...@@ -358,19 +359,26 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -358,19 +359,26 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
// Log data // Log data
if (m_loggingEnabled && m_logfile) if (m_loggingEnabled && m_logfile)
{ {
uint8_t buf[MAVLINK_MAX_PACKET_LEN+sizeof(quint64)] = {0}; uint8_t buf[MAVLINK_MAX_PACKET_LEN+sizeof(quint64)];
quint64 time = QGC::groundTimeUsecs();
memcpy(buf, (void*)&time, sizeof(quint64)); // Write the uint64 time in microseconds in big endian format before the message.
// Write message to buffer // This timestamp is saved in UTC time. We are only saving in ms precision because
mavlink_msg_to_send_buffer(buf+sizeof(quint64), &message); // getting more than this isn't possible with Qt without a ton of extra code.
//we need to write the maximum package length for having a quint64 time = (quint64)QDateTime::currentMSecsSinceEpoch() * 1000;
//consistent file structure and beeing able to parse it again qToBigEndian(time, buf);
int len = MAVLINK_MAX_PACKET_LEN + sizeof(quint64);
// Then write the message to the buffer
int len = mavlink_msg_to_send_buffer(buf + sizeof(quint64), &message);
// Determine how many bytes were written by adding the timestamp size to the message size
len += sizeof(quint64);
// Now write this timestamp/message pair to the log.
QByteArray b((const char*)buf, len); QByteArray b((const char*)buf, len);
if(m_logfile->write(b) != len) if(m_logfile->write(b) != len)
{ {
// If there's an error logging data, raise an alert and stop logging.
emit protocolStatusMessage(tr("MAVLink Logging failed"), tr("Could not write to file %1, disabling logging.").arg(m_logfile->fileName())); emit protocolStatusMessage(tr("MAVLink Logging failed"), tr("Could not write to file %1, disabling logging.").arg(m_logfile->fileName()));
// Stop logging
enableLogging(false); enableLogging(false);
} }
} }
......
This diff is collapsed.
...@@ -52,10 +52,10 @@ public slots: ...@@ -52,10 +52,10 @@ public slots:
void playPause(bool play); void playPause(bool play);
/** @brief Replay the logfile */ /** @brief Replay the logfile */
void play(); void play();
/** @brief Pause the logfile */ /** @brief Pause the log player. */
void pause(); void pause();
/** @brief Reset the logfile */ /** @brief Reset the internal log player state, including the UI */
bool reset(int packetIndex=0); void reset();
/** @brief Select logfile */ /** @brief Select logfile */
bool selectLogFile(const QString startDirectory); bool selectLogFile(const QString startDirectory);
/** @brief Select logfile */ /** @brief Select logfile */
...@@ -72,21 +72,22 @@ public slots: ...@@ -72,21 +72,22 @@ public slots:
signals: signals:
/** @brief Send ready bytes */ /** @brief Send ready bytes */
void bytesReady(LinkInterface* link, const QByteArray& bytes); void bytesReady(LinkInterface* link, const QByteArray& bytes);
void logFileEndReached();
protected: protected:
int lineCounter; quint64 playbackStartTime; ///< The time when the logfile was first played back. This is used to pace out replaying the messages to fix long-term drift/skew. 0 indicates that the player hasn't initiated playback of this log file. In units of milliseconds since epoch UTC.
int totalLines; quint64 logCurrentTime; ///< The timestamp of the next message in the log file. In units of microseconds since epoch UTC.
quint64 startTime; quint64 logStartTime; ///< The first timestamp in the current log file. In units of microseconds since epoch UTC.
quint64 endTime; quint64 logEndTime; ///< The last timestamp in the current log file. In units of microseconds since epoch UTC.
quint64 currentStartTime;
float accelerationFactor; float accelerationFactor;
MAVLinkProtocol* mavlink; MAVLinkProtocol* mavlink;
MAVLinkSimulationLink* logLink; MAVLinkSimulationLink* logLink;
QFile logFile; QFile logFile;
QTimer loopTimer; QTimer loopTimer;
int loopCounter; int loopCounter;
bool mavlinkLogFormat; bool mavlinkLogFormat; ///< If the logfile is stored in the timestamped MAVLink log format
int binaryBaudRate; int binaryBaudRate;
static const int defaultBinaryBaudRate = 57600;
bool isPlaying; bool isPlaying;
unsigned int currPacketCount; unsigned int currPacketCount;
static const int packetLen = MAVLINK_MAX_PACKET_LEN; static const int packetLen = MAVLINK_MAX_PACKET_LEN;
...@@ -100,6 +101,35 @@ protected: ...@@ -100,6 +101,35 @@ protected:
private: private:
Ui::QGCMAVLinkLogPlayer *ui; Ui::QGCMAVLinkLogPlayer *ui;
virtual void paintEvent(QPaintEvent *); virtual void paintEvent(QPaintEvent *);
/** @brief Parse out a quint64 timestamp in microseconds in the proper endianness. */
quint64 parseTimestamp(const QByteArray &data);
/**
* This function parses out the next MAVLink message and its corresponding timestamp.
*
* It makes no assumptions about where in the file we currently are. It leaves the file right
* at the beginning of the successfully parsed message. Note that this function will not attempt to
* correct for any MAVLink parsing failures, so it always returns the next successfully-parsed
* message.
*
* @param msg[output] Where the final parsed message output will go.
* @return A Unix timestamp in microseconds UTC or 0 if parsing failed
*/
quint64 findNextMavlinkMessage(mavlink_message_t *msg);
/**
* Updates the QSlider UI to be at the given percentage.
* @param percent A percentage value between 0.0% and 100.0%.
*/
void updatePositionSliderUi(float percent);
/**
* Jumps to a new position in the current playback file as a percentage.
* @param percentage The position of the file to jump to as a percentage.
* @return True if the new file position was successfully jumped to, false otherwise
*/
bool jumpToPlaybackLocation(float percentage);
}; };
#endif // QGCMAVLINKLOGPLAYER_H #endif // QGCMAVLINKLOGPLAYER_H
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<item> <item>
<widget class="QLabel" name="logStatsLabel"> <widget class="QLabel" name="logStatsLabel">
<property name="text"> <property name="text">
<string>No logfile selected..</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
...@@ -54,6 +54,16 @@ ...@@ -54,6 +54,16 @@
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time</string>
</property>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -119,7 +129,7 @@ ...@@ -119,7 +129,7 @@
<item> <item>
<widget class="QLabel" name="logFileNameLabel"> <widget class="QLabel" name="logFileNameLabel">
<property name="text"> <property name="text">
<string>-</string> <string>No logfile selected..</string>
</property> </property>
</widget> </widget>
</item> </item>
......
...@@ -37,7 +37,7 @@ QGCStatusBar::QGCStatusBar(QWidget *parent) : ...@@ -37,7 +37,7 @@ QGCStatusBar::QGCStatusBar(QWidget *parent) :
{ {
setObjectName("QGC_STATUSBAR"); setObjectName("QGC_STATUSBAR");
toggleLoggingButton = new QPushButton("Logging", this); toggleLoggingButton = new QPushButton(tr("Log to file"), this);
toggleLoggingButton->setCheckable(true); toggleLoggingButton->setCheckable(true);
addPermanentWidget(toggleLoggingButton); addPermanentWidget(toggleLoggingButton);
......
...@@ -643,7 +643,7 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit) ...@@ -643,7 +643,7 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit)
// Connect actions // Connect actions
connect(selectAllCheckBox, SIGNAL(clicked(bool)), checkBox, SLOT(setChecked(bool))); connect(selectAllCheckBox, SIGNAL(clicked(bool)), checkBox, SLOT(setChecked(bool)));
QObject::connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(takeButtonClick(bool))); QObject::connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(takeButtonClick(bool)));
QObject::connect(this, SIGNAL(curveVisible(QString, bool)), plot, SLOT(setVisible(QString, bool))); QObject::connect(this, SIGNAL(curveVisible(QString, bool)), plot, SLOT(setVisibleById(QString, bool)));
// Set UI components to initial state // Set UI components to initial state
checkBox->setChecked(false); checkBox->setChecked(false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment