diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index b7bf9eca1..cc70f1198 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -29,6 +29,8 @@ #include #include // DEBUG: to display the thread ID +#define TIMESTAMP_SIZE_BYTES 4 + LogFile::LogFile(QObject *parent) : QIODevice(parent), m_timer(this), m_previousTimeStamp(0), @@ -156,7 +158,7 @@ void LogFile::timerFired() } m_timer_tick++; - if (m_file.bytesAvailable() > 4) { + if (m_file.bytesAvailable() > TIMESTAMP_SIZE_BYTES) { int time; time = m_myTime.elapsed(); @@ -182,7 +184,7 @@ void LogFile::timerFired() // read data size qint64 dataSize; if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) { - qDebug() << "LogFile - end of log file reached"; + qDebug() << "LogFile replay - end of log file reached"; stopReplay(); return; } @@ -190,14 +192,14 @@ void LogFile::timerFired() // check size consistency if (dataSize < 1 || dataSize > (1024 * 1024)) { - qWarning() << "LogFile - corrupted log file! Unlikely packet size:" << dataSize; + qWarning() << "LogFile replay - corrupted log file! Unlikely packet size:" << dataSize; stopReplay(); return; } // read data if (m_file.bytesAvailable() < dataSize) { - qDebug() << "LogFile - end of log file reached"; + qDebug() << "LogFile replay - end of log file reached"; stopReplay(); return; } @@ -216,7 +218,7 @@ void LogFile::timerFired() } // read next timestamp if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) { - qDebug() << "LogFile - end of log file reached"; + qDebug() << "LogFile replay - end of log file reached"; stopReplay(); return; } @@ -226,7 +228,7 @@ void LogFile::timerFired() // some validity checks if ((m_nextTimeStamp < m_previousTimeStamp) // logfile goes back in time || ((m_nextTimeStamp - m_previousTimeStamp) > 60 * 60 * 1000)) { // gap of more than 60 minutes - qWarning() << "LogFile - corrupted log file! Unlikely timestamp:" << m_nextTimeStamp << "after" << m_previousTimeStamp; + qWarning() << "LogFile replay - corrupted log file! Unlikely timestamp:" << m_nextTimeStamp << "after" << m_previousTimeStamp; stopReplay(); return; } @@ -235,7 +237,7 @@ void LogFile::timerFired() time = m_myTime.elapsed(); // number of milliseconds since start of playback } } else { - qDebug() << "LogFile - end of log file reached"; + qDebug() << "LogFile replay - end of log file reached"; stopReplay(); } } @@ -324,12 +326,12 @@ bool LogFile::stopReplay() * If no position is given, resumes from the last position * */ - bool LogFile::resumeReplay(quint32 desiredPosition) { if (m_timer.isActive()) { return false; } + qDebug() << "LogFile - resumeReplay"; // Clear the playout buffer: m_mutex.lock(); @@ -346,7 +348,11 @@ bool LogFile::resumeReplay(quint32 desiredPosition) for (int i = 0; i < m_timeStamps.size(); i++) { if (m_timeStamps.at(i) >= desiredPosition) { - m_file.seek(m_timeStampPositions.at(i)); + int bytesToSkip = m_timeStampPositions.at(i); + bool seek_ok = m_file.seek(bytesToSkip); + if (!seek_ok) { + qWarning() << "LogFile resumeReplay - an error occurred while seeking through the logfile."; + } m_lastPlayed = m_timeStamps.at(i); break; } @@ -401,6 +407,7 @@ bool LogFile::pauseAndResetPosition() if (!m_file.isOpen() || !m_timer.isActive()) { return false; } + qDebug() << "LogFile - pauseAndResetPosition"; m_timer.stop(); m_replayStatus = STOPPED; @@ -426,11 +433,11 @@ ReplayState LogFile::getReplayStatus() /** * FUNCTION: buildIndex() * - * Walk through the opened logfile and sets the start and end position timestamps + * Walk through the opened logfile and stores the first and last position timestamps. * Also builds an index for quickly skipping to a specific position in the logfile. * - * returns true when indexing has completed successfully - * returns false when a problem was encountered + * Returns true when indexing has completed successfully. + * Returns false when a problem was encountered. * */ bool LogFile::buildIndex() @@ -439,18 +446,28 @@ bool LogFile::buildIndex() qint64 totalSize; qint64 readPointer = 0; quint64 index = 0; + int bytesRead = 0; - QByteArray arr = m_file.readAll(); + qDebug() << "LogFile - buildIndex"; + // Ensure empty vectors: + m_timeStampPositions.clear(); + m_timeStamps.clear(); + + QByteArray arr = m_file.readAll(); totalSize = arr.size(); QDataStream dataStream(&arr, QIODevice::ReadOnly); - // set the start timestamp - if (totalSize - readPointer >= 4) { - dataStream.readRawData((char *)&timeStamp, 4); + // set the first timestamp + if (totalSize - readPointer >= TIMESTAMP_SIZE_BYTES) { + bytesRead = dataStream.readRawData((char *)&timeStamp, TIMESTAMP_SIZE_BYTES); + if (bytesRead != TIMESTAMP_SIZE_BYTES) { + qWarning() << "LogFile buildIndex - read first timeStamp: readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n"; + return false; + } m_timeStamps.append(timeStamp); m_timeStampPositions.append(readPointer); - readPointer += 4; + readPointer += TIMESTAMP_SIZE_BYTES; index++; m_beginTimeStamp = timeStamp; m_endTimeStamp = timeStamp; @@ -461,22 +478,27 @@ bool LogFile::buildIndex() // Check if there are enough bytes remaining for a correct "dataSize" field if (totalSize - readPointer < (qint64)sizeof(dataSize)) { - qDebug() << "Error: Logfile corrupted! Unexpected end of file"; + qWarning() << "LogFile buildIndex - logfile corrupted! Unexpected end of file"; + return false; + } + + // Read the dataSize field and check for I/O errors + bytesRead = dataStream.readRawData((char *)&dataSize, sizeof(dataSize)); + if (bytesRead != sizeof(dataSize)) { + qWarning() << "LogFile buildIndex - read dataSize: readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n"; return false; } - // Read the dataSize field - dataStream.readRawData((char *)&dataSize, sizeof(dataSize)); readPointer += sizeof(dataSize); if (dataSize < 1 || dataSize > (1024 * 1024)) { - qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n"; + qWarning() << "LogFile buildIndex - logfile corrupted! Unlikely packet size: " << dataSize << "\n"; return false; } // Check if there are enough bytes remaining if (totalSize - readPointer < dataSize) { - qDebug() << "Error: Logfile corrupted! Unexpected end of file"; + qWarning() << "LogFile buildIndex - logfile corrupted! Unexpected end of file"; return false; } @@ -484,18 +506,23 @@ bool LogFile::buildIndex() readPointer += dataStream.skipRawData(dataSize); // read the next timestamp - if (totalSize - readPointer >= 4) { - dataStream.readRawData((char *)&timeStamp, 4); + if (totalSize - readPointer >= TIMESTAMP_SIZE_BYTES) { + bytesRead = dataStream.readRawData((char *)&timeStamp, TIMESTAMP_SIZE_BYTES); + if (bytesRead != TIMESTAMP_SIZE_BYTES) { + qWarning() << "LogFile buildIndex - read timeStamp, readRawData returned unexpected number of bytes:" << bytesRead << "at position" << readPointer << "\n"; + return false; + } // some validity checks if (timeStamp < m_endTimeStamp // logfile goes back in time || (timeStamp - m_endTimeStamp) > (60 * 60 * 1000)) { // gap of more than 60 minutes) - qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << timeStamp << " after " << m_endTimeStamp; + qWarning() << "LogFile buildIndex - logfile corrupted! Unlikely timestamp " << timeStamp << " after " << m_endTimeStamp; + return false; } m_timeStamps.append(timeStamp); m_timeStampPositions.append(readPointer); - readPointer += 4; + readPointer += TIMESTAMP_SIZE_BYTES; index++; m_endTimeStamp = timeStamp; } else { @@ -504,7 +531,7 @@ bool LogFile::buildIndex() } } - emit updateBeginAndEndtimes(m_beginTimeStamp, m_endTimeStamp); + emit updateBeginAndEndTimes(m_beginTimeStamp, m_endTimeStamp); // reset the read pointer to the start of the file m_file.seek(0); diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index f36173e3e..3246d6b12 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -100,7 +100,7 @@ signals: void replayStarted(); void replayFinished(); void playbackPosition(quint32); - void updateBeginAndEndtimes(quint32, quint32); + void updateBeginAndEndTimes(quint32, quint32); protected: QByteArray m_dataBuffer; diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp index 655db48f9..5fdc2773f 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp @@ -79,7 +79,7 @@ void LoggingGadgetWidget::setPlugin(LoggingPlugin *p) // Feedback from logfile to GUI connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged); - connect(logFile, &LogFile::updateBeginAndEndtimes, this, &LoggingGadgetWidget::updateBeginAndEndtimes); + connect(logFile, &LogFile::updateBeginAndEndTimes, this, &LoggingGadgetWidget::updateBeginAndEndTimes); connect(logFile, &LogFile::playbackPosition, this, &LoggingGadgetWidget::playbackPosition); connect(logFile, &LogFile::replayStarted, this, &LoggingGadgetWidget::enableButtons); connect(logFile, &LogFile::replayFinished, this, &LoggingGadgetWidget::disableButtons); @@ -174,7 +174,7 @@ void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state) } } -void LoggingGadgetWidget::updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp) +void LoggingGadgetWidget::updateBeginAndEndTimes(quint32 startTimeStamp, quint32 endTimeStamp) { int startSec, startMin, endSec, endMin; diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.h b/ground/gcs/src/plugins/logging/logginggadgetwidget.h index f2fc451f3..34491936e 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.h +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.h @@ -49,7 +49,7 @@ public: protected slots: void stateChanged(LoggingPlugin::State state); - void updateBeginAndEndtimes(quint32 startTimeStamp, quint32 endTimeStamp); + void updateBeginAndEndTimes(quint32 startTimeStamp, quint32 endTimeStamp); void playbackPosition(quint32 positionTimeStamp); void playPauseButtonAction(); void stopButtonAction();