8#include <QtConcurrent/QtConcurrent>
9#include <QtCore/QFileInfo>
10#include <QtCore/QFutureWatcher>
22 const QString suffix = QFileInfo(filePath).suffix().toLower();
24 if (suffix == QStringLiteral(
"bin") || suffix == QStringLiteral(
"log")) {
28 if (suffix == QStringLiteral(
"ulg")) {
32 const QString fileTypeDescription = suffix.isEmpty()
33 ? LogFileParser::tr(
"no extension")
34 : QStringLiteral(
".%1").arg(suffix);
38 "Unsupported file type (%1) for file '%2'. Expected .bin, .log, or .ulg.")
39 .arg(fileTypeDescription, filePath);
49LogFileParser::LogFileParser(QObject *parent)
52 qCDebug(LogFileParserLog) <<
this;
55LogFileParser::~LogFileParser()
57 qCDebug(LogFileParserLog) <<
this;
60bool LogFileParser::parseFile(
const QString &filePath)
70 qCDebug(LogFileParserLog) <<
"Parsed fields" << _availableFields.count()
71 <<
"parameters" << _parameters.count()
72 <<
"events" << _events.count();
76void LogFileParser::parseFileAsync(
const QString &filePath)
78 const quint64 requestId = ++_parseRequestId;
81 auto *watcher =
new QFutureWatcher<LogParseResult>(
this);
82 (void) connect(watcher, &QFutureWatcher<LogParseResult>::finished,
this,
83 [
this, watcher, filePath, requestId]() {
85 watcher->deleteLater();
87 if (requestId != _parseRequestId) {
101 watcher->setFuture(QtConcurrent::run([filePath]() {
102 return _parseFile(filePath);
137void LogFileParser::clear()
139 const bool oldParsed = _parsed;
146 if (!_events.isEmpty()) { _events.clear(); emit
eventsChanged(); }
147 if (!_messages.isEmpty()) { _messages.clear(); emit
messagesChanged(); }
149 if (!_dropouts.isEmpty()) { _dropouts.clear(); emit
dropoutsChanged(); }
153 _fieldSamples.clear();
154 if (_minTimestamp != -1.0 || _maxTimestamp != -1.0) {
155 _minTimestamp = -1.0;
156 _maxTimestamp = -1.0;
162QVariantList LogFileParser::fieldSamples(
const QString &fieldName)
const
165 const auto it = _fieldSamples.constFind(fieldName);
166 if (it == _fieldSamples.cend()) {
return output; }
167 const QVector<QPointF> &points = it.value();
168 output.reserve(points.size());
169 for (
const QPointF &p : points) { output.append(p); }
173double LogFileParser::fieldValueAt(
const QString &fieldName,
double timestampSeconds)
const
175 const auto it = _fieldSamples.constFind(fieldName);
176 if (it == _fieldSamples.cend() || it->isEmpty()) {
177 return std::numeric_limits<double>::quiet_NaN();
179 const QVector<QPointF> &points = it.value();
180 const auto lower = std::lower_bound(points.cbegin(), points.cend(), timestampSeconds,
181 [](
const QPointF &p,
double t) { return p.x() < t; });
183 if (lower == points.cbegin()) {
return lower->y(); }
184 if (lower == points.cend()) {
return points.constLast().y(); }
186 const auto prev = std::prev(lower);
187 return (std::fabs(prev->x() - timestampSeconds) <= std::fabs(lower->x() - timestampSeconds))
188 ? prev->y() : lower->y();
191QString LogFileParser::modeAt(
double timestampSeconds)
const
193 for (
const QVariant &v : _modeSegments) {
194 const QVariantMap seg = v.toMap();
195 const double start = seg.value(QStringLiteral(
"start")).toDouble();
196 const double end = seg.value(QStringLiteral(
"end")).toDouble();
197 if (timestampSeconds >= start && timestampSeconds <= end) {
198 return seg.value(QStringLiteral(
"mode")).toString();
204QVariantList LogFileParser::eventsNear(
double timestampSeconds,
double thresholdSeconds)
const
206 QVariantList matches;
207 const double threshold = std::max(0.0, thresholdSeconds);
208 const auto lower = std::lower_bound(_events.cbegin(), _events.cend(),
209 timestampSeconds - threshold,
210 [](
const QVariant &v,
double t) {
211 return v.toMap().value(QStringLiteral(
"time")).toDouble() < t;
213 for (
auto it = lower; it != _events.cend(); ++it) {
214 const QVariantMap ev = it->toMap();
215 if (ev.value(QStringLiteral(
"time")).toDouble() > timestampSeconds + threshold) {
break; }
221void LogFileParser::_setParseError(
const QString &
error)
223 if (_parseError !=
error) {
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void detectedVehicleTypeChanged()
void sampleCountChanged()
void plottableFieldsChanged()
void availableFieldsChanged()
void modeSegmentsChanged()
void parseFileFinished(const QString &filePath, bool ok, const QString &errorMessage)
LogParseResult parseFile(const QString &filePath)
LogParseResult parseFile(const QString &filePath)
QString detectedVehicleType
QVariantList modeSegments
QStringList plottableFields
QStringList availableFields
QHash< QString, QVector< QPointF > > fieldSamples