Commit fa6f3f71 authored by Don Gagne's avatar Don Gagne

Log Replay fixes

parent 8ef001af
...@@ -52,6 +52,7 @@ ParameterManager::ParameterManager(Vehicle* vehicle) ...@@ -52,6 +52,7 @@ ParameterManager::ParameterManager(Vehicle* vehicle)
, _initialLoadComplete(false) , _initialLoadComplete(false)
, _waitingForDefaultComponent(false) , _waitingForDefaultComponent(false)
, _saveRequired(false) , _saveRequired(false)
, _logReplay(vehicle->priorityLink() && vehicle->priorityLink()->isLogReplay())
, _parameterSetMajorVersion(-1) , _parameterSetMajorVersion(-1)
, _parameterMetaData(NULL) , _parameterMetaData(NULL)
, _prevWaitingReadParamIndexCount(0) , _prevWaitingReadParamIndexCount(0)
...@@ -83,6 +84,7 @@ ParameterManager::ParameterManager(Vehicle* vehicle) ...@@ -83,6 +84,7 @@ ParameterManager::ParameterManager(Vehicle* vehicle)
// Ensure the cache directory exists // Ensure the cache directory exists
QFileInfo(QSettings().fileName()).dir().mkdir("ParamCache"); QFileInfo(QSettings().fileName()).dir().mkdir("ParamCache");
refreshAllParameters(); refreshAllParameters();
} }
...@@ -135,7 +137,7 @@ void ParameterManager::_parameterUpdate(int vehicleId, int componentId, QString ...@@ -135,7 +137,7 @@ void ParameterManager::_parameterUpdate(int vehicleId, int componentId, QString
} }
#endif #endif
if (_vehicle->px4Firmware() && parameterName == "_HASH_CHECK") { if (_vehicle->px4Firmware() && parameterName == "_HASH_CHECK" && !_logReplay) {
/* we received a cache hash, potentially load from cache */ /* we received a cache hash, potentially load from cache */
_tryCacheHashLoad(vehicleId, componentId, value); _tryCacheHashLoad(vehicleId, componentId, value);
return; return;
...@@ -387,6 +389,10 @@ void ParameterManager::_valueUpdated(const QVariant& value) ...@@ -387,6 +389,10 @@ void ParameterManager::_valueUpdated(const QVariant& value)
void ParameterManager::refreshAllParameters(uint8_t componentId) void ParameterManager::refreshAllParameters(uint8_t componentId)
{ {
if (_logReplay) {
return;
}
_dataMutex.lock(); _dataMutex.lock();
if (!_initialLoadComplete) { if (!_initialLoadComplete) {
......
...@@ -170,6 +170,7 @@ private: ...@@ -170,6 +170,7 @@ private:
bool _initialLoadComplete; ///< true: Initial load of all parameters complete, whether successful or not bool _initialLoadComplete; ///< true: Initial load of all parameters complete, whether successful or not
bool _waitingForDefaultComponent; ///< true: last chance wait for default component params bool _waitingForDefaultComponent; ///< true: last chance wait for default component params
bool _saveRequired; ///< true: _saveToEEPROM should be called bool _saveRequired; ///< true: _saveToEEPROM should be called
bool _logReplay; ///< true: running with log replay link
QString _versionParam; ///< Parameter which contains parameter set version QString _versionParam; ///< Parameter which contains parameter set version
int _parameterSetMajorVersion; ///< Version for parameter set, -1 if not known int _parameterSetMajorVersion; ///< Version for parameter set, -1 if not known
QObject* _parameterMetaData; ///< Opaque data from FirmwarePlugin::loadParameterMetaDataCall QObject* _parameterMetaData; ///< Opaque data from FirmwarePlugin::loadParameterMetaDataCall
......
...@@ -100,6 +100,12 @@ bool LogReplayLink::_connect(void) ...@@ -100,6 +100,12 @@ bool LogReplayLink::_connect(void)
return false; return false;
} }
_mavlinkChannel = qgcApp()->toolbox()->linkManager()->_reserveMavlinkChannel();
if (_mavlinkChannel == 0) {
qWarning() << "No mavlink channels available";
return false;
}
if (isRunning()) { if (isRunning()) {
quit(); quit();
wait(); wait();
...@@ -114,6 +120,11 @@ void LogReplayLink::_disconnect(void) ...@@ -114,6 +120,11 @@ void LogReplayLink::_disconnect(void)
quit(); quit();
wait(); wait();
_connected = false; _connected = false;
if (_mavlinkChannel != 0) {
qgcApp()->toolbox()->linkManager()->_freeMavlinkChannel(_mavlinkChannel);
}
emit disconnected(); emit disconnected();
} }
} }
...@@ -165,6 +176,36 @@ quint64 LogReplayLink::_parseTimestamp(const QByteArray& bytes) ...@@ -165,6 +176,36 @@ quint64 LogReplayLink::_parseTimestamp(const QByteArray& bytes)
return timestamp; return timestamp;
} }
/// Reads the next mavlink message from the log
/// @param bytes[output] Bytes for mavlink message
/// @return Unix timestamp in microseconds UTC for NEXT mavlink message or 0 if no message found
quint64 LogReplayLink::_readNextMavlinkMessage(QByteArray& bytes)
{
char nextByte;
mavlink_status_t status;
bytes.clear();
while (_logFile.getChar(&nextByte)) { // Loop over every byte
mavlink_message_t message;
bool messageFound = mavlink_parse_char(_mavlinkChannel, nextByte, &message, &status);
if (status.parse_state == MAVLINK_PARSE_STATE_GOT_STX) {
// This is the possible beginning of a mavlink message, clear any partial bytes
bytes.clear();
}
bytes.append(nextByte);
if (messageFound) {
// Return the timestamp for the next message
QByteArray rawTime = _logFile.read(cbTimestamp);
return _parseTimestamp(rawTime);
}
}
return 0;
}
/// Seeks to the beginning of the next successfully parsed mavlink message in the log file. /// Seeks to the beginning of the next successfully parsed mavlink message in the log file.
/// @param nextMsg[output] Parsed next message that was found /// @param nextMsg[output] Parsed next message that was found
/// @return A Unix timestamp in microseconds UTC for found message or 0 if parsing failed /// @return A Unix timestamp in microseconds UTC for found message or 0 if parsing failed
...@@ -175,7 +216,7 @@ quint64 LogReplayLink::_seekToNextMavlinkMessage(mavlink_message_t* nextMsg) ...@@ -175,7 +216,7 @@ quint64 LogReplayLink::_seekToNextMavlinkMessage(mavlink_message_t* nextMsg)
qint64 messageStartPos = -1; qint64 messageStartPos = -1;
while (_logFile.getChar(&nextByte)) { // Loop over every byte while (_logFile.getChar(&nextByte)) { // Loop over every byte
bool messageFound = mavlink_parse_char(mavlinkChannel(), nextByte, nextMsg, &status); bool messageFound = mavlink_parse_char(_mavlinkChannel, nextByte, nextMsg, &status);
if (status.parse_state == MAVLINK_PARSE_STATE_GOT_STX) { if (status.parse_state == MAVLINK_PARSE_STATE_GOT_STX) {
// This is the possible beginning of a mavlink message // This is the possible beginning of a mavlink message
...@@ -294,6 +335,8 @@ Error: ...@@ -294,6 +335,8 @@ Error:
/// induce a static drift into the log file replay. /// induce a static drift into the log file replay.
void LogReplayLink::_readNextLogEntry(void) void LogReplayLink::_readNextLogEntry(void)
{ {
QByteArray bytes;
// If we have a file with timestamps, try and pace this out following the time differences // If we have a file with timestamps, try and pace this out following the time differences
// between the timestamps and the current playback speed. // between the timestamps and the current playback speed.
if (_logTimestamped) { if (_logTimestamped) {
...@@ -304,28 +347,18 @@ void LogReplayLink::_readNextLogEntry(void) ...@@ -304,28 +347,18 @@ void LogReplayLink::_readNextLogEntry(void)
// the next timer interrupt. // the next timer interrupt.
int timeToNextExecutionMSecs = 0; int timeToNextExecutionMSecs = 0;
// We use the `_seekToNextMavlinkMessage()` function to scan ahead for MAVLink messages. This
// is necessary because we don't know how big each MAVLink message is until we finish parsing
// one, and since we only output arrays of bytes, we need to know the size of that array.
mavlink_message_t msg;
_seekToNextMavlinkMessage(&msg);
while (timeToNextExecutionMSecs < 3) { while (timeToNextExecutionMSecs < 3) {
// Read the next mavlink message from the log
// Now we're sitting at the start of a MAVLink message, so read it all into a byte array for feeding to our parser. qint64 nextTimeUSecs = _readNextMavlinkMessage(bytes);
QByteArray message = _logFile.read(msg.len + MAVLINK_NUM_NON_PAYLOAD_BYTES); emit bytesReceived(this, bytes);
emit bytesReceived(this, message);
emit playbackPercentCompleteChanged(((float)(_logCurrentTimeUSecs - _logStartTimeUSecs) / (float)_logDurationUSecs) * 100); emit playbackPercentCompleteChanged(((float)(_logCurrentTimeUSecs - _logStartTimeUSecs) / (float)_logDurationUSecs) * 100);
// If we've reached the end of the of the file, make sure we handle that well
if (_logFile.atEnd()) { if (_logFile.atEnd()) {
_finishPlayback(); _finishPlayback();
return; return;
} }
// Run our parser to find the next timestamp and leave us at the start of the next MAVLink message. _logCurrentTimeUSecs = nextTimeUSecs;
_logCurrentTimeUSecs = _seekToNextMavlinkMessage(&msg);
// Calculate how long we should wait in real time until parsing this message. // Calculate how long we should wait in real time until parsing this message.
// We pace ourselves relative to the start time of playback to fix any drift (initially set in play()) // We pace ourselves relative to the start time of playback to fix any drift (initially set in play())
......
...@@ -114,6 +114,7 @@ private: ...@@ -114,6 +114,7 @@ private:
void _replayError(const QString& errorMsg); void _replayError(const QString& errorMsg);
quint64 _parseTimestamp(const QByteArray& bytes); quint64 _parseTimestamp(const QByteArray& bytes);
quint64 _seekToNextMavlinkMessage(mavlink_message_t* nextMsg); quint64 _seekToNextMavlinkMessage(mavlink_message_t* nextMsg);
quint64 _readNextMavlinkMessage(QByteArray& bytes);
bool _loadLogFile(void); bool _loadLogFile(void);
void _finishPlayback(void); void _finishPlayback(void);
void _playbackError(void); void _playbackError(void);
...@@ -129,6 +130,7 @@ private: ...@@ -129,6 +130,7 @@ private:
LogReplayLinkConfiguration* _logReplayConfig; LogReplayLinkConfiguration* _logReplayConfig;
bool _connected; bool _connected;
int _mavlinkChannel;
QTimer _readTickTimer; ///< Timer which signals a read of next log record QTimer _readTickTimer; ///< Timer which signals a read of next log record
static const char* _errorTitle; ///< Title for communicatorError signals static const char* _errorTitle; ///< Title for communicatorError signals
......
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