Files
dbc/docs/html/md_README.html
2026-10-13 08:17:49 -04:00

1361 lines
105 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>DBC Framework: DBC Parser and Runtime Decode Module Documentation</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<td id="projectalign">
<div id="projectname">DBC Framework
</div>
<div id="projectbrief">DBC parsing and CAN signal decoding framework</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.8 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('md_README.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">DBC Parser and Runtime Decode Module Documentation</div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><a class="anchor" id="autotoc_md26"></a> </p>
<h1><a class="anchor" id="autotoc_md27"></a>
Overview</h1>
<p>This module provides a minimal but extensible DBC parser and runtime decode foundation for the <b>FrameTap</b> project.</p>
<p>Its purpose is to:</p>
<ul>
<li>parse DBC files</li>
<li>store parsed frame and signal metadata</li>
<li>build a tree for future UI integration</li>
<li>build a runtime-ready decode database</li>
<li>decode live CAN frames</li>
<li>decode CAN trace records using the same decoder</li>
</ul>
<p>The implementation follows a simple and practical design:</p>
<ul>
<li>parser logic is separated from UI logic</li>
<li>runtime decode structures are separated from tree structures</li>
<li>Qt is not required at the parser or decoder level</li>
<li>the same decode engine can be reused for live traffic and trace replay</li>
</ul>
<p>The core library uses C++17 and has no Qt dependency. Qt integration targets the installed Qt 6.8.2, which is the only supported Qt version. Qt Core and Qt Test are used by the regression tests; model tests also link QtGui for graphical metatypes. The optional adapter requires only Qt Core. Live CAN acquisition, trace-file readers, are left to the consuming application. An optional Qt Core model adapter is provided in <code>qt/</code>.</p>
<p>See <a class="el" href="md_changelog.html">changelog.md</a> for the release and development history, <a class="el" href="md_tests_2README.html">tests/README.md</a> for test instructions, and <a href="docs/html/index.html">generated API documentation</a> for the API reference.</p>
<hr />
<h1><a class="anchor" id="autotoc_md29"></a>
High-Level Architecture</h1>
<p>The module is divided into two main paths.</p>
<h2><a class="anchor" id="autotoc_md30"></a>
1. Parse and UI path</h2>
<p>Used for:</p>
<ul>
<li>browsing frames and signals</li>
<li>later integration with Qt <code>Model/View</code></li>
<li>displaying metadata</li>
</ul>
<p>Pipeline:</p>
<div class="fragment"><div class="line">DBC file</div>
<div class="line"> ↓</div>
<div class="line">DbcParser</div>
<div class="line"> ↓</div>
<div class="line">DbcDatabase</div>
<div class="line"> ↓</div>
<div class="line">DbcTreeBuilder</div>
<div class="line"> ↓</div>
<div class="line">TreeNode hierarchy</div>
<div class="line"> ↓</div>
<div class="line">DbcTreeModel → Qt views</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md31"></a>
2. Runtime decode path</h2>
<p>Used for:</p>
<ul>
<li>live CAN decoding</li>
<li>CAN trace decoding</li>
<li>fast lookup by CAN ID</li>
</ul>
<p>Pipeline:</p>
<div class="fragment"><div class="line">DBC file</div>
<div class="line"> ↓</div>
<div class="line">DbcParser</div>
<div class="line"> ↓</div>
<div class="line">DbcDatabase</div>
<div class="line"> ↓</div>
<div class="line">DbcDecodeBuilder</div>
<div class="line"> ↓</div>
<div class="line">DecodeDatabase</div>
<div class="line"> ↓</div>
<div class="line">DbcDecoder</div>
<div class="line"> ↓</div>
<div class="line">Decoded values</div>
</div><!-- fragment --><p>This separation is intentional.</p>
<p>The tree is useful for UI, but it is <b>not</b> the main data structure for runtime decoding.</p>
<hr />
<h1><a class="anchor" id="autotoc_md33"></a>
Why the Runtime Decode Layer Exists</h1>
<p>A tree structure is convenient for browsing, but a runtime decoder needs something different:</p>
<ul>
<li>fast lookup by CAN ID</li>
<li>direct access to signal decode definitions</li>
<li>minimal overhead during repeated decoding</li>
<li>the same logic for live frames and trace frames</li>
</ul>
<p>Because of that, the design uses a dedicated runtime-ready structure:</p>
<ul>
<li><code><a class="el" href="classDecodeDatabase.html" title="Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...">DecodeDatabase</a></code></li>
<li><code><a class="el" href="structDecodeFrame.html" title="Runtime-ready frame definition.">DecodeFrame</a></code></li>
<li><code><a class="el" href="structDecodeSignal.html" title="Runtime-ready signal definition.">DecodeSignal</a></code></li>
</ul>
<p>This avoids forcing UI-oriented structures into a decode role they were not meant for.</p>
<hr />
<h1><a class="anchor" id="autotoc_md35"></a>
Module Layout</h1>
<div class="fragment"><div class="line">core/ C++17 parser, statement handlers, metadata, tree, and decoder</div>
<div class="line">examples/ Command-line demo (built separately)</div>
<div class="line">qt/ Optional read-only Qt Core model adapter</div>
<div class="line">tests/ Parser, decoder, tree, and optional model tests</div>
<div class="line">docs/ Generated Doxygen documentation</div>
<div class="line">dbc.pro Root qmake project: core + tests</div>
<div class="line">Doxyfile API documentation configuration</div>
</div><!-- fragment --><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Component </th><th class="markdownTableHeadNone">Source files </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Parsed metadata </td><td class="markdownTableBodyNone"><code><a class="el" href="dbc__database_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">core/dbc_database.h</a></code>, <code><a class="el" href="frame__info_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">core/frame_info.h</a></code>, <code><a class="el" href="signal__info_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">core/signal_info.h</a></code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Parser and dispatch </td><td class="markdownTableBodyNone"><code>core/dbc_parser.*</code>, <code><a class="el" href="dbc__diagnostic_8h_source.html">core/dbc_diagnostic.h</a></code>, <code>core/dbc_statement_handler.*</code>, <code><a class="el" href="typefactory_8h_source.html">core/typefactory.h</a></code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">UI tree </td><td class="markdownTableBodyNone"><code>core/tree_node.*</code>, <code>core/dbc_tree_builder.*</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Runtime database </td><td class="markdownTableBodyNone"><code><a class="el" href="decode__database_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">core/decode_database.h</a></code>, <code>core/dbc_decode_builder.*</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Decoder </td><td class="markdownTableBodyNone"><code>core/dbc_decoder.*</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Demo </td><td class="markdownTableBodyNone"><code><a class="el" href="examples_2main_8cpp.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">examples/main.cpp</a></code>, <code>examples/demo.pro</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Build integration </td><td class="markdownTableBodyNone"><code>core/core.pro</code>, <code>core/core_files.pri</code>, <code>core/core.pri</code> </td></tr>
</table>
<hr />
<h1><a class="anchor" id="autotoc_md37"></a>
Parsed Data Structures</h1>
<h1><a class="anchor" id="autotoc_md38"></a>
&lt;tt&gt;SignalInfo&lt;/tt&gt;</h1>
<p>Represents one signal as parsed from the DBC file.</p>
<p>Fields:</p>
<ul>
<li><code>name</code></li>
<li><code>startBit</code></li>
<li><code>length</code></li>
<li><code>isLittleEndian</code></li>
<li><code>isSigned</code></li>
<li><code>factor</code></li>
<li><code>offset</code></li>
<li><code>minimum</code></li>
<li><code>maximum</code></li>
<li><code>unit</code></li>
<li><code>receivers</code></li>
<li><code>comment</code></li>
</ul>
<p>Notes:</p>
<ul>
<li><code>receivers</code> is a list because a signal may have more than one receiver ECU</li>
<li><code>factor</code> and <code>offset</code> define physical conversion</li>
<li>this structure is close to DBC content and easy to inspect</li>
</ul>
<p>Physical value rule:</p>
<div class="fragment"><div class="line">physical = raw * factor + offset</div>
</div><!-- fragment --><hr />
<h1><a class="anchor" id="autotoc_md40"></a>
&lt;tt&gt;FrameInfo&lt;/tt&gt;</h1>
<p>Represents one frame as parsed from the DBC file.</p>
<p>Fields:</p>
<ul>
<li><code>name</code></li>
<li><code>canId</code></li>
<li><code>isExtended</code></li>
<li><code>pgn</code></li>
<li><code>hasPgn</code></li>
<li><code>dlc</code></li>
<li><code>transmitter</code></li>
<li><code>comment</code></li>
<li><code>signals</code></li>
</ul>
<p>Notes:</p>
<ul>
<li><code>signals</code> is a list of <code><a class="el" href="structSignalInfo.html" title="Describes one signal inside a DBC frame.">SignalInfo</a></code></li>
<li><code>isExtended</code> is determined during CAN ID normalization</li>
<li><code>pgn</code> is derived using simplified J1939 logic when applicable</li>
</ul>
<hr />
<h1><a class="anchor" id="autotoc_md42"></a>
&lt;tt&gt;DbcDatabase&lt;/tt&gt;</h1>
<p>Top-level parsed DBC container.</p>
<p>Conceptually:</p>
<div class="fragment"><div class="line">DbcDatabase</div>
<div class="line"> └── vector&lt;FrameInfo&gt;</div>
</div><!-- fragment --><p>This is the central structure produced by <code><a class="el" href="classDbcParser.html" title="Minimal DBC parser.">DbcParser</a></code>.</p>
<hr />
<h1><a class="anchor" id="autotoc_md44"></a>
UI Tree Layer</h1>
<h1><a class="anchor" id="autotoc_md45"></a>
&lt;tt&gt;TreeNode&lt;/tt&gt;</h1>
<p>The UI tree contains three node types:</p>
<ul>
<li><code>Root</code></li>
<li><code>Frame</code></li>
<li><code>Signal</code></li>
</ul>
<p>Example hierarchy:</p>
<div class="fragment"><div class="line">dbc</div>
<div class="line"> ├── EngineData</div>
<div class="line"> │ ├── EngineSpeed</div>
<div class="line"> │ ├── OilTemp</div>
<div class="line"> │ └── CoolantTemp</div>
<div class="line"> └── VehicleData</div>
<div class="line"> ├── VehicleSpeed</div>
<div class="line"> └── Odometer</div>
</div><!-- fragment --><p>Frame and signal nodes store copies of the corresponding metadata; the root has no metadata payload. The payload types are:</p>
<ul>
<li><code><a class="el" href="structFrameInfo.html" title="Describes one CAN frame from a DBC file.">FrameInfo</a></code></li>
<li><code><a class="el" href="structSignalInfo.html" title="Describes one signal inside a DBC frame.">SignalInfo</a></code></li>
</ul>
<p>The tree supports browsing through the optional <code><a class="el" href="classDbcTreeModel.html">DbcTreeModel</a></code> adapter.</p>
<p>It is <b>not</b> the primary runtime decode structure.</p>
<hr />
<h1><a class="anchor" id="autotoc_md47"></a>
Runtime Decode Layer</h1>
<h1><a class="anchor" id="autotoc_md48"></a>
Purpose</h1>
<p>The decode layer exists so that decoding can be fast and independent from UI concerns.</p>
<p>Instead of searching a tree, the decoder uses a prepared database with direct lookup.</p>
<hr />
<h1><a class="anchor" id="autotoc_md50"></a>
&lt;tt&gt;ByteOrder&lt;/tt&gt;</h1>
<p>Runtime byte order enum:</p>
<ul>
<li><code>Intel</code></li>
<li><code>Motorola</code></li>
</ul>
<p>This is better for decode code than passing around raw DBC characters.</p>
<hr />
<h1><a class="anchor" id="autotoc_md52"></a>
&lt;tt&gt;ValueType&lt;/tt&gt;</h1>
<p>Numeric type enum:</p>
<ul>
<li><code>Unsigned</code></li>
<li><code>Signed</code></li>
</ul>
<p>This is clearer than combining multiple boolean flags during runtime logic.</p>
<hr />
<h1><a class="anchor" id="autotoc_md54"></a>
&lt;tt&gt;DecodeSignal&lt;/tt&gt;</h1>
<p>Represents one runtime-ready signal definition.</p>
<p>Fields:</p>
<ul>
<li><code>name</code></li>
<li><code>startBit</code></li>
<li><code>length</code></li>
<li><code>byteOrder</code></li>
<li><code>valueType</code></li>
<li><code>factor</code></li>
<li><code>offset</code></li>
<li><code>minimum</code></li>
<li><code>maximum</code></li>
<li><code>unit</code></li>
<li><code>receivers</code></li>
<li><code>comment</code></li>
</ul>
<p>This structure contains all information required for extracting and converting a signal value from raw frame data.</p>
<hr />
<h1><a class="anchor" id="autotoc_md56"></a>
&lt;tt&gt;DecodeFrame&lt;/tt&gt;</h1>
<p>Represents one runtime-ready frame definition.</p>
<p>Fields:</p>
<ul>
<li><code>name</code></li>
<li><code>canId</code></li>
<li><code>isExtended</code></li>
<li><code>dlc</code></li>
<li><code>pgn</code></li>
<li><code>hasPgn</code></li>
<li><code>transmitter</code></li>
<li><code>comment</code></li>
<li><code>signals</code></li>
</ul>
<p>This structure is used directly by the decoder.</p>
<hr />
<h1><a class="anchor" id="autotoc_md58"></a>
&lt;tt&gt;FrameKey&lt;/tt&gt;</h1>
<p>Stable identifier for runtime frame matching and application state.</p>
<p>Fields:</p>
<ul>
<li><code>canId</code></li>
<li><code>isExtended</code></li>
</ul>
<p>This matters because the same numeric identifier must not be confused between standard and extended frames.</p>
<hr />
<h1><a class="anchor" id="autotoc_md60"></a>
&lt;tt&gt;DecodeDatabase&lt;/tt&gt;</h1>
<p>Immutable runtime snapshot with a private frame index. Build it with <code>DbcDecodeBuilder::Build(parsed)</code> or construct it from <code>std::vector&lt;<a class="el" href="structDecodeFrame.html" title="Runtime-ready frame definition.">DecodeFrame</a>&gt;</code>. Construction validates all definitions before publishing the snapshot and throws <code>std::invalid_argument</code> for invalid metadata, including manually supplied data:</p>
<ul>
<li>Normalized CAN IDs must fit 11 bits for standard frames or 29 bits for extended frames. DBC's bit-31 encoding flag must already be removed.</li>
<li>Frame keys must be unique; signal names must be unique within their frame.</li>
<li>Signal lengths must be 1–64 bits, with Intel/Motorola layouts entirely inside the declared payload. Bit coordinates use overflow-safe 64-bit arithmetic.</li>
<li>Byte order, numeric type, and multiplexing role must be valid enum values.</li>
<li>Factor, offset, minimum, and maximum must be finite; minimum must not exceed maximum. Zero and negative factors are allowed.</li>
<li><a class="el" href="structMultiplexing.html">Multiplexing</a> requires one unsigned selector when branches are present, with branch values in its raw range. Signals may overlap only when they are branches selected by different raw values, including mixed byte orders.</li>
</ul>
<p><code>dlc</code> remains a byte count in the storage range 0–255; construction imposes no additional CAN/CAN FD payload limit. A zero-byte frame may contain no signals. Both <code><a class="el" href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b" title="Build runtime decode database.">DbcDecodeBuilder::Build</a></code> and the direct constructor apply these rules. Construction copies the input, including nested metadata, even for rvalue input. Saved mutable aliases into that input cannot modify definitions or invalidate the lookup index. Database copies still share the frozen snapshot; a failed construction or replacement leaves the previous snapshot and its lookups intact.</p>
<ul>
<li><code>GetFrames()</code> returns a borrowed <code>const std::vector&lt;<a class="el" href="structDecodeFrame.html" title="Runtime-ready frame definition.">DecodeFrame</a>&gt;&amp;</code>.</li>
<li><code>FindFrame(FrameKey)</code> returns <code>std::shared_ptr&lt;const <a class="el" href="structDecodeFrame.html" title="Runtime-ready frame definition.">DecodeFrame</a>&gt;</code>.</li>
<li><code>FindSignal(SignalKey)</code> returns <code>std::shared_ptr&lt;const <a class="el" href="structDecodeSignal.html" title="Runtime-ready signal definition.">DecodeSignal</a>&gt;</code>.</li>
<li>Missing definitions return an empty handle.</li>
<li>Copying a database shares its snapshot; replacing it installs another snapshot.</li>
</ul>
<p>Frame lookup uses a hash index; signal lookup scans the matched frame's signals. Decoding shares the snapshot without copying definitions or allocating ownership objects per signal.</p>
<hr />
<h1><a class="anchor" id="autotoc_md62"></a>
Decoder Layer</h1>
<h1><a class="anchor" id="autotoc_md63"></a>
&lt;tt&gt;RawCanFrame&lt;/tt&gt;</h1>
<p>Represents a raw CAN frame to decode.</p>
<p>Fields:</p>
<ul>
<li><code>canId</code></li>
<li><code>isExtended</code></li>
<li><code>data</code></li>
</ul>
<p>This same structure can be used for:</p>
<ul>
<li>live CAN bus input</li>
<li>replayed trace records</li>
<li>unit tests</li>
</ul>
<hr />
<h1><a class="anchor" id="autotoc_md65"></a>
&lt;tt&gt;DecodedSignalValue&lt;/tt&gt;</h1>
<p>Represents one decoded signal result.</p>
<p>Fields:</p>
<ul>
<li><code>definition</code></li>
<li><code>key</code></li>
<li><code>rawValue</code></li>
<li><code>physicalValue</code></li>
<li><code>valid</code></li>
<li><code>status</code></li>
</ul>
<hr />
<h2><a class="anchor" id="autotoc_md67"></a>
Raw value representation and precision</h2>
<p><code><a class="el" href="structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28">DecodedSignalValue::rawValue</a></code> is a C++17 <code>std::variant&lt;std::int64_t, std::uint64_t&gt;</code>. For a valid signal, signed definitions produce the <code>int64_t</code> alternative and unsigned definitions produce the <code>uint64_t</code> alternative. Raw values remain exact across their full 64-bit ranges. Check <code>valid</code> before using the physical value. Raw data is also available when <code>status == PhysicalConversionFailed</code>; other invalid results have no decoded numeric data.</p>
<p>Use <code>std::get</code> when the numeric type is known, or <code>std::get_if</code> to handle both:</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (<span class="keyword">const</span> std::int64_t *value = std::get_if&lt;std::int64_t&gt;(&amp;decodedSignal.rawValue)) {</div>
<div class="line"> std::cout &lt;&lt; *value;</div>
<div class="line">} <span class="keywordflow">else</span> {</div>
<div class="line"> std::cout &lt;&lt; std::get&lt;std::uint64_t&gt;(decodedSignal.rawValue);</div>
<div class="line">}</div>
</div><!-- fragment --><p>This replaces the previous <code>int64_t</code> field: consumers that read or print <code>rawValue</code> directly must handle the variant.</p>
<p>Physical conversion uses the active numeric type: <code>physicalValue = static_cast&lt;double&gt;(raw) * factor + offset</code>. <code>physicalValue</code> remains a <code>double</code> 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 <code>UINT64_MAX</code> remains exact in <code>rawValue</code>, but converts to approximately 18446744073709551616 in binary64 before scaling. Use <code>rawValue</code> whenever exact integer values are required.</p>
<hr />
<h1><a class="anchor" id="autotoc_md69"></a>
&lt;tt&gt;DecodedFrameValue&lt;/tt&gt;</h1>
<p>Represents one decoded frame result.</p>
<p>Fields:</p>
<ul>
<li><code>definition</code></li>
<li><code>key</code></li>
<li><code>signals</code></li>
<li><code>valid</code></li>
<li><code>status</code></li>
</ul>
<p><code>valid</code> means a matching frame definition was found. Check each signal's <code>valid</code> separately: insufficient payload data can leave individual signals invalid even when the frame is valid. An unknown frame returns <code>valid == false</code>, a null definition, its requested key, and an empty signal list.</p>
<p><code>FrameDecodeStatus</code> summarizes the result:</p>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Status </th><th class="markdownTableHeadNone">Meaning </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>UnknownFrame</code> </td><td class="markdownTableBodyNone">No definition matches both CAN ID and standard/extended type </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>InsufficientPayload</code> </td><td class="markdownTableBodyNone">Actual byte count is less than the declared <code>dlc</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>SignalErrors</code> </td><td class="markdownTableBodyNone">Payload is long enough, but at least one signal failed </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>Valid</code> </td><td class="markdownTableBodyNone">Payload is long enough and every signal is valid or inactive </td></tr>
</table>
<p>Short-payload status takes precedence over signal errors; inspect each signal's status for the individual cause. <code>valid</code> retains its existing meaning of a matched definition and does not imply <code>status == FrameDecodeStatus::Valid</code>.</p>
<p>Payload policy uses <code>dlc</code> as a byte count, including for CAN FD; it is not the encoded wire DLC. A shorter payload is never padded: all signals whose bytes are available still decode, even if other signals fail. A longer payload is accepted; bytes beyond <code>dlc</code> are ignored. Signal bit layouts must fit the declared <code>dlc</code>, so extra bytes cannot rescue an invalid definition. Empty payloads and zero-byte frame definitions follow the same rules. Results include every signal in definition order, preserving successful values and definition handles on partial failures.</p>
<p>The decoder applies factor and offset; it does not clamp physical values to the declared minimum and maximum. Non-finite conversion results (NaN or positive/ negative infinity), including overflow with finite factor/offset, produce <code>PhysicalConversionFailed</code>. The exact raw value and non-finite <code>physicalValue</code> remain available, while signal <code>valid</code> is false. Non-finite numeric parameters are rejected during database construction. Finite parameters can still overflow during conversion; conversion failure of a selector does not prevent raw branch selection.</p>
<h2><a class="anchor" id="autotoc_md70"></a>
Definition ownership and reload</h2>
<p><code><a class="el" href="structDecodedFrameValue.html#a33e971ba10030506007aa201c89f351d">DecodedFrameValue::definition</a></code> and <code><a class="el" href="structDecodedSignalValue.html#a828b5ef7faefc14fbf5dbd46249bcad2">DecodedSignalValue::definition</a></code> are owning <code>std::shared_ptr&lt;const ...&gt;</code> handles. Each handle retains the immutable runtime snapshot. Definitions remain valid until the last database copy, lookup handle, or decoded result owning that snapshot is released. An independently copied signal result retains its definition even after the parent frame result is removed. Copying or moving results preserves ownership.</p>
<p>Reload by assigning a newly built database. Stored results continue to describe the old DBC, including its units, scaling, comments, and <code>VAL_</code> descriptions; subsequent decoding uses the new DBC. Removed definitions cannot be found in the new database, but old results safely retain their old definitions. Keeping even one signal handle retains the whole old snapshot; release stored results when that metadata is no longer needed.</p>
<p><code>GetFrames()</code> is a borrowed view. References, iterators, and raw pointers obtained from it or from a handle's <code>.get()</code> do not retain ownership. Keep an owning handle or an unchanged database copy while using them. Constructor input is copied and may be changed independently afterward. The raw string pointer from <code>GetValueDescription()</code> follows the same rule: keep the signal definition handle alive while using the string.</p>
<p>Parsed <code><a class="el" href="structDbcDatabase.html" title="Parsed DBC content stored in a simple internal form.">DbcDatabase</a></code>/<code><a class="el" href="structFrameInfo.html" title="Describes one CAN frame from a DBC file.">FrameInfo</a></code>/<code><a class="el" href="structSignalInfo.html" title="Describes one signal inside a DBC frame.">SignalInfo</a></code> remain ordinary mutable value containers: borrowed pointers follow standard vector invalidation rules. Builders copy their metadata, so parsed input may be changed or destroyed after building. Tree nodes own metadata copies; the Qt model owns its tree and invalidates model indexes on reset. Runtime handles do not depend on the parsed database or tree. Synchronize replacement of a shared database variable with decoding; immutable snapshots do not make concurrent assignment to the same object safe.</p>
<h2><a class="anchor" id="autotoc_md71"></a>
Stable frame and signal identifiers</h2>
<p><code><a class="el" href="structDecodedFrameValue.html#a32143efe2023a1ecd977a9ae93e50b73">DecodedFrameValue::key</a></code> is a <code><a class="el" href="structFrameKey.html" title="Stable frame identifier: normalized CAN ID and frame type.">FrameKey</a></code> (normalized <code>canId</code>, <code>isExtended</code>), also available through <code>DecodeFrame::GetKey()</code>. <code><a class="el" href="structDecodedSignalValue.html#a33df0fcd92b23b3e08539906fc6b4c4a">DecodedSignalValue::key</a></code> is a <code><a class="el" href="structSignalKey.html">SignalKey</a></code> (frame key, exact case-sensitive signal name). Both are value types with equality and hashers (<code><a class="el" href="structFrameKeyHasher.html" title="Hasher for frame key.">FrameKeyHasher</a></code>, <code><a class="el" href="structSignalKeyHasher.html">SignalKeyHasher</a></code>) for application maps and saved selections. Construct the same keys from parsed metadata when needed; do not use addresses or vector positions as identifiers.</p>
<p>Keys stay equal across reloads and reordering when their components stay equal. Frame renaming and changes to units, bit layout, scaling, or descriptions do not change a key. Changing a CAN ID/frame type or renaming a signal produces a new key. The same name in different frames and standard/extended frames with the same numeric CAN ID remain distinct. Keys identify definitions within one logical DBC database; applications combining databases must add their own database ID. A key is not a version identifier: matching keys in different snapshots may have different metadata. Use <code>valid</code>/the definition handle to distinguish a matched result; default keys alone do not indicate successful decoding.</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classDecodeDatabase.html">DecodeDatabase</a> runtime = <a class="code hl_class" href="classDbcDecodeBuilder.html">DbcDecodeBuilder</a>().<a class="code hl_function" href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b">Build</a>(parsed);</div>
<div class="line"><a class="code hl_struct" href="structDecodedFrameValue.html">DecodedFrameValue</a> stored = <a class="code hl_class" href="classDbcDecoder.html">DbcDecoder</a>().<a class="code hl_function" href="classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7">Decode</a>(runtime, rawFrame);</div>
<div class="line"><span class="keywordflow">if</span> (stored.<a class="code hl_variable" href="structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0">valid</a> &amp;&amp; !stored.signals.empty()) {</div>
<div class="line"> <a class="code hl_struct" href="structDecodedSignalValue.html">DecodedSignalValue</a> saved = stored.signals.front();</div>
<div class="line"> <a class="code hl_struct" href="structSignalKey.html">SignalKey</a> selection = saved.<a class="code hl_variable" href="structDecodedSignalValue.html#a33df0fcd92b23b3e08539906fc6b4c4a">key</a>;</div>
<div class="line"> runtime = <a class="code hl_class" href="classDbcDecodeBuilder.html">DbcDecodeBuilder</a>().<a class="code hl_function" href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b">Build</a>(parser.ParseFile(<span class="stringliteral">&quot;updated.dbc&quot;</span>));</div>
<div class="line"> std::shared_ptr&lt;const DecodeSignal&gt; current = runtime.FindSignal(selection);</div>
<div class="line"> <span class="comment">// saved.definition retains old metadata; current holds new metadata or is empty.</span></div>
<div class="line">}</div>
<div class="ttc" id="aclassDbcDecodeBuilder_html"><div class="ttname"><a href="classDbcDecodeBuilder.html">DbcDecodeBuilder</a></div><div class="ttdoc">Converts parsed DBC data into runtime decode database.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decode__builder_8h_source.html#l00021">dbc_decode_builder.h:21</a></div></div>
<div class="ttc" id="aclassDbcDecodeBuilder_html_a2bc6386dfb5e58976c42e22c19ec471b"><div class="ttname"><a href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b">DbcDecodeBuilder::Build</a></div><div class="ttdeci">DecodeDatabase Build(const DbcDatabase &amp;source) const</div><div class="ttdoc">Build runtime decode database.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decode__builder_8cpp_source.html#l00015">dbc_decode_builder.cpp:15</a></div></div>
<div class="ttc" id="aclassDbcDecoder_html"><div class="ttname"><a href="classDbcDecoder.html">DbcDecoder</a></div><div class="ttdoc">Runtime CAN decoder using prebuilt decode database.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00084">dbc_decoder.h:84</a></div></div>
<div class="ttc" id="aclassDbcDecoder_html_a345951ffe5d943a70d3a1ea1f39e74f7"><div class="ttname"><a href="classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7">DbcDecoder::Decode</a></div><div class="ttdeci">DecodedFrameValue Decode(const DecodeDatabase &amp;database, const RawCanFrame &amp;frame) const</div><div class="ttdoc">Decode one raw CAN frame.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8cpp_source.html#l00023">dbc_decoder.cpp:23</a></div></div>
<div class="ttc" id="aclassDecodeDatabase_html"><div class="ttname"><a href="classDecodeDatabase.html">DecodeDatabase</a></div><div class="ttdoc">Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...</div><div class="ttdef"><b>Definition</b> <a href="decode__database_8h_source.html#l00087">decode_database.h:87</a></div></div>
<div class="ttc" id="astructDecodedFrameValue_html"><div class="ttname"><a href="structDecodedFrameValue.html">DecodedFrameValue</a></div><div class="ttdoc">Fully decoded frame.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00071">dbc_decoder.h:71</a></div></div>
<div class="ttc" id="astructDecodedFrameValue_html_a4f51c31110dba1f73a763c596372beb0"><div class="ttname"><a href="structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0">DecodedFrameValue::valid</a></div><div class="ttdeci">bool valid</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00075">dbc_decoder.h:75</a></div></div>
<div class="ttc" id="astructDecodedSignalValue_html"><div class="ttname"><a href="structDecodedSignalValue.html">DecodedSignalValue</a></div><div class="ttdoc">One decoded signal value.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00052">dbc_decoder.h:52</a></div></div>
<div class="ttc" id="astructDecodedSignalValue_html_a33df0fcd92b23b3e08539906fc6b4c4a"><div class="ttname"><a href="structDecodedSignalValue.html#a33df0fcd92b23b3e08539906fc6b4c4a">DecodedSignalValue::key</a></div><div class="ttdeci">SignalKey key</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00054">dbc_decoder.h:54</a></div></div>
<div class="ttc" id="astructSignalKey_html"><div class="ttname"><a href="structSignalKey.html">SignalKey</a></div><div class="ttdef"><b>Definition</b> <a href="definition__key_8h_source.html#l00042">definition_key.h:42</a></div></div>
</div><!-- fragment --><p><b>API migration:</b> replace reads of <code>runtime.frames</code> with <code>runtime.GetFrames()</code>. To edit runtime definitions, prepare a vector and construct a new database; <code>frameIndexByKey</code> is now private and built automatically. <code><a class="el" href="classDbcDecoder.html#a4005c4311f57b7faf21c0cb31463039c" title="Find frame definition by CAN ID.">DbcDecoder::FindFrame</a></code> and result <code>definition</code> fields now use owning handles instead of raw pointers; <code>definition-&gt;name</code>, boolean/null checks, and existing decode calls remain usable. Use <code>.get()</code> only for temporary raw-pointer interoperation with an owner alive.</p>
<hr />
<h1><a class="anchor" id="autotoc_md73"></a>
&lt;tt&gt;DbcDecoder&lt;/tt&gt;</h1>
<p>Main runtime decoder class.</p>
<p>Responsibilities:</p>
<ul>
<li>find a frame definition by CAN ID</li>
<li>decode unconditional signals and the active multiplexed branch</li>
<li>extract raw values</li>
<li>sign-extend signed values</li>
<li>convert raw values into physical values</li>
</ul>
<p>Main methods:</p>
<ul>
<li><code>FindFrame(...)</code></li>
<li><code>Decode(...)</code></li>
</ul>
<hr />
<h1><a class="anchor" id="autotoc_md75"></a>
Parser Support</h1>
<p>The current parser supports the following DBC elements:</p>
<ul>
<li><code>BO_</code></li>
<li><code>SG_</code></li>
<li><code>CM_ BO_</code></li>
<li><code>CM_ SG_</code></li>
<li><code>VAL_</code> signal value descriptions</li>
<li>basic <code>M</code> / <code>mN</code> multiplexing</li>
</ul>
<h2><a class="anchor" id="autotoc_md76"></a>
Structured diagnostics</h2>
<p><code>ParseFileWithDiagnostics(path)</code> returns <code><a class="el" href="structDbcParseResult.html">DbcParseResult</a></code> containing <code>database</code> and <code>diagnostics</code>. Each <code><a class="el" href="structDbcDiagnostic.html">DbcDiagnostic</a></code> has <code>severity</code>, <code>code</code>, <code>filePath</code>, <code>lineNumber</code>, and <code>message</code>. Paths preserve the caller's supplied spelling. Lines are one-based physical lines, including blank lines; file-level errors use zero.</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <a class="code hl_class" href="classDbcParser.html">DbcParser</a> parser;</div>
<div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structDbcParseResult.html">DbcParseResult</a> result = parser.<a class="code hl_function" href="classDbcParser.html#a0e915ce79c2e3d4c95a5aaf2bf0409bc">ParseFileWithDiagnostics</a>(<span class="stringliteral">&quot;example.dbc&quot;</span>);</div>
<div class="line"><span class="keywordflow">for</span> (<span class="keyword">const</span> <a class="code hl_struct" href="structDbcDiagnostic.html">DbcDiagnostic</a> &amp;diagnostic : result.diagnostics) {</div>
<div class="line"> std::cerr &lt;&lt; diagnostic.filePath &lt;&lt; <span class="stringliteral">&quot;:&quot;</span> &lt;&lt; diagnostic.lineNumber</div>
<div class="line"> &lt;&lt; <span class="stringliteral">&quot;: &quot;</span> &lt;&lt; diagnostic.message &lt;&lt; <span class="charliteral">&#39;\n&#39;</span>;</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">if</span> (!result.HasErrors()) {</div>
<div class="line"> <span class="keyword">const</span> <a class="code hl_class" href="classDecodeDatabase.html">DecodeDatabase</a> runtime = <a class="code hl_class" href="classDbcDecodeBuilder.html">DbcDecodeBuilder</a>().<a class="code hl_function" href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b">Build</a>(result.database);</div>
<div class="line"> <span class="comment">// Inspect warnings before relying on decoding results.</span></div>
<div class="line">}</div>
<div class="ttc" id="aclassDbcParser_html"><div class="ttname"><a href="classDbcParser.html">DbcParser</a></div><div class="ttdoc">Minimal DBC parser.</div><div class="ttdef"><b>Definition</b> <a href="dbc__parser_8h_source.html#l00033">dbc_parser.h:33</a></div></div>
<div class="ttc" id="aclassDbcParser_html_a0e915ce79c2e3d4c95a5aaf2bf0409bc"><div class="ttname"><a href="classDbcParser.html#a0e915ce79c2e3d4c95a5aaf2bf0409bc">DbcParser::ParseFileWithDiagnostics</a></div><div class="ttdeci">DbcParseResult ParseFileWithDiagnostics(const std::string &amp;filePath) const</div><div class="ttdoc">Parse with warnings and a structured first error instead of throwing.</div><div class="ttdef"><b>Definition</b> <a href="dbc__parser_8cpp_source.html#l00044">dbc_parser.cpp:44</a></div></div>
<div class="ttc" id="astructDbcDiagnostic_html"><div class="ttname"><a href="structDbcDiagnostic.html">DbcDiagnostic</a></div><div class="ttdef"><b>Definition</b> <a href="dbc__diagnostic_8h_source.html#l00025">dbc_diagnostic.h:25</a></div></div>
<div class="ttc" id="astructDbcParseResult_html"><div class="ttname"><a href="structDbcParseResult.html">DbcParseResult</a></div><div class="ttdef"><b>Definition</b> <a href="dbc__diagnostic_8h_source.html#l00033">dbc_diagnostic.h:33</a></div></div>
</div><!-- fragment --><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Severity / code </th><th class="markdownTableHeadNone">Meaning </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>Error</code> / <code>FileOpenError</code> </td><td class="markdownTableBodyNone">Input cannot be opened </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>Error</code> / <code>FileReadError</code> </td><td class="markdownTableBodyNone">Input cannot be read completely </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>Error</code> / <code>InvalidStatement</code> </td><td class="markdownTableBodyNone">Invalid frame/signal definition, duplicate, or payload violation </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>Error</code> / <code>InvalidValueDescription</code> </td><td class="markdownTableBodyNone">Invalid <code>VAL_</code> syntax, duplicate value, or unresolved reference </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>Error</code> / <code>InvalidMultiplexing</code> </td><td class="markdownTableBodyNone">Selector, branch range, or signal overlap validation failed </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>Warning</code> / <code>UnsupportedStatement</code> </td><td class="markdownTableBodyNone">Unregistered statement skipped; decoding or metadata may be incomplete </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>Error</code> / <code>UnsupportedStatement</code> </td><td class="markdownTableBodyNone">Extended multiplexing (<code>SG_MUL_VAL_</code>) rejected </td></tr>
</table>
<p>Parsing stops at the first error and returns an empty database, together with any preceding warnings and the error. Deferred <code>VAL_</code> and multiplexing errors retain their original source lines. Invalid signal markers use <code>InvalidStatement</code>. <code>HasErrors()</code> checks severity; warnings alone do not make a parse fail.</p>
<p>Unknown statements are reported conservatively, including <code>SIG_VALTYPE_</code>, attributes (<code>BA_</code>, <code>BA_DEF_</code>, defaults and relation forms), signal types/references, environment variables, named <code>VAL_TABLE_</code> tables, and vendor extensions. For example, ignoring <code>SIG_VALTYPE_</code> may decode a floating-point signal as an integer. The parser does not implement the warned features; consumers should review warnings.</p>
<p>Common <code>VERSION</code>, <code>NS_</code>, <code>BS_</code>, and <code>BU_</code> headers produce no diagnostics. Single-token symbols inside the <code>NS_</code> declaration list are quiet regardless of indentation, even when they name unsupported syntax. Frame, signal, bus, and node definitions or a line with arguments end the list. Actual unsupported statements outside that list are reported. Node and bus metadata are not stored. Other comment forms (<code>CM_</code>, <code>CM_ BU_</code>, <code>CM_ EV_</code>) are ignored by the comment handler; comments only attach to already parsed frames/signals. Supported statements currently require one physical line.</p>
<p><code>ParseFile(path)</code> remains compatible: it returns the database, discards warnings, and throws <code>std::runtime_error</code> on the first error with the existing <code>path:line:</code> format. Use <code>ParseFileWithDiagnostics</code> to see skipped syntax. Resource failures such as allocation errors may still throw.</p>
<hr />
<h1><a class="anchor" id="autotoc_md78"></a>
Supported DBC Syntax</h1>
<h1><a class="anchor" id="autotoc_md79"></a>
Frame definition</h1>
<p>Example:</p>
<div class="fragment"><div class="line">BO_ 256 EngineData: 8 EEC1</div>
</div><!-- fragment --><p>Parsed fields:</p>
<ul>
<li>frame CAN ID</li>
<li>frame name</li>
<li>DLC</li>
<li>transmitter ECU</li>
</ul>
<hr />
<h2><a class="anchor" id="autotoc_md81"></a>
Frame validation and parse errors</h2>
<p><code>BO_</code> definitions require a decimal CAN ID, a nonempty single-token frame name, a colon, a decimal payload length, and a transmitter token. Spaces or tabs may separate fields, and whitespace before the colon is accepted. Additional trailing fields are rejected.</p>
<p>Numeric fields must contain decimal digits only; signs, hexadecimal notation, fractional values, suffixes, and overflow are rejected. CAN IDs may contain the 29-bit identifier plus the optional DBC extended flag (bit 31). Bits 29 and 30 are rejected rather than silently discarded. For compatibility, unflagged IDs above <code>0x7FF</code> are still treated as extended.</p>
<p>The payload length must fit <code>uint8_t</code> (<code>0..255</code>). This is a storage-range check, not CAN or CAN FD protocol validation; no new 8-byte or 64-byte limit is imposed.</p>
<p>Parsing stops at the first detected error. Exceptions raised while parsing a line are reported as <code>std::runtime_error</code> with the supplied file path and the one-based physical line number, including blank lines:</p>
<div class="fragment"><div class="line">example.dbc:3: Invalid CAN ID: invalid</div>
</div><!-- fragment --><p>Frame and signal definitions are validated as described here; comprehensive DBC grammar coverage is still planned. File-open exceptions contain the path but no line number. The structured diagnostic API uses line zero for file-level errors.</p>
<hr />
<h1><a class="anchor" id="autotoc_md83"></a>
Signal definition</h1>
<p>Example:</p>
<div class="fragment"><div class="line">SG_ EngineSpeed : 0|16@1+ (0.125,0) [0|8000] &quot;rpm&quot; ECU1,ECU2</div>
</div><!-- fragment --><p>Parsed fields:</p>
<ul>
<li>signal name</li>
<li>start bit</li>
<li>signal length</li>
<li>byte order</li>
<li>signedness</li>
<li>factor</li>
<li>offset</li>
<li>minimum</li>
<li>maximum</li>
<li>unit</li>
<li>receivers</li>
</ul>
<hr />
<h2><a class="anchor" id="autotoc_md85"></a>
Signal validation and parse errors</h2>
<p><code>SG_</code> statements are matched completely. Signal names must be nonempty and contain no whitespace. Spaces and tabs are accepted between syntax elements; byte order and signedness remain adjacent (<code>@0+</code>, <code>@0-</code>, <code>@1+</code>, or <code>@1-</code>). A quoted unit (which may be empty) and a nonempty comma-separated receiver list are required. Unexpected trailing fields are rejected.</p>
<p>Start bits must be unsigned decimal integers fitting <code>uint32_t</code>; lengths must be within <code>1..64</code> bits. Signs, fractional values, numeric suffixes, and overflow are rejected for these fields. Every signal bit must fit within the frame's declared payload length, using Intel increasing bit positions or Motorola sawtooth traversal. This uses the stored payload length without introducing an additional CAN or CAN FD payload limit.</p>
<p>Factor, offset, minimum, and maximum accept signed decimal numbers, fractions, and scientific notation. The entire numeric token must be valid; hexadecimal numbers, NaN, infinity, conversion overflow, and conversion underflow are rejected. Minimum must not exceed maximum. Zero and negative factors are allowed.</p>
<p>Basic multiplexing markers <code>M</code> and <code>mN</code> are supported as described below. Overlapping signals are rejected unless their branch values differ. Duplicate frame keys and signal names within a frame are rejected.</p>
<p>Invalid signal definitions stop parsing with <code>path:line: description</code>, including when the signal exceeds the declared payload length.</p>
<hr />
<h1><a class="anchor" id="autotoc_md87"></a>
Basic multiplexing</h1>
<div class="fragment"><div class="line">BO_ 256 Status: 3 ECU</div>
<div class="line"> SG_ Mode M : 0|8@1+ (1,0) [0|255] &quot;&quot; ECU</div>
<div class="line"> SG_ Temperature m1 : 8|8@1- (1,0) [-128|127] &quot;C&quot; ECU</div>
<div class="line"> SG_ Pressure m2 : 8|8@1+ (2,0) [0|510] &quot;kPa&quot; ECU</div>
<div class="line"> SG_ Counter : 16|8@1+ (1,0) [0|255] &quot;&quot; ECU</div>
</div><!-- fragment --><p><code><a class="el" href="structSignalInfo.html" title="Describes one signal inside a DBC frame.">SignalInfo</a></code> and <code><a class="el" href="structDecodeSignal.html" title="Runtime-ready signal definition.">DecodeSignal</a></code> contain <code>multiplexing</code>: a <code>MultiplexRole</code> (<code>Unconditional</code>, <code>Selector</code>, or <code>Branch</code>) and an exact <code>uint64_t</code> branch <code>value</code>. Each frame may have one unsigned selector (<code>M</code>); a branch (<code>mN</code>) references that selector implicitly. The selector may appear after its branches. <code>N</code> must contain only decimal digits, fit <code>uint64_t</code>, and fit the selector's bit width. Leading zeros are accepted. A selector without branches is allowed. Signed selectors, missing selectors, multiple selectors, nested/combined markers, and extended <code>SG_MUL_VAL_</code> statements are rejected with the originating <code>path:line</code>. The dispatcher registers the unsupported statement handler through <code><a class="el" href="classTypeFactory.html" title="Registry-based factory for creating objects by runtime identifier.">TypeFactory</a></code>.</p>
<p>Signal bits may overlap only between branches with different selector values. This validation uses Intel or Motorola bit traversal, including mixed byte orders. It also rejects overlapping unconditional signals. Metadata survives the runtime and tree builders; the optional Qt adapter does not add multiplexing roles yet.</p>
<p>The shared decoder extracts the selector before processing branches, compares its <b>raw unsigned value</b>, and leaves result order equal to definition order. Factor, offset, and <code>VAL_</code> descriptions do not influence branch selection. Unconditional signals continue to decode. An unmapped selector value leaves all branches inactive.</p>
<p>Each result has <code>SignalDecodeStatus status</code>:</p>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Status </th><th class="markdownTableHeadNone">Meaning </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>Valid</code> </td><td class="markdownTableBodyNone">Raw and physical values are available; <code>valid == true</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>Inactive</code> </td><td class="markdownTableBodyNone">Selector is available and chooses another branch </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>SelectorUnavailable</code> </td><td class="markdownTableBodyNone">Branch activation is unknown because selector bytes are missing </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>InsufficientPayload</code> </td><td class="markdownTableBodyNone">Selected or unconditional signal bytes are missing </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>InvalidDefinition</code> </td><td class="markdownTableBodyNone">Defensive decoder check failed; invalid definitions are rejected during database construction </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>PhysicalConversionFailed</code> </td><td class="markdownTableBodyNone">Raw value is available, but the converted physical value is NaN or infinity </td></tr>
</table>
<p>All statuses except <code>Valid</code> have <code>valid == false</code> and <code>GetValueDescription()</code> returns nullptr. <code>PhysicalConversionFailed</code> preserves extracted raw data and the non-finite conversion result; other invalid statuses have no decoded numeric data. Check <code>status</code> to distinguish inactive branches from errors. Consumers constructing runtime metadata manually receive the same selector and non-overlap validation as parsed files. Extended and nested multiplexing are outside this stage and are explicitly rejected, rather than silently decoded as unconditional signals.</p>
<hr />
<h1><a class="anchor" id="autotoc_md89"></a>
Comments</h1>
<p>Frame comment example:</p>
<div class="fragment"><div class="line">CM_ BO_ 256 &quot;Engine data frame&quot;;</div>
</div><!-- fragment --><p>Signal comment example:</p>
<div class="fragment"><div class="line">CM_ SG_ 256 EngineSpeed &quot;Actual engine speed&quot;;</div>
</div><!-- fragment --><p>Stored in:</p>
<ul>
<li><code><a class="el" href="structFrameInfo.html#ace75121294f9d89b762080ab5643293c">FrameInfo::comment</a></code></li>
<li><code><a class="el" href="structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5">SignalInfo::comment</a></code></li>
</ul>
<hr />
<h1><a class="anchor" id="autotoc_md91"></a>
CAN ID Normalization</h1>
<p>The parser normalizes frame identifiers.</p>
<p>Common DBC behavior:</p>
<ul>
<li>extended identifiers may be stored with bit 31 set</li>
<li>the actual 29-bit identifier must be extracted from that value</li>
</ul>
<p>The parser therefore stores:</p>
<ul>
<li>normalized <code>canId</code></li>
<li>separate <code>isExtended</code> flag</li>
</ul>
<p>This is important both for correct lookup and for future interoperability with live CAN APIs.</p>
<hr />
<h1><a class="anchor" id="autotoc_md93"></a>
PGN Extraction</h1>
<p>PGN is derived only when the frame is treated as extended.</p>
<p>The current logic is simplified J1939 extraction:</p>
<ul>
<li><code>pf</code></li>
<li><code>ps</code></li>
<li><code>dp</code></li>
</ul>
<p>This is enough for a practical start but should not be treated as full J1939 validation.</p>
<hr />
<h1><a class="anchor" id="autotoc_md95"></a>
Decode Flow</h1>
<p>Typical runtime decode flow:</p>
<div class="fragment"><div class="line">RawCanFrame</div>
<div class="line"> ↓</div>
<div class="line">Find frame in DecodeDatabase</div>
<div class="line"> ↓</div>
<div class="line">Extract multiplexor selector first (when present)</div>
<div class="line">For each unconditional or active signal:</div>
<div class="line"> extract raw bits</div>
<div class="line"> apply sign extension if needed</div>
<div class="line"> convert to physical value</div>
<div class="line"> ↓</div>
<div class="line">DecodedFrameValue</div>
</div><!-- fragment --><hr />
<h1><a class="anchor" id="autotoc_md97"></a>
Intel and Motorola Extraction</h1>
<p>The decoder currently has separate extraction paths:</p>
<ul>
<li><code>ExtractIntel(...)</code></li>
<li><code>ExtractMotorola(...)</code></li>
</ul>
<p>This is important because byte order is not just metadata once decoding starts.</p>
<p>Intel and Motorola require different bit extraction logic.</p>
<p>This is one of the main reasons why the runtime decode layer should be explicit and prepared in advance.</p>
<hr />
<h1><a class="anchor" id="autotoc_md99"></a>
Example Usage</h1>
<p>Include the public headers from the <code>core/</code> include directory supplied by <code>core/core.pri</code>:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="dbc__parser_8h.html">dbc_parser.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;<a class="code" href="dbc__tree__builder_8h.html">dbc_tree_builder.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;<a class="code" href="dbc__decode__builder_8h.html">dbc_decode_builder.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;<a class="code" href="dbc__decoder_8h.html">dbc_decoder.h</a>&quot;</span></div>
<div class="ttc" id="adbc__decode__builder_8h_html"><div class="ttname"><a href="dbc__decode__builder_8h.html">dbc_decode_builder.h</a></div><div class="ttdoc">Created: 2026-03-13 Author: Deeaitch (Dim. Himro)</div></div>
<div class="ttc" id="adbc__decoder_8h_html"><div class="ttname"><a href="dbc__decoder_8h.html">dbc_decoder.h</a></div><div class="ttdoc">Created: 2026-03-13 Author: Deeaitch (Dim. Himro)</div></div>
<div class="ttc" id="adbc__parser_8h_html"><div class="ttname"><a href="dbc__parser_8h.html">dbc_parser.h</a></div><div class="ttdoc">Created: 2026-03-13 Author: Deeaitch (Dim. Himro)</div></div>
<div class="ttc" id="adbc__tree__builder_8h_html"><div class="ttname"><a href="dbc__tree__builder_8h.html">dbc_tree_builder.h</a></div><div class="ttdoc">Created: 2026-03-13 Author: Deeaitch (Dim. Himro)</div></div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md100"></a>
Parse DBC</h2>
<div class="fragment"><div class="line"><a class="code hl_class" href="classDbcParser.html">DbcParser</a> parser;</div>
<div class="line"><a class="code hl_struct" href="structDbcDatabase.html">DbcDatabase</a> database = parser.<a class="code hl_function" href="classDbcParser.html#aef72826942c9095d653fafa435855e56">ParseFile</a>(<span class="stringliteral">&quot;example.dbc&quot;</span>);</div>
<div class="ttc" id="aclassDbcParser_html_aef72826942c9095d653fafa435855e56"><div class="ttname"><a href="classDbcParser.html#aef72826942c9095d653fafa435855e56">DbcParser::ParseFile</a></div><div class="ttdeci">DbcDatabase ParseFile(const std::string &amp;filePath) const</div><div class="ttdoc">Parse DBC file.</div><div class="ttdef"><b>Definition</b> <a href="dbc__parser_8cpp_source.html#l00031">dbc_parser.cpp:31</a></div></div>
<div class="ttc" id="astructDbcDatabase_html"><div class="ttname"><a href="structDbcDatabase.html">DbcDatabase</a></div><div class="ttdoc">Parsed DBC content stored in a simple internal form.</div><div class="ttdef"><b>Definition</b> <a href="dbc__database_8h_source.html#l00022">dbc_database.h:22</a></div></div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md101"></a>
Build UI tree</h2>
<div class="fragment"><div class="line"><a class="code hl_class" href="classDbcTreeBuilder.html">DbcTreeBuilder</a> treeBuilder;</div>
<div class="line">std::unique_ptr&lt;TreeNode&gt; root = treeBuilder.<a class="code hl_function" href="classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b">Build</a>(database);</div>
<div class="ttc" id="aclassDbcTreeBuilder_html"><div class="ttname"><a href="classDbcTreeBuilder.html">DbcTreeBuilder</a></div><div class="ttdoc">Builds a simple tree from parsed DBC database.</div><div class="ttdef"><b>Definition</b> <a href="dbc__tree__builder_8h_source.html#l00023">dbc_tree_builder.h:23</a></div></div>
<div class="ttc" id="aclassDbcTreeBuilder_html_a7e57d067d831b14b383947fd125edd4b"><div class="ttname"><a href="classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b">DbcTreeBuilder::Build</a></div><div class="ttdeci">std::unique_ptr&lt; TreeNode &gt; Build(const DbcDatabase &amp;database) const</div><div class="ttdoc">Build tree representation of parsed DBC data.</div><div class="ttdef"><b>Definition</b> <a href="dbc__tree__builder_8cpp_source.html#l00014">dbc_tree_builder.cpp:14</a></div></div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md102"></a>
Build runtime decode database</h2>
<div class="fragment"><div class="line"><a class="code hl_class" href="classDbcDecodeBuilder.html">DbcDecodeBuilder</a> decodeBuilder;</div>
<div class="line"><a class="code hl_class" href="classDecodeDatabase.html">DecodeDatabase</a> decodeDatabase = decodeBuilder.<a class="code hl_function" href="classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b">Build</a>(database);</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md103"></a>
Decode a raw frame</h2>
<div class="fragment"><div class="line"><a class="code hl_struct" href="structRawCanFrame.html">RawCanFrame</a> rawFrame;</div>
<div class="line">rawFrame.<a class="code hl_variable" href="structRawCanFrame.html#a2d0e7fa0e3d5c20bbed55ed8f7888ff4">canId</a> = 256; <span class="comment">// EngineData from the DBC example above</span></div>
<div class="line">rawFrame.<a class="code hl_variable" href="structRawCanFrame.html#a462193d275adc1dba8bd18ffa0e36bb7">isExtended</a> = <span class="keyword">false</span>;</div>
<div class="line">rawFrame.<a class="code hl_variable" href="structRawCanFrame.html#a0acb487612104c99c9907344c035df83">data</a> = {0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};</div>
<div class="line"> </div>
<div class="line"><a class="code hl_class" href="classDbcDecoder.html">DbcDecoder</a> decoder;</div>
<div class="line"><a class="code hl_struct" href="structDecodedFrameValue.html">DecodedFrameValue</a> decoded = decoder.<a class="code hl_function" href="classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7">Decode</a>(decodeDatabase, rawFrame);</div>
<div class="ttc" id="astructRawCanFrame_html"><div class="ttname"><a href="structRawCanFrame.html">RawCanFrame</a></div><div class="ttdoc">Raw CAN frame used for runtime or trace decoding.</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00024">dbc_decoder.h:24</a></div></div>
<div class="ttc" id="astructRawCanFrame_html_a0acb487612104c99c9907344c035df83"><div class="ttname"><a href="structRawCanFrame.html#a0acb487612104c99c9907344c035df83">RawCanFrame::data</a></div><div class="ttdeci">std::vector&lt; std::uint8_t &gt; data</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00027">dbc_decoder.h:27</a></div></div>
<div class="ttc" id="astructRawCanFrame_html_a2d0e7fa0e3d5c20bbed55ed8f7888ff4"><div class="ttname"><a href="structRawCanFrame.html#a2d0e7fa0e3d5c20bbed55ed8f7888ff4">RawCanFrame::canId</a></div><div class="ttdeci">std::uint32_t canId</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00025">dbc_decoder.h:25</a></div></div>
<div class="ttc" id="astructRawCanFrame_html_a462193d275adc1dba8bd18ffa0e36bb7"><div class="ttname"><a href="structRawCanFrame.html#a462193d275adc1dba8bd18ffa0e36bb7">RawCanFrame::isExtended</a></div><div class="ttdeci">bool isExtended</div><div class="ttdef"><b>Definition</b> <a href="dbc__decoder_8h_source.html#l00026">dbc_decoder.h:26</a></div></div>
</div><!-- fragment --><hr />
<h1><a class="anchor" id="autotoc_md105"></a>
Unified Decode Strategy</h1>
<p>A key design goal is that the same decoder should work for both:</p>
<ul>
<li>live CAN frames</li>
<li>trace replay frames</li>
</ul>
<p>That means this architecture supports:</p>
<h2><a class="anchor" id="autotoc_md106"></a>
live path</h2>
<div class="fragment"><div class="line">live CAN input</div>
<div class="line"> ↓</div>
<div class="line">RawCanFrame</div>
<div class="line"> ↓</div>
<div class="line">DbcDecoder</div>
<div class="line"> ↓</div>
<div class="line">decoded signal values</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md107"></a>
trace path</h2>
<div class="fragment"><div class="line">trace reader</div>
<div class="line"> ↓</div>
<div class="line">RawCanFrame</div>
<div class="line"> ↓</div>
<div class="line">DbcDecoder</div>
<div class="line"> ↓</div>
<div class="line">decoded signal values</div>
</div><!-- fragment --><p>This avoids duplicating decode logic in two separate parts of the application.</p>
<hr />
<h1><a class="anchor" id="autotoc_md109"></a>
Intended Use in FrameTap</h1>
<p>This module is meant to support at least the following FrameTap workflows:</p>
<ul>
<li>load a DBC file</li>
<li>browse frames and signals</li>
<li>search signals</li>
<li>drag a signal into a plot later</li>
<li>decode live CAN traffic</li>
<li>decode recorded traces</li>
<li>convert raw values into physical values</li>
<li>show metadata like units, comments, transmitter, receivers, and PGN</li>
</ul>
<p>Example combined workflow:</p>
<div class="fragment"><div class="line">Load DBC</div>
<div class="line"> ↓</div>
<div class="line">Parse into DbcDatabase</div>
<div class="line"> ↓</div>
<div class="line">Build UI tree</div>
<div class="line"> ↓</div>
<div class="line">Build DecodeDatabase</div>
<div class="line"> ↓</div>
<div class="line">Use same decode engine for:</div>
<div class="line"> - live frames</div>
<div class="line"> - trace replay</div>
</div><!-- fragment --><hr />
<h1><a class="anchor" id="autotoc_md111"></a>
Why the Tree Is Not Enough</h1>
<p>The tree exists for browsing.</p>
<p>However, runtime decode should not rely on tree traversal because that would introduce unnecessary coupling and inefficiency.</p>
<p>A runtime decoder needs:</p>
<ul>
<li>fast key-based access</li>
<li>minimal interpretation at decode time</li>
<li>direct signal definitions already prepared</li>
</ul>
<p>That is why <code><a class="el" href="classDecodeDatabase.html" title="Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...">DecodeDatabase</a></code> is a separate layer.</p>
<hr />
<h1><a class="anchor" id="autotoc_md113"></a>
Statement Handler Factory</h1>
<p><code><a class="el" href="classDbcParser.html" title="Minimal DBC parser.">DbcParser</a></code> owns file reading, trimming, line numbers, and error reporting. Each <code>ParseFile()</code> call creates a fresh <code><a class="el" href="structDbcParseContext.html">DbcParseContext</a></code> and a <code><a class="el" href="classDbcStatementDispatcher.html">DbcStatementDispatcher</a></code>. The context contains the parsed database and current frame; handlers receive it by reference and retain no parsing state.</p>
<p>The dispatcher uses <code><a class="el" href="classTypeFactory.html" title="Registry-based factory for creating objects by runtime identifier.">TypeFactory</a>&lt;std::string, <a class="el" href="classDbcStatementHandler.html">DbcStatementHandler</a>&gt;</code> to create registered handlers once per parsing session, then reuses them for all matching lines:</p>
<ul>
<li><code>BO_</code> → <code><a class="el" href="classDbcFrameHandler.html">DbcFrameHandler</a></code></li>
<li><code>SG_</code> → <code><a class="el" href="classDbcSignalHandler.html">DbcSignalHandler</a></code></li>
<li><code>CM_</code> → <code><a class="el" href="classDbcCommentHandler.html">DbcCommentHandler</a></code></li>
<li><code>VAL_</code> → <code><a class="el" href="classDbcValueDescriptionHandler.html">DbcValueDescriptionHandler</a></code></li>
<li><code>SG_MUL_VAL_</code> → <code><a class="el" href="classDbcUnsupportedMultiplexingHandler.html">DbcUnsupportedMultiplexingHandler</a></code></li>
<li><code>VERSION</code>, <code>NS_</code>, <code>BS_</code>, <code>BU_</code> → <code><a class="el" href="classDbcHeaderHandler.html">DbcHeaderHandler</a></code> (also accepts attached colons)</li>
</ul>
<p>Grammar implementations live in <code><a class="el" href="dbc__statement__handler_8cpp_source.html">core/dbc_statement_handler.cpp</a></code>; their interface, context, and dispatcher live in <code><a class="el" href="dbc__statement__handler_8h_source.html">core/dbc_statement_handler.h</a></code>. <code><a class="el" href="typefactory_8h_source.html">core/typefactory.h</a></code> provides the generic registry and object creation.</p>
<p>To add a construct, implement a default-constructible handler deriving from <code><a class="el" href="classDbcStatementHandler.html">DbcStatementHandler</a></code> with:</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> Handle(<span class="keyword">const</span> std::string &amp;line, <a class="code hl_struct" href="structDbcParseContext.html">DbcParseContext</a> &amp;context) <span class="keyword">const override</span>;</div>
<div class="ttc" id="astructDbcParseContext_html"><div class="ttname"><a href="structDbcParseContext.html">DbcParseContext</a></div><div class="ttdef"><b>Definition</b> <a href="dbc__statement__handler_8h_source.html#l00032">dbc_statement_handler.h:32</a></div></div>
</div><!-- fragment --><p>Register it in the dispatcher constructor:</p>
<div class="fragment"><div class="line">RegisterType&lt;MyCustomHandler&gt;(<span class="stringliteral">&quot;CUSTOM_&quot;</span>); <span class="comment">// after implementing MyCustomHandler</span></div>
</div><!-- fragment --><p>Registration creates one handler; replacing a registration replaces that instance. Register during initialization before dispatching. A line is routed using its full first whitespace-delimited keyword, so <code>BO_TX_BU_</code> cannot match <code>BO_</code>. Unregistered keywords produce <code>UnsupportedStatement</code> warnings through <code>ParseFileWithDiagnostics</code>. <code>SG_</code> and <code>CM_</code> accept spaces and tabs after their keywords.</p>
<p>This factory handles statements inside DBC files. A separate format-level factory can be introduced when another file format is implemented. The decoder and database builders remain independent of statement dispatch.</p>
<hr />
<h1><a class="anchor" id="autotoc_md115"></a>
Signal value descriptions (&lt;tt&gt;VAL_&lt;/tt&gt;)</h1>
<p>Signal descriptions attach text to exact raw integer values:</p>
<div class="fragment"><div class="line">BO_ 256 Status: 8 ECU</div>
<div class="line"> SG_ State : 0|8@1+ (1,0) [0|255] &quot;&quot; ECU</div>
<div class="line">VAL_ 256 State 0 &quot;Off&quot; 1 &quot;On&quot; 2 &quot;Error&quot;;</div>
</div><!-- fragment --><p>Each statement must occupy one physical line, contain at least one integer/text pair, and end with a semicolon. Spaces and tabs are accepted between fields; descriptions may contain whitespace, semicolons, and empty text. Inside quoted text, <code>\"&lt;/tt&gt; and &lt;tt&gt;\\\\&lt;/tt&gt; represent a quote and a backslash; other escapes are rejected.
Keys are decimal integers in &lt;tt&gt;INT64_MIN..UINT64_MAX&lt;/tt&gt;, with an optional minus
sign; plus signs, fractions, hexadecimal numbers, exponents, and overflow are
rejected. Keys never pass through &lt;tt&gt;double&lt;/tt&gt;.
&lt;tt&gt;VAL_&lt;/tt&gt; may appear before or after its frame and signal declarations. References
are resolved after reading the file using the same CAN ID normalization as
&lt;tt&gt;BO_&lt;/tt&gt;, including bit 31 for extended identifiers. Standard and extended frames
with the same normalized ID remain distinct. Missing or ambiguous references,
malformed statements, and duplicate integer keys produce &lt;tt&gt;path:line: description&lt;/tt&gt;
errors at the originating &lt;tt&gt;VAL_&lt;/tt&gt; line. Distinct keys from multiple statements
are merged; &lt;tt&gt;0&lt;/tt&gt;, &lt;tt&gt;00&lt;/tt&gt;, and &lt;tt&gt;-0&lt;/tt&gt; are the same key. Keys need not fit the referenced
signal's bit width or signedness; unreachable keys simply cannot match a decode.
Mappings are available as &lt;tt&gt;SignalInfo::valueDescriptions&lt;/tt&gt; and
&lt;tt&gt;DecodeSignal::valueDescriptions&lt;/tt&gt;, and survive both database builders, including
&lt;tt&gt;TreeNode::GetSignal()&lt;/tt&gt;. Consumers can look up a decoded result directly:
@icode{cpp}
const DecodedSignalValue &amp;value = decodedFrame.signals.at(0);
if (const std::string *description = value.GetValueDescription()) {
std::cout &lt;&lt; *description;
}
@endicode
&lt;tt&gt;GetValueDescription()&lt;/tt&gt; uses the exact raw integer before factor/offset scaling.
It returns &lt;tt&gt;nullptr&lt;/tt&gt; for an invalid decode or an unknown value; numeric decoding
and &lt;tt&gt;physicalValue&lt;/tt&gt; are unchanged. A mapped empty string returns a non-null
pointer. The pointer belongs to the signal definition and stays valid while that
definition remains alive. A decoded signal owns its immutable definition across reload.
For metadata or standalone raw values, use
&lt;tt&gt;FindValueDescription(signal.valueDescriptions, rawValue)&lt;/tt&gt;, where &lt;tt&gt;rawValue&lt;/tt&gt; is
&lt;tt&gt;RawSignalValue&lt;/tt&gt; (&lt;tt&gt;std::variant\&lt;std::int64_t, std::uint64_t\&gt;&lt;/tt&gt;). The helper matches
nonnegative signed and unsigned values identically and keeps negative values
distinct from large unsigned values. Stored keys use negative &lt;tt&gt;int64_t&lt;/tt&gt; and
nonnegative &lt;tt&gt;uint64_t&lt;/tt&gt;; when constructing mappings manually, normalize keys
with &lt;tt&gt;NormalizeValueKey()&lt;/tt&gt; before insertion.
Named &lt;tt&gt;VAL_TABLE_&lt;/tt&gt; tables, environment-variable mappings, multiline statements,
are outside this implementation; the optional Qt adapter exposes signal mappings.
&lt;hr&gt;
@section autotoc_md117 Current Limitations
This is still a minimal implementation.
Not supported yet:
- extended and nested multiplexing (&lt;tt&gt;SG_MUL_VAL_&lt;/tt&gt;, &lt;tt&gt;mNM&lt;/tt&gt;)
- named &lt;tt&gt;VAL_TABLE_&lt;/tt&gt; tables and environment-variable value descriptions
- &lt;tt&gt;BA_&lt;/tt&gt; attributes
- &lt;tt&gt;BA_DEF_&lt;/tt&gt; definitions and attribute defaults
- &lt;tt&gt;SIG_VALTYPE_&lt;/tt&gt; floating-point signal types
- signal types/references (&lt;tt&gt;SGTYPE_&lt;/tt&gt;, &lt;tt&gt;SIG_TYPE_REF_&lt;/tt&gt;) and environment variables
- advanced comment handling
- full DBC grammar coverage
- full J1939 validation
- extensive edge-case handling for unusual DBC formatting
Additional behavior to account for:
- unregistered DBC keywords are skipped with warnings in the diagnostic API
- an &lt;tt&gt;SG_&lt;/tt&gt; statement before the first frame is rejected
- duplicate frame keys (normalized CAN ID and frame type) and repeated signal
names within a frame are rejected at their definition lines; manually created
databases are also checked for ambiguous &lt;tt&gt;VAL_&lt;/tt&gt; references during resolution
- payload lengths are checked against storage bounds (&lt;tt&gt;0..255&lt;/tt&gt;), rather than
CAN or CAN FD protocol limits
- comment handling is limited to the supported forms and already parsed targets
Motorola extraction uses DBC sawtooth numbering: a start bit of 7 traverses
&lt;tt&gt;7..0, 15..8, 23..16&lt;/tt&gt;. Regression tests cover aligned and unaligned signals,
byte boundaries, and 64-bit values.
&lt;hr&gt;
@section autotoc_md119 Recommended Next Steps
A practical development order would be:
@subsection autotoc_md120 Stage 1 - already implemented
- &lt;tt&gt;BO_&lt;/tt&gt;
- &lt;tt&gt;SG_&lt;/tt&gt;
- &lt;tt&gt;CM_&lt;/tt&gt;
- &lt;tt&gt;VAL_&lt;/tt&gt; signal value descriptions
- normalized CAN ID
- &lt;tt&gt;isExtended&lt;/tt&gt;
- transmitter
- receivers
- comments
- tree representation
- runtime decode database
- runtime decoder
@subsection autotoc_md121 Stage 2
Recommended additions:
- selective decoding of only chosen signals
@subsection autotoc_md122 Stage 3
Recommended additions:
- basic multiplexing (implemented)
- attribute parsing
- richer J1939 support
- CSV export of decoded traces
- optimized filtering and signal selection
@subsection autotoc_md123 Stage 4
Advanced functionality:
- live plot integration
- signal subscriptions
- per-signal trace decode pipelines
- decoder-assisted export formats
&lt;hr&gt;
@section autotoc_md125 Build Integration
The repository supplies qmake projects. A C++17 compiler is required; the root
build also requires Qt Core and Qt Test development packages. Other build
systems can compile the sources listed in &lt;tt&gt;core/core_files.pri&lt;/tt&gt;; no CMake
configuration is currently provided.
Qt-dependent qmake targets share &lt;tt&gt;qt/qt_version.pri&lt;/tt&gt;, which rejects Qt versions
other than 6.8.2. The core library remains independent of Qt libraries.
Open &lt;tt&gt;dbc.pro&lt;/tt&gt; in Qt Creator to see two subprojects: &lt;tt&gt;core&lt;/tt&gt; and &lt;tt&gt;tests&lt;/tt&gt;.
&lt;tt&gt;core/core.pro&lt;/tt&gt; builds the C++17 static library &lt;tt&gt;dbc_core&lt;/tt&gt; without a Qt dependency.
&lt;tt&gt;tests/tests.pro&lt;/tt&gt; builds the QtTest executable &lt;tt&gt;dbc_tests&lt;/tt&gt; and links that library.
The root project declares &lt;tt&gt;tests.depends = core&lt;/tt&gt; for parallel builds.
Build out of source with Qt 6.8.2:
@icode{sh}
mkdir build
cd build
qmake6 ../dbc.pro
make -j
make check
@endicode
&lt;tt&gt;core/core_files.pri&lt;/tt&gt; lists the library sources and headers.
Consumers include &lt;tt&gt;core/core.pri&lt;/tt&gt; for include paths and library linkage; the test
source lists live in &lt;tt&gt;tests/parser_tests.pri&lt;/tt&gt; and &lt;tt&gt;tests/decoder_tests.pri&lt;/tt&gt;.
When building a consumer separately, pass
&lt;tt&gt;DBC_CORE_BUILD_DIR=/absolute/path/to/build/core&lt;/tt&gt; to qmake.
@subsection autotoc_md126 Build core without Qt libraries
From the repository root:
@icode{sh}
mkdir -p build/core
cd build/core
qmake6 ../../core/core.pro
make -j
@endicode
qmake is still the build tool; this target does not link Qt libraries.
@subsection autotoc_md127 Optional Qt model adapter
The adapter and its &lt;tt&gt;QAbstractItemModelTester&lt;/tt&gt; suite use Qt 6.8.2.
The adapter itself links only Qt Core.
The model test executable additionally links QtGui and uses QGuiApplication so
QAbstractItemModelTester can resolve graphical metatypes such as QPixmap. It
defaults to the &lt;tt&gt;offscreen&lt;/tt&gt; platform when &lt;tt&gt;QT_QPA_PLATFORM&lt;/tt&gt; is unset or empty;
no display server is required. An explicit platform setting is preserved.
Enable its library and focused QtTest suite:
@icode{sh}
mkdir -p build-qt
cd build-qt
qmake6 ../dbc.pro CONFIG+=dbc_qt
make -j
make check
@endicode
Consumers include &lt;tt&gt;qt/qt.pri&lt;/tt&gt; instead of &lt;tt&gt;core/core.pri&lt;/tt&gt;, and set
&lt;tt&gt;DBC_CORE_BUILD_DIR&lt;/tt&gt; and &lt;tt&gt;DBC_QT_BUILD_DIR&lt;/tt&gt; to the corresponding library build
directories when building separately. A widget application also needs &lt;tt&gt;QT += widgets&lt;/tt&gt;. The adapter integration enables
&lt;tt&gt;no_keywords&lt;/tt&gt;, because core metadata has a &lt;tt&gt;signals&lt;/tt&gt; member; use &lt;tt&gt;Q_SIGNALS&lt;/tt&gt;,
&lt;tt&gt;Q_SLOTS&lt;/tt&gt;, and &lt;tt&gt;Q_EMIT&lt;/tt&gt; in consuming Qt classes.
@icode{cpp}
#include "<a class="el" href="dbc__parser_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">dbc_parser.h</a>"
#include "<a class="el" href="dbc__tree__builder_8h.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">dbc_tree_builder.h</a>"
#include "<a class="el" href="dbc__tree__model_8h_source.html">dbc_tree_model.h</a>"
#include &lt;QTreeView&gt;
// Run after constructing QApplication; view owns the model through QObject.
QTreeView view;
DbcTreeModel *model = new DbcTreeModel(&amp;view);
model-&gt;SetTree(DbcTreeBuilder().Build(DbcParser().ParseFile("example.dbc")));
view.setModel(model);
view.expandAll();
view.show();
// On reload, pass a newly built tree to SetTree(); to clear:
// model-&gt;SetTree(nullptr);
@endicode
The root is invisible: frames are top-level rows, signals are their children.
Only column zero has children. &lt;tt&gt;parent()&lt;/tt&gt; always returns column zero.
The model takes exclusive ownership of the tree; do not retain mutable aliases.
Metadata is copied by the tree builder, so the parsed database may be destroyed.
&lt;tt&gt;TreeNode::GetParent()&lt;/tt&gt; is non-owning and &lt;tt&gt;GetRow()&lt;/tt&gt; gives the zero-based sibling
position (zero for a detached node/root). Nodes cannot be copied or moved;
transferring their &lt;tt&gt;unique_ptr&lt;/tt&gt; ownership preserves addresses and navigation.
Call &lt;tt&gt;SetTree()&lt;/tt&gt; on the model's thread. It accepts a detached Root or nullptr,
uses &lt;tt&gt;beginResetModel()&lt;/tt&gt;/&lt;tt&gt;endResetModel()&lt;/tt&gt;, and destroys the previous tree during
reset. All ordinary QModelIndex values expire on reset and must not be reused;
QPersistentModelIndex values are invalidated by Qt. Destroying the model also
invalidates indexes. Invalid and foreign indexes return no data/flags/children.
Valid items are enabled and selectable, with no editing support.
&lt;table class="markdownTable"&gt;
&lt;tr class="markdownTableHead"&gt; &lt;th class="markdownTableHeadNone"&gt; Column (zero-based enum) </code></p>
<p><code> Frame display </code></p>
<p><code> Signal display </code></p>
<p><code> </code></p>
<p><code> 0 <code>Name</code> </code></p>
<p><code> Name </code></p>
<p><code> Name </code></p>
<p><code> </code></p>
<p><code> 1 <code>CanId</code> </code></p>
<p><code> Normalized hexadecimal ID </code></p>
<p><code> Empty </code></p>
<p><code> </code></p>
<p><code> 2 <code>PayloadLength</code> </code></p>
<p><code> Bytes </code></p>
<p><code> Empty </code></p>
<p><code> </code></p>
<p><code> 3 <code>StartBit</code> </code></p>
<p><code> Empty </code></p>
<p><code> DBC start bit </code></p>
<p><code> </code></p>
<p><code> 4 <code>BitLength</code> </code></p>
<p><code> Empty </code></p>
<p><code> Bit count </code></p>
<p><code> </code></p>
<p><code> 5 <code>ByteOrder</code> </code></p>
<p><code> Empty </code></p>
<p><code> Intel / Motorola </code></p>
<p><code> </code></p>
<p><code> 6 <code>Signed</code> </code></p>
<p><code> Empty </code></p>
<p><code> Signed / Unsigned </code></p>
<p><code> </code></p>
<p><code> 7 <code>Unit</code> </code></p>
<p><code> Empty </code></p>
<p><code> Unit </code></p>
<p><code> </code></p>
<p><code> 8 <code>Comment</code> </code></p>
<p><code> Comment </code></p>
<p><code> Comment </code></p>
<p><code></code></p>
<p><code>Horizontal DisplayRole headers describe these columns; other header requests return invalid QVariant. ToolTipRole returns the comment on every column. Custom roles also apply on every column; inapplicable roles return invalid QVariant:</code></p>
<p><code></p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Role </th><th class="markdownTableHeadNone">Node types </th><th class="markdownTableHeadNone">QVariant content </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>NodeTypeRole</code> </td><td class="markdownTableBodyNone">Frame, signal </td><td class="markdownTableBodyNone">int corresponding to NodeType </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>CanIdRole</code>, <code>PayloadLengthRole</code>, <code>ExtendedRole</code> </td><td class="markdownTableBodyNone">Frame </td><td class="markdownTableBodyNone">uint, int, bool </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>StartBitRole</code>, <code>BitLengthRole</code> </td><td class="markdownTableBodyNone">Signal </td><td class="markdownTableBodyNone">uint </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>LittleEndianRole</code>, <code>SignedRole</code> </td><td class="markdownTableBodyNone">Signal </td><td class="markdownTableBodyNone">bool </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>UnitRole</code> </td><td class="markdownTableBodyNone">Signal </td><td class="markdownTableBodyNone">QString </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>CommentRole</code> </td><td class="markdownTableBodyNone">Frame, signal </td><td class="markdownTableBodyNone">QString </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>ValueDescriptionsRole</code> </td><td class="markdownTableBodyNone">Signal </td><td class="markdownTableBodyNone">QVariantList of QVariantMap entries </td></tr>
</table>
<p></code></p>
<p><code>Each value-description entry contains <code>value</code> (qlonglong for negative keys, qulonglong for nonnegative keys) and <code>description</code> (QString). This preserves the full signed/unsigned 64-bit range without converting through double. An unmapped signal returns an empty list. Data comes from <code><a class="el" href="structSignalInfo.html#a43f47d0433d0cc39076bd7278b46af9c">SignalInfo::valueDescriptions</a></code>. Unsupported roles return invalid QVariant.</code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md128"></a>
Standalone tree tests without Qt</h2>
<p><code></code></p>
<p><code>From the repository root, use only a C++17 compiler:</code></p>
<p><code></p><div class="fragment"><div class="line">c++ -std=c++17 -Icore tests/tree_node_test.cpp core/tree_node.cpp \</div>
<div class="line"> core/dbc_tree_builder.cpp -o /tmp/dbc_tree_node_test</div>
<div class="line">/tmp/dbc_tree_node_test</div>
</div><!-- fragment --><p></code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md129"></a>
Build and run the demo</h2>
<p><code></code></p>
<p><code>After building core, run these commands from the repository root:</code></p>
<p><code></p><div class="fragment"><div class="line">mkdir -p build/examples</div>
<div class="line">cd build/examples</div>
<div class="line">qmake6 ../../examples/demo.pro DBC_CORE_BUILD_DIR=../core</div>
<div class="line">make -j</div>
<div class="line">./dbc_demo /absolute/path/to/example.dbc</div>
</div><!-- fragment --><p></code></p>
<p><code>The demo prints the parsed tree and decodes eight zero bytes using the first frame definition. Replace that sample payload in <code><a class="el" href="examples_2main_8cpp.html" title="Created: 2026-03-13 Author: Deeaitch (Dim. Himro)">examples/main.cpp</a></code> to feed live CAN data or trace records.</code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md130"></a>
Generate API documentation</h2>
<p><code></code></p>
<p><code>With Doxygen installed, run from the repository root:</code></p>
<p><code></p><div class="fragment"><div class="line">doxygen Doxyfile</div>
</div><!-- fragment --><p></code></p>
<p><code>Open <code>docs/html/index.html</code> to view the generated reference.</code></p>
<p><code></p><hr />
<p></code></p>
<p><code></code></p>
<h1><a class="anchor" id="autotoc_md132"></a>
Regression tests</h1>
<p><code></code></p>
<p><code>See <a class="el" href="md_tests_2README.html">tests/README.md</a> for QtTest build and execution commands. Tests cover frame validation and error locations, Intel and Motorola extraction, signal syntax and payload bounds, <code>VAL_</code> syntax and reference validation, raw description lookup and preservation through both builders, statement dispatch, signed and unsigned 64-bit boundaries, physical conversion, numeric output, and invalid signal payloads.</code></p>
<p><code></code></p>
<h1><a class="anchor" id="autotoc_md133"></a>
Measuring code coverage</h1>
<p><code></code></p>
<p><code>Coverage instrumentation is separate from the QtTest suite named <code>CoverageTest</code>: that suite runs extra regression checks, but coverage counters require a specially instrumented build. Use a separate build directory for each coverage tool.</code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md134"></a>
GCC, gcov, and LCOV on Debian/Ubuntu</h2>
<p><code></code></p>
<p><code>Install the build and report tools:</code></p>
<p><code></p><div class="fragment"><div class="line">sudo apt install build-essential qt6-base-dev qt6-base-dev-tools qmake6 lcov</div>
<div class="line"># Optional IDE:</div>
<div class="line">sudo apt install qtcreator</div>
</div><!-- fragment --><p></code></p>
<p><code>GCC supplies <code>gcov</code>; the <code>lcov</code> package supplies <code>lcov</code> and <code>genhtml</code>. Use the <code>gcov</code> version matching the GCC used by the selected Qt Creator kit. These instructions use GCC and Qt 6.8.2.</code></p>
<p><code>From the repository root, create a fresh coverage build. <code>--coverage</code> must be passed to both compilation and linking; Debug avoids optimization that can make source-level results harder to interpret. <code>-fprofile-abs-path</code> makes source paths in the coverage data independent of the compilation working directory.</code></p>
<p><code></p><div class="fragment"><div class="line">DBC_SOURCE_DIR=&quot;$(pwd)&quot;</div>
<div class="line">mkdir -p build-coverage</div>
<div class="line">cd build-coverage</div>
<div class="line"> </div>
<div class="line">qmake6 &quot;$DBC_SOURCE_DIR/dbc.pro&quot; \</div>
<div class="line"> CONFIG+=dbc_qt CONFIG+=debug CONFIG-=release \</div>
<div class="line"> &#39;QMAKE_CXXFLAGS+=--coverage -fprofile-abs-path&#39; \</div>
<div class="line"> &#39;QMAKE_LFLAGS+=--coverage&#39;</div>
<div class="line">make -j4</div>
<div class="line"> </div>
<div class="line"># The standalone tree test is not a qmake target; instrument it separately.</div>
<div class="line">mkdir -p standalone</div>
<div class="line">c++ -std=c++17 -O0 -g --coverage -fprofile-abs-path \</div>
<div class="line"> -I&quot;$DBC_SOURCE_DIR/core&quot; \</div>
<div class="line"> &quot;$DBC_SOURCE_DIR/tests/tree_node_test.cpp&quot; \</div>
<div class="line"> &quot;$DBC_SOURCE_DIR/core/tree_node.cpp&quot; \</div>
<div class="line"> &quot;$DBC_SOURCE_DIR/core/dbc_tree_builder.cpp&quot; \</div>
<div class="line"> -o standalone/tree_node_tests</div>
<div class="line"> </div>
<div class="line"># Capture a zero-count baseline so unexecuted compiled code remains in the report.</div>
<div class="line">lcov --capture --initial --directory . --branch-coverage \</div>
<div class="line"> --include &quot;$DBC_SOURCE_DIR/core/*&quot; --include &quot;$DBC_SOURCE_DIR/qt/*&quot; \</div>
<div class="line"> --output-file baseline.info</div>
<div class="line"> </div>
<div class="line"># Reset counts before each new measurement; otherwise executions accumulate.</div>
<div class="line">lcov --zerocounters --directory .</div>
<div class="line">make check</div>
<div class="line">./standalone/tree_node_tests</div>
<div class="line"> </div>
<div class="line">lcov --capture --directory . --branch-coverage \</div>
<div class="line"> --include &quot;$DBC_SOURCE_DIR/core/*&quot; --include &quot;$DBC_SOURCE_DIR/qt/*&quot; \</div>
<div class="line"> --output-file executed.info</div>
<div class="line">lcov --add-tracefile baseline.info --add-tracefile executed.info \</div>
<div class="line"> --branch-coverage --output-file coverage.info</div>
<div class="line"> </div>
<div class="line">genhtml coverage.info --branch-coverage --demangle-cpp --output-directory html</div>
<div class="line">lcov --summary coverage.info --branch-coverage</div>
</div><!-- fragment --><p></code></p>
<p><code>Open <code>build-coverage/html/index.html</code> in a browser. The report includes the library's <code>core/</code> and <code>qt/</code> sources and instantiated header code; test sources, generated moc files, and Qt/STL headers are excluded. Click a filename to inspect execution counts, uncovered lines, and branch outcomes. Branch coverage is a separate metric: executing a line does not necessarily exercise every outcome. C++ branch data can also include compiler-generated exception paths.</code></p>
<p><code>For another run with unchanged sources, repeat the reset, test execution, capture, merge, and HTML generation steps. After changing sources or compiler flags, rebuild and regenerate <code>baseline.info</code> before measuring again. A fresh build directory avoids mixing old profiling data with a different build.</code></p>
<p><code>An initial measurement with GCC 14.2 and Qt 6.8.2 on 2026-10-07, including both QtTest executables and the standalone tree test, yielded 97.8% line coverage (724/740) and 70.7% branch coverage (833/1178). These are a snapshot, not fixed expected values for later changes or other toolchains.</code></p>
<p><code>After adding direct comment-handler and ambiguous <code>VAL_</code> reference tests, the same configuration measured 98.4% line coverage (728/740) and 71.4% branch coverage (841/1178).</code></p>
<p><code>See <a href="https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html">GCC instrumentation options</a> and the <a href="https://github.com/linux-test-project/lcov">LCOV project documentation</a>.</code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md135"></a>
Configure the GCC coverage build in Qt Creator</h2>
<p><code></code></p>
<p><code></p><ol type="1">
<li>Open <code>dbc.pro</code> and select a GCC kit with Qt 6.8.2.</li>
<li>In <b>Projects &gt; Build Settings</b>, clone <b>Debug</b> as <b>Coverage</b>.</li>
<li>Choose a separate build directory, such as <code>build-coverage</code>.</li>
<li><p class="startli">Expand the <b>qmake</b> build step and add these <b>Additional arguments</b>:</p>
<div class="fragment"><div class="line">CONFIG+=dbc_qt CONFIG+=debug CONFIG-=release &quot;QMAKE_CXXFLAGS+=--coverage -fprofile-abs-path&quot; &quot;QMAKE_LFLAGS+=--coverage&quot;</div>
</div><!-- fragment --></li>
<li>Run qmake and build the project. Both <code>dbc_tests</code> and <code>dbc_model_tests</code> must run to include coverage from the core and optional model adapter.</li>
<li>In a terminal in the coverage build directory, compile the standalone test and run the LCOV/report commands above. Set <code>DBC_SOURCE_DIR</code> to the absolute repository path if using a new terminal. <code>make check</code> runs both QtTest executables; the standalone tree executable must be run separately.</li>
<li>View <code>html/index.html</code> in a browser. This workflow produces HTML reports; it does not require a licensed coverage toolchain.</li>
</ol>
<p></code></p>
<p><code></code></p>
<h2><a class="anchor" id="autotoc_md136"></a>
Configure all build variants in Qt Creator</h2>
<p><code></code></p>
<p><code>The local <code>dbc.pro.user</code> stores machine-specific kit IDs and build/run settings. It is ignored by Git (<code>*.user</code>) and should not be committed or copied between machines. Recreate the configurations below through the UI when setting up a new checkout. The <code>Qt4ProjectManager</code> identifiers inside <code>.user</code> are historical Qt Creator setting names; the project still requires Qt 6.8.2.</code></p>
<p><code>The local configuration set uses these independent build directories:</code></p>
<p><code></p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Configuration </th><th class="markdownTableHeadNone">Build directory example </th><th class="markdownTableHeadNone">Purpose </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Debug </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Debug</code> </td><td class="markdownTableBodyNone">Core library and parser/decoder/coverage regression tests </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Release </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Release</code> </td><td class="markdownTableBodyNone">The same targets with release settings </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Profile </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Profile</code> </td><td class="markdownTableBodyNone">Existing Qt Creator profiling configuration; not code coverage </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Debug Qt Models </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Debug-Qt-Models</code> </td><td class="markdownTableBodyNone">Debug targets plus optional adapter and model tests </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Release Qt Models </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Release-Qt-Models</code> </td><td class="markdownTableBodyNone">Release targets plus optional adapter and model tests </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Debug Qt Models Strict </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Debug-Qt-Models-Strict</code> </td><td class="markdownTableBodyNone">Model build with <code>QT_FATAL_WARNINGS=1</code> for builds and runs </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Coverage </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Coverage</code> </td><td class="markdownTableBodyNone">Instrumented core/model build, test execution, and LCOV HTML report </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Core Only </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Core-Only</code> </td><td class="markdownTableBodyNone">The Qt-free core static library </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Tree Tests </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Tree-Tests</code> </td><td class="markdownTableBodyNone">Standalone C++17 tree test without Qt </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Demo </td><td class="markdownTableBodyNone"><code>/tmp/build/dbc/Desktop-Demo</code> </td><td class="markdownTableBodyNone">Core library and command-line demo </td></tr>
</table>
<p></code></p>
<p><code>The temporary paths are examples; choose permanent build directories if desired. Do not share a build directory between these configurations.</code></p>
<p><code>To add the ordinary qmake configurations:</code></p>
<p><code></p><ol type="1">
<li>Open <code>dbc.pro</code> with a GCC/Qt 6.8.2 kit.</li>
<li>Go to <b>Projects &gt; Build Settings</b>. Keep the existing Debug, Release, and Profile configurations. Remove or disable a Coco build step if one remains.</li>
<li>Select Debug, press <b>Clone</b>, and name the clone <b>Debug Qt Models</b>. Set its build directory from the table and add <code>CONFIG+=dbc_qt</code> to the qmake step's <b>Additional arguments</b>.</li>
<li>Clone Release as <b>Release Qt Models</b> with the same qmake argument and its own build directory.</li>
<li>Clone Debug Qt Models as <b>Debug Qt Models Strict</b>. In <b>Build Environment</b>, add <code>QT_FATAL_WARNINGS=1</code>. Run configurations should use the build environment.</li>
<li><p class="startli">Clone Debug Qt Models as <b>Coverage</b>. In qmake <b>Additional arguments</b>, use:</p>
<div class="fragment"><div class="line">CONFIG+=dbc_qt CONFIG+=debug CONFIG-=release &quot;QMAKE_CXXFLAGS+=--coverage -fprofile-abs-path&quot; &quot;QMAKE_LFLAGS+=--coverage&quot;</div>
</div><!-- fragment --></li>
<li>For Coverage, select <b>Add Build Step &gt; Custom Process Step</b> after qmake and Make, then set:</li>
</ol>
<p></code></p>
<p><code></p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Field </th><th class="markdownTableHeadNone">Value </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Command </td><td class="markdownTableBodyNone"><code>/bin/sh</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">Arguments </td><td class="markdownTableBodyNone"><code>"%{sourceDir}/tests/coverage_report.sh" "%{sourceDir}" "%{buildDir}"</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">Working directory </td><td class="markdownTableBodyNone"><code>%{buildDir}</code> </td></tr>
</table>
<p></code></p>
<p><code> This script compiles the standalone tree test, resets counters, runs both QtTest executables and the tree test, and generates <code>%{buildDir}/html/index.html</code>. It stops if any test fails. Therefore building Coverage also executes tests. <code>lcov</code> and <code>genhtml</code> must be installed. Use this configuration with the GCC kit; <code>gcov</code> and the compiler used for the standalone test must match that kit.</p><ol type="1">
<li>Run qmake and build each new configuration once. The default root builds expose <code>dbc_tests</code>; model configurations also expose <code>dbc_model_tests</code>.</li>
</ol>
<p></code></p>
<p><code>Qt Creator expands <code>%{sourceDir}</code> and <code>%{buildDir}</code> in custom steps to the source and active build directories. Use the field's variable chooser if needed.</code></p>
<p><code>For the three independent builds, clone Debug, assign the name and build directory from the table, and replace its qmake/Make build steps with the custom process steps below. These steps are local IDE settings and do not change <code>dbc.pro</code>. Give each step a descriptive name and retain the listed order.</code></p>
<p><code>For <b>Core Only</b>:</code></p>
<p><code></p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Command </th><th class="markdownTableHeadNone">Arguments </th><th class="markdownTableHeadNone">Working directory </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>/usr/bin/mkdir</code> </td><td class="markdownTableBodyNone"><code>-p "%{buildDir}"</code> </td><td class="markdownTableBodyNone"><code>%{sourceDir}</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>/usr/bin/qmake6</code> </td><td class="markdownTableBodyNone"><code>"%{sourceDir}/core/core.pro" CONFIG+=debug CONFIG-=release</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>/usr/bin/make</code> </td><td class="markdownTableBodyNone"><code>-j4</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}</code> </td></tr>
</table>
<p></code></p>
<p><code>Keep a clean step with <code>make clean</code> in <code>%{buildDir}</code>. Core Only creates a static library, so there is no executable to run.</code></p>
<p><code>For <b>Tree Tests</b>:</code></p>
<p><code></p><ol type="1">
<li>Add a custom step with command <code>/usr/bin/mkdir</code>, arguments <code>-p "%{buildDir}"</code>, and working directory <code>%{sourceDir}</code>.</li>
<li><p class="startli">Add a custom step with command <code>/usr/bin/c++</code>, working directory <code>%{buildDir}</code>, and these arguments:</p>
<div class="fragment"><div class="line">-std=c++17 -O0 -g -I&quot;%{sourceDir}/core&quot; &quot;%{sourceDir}/tests/tree_node_test.cpp&quot; &quot;%{sourceDir}/core/tree_node.cpp&quot; &quot;%{sourceDir}/core/dbc_tree_builder.cpp&quot; -o &quot;%{buildDir}/tree_node_tests&quot;</div>
</div><!-- fragment --></li>
<li>Remove the default Make clean step: this direct compiler build creates no Makefile. Run the resulting executable as described below.</li>
</ol>
<p></code></p>
<p><code>For <b>Demo</b>:</code></p>
<p><code></p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Command </th><th class="markdownTableHeadNone">Arguments </th><th class="markdownTableHeadNone">Working directory </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>/usr/bin/mkdir</code> </td><td class="markdownTableBodyNone"><code>-p "%{buildDir}/core" "%{buildDir}/examples"</code> </td><td class="markdownTableBodyNone"><code>%{sourceDir}</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>/usr/bin/qmake6</code> </td><td class="markdownTableBodyNone"><code>"%{sourceDir}/core/core.pro" CONFIG+=debug CONFIG-=release</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}/core</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>/usr/bin/make</code> </td><td class="markdownTableBodyNone"><code>-j4</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}/core</code> </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>/usr/bin/qmake6</code> </td><td class="markdownTableBodyNone"><code>"%{sourceDir}/examples/demo.pro" "DBC_CORE_BUILD_DIR=%{buildDir}/core" CONFIG+=debug CONFIG-=release</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}/examples</code> </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>/usr/bin/make</code> </td><td class="markdownTableBodyNone"><code>-j4</code> </td><td class="markdownTableBodyNone"><code>%{buildDir}/examples</code> </td></tr>
</table>
<p></code></p>
<p><code>Replace the default clean step with two custom steps: <code>/usr/bin/make</code> with arguments <code>clean</code>, first in <code>%{buildDir}/examples</code>, then in <code>%{buildDir}/core</code>.</code></p>
<p><code>To configure execution and switch variants:</code></p>
<p><code></p><ol type="1">
<li>Go to <b>Projects &gt; Run Settings</b> and select the appropriate qmake target: <code>dbc_tests</code> for ordinary builds or <code>dbc_model_tests</code> for model builds.</li>
<li>To run all QtTest suites together, add a <b>Custom Executable</b> named <b>All QtTest suites</b>, with executable <code>/usr/bin/make</code>, arguments <code>check</code>, and working directory <code>%{buildDir}</code>. Use it with an ordinary or model qmake configuration. Coverage already runs every test in its final build step.</li>
<li>For Tree Tests, add a <b>Custom Executable</b> named <b>Standalone tree test</b>, executable <code>%{buildDir}/tree_node_tests</code>, working directory <code>%{buildDir}</code>, and no arguments.</li>
<li>For Demo, add a <b>Custom Executable</b> named <b>Demo</b>, executable <code>%{buildDir}/examples/dbc_demo</code>, working directory <code>%{buildDir}/examples</code>. Set <b>Command line arguments</b> to the quoted absolute path of your DBC file.</li>
<li>For Coverage on Linux, optionally add a <b>Custom Executable</b> named <b>Coverage HTML report</b>, executable <code>/usr/bin/xdg-open</code>, arguments <code>"%{buildDir}/html/index.html"</code>, working directory <code>%{buildDir}</code>. Running it opens the generated report in the default browser.</li>
<li>Use the kit/build/run selector above the Run button to choose the build configuration and its corresponding executable. Build with <b>Ctrl+B</b>, then run with <b>Ctrl+R</b>. The Build Settings configuration list can also switch the active build.</li>
<li>If <code>.user</code> was edited externally, close and reopen the project so Qt Creator reads the new settings. Do not edit it while the project is open, because Qt Creator can overwrite external changes when saving its session.</li>
</ol>
<p></code></p>
<p><code>See Qt Creator's <a href="https://doc.qt.io/qtcreator/creator-build-settings.html">build configuration guide</a> and <a href="https://doc.qt.io/qtcreator/creator-run-settings.html">run configuration guide</a>. </code></p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.8 </li>
</ul>
</div>
</body>
</html>