diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index 33ffa7ea068d6885e8b06b437c69bfcb9e031db1..9dcea3cdf1b5ea9d1a24502468bd7f1f7dcb03c8 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -604,6 +604,7 @@ HEADERS += \
src/comm/LinkConfiguration.h \
src/comm/LinkInterface.h \
src/comm/LinkManager.h \
+ src/comm/LogReplayLink.h \
src/comm/MAVLinkProtocol.h \
src/comm/ProtocolInterface.h \
src/comm/QGCMAVLink.h \
@@ -664,7 +665,6 @@ HEADERS += \
src/GPS/vehicle_gps_position.h \
src/Joystick/JoystickSDL.h \
src/RunGuard.h \
- src/comm/LogReplayLink.h \
src/comm/QGCHilLink.h \
src/comm/QGCJSBSimLink.h \
src/comm/QGCXPlaneLink.h \
@@ -780,6 +780,7 @@ SOURCES += \
src/comm/LinkConfiguration.cc \
src/comm/LinkInterface.cc \
src/comm/LinkManager.cc \
+ src/comm/LogReplayLink.cc \
src/comm/MAVLinkProtocol.cc \
src/comm/QGCMAVLink.cc \
src/comm/TCPLink.cc \
@@ -822,7 +823,6 @@ SOURCES += \
src/GPS/RTCM/RTCMMavlink.cc \
src/Joystick/JoystickSDL.cc \
src/RunGuard.cc \
- src/comm/LogReplayLink.cc \
src/comm/QGCJSBSimLink.cc \
src/comm/QGCXPlaneLink.cc \
src/uas/FileManager.cc \
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index d5517633cc55309b478d40fddc9302aedd7c3bb3..8de7ae380fead56ae74a6508e900e9851b821419 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -77,6 +77,7 @@
src/PlanView/GeoFenceMapVisuals.qml
src/QmlControls/IndicatorButton.qml
src/QmlControls/JoystickThumbPad.qml
+ src/QmlControls/LogReplayStatusBar.qml
src/QmlControls/MAVLinkMessageButton.qml
src/QmlControls/MissionCommandDialog.qml
src/PlanView/MissionItemEditor.qml
diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml
index 5f913079dee2a250d2954e82de3a59d7115fdcb8..4ee65f955204d5429338cbd04e23f85b4ab09d67 100644
--- a/src/FlightDisplay/FlightDisplayView.qml
+++ b/src/FlightDisplay/FlightDisplayView.qml
@@ -312,7 +312,10 @@ Item {
Item {
id: _mapAndVideo
- anchors.fill: parent
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: logReplayStatusBar.top
//-- Map View
Item {
@@ -737,6 +740,14 @@ Item {
}
}
+ LogReplayStatusBar {
+ id: logReplayStatusBar
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ visible: QGroundControl.settingsManager.flyViewSettings.showLogReplayStatusBar.rawValue &&_flightMapContainer.state === "fullMode"
+ }
+
//-- Airspace Indicator
Rectangle {
id: airspaceIndicator
diff --git a/src/FlightDisplay/FlightDisplayViewMap.qml b/src/FlightDisplay/FlightDisplayViewMap.qml
index a5ef10dbfbe76ec43663955e6fbc54efc7c60d4b..6aaea9570ccc77265b0ac030cd2e23f657b59382 100644
--- a/src/FlightDisplay/FlightDisplayViewMap.qml
+++ b/src/FlightDisplay/FlightDisplayViewMap.qml
@@ -26,7 +26,6 @@ import QGroundControl.Vehicle 1.0
FlightMap {
id: flightMap
- anchors.fill: parent
mapName: _mapName
allowGCSLocationCenter: !userPanned
allowVehicleLocationCenter: !_keepVehicleCentered
diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc
index 8c4cf014c352839a8fa10aea7dacea8d2ede10fe..d258e8c31aa8b976b32eba4b358507c059b6551c 100644
--- a/src/QGCApplication.cc
+++ b/src/QGCApplication.cc
@@ -100,6 +100,7 @@
#include "MavlinkConsoleController.h"
#include "MAVLinkInspectorController.h"
#include "GeoTagController.h"
+#include "LogReplayLink.h"
#ifndef __mobile__
#include "FirmwareUpgradeController.h"
@@ -485,6 +486,9 @@ void QGCApplication::_initCommon()
qmlRegisterUncreatableType ("QGroundControl", 1, 0, "QmlObjectListModel", kRefOnly);
qmlRegisterUncreatableType ("QGroundControl", 1, 0, "MissionCommandTree", kRefOnly);
qmlRegisterUncreatableType ("QGroundControl", 1, 0, "CameraCalc", kRefOnly);
+ qmlRegisterUncreatableType ("QGroundControl", 1, 0, "LogReplayLink", kRefOnly);
+
+ qmlRegisterType ("QGroundControl", 1, 0, "LogReplayLinkController");
qmlRegisterUncreatableType ("QGroundControl.AutoPilotPlugin", 1, 0, "AutoPilotPlugin", kRefOnly);
qmlRegisterUncreatableType ("QGroundControl.AutoPilotPlugin", 1, 0, "VehicleComponent", kRefOnly);
diff --git a/src/QmlControls/LogReplayStatusBar.qml b/src/QmlControls/LogReplayStatusBar.qml
new file mode 100644
index 0000000000000000000000000000000000000000..98d67d642163aaf5a2b0477419efb0106520aea8
--- /dev/null
+++ b/src/QmlControls/LogReplayStatusBar.qml
@@ -0,0 +1,91 @@
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Layouts 1.11
+import QtQuick.Dialogs 1.2
+
+import QGroundControl 1.0
+import QGroundControl.Palette 1.0
+import QGroundControl.ScreenTools 1.0
+
+Rectangle {
+ height: visible ? (rowLayout.height + (_margins * 2)) : 0
+ color: qgcPal.window
+
+ property real _margins: ScreenTools.defaultFontPixelHeight / 4
+ property var _logReplayLink: null
+
+ function pickLogFile() {
+ if (mainWindow.activeVehicle) {
+ mainWindow.showMessageDialog(qsTr("Log Replay"), qsTr("You must close all connections prior to replaying a log."), StandardButton.Ok)
+ return
+ }
+
+ filePicker.openForLoad()
+ }
+
+ QGCPalette { id: qgcPal }
+
+ QGCFileDialog {
+ id: filePicker
+ title: qsTr("Select Telemetery Log")
+ nameFilters: [qsTr("Telemetry Logs (*.%1)").arg(QGroundControl.settingsManager.appSettings.telemetryFileExtension), qsTr("All Files (*)")]
+ selectExisting: true
+ folder: QGroundControl.settingsManager.appSettings.telemetrySavePath
+ onAcceptedForLoad: {
+ controller.link = QGroundControl.linkManager.startLogReplay(file)
+ close()
+ }
+ }
+
+ LogReplayLinkController {
+ id: controller
+
+ onPercentCompleteChanged: slider.updatePercentComplete(percentComplete)
+ }
+
+ RowLayout {
+ id: rowLayout
+ anchors.margins: _margins
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ QGCButton {
+ text: controller.isPlaying ? qsTr("Pause") : qsTr("Play")
+ enabled: controller.link
+ onClicked: controller.isPlaying = !controller.isPlaying
+ }
+
+ QGCLabel { text: controller.playheadTime }
+
+ Slider {
+ id: slider
+ Layout.fillWidth: true
+ minimumValue: 0
+ maximumValue: 100
+ enabled: controller.link
+
+ property bool manualUpdate: false
+
+ function updatePercentComplete(percentComplete) {
+ manualUpdate = true
+ value = percentComplete
+ manualUpdate = false
+ }
+
+ onValueChanged: {
+ if (!manualUpdate) {
+ controller.percentComplete = value
+ }
+ }
+ }
+
+ QGCLabel { text: controller.totalTime }
+
+ QGCButton {
+ text: qsTr("Load Telemetry Log")
+ onClicked: pickLogFile()
+ visible: !controller.link
+ }
+ }
+}
diff --git a/src/QmlControls/QGroundControl/Controls/qmldir b/src/QmlControls/QGroundControl/Controls/qmldir
index c4850c1067d53e54e747b75ab13f938301416a45..b96999f620ba92cb538c4027df64d75888222fc6 100644
--- a/src/QmlControls/QGroundControl/Controls/qmldir
+++ b/src/QmlControls/QGroundControl/Controls/qmldir
@@ -20,6 +20,7 @@ GeoFenceMapVisuals 1.0 GeoFenceMapVisuals.qml
HackFileDialog 1.0 HackFileDialog.qml
IndicatorButton 1.0 IndicatorButton.qml
JoystickThumbPad 1.0 JoystickThumbPad.qml
+LogReplayStatusBar 1.0 LogReplayStatusBar.qml
MAVLinkMessageButton 1.0 MAVLinkMessageButton.qml
MissionCommandDialog 1.0 MissionCommandDialog.qml
MissionItemEditor 1.0 MissionItemEditor.qml
diff --git a/src/comm/LinkConfiguration.cc b/src/comm/LinkConfiguration.cc
index e6a61144de8f36318c0e14b0580a800ebe95e2d8..6168ccf6ea3c4dc7085aca7abab8bb7b21dc432f 100644
--- a/src/comm/LinkConfiguration.cc
+++ b/src/comm/LinkConfiguration.cc
@@ -20,9 +20,7 @@
#endif
#include "UDPLink.h"
#include "TCPLink.h"
-#if !defined(__mobile__)
#include "LogReplayLink.h"
-#endif
#ifdef QGC_ENABLE_BLUETOOTH
#include "BluetoothLink.h"
#endif
@@ -98,11 +96,9 @@ LinkConfiguration* LinkConfiguration::createSettings(int type, const QString& na
config = new BluetoothConfiguration(name);
break;
#endif
-#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
config = new LogReplayLinkConfiguration(name);
break;
-#endif
#ifdef QT_DEBUG
case LinkConfiguration::TypeMock:
config = new MockConfiguration(name);
@@ -136,11 +132,9 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc
dupe = new BluetoothConfiguration(dynamic_cast(source));
break;
#endif
-#ifndef __mobile__
case TypeLogReplay:
dupe = new LogReplayLinkConfiguration(dynamic_cast(source));
break;
-#endif
#ifdef QT_DEBUG
case TypeMock:
dupe = new MockConfiguration(dynamic_cast(source));
diff --git a/src/comm/LinkConfiguration.h b/src/comm/LinkConfiguration.h
index a32e65f53e2caa0c0189315e43c3faf1a36adb30..94f37cf9e5cd469c6d386514c7bc1240fe5ee668 100644
--- a/src/comm/LinkConfiguration.h
+++ b/src/comm/LinkConfiguration.h
@@ -57,9 +57,7 @@ public:
#ifdef QT_DEBUG
TypeMock, ///< Mock Link for Unitesting
#endif
-#ifndef __mobile__
TypeLogReplay,
-#endif
TypeLast // Last type value (type >= TypeLast == invalid)
};
Q_ENUM(LinkType)
diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc
index 9724cab9c75dd71fa9f0ab81bf6e3bb14c7367a3..4ed7a1719b6f0ec7607368cd0090a68e89327174 100644
--- a/src/comm/LinkManager.cc
+++ b/src/comm/LinkManager.cc
@@ -21,6 +21,7 @@
#include "UDPLink.h"
#include "TCPLink.h"
#include "SettingsManager.h"
+#include "LogReplayLink.h"
#ifdef QGC_ENABLE_BLUETOOTH
#include "BluetoothLink.h"
#endif
@@ -139,11 +140,9 @@ LinkInterface* LinkManager::createConnectedLink(SharedLinkConfigurationPointer&
pLink = new BluetoothLink(config);
break;
#endif
-#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
pLink = new LogReplayLink(config);
break;
-#endif
#ifdef QT_DEBUG
case LinkConfiguration::TypeMock:
pLink = new MockLink(config);
@@ -393,11 +392,9 @@ void LinkManager::loadLinkConfigurationList()
pLink = dynamic_cast(new BluetoothConfiguration(name));
break;
#endif
-#ifndef __mobile__
case LinkConfiguration::TypeLogReplay:
pLink = dynamic_cast(new LogReplayLinkConfiguration(name));
break;
-#endif
#ifdef QT_DEBUG
case LinkConfiguration::TypeMock:
pLink = dynamic_cast(new MockConfiguration(name));
@@ -847,7 +844,6 @@ void LinkManager::_fixUnnamed(LinkConfiguration* config)
}
break;
#endif
-#ifndef __mobile__
case LinkConfiguration::TypeLogReplay: {
LogReplayLinkConfiguration* tconfig = dynamic_cast(config);
if(tconfig) {
@@ -855,7 +851,6 @@ void LinkManager::_fixUnnamed(LinkConfiguration* config)
}
}
break;
-#endif
#ifdef QT_DEBUG
case LinkConfiguration::TypeMock:
config->setName(QString("Mock Link"));
@@ -1015,3 +1010,13 @@ void LinkManager::_freeMavlinkChannel(int channel)
void LinkManager::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message) {
link->startMavlinkMessagesTimer(message.sysid);
}
+
+LogReplayLink* LinkManager::startLogReplay(const QString& logFile)
+{
+ LogReplayLinkConfiguration* linkConfig = new LogReplayLinkConfiguration(tr("Log Replay"));
+ linkConfig->setLogFilename(logFile);
+ linkConfig->setName(linkConfig->logFilenameShort());
+
+ SharedLinkConfigurationPointer sharedConfig = addConfiguration(linkConfig);
+ return qobject_cast(createConnectedLink(sharedConfig));
+}
diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h
index 8322e1c6f593296ac3e64155226efa060ada8706..e6f278bc75dae230356901f7c7de5522936f3c55 100644
--- a/src/comm/LinkManager.h
+++ b/src/comm/LinkManager.h
@@ -43,6 +43,7 @@ Q_DECLARE_LOGGING_CATEGORY(LinkManagerVerboseLog)
class QGCApplication;
class UDPConfiguration;
class AutoConnectSettings;
+class LogReplayLink;
/// Manage communication links
///
@@ -129,6 +130,8 @@ public:
// Called to signal app shutdown. Disconnects all links while turning off auto-connect.
Q_INVOKABLE void shutdown(void);
+ Q_INVOKABLE LogReplayLink* startLogReplay(const QString& logFile);
+
#ifdef QT_DEBUG
// Only used by unit test tp restart after a shutdown
void restart(void) { setConnectionsAllowed(); }
diff --git a/src/comm/LogReplayLink.cc b/src/comm/LogReplayLink.cc
index 579b45322e9d84da8ea2816f6d3d607160b06bfc..06cbbe574163e4a8029dddbb8dc56b547b84a8db 100644
--- a/src/comm/LogReplayLink.cc
+++ b/src/comm/LogReplayLink.cc
@@ -19,13 +19,13 @@
const char* LogReplayLinkConfiguration::_logFilenameKey = "logFilename";
LogReplayLinkConfiguration::LogReplayLinkConfiguration(const QString& name)
- : LinkConfiguration(name)
+ : LinkConfiguration(name)
{
}
LogReplayLinkConfiguration::LogReplayLinkConfiguration(LogReplayLinkConfiguration* copy)
- : LinkConfiguration(copy)
+ : LinkConfiguration(copy)
{
_logFilename = copy->logFilename();
}
@@ -448,7 +448,7 @@ void LogReplayLink::_resetPlaybackToBeginning(void)
_logCurrentTimeUSecs = _logStartTimeUSecs;
}
-void LogReplayLink::movePlayhead(int percentComplete)
+void LogReplayLink::movePlayhead(qreal percentComplete)
{
if (isPlaying()) {
_pauseOnThread();
@@ -459,17 +459,19 @@ void LogReplayLink::movePlayhead(int percentComplete)
}
}
- if (percentComplete < 0 || percentComplete > 100) {
- qWarning() << "Bad percentage value" << percentComplete;
- return;
+ if (percentComplete < 0) {
+ percentComplete = 0;
+ }
+ if (percentComplete > 100) {
+ percentComplete = 100;
}
- float floatPercentComplete = (float)percentComplete / 100.0f;
+ qreal percentCompleteMult = percentComplete / 100.0;
if (_logTimestamped) {
// But if we have a timestamped MAVLink log, then actually aim to hit that percentage in terms of
// time through the file.
- qint64 newFilePos = (qint64)(floatPercentComplete * (float)_logFile.size());
+ qint64 newFilePos = (qint64)(percentCompleteMult * (qreal)_logFile.size());
// Now seek to the appropriate position, failing gracefully if we can't.
if (!_logFile.seek(newFilePos)) {
@@ -482,13 +484,13 @@ void LogReplayLink::movePlayhead(int percentComplete)
_logCurrentTimeUSecs = _seekToNextMavlinkMessage(&dummy);
// Now calculate the current file location based on time.
- float newRelativeTimeUSecs = (float)(_logCurrentTimeUSecs - _logStartTimeUSecs);
+ qreal newRelativeTimeUSecs = (qreal)(_logCurrentTimeUSecs - _logStartTimeUSecs);
// Calculate the effective baud rate of the file in bytes/s.
- float baudRate = _logFile.size() / (float)_logDurationUSecs / 1e6;
+ qreal baudRate = _logFile.size() / (qreal)_logDurationUSecs / 1e6;
// And the desired time is:
- float desiredTimeUSecs = floatPercentComplete * _logDurationUSecs;
+ qreal desiredTimeUSecs = percentCompleteMult * _logDurationUSecs;
// And now jump the necessary number of bytes in the proper direction
qint64 offset = (newRelativeTimeUSecs - desiredTimeUSecs) * baudRate;
@@ -503,13 +505,13 @@ void LogReplayLink::movePlayhead(int percentComplete)
_signalCurrentLogTimeSecs();
// Now update the UI with our actual final position.
- newRelativeTimeUSecs = (float)(_logCurrentTimeUSecs - _logStartTimeUSecs);
+ newRelativeTimeUSecs = (qreal)(_logCurrentTimeUSecs - _logStartTimeUSecs);
percentComplete = (newRelativeTimeUSecs / _logDurationUSecs) * 100;
emit playbackPercentCompleteChanged(percentComplete);
} else {
// If we're working with a non-timestamped file, we just jump to that percentage of the file,
// align to the next MAVLink message and roll with it. No reason to do anything more complicated.
- qint64 newFilePos = (qint64)(floatPercentComplete * (float)_logFile.size());
+ qint64 newFilePos = (qint64)(percentCompleteMult * (qreal)_logFile.size());
// Now seek to the appropriate position, failing gracefully if we can't.
if (!_logFile.seek(newFilePos)) {
@@ -560,15 +562,117 @@ void LogReplayLink::_finishPlayback(void)
emit playbackAtEnd();
}
-/// @brief Called when an error occurs during playback to reset playback system state.
-void LogReplayLink::_playbackError(void)
+void LogReplayLink::_signalCurrentLogTimeSecs(void)
{
- _pause();
- _logFile.close();
- emit playbackError();
+ emit currentLogTimeSecs((_logCurrentTimeUSecs - _logStartTimeUSecs) / 1000000);
}
-void LogReplayLink::_signalCurrentLogTimeSecs(void)
+LogReplayLinkController::LogReplayLinkController(void)
+ : _link (nullptr)
+ , _isPlaying (false)
+ , _percentComplete (0)
+ , _playheadSecs (0)
{
- emit currentLogTimeSecs((_logCurrentTimeUSecs - _logStartTimeUSecs) / 1000000);
+
+}
+
+void LogReplayLinkController::setLink(LogReplayLink* link)
+{
+ if (_link) {
+ disconnect(_link);
+ _isPlaying = false;
+ _percentComplete = 0;
+ _playheadTime.clear();
+ _totalTime.clear();
+ _link = nullptr;
+ emit isPlayingChanged(false);
+ emit percentCompleteChanged(0);
+ emit playheadTimeChanged(QString());
+ emit totalTimeChanged(QString());
+ emit linkChanged(nullptr);
+ }
+
+
+ if (link) {
+ _link = link;
+ connect(_link, &LogReplayLink::logFileStats, this, &LogReplayLinkController::_logFileStats);
+ connect(_link, &LogReplayLink::playbackStarted, this, &LogReplayLinkController::_playbackStarted);
+ connect(_link, &LogReplayLink::playbackPaused, this, &LogReplayLinkController::_playbackPaused);
+ connect(_link, &LogReplayLink::playbackPercentCompleteChanged, this, &LogReplayLinkController::_playbackPercentCompleteChanged);
+ connect(_link, &LogReplayLink::currentLogTimeSecs, this, &LogReplayLinkController::_currentLogTimeSecs);
+ connect(_link, &LogReplayLink::disconnected, this, &LogReplayLinkController::_linkDisconnected);
+ emit linkChanged(_link);
+ }
+}
+
+void LogReplayLinkController::setIsPlaying(bool isPlaying)
+{
+ if (isPlaying) {
+ _link->play();
+ } else {
+ _link->pause();
+ }
+}
+
+void LogReplayLinkController::setPercentComplete(qreal percentComplete)
+{
+ _link->movePlayhead(percentComplete);
+}
+
+void LogReplayLinkController::_logFileStats(bool logTimestamped, int logDurationSecs, int binaryBaudRate)
+{
+ Q_UNUSED(logTimestamped);
+ Q_UNUSED(binaryBaudRate);
+
+ _totalTime = _secondsToHMS(logDurationSecs);
+ emit totalTimeChanged(_totalTime);
+}
+
+void LogReplayLinkController::_playbackStarted(void)
+{
+ _isPlaying = true;
+ emit isPlayingChanged(true);
+}
+
+void LogReplayLinkController::_playbackPaused(void)
+{
+ _isPlaying = false;
+ emit isPlayingChanged(true);
+}
+
+void LogReplayLinkController::_playbackAtEnd(void)
+{
+ _isPlaying = false;
+ emit isPlayingChanged(true);
+}
+
+void LogReplayLinkController::_playbackPercentCompleteChanged(qreal percentComplete)
+{
+ _percentComplete = percentComplete;
+ emit percentCompleteChanged(_percentComplete);
+}
+
+void LogReplayLinkController::_currentLogTimeSecs(int secs)
+{
+ if (_playheadSecs != secs) {
+ _playheadSecs = secs;
+ _playheadTime = _secondsToHMS(secs);
+ emit playheadTimeChanged(_playheadTime);
+ }
+}
+
+void LogReplayLinkController::_linkDisconnected(void)
+{
+ setLink(nullptr);
+}
+
+QString LogReplayLinkController::_secondsToHMS(int seconds)
+{
+ int secondsPart = seconds;
+ int minutesPart = secondsPart / 60;
+ int hoursPart = minutesPart / 60;
+ secondsPart -= 60 * minutesPart;
+ minutesPart -= 60 * hoursPart;
+
+ return tr("%1h:%2m:%3s").arg(hoursPart, 2).arg(minutesPart, 2).arg(secondsPart, 2);
}
diff --git a/src/comm/LogReplayLink.h b/src/comm/LogReplayLink.h
index fb5de6ee6abd74edca13dfbaf483cd84b3490c73..6bb8bc17083174584eb707fb91c6f468cd4d446a 100644
--- a/src/comm/LogReplayLink.h
+++ b/src/comm/LogReplayLink.h
@@ -7,11 +7,9 @@
*
****************************************************************************/
-
#pragma once
-#include "LinkInterface.h"
-#include "LinkConfiguration.h"
+#include "LinkManager.h"
#include "MAVLinkProtocol.h"
#include
@@ -22,7 +20,6 @@ class LogReplayLinkConfiguration : public LinkConfiguration
Q_OBJECT
public:
-
Q_PROPERTY(QString fileName READ logFilename WRITE setLogFilename NOTIFY fileNameChanged)
LogReplayLinkConfiguration(const QString& name);
@@ -41,6 +38,7 @@ public:
void updateSettings ();
QString settingsURL () { return "LogReplaySettings.qml"; }
QString settingsTitle () { return tr("Log Replay Link Settings"); }
+
signals:
void fileNameChanged();
@@ -66,7 +64,7 @@ public:
void pause(void) { emit _pauseOnThread(); }
/// Move the playhead to the specified percent complete
- void movePlayhead(int percentComplete);
+ void movePlayhead(qreal percentComplete);
/// Sets the acceleration factor: -100: 0.01X, 0: 1.0X, 100: 100.0X
void setAccelerationFactor(int factor) { emit _setAccelerationFactorOnThread(factor); }
@@ -92,8 +90,7 @@ signals:
void playbackStarted(void);
void playbackPaused(void);
void playbackAtEnd(void);
- void playbackError(void);
- void playbackPercentCompleteChanged(int percentComplete);
+ void playbackPercentCompleteChanged(qreal percentComplete);
void currentLogTimeSecs(int secs);
// Internal signals
@@ -118,7 +115,6 @@ private:
quint64 _readNextMavlinkMessage(QByteArray& bytes);
bool _loadLogFile(void);
void _finishPlayback(void);
- void _playbackError(void);
void _resetPlaybackToBeginning(void);
void _signalCurrentLogTimeSecs(void);
@@ -156,3 +152,51 @@ private:
static const int cbTimestamp = sizeof(quint64);
};
+class LogReplayLinkController : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_PROPERTY(LogReplayLink* link READ link WRITE setLink NOTIFY linkChanged)
+ Q_PROPERTY(bool isPlaying READ isPlaying WRITE setIsPlaying NOTIFY isPlayingChanged)
+ Q_PROPERTY(qreal percentComplete READ percentComplete WRITE setPercentComplete NOTIFY percentCompleteChanged)
+ Q_PROPERTY(QString totalTime MEMBER _totalTime NOTIFY totalTimeChanged)
+ Q_PROPERTY(QString playheadTime MEMBER _playheadTime NOTIFY playheadTimeChanged)
+
+ LogReplayLinkController(void);
+
+ LogReplayLink* link (void) { return _link; }
+ bool isPlaying (void) { return _isPlaying; }
+ qreal percentComplete (void) { return _percentComplete; }
+
+ void setLink (LogReplayLink* link);
+ void setIsPlaying (bool isPlaying);
+ void setPercentComplete (qreal percentComplete);
+
+signals:
+ void linkChanged (LogReplayLink* link);
+ void isPlayingChanged (bool isPlaying);
+ void percentCompleteChanged (qreal percentComplete);
+ void playheadTimeChanged (QString playheadTime);
+ void totalTimeChanged (QString totalTime);
+
+private slots:
+ void _logFileStats (bool logTimestamped, int logDurationSecs, int binaryBaudRate);
+ void _playbackStarted (void);
+ void _playbackPaused (void);
+ void _playbackAtEnd (void);
+ void _playbackPercentCompleteChanged (qreal percentComplete);
+ void _currentLogTimeSecs (int secs);
+ void _linkDisconnected (void);
+
+private:
+ QString _secondsToHMS(int seconds);
+
+ LogReplayLink* _link;
+ bool _isPlaying;
+ qreal _percentComplete;
+ int _playheadSecs;
+ QString _playheadTime;
+ QString _totalTime;
+};
+