forked from PlotJuggler/plotjuggler-ros-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson_string_parser.cpp
More file actions
168 lines (144 loc) · 4.72 KB
/
json_string_parser.cpp
File metadata and controls
168 lines (144 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "json_string_parser.h"
#include <QDebug>
#include <cstdint>
#include <stdexcept>
using namespace PJ;
namespace
{
uint32_t ReadLe32(const uint8_t* ptr)
{
return (uint32_t(ptr[0]) << 0) | (uint32_t(ptr[1]) << 8) | (uint32_t(ptr[2]) << 16) |
(uint32_t(ptr[3]) << 24);
}
}
JsonStringParser::JsonStringParser(const std::string& topic_name, PJ::PlotDataMapRef& data)
: MessageParser(topic_name, data)
{
qInfo().noquote() << QString("[JsonStringParser] created parser for topic=%1")
.arg(QString::fromStdString(topic_name));
}
QString JsonStringParser::topicPrefix() const
{
return QString::fromStdString(_topic_name);
}
bool JsonStringParser::parseRos2StringPayload(const PJ::MessageRef serialized_msg, std::string& text) const
{
const uint8_t* data = serialized_msg.data();
const size_t size = serialized_msg.size();
if (size < 8)
{
qWarning().noquote() << QString("[%1] ROS2 String message too short to parse (%2 bytes)")
.arg(topicPrefix())
.arg(size);
return false;
}
const uint32_t cdr_header = ReadLe32(data);
if (cdr_header != 0x00010000 && cdr_header != 0x00000000)
{
qWarning().noquote() << QString("[%1] unexpected CDR encapsulation for std_msgs/String: 0x%2")
.arg(topicPrefix())
.arg(cdr_header, 8, 16, QLatin1Char('0'));
}
const uint32_t string_size = ReadLe32(data + 4);
const size_t payload_end = size_t(8) + size_t(string_size);
if (payload_end > size || string_size == 0)
{
qWarning().noquote() << QString("[%1] invalid std_msgs/String payload size: %2")
.arg(topicPrefix())
.arg(string_size);
return false;
}
const char* str_ptr = reinterpret_cast<const char*>(data + 8);
if (str_ptr[string_size - 1] != '\0')
{
qWarning().noquote() << QString("[%1] std_msgs/String payload is not null-terminated")
.arg(topicPrefix());
return false;
}
text.assign(str_ptr, str_ptr + string_size - 1);
return true;
}
void JsonStringParser::pushNumeric(const std::string& key, double timestamp, double value)
{
if (key.empty())
{
return;
}
const QString qkey = QString::fromStdString(key);
if (!_known_series.contains(qkey))
{
if (_known_series.size() >= qsizetype(_max_series))
{
qWarning().noquote() << QString("[%1] refusing to create additional JSON series beyond limit %2: %3")
.arg(topicPrefix())
.arg(_max_series)
.arg(qkey);
return;
}
_known_series.insert(qkey);
}
getSeries(key).pushBack({ timestamp, value });
}
void JsonStringParser::flattenJson(const nlohmann::json& value, const std::string& prefix,
double timestamp)
{
if (value.is_object())
{
for (auto it = value.begin(); it != value.end(); ++it)
{
const std::string child_key = prefix.empty() ? it.key() : prefix + "." + it.key();
flattenJson(it.value(), child_key, timestamp);
}
return;
}
if (value.is_number_integer())
{
pushNumeric(prefix, timestamp, static_cast<double>(value.get<int64_t>()));
return;
}
if (value.is_number_unsigned())
{
pushNumeric(prefix, timestamp, static_cast<double>(value.get<uint64_t>()));
return;
}
if (value.is_number_float())
{
pushNumeric(prefix, timestamp, value.get<double>());
return;
}
}
bool JsonStringParser::parseMessage(const PJ::MessageRef serialized_msg, double& timestamp)
{
qInfo().noquote() << QString("[JsonStringParser] parseMessage topic=%1 size=%2 timestamp=%3")
.arg(topicPrefix())
.arg(serialized_msg.size())
.arg(timestamp, 0, 'g', 17);
std::string text;
if (!parseRos2StringPayload(serialized_msg, text))
{
return false;
}
nlohmann::json value;
try
{
value = nlohmann::json::parse(text);
}
catch (const std::exception& ex)
{
qWarning().noquote() << QString("[%1] failed to parse JSON from std_msgs/String: %2")
.arg(topicPrefix())
.arg(ex.what());
return false;
}
if (!value.is_object())
{
qWarning().noquote() << QString("[%1] expected top-level JSON object in std_msgs/String")
.arg(topicPrefix());
return false;
}
qInfo().noquote() << QString("[JsonStringParser] parsed JSON object topic=%1 keys=%2")
.arg(topicPrefix())
.arg(int(value.size()));
flattenJson(value, "", timestamp);
return true;
}