Skip to content

Commit 5653ea0

Browse files
author
Martin
committed
Parsing VAL attributes and assigning it to the signals
1 parent 284110b commit 5653ea0

File tree

5 files changed

+253
-13
lines changed

5 files changed

+253
-13
lines changed

include/libdbc/message.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ struct Message {
2929
ParseSignalsStatus parseSignals(const std::vector<uint8_t>& data, std::vector<double>& values) const;
3030

3131
void appendSignal(const Signal& signal);
32-
const std::vector<Signal> signals() const;
32+
const std::vector<Signal>& getSignals() const;
3333
uint32_t id() const;
34+
void addValueDescription(const std::string& signal_name, const std::vector<Signal::SignalValueDescriptions>&);
3435

3536
virtual bool operator==(const Message& rhs) const;
3637

include/libdbc/signal.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
namespace libdbc {
1010
struct Signal {
11+
struct SignalValueDescriptions {
12+
uint32_t value;
13+
std::string description;
14+
};
15+
1116
std::string name;
1217
bool is_multiplexed;
1318
uint32_t start_bit;
@@ -20,6 +25,7 @@ struct Signal {
2025
double max;
2126
std::string unit;
2227
std::vector<std::string> receivers;
28+
std::vector<SignalValueDescriptions> svDescriptions;
2329

2430
Signal() = delete;
2531
explicit Signal(std::string name,

src/dbc.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,119 @@ const auto unitPattern = "\"(.*)\""; // Random string
2525
const auto receiverPattern = "([\\w\\,]+|Vector__XXX)*";
2626
const auto whiteSpace = "\\s";
2727

28+
enum VALToken { Identifier = 0, CANId, SignalName, Value, Description };
29+
30+
struct VALObject {
31+
uint32_t can_id;
32+
std::string signal_name;
33+
std::vector<libdbc::Signal::SignalValueDescriptions> vd;
34+
};
35+
36+
bool parseVal(const std::string& str, VALObject& obj) {
37+
obj.signal_name = "";
38+
obj.vd.clear();
39+
auto state = Identifier;
40+
const char* a = str.data();
41+
libdbc::Signal::SignalValueDescriptions vd;
42+
for (;;) {
43+
switch (state) {
44+
case Identifier: {
45+
if (*a != 'V')
46+
return false;
47+
a++;
48+
if (*a != 'A')
49+
return false;
50+
a++;
51+
if (*a != 'L')
52+
return false;
53+
a++;
54+
if (*a != '_')
55+
return false;
56+
a++;
57+
if (*a != ' ')
58+
return false;
59+
a++; // skip whitespace
60+
state = CANId;
61+
break;
62+
}
63+
case CANId: {
64+
std::string can_id_str;
65+
while (*a >= '0' && *a <= '9') {
66+
can_id_str += *a;
67+
a++;
68+
}
69+
if (can_id_str.empty())
70+
return false;
71+
obj.can_id = std::stoul(can_id_str);
72+
if (*a != ' ')
73+
return false;
74+
a++; // skip whitespace
75+
state = SignalName;
76+
break;
77+
}
78+
case SignalName: {
79+
if ((*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || *a == '_')
80+
obj.signal_name += *a;
81+
else
82+
return false;
83+
a++;
84+
while ((*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || *a == '_' || (*a >= '0' && *a <= '9')) {
85+
obj.signal_name += *a;
86+
a++;
87+
}
88+
if (*a != ' ')
89+
return false;
90+
a++; // skip whitespace
91+
state = Value;
92+
break;
93+
}
94+
case Value: {
95+
std::string value_str;
96+
while (*a >= '0' && *a <= '9') {
97+
value_str += *a;
98+
a++;
99+
}
100+
if (*a == ';') {
101+
if (value_str.empty())
102+
return true;
103+
return false;
104+
}
105+
if (value_str.empty())
106+
return false;
107+
108+
if (*a != ' ')
109+
return false;
110+
a++; // skip whitespace
111+
vd.value = (uint32_t)std::stoul(value_str);
112+
state = Description;
113+
break;
114+
}
115+
case Description: {
116+
std::string desc;
117+
if (*a != '"')
118+
return false;
119+
a++;
120+
while (*a != '"' && *a != 0) {
121+
desc += *a;
122+
a++;
123+
}
124+
if (*a == 0)
125+
return false;
126+
a++;
127+
if (*a != ' ')
128+
return false;
129+
a++; // skip whitespace
130+
131+
vd.description = desc;
132+
obj.vd.push_back(vd);
133+
134+
state = Value;
135+
break;
136+
}
137+
}
138+
}
139+
}
140+
28141
} // anonymous namespace
29142

30143
namespace libdbc {
@@ -123,6 +236,9 @@ void DbcParser::parse_dbc_nodes(std::istream& file_stream) {
123236
void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
124237
std::smatch match;
125238

239+
std::vector<VALObject> sv;
240+
241+
VALObject obj;
126242
for (const auto& line : lines) {
127243
if (std::regex_search(line, match, message_re)) {
128244
uint32_t id = std::stoul(match.str(2));
@@ -133,6 +249,7 @@ void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
133249
Message msg(id, name, size, node);
134250

135251
messages.push_back(msg);
252+
continue;
136253
}
137254

138255
if (std::regex_search(line, match, signal_re)) {
@@ -158,6 +275,21 @@ void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
158275

159276
Signal sig(name, is_multiplexed, start_bit, size, is_bigendian, is_signed, factor, offset, min, max, unit, receivers);
160277
messages.back().appendSignal(sig);
278+
continue;
279+
}
280+
281+
if (parseVal(line, obj)) {
282+
sv.push_back(obj);
283+
continue;
284+
}
285+
}
286+
287+
for (const auto& obj : sv) {
288+
for (auto& msg : messages) {
289+
if (msg.id() == obj.can_id) {
290+
msg.addValueDescription(obj.signal_name, obj.vd);
291+
break;
292+
}
161293
}
162294
}
163295
}

src/message.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,23 @@ void Message::appendSignal(const Signal& signal) {
6767
m_signals.push_back(signal);
6868
}
6969

70-
const std::vector<Signal> Message::signals() const {
70+
const std::vector<Signal>& Message::getSignals() const {
7171
return m_signals;
7272
}
7373

7474
uint32_t Message::id() const {
7575
return m_id;
7676
}
7777

78+
void Message::addValueDescription(const std::string& signal_name, const std::vector<Signal::SignalValueDescriptions>& vd) {
79+
for (auto& s : m_signals) {
80+
if (s.name.compare(signal_name) == 0) {
81+
s.svDescriptions = vd;
82+
return;
83+
}
84+
}
85+
}
86+
7887
std::ostream& operator<<(std::ostream& out, const Message& msg) {
7988
out << "Message: {id: " << msg.id() << ", ";
8089
out << "name: " << msg.m_name << ", ";

test/test_dbc.cpp

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ TEST_CASE("Testing dbc file loading", "[fileio]") {
5757

5858
REQUIRE(parser->get_messages() == msgs);
5959

60-
REQUIRE(parser->get_messages().front().signals() == msg.signals());
60+
REQUIRE(parser->get_messages().front().getSignals() == msg.getSignals());
6161
}
6262
}
6363

@@ -80,13 +80,13 @@ TEST_CASE("Testing big endian, little endian") {
8080
parser.parse_file(filename);
8181

8282
REQUIRE(parser.get_messages().size() == 1);
83-
REQUIRE(parser.get_messages().at(0).signals().size() == 2);
83+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);
8484
{
85-
const auto signal = parser.get_messages().at(0).signals().at(0);
85+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
8686
REQUIRE(signal.is_bigendian == true);
8787
}
8888
{
89-
const auto signal = parser.get_messages().at(0).signals().at(1);
89+
const auto signal = parser.get_messages().at(0).getSignals().at(1);
9090
REQUIRE(signal.is_bigendian == false);
9191
}
9292
}
@@ -104,31 +104,31 @@ TEST_CASE("Testing negative values") {
104104
parser.parse_file(filename);
105105

106106
REQUIRE(parser.get_messages().size() == 1);
107-
REQUIRE(parser.get_messages().at(0).signals().size() == 4);
107+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 4);
108108

109109
SECTION("Evaluating first message") {
110-
const auto signal = parser.get_messages().at(0).signals().at(0);
110+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
111111
REQUIRE(signal.factor == 0.1);
112112
REQUIRE(signal.offset == 0);
113113
REQUIRE(signal.min == -3276.8);
114114
REQUIRE(signal.max == -3276.7);
115115
}
116116
SECTION("Evaluating second message") {
117-
const auto signal = parser.get_messages().at(0).signals().at(1);
117+
const auto signal = parser.get_messages().at(0).getSignals().at(1);
118118
REQUIRE(signal.factor == 0.1);
119119
REQUIRE(signal.offset == 0);
120120
REQUIRE(signal.min == -3276.8);
121121
REQUIRE(signal.max == -3276.7);
122122
}
123123
SECTION("Evaluating third message") {
124-
const auto signal = parser.get_messages().at(0).signals().at(2);
124+
const auto signal = parser.get_messages().at(0).getSignals().at(2);
125125
REQUIRE(signal.factor == 10);
126126
REQUIRE(signal.offset == 0);
127127
REQUIRE(signal.min == -3276.8);
128128
REQUIRE(signal.max == -3276.7);
129129
}
130130
SECTION("Evaluating fourth message") {
131-
const auto signal = parser.get_messages().at(0).signals().at(3);
131+
const auto signal = parser.get_messages().at(0).getSignals().at(3);
132132
REQUIRE(signal.factor == 1);
133133
REQUIRE(signal.offset == -10);
134134
REQUIRE(signal.min == 0);
@@ -146,9 +146,101 @@ TEST_CASE("Special characters in unit") {
146146
parser.parse_file(filename);
147147

148148
REQUIRE(parser.get_messages().size() == 1);
149-
REQUIRE(parser.get_messages().at(0).signals().size() == 1);
149+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 1);
150150
SECTION("Checking that signal with special characters as unit is parsed correctly") {
151-
const auto signal = parser.get_messages().at(0).signals().at(0);
151+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
152152
REQUIRE(signal.unit.compare("Km/h") == 0);
153153
}
154154
}
155+
156+
TEST_CASE("Signal Value Description") {
157+
const auto* filename = std::tmpnam(NULL);
158+
159+
create_tmp_dbc_with(filename, R"(BO_ 234 MSG1: 8 Vector__XXX
160+
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
161+
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3
162+
VAL_ 234 State1 123 "Description 1" 0 "Description 2" 90903489 "Big value and special characters &$§())!" ;)");
163+
164+
auto parser = libdbc::DbcParser();
165+
parser.parse_file(filename);
166+
167+
REQUIRE(parser.get_messages().size() == 1);
168+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);
169+
170+
REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 3);
171+
REQUIRE(parser.get_messages().at(0).getSignals().at(1).svDescriptions.size() == 0);
172+
173+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
174+
REQUIRE(signal.svDescriptions.at(0).value == 123);
175+
REQUIRE(signal.svDescriptions.at(0).description == "Description 1");
176+
REQUIRE(signal.svDescriptions.at(1).value == 0);
177+
REQUIRE(signal.svDescriptions.at(1).description == "Description 2");
178+
REQUIRE(signal.svDescriptions.at(2).value == 90903489);
179+
REQUIRE(signal.svDescriptions.at(2).description == "Big value and special characters &$§())!");
180+
}
181+
182+
TEST_CASE("Signal Value Description Extended CAN id") {
183+
/*
184+
* It should not crash, even extended CAN id is used
185+
*/
186+
const auto* filename = std::tmpnam(NULL);
187+
188+
create_tmp_dbc_with(filename, R"(BO_ 3221225472 MSG1: 8 Vector__XXX
189+
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
190+
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3
191+
VAL_ 3221225472 State1 123 "Description 1" 0 "Description 2" 4000000000 "Big value and special characters &$§())!" ;)");
192+
193+
auto parser = libdbc::DbcParser();
194+
parser.parse_file(filename);
195+
196+
REQUIRE(parser.get_messages().size() == 1);
197+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);
198+
199+
REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 3);
200+
REQUIRE(parser.get_messages().at(0).getSignals().at(1).svDescriptions.size() == 0);
201+
202+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
203+
REQUIRE(signal.svDescriptions.at(0).value == 123);
204+
REQUIRE(signal.svDescriptions.at(0).description == "Description 1");
205+
REQUIRE(signal.svDescriptions.at(1).value == 0);
206+
REQUIRE(signal.svDescriptions.at(1).description == "Description 2");
207+
REQUIRE(signal.svDescriptions.at(2).value == 4000000000);
208+
REQUIRE(signal.svDescriptions.at(2).description == "Big value and special characters &$§())!");
209+
}
210+
211+
TEST_CASE("Signal Value Multiple VAL_") {
212+
/*
213+
* It should not crash, even extended CAN id is used
214+
*/
215+
const auto* filename = std::tmpnam(NULL);
216+
217+
create_tmp_dbc_with(filename, R"(BO_ 3221225472 MSG1: 8 Vector__XXX
218+
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
219+
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3"
220+
BO_ 123 MSG1: 8 Vector__XXX
221+
SG_ State1 : 0|8@1+ (1,0) [0|200] "Km/h" DEVICE1,DEVICE2,DEVICE3
222+
SG_ State2 : 0|8@1+ (1,0) [0|204] "" DEVICE1,DEVICE2,DEVICE3
223+
VAL_ 3221225472 State1 123 "Description 1" 0 "Description 2"
224+
VAL_ 123 State1 123 "Description 3" 0 "Description 4")");
225+
226+
auto parser = libdbc::DbcParser();
227+
parser.parse_file(filename);
228+
229+
REQUIRE(parser.get_messages().size() == 1);
230+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 2);
231+
232+
REQUIRE(parser.get_messages().at(0).getSignals().at(0).svDescriptions.size() == 2);
233+
REQUIRE(parser.get_messages().at(0).getSignals().at(1).svDescriptions.size() == 2);
234+
235+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
236+
REQUIRE(signal.svDescriptions.at(0).value == 123);
237+
REQUIRE(signal.svDescriptions.at(0).description == "Description 1");
238+
REQUIRE(signal.svDescriptions.at(1).value == 0);
239+
REQUIRE(signal.svDescriptions.at(1).description == "Description 2");
240+
241+
const auto signal2 = parser.get_messages().at(0).getSignals().at(0);
242+
REQUIRE(signal2.svDescriptions.at(0).value == 123);
243+
REQUIRE(signal2.svDescriptions.at(0).description == "Description 3");
244+
REQUIRE(signal2.svDescriptions.at(1).value == 0);
245+
REQUIRE(signal2.svDescriptions.at(1).description == "Description 4");
246+
}

0 commit comments

Comments
 (0)