1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-30 15:52:12 +01:00

LP-517 gcs: make uavtalk log file more robust and thread safe

This commit is contained in:
Philippe Renon 2017-05-11 01:56:30 +02:00
parent f4b53b75c1
commit 5220cb0d6f
2 changed files with 86 additions and 45 deletions

View File

@ -27,17 +27,18 @@
#include <QDebug>
#include <QtGlobal>
LogFile::LogFile(QObject *parent) :
QIODevice(parent),
LogFile::LogFile(QObject *parent) : QIODevice(parent),
m_timer(this),
m_lastTimeStamp(0),
m_previousTimeStamp(0),
m_nextTimeStamp(0),
m_lastPlayed(0),
m_timeOffset(0),
m_playbackSpeed(1.0),
m_nextTimeStamp(0),
m_useProvidedTimeStamp(false)
m_useProvidedTimeStamp(false),
m_providedTimeStamp(0)
{
connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired()));
connect(&m_timer, &QTimer::timeout, this, &LogFile::timerFired);
}
bool LogFile::isSequential() const
{
@ -64,7 +65,7 @@ bool LogFile::open(OpenMode mode)
qDebug() << "LogFile - open" << fileName();
if (m_file.open(mode) == false) {
qDebug() << "Unable to open " << m_file.fileName() << " for logging";
qWarning() << "Unable to open " << m_file.fileName() << " for logging";
return false;
}
@ -93,9 +94,9 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
return dataSize;
}
// If m_nextTimeStamp != -1 then use this timestamp instead of the timer
// If needed, use provided timestamp instead of the GCS timer
// This is used when saving logs from on-board logging
quint32 timeStamp = m_useProvidedTimeStamp ? m_nextTimeStamp : m_myTime.elapsed();
quint32 timeStamp = m_useProvidedTimeStamp ? m_providedTimeStamp : m_myTime.elapsed();
m_file.write((char *)&timeStamp, sizeof(timeStamp));
m_file.write((char *)&dataSize, sizeof(dataSize));
@ -112,67 +113,83 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize)
return dataSize;
}
qint64 LogFile::readData(char *data, qint64 maxSize)
qint64 LogFile::readData(char *data, qint64 maxlen)
{
QMutexLocker locker(&m_mutex);
qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size());
memcpy(data, m_dataBuffer.data(), toRead);
m_dataBuffer.remove(0, toRead);
return toRead;
qint64 len = qMin(maxlen, (qint64)m_dataBuffer.size());
if (len) {
memcpy(data, m_dataBuffer.data(), len);
m_dataBuffer.remove(0, len);
}
return len;
}
qint64 LogFile::bytesAvailable() const
{
return m_dataBuffer.size();
QMutexLocker locker(&m_mutex);
qint64 len = m_dataBuffer.size();
return len;
}
void LogFile::timerFired()
{
qint64 dataSize;
if (m_file.bytesAvailable() > 4) {
int time;
time = m_myTime.elapsed();
// TODO: going back in time will be a problem
while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_lastTimeStamp)) {
while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_nextTimeStamp)) {
m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed);
// read data size
qint64 dataSize;
if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) {
qDebug() << "LogFile - end of log file reached";
stopReplay();
return;
}
m_file.read((char *)&dataSize, sizeof(dataSize));
// check size consistency
if (dataSize < 1 || dataSize > (1024 * 1024)) {
qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n";
qWarning() << "LogFile - corrupted log file! Unlikely packet size:" << dataSize;
stopReplay();
return;
}
// read data
if (m_file.bytesAvailable() < dataSize) {
qDebug() << "LogFile - end of log file reached";
stopReplay();
return;
}
QByteArray data = m_file.read(dataSize);
// make data available
m_mutex.lock();
m_dataBuffer.append(m_file.read(dataSize));
m_dataBuffer.append(data);
m_mutex.unlock();
emit readyRead();
if (m_file.bytesAvailable() < (qint64)sizeof(m_lastTimeStamp)) {
// read next timestamp
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
qDebug() << "LogFile - end of log file reached";
stopReplay();
return;
}
m_previousTimeStamp = m_nextTimeStamp;
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
int save = m_lastTimeStamp;
m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp));
// some validity checks
if (m_lastTimeStamp < save // logfile goes back in time
|| (m_lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes)
qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << m_lastTimeStamp << " after " << save << "\n";
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;
stopReplay();
return;
}
@ -181,26 +198,44 @@ void LogFile::timerFired()
time = m_myTime.elapsed();
}
} else {
qDebug() << "LogFile - end of log file reached";
stopReplay();
}
}
bool LogFile::startReplay()
{
if (!m_file.isOpen() || m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - startReplay";
m_dataBuffer.clear();
m_myTime.restart();
m_timeOffset = 0;
m_lastPlayed = 0;
m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp));
m_timeOffset = 0;
m_lastPlayed = 0;
m_previousTimeStamp = 0;
m_nextTimeStamp = 0;
m_dataBuffer.clear();
// read next timestamp
if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) {
qWarning() << "LogFile - invalid log file!";
return false;
}
m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp));
m_timer.setInterval(10);
m_timer.start();
emit replayStarted();
return true;
}
bool LogFile::stopReplay()
{
if (!m_file.isOpen() || !m_timer.isActive()) {
return false;
}
qDebug() << "LogFile - stopReplay";
m_timer.stop();

View File

@ -40,15 +40,7 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice {
public:
explicit LogFile(QObject *parent = 0);
bool isSequential() const;
qint64 bytesAvailable() const;
qint64 bytesToWrite() const
{
return m_file.bytesToWrite();
};
bool open(OpenMode mode);
QString fileName()
QString fileName() const
{
return m_file.fileName();
};
@ -56,7 +48,18 @@ public:
{
m_file.setFileName(name);
};
bool isSequential() const;
bool open(OpenMode mode);
void close();
qint64 bytesAvailable() const;
qint64 bytesToWrite() const
{
return m_file.bytesToWrite();
};
qint64 writeData(const char *data, qint64 dataSize);
qint64 readData(char *data, qint64 maxlen);
@ -65,9 +68,9 @@ public:
m_useProvidedTimeStamp = useProvidedTimeStamp;
}
void setNextTimeStamp(quint32 nextTimestamp)
void setNextTimeStamp(quint32 providedTimestamp)
{
m_nextTimeStamp = nextTimestamp;
m_providedTimeStamp = providedTimestamp;
}
public slots:
@ -94,16 +97,19 @@ protected:
QTimer m_timer;
QTime m_myTime;
QFile m_file;
qint32 m_lastTimeStamp;
qint32 m_previousTimeStamp;
qint32 m_nextTimeStamp;
double m_lastPlayed;
QMutex m_mutex;
// QMutex wants to be mutable
// http://stackoverflow.com/questions/25521570/can-mutex-locking-function-be-marked-as-const
mutable QMutex m_mutex;
int m_timeOffset;
double m_playbackSpeed;
private:
quint32 m_nextTimeStamp;
bool m_useProvidedTimeStamp;
qint32 m_providedTimeStamp;
};
#endif // LOGFILE_H