diff --git a/docs/doxygen_warnings.log b/docs/doxygen_warnings.log index cf37f61..bdf9ccb 100644 --- a/docs/doxygen_warnings.log +++ b/docs/doxygen_warnings.log @@ -2,7 +2,7 @@ /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:22: warning: Compound DbcFrameHandler is not documented. /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:30: warning: Compound DbcSignalHandler is not documented. /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:16: warning: Compound DbcStatementHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/main.cpp:98: warning: Member main(int argc, char *argv[]) (function) of file main.cpp is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/main.cpp:101: warning: Member main(int argc, char *argv[]) (function) of file main.cpp is not documented. /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:40: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcCommentHandler is not documented. /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:24: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcFrameHandler is not documented. /home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:12: warning: Member database (variable) of struct DbcParseContext is not documented. diff --git a/docs/html/classDbcCommentHandler.html b/docs/html/classDbcCommentHandler.html index 9dac6f5..98aaefc 100644 --- a/docs/html/classDbcCommentHandler.html +++ b/docs/html/classDbcCommentHandler.html @@ -149,7 +149,7 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 302 of file dbc_statement_handler.cpp.

+

Definition at line 303 of file dbc_statement_handler.cpp.

diff --git a/docs/html/classDbcFrameHandler.html b/docs/html/classDbcFrameHandler.html index d59b675..8dd89a5 100644 --- a/docs/html/classDbcFrameHandler.html +++ b/docs/html/classDbcFrameHandler.html @@ -149,7 +149,7 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 280 of file dbc_statement_handler.cpp.

+

Definition at line 281 of file dbc_statement_handler.cpp.

diff --git a/docs/html/classDbcParser.html b/docs/html/classDbcParser.html index ca824d9..84f346e 100644 --- a/docs/html/classDbcParser.html +++ b/docs/html/classDbcParser.html @@ -157,7 +157,7 @@ Public Member Functions

Definition at line 40 of file dbc_parser.cpp.

-

References DbcStatementDispatcher::Dispatch().

+

References DbcStatementDispatcher::Dispatch().

diff --git a/docs/html/classDbcSignalHandler.html b/docs/html/classDbcSignalHandler.html index 27a9a4f..e8ac567 100644 --- a/docs/html/classDbcSignalHandler.html +++ b/docs/html/classDbcSignalHandler.html @@ -149,7 +149,7 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 285 of file dbc_statement_handler.cpp.

+

Definition at line 286 of file dbc_statement_handler.cpp.

diff --git a/docs/html/classDbcStatementDispatcher.html b/docs/html/classDbcStatementDispatcher.html index 2b4ab73..7de847b 100644 --- a/docs/html/classDbcStatementDispatcher.html +++ b/docs/html/classDbcStatementDispatcher.html @@ -127,7 +127,7 @@ Public Member Functions
-

Definition at line 307 of file dbc_statement_handler.cpp.

+

Definition at line 308 of file dbc_statement_handler.cpp.

@@ -189,7 +189,7 @@ template<class Handler >

Returns false for an unregistered keyword; input must be trimmed.

-

Definition at line 313 of file dbc_statement_handler.cpp.

+

Definition at line 314 of file dbc_statement_handler.cpp.

Referenced by DbcParser::ParseFile().

diff --git a/docs/html/dbc__decoder_8cpp_source.html b/docs/html/dbc__decoder_8cpp_source.html index f7ac376..d52d007 100644 --- a/docs/html/dbc__decoder_8cpp_source.html +++ b/docs/html/dbc__decoder_8cpp_source.html @@ -150,105 +150,106 @@ $(document).ready(function(){initNavTree('dbc__decoder_8cpp_source.html',''); in
57 else
58 decoded.rawValue = unsignedValue;
59
-
60 decoded.physicalValue =
-
61 std::visit([&signal](auto rawValue) {
-
62 return (static_cast<double>(rawValue) * signal.factor) + signal.offset;
-
63 },
-
64 decoded.rawValue);
-
65 decoded.valid = true;
-
66
-
67 result.signals.push_back(decoded);
-
68 }
-
69
-
70 return result;
-
71}
+
60 double numericValue;
+
61 if (const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
+
62 numericValue = static_cast<double>(*signedValue);
+
63 else
+
64 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
+
65 decoded.physicalValue = numericValue * signal.factor + signal.offset;
+
66 decoded.valid = true;
+
67
+
68 result.signals.push_back(decoded);
+
69 }
+
70
+
71 return result;
+
72}
-
72
-
73bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
-
74 const DecodeSignal &signal,
-
75 std::uint64_t &value) {
-
76 if ((signal.length == 0U) || (signal.length > 64U))
-
77 return false;
-
78
-
79 if (signal.byteOrder == ByteOrder::Intel)
-
80 return ExtractIntel(data, signal.startBit, signal.length, value);
-
81
-
82 return ExtractMotorola(data, signal.startBit, signal.length, value);
-
83}
-
84
-
85bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
-
86 std::uint32_t startBit,
-
87 std::uint32_t length,
-
88 std::uint64_t &value) {
-
89 value = 0U;
-
90
-
91 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
-
92 const std::uint32_t absoluteBit = startBit + bitIndex;
-
93 const std::uint32_t byteIndex = absoluteBit / 8U;
-
94 const std::uint32_t bitInByte = absoluteBit % 8U;
-
95
-
96 if (byteIndex >= data.size())
-
97 return false;
-
98
-
99 const std::uint64_t bitValue =
-
100 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
-
101
-
102 value |= bitValue;
-
103 }
-
104
-
105 return true;
-
106}
-
107
-
108bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
-
109 std::uint32_t startBit,
-
110 std::uint32_t length,
-
111 std::uint64_t &value) {
-
112 /*
-
113 * DBC Motorola bit numbering:
-
114 * - startBit points to the most significant bit of the signal
-
115 * - inside a byte, bit numbering goes 7..0
-
116 * - crossing byte boundary moves to the next byte, bit 7
-
117 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
-
118 */
-
119
-
120 value = 0U;
-
121
-
122 std::size_t byteIndex = startBit / 8U;
-
123 std::uint32_t bitInByte = startBit % 8U;
-
124
-
125 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
-
126 if (byteIndex >= data.size())
-
127 return false;
-
128
-
129 value <<= 1U;
-
130 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
-
131
-
132 if (bitInByte == 0U) {
-
133 ++byteIndex;
-
134 bitInByte = 7U;
-
135 } else
-
136 --bitInByte;
-
137 }
-
138
-
139 return true;
-
140}
-
141
-
142std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
-
143 if ((bitLength == 0U) || (bitLength > 64U))
-
144 return 0;
-
145
-
146 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
-
147 const std::uint64_t valueMask = (bitLength == 64U)
-
148 ? ~std::uint64_t(0U)
-
149 : (std::uint64_t(1U) << bitLength) - 1U;
-
150 value &= valueMask;
-
151
-
152 if ((value & signMask) == 0U)
-
153 return static_cast<std::int64_t>(value);
-
154
-
155 // The complemented magnitude fits int64_t, including for INT64_MIN.
-
156 return -1 - static_cast<std::int64_t>((~value) & valueMask);
-
157}
+
73
+
74bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
+
75 const DecodeSignal &signal,
+
76 std::uint64_t &value) {
+
77 if ((signal.length == 0U) || (signal.length > 64U))
+
78 return false;
+
79
+
80 if (signal.byteOrder == ByteOrder::Intel)
+
81 return ExtractIntel(data, signal.startBit, signal.length, value);
+
82
+
83 return ExtractMotorola(data, signal.startBit, signal.length, value);
+
84}
+
85
+
86bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
+
87 std::uint32_t startBit,
+
88 std::uint32_t length,
+
89 std::uint64_t &value) {
+
90 value = 0U;
+
91
+
92 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
+
93 const std::uint32_t absoluteBit = startBit + bitIndex;
+
94 const std::uint32_t byteIndex = absoluteBit / 8U;
+
95 const std::uint32_t bitInByte = absoluteBit % 8U;
+
96
+
97 if (byteIndex >= data.size())
+
98 return false;
+
99
+
100 const std::uint64_t bitValue =
+
101 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
+
102
+
103 value |= bitValue;
+
104 }
+
105
+
106 return true;
+
107}
+
108
+
109bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
+
110 std::uint32_t startBit,
+
111 std::uint32_t length,
+
112 std::uint64_t &value) {
+
113 /*
+
114 * DBC Motorola bit numbering:
+
115 * - startBit points to the most significant bit of the signal
+
116 * - inside a byte, bit numbering goes 7..0
+
117 * - crossing byte boundary moves to the next byte, bit 7
+
118 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
+
119 */
+
120
+
121 value = 0U;
+
122
+
123 std::size_t byteIndex = startBit / 8U;
+
124 std::uint32_t bitInByte = startBit % 8U;
+
125
+
126 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
+
127 if (byteIndex >= data.size())
+
128 return false;
+
129
+
130 value <<= 1U;
+
131 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
+
132
+
133 if (bitInByte == 0U) {
+
134 ++byteIndex;
+
135 bitInByte = 7U;
+
136 } else
+
137 --bitInByte;
+
138 }
+
139
+
140 return true;
+
141}
+
142
+
143std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
+
144 if ((bitLength == 0U) || (bitLength > 64U))
+
145 return 0;
+
146
+
147 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
+
148 const std::uint64_t valueMask = (bitLength == 64U)
+
149 ? ~std::uint64_t(0U)
+
150 : (std::uint64_t(1U) << bitLength) - 1U;
+
151 value &= valueMask;
+
152
+
153 if ((value & signMask) == 0U)
+
154 return static_cast<std::int64_t>(value);
+
155
+
156 // The complemented magnitude fits int64_t, including for INT64_MIN.
+
157 return -1 - static_cast<std::int64_t>((~value) & valueMask);
+
158}
DbcDecoder::Decode
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
Definition dbc_decoder.cpp:31
DbcDecoder::FindFrame
const DecodeFrame * FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
Find frame definition by CAN ID.
Definition dbc_decoder.cpp:14
dbc_decoder.h
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
diff --git a/docs/html/dbc__decoder__test_8cpp_source.html b/docs/html/dbc__decoder__test_8cpp_source.html index f14acf6..1279b8e 100644 --- a/docs/html/dbc__decoder__test_8cpp_source.html +++ b/docs/html/dbc__decoder__test_8cpp_source.html @@ -218,25 +218,28 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
118 10.0;
119 std::ostringstream actualText;
120 std::ostringstream expectedText;
-
121 std::visit([&actualText](auto raw) { actualText << raw; }, decoded.rawValue);
-
122 if (type == ValueType::Unsigned)
-
123 expectedText << bits;
-
124 else
-
125 expectedText << signedExpected;
-
126 if (!decoded.valid || decoded.rawValue != expected ||
-
127 decoded.physicalValue != physical || actualText.str() != expectedText.str()) {
-
128 std::cerr << "FAIL: 64-bit boundary " << bits << '\n';
-
129 ++failures;
-
130 }
-
131 ++boundaryCases;
-
132 }
-
133 }
-
134 }
-
135 if (failures != 0)
-
136 return 1;
-
137 std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n";
-
138 return 0;
-
139}
+
121 if (const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
+
122 actualText << *signedValue;
+
123 else
+
124 actualText << std::get<std::uint64_t>(decoded.rawValue);
+
125 if (type == ValueType::Unsigned)
+
126 expectedText << bits;
+
127 else
+
128 expectedText << signedExpected;
+
129 if (!decoded.valid || decoded.rawValue != expected ||
+
130 decoded.physicalValue != physical || actualText.str() != expectedText.str()) {
+
131 std::cerr << "FAIL: 64-bit boundary " << bits << '\n';
+
132 ++failures;
+
133 }
+
134 ++boundaryCases;
+
135 }
+
136 }
+
137 }
+
138 if (failures != 0)
+
139 return 1;
+
140 std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n";
+
141 return 0;
+
142}
DbcDecoder
Runtime CAN decoder using prebuilt decode database.
Definition dbc_decoder.h:64
DbcDecoder::Decode
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
Definition dbc_decoder.cpp:31
dbc_decoder.h
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
diff --git a/docs/html/dbc__parser_8cpp_source.html b/docs/html/dbc__parser_8cpp_source.html index 379414a..fa3fa3c 100644 --- a/docs/html/dbc__parser_8cpp_source.html +++ b/docs/html/dbc__parser_8cpp_source.html @@ -157,7 +157,7 @@ $(document).ready(function(){initNavTree('dbc__parser_8cpp_source.html',''); ini
70}
DbcParser::ParseFile
DbcDatabase ParseFile(const std::string &filePath) const
Parse DBC file.
Definition dbc_parser.cpp:40
DbcStatementDispatcher
Definition dbc_statement_handler.h:47
-
DbcStatementDispatcher::Dispatch
bool Dispatch(const std::string &line, DbcParseContext &context) const
Definition dbc_statement_handler.cpp:313
+
DbcStatementDispatcher::Dispatch
bool Dispatch(const std::string &line, DbcParseContext &context) const
Definition dbc_statement_handler.cpp:314
dbc_parser.h
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
DbcDatabase
Parsed DBC content stored in a simple internal form.
Definition dbc_database.h:22
DbcParseContext
Definition dbc_statement_handler.h:11
diff --git a/docs/html/dbc__parser__test_8cpp_source.html b/docs/html/dbc__parser__test_8cpp_source.html index 67f8873..5f11c75 100644 --- a/docs/html/dbc__parser__test_8cpp_source.html +++ b/docs/html/dbc__parser__test_8cpp_source.html @@ -133,228 +133,233 @@ $(document).ready(function(){initNavTree('dbc__parser__test_8cpp_source.html',''
33 }
34};
35
-
36int main() {
-
37 Fixture fixture;
-
38 int failures = 0;
-
39 std::size_t count = 0U;
-
40 const auto check = [&](bool passed, const std::string &name) {
-
41 ++count;
-
42 if (!passed) {
-
43 ++failures;
-
44 std::cerr << "FAIL: " << name << '\n';
-
45 }
-
46 };
-
47 struct ValidCase {
-
48 const char *line;
-
49 std::uint32_t id;
-
50 bool extended;
-
51 unsigned length;
-
52 };
-
53 const ValidCase valid[] = {
-
54 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
-
55 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
-
56 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
-
57 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
-
58 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
-
59 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
-
60 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
-
61 for (const auto &test: valid) {
-
62 fixture.Write(std::string(test.line) + '\n');
-
63 try {
-
64 const auto database = DbcParser().ParseFile(fixture.path.string());
-
65 check(database.frames.size() == 1U && database.frames[0].name == "Frame" &&
-
66 database.frames[0].canId == test.id &&
-
67 database.frames[0].isExtended == test.extended &&
-
68 database.frames[0].dlc == test.length &&
-
69 database.frames[0].transmitter == "ECU",
-
70 test.line);
-
71 } catch (const std::exception &error) { check(false, error.what()); }
-
72 }
-
73 const char *invalid[] = {
-
74 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
-
75 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
-
76 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
-
77 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
-
78 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
-
79 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
-
80 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
-
81 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
-
82 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
-
83 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
-
84 for (const auto *line: invalid) {
-
85 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
-
86 try {
-
87 DbcParser().ParseFile(fixture.path.string());
-
88 check(false, line);
-
89 } catch (const std::runtime_error &error) {
-
90 const std::string prefix = fixture.path.string() + ":3: ";
-
91 check(std::string(error.what()).find(prefix) == 0U &&
-
92 std::string(error.what()).size() > prefix.size(),
-
93 line);
-
94 }
-
95 }
-
96 fixture.Write(
-
97 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
-
98 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
-
99 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
-
100 "BO_ 257 Second: 8 ECU\n");
-
101 const auto database = DbcParser().ParseFile(fixture.path.string());
-
102 check(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
-
103 database.frames[0].comment == "Frame comment" &&
-
104 database.frames[0].signals[0].comment == "Signal comment",
-
105 "Integration");
-
106 fixture.Write("\nSG_ Speed : invalid\n");
-
107 try {
-
108 DbcParser().ParseFile(fixture.path.string());
-
109 check(false, "Signal error location");
-
110 } catch (const std::runtime_error &error) {
-
111 check(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
-
112 "Signal error location");
-
113 }
-
114 const DbcParser signalParser;
-
115 const auto signalLine = [](const std::string &start, const std::string &length,
-
116 const std::string &order, const std::string &factor,
-
117 const std::string &offset, const std::string &minimum,
-
118 const std::string &maximum) {
-
119 return "SG_ Value : " + start + "|" + length + "@" + order +
-
120 " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU";
-
121 };
-
122 const auto rejectSignal = [&](const std::string &line, unsigned payload = 8U) {
-
123 fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n");
-
124 try {
-
125 signalParser.ParseFile(fixture.path.string());
-
126 check(false, "Reject " + line);
-
127 } catch (const std::runtime_error &error) {
-
128 const std::string prefix = fixture.path.string() + ":3: ";
-
129 check(std::string(error.what()).find(prefix) == 0U &&
-
130 std::string(error.what()).size() > prefix.size(),
-
131 "Reject " + line);
-
132 }
-
133 };
-
134 const std::string ordinary = signalLine("0", "8", "1+", "1", "0", "0", "255");
-
135 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
-
136 "4294967296", "999999999999999999999"}) {
-
137 rejectSignal(signalLine(value, "8", "1+", "1", "0", "0", "255"));
-
138 rejectSignal(signalLine("0", value, "1+", "1", "0", "0", "255"));
-
139 }
-
140 for (const std::string length: {"0", "65"})
-
141 rejectSignal(signalLine("0", length, "1+", "1", "0", "0", "255"));
-
142 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
-
143 rejectSignal(signalLine("0", "8", order, "1", "0", "0", "255"));
-
144 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
-
145 rejectSignal(signalLine("0", "8", "1+", value, "0", "0", "255"));
-
146 rejectSignal(signalLine("0", "8", "1+", "1", value, "0", "255"));
-
147 rejectSignal(signalLine("0", "8", "1+", "1", "0", value, "255"));
-
148 rejectSignal(signalLine("0", "8", "1+", "1", "0", "0", value));
-
149 }
-
150 rejectSignal(signalLine("0", "8", "1+", "1", "0", "2", "1"));
-
151 for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) {
-
152 std::string line = ordinary;
-
153 line.replace(4U, 5U, name);
-
154 rejectSignal(line);
-
155 }
-
156 for (const std::string broken: {
-
157 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
-
158 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
-
159 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
-
160 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
-
161 rejectSignal(broken);
-
162 rejectSignal(signalLine("64", "1", "1+", "1", "0", "0", "1"));
-
163 rejectSignal(signalLine("63", "2", "1+", "1", "0", "0", "3"));
-
164 rejectSignal(signalLine("56", "2", "0+", "1", "0", "0", "3"));
-
165 rejectSignal(signalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
-
166 rejectSignal(ordinary, 0U);
-
167 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
-
168 std::string line = ordinary;
-
169 line.erase(line.find(delimiter), 1U);
-
170 rejectSignal(line);
-
171 }
-
172 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
-
173 signalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
-
174 signalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n");
-
175 const auto factors = signalParser.ParseFile(fixture.path.string());
-
176 check(factors.frames[0].signals.size() == 2U &&
-
177 factors.frames[0].signals[0].factor == 0.0 &&
-
178 factors.frames[0].signals[1].factor == -1.0,
-
179 "Zero and negative factors and equal range boundaries");
-
180
-
181 struct SignalCase {
-
182 const char *start;
-
183 const char *length;
-
184 const char *order;
-
185 unsigned payload;
-
186 };
-
187 const SignalCase validSignals[] = {
-
188 {"0", "1", "1+", 1U},
-
189 {"7", "1", "0-", 1U},
-
190 {"0", "64", "1+", 8U},
-
191 {"7", "64", "0-", 8U},
-
192 {"63", "1", "1+", 8U},
-
193 {"56", "1", "0+", 8U},
-
194 {"3", "12", "0+", 2U},
-
195 {"2039", "1", "1+", 255U}};
-
196 for (const auto &test: validSignals) {
-
197 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
-
198 signalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
-
199 try {
-
200 const auto parsed = signalParser.ParseFile(fixture.path.string());
-
201 const auto &signal = parsed.frames.at(0).signals.at(0);
-
202 check(signal.startBit == std::stoul(test.start) &&
-
203 signal.length == std::stoul(test.length) &&
-
204 signal.isLittleEndian == (test.order[0] == '1') &&
-
205 signal.isSigned == (test.order[1] == '-') &&
-
206 signal.factor == 5.0 && signal.offset == -0.25 &&
-
207 signal.minimum == -1.0 && signal.maximum == 200.0,
-
208 "Valid signal boundary and numeric metadata");
-
209 } catch (const std::exception &error) { check(false, error.what()); }
-
210 }
-
211 fixture.Write("BO_ 1 Frame: 8 ECU\n"
-
212 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
-
213 try {
-
214 const auto parsed = signalParser.ParseFile(fixture.path.string());
-
215 const auto &signal = parsed.frames.at(0).signals.at(0);
-
216 check(signal.name == "Value" && signal.unit == "rpm" &&
-
217 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
-
218 "Signal tabs, spaces, and receiver list");
-
219 } catch (const std::exception &error) { check(false, error.what()); }
-
220 DbcDatabase dispatchDatabase;
-
221 DbcParseContext context{dispatchDatabase, nullptr};
-
222 DbcStatementDispatcher dispatcher;
-
223 dispatcher.RegisterType<CountingHandler>("TEST_");
-
224 check(dispatcher.Dispatch("TEST_ first", context) &&
-
225 dispatcher.Dispatch("TEST_ second", context) &&
-
226 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
-
227 dispatchDatabase.frames.size() == 2U,
-
228 "Factory dispatch and handler reuse");
-
229 check(!dispatcher.Dispatch("TEST_OTHER data", context) &&
-
230 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
-
231 !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) &&
-
232 CountingHandler::calls == 2,
-
233 "Exact and unknown keyword dispatch");
-
234 const DbcParser parser;
-
235 fixture.Write("BO_ 1 First: 8 ECU\n");
-
236 check(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
-
237 fixture.Write("SG_ Speed : invalid\n");
-
238 try {
-
239 parser.ParseFile(fixture.path.string());
-
240 check(false, "Independent parse context");
-
241 } catch (const std::runtime_error &error) {
-
242 check(std::string(error.what()).find("Signal found before any frame") !=
-
243 std::string::npos,
-
244 "Independent parse context");
-
245 }
-
246 fixture.Write("BO_ 2 Second: 8 ECU\n");
-
247 const auto recovered = parser.ParseFile(fixture.path.string());
-
248 check(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
-
249 "Fresh parse after error");
-
250 if (failures != 0) return 1;
-
251 std::cout << "All " << count << " parser cases passed.\n";
-
252 return 0;
-
253}
+
36std::string SignalLine(const std::string &start, const std::string &length,
+
37 const std::string &order, const std::string &factor,
+
38 const std::string &offset, const std::string &minimum,
+
39 const std::string &maximum) {
+
40 return "SG_ Value : " + start + "|" + length + "@" + order +
+
41 " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU";
+
42}
+
43
+
44struct TestContext {
+
45 int failures = 0;
+
46 std::size_t count = 0U;
+
47 void Check(bool passed, const std::string &name) {
+
48 ++count;
+
49 if (!passed) {
+
50 ++failures;
+
51 std::cerr << "FAIL: " << name << '\n';
+
52 }
+
53 }
+
54 void RejectSignal(const Fixture &fixture, const std::string &line, unsigned payload = 8U) {
+
55 fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n");
+
56 try {
+
57 DbcParser().ParseFile(fixture.path.string());
+
58 Check(false, "Reject " + line);
+
59 } catch (const std::runtime_error &error) {
+
60 const std::string prefix = fixture.path.string() + ":3: ";
+
61 Check(std::string(error.what()).find(prefix) == 0U &&
+
62 std::string(error.what()).size() > prefix.size(),
+
63 "Reject " + line);
+
64 }
+
65 }
+
66};
+
67
+
68int main() {
+
69 Fixture fixture;
+
70 TestContext tests;
+
71 struct ValidCase {
+
72 const char *line;
+
73 std::uint32_t id;
+
74 bool extended;
+
75 unsigned length;
+
76 };
+
77 const ValidCase valid[] = {
+
78 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
+
79 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
+
80 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
+
81 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
+
82 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
+
83 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
+
84 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
+
85 for (const auto &test: valid) {
+
86 fixture.Write(std::string(test.line) + '\n');
+
87 try {
+
88 const auto database = DbcParser().ParseFile(fixture.path.string());
+
89 tests.Check(database.frames.size() == 1U && database.frames[0].name == "Frame" &&
+
90 database.frames[0].canId == test.id &&
+
91 database.frames[0].isExtended == test.extended &&
+
92 database.frames[0].dlc == test.length &&
+
93 database.frames[0].transmitter == "ECU",
+
94 test.line);
+
95 } catch (const std::exception &error) { tests.Check(false, error.what()); }
+
96 }
+
97 const char *invalid[] = {
+
98 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
+
99 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
+
100 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
+
101 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
+
102 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
+
103 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
+
104 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
+
105 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
+
106 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
+
107 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
+
108 for (const auto *line: invalid) {
+
109 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
+
110 try {
+
111 DbcParser().ParseFile(fixture.path.string());
+
112 tests.Check(false, line);
+
113 } catch (const std::runtime_error &error) {
+
114 const std::string prefix = fixture.path.string() + ":3: ";
+
115 tests.Check(std::string(error.what()).find(prefix) == 0U &&
+
116 std::string(error.what()).size() > prefix.size(),
+
117 line);
+
118 }
+
119 }
+
120 fixture.Write(
+
121 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
+
122 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
+
123 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
+
124 "BO_ 257 Second: 8 ECU\n");
+
125 const auto database = DbcParser().ParseFile(fixture.path.string());
+
126 tests.Check(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
+
127 database.frames[0].comment == "Frame comment" &&
+
128 database.frames[0].signals[0].comment == "Signal comment",
+
129 "Integration");
+
130 fixture.Write("\nSG_ Speed : invalid\n");
+
131 try {
+
132 DbcParser().ParseFile(fixture.path.string());
+
133 tests.Check(false, "Signal error location");
+
134 } catch (const std::runtime_error &error) {
+
135 tests.Check(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
+
136 "Signal error location");
+
137 }
+
138 const DbcParser signalParser;
+
139 const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
+
140 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
+
141 "4294967296", "999999999999999999999"}) {
+
142 tests.RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255"));
+
143 tests.RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255"));
+
144 }
+
145 for (const std::string length: {"0", "65"})
+
146 tests.RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255"));
+
147 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
+
148 tests.RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255"));
+
149 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
+
150 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
+
151 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
+
152 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
+
153 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
+
154 }
+
155 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
+
156 for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) {
+
157 std::string line = ordinary;
+
158 line.replace(4U, 5U, name);
+
159 tests.RejectSignal(fixture, line);
+
160 }
+
161 for (const std::string broken: {
+
162 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
+
163 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
+
164 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
+
165 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
+
166 tests.RejectSignal(fixture, broken);
+
167 tests.RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1"));
+
168 tests.RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3"));
+
169 tests.RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3"));
+
170 tests.RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
+
171 tests.RejectSignal(fixture, ordinary, 0U);
+
172 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
+
173 std::string line = ordinary;
+
174 line.erase(line.find(delimiter), 1U);
+
175 tests.RejectSignal(fixture, line);
+
176 }
+
177 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
+
178 SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
+
179 SignalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n");
+
180 const auto factors = signalParser.ParseFile(fixture.path.string());
+
181 tests.Check(factors.frames[0].signals.size() == 2U &&
+
182 factors.frames[0].signals[0].factor == 0.0 &&
+
183 factors.frames[0].signals[1].factor == -1.0,
+
184 "Zero and negative factors and equal range boundaries");
+
185
+
186 struct SignalCase {
+
187 const char *start;
+
188 const char *length;
+
189 const char *order;
+
190 unsigned payload;
+
191 };
+
192 const SignalCase validSignals[] = {
+
193 {"0", "1", "1+", 1U},
+
194 {"7", "1", "0-", 1U},
+
195 {"0", "64", "1+", 8U},
+
196 {"7", "64", "0-", 8U},
+
197 {"63", "1", "1+", 8U},
+
198 {"56", "1", "0+", 8U},
+
199 {"3", "12", "0+", 2U},
+
200 {"2039", "1", "1+", 255U}};
+
201 for (const auto &test: validSignals) {
+
202 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
+
203 SignalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
+
204 try {
+
205 const auto parsed = signalParser.ParseFile(fixture.path.string());
+
206 const auto &signal = parsed.frames.at(0).signals.at(0);
+
207 tests.Check(signal.startBit == std::stoul(test.start) &&
+
208 signal.length == std::stoul(test.length) &&
+
209 signal.isLittleEndian == (test.order[0] == '1') &&
+
210 signal.isSigned == (test.order[1] == '-') &&
+
211 signal.factor == 5.0 && signal.offset == -0.25 &&
+
212 signal.minimum == -1.0 && signal.maximum == 200.0,
+
213 "Valid signal boundary and numeric metadata");
+
214 } catch (const std::exception &error) { tests.Check(false, error.what()); }
+
215 }
+
216 fixture.Write("BO_ 1 Frame: 8 ECU\n"
+
217 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
+
218 try {
+
219 const auto parsed = signalParser.ParseFile(fixture.path.string());
+
220 const auto &signal = parsed.frames.at(0).signals.at(0);
+
221 tests.Check(signal.name == "Value" && signal.unit == "rpm" &&
+
222 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
+
223 "Signal tabs, spaces, and receiver list");
+
224 } catch (const std::exception &error) { tests.Check(false, error.what()); }
+
225 DbcDatabase dispatchDatabase;
+
226 DbcParseContext context{dispatchDatabase, nullptr};
+
227 DbcStatementDispatcher dispatcher;
+
228 dispatcher.RegisterType<CountingHandler>("TEST_");
+
229 tests.Check(dispatcher.Dispatch("TEST_ first", context) &&
+
230 dispatcher.Dispatch("TEST_ second", context) &&
+
231 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
+
232 dispatchDatabase.frames.size() == 2U,
+
233 "Factory dispatch and handler reuse");
+
234 tests.Check(!dispatcher.Dispatch("TEST_OTHER data", context) &&
+
235 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
+
236 !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) &&
+
237 CountingHandler::calls == 2,
+
238 "Exact and unknown keyword dispatch");
+
239 const DbcParser parser;
+
240 fixture.Write("BO_ 1 First: 8 ECU\n");
+
241 tests.Check(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
+
242 fixture.Write("SG_ Speed : invalid\n");
+
243 try {
+
244 parser.ParseFile(fixture.path.string());
+
245 tests.Check(false, "Independent parse context");
+
246 } catch (const std::runtime_error &error) {
+
247 tests.Check(std::string(error.what()).find("Signal found before any frame") !=
+
248 std::string::npos,
+
249 "Independent parse context");
+
250 }
+
251 fixture.Write("BO_ 2 Second: 8 ECU\n");
+
252 const auto recovered = parser.ParseFile(fixture.path.string());
+
253 tests.Check(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
+
254 "Fresh parse after error");
+
255 if (tests.failures != 0) return 1;
+
256 std::cout << "All " << tests.count << " parser cases passed.\n";
+
257 return 0;
+
258}
DbcParser
Minimal DBC parser.
Definition dbc_parser.h:33
DbcParser::ParseFile
DbcDatabase ParseFile(const std::string &filePath) const
Parse DBC file.
Definition dbc_parser.cpp:40
DbcStatementDispatcher
Definition dbc_statement_handler.h:47
-
DbcStatementDispatcher::Dispatch
bool Dispatch(const std::string &line, DbcParseContext &context) const
Definition dbc_statement_handler.cpp:313
+
DbcStatementDispatcher::Dispatch
bool Dispatch(const std::string &line, DbcParseContext &context) const
Definition dbc_statement_handler.cpp:314
DbcStatementHandler
Definition dbc_statement_handler.h:16
dbc_parser.h
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
DbcDatabase
Parsed DBC content stored in a simple internal form.
Definition dbc_database.h:22
diff --git a/docs/html/dbc__statement__handler_8cpp_source.html b/docs/html/dbc__statement__handler_8cpp_source.html index 855638b..30ee562 100644 --- a/docs/html/dbc__statement__handler_8cpp_source.html +++ b/docs/html/dbc__statement__handler_8cpp_source.html @@ -120,305 +120,306 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8cpp_source.ht
20 return value;
21 }
22
-
28 std::string TrimText(const std::string &text) {
-
29 std::string::size_type begin = 0U;
-
30 while ((begin < text.size()) &&
-
31 std::isspace(static_cast<unsigned char>(text[begin])))
-
32 ++begin;
-
33
-
34 std::string::size_type end = text.size();
-
35 while ((end > begin) &&
-
36 std::isspace(static_cast<unsigned char>(text[end - 1U])))
-
37 --end;
-
38
-
39 return text.substr(begin, end - begin);
-
40 }
-
41 FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool);
-
42 SignalInfo *FindSignalByName(FrameInfo &, const std::string &);
-
43}// namespace
-
44
-
45namespace {
-
46 std::vector<std::string> SplitReceivers(const std::string &text) {
-
47 std::vector<std::string> receivers;
-
48 std::string token;
-
49 std::istringstream stream(text);
+
23 double ParsePhysicalValue(const std::string &text, const char *field) {
+
24 static const std::regex number(
+
25 R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)");
+
26 if (!std::regex_match(text, number))
+
27 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
+
28 std::size_t consumed = 0U;
+
29 double value;
+
30 try {
+
31 value = std::stod(text, &consumed);
+
32 } catch (const std::exception &) {
+
33 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
+
34 }
+
35 if (consumed != text.size() || !std::isfinite(value))
+
36 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
+
37 return value;
+
38 }
+
39
+
45 std::string TrimText(const std::string &text) {
+
46 std::string::size_type begin = 0U;
+
47 while ((begin < text.size()) &&
+
48 std::isspace(static_cast<unsigned char>(text[begin])))
+
49 ++begin;
50
-
51 while (std::getline(stream, token, ',')) {
-
52 token = TrimText(token);
-
53 if (!token.empty())
-
54 receivers.push_back(token);
-
55 }
-
56
-
57 return receivers;
-
58 }
-
59
-
60 void NormalizeCanId(std::uint32_t rawCanId,
-
61 std::uint32_t &normalizedCanId,
-
62 bool &isExtended) {
-
63 /*
-
64 * DBC commonly stores extended identifiers with bit 31 set.
-
65 * Example:
-
66 * raw id = 0x80000000 | actual_29_bit_id
-
67 */
-
68 if ((rawCanId & 0x80000000U) != 0U) {
-
69 isExtended = true;
-
70 normalizedCanId = (rawCanId & 0x1FFFFFFFU);
-
71 } else {
-
72 isExtended = (rawCanId > 0x7FFU);
-
73 normalizedCanId = rawCanId;
-
74 }
+
51 std::string::size_type end = text.size();
+
52 while ((end > begin) &&
+
53 std::isspace(static_cast<unsigned char>(text[end - 1U])))
+
54 --end;
+
55
+
56 return text.substr(begin, end - begin);
+
57 }
+
58 FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool);
+
59 SignalInfo *FindSignalByName(FrameInfo &, const std::string &);
+
60}// namespace
+
61
+
62namespace {
+
63 std::vector<std::string> SplitReceivers(const std::string &text) {
+
64 std::vector<std::string> receivers;
+
65 std::string token;
+
66 std::istringstream stream(text);
+
67
+
68 while (std::getline(stream, token, ',')) {
+
69 token = TrimText(token);
+
70 if (!token.empty())
+
71 receivers.push_back(token);
+
72 }
+
73
+
74 return receivers;
75 }
76
-
77 std::uint32_t TryExtractPgn(std::uint32_t canId, bool isExtended, bool &hasPgn) {
-
78 hasPgn = false;
-
79
-
80 if (!isExtended)
-
81 return 0U;
-
82
-
83 if ((canId & 0x1FFFFFFFU) != canId)
-
84 return 0U;
-
85
-
86 const std::uint32_t pf = (canId >> 16U) & 0xFFU;
-
87 const std::uint32_t ps = (canId >> 8U) & 0xFFU;
-
88 const std::uint32_t dp = (canId >> 24U) & 0x01U;
-
89
-
90 std::uint32_t pgn = 0U;
-
91
-
92 if (pf < 240U)
-
93 pgn = (dp << 16U) | (pf << 8U);
-
94 else
-
95 pgn = (dp << 16U) | (pf << 8U) | ps;
+
77 void NormalizeCanId(std::uint32_t rawCanId,
+
78 std::uint32_t &normalizedCanId,
+
79 bool &isExtended) {
+
80 /*
+
81 * DBC commonly stores extended identifiers with bit 31 set.
+
82 * Example:
+
83 * raw id = 0x80000000 | actual_29_bit_id
+
84 */
+
85 if ((rawCanId & 0x80000000U) != 0U) {
+
86 isExtended = true;
+
87 normalizedCanId = (rawCanId & 0x1FFFFFFFU);
+
88 } else {
+
89 isExtended = (rawCanId > 0x7FFU);
+
90 normalizedCanId = rawCanId;
+
91 }
+
92 }
+
93
+
94 std::uint32_t TryExtractPgn(std::uint32_t canId, bool isExtended, bool &hasPgn) {
+
95 hasPgn = false;
96
-
97 hasPgn = true;
-
98 return pgn;
-
99 }
-
100
-
101}// namespace
+
97 if (!isExtended)
+
98 return 0U;
+
99
+
100 if ((canId & 0x1FFFFFFFU) != canId)
+
101 return 0U;
102
-
103FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
-
104 /*
-
105 * Example:
-
106 * BO_ 256 EngineData: 8 EEC1
-
107 */
+
103 const std::uint32_t pf = (canId >> 16U) & 0xFFU;
+
104 const std::uint32_t ps = (canId >> 8U) & 0xFFU;
+
105 const std::uint32_t dp = (canId >> 24U) & 0x01U;
+
106
+
107 std::uint32_t pgn = 0U;
108
-
109 std::istringstream stream(line);
-
110 std::string keyword;
-
111 std::string idText;
-
112 if (!(stream >> keyword >> idText) || keyword != "BO_")
-
113 throw std::runtime_error("Missing CAN ID in frame definition.");
-
114
-
115 const std::uint32_t rawCanId = ParseDecimal(
-
116 idText, std::numeric_limits<std::uint32_t>::max(), "CAN ID");
-
117 // Only bit 31 may accompany the actual 29-bit identifier.
-
118 if ((rawCanId & 0x60000000U) != 0U)
-
119 throw std::runtime_error("CAN ID exceeds the 29-bit identifier range.");
-
120
-
121 std::string nameText;
-
122 if (!std::getline(stream, nameText, ':') || stream.eof())
-
123 throw std::runtime_error("Missing ':' in frame definition.");
-
124 std::istringstream nameStream(nameText);
-
125 FrameInfo frame;
-
126 std::string extra;
-
127 if (!(nameStream >> frame.name) || (nameStream >> extra))
-
128 throw std::runtime_error("Missing or invalid frame name.");
-
129
-
130 std::string lengthText;
-
131 if (!(stream >> lengthText))
-
132 throw std::runtime_error("Missing payload length in frame definition.");
-
133 frame.dlc = static_cast<std::uint8_t>(ParseDecimal(
-
134 lengthText, std::numeric_limits<std::uint8_t>::max(), "payload length"));
-
135 if (!(stream >> frame.transmitter))
-
136 throw std::runtime_error("Missing transmitter in frame definition.");
-
137 if (stream >> extra)
-
138 throw std::runtime_error("Unexpected trailing field in frame definition: " + extra);
-
139
-
140 NormalizeCanId(rawCanId, frame.canId, frame.isExtended);
-
141 frame.pgn = TryExtractPgn(frame.canId, frame.isExtended, frame.hasPgn);
-
142
-
143 return frame;
-
144}
-
145
-
146SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
-
147 // Match the complete statement before converting any numeric fields.
-
148 static const std::regex syntax(
-
149 R"dbc(^SG_[ \t]+([^:]+):[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*\‍([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*"([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
-
150 std::smatch fields;
-
151 if (!std::regex_match(line, fields, syntax))
-
152 throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
-
153
-
154 SignalInfo signal;
-
155 signal.name = TrimText(fields[1].str());
-
156 if (signal.name.empty() || signal.name.find_first_of(" \t\r\n") != std::string::npos)
-
157 throw std::runtime_error("Invalid signal name or unsupported multiplexing syntax.");
-
158
-
159 signal.startBit = ParseDecimal(fields[2].str(),
-
160 std::numeric_limits<std::uint32_t>::max(), "signal start bit");
-
161 signal.length = ParseDecimal(fields[3].str(), 64U, "signal length");
-
162 if (signal.length == 0U)
-
163 throw std::runtime_error("Signal length must be within 1..64 bits.");
-
164 signal.isLittleEndian = fields[4].str() == "1";
-
165 signal.isSigned = fields[5].str() == "-";
-
166
-
167 const auto parsePhysical = [](const std::string &text, const char *field) {
-
168 static const std::regex number(
-
169 R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)");
-
170 if (!std::regex_match(text, number))
-
171 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
-
172 std::size_t consumed = 0U;
-
173 double value;
-
174 try {
-
175 value = std::stod(text, &consumed);
-
176 } catch (const std::exception &) {
-
177 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
-
178 }
-
179 if (consumed != text.size() || !std::isfinite(value))
-
180 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
-
181 return value;
-
182 };
-
183 signal.factor = parsePhysical(fields[6].str(), "signal factor");
-
184 signal.offset = parsePhysical(fields[7].str(), "signal offset");
-
185 signal.minimum = parsePhysical(fields[8].str(), "signal minimum");
-
186 signal.maximum = parsePhysical(fields[9].str(), "signal maximum");
-
187 if (signal.minimum > signal.maximum)
-
188 throw std::runtime_error("Signal minimum exceeds maximum.");
-
189 signal.unit = fields[10].str();
-
190 signal.receivers = SplitReceivers(fields[11].str());
-
191 return signal;
-
192}
-
193
-
194void DbcCommentHandler::ParseCommentLine(const std::string &line, DbcDatabase &database) {
-
195 /*
-
196 * Examples:
-
197 * CM_ BO_ 256 "Frame comment";
-
198 * CM_ SG_ 256 EngineSpeed "Signal comment";
-
199 */
-
200
-
201 std::istringstream stream(line);
-
202 std::string token;
-
203 stream >> token;
-
204
-
205 if (token != "CM_")
-
206 return;
-
207
-
208 stream >> token;
-
209
-
210 if (token == "BO_") {
-
211 std::uint32_t rawCanId = 0U;
-
212 std::uint32_t canId = 0U;
-
213 bool isExtended = false;
-
214
-
215 stream >> rawCanId;
-
216 NormalizeCanId(rawCanId, canId, isExtended);
-
217
-
218 const std::string::size_type quoteBegin = line.find('"');
-
219 const std::string::size_type quoteEnd = line.rfind('"');
-
220
-
221 if ((quoteBegin == std::string::npos) ||
-
222 (quoteEnd == std::string::npos) ||
-
223 (quoteEnd <= quoteBegin))
-
224 return;
-
225
-
226 FrameInfo *frame = FindFrameById(database, canId, isExtended);
-
227 if (frame != nullptr)
-
228 frame->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
-
229 } else if (token == "SG_") {
-
230 std::uint32_t rawCanId = 0U;
-
231 std::uint32_t canId = 0U;
-
232 bool isExtended = false;
-
233 std::string signalName;
-
234
-
235 stream >> rawCanId;
-
236 stream >> signalName;
-
237
-
238 NormalizeCanId(rawCanId, canId, isExtended);
-
239
-
240 const std::string::size_type quoteBegin = line.find('"');
-
241 const std::string::size_type quoteEnd = line.rfind('"');
-
242
-
243 if ((quoteBegin == std::string::npos) ||
-
244 (quoteEnd == std::string::npos) ||
-
245 (quoteEnd <= quoteBegin))
-
246 return;
-
247
-
248 FrameInfo *frame = FindFrameById(database, canId, isExtended);
-
249 if (frame != nullptr) {
-
250 SignalInfo *signal = FindSignalByName(*frame, signalName);
-
251 if (signal != nullptr)
-
252 signal->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
-
253 }
-
254 }
-
255}
-
256
-
257namespace {
-
258 FrameInfo *FindFrameById(DbcDatabase &database,
-
259 std::uint32_t canId,
-
260 bool isExtended) {
-
261 for (std::size_t index = 0U; index < database.frames.size(); ++index) {
-
262 if ((database.frames[index].canId == canId) &&
-
263 (database.frames[index].isExtended == isExtended))
-
264 return &database.frames[index];
-
265 }
-
266
-
267 return nullptr;
-
268 }
-
269
-
270 SignalInfo *FindSignalByName(FrameInfo &frame, const std::string &signalName) {
-
271 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
-
272 if (frame.signals[index].name == signalName)
-
273 return &frame.signals[index];
-
274 }
-
275
-
276 return nullptr;
-
277 }
-
278}// namespace
-
279
-
280void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const {
-
281 context.database.frames.push_back(ParseFrameLine(line));
-
282 context.currentFrame = &context.database.frames.back();
-
283}
-
284
-
285void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const {
-
286 if (context.currentFrame == nullptr)
-
287 throw std::runtime_error("Signal found before any frame definition.");
-
288 SignalInfo signal = ParseSignalLine(line);
-
289 const std::uint64_t payloadBits = static_cast<std::uint64_t>(context.currentFrame->dlc) * 8U;
-
290 std::uint64_t bit = signal.startBit;
-
291 for (std::uint32_t index = 0U; index < signal.length; ++index) {
-
292 if (bit >= payloadBits)
-
293 throw std::runtime_error("Signal exceeds the frame payload length.");
-
294 if (signal.isLittleEndian)
-
295 ++bit;
-
296 else
-
297 bit = (bit % 8U == 0U) ? bit + 15U : bit - 1U;
-
298 }
-
299 context.currentFrame->signals.push_back(std::move(signal));
-
300}
-
301
-
302void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const {
-
303 if (line.compare(0U, 4U, "CM_ ") == 0)
-
304 ParseCommentLine(line, context.database);
-
305}
-
306
-
307DbcStatementDispatcher::DbcStatementDispatcher() {
-
308 RegisterType<DbcFrameHandler>("BO_");
-
309 RegisterType<DbcSignalHandler>("SG_");
-
310 RegisterType<DbcCommentHandler>("CM_");
-
311}
-
312
-
-
313bool DbcStatementDispatcher::Dispatch(const std::string &line,
-
314 DbcParseContext &context) const {
-
315 std::istringstream stream(line);
-
316 std::string keyword;
-
317 stream >> keyword;
-
318 const auto handler = m_handlers.find(keyword);
-
319 if (handler == m_handlers.end())
-
320 return false;
-
321 handler->second->Handle(line, context);
-
322 return true;
-
323}
+
109 if (pf < 240U)
+
110 pgn = (dp << 16U) | (pf << 8U);
+
111 else
+
112 pgn = (dp << 16U) | (pf << 8U) | ps;
+
113
+
114 hasPgn = true;
+
115 return pgn;
+
116 }
+
117
+
118}// namespace
+
119
+
120FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
+
121 /*
+
122 * Example:
+
123 * BO_ 256 EngineData: 8 EEC1
+
124 */
+
125
+
126 std::istringstream stream(line);
+
127 std::string keyword;
+
128 std::string idText;
+
129 if (!(stream >> keyword >> idText) || keyword != "BO_")
+
130 throw std::runtime_error("Missing CAN ID in frame definition.");
+
131
+
132 const std::uint32_t rawCanId = ParseDecimal(
+
133 idText, std::numeric_limits<std::uint32_t>::max(), "CAN ID");
+
134 // Only bit 31 may accompany the actual 29-bit identifier.
+
135 if ((rawCanId & 0x60000000U) != 0U)
+
136 throw std::runtime_error("CAN ID exceeds the 29-bit identifier range.");
+
137
+
138 std::string nameText;
+
139 if (!std::getline(stream, nameText, ':') || stream.eof())
+
140 throw std::runtime_error("Missing ':' in frame definition.");
+
141 std::istringstream nameStream(nameText);
+
142 FrameInfo frame;
+
143 std::string extra;
+
144 if (!(nameStream >> frame.name) || (nameStream >> extra))
+
145 throw std::runtime_error("Missing or invalid frame name.");
+
146
+
147 std::string lengthText;
+
148 if (!(stream >> lengthText))
+
149 throw std::runtime_error("Missing payload length in frame definition.");
+
150 frame.dlc = static_cast<std::uint8_t>(ParseDecimal(
+
151 lengthText, std::numeric_limits<std::uint8_t>::max(), "payload length"));
+
152 if (!(stream >> frame.transmitter))
+
153 throw std::runtime_error("Missing transmitter in frame definition.");
+
154 if (stream >> extra)
+
155 throw std::runtime_error("Unexpected trailing field in frame definition: " + extra);
+
156
+
157 NormalizeCanId(rawCanId, frame.canId, frame.isExtended);
+
158 frame.pgn = TryExtractPgn(frame.canId, frame.isExtended, frame.hasPgn);
+
159
+
160 return frame;
+
161}
+
162
+
163SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
+
164 // Match the complete statement before converting any numeric fields.
+
165 static const std::regex syntax(
+
166 R"dbc(^SG_[ \t]+([^:]+):[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*\‍([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*"([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
+
167 std::smatch fields;
+
168 if (!std::regex_match(line, fields, syntax))
+
169 throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
+
170
+
171 SignalInfo signal;
+
172 signal.name = TrimText(fields[1].str());
+
173 if (signal.name.empty() || signal.name.find_first_of(" \t\r\n") != std::string::npos)
+
174 throw std::runtime_error("Invalid signal name or unsupported multiplexing syntax.");
+
175
+
176 signal.startBit = ParseDecimal(fields[2].str(),
+
177 std::numeric_limits<std::uint32_t>::max(), "signal start bit");
+
178 signal.length = ParseDecimal(fields[3].str(), 64U, "signal length");
+
179 if (signal.length == 0U)
+
180 throw std::runtime_error("Signal length must be within 1..64 bits.");
+
181 signal.isLittleEndian = fields[4].str() == "1";
+
182 signal.isSigned = fields[5].str() == "-";
+
183
+
184 signal.factor = ParsePhysicalValue(fields[6].str(), "signal factor");
+
185 signal.offset = ParsePhysicalValue(fields[7].str(), "signal offset");
+
186 signal.minimum = ParsePhysicalValue(fields[8].str(), "signal minimum");
+
187 signal.maximum = ParsePhysicalValue(fields[9].str(), "signal maximum");
+
188 if (signal.minimum > signal.maximum)
+
189 throw std::runtime_error("Signal minimum exceeds maximum.");
+
190 signal.unit = fields[10].str();
+
191 signal.receivers = SplitReceivers(fields[11].str());
+
192 return signal;
+
193}
+
194
+
195void DbcCommentHandler::ParseCommentLine(const std::string &line, DbcDatabase &database) {
+
196 /*
+
197 * Examples:
+
198 * CM_ BO_ 256 "Frame comment";
+
199 * CM_ SG_ 256 EngineSpeed "Signal comment";
+
200 */
+
201
+
202 std::istringstream stream(line);
+
203 std::string token;
+
204 stream >> token;
+
205
+
206 if (token != "CM_")
+
207 return;
+
208
+
209 stream >> token;
+
210
+
211 if (token == "BO_") {
+
212 std::uint32_t rawCanId = 0U;
+
213 std::uint32_t canId = 0U;
+
214 bool isExtended = false;
+
215
+
216 stream >> rawCanId;
+
217 NormalizeCanId(rawCanId, canId, isExtended);
+
218
+
219 const std::string::size_type quoteBegin = line.find('"');
+
220 const std::string::size_type quoteEnd = line.rfind('"');
+
221
+
222 if ((quoteBegin == std::string::npos) ||
+
223 (quoteEnd == std::string::npos) ||
+
224 (quoteEnd <= quoteBegin))
+
225 return;
+
226
+
227 FrameInfo *frame = FindFrameById(database, canId, isExtended);
+
228 if (frame != nullptr)
+
229 frame->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
+
230 } else if (token == "SG_") {
+
231 std::uint32_t rawCanId = 0U;
+
232 std::uint32_t canId = 0U;
+
233 bool isExtended = false;
+
234 std::string signalName;
+
235
+
236 stream >> rawCanId;
+
237 stream >> signalName;
+
238
+
239 NormalizeCanId(rawCanId, canId, isExtended);
+
240
+
241 const std::string::size_type quoteBegin = line.find('"');
+
242 const std::string::size_type quoteEnd = line.rfind('"');
+
243
+
244 if ((quoteBegin == std::string::npos) ||
+
245 (quoteEnd == std::string::npos) ||
+
246 (quoteEnd <= quoteBegin))
+
247 return;
+
248
+
249 FrameInfo *frame = FindFrameById(database, canId, isExtended);
+
250 if (frame != nullptr) {
+
251 SignalInfo *signal = FindSignalByName(*frame, signalName);
+
252 if (signal != nullptr)
+
253 signal->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
+
254 }
+
255 }
+
256}
+
257
+
258namespace {
+
259 FrameInfo *FindFrameById(DbcDatabase &database,
+
260 std::uint32_t canId,
+
261 bool isExtended) {
+
262 for (std::size_t index = 0U; index < database.frames.size(); ++index) {
+
263 if ((database.frames[index].canId == canId) &&
+
264 (database.frames[index].isExtended == isExtended))
+
265 return &database.frames[index];
+
266 }
+
267
+
268 return nullptr;
+
269 }
+
270
+
271 SignalInfo *FindSignalByName(FrameInfo &frame, const std::string &signalName) {
+
272 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
+
273 if (frame.signals[index].name == signalName)
+
274 return &frame.signals[index];
+
275 }
+
276
+
277 return nullptr;
+
278 }
+
279}// namespace
+
280
+
281void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const {
+
282 context.database.frames.push_back(ParseFrameLine(line));
+
283 context.currentFrame = &context.database.frames.back();
+
284}
+
285
+
286void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const {
+
287 if (context.currentFrame == nullptr)
+
288 throw std::runtime_error("Signal found before any frame definition.");
+
289 SignalInfo signal = ParseSignalLine(line);
+
290 const std::uint64_t payloadBits = static_cast<std::uint64_t>(context.currentFrame->dlc) * 8U;
+
291 std::uint64_t bit = signal.startBit;
+
292 for (std::uint32_t index = 0U; index < signal.length; ++index) {
+
293 if (bit >= payloadBits)
+
294 throw std::runtime_error("Signal exceeds the frame payload length.");
+
295 if (signal.isLittleEndian)
+
296 ++bit;
+
297 else
+
298 bit = (bit % 8U == 0U) ? bit + 15U : bit - 1U;
+
299 }
+
300 context.currentFrame->signals.push_back(std::move(signal));
+
301}
+
302
+
303void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const {
+
304 if (line.compare(0U, 4U, "CM_ ") == 0)
+
305 ParseCommentLine(line, context.database);
+
306}
+
307
+
308DbcStatementDispatcher::DbcStatementDispatcher() {
+
309 RegisterType<DbcFrameHandler>("BO_");
+
310 RegisterType<DbcSignalHandler>("SG_");
+
311 RegisterType<DbcCommentHandler>("CM_");
+
312}
+
313
+
+
314bool DbcStatementDispatcher::Dispatch(const std::string &line,
+
315 DbcParseContext &context) const {
+
316 std::istringstream stream(line);
+
317 std::string keyword;
+
318 stream >> keyword;
+
319 const auto handler = m_handlers.find(keyword);
+
320 if (handler == m_handlers.end())
+
321 return false;
+
322 handler->second->Handle(line, context);
+
323 return true;
+
324}
-
bool Dispatch(const std::string &line, DbcParseContext &context) const
+
bool Dispatch(const std::string &line, DbcParseContext &context) const
Parsed DBC content stored in a simple internal form.
std::vector< FrameInfo > frames
diff --git a/docs/html/dbc__statement__handler_8h_source.html b/docs/html/dbc__statement__handler_8h_source.html index 5466c66..a441043 100644 --- a/docs/html/dbc__statement__handler_8h_source.html +++ b/docs/html/dbc__statement__handler_8h_source.html @@ -176,7 +176,7 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8h_source.html
-
bool Dispatch(const std::string &line, DbcParseContext &context) const
+
bool Dispatch(const std::string &line, DbcParseContext &context) const
Registry-based factory for creating objects by runtime identifier.
Definition typefactory.h:59
BasePtr create(const ClassId &id, Args... args) const
Creates an instance for the given id using provided arguments.
Definition typefactory.h:97
diff --git a/docs/html/main_8cpp.html b/docs/html/main_8cpp.html index 1907ad1..dfe9b86 100644 --- a/docs/html/main_8cpp.html +++ b/docs/html/main_8cpp.html @@ -147,7 +147,7 @@ Functions
-

Definition at line 98 of file main.cpp.

+

Definition at line 101 of file main.cpp.

diff --git a/docs/html/main_8cpp_source.html b/docs/html/main_8cpp_source.html index 5ca134b..1c3bec7 100644 --- a/docs/html/main_8cpp_source.html +++ b/docs/html/main_8cpp_source.html @@ -178,53 +178,56 @@ $(document).ready(function(){initNavTree('main_8cpp_source.html',''); initResiza
88
89 std::cout << " " << signal.definition->name
90 << " raw=";
-
91 std::visit([](auto rawValue) { std::cout << rawValue; }, signal.rawValue);
-
92 std::cout << " physical=" << signal.physicalValue
-
93 << " " << signal.definition->unit
-
94 << "\n";
-
95 }
-
96}
-
97
-
98int main(int argc, char *argv[]) {
-
99 if (argc < 2) {
-
100 std::cerr << "Usage: dbc_demo <file.dbc>\n";
-
101 return 1;
-
102 }
-
103
-
104 try {
-
105 DbcParser parser;
-
106 DbcDatabase database = parser.ParseFile(argv[1]);
-
107
-
108 DbcTreeBuilder treeBuilder;
-
109 std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
+
91 if (const auto *signedValue = std::get_if<std::int64_t>(&signal.rawValue))
+
92 std::cout << *signedValue;
+
93 else
+
94 std::cout << std::get<std::uint64_t>(signal.rawValue);
+
95 std::cout << " physical=" << signal.physicalValue
+
96 << " " << signal.definition->unit
+
97 << "\n";
+
98 }
+
99}
+
100
+
101int main(int argc, char *argv[]) {
+
102 if (argc < 2) {
+
103 std::cerr << "Usage: dbc_demo <file.dbc>\n";
+
104 return 1;
+
105 }
+
106
+
107 try {
+
108 DbcParser parser;
+
109 DbcDatabase database = parser.ParseFile(argv[1]);
110
-
111 std::cout << "=== Parsed tree ===\n";
-
112 PrintTree(root.get(), 0);
+
111 DbcTreeBuilder treeBuilder;
+
112 std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
113
-
114 DbcDecodeBuilder decodeBuilder;
-
115 DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
+
114 std::cout << "=== Parsed tree ===\n";
+
115 PrintTree(root.get(), 0);
116
-
117 /*
-
118 * Example raw frame.
-
119 * Replace with live CAN frame or trace record later.
-
120 */
-
121 RawCanFrame rawFrame;
-
122 rawFrame.canId = decodeDatabase.frames.empty() ? 0U : decodeDatabase.frames[0].canId;
-
123 rawFrame.isExtended = decodeDatabase.frames.empty() ? false : decodeDatabase.frames[0].isExtended;
-
124 rawFrame.data.resize(8U, 0U);
-
125
-
126 DbcDecoder decoder;
-
127 DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
+
117 DbcDecodeBuilder decodeBuilder;
+
118 DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
+
119
+
120 /*
+
121 * Example raw frame.
+
122 * Replace with live CAN frame or trace record later.
+
123 */
+
124 RawCanFrame rawFrame;
+
125 rawFrame.canId = decodeDatabase.frames.empty() ? 0U : decodeDatabase.frames[0].canId;
+
126 rawFrame.isExtended = decodeDatabase.frames.empty() ? false : decodeDatabase.frames[0].isExtended;
+
127 rawFrame.data.resize(8U, 0U);
128
-
129 std::cout << "\n=== Decoded frame ===\n";
-
130 PrintDecodedFrame(decoded);
-
131 } catch (const std::exception &ex) {
-
132 std::cerr << "Error: " << ex.what() << "\n";
-
133 return 2;
-
134 }
-
135
-
136 return 0;
-
137}
+
129 DbcDecoder decoder;
+
130 DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
+
131
+
132 std::cout << "\n=== Decoded frame ===\n";
+
133 PrintDecodedFrame(decoded);
+
134 } catch (const std::exception &ex) {
+
135 std::cerr << "Error: " << ex.what() << "\n";
+
136 return 2;
+
137 }
+
138
+
139 return 0;
+
140}
DbcDecodeBuilder
Converts parsed DBC data into runtime decode database.
Definition dbc_decode_builder.h:21
DbcDecodeBuilder::Build
DecodeDatabase Build(const DbcDatabase &source) const
Build runtime decode database.
Definition dbc_decode_builder.cpp:14
DbcDecoder
Runtime CAN decoder using prebuilt decode database.
Definition dbc_decoder.h:64
diff --git a/docs/html/md_README.html b/docs/html/md_README.html index 162256a..ed88b20 100644 --- a/docs/html/md_README.html +++ b/docs/html/md_README.html @@ -441,8 +441,12 @@ Decoder Layer

Raw value representation and precision

DecodedSignalValue::rawValue is a C++17 std::variant<std::int64_t, std::uint64_t>. For a valid signal, signed definitions produce the int64_t alternative and unsigned definitions produce the uint64_t alternative. Raw values remain exact across their full 64-bit ranges. Check valid before using the value; an invalid result's default value is not decoded data.

-

Use std::get when the numeric type is known, or std::visit to handle both:

-
std::visit([] (auto raw) { std::cout << raw; }, decodedSignal.rawValue);
+

Use std::get when the numeric type is known, or std::get_if to handle both:

+
if (const auto *value = std::get_if<std::int64_t>(&decodedSignal.rawValue)) {
+
std::cout << *value;
+
} else {
+
std::cout << std::get<std::uint64_t>(decodedSignal.rawValue);
+
}

This replaces the previous int64_t field: consumers that read or print rawValue directly must handle the variant.

Physical conversion uses the active numeric type: physicalValue = static_cast<double>(raw) * factor + offset. physicalValue remains a double and is approximate for large integers. On usual IEEE 754 binary64 implementations, integers are exactly representable through 2^53; above that, some integers round to the same floating-point value. For example, unsigned UINT64_MAX remains exact in rawValue, but converts to approximately 18446744073709551616 in binary64 before scaling. Use rawValue whenever exact integer values are required.