25 std::string TrimText (
const std::string &text) {
26 std::string::size_type begin = 0U;
27 while ((begin < text.size()) &&
28 std::isspace (
static_cast<unsigned char> (text[begin])))
31 std::string::size_type end = text.size();
32 while ((end > begin) &&
33 std::isspace (
static_cast<unsigned char> (text[end - 1U])))
36 return text.substr (begin, end - begin);
41 std::ifstream input (filePath.c_str());
43 throw std::runtime_error (
"Failed to open DBC file: " + filePath);
49 while (std::getline (input, line)) {
54 if (IsFrameLine (line)) {
56 database.
frames.push_back (frame);
57 currentFrame = &database.
frames.back();
58 }
else if (IsSignalLine (line)) {
59 if (currentFrame ==
nullptr)
60 throw std::runtime_error (
"Signal found before any frame definition.");
63 currentFrame->signals.push_back (signal);
64 }
else if (IsCommentLine (line))
65 ParseCommentLine (line, database);
71bool DbcParser::IsFrameLine (
const std::string &line) {
72 return (line.size() >= 4U) && (line.compare (0U, 4U,
"BO_ ") == 0);
75bool DbcParser::IsSignalLine (
const std::string &line) {
76 return (line.size() >= 4U) && (line.compare (0U, 4U,
"SG_ ") == 0);
79bool DbcParser::IsCommentLine (
const std::string &line) {
80 return (line.size() >= 4U) && (line.compare (0U, 4U,
"CM_ ") == 0);
83std::string DbcParser::Trim (
const std::string &text) {
84 return TrimText (text);
87std::vector<std::string> DbcParser::SplitReceivers (
const std::string &text) {
88 std::vector<std::string> receivers;
90 std::istringstream stream (text);
92 while (std::getline (stream, token,
',')) {
93 token = TrimText (token);
95 receivers.push_back (token);
101void DbcParser::NormalizeCanId (std::uint32_t rawCanId,
102 std::uint32_t &normalizedCanId,
109 if ((rawCanId & 0x80000000U) != 0U) {
111 normalizedCanId = (rawCanId & 0x1FFFFFFFU);
113 isExtended = (rawCanId > 0x7FFU);
114 normalizedCanId = rawCanId;
118std::uint32_t DbcParser::TryExtractPgn (std::uint32_t canId,
bool isExtended,
bool &hasPgn) {
124 if ((canId & 0x1FFFFFFFU) != canId)
127 const std::uint32_t pf = (canId >> 16U) & 0xFFU;
128 const std::uint32_t ps = (canId >> 8U) & 0xFFU;
129 const std::uint32_t dp = (canId >> 24U) & 0x01U;
131 std::uint32_t pgn = 0U;
134 pgn = (dp << 16U) | (pf << 8U);
136 pgn = (dp << 16U) | (pf << 8U) | ps;
142FrameInfo DbcParser::ParseFrameLine (
const std::string &line) {
148 std::istringstream stream (line);
151 std::uint32_t rawCanId = 0U;
155 throw std::runtime_error (
"Invalid frame line: " + line);
162 throw std::runtime_error (
"Missing frame name: " + line);
164 if (token[token.size() - 1U] ==
':')
165 token.erase (token.size() - 1U, 1U);
170 unsigned int dlcValue = 0U;
172 frame.
dlc =
static_cast<std::uint8_t
> (dlcValue);
181SignalInfo DbcParser::ParseSignalLine (
const std::string &line) {
189 std::string work = TrimText (line);
190 if (work.compare (0U, 4U,
"SG_ ") != 0)
191 throw std::runtime_error (
"Invalid signal line: " + line);
195 const std::string::size_type colonPos = work.find (
':');
196 if (colonPos == std::string::npos)
197 throw std::runtime_error (
"Signal line missing ':' : " + line);
199 signal.
name = TrimText (work.substr (0U, colonPos));
200 std::string rest = TrimText (work.substr (colonPos + 1U));
202 const std::string::size_type pipePos = rest.find (
'|');
203 const std::string::size_type atPos = rest.find (
'@');
204 const std::string::size_type signPos = rest.find_first_of (
"+-", atPos);
205 const std::string::size_type factorBegin = rest.find (
'(');
206 const std::string::size_type factorComma = rest.find (
',', factorBegin);
207 const std::string::size_type factorEnd = rest.find (
')', factorComma);
208 const std::string::size_type rangeBegin = rest.find (
'[');
209 const std::string::size_type rangeSep = rest.find (
'|', rangeBegin);
210 const std::string::size_type rangeEnd = rest.find (
']', rangeSep);
211 const std::string::size_type unitBegin = rest.find (
'"', rangeEnd);
212 const std::string::size_type unitEnd = rest.find (
'"', unitBegin + 1U);
214 if ((pipePos == std::string::npos) ||
215 (atPos == std::string::npos) ||
216 (signPos == std::string::npos) ||
217 (factorBegin == std::string::npos) ||
218 (factorComma == std::string::npos) ||
219 (factorEnd == std::string::npos) ||
220 (rangeBegin == std::string::npos) ||
221 (rangeSep == std::string::npos) ||
222 (rangeEnd == std::string::npos) ||
223 (unitBegin == std::string::npos) ||
224 (unitEnd == std::string::npos))
225 throw std::runtime_error (
"Unsupported signal syntax: " + line);
227 signal.
startBit =
static_cast<std::uint32_t
> (
228 std::stoul (TrimText (rest.substr (0U, pipePos)))
231 signal.
length =
static_cast<std::uint32_t
> (
232 std::stoul (TrimText (rest.substr (pipePos + 1U, atPos - pipePos - 1U)))
236 if ((atPos + 1U) >= rest.size())
237 throw std::runtime_error (
"Invalid endianness in signal: " + line);
239 const char endianChar = rest[atPos + 1U];
244 const char signChar = rest[signPos];
245 signal.
isSigned = (signChar ==
'-');
248 signal.
factor = std::stod (
249 TrimText (rest.substr (factorBegin + 1U, factorComma - factorBegin - 1U))
252 signal.
offset = std::stod (
253 TrimText (rest.substr (factorComma + 1U, factorEnd - factorComma - 1U))
257 TrimText (rest.substr (rangeBegin + 1U, rangeSep - rangeBegin - 1U))
261 TrimText (rest.substr (rangeSep + 1U, rangeEnd - rangeSep - 1U))
264 signal.
unit = rest.substr (unitBegin + 1U, unitEnd - unitBegin - 1U);
267 const std::string receiversText = TrimText (rest.substr (unitEnd + 1U));
268 signal.
receivers = SplitReceivers (receiversText);
274void DbcParser::ParseCommentLine (
const std::string &line,
DbcDatabase &database) {
281 std::istringstream stream (line);
290 if (token ==
"BO_") {
291 std::uint32_t rawCanId = 0U;
292 std::uint32_t canId = 0U;
293 bool isExtended =
false;
296 NormalizeCanId (rawCanId, canId, isExtended);
298 const std::string::size_type quoteBegin = line.find (
'"');
299 const std::string::size_type quoteEnd = line.rfind (
'"');
301 if ((quoteBegin == std::string::npos) ||
302 (quoteEnd == std::string::npos) ||
303 (quoteEnd <= quoteBegin))
306 FrameInfo *frame = FindFrameById (database, canId, isExtended);
307 if (frame !=
nullptr)
308 frame->
comment = line.substr (quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
309 }
else if (token ==
"SG_") {
310 std::uint32_t rawCanId = 0U;
311 std::uint32_t canId = 0U;
312 bool isExtended =
false;
313 std::string signalName;
316 stream >> signalName;
318 NormalizeCanId (rawCanId, canId, isExtended);
320 const std::string::size_type quoteBegin = line.find (
'"');
321 const std::string::size_type quoteEnd = line.rfind (
'"');
323 if ((quoteBegin == std::string::npos) ||
324 (quoteEnd == std::string::npos) ||
325 (quoteEnd <= quoteBegin))
328 FrameInfo *frame = FindFrameById (database, canId, isExtended);
329 if (frame !=
nullptr) {
330 SignalInfo *signal = FindSignalByName (*frame, signalName);
331 if (signal !=
nullptr)
332 signal->
comment = line.substr (quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
340 for (std::size_t index = 0U; index < database.
frames.size(); ++index) {
341 if ((database.
frames[index].canId == canId) &&
342 (database.
frames[index].isExtended == isExtended))
343 return &database.
frames[index];
350 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
351 if (frame.signals[index].
name == signalName)
352 return &frame.signals[index];
DbcDatabase ParseFile(const std::string &filePath) const
Parse DBC file.
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
Parsed DBC content stored in a simple internal form.
std::vector< FrameInfo > frames
Describes one CAN frame from a DBC file.
Describes one signal inside a DBC frame.
std::vector< std::string > receivers