QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
ULogUtility.cc
Go to the documentation of this file.
1#include "ULogUtility.h"
3
4#include <cstring>
5
6#include <ulog_cpp/reader.hpp>
7
8QGC_LOGGING_CATEGORY(ULogUtilityLog, "Utilities.ULogUtility")
9
10namespace ULogUtility
11{
12
13// ============================================================================
14// Header Validation
15// ============================================================================
16
17bool isValidHeader(const char *data, qint64 size)
18{
19 if (size < kMagicSize) {
20 return false;
21 }
22 return memcmp(data, kMagicBytes, kMagicSize) == 0;
23}
24
25int getVersion(const char *data, qint64 size)
26{
27 if (size < 5) {
28 return -1;
29 }
30 if (!isValidHeader(data, size)) {
31 return -1;
32 }
33 return static_cast<uint8_t>(data[4]);
34}
35
36uint64_t getHeaderTimestamp(const char *data, qint64 size)
37{
38 if (size < kHeaderSize) {
39 return 0;
40 }
41 if (!isValidHeader(data, size)) {
42 return 0;
43 }
44
45 // Timestamp is at offset 8 (after magic[4] + version[1] + compat[1] + flags[2])
46 uint64_t timestamp;
47 memcpy(&timestamp, data + 8, sizeof(timestamp));
48 return timestamp;
49}
50
51// ============================================================================
52// MessageHandler Implementation
53// ============================================================================
54
55MessageHandler::MessageHandler(const std::string &messageName,
56 const MessageCallback &callback,
57 QString &errorMsg)
58 : _targetMessageName(messageName)
59 , _callback(callback)
60 , _errorMessage(errorMsg)
61{
62}
63
64void MessageHandler::error(const std::string &msg, bool is_recoverable)
65{
66 if (!is_recoverable) {
67 _hadFatalError = true;
68 }
69 if (!_errorMessage.isEmpty()) {
70 _errorMessage.append(QStringLiteral(", "));
71 }
72 _errorMessage.append(QString::fromStdString(msg));
73}
74
75void MessageHandler::messageFormat(const ulog_cpp::MessageFormat &message_format)
76{
77 if (message_format.name() == _targetMessageName) {
78 _messageFormat = std::make_shared<ulog_cpp::MessageFormat>(message_format);
79 }
80}
81
82void MessageHandler::addLoggedMessage(const ulog_cpp::AddLoggedMessage &add_logged_message)
83{
84 if (add_logged_message.messageName() == _targetMessageName && _messageFormat) {
85 _messageIds.insert(add_logged_message.msgId());
86 }
87}
88
90{
91 _headerComplete = true;
92 if (_messageFormat) {
93 _messageFormat->resolveDefinition({{_targetMessageName, _messageFormat}});
94 }
95}
96
97void MessageHandler::data(const ulog_cpp::Data &data)
98{
99 if (!_headerComplete || !_messageFormat) {
100 return;
101 }
102
103 if (!_messageIds.contains(data.msgId())) {
104 return;
105 }
106
107 try {
108 const ulog_cpp::TypedDataView typedData(data, *_messageFormat);
109 ++_messageCount;
110 if (!_callback(typedData)) {
111 // Callback returned false, stop processing
112 // Note: ulog_cpp doesn't support early termination, so we just skip remaining
113 }
114 } catch (const ulog_cpp::AccessException &exception) {
115 qCWarning(ULogUtilityLog) << "Failed to parse" << QString::fromStdString(_targetMessageName)
116 << ":" << exception.what();
117 QStringList fields;
118 for (const std::string &name : _messageFormat->fieldNames()) {
119 fields.append(QString::fromStdString(name));
120 }
121 qCDebug(ULogUtilityLog) << "Available fields:" << fields;
122 }
123}
124
125// ============================================================================
126// Message Iteration
127// ============================================================================
128
129bool iterateMessages(const char *data, qint64 size,
130 const std::string &messageName,
131 const MessageCallback &callback,
132 QString &errorMessage)
133{
134 errorMessage.clear();
135
136 auto handler = std::make_shared<MessageHandler>(messageName, callback, errorMessage);
137 ulog_cpp::Reader parser(handler);
138 parser.readChunk(reinterpret_cast<const uint8_t*>(data), static_cast<size_t>(size));
139
140 if (handler->hadFatalError()) {
141 errorMessage = QStringLiteral("Could not parse ULog");
142 return false;
143 }
144
145 if (!handler->isHeaderComplete()) {
146 errorMessage = QStringLiteral("Could not parse ULog header");
147 return false;
148 }
149
150 return true;
151}
152
153} // namespace ULogUtility
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void addLoggedMessage(const ulog_cpp::AddLoggedMessage &add_logged_message) override
void messageFormat(const ulog_cpp::MessageFormat &message_format) override
void headerComplete() override
void data(const ulog_cpp::Data &data) override
void error(const std::string &msg, bool is_recoverable) override
std::function< bool(const ulog_cpp::TypedDataView &sample)> MessageCallback
Definition ULogUtility.h:59
uint64_t getHeaderTimestamp(const char *data, qint64 size)
bool iterateMessages(const char *data, qint64 size, const std::string &messageName, const MessageCallback &callback, QString &errorMessage)
constexpr int kHeaderSize
Definition ULogUtility.h:28
constexpr char kMagicBytes[]
ULog file magic bytes: "ULog" followed by 0x01 (version 1) followed by 0x12 (file compat)
Definition ULogUtility.h:26
constexpr int kMagicSize
Definition ULogUtility.h:27
int getVersion(const char *data, qint64 size)