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:
parent
f4b53b75c1
commit
5220cb0d6f
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user