diff --git a/docs/dbcframework.tag b/docs/dbcframework.tag index 35341d2..26b0486 100644 --- a/docs/dbcframework.tag +++ b/docs/dbcframework.tag @@ -448,6 +448,18 @@ (const std::string &line, DbcParseContext &context) const override + + DbcMultiplexingHandler + classDbcMultiplexingHandler.html + DbcStatementHandler + + void + Handle + classDbcMultiplexingHandler.html + a16f9e9f898640200477d2dcc8bab442e + (const std::string &line, DbcParseContext &context) const override + + DbcParseContext structDbcParseContext.html @@ -737,18 +749,6 @@ (const QModelIndex &index) const override - - DbcUnsupportedMultiplexingHandler - classDbcUnsupportedMultiplexingHandler.html - DbcStatementHandler - - void - Handle - classDbcUnsupportedMultiplexingHandler.html - a9853fd67465f92ef587792986ea179ac - (const std::string &line, DbcParseContext &context) const override - - DbcValueDescriptionHandler classDbcValueDescriptionHandler.html @@ -1227,16 +1227,17 @@ (const FrameKey &key) const + + dbc_detail::MultiplexError + classdbc__detail_1_1MultiplexError.html + + + dbc_detail::MultiplexGraph + classdbc__detail_1_1MultiplexGraph.html + Multiplexing structMultiplexing.html - - MultiplexRole - role - structMultiplexing.html - a62b70a0e3f2a9c7a457b3694ce8625c3 - - std::uint64_t value @@ -1244,6 +1245,24 @@ a79158d4fdbfd68a3d51a8ce79d34fd67 + + std::string + selector + structMultiplexing.html + aa91e54403c78a663686b2fd22282afaf + + + + std::vector< MultiplexRange > + ranges + structMultiplexing.html + aa174ac4a3af9b361d2de7517dfd4b69e + + + + + MultiplexRange + structMultiplexRange.html PendingAttribute @@ -1309,6 +1328,10 @@ + + PendingMultiplexing + structPendingMultiplexing.html + PendingValueDescriptions structPendingValueDescriptions.html diff --git a/docs/doxygen_warnings.log b/docs/doxygen_warnings.log index b9ec174..3f831df 100644 --- a/docs/doxygen_warnings.log +++ b/docs/doxygen_warnings.log @@ -1 +1,19 @@ +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:68: warning: Member ResolveMultiplexing(const std::string &filePath) (function) of struct DbcParseContext is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:67: warning: Member pendingMultiplexing (variable) of struct DbcParseContext is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplexing.h:25: warning: Member role (variable) of struct Multiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplexing.h:19: warning: Member minimum (variable) of struct MultiplexRange is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplexing.h:20: warning: Member maximum (variable) of struct MultiplexRange is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:51: warning: Member canId (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:52: warning: Member isExtended (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:53: warning: Member signalName (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:54: warning: Member selectorName (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:55: warning: Member ranges (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:56: warning: Member lineNumber (variable) of struct PendingMultiplexing is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:13: warning: Member MultiplexError(std::size_t signalIndex, const std::string &message) (function) of class dbc_detail::MultiplexError is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:15: warning: Member index (variable) of class dbc_detail::MultiplexError is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:22: warning: Member MultiplexGraph(const std::vector< Signal > &public) (function) of class dbc_detail::MultiplexGraph is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:69: warning: Member Matches(std::size_t index, std::uint64_t value) const (function) of class dbc_detail::MultiplexGraph is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:77: warning: Member AreMutuallyExclusive(std::size_t first, std::size_t second) const (function) of class dbc_detail::MultiplexGraph is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:97: warning: Member parents (variable) of class dbc_detail::MultiplexGraph is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/multiplex_graph.h:98: warning: Member ranges (variable) of class dbc_detail::MultiplexGraph is not documented. error: failed to run qhelpgenerator on index.qhp diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 9e94d24..124636a 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -94,48 +94,53 @@ $(document).ready(function(){initNavTree('annotated.html',''); initResizable();
Here are the classes, structs, unions and interfaces with brief descriptions:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
[detail level 12]
 CAttributeAssignmentExplicit assignment; defaults remain on definitions
 CAttributeDefinitionAttribute type, permitted range, and optional default
 CDbcAttributeHandlerDefer typed attribute statements for resolution
 CDbcCommentHandlerDefer frame and signal comments for target resolution
 CDbcDatabaseParsed DBC content stored in a simple internal form
 CDbcDecodeBuilderConverts parsed DBC data into runtime decode database
 CDbcDecoderRuntime CAN decoder using prebuilt decode database
 CDbcDiagnosticDiagnostic message and physical source location
 CDbcDiagnosticError
 CDbcFrameHandlerParse and append frame definitions
 CDbcHeaderHandler
 CDbcParseContext
 CDbcParserMinimal DBC parser
 CDbcParseResultParsed database and diagnostics; the database is empty on error
 CDbcParserOptions
 CDbcSignalHandlerParse and append signals to the current frame
 CDbcStatementDispatcher
 CDbcStatementHandlerInterface for processing a registered DBC statement
 CDbcTreeBuilderBuilds a simple tree from parsed DBC database
 CDbcTreeModel
 CDbcUnsupportedMultiplexingHandlerReject unsupported extended multiplexing statements
 CDbcValueDescriptionHandlerDefer raw value descriptions for target resolution
 CDecodeDatabaseImmutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles and decoded results keep old definitions alive
 CDecodedFrameValueFully decoded frame
 CDecodedSignalValueOne decoded signal value
 CDecodeFrameRuntime-ready frame definition
 CDecodeSignalRuntime-ready signal definition
 CFrameInfoDescribes one CAN frame from a DBC file
 CFrameKeyStable frame identifier: normalized CAN ID and frame type
 CFrameKeyHasherHasher for frame key
 CMultiplexing
 CPendingAttributeAttribute statement retained for ordered resolution
 CPendingCommentDeferred frame or signal comment and its source location
 CPendingValueDescriptionsDeferred raw value descriptions and their target
 CPgnLookupResult
 CRawCanFrameRaw CAN frame used for runtime or trace decoding
 CSignalInfoDescribes one signal inside a DBC frame
 CSignalKey
 CSignalKeyHasherHasher for stable signal keys
 CTreeNodeTree node for later use in model/view or other hierarchy consumers
 CTypeFactoryRegistry-based factory for creating objects by runtime identifier
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 ▼Ndbc_detail
 CMultiplexError
 CMultiplexGraph
 CAttributeAssignmentExplicit assignment; defaults remain on definitions
 CAttributeDefinitionAttribute type, permitted range, and optional default
 CDbcAttributeHandlerDefer typed attribute statements for resolution
 CDbcCommentHandlerDefer frame and signal comments for target resolution
 CDbcDatabaseParsed DBC content stored in a simple internal form
 CDbcDecodeBuilderConverts parsed DBC data into runtime decode database
 CDbcDecoderRuntime CAN decoder using prebuilt decode database
 CDbcDiagnosticDiagnostic message and physical source location
 CDbcDiagnosticError
 CDbcFrameHandlerParse and append frame definitions
 CDbcHeaderHandler
 CDbcMultiplexingHandlerParse extended multiplexing conditions for deferred resolution
 CDbcParseContext
 CDbcParserMinimal DBC parser
 CDbcParseResultParsed database and diagnostics; the database is empty on error
 CDbcParserOptions
 CDbcSignalHandlerParse and append signals to the current frame
 CDbcStatementDispatcher
 CDbcStatementHandlerInterface for processing a registered DBC statement
 CDbcTreeBuilderBuilds a simple tree from parsed DBC database
 CDbcTreeModel
 CDbcValueDescriptionHandlerDefer raw value descriptions for target resolution
 CDecodeDatabaseImmutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles and decoded results keep old definitions alive
 CDecodedFrameValueFully decoded frame
 CDecodedSignalValueOne decoded signal value
 CDecodeFrameRuntime-ready frame definition
 CDecodeSignalRuntime-ready signal definition
 CFrameInfoDescribes one CAN frame from a DBC file
 CFrameKeyStable frame identifier: normalized CAN ID and frame type
 CFrameKeyHasherHasher for frame key
 CMultiplexingBasic markers and optional explicit extended multiplexing condition
 CMultiplexRangeInclusive raw selector range, without expanding individual values
 CPendingAttributeAttribute statement retained for ordered resolution
 CPendingCommentDeferred frame or signal comment and its source location
 CPendingMultiplexingDeferred extended multiplexing condition and source location
 CPendingValueDescriptionsDeferred raw value descriptions and their target
 CPgnLookupResult
 CRawCanFrameRaw CAN frame used for runtime or trace decoding
 CSignalInfoDescribes one signal inside a DBC frame
 CSignalKey
 CSignalKeyHasherHasher for stable signal keys
 CTreeNodeTree node for later use in model/view or other hierarchy consumers
 CTypeFactoryRegistry-based factory for creating objects by runtime identifier
diff --git a/docs/html/annotated_dup.js b/docs/html/annotated_dup.js index 19b199e..c48d144 100644 --- a/docs/html/annotated_dup.js +++ b/docs/html/annotated_dup.js @@ -1,5 +1,9 @@ var annotated_dup = [ + [ "dbc_detail", null, [ + [ "MultiplexError", "classdbc__detail_1_1MultiplexError.html", null ], + [ "MultiplexGraph", "classdbc__detail_1_1MultiplexGraph.html", null ] + ] ], [ "AttributeAssignment", "structAttributeAssignment.html", "structAttributeAssignment" ], [ "AttributeDefinition", "structAttributeDefinition.html", "structAttributeDefinition" ], [ "DbcAttributeHandler", "classDbcAttributeHandler.html", "classDbcAttributeHandler" ], @@ -11,6 +15,7 @@ var annotated_dup = [ "DbcDiagnosticError", "classDbcDiagnosticError.html", "classDbcDiagnosticError" ], [ "DbcFrameHandler", "classDbcFrameHandler.html", "classDbcFrameHandler" ], [ "DbcHeaderHandler", "classDbcHeaderHandler.html", "classDbcHeaderHandler" ], + [ "DbcMultiplexingHandler", "classDbcMultiplexingHandler.html", "classDbcMultiplexingHandler" ], [ "DbcParseContext", "structDbcParseContext.html", "structDbcParseContext" ], [ "DbcParser", "classDbcParser.html", "classDbcParser" ], [ "DbcParseResult", "structDbcParseResult.html", "structDbcParseResult" ], @@ -20,7 +25,6 @@ var annotated_dup = [ "DbcStatementHandler", "classDbcStatementHandler.html", "classDbcStatementHandler" ], [ "DbcTreeBuilder", "classDbcTreeBuilder.html", "classDbcTreeBuilder" ], [ "DbcTreeModel", "classDbcTreeModel.html", "classDbcTreeModel" ], - [ "DbcUnsupportedMultiplexingHandler", "classDbcUnsupportedMultiplexingHandler.html", "classDbcUnsupportedMultiplexingHandler" ], [ "DbcValueDescriptionHandler", "classDbcValueDescriptionHandler.html", "classDbcValueDescriptionHandler" ], [ "DecodeDatabase", "classDecodeDatabase.html", "classDecodeDatabase" ], [ "DecodedFrameValue", "structDecodedFrameValue.html", "structDecodedFrameValue" ], @@ -31,8 +35,10 @@ var annotated_dup = [ "FrameKey", "structFrameKey.html", "structFrameKey" ], [ "FrameKeyHasher", "structFrameKeyHasher.html", "structFrameKeyHasher" ], [ "Multiplexing", "structMultiplexing.html", "structMultiplexing" ], + [ "MultiplexRange", "structMultiplexRange.html", null ], [ "PendingAttribute", "structPendingAttribute.html", "structPendingAttribute" ], [ "PendingComment", "structPendingComment.html", "structPendingComment" ], + [ "PendingMultiplexing", "structPendingMultiplexing.html", null ], [ "PendingValueDescriptions", "structPendingValueDescriptions.html", "structPendingValueDescriptions" ], [ "PgnLookupResult", "structPgnLookupResult.html", "structPgnLookupResult" ], [ "RawCanFrame", "structRawCanFrame.html", "structRawCanFrame" ], diff --git a/docs/html/classDbcAttributeHandler.html b/docs/html/classDbcAttributeHandler.html index 3a1eed1..a6bf9e2 100644 --- a/docs/html/classDbcAttributeHandler.html +++ b/docs/html/classDbcAttributeHandler.html @@ -118,7 +118,7 @@ Public Member Functions

Detailed Description

Defer typed attribute statements for resolution.

-

Definition at line 106 of file dbc_statement_handler.h.

+

Definition at line 119 of file dbc_statement_handler.h.

Member Function Documentation

◆ Handle()

@@ -158,9 +158,9 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 251 of file dbc_attributes.cpp.

+

Definition at line 255 of file dbc_attributes.cpp.

-

References DbcParseContext::lineNumber, and DbcParseContext::pendingAttributes.

+

References DbcParseContext::lineNumber, and DbcParseContext::pendingAttributes.

diff --git a/docs/html/classDbcCommentHandler.html b/docs/html/classDbcCommentHandler.html index 3072895..b840e0c 100644 --- a/docs/html/classDbcCommentHandler.html +++ b/docs/html/classDbcCommentHandler.html @@ -118,7 +118,7 @@ Public Member Functions

Detailed Description

Defer frame and signal comments for target resolution.

-

Definition at line 100 of file dbc_statement_handler.h.

+

Definition at line 113 of file dbc_statement_handler.h.

Member Function Documentation

◆ Handle()

@@ -158,9 +158,9 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 306 of file dbc_statement_handler.cpp.

+

Definition at line 308 of file dbc_statement_handler.cpp.

-

References PendingComment::canId, PendingComment::comment, PendingComment::isExtended, PendingComment::isSignal, PendingComment::lineNumber, DbcParseContext::lineNumber, DbcParseContext::pendingComments, and PendingComment::signalName.

+

References PendingComment::canId, PendingComment::comment, PendingComment::isExtended, PendingComment::isSignal, PendingComment::lineNumber, DbcParseContext::lineNumber, DbcParseContext::pendingComments, and PendingComment::signalName.

diff --git a/docs/html/classDbcDecodeBuilder.html b/docs/html/classDbcDecodeBuilder.html index c218a43..3741d54 100644 --- a/docs/html/classDbcDecodeBuilder.html +++ b/docs/html/classDbcDecodeBuilder.html @@ -146,7 +146,7 @@ Public Member Functions

Definition at line 15 of file dbc_decode_builder.cpp.

-

References DecodeSignal::attributes, DecodeFrame::attributes, DecodeSignal::byteOrder, DecodeFrame::canId, DecodeSignal::comment, DecodeFrame::comment, DecodeFrame::cycleTimeMs, DecodeFrame::dlc, DecodeSignal::factor, DecodeFrame::frameFormat, DbcDatabase::frames, DecodeFrame::hasPgn, DecodeFrame::isExtended, DecodeSignal::length, DecodeSignal::maximum, DecodeSignal::minimum, DecodeSignal::multiplexing, DecodeSignal::name, DecodeFrame::name, DecodeSignal::offset, DecodeFrame::pgn, DecodeSignal::receivers, DecodeSignal::startBit, DecodeFrame::transmitter, DecodeSignal::unit, DecodeSignal::valueDescriptions, and DecodeSignal::valueType.

+

References DecodeSignal::attributes, DecodeFrame::attributes, DecodeSignal::byteOrder, DecodeFrame::canId, DecodeSignal::comment, DecodeFrame::comment, DecodeFrame::cycleTimeMs, DecodeFrame::dlc, DecodeSignal::factor, DecodeFrame::frameFormat, DbcDatabase::frames, DecodeFrame::hasPgn, DecodeFrame::isExtended, DecodeSignal::length, DecodeSignal::maximum, DecodeSignal::minimum, DecodeSignal::multiplexing, DecodeSignal::name, DecodeFrame::name, DecodeSignal::offset, DecodeFrame::pgn, DecodeSignal::receivers, DecodeSignal::startBit, DecodeFrame::transmitter, DecodeSignal::unit, DecodeSignal::valueDescriptions, and DecodeSignal::valueType.

Referenced by main().

diff --git a/docs/html/classDbcDecoder.html b/docs/html/classDbcDecoder.html index 050b435..a41c534 100644 --- a/docs/html/classDbcDecoder.html +++ b/docs/html/classDbcDecoder.html @@ -91,7 +91,6 @@ $(document).ready(function(){initNavTree('classDbcDecoder.html',''); initResizab
DbcDecoder Class Reference
@@ -118,7 +117,7 @@ Public Member Functions

Detailed Description

Runtime CAN decoder using prebuilt decode database.

-

Definition at line 86 of file dbc_decoder.h.

+

Definition at line 87 of file dbc_decoder.h.

Member Function Documentation

◆ FindFrame()

@@ -165,7 +164,7 @@ Public Member Functions

Definition at line 20 of file dbc_decoder.cpp.

-

References PgnLookupResult::definition.

+

References PgnLookupResult::definition.

diff --git a/docs/html/classDbcDiagnosticError.html b/docs/html/classDbcDiagnosticError.html index 1fb8e08..419eb40 100644 --- a/docs/html/classDbcDiagnosticError.html +++ b/docs/html/classDbcDiagnosticError.html @@ -191,7 +191,7 @@ Public Attributes

Definition at line 40 of file dbc_statement_handler.h.

-

Referenced by DbcParser::ParseFileWithDiagnostics().

+

Referenced by DbcParser::ParseFileWithDiagnostics().

diff --git a/docs/html/classDbcFrameHandler.html b/docs/html/classDbcFrameHandler.html index 1efb842..69d28ab 100644 --- a/docs/html/classDbcFrameHandler.html +++ b/docs/html/classDbcFrameHandler.html @@ -118,7 +118,7 @@ Public Member Functions

Detailed Description

Parse and append frame definitions.

-

Definition at line 82 of file dbc_statement_handler.h.

+

Definition at line 95 of file dbc_statement_handler.h.

Member Function Documentation

◆ Handle()

@@ -158,9 +158,9 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 278 of file dbc_statement_handler.cpp.

+

Definition at line 280 of file dbc_statement_handler.cpp.

-

References FrameInfo::canId, DbcParseContext::currentFrame, DbcParseContext::database, DbcParseContext::enableJ1939, DbcDatabase::frames, FrameInfo::hasPgn, FrameInfo::isExtended, FrameInfo::pgn, and DbcParseContext::signalLines.

+

References FrameInfo::canId, DbcParseContext::currentFrame, DbcParseContext::database, DbcParseContext::enableJ1939, DbcDatabase::frames, FrameInfo::hasPgn, FrameInfo::isExtended, FrameInfo::pgn, and DbcParseContext::signalLines.

diff --git a/docs/html/classDbcHeaderHandler.html b/docs/html/classDbcHeaderHandler.html index 19e2cae..2aff14e 100644 --- a/docs/html/classDbcHeaderHandler.html +++ b/docs/html/classDbcHeaderHandler.html @@ -115,7 +115,7 @@ Public Member Functions

Detailed Description

Common header metadata does not change the supported decode definitions.

-

Definition at line 124 of file dbc_statement_handler.h.

+

Definition at line 137 of file dbc_statement_handler.h.

Member Function Documentation

◆ Handle()

@@ -155,7 +155,7 @@ Public Member Functions

Implements DbcStatementHandler.

-

Definition at line 388 of file dbc_statement_handler.cpp.

+

Definition at line 390 of file dbc_statement_handler.cpp.

diff --git a/docs/html/classDbcMultiplexingHandler-members.html b/docs/html/classDbcMultiplexingHandler-members.html new file mode 100644 index 0000000..412148d --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler-members.html @@ -0,0 +1,110 @@ + + + + + + + +DBC Framework: Member List + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
DbcMultiplexingHandler Member List
+
+
+ +

This is the complete list of members for DbcMultiplexingHandler, including all inherited members.

+ + + +
Handle(const std::string &line, DbcParseContext &context) const overrideDbcMultiplexingHandlervirtual
~DbcStatementHandler()=default (defined in DbcStatementHandler)DbcStatementHandlervirtual
+
+ + + + diff --git a/docs/html/classDbcMultiplexingHandler.html b/docs/html/classDbcMultiplexingHandler.html new file mode 100644 index 0000000..5d108f0 --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler.html @@ -0,0 +1,181 @@ + + + + + + + +DBC Framework: DbcMultiplexingHandler Class Reference + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+ +
DbcMultiplexingHandler Class Reference
+
+
+ +

Parse extended multiplexing conditions for deferred resolution. + More...

+ +

#include <dbc_statement_handler.h>

+
+ + Inheritance diagram for DbcMultiplexingHandler:
+
+
+ + + + + + +

+Public Member Functions

void Handle (const std::string &line, DbcParseContext &context) const override
 Process a trimmed statement using state belonging to this parse.
 
+

Detailed Description

+

Parse extended multiplexing conditions for deferred resolution.

+ +

Definition at line 131 of file dbc_statement_handler.h.

+

Member Function Documentation

+ +

◆ Handle()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void DbcMultiplexingHandler::Handle (const std::string & line,
DbcParseContext & context 
) const
+
+overridevirtual
+
+ +

Process a trimmed statement using state belonging to this parse.

+ +

Implements DbcStatementHandler.

+ +

Definition at line 453 of file dbc_statement_handler.cpp.

+ +

References DbcParseContext::lineNumber.

+ +
+
+
The documentation for this class was generated from the following files: +
+
+ + + + diff --git a/docs/html/classDbcMultiplexingHandler.js b/docs/html/classDbcMultiplexingHandler.js new file mode 100644 index 0000000..0acbfcf --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler.js @@ -0,0 +1,4 @@ +var classDbcMultiplexingHandler = +[ + [ "Handle", "classDbcMultiplexingHandler.html#a16f9e9f898640200477d2dcc8bab442e", null ] +]; \ No newline at end of file diff --git a/docs/html/classDbcMultiplexingHandler__inherit__graph.map b/docs/html/classDbcMultiplexingHandler__inherit__graph.map new file mode 100644 index 0000000..2617620 --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler__inherit__graph.map @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/html/classDbcMultiplexingHandler__inherit__graph.md5 b/docs/html/classDbcMultiplexingHandler__inherit__graph.md5 new file mode 100644 index 0000000..196b80e --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler__inherit__graph.md5 @@ -0,0 +1 @@ +daec8426452e51534b2e501b2b034fdd \ No newline at end of file diff --git a/docs/html/classDbcMultiplexingHandler__inherit__graph.svg b/docs/html/classDbcMultiplexingHandler__inherit__graph.svg new file mode 100644 index 0000000..16e5e2f --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler__inherit__graph.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + +DbcMultiplexingHandler + + +Node1 + + +DbcMultiplexingHandler +  ++ +Handle() + + + + + + + + +Node2 + + +DbcStatementHandler +  ++ +~DbcStatementHandler() ++ +Handle() + + + + + + + + +Node2->Node1 + + + + + + + + + + + + + diff --git a/docs/html/classDbcMultiplexingHandler__inherit__graph_org.svg b/docs/html/classDbcMultiplexingHandler__inherit__graph_org.svg new file mode 100644 index 0000000..8c78316 --- /dev/null +++ b/docs/html/classDbcMultiplexingHandler__inherit__graph_org.svg @@ -0,0 +1,53 @@ + + + + + + +DbcMultiplexingHandler + + +Node1 + + +DbcMultiplexingHandler +  ++ +Handle() + + + + + + + + +Node2 + + +DbcStatementHandler +  ++ +~DbcStatementHandler() ++ +Handle() + + + + + + + + +Node2->Node1 + + + + + + + + diff --git a/docs/html/classDbcParser.html b/docs/html/classDbcParser.html index 5b40f65..dc0ce7c 100644 --- a/docs/html/classDbcParser.html +++ b/docs/html/classDbcParser.html @@ -121,14 +121,14 @@ Public Member Functions
  • SG_
  • CM_ BO_
  • CM_ SG_
  • -
  • basic M / mN multiplexing
  • +
  • basic and extended M / mN / mNM / SG_MUL_VAL_ multiplexing
  • VAL_ signal value descriptions
  • BA_DEF_, BA_DEF_DEF_, BA_ typed attributes, frame format and cycle time
  • -

    Frame/signal comments support multiline quoted text and deferred references.

    -

    Reports unsupported statements as warnings, except SG_MUL_VAL_ which is an error. VERSION, NS_, BS_, BU_ and NS_ symbol declarations stay quiet.

    +

    Frame/signal comments support multiline quoted text and deferred references. Attribute statements support multiline fields and quoted strings, ending at a semicolon outside quoted text. Diagnostics use the first physical line.

    +

    Reports unsupported statements as warnings. Invalid multiplexing is an error. VERSION, NS_, BS_, BU_ and NS_ symbol declarations stay quiet.

    -

    Definition at line 41 of file dbc_parser.h.

    +

    Definition at line 43 of file dbc_parser.h.

    Constructor & Destructor Documentation

    ◆ DbcParser()

    @@ -156,7 +156,7 @@ Public Member Functions

    Create a parser with explicit extended-frame interpretation options.

    -

    Definition at line 44 of file dbc_parser.h.

    +

    Definition at line 46 of file dbc_parser.h.

    @@ -192,9 +192,9 @@ Public Member Functions -

    Definition at line 61 of file dbc_parser.cpp.

    +

    Definition at line 90 of file dbc_parser.cpp.

    -

    References DbcParseResult::database, DbcParseResult::diagnostics, and ParseFileWithDiagnostics().

    +

    References DbcParseResult::database, DbcParseResult::diagnostics, and ParseFileWithDiagnostics().

    Referenced by main().

    @@ -219,11 +219,11 @@ Public Member Functions

    Parse with warnings and a structured first error instead of throwing.

    Returns
    Valid database with diagnostics; empty database on error. File errors use line zero; statement errors use physical one-based lines. Warnings indicate ignored syntax and possible incomplete decoding.
    -

    Definition at line 74 of file dbc_parser.cpp.

    +

    Definition at line 103 of file dbc_parser.cpp.

    -

    References DbcParseResult::database, DbcDiagnosticError::diagnostic, DbcParseResult::diagnostics, DbcStatementDispatcher::Dispatch(), and DbcParserOptions::enableJ1939.

    +

    References DbcParseResult::database, DbcDiagnosticError::diagnostic, DbcParseResult::diagnostics, DbcStatementDispatcher::Dispatch(), and DbcParserOptions::enableJ1939.

    -

    Referenced by ParseFile().

    +

    Referenced by ParseFile().

    diff --git a/docs/html/classDbcSignalHandler.html b/docs/html/classDbcSignalHandler.html index f9b464f..12c321e 100644 --- a/docs/html/classDbcSignalHandler.html +++ b/docs/html/classDbcSignalHandler.html @@ -118,7 +118,7 @@ Public Member Functions

    Detailed Description

    Parse and append signals to the current frame.

    -

    Definition at line 91 of file dbc_statement_handler.h.

    +

    Definition at line 104 of file dbc_statement_handler.h.

    Member Function Documentation

    ◆ Handle()

    @@ -158,9 +158,9 @@ Public Member Functions

    Implements DbcStatementHandler.

    -

    Definition at line 292 of file dbc_statement_handler.cpp.

    +

    Definition at line 294 of file dbc_statement_handler.cpp.

    -

    References DbcParseContext::currentFrame, FrameInfo::dlc, SignalInfo::isLittleEndian, SignalInfo::length, DbcParseContext::lineNumber, FrameInfo::name, SignalInfo::name, DbcParseContext::signalLines, and SignalInfo::startBit.

    +

    References DbcParseContext::currentFrame, FrameInfo::dlc, SignalInfo::isLittleEndian, SignalInfo::length, DbcParseContext::lineNumber, FrameInfo::name, SignalInfo::name, DbcParseContext::signalLines, and SignalInfo::startBit.

    diff --git a/docs/html/classDbcStatementDispatcher.html b/docs/html/classDbcStatementDispatcher.html index 3c85e1e..920c039 100644 --- a/docs/html/classDbcStatementDispatcher.html +++ b/docs/html/classDbcStatementDispatcher.html @@ -114,7 +114,7 @@ Public Member Functions

    Detailed Description

    Exact-key dispatch to handlers created once per registration via TypeFactory.

    -

    Definition at line 130 of file dbc_statement_handler.h.

    +

    Definition at line 143 of file dbc_statement_handler.h.

    Constructor & Destructor Documentation

    ◆ DbcStatementDispatcher()

    @@ -133,7 +133,7 @@ Public Member Functions

    Register supported statement handlers through TypeFactory.

    -

    Definition at line 370 of file dbc_statement_handler.cpp.

    +

    Definition at line 372 of file dbc_statement_handler.cpp.

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

    Register or replace a handler and create its reusable instance.

    -

    Definition at line 137 of file dbc_statement_handler.h.

    +

    Definition at line 150 of file dbc_statement_handler.h.

    References TypeFactory< ClassId, BaseClass, Args >::create(), and TypeFactory< ClassId, BaseClass, Args >::registerType().

    @@ -199,9 +199,9 @@ template<class Handler >

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

    -

    Definition at line 390 of file dbc_statement_handler.cpp.

    +

    Definition at line 392 of file dbc_statement_handler.cpp.

    -

    Referenced by DbcParser::ParseFileWithDiagnostics().

    +

    Referenced by DbcParser::ParseFileWithDiagnostics().

    diff --git a/docs/html/classDbcStatementHandler.html b/docs/html/classDbcStatementHandler.html index d8bf2c1..0d2d56f 100644 --- a/docs/html/classDbcStatementHandler.html +++ b/docs/html/classDbcStatementHandler.html @@ -118,7 +118,7 @@ Public Member Functions

    Detailed Description

    Interface for processing a registered DBC statement.

    -

    Definition at line 74 of file dbc_statement_handler.h.

    +

    Definition at line 87 of file dbc_statement_handler.h.

    Member Function Documentation

    ◆ Handle()

    @@ -156,7 +156,7 @@ Public Member Functions

    Process a trimmed statement using state belonging to this parse.

    -

    Implemented in DbcFrameHandler, DbcSignalHandler, DbcCommentHandler, DbcAttributeHandler, DbcValueDescriptionHandler, DbcUnsupportedMultiplexingHandler, and DbcHeaderHandler.

    +

    Implemented in DbcFrameHandler, DbcSignalHandler, DbcCommentHandler, DbcAttributeHandler, DbcValueDescriptionHandler, DbcMultiplexingHandler, and DbcHeaderHandler.

    diff --git a/docs/html/classDbcStatementHandler__inherit__graph.map b/docs/html/classDbcStatementHandler__inherit__graph.map index 6f4e529..3afe99b 100644 --- a/docs/html/classDbcStatementHandler__inherit__graph.map +++ b/docs/html/classDbcStatementHandler__inherit__graph.map @@ -10,10 +10,10 @@ - - - - - - + + + + + + diff --git a/docs/html/classDbcStatementHandler__inherit__graph.md5 b/docs/html/classDbcStatementHandler__inherit__graph.md5 index 42a56ec..af5f909 100644 --- a/docs/html/classDbcStatementHandler__inherit__graph.md5 +++ b/docs/html/classDbcStatementHandler__inherit__graph.md5 @@ -1 +1 @@ -5f027bd277d1b10d4e4195710b2631a3 \ No newline at end of file +2aacbc7d65e32463c49617e36866cbe8 \ No newline at end of file diff --git a/docs/html/classDbcStatementHandler__inherit__graph.svg b/docs/html/classDbcStatementHandler__inherit__graph.svg index 64daf18..d0246d6 100644 --- a/docs/html/classDbcStatementHandler__inherit__graph.svg +++ b/docs/html/classDbcStatementHandler__inherit__graph.svg @@ -46,7 +46,7 @@ @@ -200,15 +200,15 @@ var sectionId = 'dynsection-0'; Node7 - - -DbcSignalHandler -  -+ -Handle() - - - + + +DbcMultiplexingHandler +  ++ +Handle() + + + @@ -216,24 +216,23 @@ var sectionId = 'dynsection-0'; Node1->Node7 - - + + Node8 - - -DbcUnsupportedMultiplexing -Handler -  -+ -Handle() - - - + + +DbcSignalHandler +  ++ +Handle() + + + @@ -241,8 +240,8 @@ var sectionId = 'dynsection-0'; Node1->Node8 - - + + @@ -250,14 +249,14 @@ var sectionId = 'dynsection-0'; Node9 - -DbcValueDescriptionHandler -  -+ -Handle() - - - + +DbcValueDescriptionHandler +  ++ +Handle() + + + @@ -265,8 +264,8 @@ var sectionId = 'dynsection-0'; Node1->Node9 - - + + diff --git a/docs/html/classDbcStatementHandler__inherit__graph_org.svg b/docs/html/classDbcStatementHandler__inherit__graph_org.svg index f5a4ec6..084588c 100644 --- a/docs/html/classDbcStatementHandler__inherit__graph_org.svg +++ b/docs/html/classDbcStatementHandler__inherit__graph_org.svg @@ -4,8 +4,8 @@ - + DbcStatementHandler @@ -154,15 +154,15 @@ Node7 - - -DbcSignalHandler -  -+ -Handle() - - - + + +DbcMultiplexingHandler +  ++ +Handle() + + + @@ -170,24 +170,23 @@ Node1->Node7 - - + + Node8 - - -DbcUnsupportedMultiplexing -Handler -  -+ -Handle() - - - + + +DbcSignalHandler +  ++ +Handle() + + + @@ -195,8 +194,8 @@ Node1->Node8 - - + + @@ -204,14 +203,14 @@ Node9 - -DbcValueDescriptionHandler -  -+ -Handle() - - - + +DbcValueDescriptionHandler +  ++ +Handle() + + + @@ -219,8 +218,8 @@ Node1->Node9 - - + + diff --git a/docs/html/classDbcValueDescriptionHandler.html b/docs/html/classDbcValueDescriptionHandler.html index 9d9e218..04d7e90 100644 --- a/docs/html/classDbcValueDescriptionHandler.html +++ b/docs/html/classDbcValueDescriptionHandler.html @@ -118,7 +118,7 @@ Public Member Functions

    Detailed Description

    Defer raw value descriptions for target resolution.

    -

    Definition at line 112 of file dbc_statement_handler.h.

    +

    Definition at line 125 of file dbc_statement_handler.h.

    Member Function Documentation

    ◆ Handle()

    @@ -158,9 +158,9 @@ Public Member Functions

    Implements DbcStatementHandler.

    -

    Definition at line 402 of file dbc_statement_handler.cpp.

    +

    Definition at line 404 of file dbc_statement_handler.cpp.

    -

    References PendingValueDescriptions::canId, PendingValueDescriptions::descriptions, PendingValueDescriptions::isExtended, PendingValueDescriptions::lineNumber, DbcParseContext::lineNumber, DbcParseContext::pendingValues, and PendingValueDescriptions::signalName.

    +

    References PendingValueDescriptions::canId, PendingValueDescriptions::descriptions, PendingValueDescriptions::isExtended, PendingValueDescriptions::lineNumber, DbcParseContext::lineNumber, DbcParseContext::pendingValues, and PendingValueDescriptions::signalName.

    diff --git a/docs/html/classDecodeDatabase-members.html b/docs/html/classDecodeDatabase-members.html index 6a01ce6..547ffab 100644 --- a/docs/html/classDecodeDatabase-members.html +++ b/docs/html/classDecodeDatabase-members.html @@ -96,12 +96,13 @@ $(document).ready(function(){initNavTree('classDecodeDatabase.html',''); initRes

    This is the complete list of members for DecodeDatabase, including all inherited members.

    - - - - - - + + + + + + +
    DecodeDatabase()=default (defined in DecodeDatabase)DecodeDatabase
    DecodeDatabase(const std::vector< DecodeFrame > &frames)DecodeDatabaseexplicit
    FindFrame(const FrameKey &key) constDecodeDatabase
    FindFrameByPgn(std::uint32_t pgn) constDecodeDatabase
    FindSignal(const SignalKey &key) constDecodeDatabase
    GetFrames() constDecodeDatabase
    DbcDecoder (defined in DecodeDatabase)DecodeDatabasefriend
    DecodeDatabase()=default (defined in DecodeDatabase)DecodeDatabase
    DecodeDatabase(const std::vector< DecodeFrame > &frames)DecodeDatabaseexplicit
    FindFrame(const FrameKey &key) constDecodeDatabase
    FindFrameByPgn(std::uint32_t pgn) constDecodeDatabase
    FindSignal(const SignalKey &key) constDecodeDatabase
    GetFrames() constDecodeDatabase
    diff --git a/docs/html/classDecodeDatabase.html b/docs/html/classDecodeDatabase.html index d306822..1a20821 100644 --- a/docs/html/classDecodeDatabase.html +++ b/docs/html/classDecodeDatabase.html @@ -93,6 +93,7 @@ $(document).ready(function(){initNavTree('classDecodeDatabase.html',''); initRes
    Classes | Public Member Functions | +Friends | List of all members
    DecodeDatabase Class Reference
    @@ -116,11 +117,16 @@ Public Member Functions std::shared_ptr< const DecodeSignal > FindSignal (const SignalKey &key) const  Return an owning signal handle, or an empty handle for a missing key.
      + + + +

    +Friends

    class DbcDecoder
     

    Detailed Description

    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles and decoded results keep old definitions alive.

    -

    Definition at line 101 of file decode_database.h.

    +

    Definition at line 102 of file decode_database.h.

    Constructor & Destructor Documentation

    ◆ DecodeDatabase()

    @@ -152,7 +158,7 @@ Public Member Functions -

    Definition at line 111 of file decode_database.cpp.

    +

    Definition at line 103 of file decode_database.cpp.

    @@ -173,7 +179,7 @@ Public Member Functions

    Borrowed view, valid while this snapshot remains alive and unchanged.

    -

    Definition at line 115 of file decode_database.cpp.

    +

    Definition at line 107 of file decode_database.cpp.

    Referenced by main().

    @@ -196,9 +202,9 @@ Public Member Functions

    Owning handles retain the entire snapshot across reload or destruction.

    -

    Definition at line 120 of file decode_database.cpp.

    +

    Definition at line 112 of file decode_database.cpp.

    -

    Referenced by FindSignal().

    +

    Referenced by FindSignal().

    @@ -219,9 +225,9 @@ Public Member Functions

    Only explicitly marked hasPgn frames participate; ambiguous results have no definition.

    -

    Definition at line 130 of file decode_database.cpp.

    +

    Definition at line 122 of file decode_database.cpp.

    -

    References PgnLookupResult::ambiguous, and PgnLookupResult::definition.

    +

    References PgnLookupResult::ambiguous, and PgnLookupResult::definition.

    @@ -243,9 +249,34 @@ Public Member Functions

    Return an owning signal handle, or an empty handle for a missing key.

    -

    Definition at line 146 of file decode_database.cpp.

    +

    Definition at line 138 of file decode_database.cpp.

    -

    References FindFrame(), SignalKey::frame, DecodeSignal::name, and SignalKey::name.

    +

    References FindFrame(), SignalKey::frame, DecodeSignal::name, and SignalKey::name.

    + + + +

    Friends And Related Symbol Documentation

    + +

    ◆ DbcDecoder

    + +
    +
    + + + + + +
    + + + + +
    friend class DbcDecoder
    +
    +friend
    +
    + +

    Definition at line 122 of file decode_database.h.

    diff --git a/docs/html/classTypeFactory.html b/docs/html/classTypeFactory.html index 06b1eb6..534a5f4 100644 --- a/docs/html/classTypeFactory.html +++ b/docs/html/classTypeFactory.html @@ -274,7 +274,7 @@ template<class Derived >

    References TypeFactory< ClassId, BaseClass, Args >::classes.

    -

    Referenced by DbcStatementDispatcher::RegisterType().

    +

    Referenced by DbcStatementDispatcher::RegisterType().

    @@ -368,7 +368,7 @@ template<class ClassId , class BaseClass , class... Args>

    References TypeFactory< ClassId, BaseClass, Args >::creator().

    -

    Referenced by DbcStatementDispatcher::RegisterType().

    +

    Referenced by DbcStatementDispatcher::RegisterType().

    diff --git a/docs/html/classdbc__detail_1_1MultiplexError-members.html b/docs/html/classdbc__detail_1_1MultiplexError-members.html new file mode 100644 index 0000000..8124438 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError-members.html @@ -0,0 +1,110 @@ + + + + + + + +DBC Framework: Member List + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    dbc_detail::MultiplexError Member List
    +
    +
    + +

    This is the complete list of members for dbc_detail::MultiplexError, including all inherited members.

    + + + +
    index (defined in dbc_detail::MultiplexError)dbc_detail::MultiplexError
    MultiplexError(std::size_t signalIndex, const std::string &message) (defined in dbc_detail::MultiplexError)dbc_detail::MultiplexErrorinline
    +
    + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexError.html b/docs/html/classdbc__detail_1_1MultiplexError.html new file mode 100644 index 0000000..4923f7e --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError.html @@ -0,0 +1,193 @@ + + + + + + + +DBC Framework: dbc_detail::MultiplexError Class Reference + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    dbc_detail::MultiplexError Class Reference
    +
    +
    + +

    #include <multiplex_graph.h>

    +
    + + Inheritance diagram for dbc_detail::MultiplexError:
    +
    +
    + + + + + +

    +Public Member Functions

     MultiplexError (std::size_t signalIndex, const std::string &message)
     
    + + + +

    +Public Attributes

    std::size_t index
     
    +

    Detailed Description

    +

    Validation failure associated with a signal in declaration order.

    + +

    Definition at line 11 of file multiplex_graph.h.

    +

    Constructor & Destructor Documentation

    + +

    ◆ MultiplexError()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    dbc_detail::MultiplexError::MultiplexError (std::size_t signalIndex,
    const std::string & message 
    )
    +
    +inline
    +
    + +

    Definition at line 13 of file multiplex_graph.h.

    + +
    +
    +

    Member Data Documentation

    + +

    ◆ index

    + +
    +
    + + + + +
    std::size_t dbc_detail::MultiplexError::index
    +
    + +

    Definition at line 15 of file multiplex_graph.h.

    + +
    +
    +
    The documentation for this class was generated from the following file: +
    +
    + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.map b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.map new file mode 100644 index 0000000..779d183 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.md5 b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.md5 new file mode 100644 index 0000000..61509cc --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.md5 @@ -0,0 +1 @@ +ad097ef2ceba6a2378321b0bce266fe8 \ No newline at end of file diff --git a/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.svg b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.svg new file mode 100644 index 0000000..549ecb8 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + +dbc_detail::MultiplexError + + +Node1 + + +dbc_detail::MultiplexError ++ +index ++ +MultiplexError() + + + + + + + + + +Node2 + + +std::invalid_argument +  +  + + + + + + + + +Node2->Node1 + + + + + + + + +Node3 + + +std::logic_error +  +  + + + + + + + + +Node3->Node2 + + + + + + + + + + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph_org.svg b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph_org.svg new file mode 100644 index 0000000..dda84a5 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexError__inherit__graph_org.svg @@ -0,0 +1,75 @@ + + + + + + +dbc_detail::MultiplexError + + +Node1 + + +dbc_detail::MultiplexError ++ +index ++ +MultiplexError() + + + + + + + + + +Node2 + + +std::invalid_argument +  +  + + + + + + + + +Node2->Node1 + + + + + + + + +Node3 + + +std::logic_error +  +  + + + + + + + + +Node3->Node2 + + + + + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexGraph-members.html b/docs/html/classdbc__detail_1_1MultiplexGraph-members.html new file mode 100644 index 0000000..07ad147 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexGraph-members.html @@ -0,0 +1,113 @@ + + + + + + + +DBC Framework: Member List + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    dbc_detail::MultiplexGraph Member List
    +
    +
    + +

    This is the complete list of members for dbc_detail::MultiplexGraph, including all inherited members.

    + + + + + + +
    AreMutuallyExclusive(std::size_t first, std::size_t second) const (defined in dbc_detail::MultiplexGraph)dbc_detail::MultiplexGraphinline
    Matches(std::size_t index, std::uint64_t value) const (defined in dbc_detail::MultiplexGraph)dbc_detail::MultiplexGraphinline
    MultiplexGraph(const std::vector< Signal > &public) (defined in dbc_detail::MultiplexGraph)dbc_detail::MultiplexGraphinlineexplicit
    parents (defined in dbc_detail::MultiplexGraph)dbc_detail::MultiplexGraph
    ranges (defined in dbc_detail::MultiplexGraph)dbc_detail::MultiplexGraph
    +
    + + + + diff --git a/docs/html/classdbc__detail_1_1MultiplexGraph.html b/docs/html/classdbc__detail_1_1MultiplexGraph.html new file mode 100644 index 0000000..3e3f887 --- /dev/null +++ b/docs/html/classdbc__detail_1_1MultiplexGraph.html @@ -0,0 +1,278 @@ + + + + + + + +DBC Framework: dbc_detail::MultiplexGraph Class Reference + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    dbc_detail::MultiplexGraph Class Reference
    +
    +
    + +

    #include <multiplex_graph.h>

    + + + + + + + + + +

    +Public Member Functions

    template<class Signal >
     MultiplexGraph (const std::vector< Signal > &public)
     
    bool Matches (std::size_t index, std::uint64_t value) const
     
    bool AreMutuallyExclusive (std::size_t first, std::size_t second) const
     
    + + + + + +

    +Public Attributes

    std::vector< std::size_t > parents
     
    std::vector< std::vector< MultiplexRange > > ranges
     
    +

    Detailed Description

    +

    Resolved parent links shared by parser validation and runtime decoding.

    + +

    Definition at line 19 of file multiplex_graph.h.

    +

    Constructor & Destructor Documentation

    + +

    ◆ MultiplexGraph()

    + +
    +
    +
    +template<class Signal >
    + + + + + +
    + + + + + + + + +
    dbc_detail::MultiplexGraph::MultiplexGraph (const std::vector< Signal > & public)
    +
    +inlineexplicit
    +
    + +

    Definition at line 22 of file multiplex_graph.h.

    + +
    +
    +

    Member Function Documentation

    + +

    ◆ Matches()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    bool dbc_detail::MultiplexGraph::Matches (std::size_t index,
    std::uint64_t value 
    ) const
    +
    +inline
    +
    + +

    Definition at line 69 of file multiplex_graph.h.

    + +
    +
    + +

    ◆ AreMutuallyExclusive()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    bool dbc_detail::MultiplexGraph::AreMutuallyExclusive (std::size_t first,
    std::size_t second 
    ) const
    +
    +inline
    +
    + +

    Definition at line 77 of file multiplex_graph.h.

    + +
    +
    +

    Member Data Documentation

    + +

    ◆ parents

    + +
    +
    + + + + +
    std::vector<std::size_t> dbc_detail::MultiplexGraph::parents
    +
    + +

    Definition at line 97 of file multiplex_graph.h.

    + +
    +
    + +

    ◆ ranges

    + +
    +
    + + + + +
    std::vector<std::vector<MultiplexRange> > dbc_detail::MultiplexGraph::ranges
    +
    + +

    Definition at line 98 of file multiplex_graph.h.

    + +
    +
    +
    The documentation for this class was generated from the following file: +
    +
    + + + + diff --git a/docs/html/classes.html b/docs/html/classes.html index 67735e7..8d0ceb9 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -100,16 +100,16 @@ $(document).ready(function(){initNavTree('classes.html',''); initResizable(); })
    AttributeAssignment
    AttributeDefinition
    D
    -
    DbcAttributeHandler
    DbcCommentHandler
    DbcDatabase
    DbcDecodeBuilder
    DbcDecoder
    DbcDiagnostic
    DbcDiagnosticError
    DbcFrameHandler
    DbcHeaderHandler
    DbcParseContext
    DbcParser
    DbcParseResult
    DbcParserOptions
    DbcSignalHandler
    DbcStatementDispatcher
    DbcStatementHandler
    DbcTreeBuilder
    DbcTreeModel
    DbcUnsupportedMultiplexingHandler
    DbcValueDescriptionHandler
    DecodeDatabase
    DecodedFrameValue
    DecodedSignalValue
    DecodeFrame
    DecodeSignal
    +
    DbcAttributeHandler
    DbcCommentHandler
    DbcDatabase
    DbcDecodeBuilder
    DbcDecoder
    DbcDiagnostic
    DbcDiagnosticError
    DbcFrameHandler
    DbcHeaderHandler
    DbcMultiplexingHandler
    DbcParseContext
    DbcParser
    DbcParseResult
    DbcParserOptions
    DbcSignalHandler
    DbcStatementDispatcher
    DbcStatementHandler
    DbcTreeBuilder
    DbcTreeModel
    DbcValueDescriptionHandler
    DecodeDatabase
    DecodedFrameValue
    DecodedSignalValue
    DecodeFrame
    DecodeSignal
    F
    FrameInfo
    FrameKey
    FrameKeyHasher
    M
    -
    Multiplexing
    +
    MultiplexError (dbc_detail)
    MultiplexGraph (dbc_detail)
    Multiplexing
    MultiplexRange
    P
    -
    PendingAttribute
    PendingComment
    PendingValueDescriptions
    PgnLookupResult
    +
    PendingAttribute
    PendingComment
    PendingMultiplexing
    PendingValueDescriptions
    PgnLookupResult
    R
    RawCanFrame
    diff --git a/docs/html/dbc__attributes_8cpp_source.html b/docs/html/dbc__attributes_8cpp_source.html index 251e450..2353fbf 100644 --- a/docs/html/dbc__attributes_8cpp_source.html +++ b/docs/html/dbc__attributes_8cpp_source.html @@ -111,331 +111,335 @@ $(document).ready(function(){initNavTree('dbc__attributes_8cpp_source.html','');
    11 bool quoted = false;
    12 };
    13
    -
    14 std::vector<Token> Tokenize(const std::string &text) {
    -
    15 std::vector<Token> tokens;
    -
    16 std::size_t index = 0U;
    -
    17 while (index < text.size()) {
    -
    18 const char character = text[index++];
    -
    19 if (character == ' ' || character == '\t')
    -
    20 continue;
    -
    21 Token token;
    -
    22 if (character == '"') {
    -
    23 token.quoted = true;
    -
    24 bool closed = false;
    -
    25 while (index < text.size()) {
    -
    26 char next = text[index++];
    -
    27 if (next == '"') {
    -
    28 closed = true;
    -
    29 break;
    -
    30 }
    -
    31 if (next == '\\') {
    -
    32 if (index == text.size())
    -
    33 throw std::runtime_error("Incomplete attribute escape.");
    -
    34 next = text[index++];
    -
    35 if (next != '"' && next != '\\')
    -
    36 throw std::runtime_error("Invalid attribute escape.");
    -
    37 }
    -
    38 token.text += next;
    -
    39 }
    -
    40 if (!closed)
    -
    41 throw std::runtime_error("Unterminated attribute string.");
    -
    42 if (index < text.size() && text[index] != ' ' && text[index] != '\t' &&
    -
    43 text[index] != ',' && text[index] != ';')
    -
    44 throw std::runtime_error("Missing separator after attribute string.");
    -
    45 } else if (character == ';' || character == ',') {
    -
    46 token.text = character;
    -
    47 } else {
    -
    48 token.text = character;
    -
    49 while (index < text.size() && text[index] != ' ' && text[index] != '\t' &&
    -
    50 text[index] != ';' && text[index] != ',') {
    -
    51 if (text[index] == '"')
    -
    52 throw std::runtime_error("Missing separator before attribute string.");
    -
    53 token.text += text[index++];
    -
    54 }
    -
    55 }
    -
    56 tokens.push_back(token);
    -
    57 }
    -
    58 if (tokens.empty() || tokens.back().quoted || tokens.back().text != ";")
    -
    59 throw std::runtime_error("Attribute statement requires a semicolon.");
    -
    60 tokens.pop_back();
    -
    61 return tokens;
    -
    62 }
    -
    63
    -
    64 class AttributeTokens {
    -
    65 public:
    -
    66 explicit AttributeTokens(const std::string &line) : tokens(Tokenize(line)) {}
    -
    67 Token Take() {
    -
    68 if (position == tokens.size())
    -
    69 throw std::runtime_error("Incomplete attribute statement.");
    -
    70 return tokens[position++];
    -
    71 }
    -
    72 std::string Word() {
    -
    73 const Token token = Take();
    -
    74 if (token.quoted || token.text == "," || token.text == ";")
    -
    75 throw std::runtime_error("Expected an attribute keyword or number.");
    -
    76 return token.text;
    -
    77 }
    -
    78 std::string Quoted() {
    -
    79 const Token token = Take();
    -
    80 if (!token.quoted)
    -
    81 throw std::runtime_error("Expected a quoted attribute name or string.");
    -
    82 return token.text;
    -
    83 }
    -
    84 bool Empty() const { return position == tokens.size(); }
    -
    85 void End() const {
    -
    86 if (!Empty())
    -
    87 throw std::runtime_error("Unexpected trailing attribute fields.");
    -
    88 }
    -
    89
    -
    90 private:
    -
    91 std::vector<Token> tokens;
    -
    92 std::size_t position = 0U;
    -
    93 };
    -
    94
    -
    95 bool IsScope(const std::string &text) {
    -
    96 return text == "BO_" || text == "SG_" || text == "BU_" || text == "EV_";
    -
    97 }
    +
    14 bool IsWhitespace(char character) {
    +
    15 return character == ' ' || character == '\t' || character == '\n' || character == '\r';
    +
    16 }
    +
    17
    +
    18 std::vector<Token> Tokenize(const std::string &text) {
    +
    19 std::vector<Token> tokens;
    +
    20 std::size_t index = 0U;
    +
    21 while (index < text.size()) {
    +
    22 const char character = text[index++];
    +
    23 if (IsWhitespace(character))
    +
    24 continue;
    +
    25 Token token;
    +
    26 if (character == '"') {
    +
    27 token.quoted = true;
    +
    28 bool closed = false;
    +
    29 while (index < text.size()) {
    +
    30 char next = text[index++];
    +
    31 if (next == '"') {
    +
    32 closed = true;
    +
    33 break;
    +
    34 }
    +
    35 if (next == '\\') {
    +
    36 if (index == text.size())
    +
    37 throw std::runtime_error("Incomplete attribute escape.");
    +
    38 next = text[index++];
    +
    39 if (next != '"' && next != '\\')
    +
    40 throw std::runtime_error("Invalid attribute escape.");
    +
    41 }
    +
    42 token.text += next;
    +
    43 }
    +
    44 if (!closed)
    +
    45 throw std::runtime_error("Unterminated attribute string.");
    +
    46 if (index < text.size() && !IsWhitespace(text[index]) &&
    +
    47 text[index] != ',' && text[index] != ';')
    +
    48 throw std::runtime_error("Missing separator after attribute string.");
    +
    49 } else if (character == ';' || character == ',') {
    +
    50 token.text = character;
    +
    51 } else {
    +
    52 token.text = character;
    +
    53 while (index < text.size() && !IsWhitespace(text[index]) &&
    +
    54 text[index] != ';' && text[index] != ',') {
    +
    55 if (text[index] == '"')
    +
    56 throw std::runtime_error("Missing separator before attribute string.");
    +
    57 token.text += text[index++];
    +
    58 }
    +
    59 }
    +
    60 tokens.push_back(token);
    +
    61 }
    +
    62 if (tokens.empty() || tokens.back().quoted || tokens.back().text != ";")
    +
    63 throw std::runtime_error("Attribute statement requires a semicolon.");
    +
    64 tokens.pop_back();
    +
    65 return tokens;
    +
    66 }
    +
    67
    +
    68 class AttributeTokens {
    +
    69 public:
    +
    70 explicit AttributeTokens(const std::string &line) : tokens(Tokenize(line)) {}
    +
    71 Token Take() {
    +
    72 if (position == tokens.size())
    +
    73 throw std::runtime_error("Incomplete attribute statement.");
    +
    74 return tokens[position++];
    +
    75 }
    +
    76 std::string Word() {
    +
    77 const Token token = Take();
    +
    78 if (token.quoted || token.text == "," || token.text == ";")
    +
    79 throw std::runtime_error("Expected an attribute keyword or number.");
    +
    80 return token.text;
    +
    81 }
    +
    82 std::string Quoted() {
    +
    83 const Token token = Take();
    +
    84 if (!token.quoted)
    +
    85 throw std::runtime_error("Expected a quoted attribute name or string.");
    +
    86 return token.text;
    +
    87 }
    +
    88 bool Empty() const { return position == tokens.size(); }
    +
    89 void End() const {
    +
    90 if (!Empty())
    +
    91 throw std::runtime_error("Unexpected trailing attribute fields.");
    +
    92 }
    +
    93
    +
    94 private:
    +
    95 std::vector<Token> tokens;
    +
    96 std::size_t position = 0U;
    +
    97 };
    98
    -
    99 AttributeScope ParseScope(const std::string &text) {
    -
    100 if (text == "BO_") return AttributeScope::Frame;
    -
    101 if (text == "SG_") return AttributeScope::Signal;
    -
    102 if (text == "BU_") return AttributeScope::Node;
    -
    103 if (text == "EV_") return AttributeScope::Environment;
    -
    104 throw std::runtime_error("Unsupported attribute scope: " + text);
    -
    105 }
    -
    106
    -
    107 template<class Numeric>
    -
    108 Numeric ParseNumber(const std::string &text) {
    -
    109 const char *begin = text.data();
    -
    110 const char *end = begin + text.size();
    -
    111 if (begin != end && *begin == '+') {
    -
    112 ++begin;
    -
    113 if (begin != end && (*begin == '-' || *begin == '+'))
    -
    114 throw std::runtime_error("Invalid attribute number: " + text);
    -
    115 }
    -
    116 Numeric value = 0;
    -
    117 const std::from_chars_result parsed = std::from_chars(begin, end, value);
    -
    118 if (begin == end || parsed.ec != std::errc() || parsed.ptr != end || !std::isfinite(value))
    -
    119 throw std::runtime_error("Invalid attribute number: " + text);
    -
    120 return value;
    -
    121 }
    -
    122
    -
    123 AttributeValue Value(const Token &token, const AttributeDefinition &definition, bool isDefault) {
    -
    124 if (definition.type == AttributeType::String) {
    -
    125 if (!token.quoted) throw std::runtime_error("Attribute STRING requires quoted text.");
    -
    126 return token.text;
    -
    127 }
    -
    128 if (definition.type == AttributeType::Enum && isDefault && token.quoted) {
    -
    129 for (std::size_t index = 0U; index < definition.enumValues.size(); ++index) {
    -
    130 if (definition.enumValues[index] == token.text)
    -
    131 return static_cast<std::int64_t>(index);
    -
    132 }
    -
    133 throw std::runtime_error("Unknown attribute ENUM default label.");
    -
    134 }
    -
    135 if (token.quoted) throw std::runtime_error("Numeric attribute requires an unquoted number.");
    -
    136 if (definition.type == AttributeType::Float) {
    -
    137 const double value = ParseNumber<double>(token.text);
    -
    138 if (value < definition.minimum || value > definition.maximum)
    -
    139 throw std::runtime_error("Attribute FLOAT value outside definition range.");
    -
    140 return value;
    -
    141 }
    -
    142 const std::int64_t value = ParseNumber<std::int64_t>(token.text);
    -
    143 if (value < definition.integerMinimum || value > definition.integerMaximum)
    -
    144 throw std::runtime_error("Attribute integer/ENUM value outside definition range.");
    -
    145 return value;
    -
    146 }
    -
    147
    -
    148 void Define(AttributeTokens &tokens, DbcDatabase &database) {
    -
    149 AttributeDefinition definition;
    -
    150 const Token first = tokens.Take();
    -
    151 std::string name = first.text;
    -
    152 if (!first.quoted) {
    -
    153 definition.scope = ParseScope(first.text);
    -
    154 name = tokens.Quoted();
    -
    155 }
    -
    156 if (name.empty()) throw std::runtime_error("Empty attribute name.");
    -
    157 const std::string type = tokens.Word();
    -
    158 if (type == "INT" || type == "HEX") {
    -
    159 definition.type = type == "INT" ? AttributeType::Integer : AttributeType::Hex;
    -
    160 definition.integerMinimum = ParseNumber<std::int64_t>(tokens.Word());
    -
    161 definition.integerMaximum = ParseNumber<std::int64_t>(tokens.Word());
    -
    162 if (definition.integerMinimum > definition.integerMaximum)
    -
    163 throw std::runtime_error("Reversed attribute integer range.");
    -
    164 } else if (type == "FLOAT") {
    -
    165 definition.type = AttributeType::Float;
    -
    166 definition.minimum = ParseNumber<double>(tokens.Word());
    -
    167 definition.maximum = ParseNumber<double>(tokens.Word());
    -
    168 if (definition.minimum > definition.maximum)
    -
    169 throw std::runtime_error("Reversed attribute FLOAT range.");
    -
    170 } else if (type == "STRING") {
    -
    171 definition.type = AttributeType::String;
    -
    172 } else if (type == "ENUM") {
    -
    173 definition.type = AttributeType::Enum;
    -
    174 std::set<std::string> labels;
    -
    175 for (;;) {
    -
    176 const std::string label = tokens.Quoted();
    -
    177 if (!labels.insert(label).second)
    -
    178 throw std::runtime_error("Duplicate attribute ENUM label.");
    -
    179 definition.enumValues.push_back(label);
    -
    180 if (tokens.Empty()) break;
    -
    181 const Token separator = tokens.Take();
    -
    182 if (separator.quoted || separator.text != ",") throw std::runtime_error("Expected ENUM comma.");
    -
    183 }
    -
    184 definition.integerMaximum = static_cast<std::int64_t>(definition.enumValues.size() - 1U);
    -
    185 } else {
    -
    186 throw std::runtime_error("Unsupported attribute definition type: " + type);
    -
    187 }
    -
    188 tokens.End();
    -
    189 if (name == "VFrameFormat" && (definition.scope != AttributeScope::Frame || definition.type != AttributeType::Enum))
    -
    190 throw std::runtime_error("VFrameFormat requires a BO_ ENUM definition.");
    -
    191 if (name == "GenMsgCycleTime" && (definition.scope != AttributeScope::Frame ||
    -
    192 (definition.type != AttributeType::Integer && definition.type != AttributeType::Hex)))
    -
    193 throw std::runtime_error("GenMsgCycleTime requires a BO_ integer definition.");
    -
    194 if (!database.attributeDefinitions.emplace(name, definition).second)
    -
    195 throw std::runtime_error("Duplicate attribute definition: " + name);
    -
    196 }
    -
    197
    -
    198 AttributeDefinition &FindDefinition(DbcDatabase &database, const std::string &name) {
    -
    199 const std::map<std::string, AttributeDefinition>::iterator found = database.attributeDefinitions.find(name);
    -
    200 if (found == database.attributeDefinitions.end())
    -
    201 throw std::runtime_error("Undefined attribute: " + name);
    -
    202 return found->second;
    -
    203 }
    -
    204
    -
    205 void ParseId(const std::string &text, AttributeAssignment &assignment) {
    -
    206 const std::int64_t raw = ParseNumber<std::int64_t>(text);
    -
    207 if (raw < 0 || raw > std::numeric_limits<std::uint32_t>::max() || (raw & 0x60000000U) != 0)
    -
    208 throw std::runtime_error("Invalid attribute CAN ID.");
    -
    209 const std::uint32_t id = static_cast<std::uint32_t>(raw);
    -
    210 assignment.canId = id & 0x1fffffffU;
    -
    211 assignment.isExtended = (id & 0x80000000U) != 0U || id > 0x7ffU;
    -
    212 }
    -
    213
    -
    214 AttributeMap &Target(DbcDatabase &database, const AttributeAssignment &assignment) {
    -
    215 if (assignment.scope == AttributeScope::Database) return database.attributes;
    -
    216 for (FrameInfo &frame: database.frames) {
    -
    217 if (frame.canId != assignment.canId || frame.isExtended != assignment.isExtended) continue;
    -
    218 if (assignment.scope == AttributeScope::Frame) return frame.attributes;
    -
    219 for (SignalInfo &signal: frame.signals) {
    -
    220 if (signal.name == assignment.targetName) return signal.attributes;
    -
    221 }
    -
    222 throw std::runtime_error("Unresolved attribute signal: " + assignment.targetName);
    -
    223 }
    -
    224 throw std::runtime_error("Unresolved attribute frame.");
    -
    225 }
    -
    226
    -
    227 void ValidateCycleTime(const std::string &name, const AttributeValue &value) {
    -
    228 if (name != "GenMsgCycleTime") return;
    -
    229 const std::int64_t milliseconds = std::get<std::int64_t>(value);
    -
    230 if (milliseconds < 0 || milliseconds > std::numeric_limits<std::uint32_t>::max())
    -
    231 throw std::runtime_error("GenMsgCycleTime must fit unsigned 32-bit milliseconds.");
    -
    232 }
    -
    233
    -
    234 void ApplyDefault(DbcDatabase &database, const std::string &name, const AttributeDefinition &definition) {
    -
    235 if (!definition.defaultValue) return;
    -
    236 if (definition.scope == AttributeScope::Database) {
    -
    237 database.attributes[name] = *definition.defaultValue;
    -
    238 return;
    -
    239 }
    -
    240 if (definition.scope != AttributeScope::Frame && definition.scope != AttributeScope::Signal)
    -
    241 return;
    -
    242 for (FrameInfo &frame: database.frames) {
    -
    243 if (definition.scope == AttributeScope::Frame) frame.attributes[name] = *definition.defaultValue;
    -
    244 if (definition.scope == AttributeScope::Signal) {
    -
    245 for (SignalInfo &signal: frame.signals) signal.attributes[name] = *definition.defaultValue;
    -
    246 }
    -
    247 }
    -
    248 }
    -
    249}// namespace
    -
    250
    -
    -
    251void DbcAttributeHandler::Handle(const std::string &line, DbcParseContext &context) const {
    -
    252 context.pendingAttributes.push_back({line, context.lineNumber});
    -
    253}
    -
    +
    99 bool IsScope(const std::string &text) {
    +
    100 return text == "BO_" || text == "SG_" || text == "BU_" || text == "EV_";
    +
    101 }
    +
    102
    +
    103 AttributeScope ParseScope(const std::string &text) {
    +
    104 if (text == "BO_") return AttributeScope::Frame;
    +
    105 if (text == "SG_") return AttributeScope::Signal;
    +
    106 if (text == "BU_") return AttributeScope::Node;
    +
    107 if (text == "EV_") return AttributeScope::Environment;
    +
    108 throw std::runtime_error("Unsupported attribute scope: " + text);
    +
    109 }
    +
    110
    +
    111 template<class Numeric>
    +
    112 Numeric ParseNumber(const std::string &text) {
    +
    113 const char *begin = text.data();
    +
    114 const char *end = begin + text.size();
    +
    115 if (begin != end && *begin == '+') {
    +
    116 ++begin;
    +
    117 if (begin != end && (*begin == '-' || *begin == '+'))
    +
    118 throw std::runtime_error("Invalid attribute number: " + text);
    +
    119 }
    +
    120 Numeric value = 0;
    +
    121 const std::from_chars_result parsed = std::from_chars(begin, end, value);
    +
    122 if (begin == end || parsed.ec != std::errc() || parsed.ptr != end || !std::isfinite(value))
    +
    123 throw std::runtime_error("Invalid attribute number: " + text);
    +
    124 return value;
    +
    125 }
    +
    126
    +
    127 AttributeValue Value(const Token &token, const AttributeDefinition &definition, bool isDefault) {
    +
    128 if (definition.type == AttributeType::String) {
    +
    129 if (!token.quoted) throw std::runtime_error("Attribute STRING requires quoted text.");
    +
    130 return token.text;
    +
    131 }
    +
    132 if (definition.type == AttributeType::Enum && isDefault && token.quoted) {
    +
    133 for (std::size_t index = 0U; index < definition.enumValues.size(); ++index) {
    +
    134 if (definition.enumValues[index] == token.text)
    +
    135 return static_cast<std::int64_t>(index);
    +
    136 }
    +
    137 throw std::runtime_error("Unknown attribute ENUM default label.");
    +
    138 }
    +
    139 if (token.quoted) throw std::runtime_error("Numeric attribute requires an unquoted number.");
    +
    140 if (definition.type == AttributeType::Float) {
    +
    141 const double value = ParseNumber<double>(token.text);
    +
    142 if (value < definition.minimum || value > definition.maximum)
    +
    143 throw std::runtime_error("Attribute FLOAT value outside definition range.");
    +
    144 return value;
    +
    145 }
    +
    146 const std::int64_t value = ParseNumber<std::int64_t>(token.text);
    +
    147 if (value < definition.integerMinimum || value > definition.integerMaximum)
    +
    148 throw std::runtime_error("Attribute integer/ENUM value outside definition range.");
    +
    149 return value;
    +
    150 }
    +
    151
    +
    152 void Define(AttributeTokens &tokens, DbcDatabase &database) {
    +
    153 AttributeDefinition definition;
    +
    154 const Token first = tokens.Take();
    +
    155 std::string name = first.text;
    +
    156 if (!first.quoted) {
    +
    157 definition.scope = ParseScope(first.text);
    +
    158 name = tokens.Quoted();
    +
    159 }
    +
    160 if (name.empty()) throw std::runtime_error("Empty attribute name.");
    +
    161 const std::string type = tokens.Word();
    +
    162 if (type == "INT" || type == "HEX") {
    +
    163 definition.type = type == "INT" ? AttributeType::Integer : AttributeType::Hex;
    +
    164 definition.integerMinimum = ParseNumber<std::int64_t>(tokens.Word());
    +
    165 definition.integerMaximum = ParseNumber<std::int64_t>(tokens.Word());
    +
    166 if (definition.integerMinimum > definition.integerMaximum)
    +
    167 throw std::runtime_error("Reversed attribute integer range.");
    +
    168 } else if (type == "FLOAT") {
    +
    169 definition.type = AttributeType::Float;
    +
    170 definition.minimum = ParseNumber<double>(tokens.Word());
    +
    171 definition.maximum = ParseNumber<double>(tokens.Word());
    +
    172 if (definition.minimum > definition.maximum)
    +
    173 throw std::runtime_error("Reversed attribute FLOAT range.");
    +
    174 } else if (type == "STRING") {
    +
    175 definition.type = AttributeType::String;
    +
    176 } else if (type == "ENUM") {
    +
    177 definition.type = AttributeType::Enum;
    +
    178 std::set<std::string> labels;
    +
    179 for (;;) {
    +
    180 const std::string label = tokens.Quoted();
    +
    181 if (!labels.insert(label).second)
    +
    182 throw std::runtime_error("Duplicate attribute ENUM label.");
    +
    183 definition.enumValues.push_back(label);
    +
    184 if (tokens.Empty()) break;
    +
    185 const Token separator = tokens.Take();
    +
    186 if (separator.quoted || separator.text != ",") throw std::runtime_error("Expected ENUM comma.");
    +
    187 }
    +
    188 definition.integerMaximum = static_cast<std::int64_t>(definition.enumValues.size() - 1U);
    +
    189 } else {
    +
    190 throw std::runtime_error("Unsupported attribute definition type: " + type);
    +
    191 }
    +
    192 tokens.End();
    +
    193 if (name == "VFrameFormat" && (definition.scope != AttributeScope::Frame || definition.type != AttributeType::Enum))
    +
    194 throw std::runtime_error("VFrameFormat requires a BO_ ENUM definition.");
    +
    195 if (name == "GenMsgCycleTime" && (definition.scope != AttributeScope::Frame ||
    +
    196 (definition.type != AttributeType::Integer && definition.type != AttributeType::Hex)))
    +
    197 throw std::runtime_error("GenMsgCycleTime requires a BO_ integer definition.");
    +
    198 if (!database.attributeDefinitions.emplace(name, definition).second)
    +
    199 throw std::runtime_error("Duplicate attribute definition: " + name);
    +
    200 }
    +
    201
    +
    202 AttributeDefinition &FindDefinition(DbcDatabase &database, const std::string &name) {
    +
    203 const std::map<std::string, AttributeDefinition>::iterator found = database.attributeDefinitions.find(name);
    +
    204 if (found == database.attributeDefinitions.end())
    +
    205 throw std::runtime_error("Undefined attribute: " + name);
    +
    206 return found->second;
    +
    207 }
    +
    208
    +
    209 void ParseId(const std::string &text, AttributeAssignment &assignment) {
    +
    210 const std::int64_t raw = ParseNumber<std::int64_t>(text);
    +
    211 if (raw < 0 || raw > std::numeric_limits<std::uint32_t>::max() || (raw & 0x60000000U) != 0)
    +
    212 throw std::runtime_error("Invalid attribute CAN ID.");
    +
    213 const std::uint32_t id = static_cast<std::uint32_t>(raw);
    +
    214 assignment.canId = id & 0x1fffffffU;
    +
    215 assignment.isExtended = (id & 0x80000000U) != 0U || id > 0x7ffU;
    +
    216 }
    +
    217
    +
    218 AttributeMap &Target(DbcDatabase &database, const AttributeAssignment &assignment) {
    +
    219 if (assignment.scope == AttributeScope::Database) return database.attributes;
    +
    220 for (FrameInfo &frame: database.frames) {
    +
    221 if (frame.canId != assignment.canId || frame.isExtended != assignment.isExtended) continue;
    +
    222 if (assignment.scope == AttributeScope::Frame) return frame.attributes;
    +
    223 for (SignalInfo &signal: frame.signals) {
    +
    224 if (signal.name == assignment.targetName) return signal.attributes;
    +
    225 }
    +
    226 throw std::runtime_error("Unresolved attribute signal: " + assignment.targetName);
    +
    227 }
    +
    228 throw std::runtime_error("Unresolved attribute frame.");
    +
    229 }
    +
    230
    +
    231 void ValidateCycleTime(const std::string &name, const AttributeValue &value) {
    +
    232 if (name != "GenMsgCycleTime") return;
    +
    233 const std::int64_t milliseconds = std::get<std::int64_t>(value);
    +
    234 if (milliseconds < 0 || milliseconds > std::numeric_limits<std::uint32_t>::max())
    +
    235 throw std::runtime_error("GenMsgCycleTime must fit unsigned 32-bit milliseconds.");
    +
    236 }
    +
    237
    +
    238 void ApplyDefault(DbcDatabase &database, const std::string &name, const AttributeDefinition &definition) {
    +
    239 if (!definition.defaultValue) return;
    +
    240 if (definition.scope == AttributeScope::Database) {
    +
    241 database.attributes[name] = *definition.defaultValue;
    +
    242 return;
    +
    243 }
    +
    244 if (definition.scope != AttributeScope::Frame && definition.scope != AttributeScope::Signal)
    +
    245 return;
    +
    246 for (FrameInfo &frame: database.frames) {
    +
    247 if (definition.scope == AttributeScope::Frame) frame.attributes[name] = *definition.defaultValue;
    +
    248 if (definition.scope == AttributeScope::Signal) {
    +
    249 for (SignalInfo &signal: frame.signals) signal.attributes[name] = *definition.defaultValue;
    +
    250 }
    +
    251 }
    +
    252 }
    +
    253}// namespace
    254
    -
    255void DbcParseContext::ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics) {
    -
    256 std::map<std::string, std::size_t> defaultLines;
    -
    257 std::vector<std::size_t> assignmentLines;
    -
    258 // Resolve each phase independently of source ordering.
    -
    259 const char *keywords[] = {"BA_DEF_", "BA_DEF_DEF_", "BA_"};
    -
    260 for (const char *phase: keywords) {
    -
    261 for (const PendingAttribute &pending: pendingAttributes) {
    -
    262 const std::string keyword = pending.statement.substr(0U, pending.statement.find_first_of(" \t"));
    -
    263 if (keyword != phase) continue;
    -
    264 try {
    -
    265 AttributeTokens tokens(pending.statement);
    -
    266 tokens.Word();
    -
    267 if (keyword == "BA_DEF_") {
    -
    268 Define(tokens, database);
    -
    269 continue;
    -
    270 }
    -
    271 const std::string name = tokens.Quoted();
    -
    272 AttributeDefinition &definition = FindDefinition(database, name);
    -
    273 if (keyword == "BA_DEF_DEF_") {
    -
    274 if (definition.defaultValue) throw std::runtime_error("Duplicate attribute default: " + name);
    -
    275 definition.defaultValue = Value(tokens.Take(), definition, true);
    -
    276 ValidateCycleTime(name, *definition.defaultValue);
    -
    277 tokens.End();
    -
    278 defaultLines[name] = pending.lineNumber;
    -
    279 ApplyDefault(database, name, definition);
    -
    280 continue;
    -
    281 }
    -
    282 AttributeAssignment assignment;
    -
    283 assignment.name = name;
    -
    284 Token value = tokens.Take();
    -
    285 if (!value.quoted && IsScope(value.text)) {
    -
    286 assignment.scope = ParseScope(value.text);
    -
    287 if (assignment.scope == AttributeScope::Frame || assignment.scope == AttributeScope::Signal)
    -
    288 ParseId(tokens.Word(), assignment);
    -
    289 if (assignment.scope != AttributeScope::Frame)
    -
    290 assignment.targetName = tokens.Word();
    -
    291 value = tokens.Take();
    -
    292 }
    -
    293 if (assignment.scope != definition.scope) throw std::runtime_error("Attribute assignment scope differs from definition.");
    -
    294 assignment.value = Value(value, definition, false);
    -
    295 ValidateCycleTime(name, assignment.value);
    -
    296 tokens.End();
    -
    297 // Repeated explicit assignments use the last value, matching comments.
    -
    298 if (assignment.scope != AttributeScope::Node && assignment.scope != AttributeScope::Environment)
    -
    299 Target(database, assignment)[name] = assignment.value;
    -
    300 database.attributeAssignments.push_back(assignment);
    -
    301 assignmentLines.push_back(pending.lineNumber);
    -
    302 } catch (const std::exception &error) {
    -
    303 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidAttribute, filePath, pending.lineNumber, error.what());
    -
    304 }
    -
    305 }
    -
    306 }
    -
    307 for (FrameInfo &frame: database.frames) {
    -
    308 for (const AttributeMap::value_type &attribute: frame.attributes) {
    -
    309 if (attribute.first != "VFrameFormat" && attribute.first != "GenMsgCycleTime") continue;
    -
    310 std::size_t line = defaultLines[attribute.first];
    -
    311 for (std::size_t index = 0U; index < database.attributeAssignments.size(); ++index) {
    -
    312 const AttributeAssignment &assignment = database.attributeAssignments[index];
    -
    313 if (assignment.name == attribute.first && assignment.scope == AttributeScope::Frame &&
    -
    314 assignment.canId == frame.canId && assignment.isExtended == frame.isExtended)
    -
    315 line = assignmentLines[index];
    -
    316 }
    -
    317 const std::int64_t value = std::get<std::int64_t>(attribute.second);
    -
    318 if (attribute.first == "GenMsgCycleTime") {
    -
    319 frame.cycleTimeMs = static_cast<std::uint32_t>(value);
    -
    320 continue;
    -
    321 }
    -
    322 frame.frameFormat = database.attributeDefinitions.at(attribute.first).enumValues[static_cast<std::size_t>(value)];
    -
    323 const std::string &format = *frame.frameFormat;
    -
    324 std::string warning;
    -
    325 if (format != "StandardCAN" && format != "ExtendedCAN")
    -
    326 warning = "Unsupported VFrameFormat '" + format + "' is preserved; decoding may be incomplete.";
    -
    327 else if ((format == "ExtendedCAN") != frame.isExtended)
    -
    328 warning = "VFrameFormat '" + format + "' conflicts with the BO_ CAN ID; ID interpretation is unchanged.";
    -
    329 if (!warning.empty())
    -
    330 diagnostics.push_back({DbcDiagnosticSeverity::Warning, DbcDiagnosticCode::UnsupportedAttribute, filePath, line, warning});
    -
    331 }
    -
    332 }
    -
    333}
    +
    255void DbcAttributeHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    256 context.pendingAttributes.push_back({line, context.lineNumber});
    +
    257}
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    258
    +
    +
    259void DbcParseContext::ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics) {
    +
    260 std::map<std::string, std::size_t> defaultLines;
    +
    261 std::vector<std::size_t> assignmentLines;
    +
    262 // Resolve each phase independently of source ordering.
    +
    263 const char *keywords[] = {"BA_DEF_", "BA_DEF_DEF_", "BA_"};
    +
    264 for (const char *phase: keywords) {
    +
    265 for (const PendingAttribute &pending: pendingAttributes) {
    +
    266 const std::string keyword = pending.statement.substr(0U, pending.statement.find_first_of(" \t\r\n"));
    +
    267 if (keyword != phase) continue;
    +
    268 try {
    +
    269 AttributeTokens tokens(pending.statement);
    +
    270 tokens.Word();
    +
    271 if (keyword == "BA_DEF_") {
    +
    272 Define(tokens, database);
    +
    273 continue;
    +
    274 }
    +
    275 const std::string name = tokens.Quoted();
    +
    276 AttributeDefinition &definition = FindDefinition(database, name);
    +
    277 if (keyword == "BA_DEF_DEF_") {
    +
    278 if (definition.defaultValue) throw std::runtime_error("Duplicate attribute default: " + name);
    +
    279 definition.defaultValue = Value(tokens.Take(), definition, true);
    +
    280 ValidateCycleTime(name, *definition.defaultValue);
    +
    281 tokens.End();
    +
    282 defaultLines[name] = pending.lineNumber;
    +
    283 ApplyDefault(database, name, definition);
    +
    284 continue;
    +
    285 }
    +
    286 AttributeAssignment assignment;
    +
    287 assignment.name = name;
    +
    288 Token value = tokens.Take();
    +
    289 if (!value.quoted && IsScope(value.text)) {
    +
    290 assignment.scope = ParseScope(value.text);
    +
    291 if (assignment.scope == AttributeScope::Frame || assignment.scope == AttributeScope::Signal)
    +
    292 ParseId(tokens.Word(), assignment);
    +
    293 if (assignment.scope != AttributeScope::Frame)
    +
    294 assignment.targetName = tokens.Word();
    +
    295 value = tokens.Take();
    +
    296 }
    +
    297 if (assignment.scope != definition.scope) throw std::runtime_error("Attribute assignment scope differs from definition.");
    +
    298 assignment.value = Value(value, definition, false);
    +
    299 ValidateCycleTime(name, assignment.value);
    +
    300 tokens.End();
    +
    301 // Repeated explicit assignments use the last value, matching comments.
    +
    302 if (assignment.scope != AttributeScope::Node && assignment.scope != AttributeScope::Environment)
    +
    303 Target(database, assignment)[name] = assignment.value;
    +
    304 database.attributeAssignments.push_back(assignment);
    +
    305 assignmentLines.push_back(pending.lineNumber);
    +
    306 } catch (const std::exception &error) {
    +
    307 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidAttribute, filePath, pending.lineNumber, error.what());
    +
    308 }
    +
    309 }
    +
    310 }
    +
    311 for (FrameInfo &frame: database.frames) {
    +
    312 for (const AttributeMap::value_type &attribute: frame.attributes) {
    +
    313 if (attribute.first != "VFrameFormat" && attribute.first != "GenMsgCycleTime") continue;
    +
    314 std::size_t line = defaultLines[attribute.first];
    +
    315 for (std::size_t index = 0U; index < database.attributeAssignments.size(); ++index) {
    +
    316 const AttributeAssignment &assignment = database.attributeAssignments[index];
    +
    317 if (assignment.name == attribute.first && assignment.scope == AttributeScope::Frame &&
    +
    318 assignment.canId == frame.canId && assignment.isExtended == frame.isExtended)
    +
    319 line = assignmentLines[index];
    +
    320 }
    +
    321 const std::int64_t value = std::get<std::int64_t>(attribute.second);
    +
    322 if (attribute.first == "GenMsgCycleTime") {
    +
    323 frame.cycleTimeMs = static_cast<std::uint32_t>(value);
    +
    324 continue;
    +
    325 }
    +
    326 frame.frameFormat = database.attributeDefinitions.at(attribute.first).enumValues[static_cast<std::size_t>(value)];
    +
    327 const std::string &format = *frame.frameFormat;
    +
    328 std::string warning;
    +
    329 if (format != "StandardCAN" && format != "ExtendedCAN")
    +
    330 warning = "Unsupported VFrameFormat '" + format + "' is preserved; decoding may be incomplete.";
    +
    331 else if ((format == "ExtendedCAN") != frame.isExtended)
    +
    332 warning = "VFrameFormat '" + format + "' conflicts with the BO_ CAN ID; ID interpretation is unchanged.";
    +
    333 if (!warning.empty())
    +
    334 diagnostics.push_back({DbcDiagnosticSeverity::Warning, DbcDiagnosticCode::UnsupportedAttribute, filePath, line, warning});
    +
    335 }
    +
    336 }
    +
    337}
    +
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    Explicit assignment; defaults remain on definitions.
    Definition attributes.h:59
    bool isExtended
    Definition attributes.h:63
    @@ -458,11 +462,11 @@ $(document).ready(function(){initNavTree('dbc__attributes_8cpp_source.html','');
    std::vector< FrameInfo > frames
    AttributeMap attributes
    std::vector< AttributeAssignment > attributeAssignments
    -
    -
    void ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)
    Resolve definitions, defaults, then assignments; append format warnings.
    -
    std::size_t lineNumber
    -
    DbcDatabase & database
    -
    std::vector< PendingAttribute > pendingAttributes
    +
    +
    void ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)
    Resolve definitions, defaults, then assignments; append format warnings.
    +
    std::size_t lineNumber
    +
    DbcDatabase & database
    +
    std::vector< PendingAttribute > pendingAttributes
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    Attribute statement retained for ordered resolution.
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    diff --git a/docs/html/dbc__coverage__test_8cpp_source.html b/docs/html/dbc__coverage__test_8cpp_source.html index fb1f876..5e2c401 100644 --- a/docs/html/dbc__coverage__test_8cpp_source.html +++ b/docs/html/dbc__coverage__test_8cpp_source.html @@ -360,14 +360,14 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    260 QFETCH(int, kind);
    261 DecodeSignal selector;
    262 selector.length = 1U;
    -
    263 selector.multiplexing.role = MultiplexRole::Selector;
    +
    263 selector.multiplexing.role = MultiplexRole::Selector;
    264 selector.name = "Selector";
    265 std::vector<DecodeFrame> definitions = SingleSignal(selector).GetFrames();
    266 DecodeSignal branch;
    267 branch.name = "Branch";
    268 branch.startBit = 8U;
    269 branch.length = 8U;
    -
    270 branch.multiplexing.role = MultiplexRole::Branch;
    +
    270 branch.multiplexing.role = MultiplexRole::Branch;
    271 branch.multiplexing.value = 1U;
    272 definitions[0].signals.push_back(branch);
    273 DecodeSignal ordinary;
    @@ -821,7 +821,7 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    721 QCOMPARE(copy->comment, original.comment);
    722 QVERIFY(copy->receivers == original.receivers);
    723 QVERIFY(copy->valueDescriptions == original.valueDescriptions);
    -
    724 QCOMPARE(copy->multiplexing.role, original.multiplexing.role);
    +
    724 QCOMPARE(copy->multiplexing.role, original.multiplexing.role);
    725 QCOMPARE(copy->multiplexing.value, original.multiplexing.value);
    726 }
    727 QCOMPARE(target.name, original.name);
    @@ -837,7 +837,7 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    737 QCOMPARE(target.comment, original.comment);
    738 QVERIFY(target.receivers == original.receivers);
    739 QVERIFY(target.valueDescriptions == original.valueDescriptions);
    -
    740 QCOMPARE(target.multiplexing.role, original.multiplexing.role);
    +
    740 QCOMPARE(target.multiplexing.role, original.multiplexing.role);
    741 QCOMPARE(target.multiplexing.value, original.multiplexing.value);
    742 }
    743 }
    @@ -913,10 +913,10 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    813 const QString selector = "SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n";
    814 const QString branch = "SG_ A m1 : 8|8@1+ (1,0) [0|255] \"\" ECU\n";
    815 QTest::newRow("missing-selector") << header + branch << 3U << QString::fromUtf8("Multiplexed branch has no selector.");
    -
    816 QTest::newRow("second-selector") << header + selector + "\nSG_ Other M : 16|1@1+ (1,0) [0|1] \"\" ECU\n"
    -
    817 << 5U << QString::fromUtf8("Multiplexing requires one unsigned selector per frame.");
    +
    816 QTest::newRow("second-selector") << header + selector + "\nSG_ Other M : 16|1@1- (1,0) [-1|0] \"\" ECU\n"
    +
    817 << 5U << QString::fromUtf8("Multiplex selectors must be unsigned.");
    818 QTest::newRow("signed-selector") << header + "SG_ Mode M : 0|1@1- (1,0) [-1|0] \"\" ECU\n"
    -
    819 << 3U << QString::fromUtf8("Multiplexing requires one unsigned selector per frame.");
    +
    819 << 3U << QString::fromUtf8("Multiplex selectors must be unsigned.");
    820 QTest::newRow("branch-range") << header + "SG_ A m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n" + selector << 3U << QString::fromUtf8("Branch value exceeds selector raw range.");
    821 QTest::newRow("same-branch-overlap") << header + selector + branch + "SG_ B m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
    822 << 5U << QString::fromUtf8("Signals overlap without mutually exclusive multiplexing conditions.");
    @@ -927,9 +927,9 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    827 QTest::newRow("ordinary-overlap") << header + "SG_ A : 8|8@1+ (1,0) [0|255] \"\" ECU\nSG_ B : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
    828 << 4U << QString::fromUtf8("Signals overlap without mutually exclusive multiplexing conditions.");
    829 QTest::newRow("extended-multiplexing") << header + "SG_MUL_VAL_ 1 A Mode 1-2;\n"
    -
    830 << 3U << QString::fromUtf8("Extended and nested multiplexing are unsupported.");
    +
    830 << 3U << QString::fromUtf8("Unresolved SG_MUL_VAL_ signal reference: A");
    831 QTest::newRow("nested-marker") << header + "SG_ A m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    832 << 3U << QString::fromUtf8("Invalid or unsupported multiplexing marker.");
    +
    832 << 3U << QString::fromUtf8("Multiplexed branch has no selector.");
    833}
    834
    835void CoverageTest::multiplexingErrorLocations() {
    @@ -992,23 +992,23 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    892 return QTest::qExec(&tests, argc, argv);
    893}
    894#include "dbc_coverage_test.moc"
    -
    Defer frame and signal comments for target resolution.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Defer frame and signal comments for target resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
    Find exact CAN ID first, then unique PGN among explicitly J1939 definitions.
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    -
    Defer raw value descriptions for target resolution.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    -
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    +
    Defer raw value descriptions for target resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    +
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    Tree node for later use in model/view or other hierarchy consumers.
    Definition tree_node.h:37
    const SignalInfo * GetSignal() const
    Get signal payload if node is signal.
    Definition tree_node.cpp:71
    const TreeNode * GetChild(std::size_t index) const
    Get child by index.
    Definition tree_node.cpp:45
    @@ -1023,45 +1023,45 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    CreatorFn creator(const ClassId &id) const
    Returns creator function for the given id.
    Definition typefactory.h:91
    Runtime decode database builder.
    CAN frame decoding API and result types.
    -
    FrameDecodeStatus
    Definition dbc_decoder.h:43
    +
    FrameDecodeStatus
    Definition dbc_decoder.h:44
    DBC file parser and interpretation options.
    Metadata tree builder.
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    -
    ValueType
    Signal numeric type.
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ValueType
    Signal numeric type.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    -
    +
    Definition dbc_parser.h:20
    -
    Runtime-ready frame definition.
    -
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    -
    std::uint32_t pgn
    -
    bool hasPgn
    -
    std::string comment
    -
    bool isExtended
    -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    std::string name
    -
    std::string transmitter
    -
    Runtime-ready signal definition.
    -
    double minimum
    -
    std::string unit
    -
    double factor
    -
    double maximum
    -
    std::string name
    -
    ValueDescriptions valueDescriptions
    -
    double offset
    -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    std::vector< std::string > receivers
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    std::string comment
    -
    Multiplexing multiplexing
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    FrameKey key
    Definition dbc_decoder.h:75
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    +
    Runtime-ready frame definition.
    +
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    +
    std::uint32_t pgn
    +
    bool hasPgn
    +
    std::string comment
    +
    bool isExtended
    +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    std::string name
    +
    std::string transmitter
    +
    Runtime-ready signal definition.
    +
    double minimum
    +
    std::string unit
    +
    double factor
    +
    double maximum
    +
    std::string name
    +
    ValueDescriptions valueDescriptions
    +
    double offset
    +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    std::vector< std::string > receivers
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    std::string comment
    +
    Multiplexing multiplexing
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    FrameKey key
    Definition dbc_decoder.h:76
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    bool hasPgn
    Definition frame_info.h:30
    @@ -1072,15 +1072,14 @@ $(document).ready(function(){initNavTree('dbc__coverage__test_8cpp_source.html',
    std::uint32_t pgn
    Definition frame_info.h:29
    std::uint32_t canId
    Definition frame_info.h:27
    Stable frame identifier: normalized CAN ID and frame type.
    -
    MultiplexRole role
    -
    std::uint64_t value
    -
    -
    bool ambiguous
    -
    std::shared_ptr< const DecodeFrame > definition
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    std::uint64_t value
    +
    +
    bool ambiguous
    +
    std::shared_ptr< const DecodeFrame > definition
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string unit
    Definition signal_info.h:36
    diff --git a/docs/html/dbc__decode__builder_8cpp_source.html b/docs/html/dbc__decode__builder_8cpp_source.html index d26faa2..6bc7f49 100644 --- a/docs/html/dbc__decode__builder_8cpp_source.html +++ b/docs/html/dbc__decode__builder_8cpp_source.html @@ -152,38 +152,38 @@ $(document).ready(function(){initNavTree('dbc__decode__builder_8cpp_source.html'
    61}
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    Runtime decode database builder.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    -
    Runtime-ready frame definition.
    -
    std::uint32_t pgn
    -
    bool hasPgn
    -
    std::string comment
    -
    bool isExtended
    -
    std::optional< std::string > frameFormat
    -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    std::optional< std::uint32_t > cycleTimeMs
    -
    std::string name
    -
    AttributeMap attributes
    -
    std::string transmitter
    -
    Runtime-ready signal definition.
    -
    double minimum
    -
    AttributeMap attributes
    -
    std::string unit
    -
    double factor
    -
    double maximum
    -
    std::string name
    -
    ValueDescriptions valueDescriptions
    -
    double offset
    -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    std::vector< std::string > receivers
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    std::string comment
    -
    Multiplexing multiplexing
    +
    Runtime-ready frame definition.
    +
    std::uint32_t pgn
    +
    bool hasPgn
    +
    std::string comment
    +
    bool isExtended
    +
    std::optional< std::string > frameFormat
    +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    std::optional< std::uint32_t > cycleTimeMs
    +
    std::string name
    +
    AttributeMap attributes
    +
    std::string transmitter
    +
    Runtime-ready signal definition.
    +
    double minimum
    +
    AttributeMap attributes
    +
    std::string unit
    +
    double factor
    +
    double maximum
    +
    std::string name
    +
    ValueDescriptions valueDescriptions
    +
    double offset
    +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    std::vector< std::string > receivers
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    std::string comment
    +
    Multiplexing multiplexing
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    diff --git a/docs/html/dbc__decode__builder_8h_source.html b/docs/html/dbc__decode__builder_8h_source.html index 279f214..2c5afa0 100644 --- a/docs/html/dbc__decode__builder_8h_source.html +++ b/docs/html/dbc__decode__builder_8h_source.html @@ -115,7 +115,7 @@ $(document).ready(function(){initNavTree('dbc__decode__builder_8h_source.html','
    32#endif /* DBC_DECODE_BUILDER_H */
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    Parsed DBC database and attribute metadata.
    Runtime definitions and immutable indexed database.
    Parsed DBC content stored in a simple internal form.
    diff --git a/docs/html/dbc__decoder_8cpp_source.html b/docs/html/dbc__decoder_8cpp_source.html index 43989dc..7a00f5f 100644 --- a/docs/html/dbc__decoder_8cpp_source.html +++ b/docs/html/dbc__decoder_8cpp_source.html @@ -177,230 +177,222 @@ $(document).ready(function(){initNavTree('dbc__decoder_8cpp_source.html',''); in
    81 ? FrameDecodeStatus::InsufficientPayload
    82 : FrameDecodeStatus::Valid;
    83
    -
    84 const SelectorState selector = ReadSelector(*definition, frame);
    +
    84 const dbc_detail::MultiplexGraph &graph = database.GetMultiplexGraph(result.key);
    85 const std::size_t count = selection != nullptr ? selected.size() : definition->signals.size();
    86 result.signals.reserve(count);
    87 for (std::size_t index = 0U; index < count; ++index) {
    88 const DecodeSignal &signal = selection != nullptr ? *selected[index] : definition->signals[index];
    -
    89 DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame, selector);
    -
    90 if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive &&
    -
    91 result.status == FrameDecodeStatus::Valid)
    -
    92 result.status = FrameDecodeStatus::SignalErrors;
    -
    93 decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
    -
    94 decoded.key = SignalKey(result.key, signal.name);
    -
    95 result.signals.push_back(std::move(decoded));
    -
    96 }
    -
    97
    -
    98 return result;
    -
    99}
    -
    100
    -
    101bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) {
    -
    102 if ((signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) ||
    -
    103 (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) ||
    -
    104 (signal.multiplexing.role != MultiplexRole::Unconditional &&
    -
    105 signal.multiplexing.role != MultiplexRole::Selector &&
    -
    106 signal.multiplexing.role != MultiplexRole::Branch))
    -
    107 return false;
    -
    108
    -
    109 return IsValidSignalLayout(signal.startBit, signal.length,
    -
    110 signal.byteOrder == ByteOrder::Intel, dlc);
    -
    111}
    -
    112
    -
    113DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
    -
    114 const RawCanFrame &frame) {
    -
    115 SelectorState selector;
    -
    116 std::size_t count = 0U;
    -
    117 for (const DecodeSignal &signal: definition.signals) {
    -
    118 if (signal.multiplexing.role == MultiplexRole::Selector) {
    -
    119 selector.definition = &signal;
    -
    120 ++count;
    -
    121 }
    -
    122 }
    -
    123 if (count != 1U)
    -
    124 return selector;
    -
    125
    -
    126 const DecodeSignal &signal = *selector.definition;
    -
    127 selector.valid = signal.valueType == ValueType::Unsigned &&
    -
    128 IsValidDefinition(signal, definition.dlc);
    -
    129 selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
    -
    130 return selector;
    -
    131}
    -
    132
    -
    133DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
    -
    134 std::uint8_t dlc,
    -
    135 const RawCanFrame &frame,
    -
    136 const SelectorState &selector) {
    -
    137 DecodedSignalValue decoded;
    -
    138 std::uint64_t unsignedValue = 0U;
    -
    139
    -
    140 if (!IsValidDefinition(signal, dlc) ||
    -
    141 (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
    -
    142 return decoded;
    -
    143 }
    -
    144 if (signal.multiplexing.role == MultiplexRole::Branch) {
    -
    145 if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
    -
    146 return decoded;
    -
    147 }
    -
    148 if (!selector.available) {
    -
    149 decoded.status = SignalDecodeStatus::SelectorUnavailable;
    -
    150 return decoded;
    -
    151 }
    -
    152 if (signal.multiplexing.value != selector.value) {
    -
    153 decoded.status = SignalDecodeStatus::Inactive;
    -
    154 return decoded;
    -
    155 }
    -
    156 }
    -
    157 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
    -
    158 decoded.status = SignalDecodeStatus::InsufficientPayload;
    -
    159 return decoded;
    -
    160 }
    -
    161
    -
    162 if (signal.valueType == ValueType::Signed)
    -
    163 decoded.rawValue = SignExtend(unsignedValue, signal.length);
    -
    164 else
    -
    165 decoded.rawValue = unsignedValue;
    -
    166
    -
    167 double numericValue;
    -
    168 if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
    -
    169 numericValue = static_cast<double>(*signedValue);
    -
    170 else
    -
    171 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
    -
    172 decoded.physicalValue = numericValue * signal.factor + signal.offset;
    -
    173 if (!std::isfinite(decoded.physicalValue)) {
    -
    174 decoded.status = SignalDecodeStatus::PhysicalConversionFailed;
    -
    175 return decoded;
    -
    176 }
    -
    177 decoded.valid = true;
    -
    178 decoded.status = SignalDecodeStatus::Valid;
    -
    179
    -
    180 return decoded;
    -
    181}
    -
    182
    -
    183bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
    -
    184 const DecodeSignal &signal,
    -
    185 std::uint64_t &value) {
    -
    186 if ((signal.length == 0U) || (signal.length > 64U))
    -
    187 return false;
    -
    188
    -
    189 if (signal.byteOrder == ByteOrder::Intel)
    -
    190 return ExtractIntel(data, signal.startBit, signal.length, value);
    -
    191
    -
    192 return ExtractMotorola(data, signal.startBit, signal.length, value);
    -
    193}
    -
    194
    -
    195bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
    -
    196 std::uint32_t startBit,
    -
    197 std::uint32_t length,
    -
    198 std::uint64_t &value) {
    -
    199 value = 0U;
    -
    200
    -
    201 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
    -
    202 const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex;
    -
    203 const std::uint64_t byteIndex = absoluteBit / 8U;
    -
    204 const std::uint32_t bitInByte = absoluteBit % 8U;
    -
    205
    -
    206 if (byteIndex >= data.size())
    -
    207 return false;
    -
    208
    -
    209 const std::uint64_t bitValue =
    -
    210 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
    -
    211
    -
    212 value |= bitValue;
    -
    213 }
    -
    214
    -
    215 return true;
    -
    216}
    -
    217
    -
    218bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
    -
    219 std::uint32_t startBit,
    -
    220 std::uint32_t length,
    -
    221 std::uint64_t &value) {
    -
    222 /*
    -
    223 * DBC Motorola bit numbering:
    -
    224 * - startBit points to the most significant bit of the signal
    -
    225 * - inside a byte, bit numbering goes 7..0
    -
    226 * - crossing byte boundary moves to the next byte, bit 7
    -
    227 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
    -
    228 */
    -
    229
    -
    230 value = 0U;
    +
    89 const std::size_t signalIndex = static_cast<std::size_t>(&signal - definition->signals.data());
    +
    90 DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame,
    +
    91 ActivationStatus(signalIndex, *definition, frame, graph));
    +
    92 if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive &&
    +
    93 result.status == FrameDecodeStatus::Valid)
    +
    94 result.status = FrameDecodeStatus::SignalErrors;
    +
    95 decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
    +
    96 decoded.key = SignalKey(result.key, signal.name);
    +
    97 result.signals.push_back(std::move(decoded));
    +
    98 }
    +
    99
    +
    100 return result;
    +
    101}
    +
    102
    +
    103bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) {
    +
    104 if ((signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) ||
    +
    105 (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) ||
    +
    106 (signal.multiplexing.role != MultiplexRole::Unconditional &&
    +
    107 signal.multiplexing.role != MultiplexRole::Selector &&
    +
    108 signal.multiplexing.role != MultiplexRole::Branch &&
    +
    109 signal.multiplexing.role != MultiplexRole::BranchSelector))
    +
    110 return false;
    +
    111
    +
    112 return IsValidSignalLayout(signal.startBit, signal.length,
    +
    113 signal.byteOrder == ByteOrder::Intel, dlc);
    +
    114}
    +
    115
    +
    116SignalDecodeStatus DbcDecoder::ActivationStatus(std::size_t index,
    +
    117 const DecodeFrame &definition,
    +
    118 const RawCanFrame &frame,
    +
    119 const dbc_detail::MultiplexGraph &graph) {
    +
    120 // Inspect ancestors from the root so inactive paths never require child bytes.
    +
    121 std::vector<std::size_t> path;
    +
    122 while (graph.parents[index] != definition.signals.size()) {
    +
    123 path.push_back(index);
    +
    124 index = graph.parents[index];
    +
    125 }
    +
    126 for (std::vector<std::size_t>::const_reverse_iterator it = path.rbegin(); it != path.rend(); ++it) {
    +
    127 const DecodeSignal &selector = definition.signals[graph.parents[*it]];
    +
    128 std::uint64_t value = 0U;
    +
    129 if (!ExtractUnsigned(frame.data, selector, value))
    +
    130 return SignalDecodeStatus::SelectorUnavailable;
    +
    131 if (!graph.Matches(*it, value))
    +
    132 return SignalDecodeStatus::Inactive;
    +
    133 }
    +
    134 return SignalDecodeStatus::Valid;
    +
    135}
    +
    136
    +
    137DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
    +
    138 std::uint8_t dlc,
    +
    139 const RawCanFrame &frame,
    +
    140 SignalDecodeStatus activation) {
    +
    141 DecodedSignalValue decoded;
    +
    142 std::uint64_t unsignedValue = 0U;
    +
    143
    +
    144 if (!IsValidDefinition(signal, dlc))
    +
    145 return decoded;
    +
    146 if (activation != SignalDecodeStatus::Valid) {
    +
    147 decoded.status = activation;
    +
    148 return decoded;
    +
    149 }
    +
    150 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
    +
    151 decoded.status = SignalDecodeStatus::InsufficientPayload;
    +
    152 return decoded;
    +
    153 }
    +
    154
    +
    155 if (signal.valueType == ValueType::Signed)
    +
    156 decoded.rawValue = SignExtend(unsignedValue, signal.length);
    +
    157 else
    +
    158 decoded.rawValue = unsignedValue;
    +
    159
    +
    160 double numericValue;
    +
    161 if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
    +
    162 numericValue = static_cast<double>(*signedValue);
    +
    163 else
    +
    164 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
    +
    165 decoded.physicalValue = numericValue * signal.factor + signal.offset;
    +
    166 if (!std::isfinite(decoded.physicalValue)) {
    +
    167 decoded.status = SignalDecodeStatus::PhysicalConversionFailed;
    +
    168 return decoded;
    +
    169 }
    +
    170 decoded.valid = true;
    +
    171 decoded.status = SignalDecodeStatus::Valid;
    +
    172
    +
    173 return decoded;
    +
    174}
    +
    175
    +
    176bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
    +
    177 const DecodeSignal &signal,
    +
    178 std::uint64_t &value) {
    +
    179 if ((signal.length == 0U) || (signal.length > 64U))
    +
    180 return false;
    +
    181
    +
    182 if (signal.byteOrder == ByteOrder::Intel)
    +
    183 return ExtractIntel(data, signal.startBit, signal.length, value);
    +
    184
    +
    185 return ExtractMotorola(data, signal.startBit, signal.length, value);
    +
    186}
    +
    187
    +
    188bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
    +
    189 std::uint32_t startBit,
    +
    190 std::uint32_t length,
    +
    191 std::uint64_t &value) {
    +
    192 value = 0U;
    +
    193
    +
    194 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
    +
    195 const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex;
    +
    196 const std::uint64_t byteIndex = absoluteBit / 8U;
    +
    197 const std::uint32_t bitInByte = absoluteBit % 8U;
    +
    198
    +
    199 if (byteIndex >= data.size())
    +
    200 return false;
    +
    201
    +
    202 const std::uint64_t bitValue =
    +
    203 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
    +
    204
    +
    205 value |= bitValue;
    +
    206 }
    +
    207
    +
    208 return true;
    +
    209}
    +
    210
    +
    211bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
    +
    212 std::uint32_t startBit,
    +
    213 std::uint32_t length,
    +
    214 std::uint64_t &value) {
    +
    215 /*
    +
    216 * DBC Motorola bit numbering:
    +
    217 * - startBit points to the most significant bit of the signal
    +
    218 * - inside a byte, bit numbering goes 7..0
    +
    219 * - crossing byte boundary moves to the next byte, bit 7
    +
    220 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
    +
    221 */
    +
    222
    +
    223 value = 0U;
    +
    224
    +
    225 std::size_t byteIndex = startBit / 8U;
    +
    226 std::uint32_t bitInByte = startBit % 8U;
    +
    227
    +
    228 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
    +
    229 if (byteIndex >= data.size())
    +
    230 return false;
    231
    -
    232 std::size_t byteIndex = startBit / 8U;
    -
    233 std::uint32_t bitInByte = startBit % 8U;
    +
    232 value <<= 1U;
    +
    233 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
    234
    -
    235 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
    -
    236 if (byteIndex >= data.size())
    -
    237 return false;
    -
    238
    -
    239 value <<= 1U;
    -
    240 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
    +
    235 if (bitInByte == 0U) {
    +
    236 ++byteIndex;
    +
    237 bitInByte = 7U;
    +
    238 } else
    +
    239 --bitInByte;
    +
    240 }
    241
    -
    242 if (bitInByte == 0U) {
    -
    243 ++byteIndex;
    -
    244 bitInByte = 7U;
    -
    245 } else
    -
    246 --bitInByte;
    -
    247 }
    +
    242 return true;
    +
    243}
    +
    244
    +
    245std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
    +
    246 if ((bitLength == 0U) || (bitLength > 64U))
    +
    247 return 0;
    248
    -
    249 return true;
    -
    250}
    -
    251
    -
    252std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
    -
    253 if ((bitLength == 0U) || (bitLength > 64U))
    -
    254 return 0;
    -
    255
    -
    256 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
    -
    257 const std::uint64_t valueMask = (bitLength == 64U)
    -
    258 ? ~std::uint64_t(0U)
    -
    259 : (std::uint64_t(1U) << bitLength) - 1U;
    -
    260 value &= valueMask;
    -
    261
    -
    262 if ((value & signMask) == 0U)
    -
    263 return static_cast<std::int64_t>(value);
    -
    264
    -
    265 // The complemented magnitude fits int64_t, including for INT64_MIN.
    -
    266 return -1 - static_cast<std::int64_t>((~value) & valueMask);
    -
    267}
    +
    249 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
    +
    250 const std::uint64_t valueMask = (bitLength == 64U)
    +
    251 ? ~std::uint64_t(0U)
    +
    252 : (std::uint64_t(1U) << bitLength) - 1U;
    +
    253 value &= valueMask;
    +
    254
    +
    255 if ((value & signMask) == 0U)
    +
    256 return static_cast<std::int64_t>(value);
    +
    257
    +
    258 // The complemented magnitude fits int64_t, including for INT64_MIN.
    +
    259 return -1 - static_cast<std::int64_t>((~value) & valueMask);
    +
    260}
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
    Find exact CAN ID first, then unique PGN among explicitly J1939 definitions.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    +
    CAN frame decoding API and result types.
    -
    Runtime-ready frame definition.
    -
    std::uint8_t dlc
    -
    Runtime-ready signal definition.
    -
    double factor
    -
    std::string name
    -
    double offset
    -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    Multiplexing multiplexing
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    FrameKey key
    Definition dbc_decoder.h:75
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    -
    SignalKey key
    Definition dbc_decoder.h:56
    -
    RawSignalValue rawValue
    Definition dbc_decoder.h:57
    -
    double physicalValue
    Definition dbc_decoder.h:58
    -
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:55
    -
    SignalDecodeStatus status
    Definition dbc_decoder.h:60
    -
    bool valid
    Definition dbc_decoder.h:59
    +
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:34
    +
    Runtime-ready frame definition.
    +
    Runtime-ready signal definition.
    +
    double factor
    +
    std::string name
    +
    double offset
    +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    Multiplexing multiplexing
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    FrameKey key
    Definition dbc_decoder.h:76
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    +
    SignalKey key
    Definition dbc_decoder.h:57
    +
    RawSignalValue rawValue
    Definition dbc_decoder.h:58
    +
    double physicalValue
    Definition dbc_decoder.h:59
    +
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:56
    +
    SignalDecodeStatus status
    Definition dbc_decoder.h:61
    +
    bool valid
    Definition dbc_decoder.h:60
    Stable frame identifier: normalized CAN ID and frame type.
    -
    MultiplexRole role
    -
    std::uint64_t value
    -
    -
    bool ambiguous
    -
    std::shared_ptr< const DecodeFrame > definition
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    +
    bool ambiguous
    +
    std::shared_ptr< const DecodeFrame > definition
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    diff --git a/docs/html/dbc__decoder_8h.html b/docs/html/dbc__decoder_8h.html index d990ecf..833e2c9 100644 --- a/docs/html/dbc__decoder_8h.html +++ b/docs/html/dbc__decoder_8h.html @@ -103,6 +103,7 @@ $(document).ready(function(){initNavTree('dbc__decoder_8h.html',''); initResizab #include <variant>
    #include <vector>
    #include "decode_database.h"
    +#include "multiplex_graph.h"

    Go to the source code of this file.

    @@ -175,7 +176,7 @@ Enumerations

    Outcome of signal extraction and physical conversion.

    -

    Definition at line 33 of file dbc_decoder.h.

    +

    Definition at line 34 of file dbc_decoder.h.

    @@ -200,7 +201,7 @@ Enumerations

    Frame summary: short payload takes precedence over individual signal errors.

    -

    Definition at line 43 of file dbc_decoder.h.

    +

    Definition at line 44 of file dbc_decoder.h.

    diff --git a/docs/html/dbc__decoder_8h_source.html b/docs/html/dbc__decoder_8h_source.html index 315aa09..839f8ae 100644 --- a/docs/html/dbc__decoder_8h_source.html +++ b/docs/html/dbc__decoder_8h_source.html @@ -107,150 +107,148 @@ $(document).ready(function(){initNavTree('dbc__decoder_8h_source.html',''); init
    17#include <vector>
    18
    19#include "decode_database.h"
    -
    20
    -
    - -
    25 std::uint32_t canId = 0U;
    -
    26 bool isExtended = false;
    -
    27 std::vector<std::uint8_t> data;
    -
    29 RawCanFrame() = default;
    -
    30};
    +
    20#include "multiplex_graph.h"
    +
    21
    +
    + +
    26 std::uint32_t canId = 0U;
    +
    27 bool isExtended = false;
    +
    28 std::vector<std::uint8_t> data;
    +
    30 RawCanFrame() = default;
    +
    31};
    -
    31
    -
    - -
    34 InvalidDefinition,
    -
    35 InsufficientPayload,
    -
    36 SelectorUnavailable,
    -
    37 Inactive,
    -
    38 Valid,
    -
    39 PhysicalConversionFailed
    -
    40};
    +
    32
    +
    + +
    35 InvalidDefinition,
    +
    36 InsufficientPayload,
    +
    37 SelectorUnavailable,
    +
    38 Inactive,
    +
    39 Valid,
    +
    40 PhysicalConversionFailed
    +
    41};
    -
    41
    -
    - -
    44 UnknownFrame,
    -
    45 InsufficientPayload,
    -
    46 SignalErrors,
    -
    47 Valid,
    -
    48 AmbiguousFrame
    -
    49};
    +
    42
    +
    + +
    45 UnknownFrame,
    +
    46 InsufficientPayload,
    +
    47 SignalErrors,
    +
    48 Valid,
    +
    49 AmbiguousFrame
    +
    50};
    -
    50
    -
    - -
    55 std::shared_ptr<const DecodeSignal> definition;
    - -
    57 RawSignalValue rawValue = std::uint64_t(0U);
    -
    58 double physicalValue = 0.0;
    -
    59 bool valid = false;
    -
    60 SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition;
    -
    -
    63 const std::string *GetValueDescription() const {
    -
    64 return valid && definition ? FindValueDescription(definition->valueDescriptions, rawValue) : nullptr;
    -
    65 }
    +
    51
    +
    + +
    56 std::shared_ptr<const DecodeSignal> definition;
    + +
    58 RawSignalValue rawValue = std::uint64_t(0U);
    +
    59 double physicalValue = 0.0;
    +
    60 bool valid = false;
    +
    61 SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition;
    +
    +
    64 const std::string *GetValueDescription() const {
    +
    65 return valid && definition ? FindValueDescription(definition->valueDescriptions, rawValue) : nullptr;
    +
    66 }
    -
    66
    -
    67 DecodedSignalValue() = default;
    -
    68};
    +
    67
    +
    68 DecodedSignalValue() = default;
    +
    69};
    -
    69
    -
    - -
    74 std::shared_ptr<const DecodeFrame> definition;
    - -
    76 std::vector<DecodedSignalValue> signals;
    -
    77 bool valid = false;
    -
    78 FrameDecodeStatus status = FrameDecodeStatus::UnknownFrame;
    -
    80 DecodedFrameValue() = default;
    -
    81};
    +
    70
    +
    + +
    75 std::shared_ptr<const DecodeFrame> definition;
    + +
    77 std::vector<DecodedSignalValue> signals;
    +
    78 bool valid = false;
    +
    79 FrameDecodeStatus status = FrameDecodeStatus::UnknownFrame;
    +
    81 DecodedFrameValue() = default;
    +
    82};
    +
    +
    83
    +
    + +
    88public:
    +
    96 std::shared_ptr<const DecodeFrame> FindFrame(const DecodeDatabase &database,
    +
    97 std::uint32_t canId,
    +
    98 bool isExtended) const;
    +
    99
    + +
    108 const RawCanFrame &frame) const;
    +
    109
    + +
    119 const RawCanFrame &frame,
    +
    120 const std::vector<SignalKey> &selection) const;
    +
    121
    +
    122private:
    +
    123 static PgnLookupResult ResolveFrame(const DecodeDatabase &database,
    +
    124 std::uint32_t canId, bool isExtended);
    +
    125
    +
    126 DecodedFrameValue DecodeImpl(const DecodeDatabase &database,
    +
    127 const RawCanFrame &frame,
    +
    128 const std::vector<SignalKey> *selection) const;
    +
    129
    +
    130 static bool IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc);
    +
    131
    +
    132 static SignalDecodeStatus ActivationStatus(std::size_t index,
    +
    133 const DecodeFrame &definition,
    +
    134 const RawCanFrame &frame,
    +
    135 const dbc_detail::MultiplexGraph &graph);
    +
    136 static DecodedSignalValue DecodeOneSignal(const DecodeSignal &signal,
    +
    137 std::uint8_t dlc,
    +
    138 const RawCanFrame &frame,
    +
    139 SignalDecodeStatus activation);
    +
    140
    +
    141 static bool ExtractUnsigned(const std::vector<std::uint8_t> &data,
    +
    142 const DecodeSignal &signal,
    +
    143 std::uint64_t &value);
    +
    144
    +
    145 static bool ExtractIntel(const std::vector<std::uint8_t> &data,
    +
    146 std::uint32_t startBit,
    +
    147 std::uint32_t length,
    +
    148 std::uint64_t &value);
    +
    149
    +
    150 static bool ExtractMotorola(const std::vector<std::uint8_t> &data,
    +
    151 std::uint32_t startBit,
    +
    152 std::uint32_t length,
    +
    153 std::uint64_t &value);
    +
    154
    +
    155 static std::int64_t SignExtend(std::uint64_t value, std::uint32_t bitLength);
    +
    156};
    -
    82
    -
    - -
    87public:
    -
    95 std::shared_ptr<const DecodeFrame> FindFrame(const DecodeDatabase &database,
    -
    96 std::uint32_t canId,
    -
    97 bool isExtended) const;
    -
    98
    - -
    107 const RawCanFrame &frame) const;
    -
    108
    - -
    118 const RawCanFrame &frame,
    -
    119 const std::vector<SignalKey> &selection) const;
    -
    120
    -
    121private:
    -
    122 static PgnLookupResult ResolveFrame(const DecodeDatabase &database,
    -
    123 std::uint32_t canId, bool isExtended);
    -
    124
    -
    125 DecodedFrameValue DecodeImpl(const DecodeDatabase &database,
    -
    126 const RawCanFrame &frame,
    -
    127 const std::vector<SignalKey> *selection) const;
    -
    128
    -
    129 static bool IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc);
    -
    130
    -
    131 struct SelectorState {
    -
    132 const DecodeSignal *definition = nullptr;
    -
    133 bool valid = false;
    -
    134 bool available = false;
    -
    135 std::uint64_t value = 0U;
    -
    136 };
    -
    137
    -
    138 static SelectorState ReadSelector(const DecodeFrame &definition, const RawCanFrame &frame);
    -
    139 static DecodedSignalValue DecodeOneSignal(const DecodeSignal &signal,
    -
    140 std::uint8_t dlc,
    -
    141 const RawCanFrame &frame,
    -
    142 const SelectorState &selector);
    -
    143
    -
    144 static bool ExtractUnsigned(const std::vector<std::uint8_t> &data,
    -
    145 const DecodeSignal &signal,
    -
    146 std::uint64_t &value);
    -
    147
    -
    148 static bool ExtractIntel(const std::vector<std::uint8_t> &data,
    -
    149 std::uint32_t startBit,
    -
    150 std::uint32_t length,
    -
    151 std::uint64_t &value);
    -
    152
    -
    153 static bool ExtractMotorola(const std::vector<std::uint8_t> &data,
    -
    154 std::uint32_t startBit,
    -
    155 std::uint32_t length,
    -
    156 std::uint64_t &value);
    157
    -
    158 static std::int64_t SignExtend(std::uint64_t value, std::uint32_t bitLength);
    -
    159};
    -
    -
    160
    -
    161#endif /* DBC_DECODER_H */
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    158#endif /* DBC_DECODER_H */
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
    Find exact CAN ID first, then unique PGN among explicitly J1939 definitions.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:33
    -
    FrameDecodeStatus
    Definition dbc_decoder.h:43
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    + +
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:34
    +
    FrameDecodeStatus
    Definition dbc_decoder.h:44
    Runtime definitions and immutable indexed database.
    -
    Runtime-ready frame definition.
    -
    Runtime-ready signal definition.
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    - -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    - -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    - -
    RawSignalValue rawValue
    Definition dbc_decoder.h:57
    - -
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:55
    -
    SignalDecodeStatus status
    Definition dbc_decoder.h:60
    - -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    Runtime-ready frame definition.
    +
    Runtime-ready signal definition.
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    + +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    + +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    + +
    RawSignalValue rawValue
    Definition dbc_decoder.h:58
    + +
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:56
    +
    SignalDecodeStatus status
    Definition dbc_decoder.h:61
    + +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64
    Stable frame identifier: normalized CAN ID and frame type.
    - -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    + +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    diff --git a/docs/html/dbc__decoder__test_8cpp_source.html b/docs/html/dbc__decoder__test_8cpp_source.html index dcb76c7..c522bc5 100644 --- a/docs/html/dbc__decoder__test_8cpp_source.html +++ b/docs/html/dbc__decoder__test_8cpp_source.html @@ -354,8 +354,8 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
    254 case 3: bad.startBit = std::numeric_limits<std::uint32_t>::max(); break;
    255 case 4: bad.byteOrder = static_cast<ByteOrder>(99); break;
    256 case 5: bad.valueType = static_cast<ValueType>(99); break;
    -
    257 case 6: bad.multiplexing.role = static_cast<MultiplexRole>(99); break;
    -
    258 case 7: bad.multiplexing.role = MultiplexRole::Branch; break;
    +
    257 case 6: bad.multiplexing.role = static_cast<MultiplexRole>(99); break;
    +
    258 case 7: bad.multiplexing.role = MultiplexRole::Branch; break;
    259 }
    260 definition.signals = {bad, good};
    261 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase({definition}));
    @@ -435,13 +435,13 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
    335 DecodeSignal selector;
    336 selector.name = "Selector";
    337 selector.length = 2U;
    -
    338 selector.multiplexing.role = MultiplexRole::Selector;
    +
    338 selector.multiplexing.role = MultiplexRole::Selector;
    339 selector.factor = std::numeric_limits<double>::max();
    340 DecodeSignal branch;
    341 branch.name = "Branch";
    342 branch.startBit = 2U;
    343 branch.length = 6U;
    -
    344 branch.multiplexing.role = MultiplexRole::Branch;
    +
    344 branch.multiplexing.role = MultiplexRole::Branch;
    345 branch.multiplexing.value = 2U;
    346 definition.signals = {branch, selector};
    347 RawCanFrame raw;
    @@ -481,46 +481,45 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
    381}
    382
    383#include "dbc_decoder_test.moc"
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    CAN frame decoding API and result types.
    -
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:33
    -
    FrameDecodeStatus
    Definition dbc_decoder.h:43
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    -
    ValueType
    Signal numeric type.
    -
    Runtime-ready frame definition.
    - -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    Runtime-ready signal definition.
    - -
    std::string name
    -
    ValueDescriptions valueDescriptions
    - -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    Multiplexing multiplexing
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    - -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    - -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    -
    RawSignalValue rawValue
    Definition dbc_decoder.h:57
    - -
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:55
    -
    SignalDecodeStatus status
    Definition dbc_decoder.h:60
    - -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:34
    +
    FrameDecodeStatus
    Definition dbc_decoder.h:44
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ValueType
    Signal numeric type.
    +
    Runtime-ready frame definition.
    + +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    Runtime-ready signal definition.
    + +
    std::string name
    +
    ValueDescriptions valueDescriptions
    + +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    Multiplexing multiplexing
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    + +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    + +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    +
    RawSignalValue rawValue
    Definition dbc_decoder.h:58
    + +
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:56
    +
    SignalDecodeStatus status
    Definition dbc_decoder.h:61
    + +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64
    Stable frame identifier: normalized CAN ID and frame type.
    -
    MultiplexRole role
    -
    std::uint64_t value
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    +
    std::uint64_t value
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    diff --git a/docs/html/dbc__lifetime__test_8cpp_source.html b/docs/html/dbc__lifetime__test_8cpp_source.html index 70ff69e..6790a37 100644 --- a/docs/html/dbc__lifetime__test_8cpp_source.html +++ b/docs/html/dbc__lifetime__test_8cpp_source.html @@ -344,43 +344,43 @@ $(document).ready(function(){initNavTree('dbc__lifetime__test_8cpp_source.html',
    244#include "dbc_lifetime_test.moc"
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
    Find exact CAN ID first, then unique PGN among explicitly J1939 definitions.
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    Runtime decode database builder.
    CAN frame decoding API and result types.
    -
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:33
    +
    SignalDecodeStatus
    Outcome of signal extraction and physical conversion.
    Definition dbc_decoder.h:34
    DBC file parser and interpretation options.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    -
    Runtime-ready frame definition.
    -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    Runtime-ready signal definition.
    -
    std::string name
    -
    std::uint32_t length
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    FrameKey key
    Definition dbc_decoder.h:75
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    -
    SignalKey key
    Definition dbc_decoder.h:56
    -
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:55
    -
    SignalDecodeStatus status
    Definition dbc_decoder.h:60
    -
    bool valid
    Definition dbc_decoder.h:59
    -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    Runtime-ready frame definition.
    +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    Runtime-ready signal definition.
    +
    std::string name
    +
    std::uint32_t length
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    FrameKey key
    Definition dbc_decoder.h:76
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    +
    SignalKey key
    Definition dbc_decoder.h:57
    +
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:56
    +
    SignalDecodeStatus status
    Definition dbc_decoder.h:61
    +
    bool valid
    Definition dbc_decoder.h:60
    +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    std::uint32_t canId
    Definition frame_info.h:27
    Stable frame identifier: normalized CAN ID and frame type.
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    diff --git a/docs/html/dbc__parser_8cpp_source.html b/docs/html/dbc__parser_8cpp_source.html index 1ffcf22..53110dd 100644 --- a/docs/html/dbc__parser_8cpp_source.html +++ b/docs/html/dbc__parser_8cpp_source.html @@ -109,9 +109,9 @@ $(document).ready(function(){initNavTree('dbc__parser_8cpp_source.html',''); ini
    19#include <utility>
    20
    21namespace {
    -
    22 // Read through the closing unescaped quote, preserving comment whitespace.
    -
    23 void ReadCommentLines(std::ifstream &input, std::string &statement,
    -
    24 std::size_t &lineNumber) {
    +
    22 // Attribute statements end at a semicolon outside quoted text.
    +
    23 void ReadAttributeLines(std::ifstream &input, std::string &statement,
    +
    24 std::size_t &lineNumber) {
    25 bool inQuote = false;
    26 bool escaped = false;
    27 std::string part = statement;
    @@ -122,138 +122,171 @@ $(document).ready(function(){initNavTree('dbc__parser_8cpp_source.html',''); ini
    32 } else if (inQuote && character == '\\') {
    33 escaped = true;
    34 } else if (character == '"') {
    -
    35 if (inQuote)
    -
    36 return;
    -
    37 inQuote = true;
    +
    35 inQuote = !inQuote;
    +
    36 } else if (!inQuote && character == ';') {
    +
    37 return;
    38 }
    39 }
    -
    40 if (!inQuote || !std::getline(input, part))
    +
    40 if (!std::getline(input, part))
    41 return;
    42 ++lineNumber;
    43 if (!part.empty() && part.back() == '\r')
    44 part.pop_back();
    45 statement += '\n';
    46 statement += part;
    -
    47 // A physical newline cannot escape the next line's first character.
    -
    48 escaped = false;
    -
    49 }
    -
    50 }
    -
    51
    -
    52 DbcDiagnosticCode StatementErrorCode(const std::string &keyword) {
    -
    53 if (keyword == "SG_MUL_VAL_")
    -
    54 return DbcDiagnosticCode::UnsupportedStatement;
    -
    55 if (keyword == "VAL_")
    -
    56 return DbcDiagnosticCode::InvalidValueDescription;
    -
    57 return DbcDiagnosticCode::InvalidStatement;
    -
    58 }
    -
    59}
    -
    60
    -
    -
    61DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
    - -
    63 for (const DbcDiagnostic &diagnostic : result.diagnostics) {
    -
    64 if (diagnostic.severity == DbcDiagnosticSeverity::Error) {
    -
    65 if (diagnostic.lineNumber == 0U)
    -
    66 throw std::runtime_error(diagnostic.message);
    -
    67 throw std::runtime_error(diagnostic.filePath + ":" +
    -
    68 std::to_string(diagnostic.lineNumber) + ": " + diagnostic.message);
    -
    69 }
    -
    70 }
    -
    71 return std::move(result.database);
    -
    72}
    +
    47 escaped = false;
    +
    48 }
    +
    49 }
    +
    50
    +
    51 // Read through the closing unescaped quote, preserving comment whitespace.
    +
    52 void ReadCommentLines(std::ifstream &input, std::string &statement,
    +
    53 std::size_t &lineNumber) {
    +
    54 bool inQuote = false;
    +
    55 bool escaped = false;
    +
    56 std::string part = statement;
    +
    57 for (;;) {
    +
    58 for (const char character: part) {
    +
    59 if (escaped) {
    +
    60 escaped = false;
    +
    61 } else if (inQuote && character == '\\') {
    +
    62 escaped = true;
    +
    63 } else if (character == '"') {
    +
    64 if (inQuote)
    +
    65 return;
    +
    66 inQuote = true;
    +
    67 }
    +
    68 }
    +
    69 if (!inQuote || !std::getline(input, part))
    +
    70 return;
    +
    71 ++lineNumber;
    +
    72 if (!part.empty() && part.back() == '\r')
    +
    73 part.pop_back();
    +
    74 statement += '\n';
    +
    75 statement += part;
    +
    76 // A physical newline cannot escape the next line's first character.
    +
    77 escaped = false;
    +
    78 }
    +
    79 }
    +
    80
    +
    81 DbcDiagnosticCode StatementErrorCode(const std::string &keyword) {
    +
    82 if (keyword == "SG_MUL_VAL_")
    +
    83 return DbcDiagnosticCode::InvalidMultiplexing;
    +
    84 if (keyword == "VAL_")
    +
    85 return DbcDiagnosticCode::InvalidValueDescription;
    +
    86 return DbcDiagnosticCode::InvalidStatement;
    +
    87 }
    +
    88}
    +
    89
    +
    +
    90DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
    + +
    92 for (const DbcDiagnostic &diagnostic : result.diagnostics) {
    +
    93 if (diagnostic.severity == DbcDiagnosticSeverity::Error) {
    +
    94 if (diagnostic.lineNumber == 0U)
    +
    95 throw std::runtime_error(diagnostic.message);
    +
    96 throw std::runtime_error(diagnostic.filePath + ":" +
    +
    97 std::to_string(diagnostic.lineNumber) + ": " + diagnostic.message);
    +
    98 }
    +
    99 }
    +
    100 return std::move(result.database);
    +
    101}
    -
    73
    -
    -
    74DbcParseResult DbcParser::ParseFileWithDiagnostics(const std::string &filePath) const {
    -
    75 DbcParseResult result;
    -
    76 std::ifstream input(filePath.c_str());
    -
    77 if (!input.is_open()) {
    -
    78 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    -
    79 DbcDiagnosticCode::FileOpenError, filePath, 0U,
    -
    80 "Failed to open DBC file: " + filePath});
    -
    81 return result;
    -
    82 }
    -
    83
    -
    84 DbcDatabase database;
    -
    85 DbcParseContext context{database, nullptr};
    -
    86 context.enableJ1939 = options.enableJ1939;
    -
    87 const DbcStatementDispatcher dispatcher;
    -
    88 bool inNamespace = false;
    -
    89 std::size_t lineNumber = 0U;
    -
    90 std::string line;
    -
    91 while (std::getline(input, line)) {
    -
    92 ++lineNumber;
    -
    93 if (!line.empty() && line.back() == '\r')
    -
    94 line.pop_back();
    -
    95 const std::string rawLine = line;
    -
    96 const std::size_t statementLine = lineNumber;
    -
    97 line = dbc_detail::TrimText(line);
    -
    98 if (line.empty())
    -
    99 continue;
    -
    100
    -
    101 std::istringstream tokens(line);
    -
    102 std::string keyword;
    -
    103 std::string argument;
    -
    104 tokens >> keyword;
    -
    105 const bool hasArgument = static_cast<bool>(tokens >> argument);
    -
    106 if (inNamespace && !hasArgument && keyword != "BO_" && keyword != "SG_" &&
    -
    107 keyword != "BS_" && keyword != "BS_:" &&
    -
    108 keyword != "BU_" && keyword != "BU_:")
    -
    109 continue; // NS_ lists syntax symbols; BO_, SG_, BS_ and BU_ end the list.
    -
    110 inNamespace = keyword == "NS_" || keyword == "NS_:";
    -
    111
    -
    112 if (keyword == "CM_") {
    -
    113 line = rawLine;
    -
    114 ReadCommentLines(input, line, lineNumber);
    -
    115 }
    -
    116
    -
    117 try {
    -
    118 context.lineNumber = statementLine;
    -
    119 if (!dispatcher.Dispatch(line, context)) {
    -
    120 result.diagnostics.push_back({DbcDiagnosticSeverity::Warning,
    -
    121 DbcDiagnosticCode::UnsupportedStatement,
    -
    122 filePath, statementLine,
    -
    123 "Unsupported statement '" + keyword +
    -
    124 "' is ignored; decoding or metadata may be incomplete."});
    -
    125 }
    -
    126 } catch (const std::exception &error) {
    -
    127 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    -
    128 StatementErrorCode(keyword), filePath,
    -
    129 statementLine, error.what()});
    -
    130 return result;
    -
    131 }
    -
    132 }
    -
    133
    -
    134 if (input.bad() || !input.eof()) {
    -
    135 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    -
    136 DbcDiagnosticCode::FileReadError, filePath, 0U,
    -
    137 "Failed to read DBC file: " + filePath});
    -
    138 return result;
    -
    139 }
    +
    102
    +
    +
    103DbcParseResult DbcParser::ParseFileWithDiagnostics(const std::string &filePath) const {
    +
    104 DbcParseResult result;
    +
    105 std::ifstream input(filePath.c_str());
    +
    106 if (!input.is_open()) {
    +
    107 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    +
    108 DbcDiagnosticCode::FileOpenError, filePath, 0U,
    +
    109 "Failed to open DBC file: " + filePath});
    +
    110 return result;
    +
    111 }
    +
    112
    +
    113 DbcDatabase database;
    +
    114 DbcParseContext context{database, nullptr};
    +
    115 context.enableJ1939 = options.enableJ1939;
    +
    116 const DbcStatementDispatcher dispatcher;
    +
    117 bool inNamespace = false;
    +
    118 std::size_t lineNumber = 0U;
    +
    119 std::string line;
    +
    120 while (std::getline(input, line)) {
    +
    121 ++lineNumber;
    +
    122 if (!line.empty() && line.back() == '\r')
    +
    123 line.pop_back();
    +
    124 const std::string rawLine = line;
    +
    125 const std::size_t statementLine = lineNumber;
    +
    126 line = dbc_detail::TrimText(line);
    +
    127 if (line.empty())
    +
    128 continue;
    +
    129
    +
    130 std::istringstream tokens(line);
    +
    131 std::string keyword;
    +
    132 std::string argument;
    +
    133 tokens >> keyword;
    +
    134 const bool hasArgument = static_cast<bool>(tokens >> argument);
    +
    135 if (inNamespace && !hasArgument && keyword != "BO_" && keyword != "SG_" &&
    +
    136 keyword != "BS_" && keyword != "BS_:" &&
    +
    137 keyword != "BU_" && keyword != "BU_:")
    +
    138 continue; // NS_ lists syntax symbols; BO_, SG_, BS_ and BU_ end the list.
    +
    139 inNamespace = keyword == "NS_" || keyword == "NS_:";
    140
    -
    141 try {
    -
    142 context.ResolveComments(filePath);
    -
    143 context.ResolveValueDescriptions(filePath);
    -
    144 context.ValidateMultiplexing(filePath);
    -
    145 context.ResolveAttributes(filePath, result.diagnostics);
    -
    146 } catch (const DbcDiagnosticError &error) {
    -
    147 result.diagnostics.push_back(error.diagnostic);
    -
    148 return result;
    -
    149 }
    -
    150 result.database = std::move(database);
    -
    151 return result;
    -
    152}
    +
    141 if (keyword == "CM_") {
    +
    142 line = rawLine;
    +
    143 ReadCommentLines(input, line, lineNumber);
    +
    144 } else if (keyword == "BA_DEF_" || keyword == "BA_DEF_DEF_" || keyword == "BA_") {
    +
    145 line = rawLine.substr(rawLine.find(keyword));
    +
    146 ReadAttributeLines(input, line, lineNumber);
    +
    147 }
    +
    148
    +
    149 try {
    +
    150 context.lineNumber = statementLine;
    +
    151 if (!dispatcher.Dispatch(line, context)) {
    +
    152 result.diagnostics.push_back({DbcDiagnosticSeverity::Warning,
    +
    153 DbcDiagnosticCode::UnsupportedStatement,
    +
    154 filePath, statementLine,
    +
    155 "Unsupported statement '" + keyword +
    +
    156 "' is ignored; decoding or metadata may be incomplete."});
    +
    157 }
    +
    158 } catch (const std::exception &error) {
    +
    159 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    +
    160 StatementErrorCode(keyword), filePath,
    +
    161 statementLine, error.what()});
    +
    162 return result;
    +
    163 }
    +
    164 }
    +
    165
    +
    166 if (input.bad() || !input.eof()) {
    +
    167 result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
    +
    168 DbcDiagnosticCode::FileReadError, filePath, 0U,
    +
    169 "Failed to read DBC file: " + filePath});
    +
    170 return result;
    +
    171 }
    +
    172
    +
    173 try {
    +
    174 context.ResolveComments(filePath);
    +
    175 context.ResolveValueDescriptions(filePath);
    +
    176 context.ResolveMultiplexing(filePath);
    +
    177 context.ValidateMultiplexing(filePath);
    +
    178 context.ResolveAttributes(filePath, result.diagnostics);
    +
    179 } catch (const DbcDiagnosticError &error) {
    +
    180 result.diagnostics.push_back(error.diagnostic);
    +
    181 return result;
    +
    182 }
    +
    183 result.database = std::move(database);
    +
    184 return result;
    +
    185}
    -
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    - -
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    +
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    + +
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    DBC file parser and interpretation options.
    Parsed DBC content stored in a simple internal form.
    Diagnostic message and physical source location.
    - +
    Parsed database and diagnostics; the database is empty on error.
    std::vector< DbcDiagnostic > diagnostics
    DbcDatabase database
    diff --git a/docs/html/dbc__parser_8h_source.html b/docs/html/dbc__parser_8h_source.html index de40db0..8587103 100644 --- a/docs/html/dbc__parser_8h_source.html +++ b/docs/html/dbc__parser_8h_source.html @@ -112,25 +112,25 @@ $(document).ready(function(){initNavTree('dbc__parser_8h_source.html',''); initR
    22};
    23
    -
    -
    41class DbcParser {
    -
    42public:
    -
    44 explicit DbcParser(DbcParserOptions options = {}) : options(options) {}
    -
    45
    -
    55 DbcDatabase ParseFile(const std::string &filePath) const;
    -
    56
    -
    63 DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const;
    -
    64
    -
    65private:
    -
    66 DbcParserOptions options;
    -
    67};
    +
    +
    43class DbcParser {
    +
    44public:
    +
    46 explicit DbcParser(DbcParserOptions options = {}) : options(options) {}
    +
    47
    +
    57 DbcDatabase ParseFile(const std::string &filePath) const;
    +
    58
    +
    65 DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const;
    +
    66
    +
    67private:
    +
    68 DbcParserOptions options;
    +
    69};
    -
    68
    -
    69#endif /* DBC_PARSER_H */
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    -
    DbcParser(DbcParserOptions options={})
    Create a parser with explicit extended-frame interpretation options.
    Definition dbc_parser.h:44
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    +
    70
    +
    71#endif /* DBC_PARSER_H */
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    +
    DbcParser(DbcParserOptions options={})
    Create a parser with explicit extended-frame interpretation options.
    Definition dbc_parser.h:46
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    Parsed DBC content stored in a simple internal form.
    Parsed database and diagnostics; the database is empty on error.
    diff --git a/docs/html/dbc__parser__test_8cpp_source.html b/docs/html/dbc__parser__test_8cpp_source.html index 76e0ff7..323a829 100644 --- a/docs/html/dbc__parser__test_8cpp_source.html +++ b/docs/html/dbc__parser__test_8cpp_source.html @@ -189,1233 +189,1506 @@ $(document).ready(function(){initNavTree('dbc__parser__test_8cpp_source.html',''
    89 }
    90private Q_SLOTS:
    91 void attributes();
    -
    92 void invalidAttributes();
    -
    93 void attributeNumbers();
    -
    94 void invalidAttributeNumbers_data();
    -
    95 void invalidAttributeNumbers();
    -
    96 void attributeWarnings();
    -
    97 void diagnostics();
    -
    98 void diagnosticErrors();
    -
    99 void diagnosticUnsupportedStatements();
    -
    100 void diagnosticNamespaceBoundaries();
    -
    101 void diagnosticFormatting();
    -
    102 void multiplexing();
    -
    103 void multiplexingBoundaries();
    -
    104 void validFrames();
    -
    105 void invalidFrames();
    -
    106 void duplicateFrames();
    -
    107 void duplicateSignals();
    -
    108 void distinctDefinitions();
    -
    109 void comments();
    -
    110 void invalidComments_data();
    -
    111 void invalidComments();
    -
    112 void integration();
    -
    113 void invalidSignals();
    -
    114 void validSignals();
    -
    115 void physicalNumbersCppLocale();
    -
    116 void physicalNumbersCLocale();
    -
    117 void dispatch();
    -
    118 void independentSessions();
    -
    119 void valueDescriptions();
    -
    120 void invalidValueDescriptions();
    -
    121};
    -
    122
    -
    123void DbcParserTest::attributes() {
    -
    124 Fixture fixture;
    -
    125 fixture.Write(
    -
    126 "BA_ \"GenMsgCycleTime\" BO_ 1 25;\n"
    -
    127 "BA_ \"VFrameFormat\" BO_ 2147483649 1;\n"
    -
    128 "BA_ \"Label\" SG_ 1 Value \"a\\\"b\\\\c\";\n"
    -
    129 "BA_ \"NodeLabel\" BU_ ECU \"node\";\n"
    -
    130 "BA_ \"Environment\" EV_ Env 2;\n"
    -
    131 "BA_DEF_DEF_ \"GenMsgCycleTime\" 100;\n"
    -
    132 "BA_DEF_DEF_ \"VFrameFormat\" \"StandardCAN\";\n"
    -
    133 "BA_DEF_DEF_ \"Label\" \"default\";\n"
    -
    134 "BA_DEF_DEF_ \"BusLabel\" \"CAN\";\n"
    -
    135 "BA_DEF_DEF_ \"Ratio\" 1.5e-1;\n"
    -
    136 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 10000;\n"
    -
    137 "BA_DEF_ BO_ \"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"StandardCAN_FD\";\n"
    -
    138 "BA_DEF_ SG_ \"Label\" STRING;\n"
    -
    139 "BA_DEF_ \"BusLabel\" STRING;\n"
    -
    140 "BA_DEF_ BO_ \"Ratio\" FLOAT -1 1;\n"
    -
    141 "BA_DEF_ BU_ \"NodeLabel\" STRING;\n"
    -
    142 "BA_DEF_ EV_ \"Environment\" HEX 0 255;\n"
    -
    143 "BO_ 1 Standard: 1 ECU\n"
    -
    144 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    145 "BO_ 2147483649 Extended: 1 ECU\n"
    -
    146 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n");
    -
    147 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    148 QVERIFY(!result.HasErrors());
    -
    149 QVERIFY(result.diagnostics.empty());
    -
    150 const DbcDatabase &database = result.database;
    -
    151 QCOMPARE(database.attributeDefinitions.size(), std::size_t(7));
    -
    152 QCOMPARE(database.attributeAssignments.size(), std::size_t(5));
    -
    153 QCOMPARE(std::get<std::string>(database.attributes.at("BusLabel")), std::string("CAN"));
    -
    154 QCOMPARE(database.frames[0].cycleTimeMs.value(), 25U);
    -
    155 QCOMPARE(database.frames[1].cycleTimeMs.value(), 100U);
    -
    156 QCOMPARE(database.frames[1].frameFormat.value(), std::string("ExtendedCAN"));
    -
    157 QVERIFY(!database.frames[1].hasPgn);
    -
    158 QCOMPARE(std::get<double>(database.frames[0].attributes.at("Ratio")), 0.15);
    -
    159 QCOMPARE(std::get<std::string>(database.frames[0].signals[0].attributes.at("Label")), std::string("a\"b\\c"));
    -
    160 QCOMPARE(std::get<std::string>(database.frames[1].signals[0].attributes.at("Label")), std::string("default"));
    -
    161 const DecodeDatabase runtime = DbcDecodeBuilder().Build(database);
    -
    162 QCOMPARE(runtime.GetFrames()[0].cycleTimeMs.value(), 25U);
    -
    163 QCOMPARE(runtime.GetFrames()[1].frameFormat.value(), std::string("ExtendedCAN"));
    -
    164 QCOMPARE(runtime.GetFrames()[0].signals[0].attributes, database.frames[0].signals[0].attributes);
    -
    165 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(database);
    -
    166 QCOMPARE(tree->GetChild(0)->GetFrame()->cycleTimeMs.value(), 25U);
    -
    167 QCOMPARE(tree->GetChild(0)->GetChild(0)->GetSignal()->attributes, database.frames[0].signals[0].attributes);
    -
    168 fixture.Write("BA_DEF_ BO_ \"Period\" INT 0 10;\nBA_DEF_DEF_ \"Period\" 1;\n"
    -
    169 "BA_ \"Period\" BO_ 1 2;\nBA_ \"Period\" BO_ 1 3;\nBO_ 1 F: 0 ECU\n");
    -
    170 const DbcDatabase repeated = DbcParser().ParseFile(fixture.path.string());
    -
    171 QCOMPARE(std::get<std::int64_t>(repeated.frames[0].attributes.at("Period")), std::int64_t(3));
    -
    172
    -
    173 fixture.Write("BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 4294967295;\n"
    -
    174 "BA_DEF_DEF_ \"GenMsgCycleTime\" 0;\n"
    -
    175 "BA_ \"GenMsgCycleTime\" BO_ 1 4294967295;\n"
    -
    176 "BA_DEF_ \"Wide\" INT -9223372036854775808 9223372036854775807;\n"
    -
    177 "BA_DEF_DEF_ \"Wide\" -9223372036854775808;\n"
    -
    178 "BA_DEF_ SG_ \"State\" ENUM \"off\",\"on\";\n"
    -
    179 "BA_DEF_DEF_ \"State\" 1;\n"
    -
    180 "BO_ 1 F: 0 ECU\nBO_ 2 Empty: 0 ECU\n");
    -
    181 const DbcDatabase boundaries = DbcParser().ParseFile(fixture.path.string());
    -
    182 QCOMPARE(boundaries.frames[0].cycleTimeMs.value(), std::numeric_limits<std::uint32_t>::max());
    -
    183 QCOMPARE(boundaries.frames[1].cycleTimeMs.value(), 0U);
    -
    184 QVERIFY(!boundaries.frames[0].frameFormat);
    -
    185 QCOMPARE(std::get<std::int64_t>(boundaries.attributes.at("Wide")), std::numeric_limits<std::int64_t>::min());
    -
    186 QCOMPARE(std::get<std::int64_t>(*boundaries.attributeDefinitions.at("State").defaultValue), std::int64_t(1));
    -
    187}
    -
    188
    -
    189void DbcParserTest::invalidAttributes() {
    -
    190 Fixture fixture;
    -
    191 const std::vector<std::string> invalid = {
    -
    192 "BA_DEF_ BO_ \"A\"STRING;",
    -
    193 "BA_DEF_ BO_\"A\" STRING;",
    -
    194 "BA_DEF_ BO_ \"A\" \"STRING\";",
    -
    195 "BA_DEF_ BO_ A STRING;",
    -
    196 "BA_DEF_ ZZ_ \"A\" STRING;",
    -
    197 "BA_DEF_ BO_ \"A\" BLOB;",
    -
    198 "BA_DEF_ BO_ \"A\" FLOAT 2 1;",
    -
    199 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 0;",
    -
    200 "BA_DEF_ BO_ \"A\" FLOAT 0 1;\nBA_ \"A\" BO_ 1 2;",
    -
    201 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ -1 0;",
    -
    202 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 4294967296 0;",
    -
    203 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 536870912 0;",
    -
    204 "BA_DEF_ BO_ \"A\" INT 2 1;",
    -
    205 "BA_DEF_ BO_ \"A\" FLOAT nan 1;",
    -
    206 "BA_DEF_ BO_ \"A\" FLOAT 0 inf;",
    -
    207 "BA_DEF_ BO_ \"A\" INT 0 9223372036854775808;",
    -
    208 "BA_DEF_ BO_ \"A\" STRING; trailing",
    -
    209 "BA_DEF_ BO_ \"A\" ENUM;",
    -
    210 "BA_DEF_ BO_ \"A\" ENUM \"one\",;",
    -
    211 "BA_DEF_ BO_ \"A\" ENUM \"one\",\"one\";",
    -
    212 "BA_DEF_ BO_ \"VFrameFormat\" STRING;",
    -
    213 "BA_DEF_ SG_ \"GenMsgCycleTime\" INT 0 10;",
    -
    214 "BA_ \"Unknown\" BO_ 1 0;",
    -
    215 "BA_DEF_DEF_ \"Unknown\" 0;",
    -
    216 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 1 2;",
    -
    217 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 1 \"0\";",
    -
    218 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" SG_ 1 S 0;",
    -
    219 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 2 0;",
    -
    220 "BA_DEF_ SG_ \"A\" INT 0 1;\nBA_ \"A\" SG_ 1 Missing 0;",
    -
    221 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_DEF_ BO_ \"A\" INT 0 1;",
    -
    222 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_DEF_DEF_ \"A\" 0;\nBA_DEF_DEF_ \"A\" 1;",
    -
    223 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 \"bad\\q\";",
    -
    224 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 \"unterminated;",
    -
    225 "BA_DEF_ BO_ \"A\" ENUM \"one\";\nBA_DEF_DEF_ \"A\" \"missing\";",
    -
    226 "BA_DEF_ BO_ \"A\" ENUM \"one\";\nBA_ \"A\" BO_ 1 1;",
    -
    227 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT -1 4294967296;\nBA_DEF_DEF_ \"GenMsgCycleTime\" -1;",
    -
    228 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 4294967296;\nBA_ \"GenMsgCycleTime\" BO_ 1 4294967296;"};
    -
    229 for (const std::string &statement: invalid) {
    -
    230 fixture.Write("BO_ 1 F: 0 ECU\n" + statement + '\n');
    -
    231 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    232 QVERIFY2(result.HasErrors(), statement.c_str());
    -
    233 QVERIFY(result.database.frames.empty());
    -
    234 QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
    -
    235 QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(2 + std::count(statement.begin(), statement.end(), '\n')));
    -
    236 QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
    -
    237 }
    -
    238}
    +
    92 void multilineAttributes();
    +
    93 void invalidMultilineAttributes();
    +
    94 void invalidAttributes();
    +
    95 void attributeNumbers();
    +
    96 void invalidAttributeNumbers_data();
    +
    97 void invalidAttributeNumbers();
    +
    98 void attributeWarnings();
    +
    99 void diagnostics();
    +
    100 void diagnosticErrors();
    +
    101 void diagnosticUnsupportedStatements();
    +
    102 void diagnosticNamespaceBoundaries();
    +
    103 void diagnosticFormatting();
    +
    104 void multiplexing();
    +
    105 void multiplexingBoundaries();
    +
    106 void extendedMultiplexing();
    +
    107 void extendedMultiplexingErrors();
    +
    108 void validFrames();
    +
    109 void invalidFrames();
    +
    110 void duplicateFrames();
    +
    111 void duplicateSignals();
    +
    112 void distinctDefinitions();
    +
    113 void comments();
    +
    114 void invalidComments_data();
    +
    115 void invalidComments();
    +
    116 void integration();
    +
    117 void invalidSignals();
    +
    118 void validSignals();
    +
    119 void physicalNumbersCppLocale();
    +
    120 void physicalNumbersCLocale();
    +
    121 void dispatch();
    +
    122 void independentSessions();
    +
    123 void valueDescriptions();
    +
    124 void invalidValueDescriptions();
    +
    125};
    +
    126
    +
    127void DbcParserTest::attributes() {
    +
    128 Fixture fixture;
    +
    129 fixture.Write(
    +
    130 "BA_ \"GenMsgCycleTime\" BO_ 1 25;\n"
    +
    131 "BA_ \"VFrameFormat\" BO_ 2147483649 1;\n"
    +
    132 "BA_ \"Label\" SG_ 1 Value \"a\\\"b\\\\c\";\n"
    +
    133 "BA_ \"NodeLabel\" BU_ ECU \"node\";\n"
    +
    134 "BA_ \"Environment\" EV_ Env 2;\n"
    +
    135 "BA_DEF_DEF_ \"GenMsgCycleTime\" 100;\n"
    +
    136 "BA_DEF_DEF_ \"VFrameFormat\" \"StandardCAN\";\n"
    +
    137 "BA_DEF_DEF_ \"Label\" \"default\";\n"
    +
    138 "BA_DEF_DEF_ \"BusLabel\" \"CAN\";\n"
    +
    139 "BA_DEF_DEF_ \"Ratio\" 1.5e-1;\n"
    +
    140 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 10000;\n"
    +
    141 "BA_DEF_ BO_ \"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"StandardCAN_FD\";\n"
    +
    142 "BA_DEF_ SG_ \"Label\" STRING;\n"
    +
    143 "BA_DEF_ \"BusLabel\" STRING;\n"
    +
    144 "BA_DEF_ BO_ \"Ratio\" FLOAT -1 1;\n"
    +
    145 "BA_DEF_ BU_ \"NodeLabel\" STRING;\n"
    +
    146 "BA_DEF_ EV_ \"Environment\" HEX 0 255;\n"
    +
    147 "BO_ 1 Standard: 1 ECU\n"
    +
    148 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    149 "BO_ 2147483649 Extended: 1 ECU\n"
    +
    150 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n");
    +
    151 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    152 QVERIFY(!result.HasErrors());
    +
    153 QVERIFY(result.diagnostics.empty());
    +
    154 const DbcDatabase &database = result.database;
    +
    155 QCOMPARE(database.attributeDefinitions.size(), std::size_t(7));
    +
    156 QCOMPARE(database.attributeAssignments.size(), std::size_t(5));
    +
    157 QCOMPARE(std::get<std::string>(database.attributes.at("BusLabel")), std::string("CAN"));
    +
    158 QCOMPARE(database.frames[0].cycleTimeMs.value(), 25U);
    +
    159 QCOMPARE(database.frames[1].cycleTimeMs.value(), 100U);
    +
    160 QCOMPARE(database.frames[1].frameFormat.value(), std::string("ExtendedCAN"));
    +
    161 QVERIFY(!database.frames[1].hasPgn);
    +
    162 QCOMPARE(std::get<double>(database.frames[0].attributes.at("Ratio")), 0.15);
    +
    163 QCOMPARE(std::get<std::string>(database.frames[0].signals[0].attributes.at("Label")), std::string("a\"b\\c"));
    +
    164 QCOMPARE(std::get<std::string>(database.frames[1].signals[0].attributes.at("Label")), std::string("default"));
    +
    165 const DecodeDatabase runtime = DbcDecodeBuilder().Build(database);
    +
    166 QCOMPARE(runtime.GetFrames()[0].cycleTimeMs.value(), 25U);
    +
    167 QCOMPARE(runtime.GetFrames()[1].frameFormat.value(), std::string("ExtendedCAN"));
    +
    168 QCOMPARE(runtime.GetFrames()[0].signals[0].attributes, database.frames[0].signals[0].attributes);
    +
    169 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(database);
    +
    170 QCOMPARE(tree->GetChild(0)->GetFrame()->cycleTimeMs.value(), 25U);
    +
    171 QCOMPARE(tree->GetChild(0)->GetChild(0)->GetSignal()->attributes, database.frames[0].signals[0].attributes);
    +
    172 fixture.Write("BA_DEF_ BO_ \"Period\" INT 0 10;\nBA_DEF_DEF_ \"Period\" 1;\n"
    +
    173 "BA_ \"Period\" BO_ 1 2;\nBA_ \"Period\" BO_ 1 3;\nBO_ 1 F: 0 ECU\n");
    +
    174 const DbcDatabase repeated = DbcParser().ParseFile(fixture.path.string());
    +
    175 QCOMPARE(std::get<std::int64_t>(repeated.frames[0].attributes.at("Period")), std::int64_t(3));
    +
    176
    +
    177 fixture.Write("BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 4294967295;\n"
    +
    178 "BA_DEF_DEF_ \"GenMsgCycleTime\" 0;\n"
    +
    179 "BA_ \"GenMsgCycleTime\" BO_ 1 4294967295;\n"
    +
    180 "BA_DEF_ \"Wide\" INT -9223372036854775808 9223372036854775807;\n"
    +
    181 "BA_DEF_DEF_ \"Wide\" -9223372036854775808;\n"
    +
    182 "BA_DEF_ SG_ \"State\" ENUM \"off\",\"on\";\n"
    +
    183 "BA_DEF_DEF_ \"State\" 1;\n"
    +
    184 "BO_ 1 F: 0 ECU\nBO_ 2 Empty: 0 ECU\n");
    +
    185 const DbcDatabase boundaries = DbcParser().ParseFile(fixture.path.string());
    +
    186 QCOMPARE(boundaries.frames[0].cycleTimeMs.value(), std::numeric_limits<std::uint32_t>::max());
    +
    187 QCOMPARE(boundaries.frames[1].cycleTimeMs.value(), 0U);
    +
    188 QVERIFY(!boundaries.frames[0].frameFormat);
    +
    189 QCOMPARE(std::get<std::int64_t>(boundaries.attributes.at("Wide")), std::numeric_limits<std::int64_t>::min());
    +
    190 QCOMPARE(std::get<std::int64_t>(*boundaries.attributeDefinitions.at("State").defaultValue), std::int64_t(1));
    +
    191}
    +
    192
    +
    193void DbcParserTest::multilineAttributes() {
    +
    194 Fixture fixture;
    +
    195 fixture.Write(R"DBC(BA_
    +
    196 "GenMsgCycleTime" BO_ 1
    +
    197 25;
    +
    198BA_DEF_ BO_ "VFrameFormat" ENUM
    +
    199 "StandardCAN",
    +
    200 "StandardCAN_FD";
    +
    201BA_DEF_DEF_
    +
    202 "VFrameFormat"
    +
    203 "StandardCAN_FD";
    +
    204BA_DEF_ BO_ "GenMsgCycleTime"
    +
    205 INT 0 100;
    +
    206BA_DEF_DEF_ "GenMsgCycleTime"
    +
    207 50;
    +
    208BA_DEF_ SG_ "Label" STRING;
    +
    209BA_ "Label" SG_ 1 Value
    +
    210 "first; \"quoted\"
    +
    211second\\path";
    +
    212BA_ "VFrameFormat" BO_ 1
    +
    213 0;
    +
    214BO_ 1 F: 1 ECU
    +
    215SG_ Value : 0|8@1+ (1,0) [0|255] "" ECU
    +
    216BO_ 2 Default: 0 ECU
    +
    217)DBC");
    +
    218 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    219 QVERIFY(!result.HasErrors());
    +
    220 QCOMPARE(result.database.frames.size(), std::size_t(2));
    +
    221 QCOMPARE(result.database.frames[0].cycleTimeMs.value(), 25U);
    +
    222 QCOMPARE(result.database.frames[1].cycleTimeMs.value(), 50U);
    +
    223 QCOMPARE(result.database.frames[0].frameFormat.value(), std::string("StandardCAN"));
    +
    224 QCOMPARE(result.database.frames[1].frameFormat.value(), std::string("StandardCAN_FD"));
    +
    225 QCOMPARE(std::get<std::string>(result.database.frames[0].signals[0].attributes.at("Label")),
    +
    226 std::string("first; \"quoted\"\nsecond\\path"));
    +
    227 QCOMPARE(result.diagnostics.size(), std::size_t(1));
    +
    228 QCOMPARE(result.diagnostics[0].code, DbcDiagnosticCode::UnsupportedAttribute);
    +
    229 QCOMPARE(result.diagnostics[0].lineNumber, std::size_t(7));
    +
    230
    +
    231 fixture.Write("BA_DEF_ BO_ \"VFrameFormat\" ENUM\r\n \"StandardCAN\",\r\n \"ExtendedCAN_FD\";\r\n"
    +
    232 "BA_\r\n \"VFrameFormat\" BO_ 1\r\n 1;\r\nBO_ 1 F: 0 ECU\r\n");
    +
    233 const DbcParseResult explicitFormat = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    234 QVERIFY(!explicitFormat.HasErrors());
    +
    235 QCOMPARE(explicitFormat.diagnostics.size(), std::size_t(1));
    +
    236 QCOMPARE(explicitFormat.diagnostics[0].code, DbcDiagnosticCode::UnsupportedAttribute);
    +
    237 QCOMPARE(explicitFormat.diagnostics[0].lineNumber, std::size_t(4));
    +
    238 QCOMPARE(explicitFormat.database.frames[0].frameFormat.value(), std::string("ExtendedCAN_FD"));
    239
    -
    240void DbcParserTest::attributeNumbers() {
    -
    241 ApplicationLocaleGuard guard;
    -
    242 std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
    -
    243 Fixture fixture;
    -
    244 fixture.Write("BA_DEF_ \"I\" INT -9223372036854775808 +9223372036854775807;\n"
    -
    245 "BA_DEF_DEF_ \"I\" -9223372036854775808;\n"
    -
    246 "BA_ \"I\" +9223372036854775807;\n"
    -
    247 "BA_DEF_ \"H\" HEX -10 +10;\n"
    -
    248 "BA_DEF_DEF_ \"H\" +0;\n"
    -
    249 "BA_ \"H\" -10;\n"
    -
    250 "BA_DEF_ \"F\" FLOAT -1.25e+2 +2.5E2;\n"
    -
    251 "BA_DEF_DEF_ \"F\" +.5;\n"
    -
    252 "BA_ \"F\" -1.25e+2;\n"
    -
    253 "BA_DEF_ BU_ \"NodeDefault\" INT 0 10;\n"
    -
    254 "BA_DEF_DEF_ \"NodeDefault\" 5;\n"
    -
    255 "BA_DEF_ EV_ \"EnvironmentDefault\" STRING;\n"
    -
    256 "BA_DEF_DEF_ \"EnvironmentDefault\" \"default\";\n");
    -
    257 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    258 QVERIFY(!result.HasErrors());
    -
    259 QVERIFY(result.diagnostics.empty());
    -
    260 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("I").defaultValue), std::numeric_limits<std::int64_t>::min());
    -
    261 QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("I")), std::numeric_limits<std::int64_t>::max());
    -
    262 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("H").defaultValue), std::int64_t(0));
    -
    263 QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("H")), std::int64_t(-10));
    -
    264 QCOMPARE(std::get<double>(*result.database.attributeDefinitions.at("F").defaultValue), 0.5);
    -
    265 QCOMPARE(std::get<double>(result.database.attributes.at("F")), -125.0);
    -
    266 QCOMPARE(result.database.attributes.size(), std::size_t(3));
    -
    267 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("NodeDefault").defaultValue), std::int64_t(5));
    -
    268 QCOMPARE(std::get<std::string>(*result.database.attributeDefinitions.at("EnvironmentDefault").defaultValue), std::string("default"));
    +
    240 fixture.Write("BA_DEF_ \"Text\" STRING;\n BA_ \"Text\" \"first \nsecond\";\n"
    +
    241 "UnsupportedStatement\n");
    +
    242 const DbcParseResult whitespace = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    243 QVERIFY(!whitespace.HasErrors());
    +
    244 QCOMPARE(std::get<std::string>(whitespace.database.attributes.at("Text")), std::string("first \nsecond"));
    +
    245 QCOMPARE(whitespace.diagnostics.size(), std::size_t(1));
    +
    246 QCOMPARE(whitespace.diagnostics[0].code, DbcDiagnosticCode::UnsupportedStatement);
    +
    247 QCOMPARE(whitespace.diagnostics[0].lineNumber, std::size_t(4));
    +
    248}
    +
    249
    +
    250void DbcParserTest::invalidMultilineAttributes() {
    +
    251 Fixture fixture;
    +
    252 const std::vector<std::string> invalid = {
    +
    253 "BA_DEF_\n BO_ \"A\" INT\n 10 0;\n",
    +
    254 "BA_DEF_ BO_ \"A\" ENUM\n \"one\",\n;\n",
    +
    255 "BA_DEF_ BO_ \"A\" STRING\n",
    +
    256 "BA_DEF_ BO_ \"A\" ENUM\n \"unterminated;\n",
    +
    257 "BA_DEF_DEF_\n \"Unknown\"\n 0;\n",
    +
    258 "BA_\n \"Unknown\" BO_ 1\n 0;\n",
    +
    259 "BA_DEF_ BO_ \"A\" STRING\n ; trailing\n"};
    +
    260 for (const std::string &statement: invalid) {
    +
    261 fixture.Write("BO_ 1 F: 0 ECU\n" + statement);
    +
    262 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    263 QVERIFY2(result.HasErrors(), statement.c_str());
    +
    264 QVERIFY(result.database.frames.empty());
    +
    265 QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
    +
    266 QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(2));
    +
    267 QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
    +
    268 }
    269}
    270
    -
    271void DbcParserTest::invalidAttributeNumbers_data() {
    -
    272 QTest::addColumn<QString>("type");
    -
    273 QTest::addColumn<QString>("number");
    -
    274 const char *types[] = {"INT", "HEX", "FLOAT"};
    -
    275 const char *invalid[] = {"+", "-", "++1", "+-1", "--1", "1x", "0x10",
    -
    276 "nan", "inf", "-inf", "1e9999", "1e-9999"};
    -
    277 for (const char *type: types) {
    -
    278 for (const char *number: invalid) {
    -
    279 const std::string name = std::string(type) + '-' + number;
    -
    280 QTest::newRow(name.c_str()) << QString(type) << QString(number);
    -
    281 }
    -
    282 }
    -
    283 QTest::newRow("integer-overflow") << QString("INT") << QString("9223372036854775808");
    -
    284 QTest::newRow("integer-underflow") << QString("INT") << QString("-9223372036854775809");
    -
    285 QTest::newRow("integer-fraction") << QString("INT") << QString("1.5");
    -
    286}
    -
    287
    -
    288void DbcParserTest::invalidAttributeNumbers() {
    -
    289 QFETCH(QString, type);
    -
    290 QFETCH(QString, number);
    -
    291 const std::string kind = type.toStdString();
    -
    292 const std::string text = number.toStdString();
    -
    293 const std::string definition = "BA_DEF_ \"A\" " + kind + " -10 10;\n";
    -
    294 const std::string statements[] = {
    -
    295 "BA_DEF_ \"A\" " + kind + ' ' + text + " 10;\n",
    -
    296 "BA_DEF_ \"A\" " + kind + " -10 " + text + ";\n",
    -
    297 definition + "BA_DEF_DEF_ \"A\" " + text + ";\n",
    -
    298 definition + "BA_ \"A\" " + text + ";\n"};
    -
    299 Fixture fixture;
    -
    300 for (const std::string &statement: statements) {
    -
    301 fixture.Write(statement);
    -
    302 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    303 QVERIFY2(result.HasErrors(), statement.c_str());
    -
    304 QVERIFY(result.database.attributeDefinitions.empty());
    -
    305 QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
    -
    306 QCOMPARE(result.diagnostics.back().lineNumber,
    -
    307 static_cast<std::size_t>(std::count(statement.begin(), statement.end(), '\n')));
    -
    308 QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
    -
    309 }
    -
    310}
    -
    311
    -
    312void DbcParserTest::attributeWarnings() {
    -
    313 Fixture fixture;
    -
    314 fixture.Write("BA_DEF_ BO_ \"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"J1939PG\",\"StandardCAN_FD\";\n"
    -
    315 "BA_DEF_DEF_ \"VFrameFormat\" \"StandardCAN_FD\";\n"
    -
    316 "BA_ \"VFrameFormat\" BO_ 1 2;\n"
    -
    317 "BA_ \"VFrameFormat\" BO_ 2147483649 0;\n"
    -
    318 "BO_ 1 F: 0 ECU\nBO_ 2147483649 E: 0 ECU\nBO_ 2 Default: 0 ECU\n");
    -
    319 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    320 QVERIFY(!result.HasErrors());
    -
    321 QCOMPARE(result.diagnostics.size(), std::size_t(3));
    -
    322 const std::size_t lines[] = {3U, 4U, 2U};
    -
    323 for (std::size_t index = 0; index < 3U; ++index) {
    -
    324 QCOMPARE(result.diagnostics[index].code, DbcDiagnosticCode::UnsupportedAttribute);
    -
    325 QCOMPARE(result.diagnostics[index].severity, DbcDiagnosticSeverity::Warning);
    -
    326 QCOMPARE(result.diagnostics[index].lineNumber, lines[index]);
    -
    327 QCOMPARE(result.diagnostics[index].filePath, fixture.path.string());
    -
    328 }
    -
    329 QCOMPARE(result.database.frames[0].frameFormat.value(), std::string("J1939PG"));
    -
    330 QVERIFY(!result.database.frames[0].hasPgn);
    -
    331 QVERIFY(result.database.frames[1].isExtended);
    -
    332}
    -
    333
    -
    334void DbcParserTest::diagnostics() {
    -
    335 Fixture fixture;
    -
    336 fixture.Write("VERSION \"test\"\n"
    -
    337 "NS_ :\n"
    -
    338 " CM_\n"
    -
    339 " BA_\n"
    -
    340 " SIG_VALTYPE_\n"
    -
    341 " SG_MUL_VAL_\n\n"
    -
    342 "BS_:\n"
    -
    343 "BU_: ECU\n"
    -
    344 "BO_ 1 Frame: 1 ECU\n"
    -
    345 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    346 "SIG_VALTYPE_ 1 Value : 1;\n"
    -
    347 "BA_REL_ \"SignalType\" SG_ 1 Value 1;\n"
    -
    348 "VENDOR_EXTENSION_ data;\n");
    -
    349 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    350 CHECK(!result.HasErrors() && result.database.frames.size() == 1U,
    -
    351 "Warnings preserve the supported database");
    -
    352 QCOMPARE(result.diagnostics.size(), std::size_t(3U));
    -
    353 for (std::size_t index = 0U; index < result.diagnostics.size(); ++index) {
    -
    354 const DbcDiagnostic &diagnostic = result.diagnostics[index];
    -
    355 CHECK(diagnostic.severity == DbcDiagnosticSeverity::Warning &&
    -
    356 diagnostic.code == DbcDiagnosticCode::UnsupportedStatement,
    -
    357 "Unsupported statements have structured warning severity and code");
    -
    358 QCOMPARE(diagnostic.filePath, fixture.path.string());
    -
    359 QCOMPARE(diagnostic.lineNumber, 12U + index);
    -
    360 CHECK(diagnostic.message.find("ignored") != std::string::npos,
    -
    361 "Warning explains unsupported syntax");
    -
    362 }
    -
    363 CHECK(DbcParser().ParseFile(fixture.path.string()).frames.size() == 1U,
    -
    364 "Legacy API accepts files with warnings");
    -
    365 fixture.Write("VERSION \"\"\nNS_:\nSIG_VALTYPE_\n\tBA_\n BS_ :\n BU_ : ECU\n");
    -
    366 const DbcParseResult headers = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    367 CHECK(headers.diagnostics.empty(), "Common header variants stay quiet");
    -
    368 fixture.Write("NS_ :\n BA_\n BO_\n");
    -
    369 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
    -
    370 "Namespace handling does not swallow a malformed frame");
    -
    371}
    -
    372
    -
    373void DbcParserTest::diagnosticErrors() {
    -
    374 Fixture fixture;
    -
    375 struct ErrorCase {
    -
    376 const char *text;
    -
    377 DbcDiagnosticCode code;
    -
    378 std::size_t line;
    -
    379 };
    -
    380 const ErrorCase cases[] = {
    -
    381 {"UNKNOWN_ data;\n\nBO_ invalid Frame: 1 ECU\n",
    -
    382 DbcDiagnosticCode::InvalidStatement, 3U},
    -
    383 {"BO_ 1 Frame: 1 ECU\nSG_MUL_VAL_ 1 Value Mode 1-2;\n",
    -
    384 DbcDiagnosticCode::UnsupportedStatement, 2U},
    -
    385 {"BO_ 1 Frame: 1 ECU\nVAL_ 1 Missing 0 \"Off\";\n",
    -
    386 DbcDiagnosticCode::InvalidValueDescription, 2U},
    -
    387 {"BO_ 1 Frame: 1 ECU\nSG_ Value m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    388 DbcDiagnosticCode::InvalidMultiplexing, 2U},
    -
    389 {"BO_ 1 Frame: 1 ECU\nSG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
    -
    390 DbcDiagnosticCode::InvalidMultiplexing, 2U},
    -
    391 {"VAL_ broken\n", DbcDiagnosticCode::InvalidValueDescription, 1U},
    -
    392 {"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    393 DbcDiagnosticCode::InvalidStatement, 1U},
    -
    394 {"BO_ 1 Frame: 1 ECU\nBO_ 1 Duplicate: 1 ECU\n",
    -
    395 DbcDiagnosticCode::InvalidStatement, 2U},
    -
    396 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    397 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    398 DbcDiagnosticCode::InvalidStatement, 3U},
    -
    399 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    400 DbcDiagnosticCode::InvalidStatement, 2U},
    -
    401 {"BO_ 1 Frame: 1 ECU\nVAL_ 2 Missing 0 \"Off\";\n",
    -
    402 DbcDiagnosticCode::InvalidValueDescription, 2U},
    -
    403 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    404 "VAL_ 1 Value 0 \"Off\";\nVAL_ 1 Value 0 \"Duplicate\";\n",
    -
    405 DbcDiagnosticCode::InvalidValueDescription, 4U},
    -
    406 {"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n"
    -
    407 "SG_ Value m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    408 DbcDiagnosticCode::InvalidMultiplexing, 3U},
    -
    409 {"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    410 "SG_ Other M : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    411 DbcDiagnosticCode::InvalidMultiplexing, 3U},
    -
    412 {"BO_ 1 Frame: 1 ECU\nSG_ First : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    413 "SG_ Second : 7|8@0+ (1,0) [0|255] \"\" ECU\n",
    -
    414 DbcDiagnosticCode::InvalidMultiplexing, 3U}
    -
    415 };
    -
    416 for (const ErrorCase &test : cases) {
    -
    417 fixture.Write(test.text);
    -
    418 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    419 CHECK(result.HasErrors() && result.database.frames.empty(),
    -
    420 "Failed parse never returns a partial database");
    -
    421 const DbcDiagnostic &diagnostic = result.diagnostics.back();
    -
    422 CHECK(diagnostic.severity == DbcDiagnosticSeverity::Error && diagnostic.code == test.code,
    -
    423 "Error has expected severity and code");
    -
    424 QCOMPARE(diagnostic.filePath, fixture.path.string());
    -
    425 QCOMPARE(diagnostic.lineNumber, test.line);
    -
    426 CHECK(!diagnostic.message.empty(), "Error includes a message");
    -
    427 const bool hasWarning = std::string(test.text).find("UNKNOWN_") == 0U;
    -
    428 QCOMPARE(result.diagnostics.size(), hasWarning ? std::size_t(2U) : std::size_t(1U));
    -
    429 try {
    -
    430 DbcParser().ParseFile(fixture.path.string());
    -
    431 CHECK(false, "Legacy parser must throw");
    -
    432 } catch (const std::runtime_error &error) {
    -
    433 QCOMPARE(std::string(error.what()), fixture.path.string() + ":" +
    -
    434 std::to_string(test.line) + ": " + diagnostic.message);
    -
    435 }
    -
    436 }
    -
    437 const std::string missingPath = fixture.path.string() + ".missing";
    -
    438 const DbcParseResult missing = DbcParser().ParseFileWithDiagnostics(missingPath);
    -
    439 CHECK(missing.HasErrors() && missing.database.frames.empty(), "Missing file returns error");
    -
    440 QCOMPARE(missing.diagnostics.size(), std::size_t(1U));
    -
    441 CHECK(missing.diagnostics[0].code == DbcDiagnosticCode::FileOpenError,
    -
    442 "Missing file has a distinct code");
    -
    443 QCOMPARE(missing.diagnostics[0].lineNumber, std::size_t(0U));
    -
    444 QCOMPARE(missing.diagnostics[0].filePath, missingPath);
    -
    445 QCOMPARE(missing.diagnostics[0].message, "Failed to open DBC file: " + missingPath);
    -
    446 try {
    -
    447 DbcParser().ParseFile(missingPath);
    -
    448 CHECK(false, "Legacy API throws on missing file");
    -
    449 } catch (const std::runtime_error &error) {
    -
    450 QCOMPARE(std::string(error.what()), missing.diagnostics[0].message);
    -
    451 }
    -
    452 const std::string directoryPath = fixture.path.parent_path().string();
    -
    453 const DbcParseResult directory = DbcParser().ParseFileWithDiagnostics(directoryPath);
    -
    454 CHECK(directory.HasErrors() && directory.database.frames.empty(),
    -
    455 "Directory cannot be parsed as a file");
    -
    456 QCOMPARE(directory.diagnostics.size(), std::size_t(1U));
    -
    457 CHECK(directory.diagnostics[0].code == DbcDiagnosticCode::FileReadError ||
    -
    458 directory.diagnostics[0].code == DbcDiagnosticCode::FileOpenError,
    -
    459 "Directory produces a file-level error on supported platforms");
    -
    460 QCOMPARE(directory.diagnostics[0].lineNumber, std::size_t(0U));
    -
    461 QCOMPARE(directory.diagnostics[0].filePath, directoryPath);
    -
    462#ifdef __linux__
    -
    463 CHECK(directory.diagnostics[0].code == DbcDiagnosticCode::FileReadError,
    -
    464 "Linux directory input exercises the read-error path");
    -
    465 QCOMPARE(directory.diagnostics[0].message, "Failed to read DBC file: " + directoryPath);
    -
    466#endif
    -
    467 try {
    -
    468 DbcParser().ParseFile(directoryPath);
    -
    469 CHECK(false, "Legacy API throws on unreadable input");
    -
    470 } catch (const std::runtime_error &error) {
    -
    471 QCOMPARE(std::string(error.what()), directory.diagnostics[0].message);
    -
    472 }
    -
    473 fixture.Write("BO_ 1 Frame: 1 ECU\n");
    -
    474 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).diagnostics.empty(),
    -
    475 "Diagnostics belong to an independent parse session");
    -
    476}
    -
    477
    -
    478void DbcParserTest::diagnosticUnsupportedStatements() {
    -
    479 Fixture fixture;
    -
    480 const std::string definitions =
    -
    481 "BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (2,10) [10|520] \"V\" ECU\n"
    -
    482 "CM_ SG_ 1 Value \"Signal comment\";\nVAL_ 1 Value 1 \"On\";\n";
    -
    483 const std::vector<std::string> statements = {
    -
    484 "SIG_VALTYPE_ 1 Value : 1;", "SIG_VALTYPE_ 1 Value : 2;",
    -
    485 "BA_REL_ \"SignalType\" SG_ 1 Value 1;",
    -
    486 "BA_DEF_REL_ BU_SG_REL_ \"Relation\" INT 0 1;",
    -
    487 "BA_REL_ \"Relation\" BU_SG_REL_ ECU SG_ 1 Value 1;",
    -
    488 "SGTYPE_ Type : 8@1+ (1,0) [0|255] \"\" 0, Table;",
    -
    489 "SIG_TYPE_REF_ 1 Value : Type;",
    -
    490 "EV_ Environment : 0 [0|1] \"\" 0 1 DUMMY_NODE_VECTOR0 ECU;",
    -
    491 "ENVVAR_DATA_ Environment : 4;",
    -
    492 "VAL_TABLE_ Table 0 \"Off\" 1 \"On\";",
    -
    493 "BO_TX_BU_ 1 : ECU;", "VENDOR_EXTENSION_ data;", "UNKNOWN_"
    -
    494 };
    -
    495 for (const std::string &statement : statements) {
    -
    496 fixture.Write(definitions + statement + '\n');
    -
    497 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    498 CHECK(!result.HasErrors(), statement);
    -
    499 QCOMPARE(result.diagnostics.size(), std::size_t(1U));
    -
    500 const DbcDiagnostic &warning = result.diagnostics[0];
    -
    501 CHECK(warning.severity == DbcDiagnosticSeverity::Warning &&
    -
    502 warning.code == DbcDiagnosticCode::UnsupportedStatement, statement);
    -
    503 QCOMPARE(warning.filePath, fixture.path.string());
    -
    504 QCOMPARE(warning.lineNumber, std::size_t(5U));
    -
    505 const std::string keyword = statement.substr(0U, statement.find(' '));
    -
    506 CHECK(warning.message.find("'" + keyword + "'") != std::string::npos, statement);
    -
    507 const DecodeDatabase runtime = DbcDecodeBuilder().Build(result.database);
    -
    508 RawCanFrame raw;
    -
    509 raw.canId = 1U;
    -
    510 raw.data = {1U};
    -
    511 const DecodedFrameValue decoded = DbcDecoder().Decode(runtime, raw);
    -
    512 CHECK(decoded.valid && decoded.signals.size() == 1U && decoded.signals[0].valid,
    -
    513 "Warnings preserve supported signal decoding");
    -
    514 QCOMPARE(decoded.signals[0].physicalValue, 12.0);
    -
    515 CHECK(decoded.signals[0].GetValueDescription() &&
    -
    516 *decoded.signals[0].GetValueDescription() == "On",
    -
    517 "Warnings preserve VAL_ descriptions");
    -
    518 QCOMPARE(runtime.GetFrames()[0].signals[0].comment, std::string("Signal comment"));
    -
    519 }
    -
    520}
    -
    521
    -
    522void DbcParserTest::diagnosticNamespaceBoundaries() {
    -
    523 Fixture fixture;
    -
    524 const std::vector<std::string> endings = {
    -
    525 "BS_\n", "BS_:\n", "BS_ :\n", "BU_\n", "BU_:\n", "BU_ : ECU\n",
    -
    526 "BO_ 1 Frame: 1 ECU\n", "VENDOR_EXTENSION_ data;\n"
    -
    527 };
    -
    528 for (const std::string &ending : endings) {
    -
    529 fixture.Write("NS_ :\n\tSG_MUL_VAL_\n\nBA_\n" + ending + "SIG_VALTYPE_\n");
    -
    530 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    531 CHECK(!result.HasErrors(), ending);
    -
    532 const std::size_t expectedWarnings = ending.find("VENDOR_") == 0U ? 2U : 1U;
    -
    533 QCOMPARE(result.diagnostics.size(), expectedWarnings);
    -
    534 QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(6U));
    -
    535 CHECK(result.diagnostics.back().message.find("SIG_VALTYPE_") != std::string::npos,
    -
    536 "Unsupported keyword outside NS_ must produce a warning");
    -
    537 }
    -
    538 for (const std::string &definition : {std::string("BO_"), std::string("SG_")}) {
    -
    539 fixture.Write("NS_:\n\tBA_\n\t" + definition + '\n');
    -
    540 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    541 CHECK(result.HasErrors(), "Malformed definition ends NS_ instead of being hidden");
    -
    542 QCOMPARE(result.diagnostics.size(), std::size_t(1U));
    -
    543 QCOMPARE(result.diagnostics[0].lineNumber, std::size_t(3U));
    -
    544 }
    -
    545}
    -
    546
    -
    547void DbcParserTest::diagnosticFormatting() {
    -
    548 Fixture fixture;
    -
    549 fixture.path += " with spaces";
    -
    550 const DbcParser parser;
    -
    551 for (const std::string &text : {std::string(), std::string(" \t\r\n\n")}) {
    -
    552 fixture.Write(text);
    -
    553 const DbcParseResult empty = parser.ParseFileWithDiagnostics(fixture.path.string());
    -
    554 CHECK(!empty.HasErrors() && empty.diagnostics.empty() && empty.database.frames.empty(),
    -
    555 "Empty and whitespace-only inputs are valid");
    -
    556 }
    -
    557 fixture.Write("\r\n\tVENDOR_EXTENSION_ data;\r\n\r\nUNKNOWN_");
    -
    558 const std::string relativePath = std::filesystem::relative(fixture.path).string();
    -
    559 const DbcParseResult warnings = parser.ParseFileWithDiagnostics(relativePath);
    -
    560 CHECK(!warnings.HasErrors() && warnings.database.frames.empty(), "Warnings-only input");
    -
    561 QCOMPARE(warnings.diagnostics.size(), std::size_t(2U));
    -
    562 QCOMPARE(warnings.diagnostics[0].lineNumber, std::size_t(2U));
    -
    563 QCOMPARE(warnings.diagnostics[1].lineNumber, std::size_t(4U));
    -
    564 for (const DbcDiagnostic &warning : warnings.diagnostics)
    -
    565 QCOMPARE(warning.filePath, relativePath);
    -
    566
    -
    567 fixture.Write("UNKNOWN_ first;\nBO_ invalid Frame: 1 ECU\n"
    -
    568 "UNKNOWN_ after_error;\nSG_ broken\n");
    -
    569 const DbcParseResult stopped = parser.ParseFileWithDiagnostics(relativePath);
    -
    570 CHECK(stopped.HasErrors() && stopped.database.frames.empty(), "First error stops parsing");
    -
    571 QCOMPARE(stopped.diagnostics.size(), std::size_t(2U));
    -
    572 QCOMPARE(stopped.diagnostics[0].lineNumber, std::size_t(1U));
    -
    573 QCOMPARE(stopped.diagnostics[1].lineNumber, std::size_t(2U));
    -
    574 QCOMPARE(stopped.diagnostics[1].filePath, relativePath);
    -
    575
    -
    576 fixture.Write("VAL_ 1 Missing 0 \"Off\";\nBO_ 1 Frame: 1 ECU\nUNKNOWN_ data;\n");
    -
    577 const DbcParseResult deferred = parser.ParseFileWithDiagnostics(relativePath);
    -
    578 CHECK(deferred.HasErrors() && deferred.database.frames.empty(), "Deferred error rejects database");
    -
    579 QCOMPARE(deferred.diagnostics.size(), std::size_t(2U));
    -
    580 CHECK(deferred.diagnostics[0].severity == DbcDiagnosticSeverity::Warning &&
    -
    581 deferred.diagnostics[1].severity == DbcDiagnosticSeverity::Error,
    -
    582 "Deferred errors follow warnings in detection order");
    -
    583 QCOMPARE(deferred.diagnostics[0].lineNumber, std::size_t(3U));
    -
    584 QCOMPARE(deferred.diagnostics[1].lineNumber, std::size_t(1U));
    -
    585 QCOMPARE(deferred.diagnostics[1].filePath, relativePath);
    -
    586 fixture.Write("BO_ 1 Frame: 1 ECU");
    -
    587 const DbcParseResult recovered = parser.ParseFileWithDiagnostics(relativePath);
    -
    588 CHECK(!recovered.HasErrors() && recovered.diagnostics.empty() && recovered.database.frames.size() == 1U,
    -
    589 "Same parser has clean state after errors and accepts missing final newline");
    -
    590}
    -
    591
    -
    592void DbcParserTest::validFrames() {
    -
    593 Fixture fixture;
    -
    594 struct ValidCase {
    -
    595 const char *line;
    -
    596 std::uint32_t id;
    -
    597 bool extended;
    -
    598 unsigned length;
    -
    599 };
    -
    600 const ValidCase valid[] = {
    -
    601 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
    -
    602 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
    -
    603 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
    -
    604 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
    -
    605 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
    -
    606 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
    -
    607 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
    -
    608 for (const ValidCase &test: valid) {
    -
    609 fixture.Write(std::string(test.line) + '\n');
    -
    610 try {
    -
    611 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    -
    612 QCOMPARE(database.frames.size(), std::size_t(1U));
    -
    613 const FrameInfo &frame = database.frames[0];
    -
    614 QCOMPARE(frame.name, std::string("Frame"));
    -
    615 QCOMPARE(frame.canId, test.id);
    -
    616 QCOMPARE(frame.isExtended, test.extended);
    -
    617 QCOMPARE(static_cast<unsigned>(frame.dlc), test.length);
    -
    618 QCOMPARE(frame.transmitter, std::string("ECU"));
    -
    619 } catch (const std::exception &error) { CHECK(false, error.what()); }
    -
    620 }
    -
    621}
    -
    622
    -
    623void DbcParserTest::invalidFrames() {
    -
    624 Fixture fixture;
    -
    625 const char *invalid[] = {
    -
    626 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
    -
    627 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
    -
    628 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
    -
    629 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
    -
    630 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
    -
    631 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
    -
    632 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
    -
    633 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
    -
    634 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
    -
    635 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
    -
    636 for (const char *line: invalid) {
    -
    637 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
    -
    638 try {
    -
    639 DbcParser().ParseFile(fixture.path.string());
    -
    640 CHECK(false, line);
    -
    641 } catch (const std::runtime_error &error) {
    -
    642 const std::string prefix = fixture.path.string() + ":3: ";
    -
    643 CHECK(std::string(error.what()).find(prefix) == 0U &&
    -
    644 std::string(error.what()).size() > prefix.size(),
    -
    645 line);
    -
    646 }
    -
    647 }
    -
    648}
    -
    649
    -
    650void DbcParserTest::duplicateFrames() {
    -
    651 Fixture fixture;
    -
    652 struct DuplicateCase {
    -
    653 const char *firstId;
    -
    654 const char *duplicateId;
    -
    655 const char *message;
    -
    656 };
    -
    657 const DuplicateCase cases[] = {
    -
    658 {"1", "1", "Duplicate standard frame CAN ID: 1"},
    -
    659 {"2147483649", "2147483649", "Duplicate extended frame CAN ID: 1"},
    -
    660 {"2048", "2147485696", "Duplicate extended frame CAN ID: 2048"},
    -
    661 {"2147485696", "2048", "Duplicate extended frame CAN ID: 2048"},
    -
    662 {"536870911", "2684354559", "Duplicate extended frame CAN ID: 536870911"}
    -
    663 };
    -
    664 const DbcParser parser;
    -
    665 for (const DuplicateCase &test : cases) {
    -
    666 fixture.Write("BO_ " + std::string(test.firstId) + " First: 8 ECU\n"
    -
    667 "BO_ 2 Other: 8 ECU\n\n"
    -
    668 " BO_\t" + test.duplicateId + "\tSecond: 8 ECU\n");
    -
    669 try {
    -
    670 parser.ParseFile(fixture.path.string());
    -
    671 CHECK(false, "Duplicate frame must be rejected");
    -
    672 } catch (const std::runtime_error &error) {
    -
    673 QCOMPARE(std::string(error.what()), fixture.path.string() + ":4: " + test.message);
    -
    674 }
    -
    675 }
    -
    676 fixture.Write("BO_ 1 First: 8 ECU\n");
    -
    677 QCOMPARE(parser.ParseFile(fixture.path.string()).frames.size(), std::size_t(1U));
    -
    678}
    -
    679
    -
    680void DbcParserTest::duplicateSignals() {
    -
    681 Fixture fixture;
    -
    682 const std::string first = "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n";
    -
    683 const std::string duplicates[] = {
    -
    684 first,
    -
    685 " SG_\tState : 16|8@1+ (2,1) [0|511] \"V\" ECU\n",
    -
    686 "SG_ State m1 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    687 };
    -
    688 for (const std::string &duplicate : duplicates) {
    -
    689 fixture.Write("BO_ 1 Frame: 8 ECU\n" + first +
    -
    690 "SG_ Other : 8|8@1+ (1,0) [0|255] \"\" ECU\n\n" + duplicate);
    +
    271void DbcParserTest::invalidAttributes() {
    +
    272 Fixture fixture;
    +
    273 const std::vector<std::string> invalid = {
    +
    274 "BA_DEF_ BO_ \"A\"STRING;",
    +
    275 "BA_DEF_ BO_\"A\" STRING;",
    +
    276 "BA_DEF_ BO_ \"A\" \"STRING\";",
    +
    277 "BA_DEF_ BO_ A STRING;",
    +
    278 "BA_DEF_ ZZ_ \"A\" STRING;",
    +
    279 "BA_DEF_ BO_ \"A\" BLOB;",
    +
    280 "BA_DEF_ BO_ \"A\" FLOAT 2 1;",
    +
    281 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 0;",
    +
    282 "BA_DEF_ BO_ \"A\" FLOAT 0 1;\nBA_ \"A\" BO_ 1 2;",
    +
    283 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ -1 0;",
    +
    284 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 4294967296 0;",
    +
    285 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 536870912 0;",
    +
    286 "BA_DEF_ BO_ \"A\" INT 2 1;",
    +
    287 "BA_DEF_ BO_ \"A\" FLOAT nan 1;",
    +
    288 "BA_DEF_ BO_ \"A\" FLOAT 0 inf;",
    +
    289 "BA_DEF_ BO_ \"A\" INT 0 9223372036854775808;",
    +
    290 "BA_DEF_ BO_ \"A\" STRING; trailing",
    +
    291 "BA_DEF_ BO_ \"A\" ENUM;",
    +
    292 "BA_DEF_ BO_ \"A\" ENUM \"one\",;",
    +
    293 "BA_DEF_ BO_ \"A\" ENUM \"one\",\"one\";",
    +
    294 "BA_DEF_ BO_ \"VFrameFormat\" STRING;",
    +
    295 "BA_DEF_ SG_ \"GenMsgCycleTime\" INT 0 10;",
    +
    296 "BA_ \"Unknown\" BO_ 1 0;",
    +
    297 "BA_DEF_DEF_ \"Unknown\" 0;",
    +
    298 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 1 2;",
    +
    299 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 1 \"0\";",
    +
    300 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" SG_ 1 S 0;",
    +
    301 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 2 0;",
    +
    302 "BA_DEF_ SG_ \"A\" INT 0 1;\nBA_ \"A\" SG_ 1 Missing 0;",
    +
    303 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_DEF_ BO_ \"A\" INT 0 1;",
    +
    304 "BA_DEF_ BO_ \"A\" INT 0 1;\nBA_DEF_DEF_ \"A\" 0;\nBA_DEF_DEF_ \"A\" 1;",
    +
    305 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 \"bad\\q\";",
    +
    306 "BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 \"unterminated;",
    +
    307 "BA_DEF_ BO_ \"A\" ENUM \"one\";\nBA_DEF_DEF_ \"A\" \"missing\";",
    +
    308 "BA_DEF_ BO_ \"A\" ENUM \"one\";\nBA_ \"A\" BO_ 1 1;",
    +
    309 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT -1 4294967296;\nBA_DEF_DEF_ \"GenMsgCycleTime\" -1;",
    +
    310 "BA_DEF_ BO_ \"GenMsgCycleTime\" INT 0 4294967296;\nBA_ \"GenMsgCycleTime\" BO_ 1 4294967296;"};
    +
    311 for (const std::string &statement: invalid) {
    +
    312 fixture.Write("BO_ 1 F: 0 ECU\n" + statement + '\n');
    +
    313 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    314 QVERIFY2(result.HasErrors(), statement.c_str());
    +
    315 QVERIFY(result.database.frames.empty());
    +
    316 QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
    +
    317 QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(2 + std::count(statement.begin(), statement.end(), '\n')));
    +
    318 QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
    +
    319 }
    +
    320}
    +
    321
    +
    322void DbcParserTest::attributeNumbers() {
    +
    323 ApplicationLocaleGuard guard;
    +
    324 std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
    +
    325 Fixture fixture;
    +
    326 fixture.Write("BA_DEF_ \"I\" INT -9223372036854775808 +9223372036854775807;\n"
    +
    327 "BA_DEF_DEF_ \"I\" -9223372036854775808;\n"
    +
    328 "BA_ \"I\" +9223372036854775807;\n"
    +
    329 "BA_DEF_ \"H\" HEX -10 +10;\n"
    +
    330 "BA_DEF_DEF_ \"H\" +0;\n"
    +
    331 "BA_ \"H\" -10;\n"
    +
    332 "BA_DEF_ \"F\" FLOAT -1.25e+2 +2.5E2;\n"
    +
    333 "BA_DEF_DEF_ \"F\" +.5;\n"
    +
    334 "BA_ \"F\" -1.25e+2;\n"
    +
    335 "BA_DEF_ BU_ \"NodeDefault\" INT 0 10;\n"
    +
    336 "BA_DEF_DEF_ \"NodeDefault\" 5;\n"
    +
    337 "BA_DEF_ EV_ \"EnvironmentDefault\" STRING;\n"
    +
    338 "BA_DEF_DEF_ \"EnvironmentDefault\" \"default\";\n");
    +
    339 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    340 QVERIFY(!result.HasErrors());
    +
    341 QVERIFY(result.diagnostics.empty());
    +
    342 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("I").defaultValue), std::numeric_limits<std::int64_t>::min());
    +
    343 QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("I")), std::numeric_limits<std::int64_t>::max());
    +
    344 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("H").defaultValue), std::int64_t(0));
    +
    345 QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("H")), std::int64_t(-10));
    +
    346 QCOMPARE(std::get<double>(*result.database.attributeDefinitions.at("F").defaultValue), 0.5);
    +
    347 QCOMPARE(std::get<double>(result.database.attributes.at("F")), -125.0);
    +
    348 QCOMPARE(result.database.attributes.size(), std::size_t(3));
    +
    349 QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("NodeDefault").defaultValue), std::int64_t(5));
    +
    350 QCOMPARE(std::get<std::string>(*result.database.attributeDefinitions.at("EnvironmentDefault").defaultValue), std::string("default"));
    +
    351}
    +
    352
    +
    353void DbcParserTest::invalidAttributeNumbers_data() {
    +
    354 QTest::addColumn<QString>("type");
    +
    355 QTest::addColumn<QString>("number");
    +
    356 const char *types[] = {"INT", "HEX", "FLOAT"};
    +
    357 const char *invalid[] = {"+", "-", "++1", "+-1", "--1", "1x", "0x10",
    +
    358 "nan", "inf", "-inf", "1e9999", "1e-9999"};
    +
    359 for (const char *type: types) {
    +
    360 for (const char *number: invalid) {
    +
    361 const std::string name = std::string(type) + '-' + number;
    +
    362 QTest::newRow(name.c_str()) << QString(type) << QString(number);
    +
    363 }
    +
    364 }
    +
    365 QTest::newRow("integer-overflow") << QString("INT") << QString("9223372036854775808");
    +
    366 QTest::newRow("integer-underflow") << QString("INT") << QString("-9223372036854775809");
    +
    367 QTest::newRow("integer-fraction") << QString("INT") << QString("1.5");
    +
    368}
    +
    369
    +
    370void DbcParserTest::invalidAttributeNumbers() {
    +
    371 QFETCH(QString, type);
    +
    372 QFETCH(QString, number);
    +
    373 const std::string kind = type.toStdString();
    +
    374 const std::string text = number.toStdString();
    +
    375 const std::string definition = "BA_DEF_ \"A\" " + kind + " -10 10;\n";
    +
    376 const std::string statements[] = {
    +
    377 "BA_DEF_ \"A\" " + kind + ' ' + text + " 10;\n",
    +
    378 "BA_DEF_ \"A\" " + kind + " -10 " + text + ";\n",
    +
    379 definition + "BA_DEF_DEF_ \"A\" " + text + ";\n",
    +
    380 definition + "BA_ \"A\" " + text + ";\n"};
    +
    381 Fixture fixture;
    +
    382 for (const std::string &statement: statements) {
    +
    383 fixture.Write(statement);
    +
    384 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    385 QVERIFY2(result.HasErrors(), statement.c_str());
    +
    386 QVERIFY(result.database.attributeDefinitions.empty());
    +
    387 QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
    +
    388 QCOMPARE(result.diagnostics.back().lineNumber,
    +
    389 static_cast<std::size_t>(std::count(statement.begin(), statement.end(), '\n')));
    +
    390 QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
    +
    391 }
    +
    392}
    +
    393
    +
    394void DbcParserTest::attributeWarnings() {
    +
    395 Fixture fixture;
    +
    396 fixture.Write("BA_DEF_ BO_ \"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"J1939PG\",\"StandardCAN_FD\";\n"
    +
    397 "BA_DEF_DEF_ \"VFrameFormat\" \"StandardCAN_FD\";\n"
    +
    398 "BA_ \"VFrameFormat\" BO_ 1 2;\n"
    +
    399 "BA_ \"VFrameFormat\" BO_ 2147483649 0;\n"
    +
    400 "BO_ 1 F: 0 ECU\nBO_ 2147483649 E: 0 ECU\nBO_ 2 Default: 0 ECU\n");
    +
    401 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    402 QVERIFY(!result.HasErrors());
    +
    403 QCOMPARE(result.diagnostics.size(), std::size_t(3));
    +
    404 const std::size_t lines[] = {3U, 4U, 2U};
    +
    405 for (std::size_t index = 0; index < 3U; ++index) {
    +
    406 QCOMPARE(result.diagnostics[index].code, DbcDiagnosticCode::UnsupportedAttribute);
    +
    407 QCOMPARE(result.diagnostics[index].severity, DbcDiagnosticSeverity::Warning);
    +
    408 QCOMPARE(result.diagnostics[index].lineNumber, lines[index]);
    +
    409 QCOMPARE(result.diagnostics[index].filePath, fixture.path.string());
    +
    410 }
    +
    411 QCOMPARE(result.database.frames[0].frameFormat.value(), std::string("J1939PG"));
    +
    412 QVERIFY(!result.database.frames[0].hasPgn);
    +
    413 QVERIFY(result.database.frames[1].isExtended);
    +
    414}
    +
    415
    +
    416void DbcParserTest::diagnostics() {
    +
    417 Fixture fixture;
    +
    418 fixture.Write("VERSION \"test\"\n"
    +
    419 "NS_ :\n"
    +
    420 " CM_\n"
    +
    421 " BA_\n"
    +
    422 " SIG_VALTYPE_\n"
    +
    423 " SG_MUL_VAL_\n\n"
    +
    424 "BS_:\n"
    +
    425 "BU_: ECU\n"
    +
    426 "BO_ 1 Frame: 1 ECU\n"
    +
    427 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    428 "SIG_VALTYPE_ 1 Value : 1;\n"
    +
    429 "BA_REL_ \"SignalType\" SG_ 1 Value 1;\n"
    +
    430 "VENDOR_EXTENSION_ data;\n");
    +
    431 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    432 CHECK(!result.HasErrors() && result.database.frames.size() == 1U,
    +
    433 "Warnings preserve the supported database");
    +
    434 QCOMPARE(result.diagnostics.size(), std::size_t(3U));
    +
    435 for (std::size_t index = 0U; index < result.diagnostics.size(); ++index) {
    +
    436 const DbcDiagnostic &diagnostic = result.diagnostics[index];
    +
    437 CHECK(diagnostic.severity == DbcDiagnosticSeverity::Warning &&
    +
    438 diagnostic.code == DbcDiagnosticCode::UnsupportedStatement,
    +
    439 "Unsupported statements have structured warning severity and code");
    +
    440 QCOMPARE(diagnostic.filePath, fixture.path.string());
    +
    441 QCOMPARE(diagnostic.lineNumber, 12U + index);
    +
    442 CHECK(diagnostic.message.find("ignored") != std::string::npos,
    +
    443 "Warning explains unsupported syntax");
    +
    444 }
    +
    445 CHECK(DbcParser().ParseFile(fixture.path.string()).frames.size() == 1U,
    +
    446 "Legacy API accepts files with warnings");
    +
    447 fixture.Write("VERSION \"\"\nNS_:\nSIG_VALTYPE_\n\tBA_\n BS_ :\n BU_ : ECU\n");
    +
    448 const DbcParseResult headers = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    449 CHECK(headers.diagnostics.empty(), "Common header variants stay quiet");
    +
    450 fixture.Write("NS_ :\n BA_\n BO_\n");
    +
    451 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
    +
    452 "Namespace handling does not swallow a malformed frame");
    +
    453}
    +
    454
    +
    455void DbcParserTest::diagnosticErrors() {
    +
    456 Fixture fixture;
    +
    457 struct ErrorCase {
    +
    458 const char *text;
    +
    459 DbcDiagnosticCode code;
    +
    460 std::size_t line;
    +
    461 };
    +
    462 const ErrorCase cases[] = {
    +
    463 {"UNKNOWN_ data;\n\nBO_ invalid Frame: 1 ECU\n",
    +
    464 DbcDiagnosticCode::InvalidStatement, 3U},
    +
    465 {"BO_ 1 Frame: 1 ECU\nSG_MUL_VAL_ 1 Value Mode 1-2;\n",
    +
    466 DbcDiagnosticCode::InvalidMultiplexing, 2U},
    +
    467 {"BO_ 1 Frame: 1 ECU\nVAL_ 1 Missing 0 \"Off\";\n",
    +
    468 DbcDiagnosticCode::InvalidValueDescription, 2U},
    +
    469 {"BO_ 1 Frame: 1 ECU\nSG_ Value m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    470 DbcDiagnosticCode::InvalidMultiplexing, 2U},
    +
    471 {"BO_ 1 Frame: 1 ECU\nSG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
    +
    472 DbcDiagnosticCode::InvalidMultiplexing, 2U},
    +
    473 {"VAL_ broken\n", DbcDiagnosticCode::InvalidValueDescription, 1U},
    +
    474 {"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    475 DbcDiagnosticCode::InvalidStatement, 1U},
    +
    476 {"BO_ 1 Frame: 1 ECU\nBO_ 1 Duplicate: 1 ECU\n",
    +
    477 DbcDiagnosticCode::InvalidStatement, 2U},
    +
    478 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    479 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    480 DbcDiagnosticCode::InvalidStatement, 3U},
    +
    481 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    482 DbcDiagnosticCode::InvalidStatement, 2U},
    +
    483 {"BO_ 1 Frame: 1 ECU\nVAL_ 2 Missing 0 \"Off\";\n",
    +
    484 DbcDiagnosticCode::InvalidValueDescription, 2U},
    +
    485 {"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    486 "VAL_ 1 Value 0 \"Off\";\nVAL_ 1 Value 0 \"Duplicate\";\n",
    +
    487 DbcDiagnosticCode::InvalidValueDescription, 4U},
    +
    488 {"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n"
    +
    489 "SG_ Value m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    490 DbcDiagnosticCode::InvalidMultiplexing, 3U},
    +
    491 {"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    492 "SG_ Other M : 8|8@1- (1,0) [-128|127] \"\" ECU\n",
    +
    493 DbcDiagnosticCode::InvalidMultiplexing, 3U},
    +
    494 {"BO_ 1 Frame: 1 ECU\nSG_ First : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    495 "SG_ Second : 7|8@0+ (1,0) [0|255] \"\" ECU\n",
    +
    496 DbcDiagnosticCode::InvalidMultiplexing, 3U}};
    +
    497 for (const ErrorCase &test : cases) {
    +
    498 fixture.Write(test.text);
    +
    499 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    500 CHECK(result.HasErrors() && result.database.frames.empty(),
    +
    501 "Failed parse never returns a partial database");
    +
    502 const DbcDiagnostic &diagnostic = result.diagnostics.back();
    +
    503 CHECK(diagnostic.severity == DbcDiagnosticSeverity::Error && diagnostic.code == test.code,
    +
    504 "Error has expected severity and code");
    +
    505 QCOMPARE(diagnostic.filePath, fixture.path.string());
    +
    506 QCOMPARE(diagnostic.lineNumber, test.line);
    +
    507 CHECK(!diagnostic.message.empty(), "Error includes a message");
    +
    508 const bool hasWarning = std::string(test.text).find("UNKNOWN_") == 0U;
    +
    509 QCOMPARE(result.diagnostics.size(), hasWarning ? std::size_t(2U) : std::size_t(1U));
    +
    510 try {
    +
    511 DbcParser().ParseFile(fixture.path.string());
    +
    512 CHECK(false, "Legacy parser must throw");
    +
    513 } catch (const std::runtime_error &error) {
    +
    514 QCOMPARE(std::string(error.what()), fixture.path.string() + ":" +
    +
    515 std::to_string(test.line) + ": " + diagnostic.message);
    +
    516 }
    +
    517 }
    +
    518 const std::string missingPath = fixture.path.string() + ".missing";
    +
    519 const DbcParseResult missing = DbcParser().ParseFileWithDiagnostics(missingPath);
    +
    520 CHECK(missing.HasErrors() && missing.database.frames.empty(), "Missing file returns error");
    +
    521 QCOMPARE(missing.diagnostics.size(), std::size_t(1U));
    +
    522 CHECK(missing.diagnostics[0].code == DbcDiagnosticCode::FileOpenError,
    +
    523 "Missing file has a distinct code");
    +
    524 QCOMPARE(missing.diagnostics[0].lineNumber, std::size_t(0U));
    +
    525 QCOMPARE(missing.diagnostics[0].filePath, missingPath);
    +
    526 QCOMPARE(missing.diagnostics[0].message, "Failed to open DBC file: " + missingPath);
    +
    527 try {
    +
    528 DbcParser().ParseFile(missingPath);
    +
    529 CHECK(false, "Legacy API throws on missing file");
    +
    530 } catch (const std::runtime_error &error) {
    +
    531 QCOMPARE(std::string(error.what()), missing.diagnostics[0].message);
    +
    532 }
    +
    533 const std::string directoryPath = fixture.path.parent_path().string();
    +
    534 const DbcParseResult directory = DbcParser().ParseFileWithDiagnostics(directoryPath);
    +
    535 CHECK(directory.HasErrors() && directory.database.frames.empty(),
    +
    536 "Directory cannot be parsed as a file");
    +
    537 QCOMPARE(directory.diagnostics.size(), std::size_t(1U));
    +
    538 CHECK(directory.diagnostics[0].code == DbcDiagnosticCode::FileReadError ||
    +
    539 directory.diagnostics[0].code == DbcDiagnosticCode::FileOpenError,
    +
    540 "Directory produces a file-level error on supported platforms");
    +
    541 QCOMPARE(directory.diagnostics[0].lineNumber, std::size_t(0U));
    +
    542 QCOMPARE(directory.diagnostics[0].filePath, directoryPath);
    +
    543#ifdef __linux__
    +
    544 CHECK(directory.diagnostics[0].code == DbcDiagnosticCode::FileReadError,
    +
    545 "Linux directory input exercises the read-error path");
    +
    546 QCOMPARE(directory.diagnostics[0].message, "Failed to read DBC file: " + directoryPath);
    +
    547#endif
    +
    548 try {
    +
    549 DbcParser().ParseFile(directoryPath);
    +
    550 CHECK(false, "Legacy API throws on unreadable input");
    +
    551 } catch (const std::runtime_error &error) {
    +
    552 QCOMPARE(std::string(error.what()), directory.diagnostics[0].message);
    +
    553 }
    +
    554 fixture.Write("BO_ 1 Frame: 1 ECU\n");
    +
    555 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).diagnostics.empty(),
    +
    556 "Diagnostics belong to an independent parse session");
    +
    557}
    +
    558
    +
    559void DbcParserTest::diagnosticUnsupportedStatements() {
    +
    560 Fixture fixture;
    +
    561 const std::string definitions =
    +
    562 "BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (2,10) [10|520] \"V\" ECU\n"
    +
    563 "CM_ SG_ 1 Value \"Signal comment\";\nVAL_ 1 Value 1 \"On\";\n";
    +
    564 const std::vector<std::string> statements = {
    +
    565 "SIG_VALTYPE_ 1 Value : 1;", "SIG_VALTYPE_ 1 Value : 2;",
    +
    566 "BA_REL_ \"SignalType\" SG_ 1 Value 1;",
    +
    567 "BA_DEF_REL_ BU_SG_REL_ \"Relation\" INT 0 1;",
    +
    568 "BA_REL_ \"Relation\" BU_SG_REL_ ECU SG_ 1 Value 1;",
    +
    569 "SGTYPE_ Type : 8@1+ (1,0) [0|255] \"\" 0, Table;",
    +
    570 "SIG_TYPE_REF_ 1 Value : Type;",
    +
    571 "EV_ Environment : 0 [0|1] \"\" 0 1 DUMMY_NODE_VECTOR0 ECU;",
    +
    572 "ENVVAR_DATA_ Environment : 4;",
    +
    573 "VAL_TABLE_ Table 0 \"Off\" 1 \"On\";",
    +
    574 "BO_TX_BU_ 1 : ECU;", "VENDOR_EXTENSION_ data;", "UNKNOWN_"
    +
    575 };
    +
    576 for (const std::string &statement : statements) {
    +
    577 fixture.Write(definitions + statement + '\n');
    +
    578 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    579 CHECK(!result.HasErrors(), statement);
    +
    580 QCOMPARE(result.diagnostics.size(), std::size_t(1U));
    +
    581 const DbcDiagnostic &warning = result.diagnostics[0];
    +
    582 CHECK(warning.severity == DbcDiagnosticSeverity::Warning &&
    +
    583 warning.code == DbcDiagnosticCode::UnsupportedStatement, statement);
    +
    584 QCOMPARE(warning.filePath, fixture.path.string());
    +
    585 QCOMPARE(warning.lineNumber, std::size_t(5U));
    +
    586 const std::string keyword = statement.substr(0U, statement.find(' '));
    +
    587 CHECK(warning.message.find("'" + keyword + "'") != std::string::npos, statement);
    +
    588 const DecodeDatabase runtime = DbcDecodeBuilder().Build(result.database);
    +
    589 RawCanFrame raw;
    +
    590 raw.canId = 1U;
    +
    591 raw.data = {1U};
    +
    592 const DecodedFrameValue decoded = DbcDecoder().Decode(runtime, raw);
    +
    593 CHECK(decoded.valid && decoded.signals.size() == 1U && decoded.signals[0].valid,
    +
    594 "Warnings preserve supported signal decoding");
    +
    595 QCOMPARE(decoded.signals[0].physicalValue, 12.0);
    +
    596 CHECK(decoded.signals[0].GetValueDescription() &&
    +
    597 *decoded.signals[0].GetValueDescription() == "On",
    +
    598 "Warnings preserve VAL_ descriptions");
    +
    599 QCOMPARE(runtime.GetFrames()[0].signals[0].comment, std::string("Signal comment"));
    +
    600 }
    +
    601}
    +
    602
    +
    603void DbcParserTest::diagnosticNamespaceBoundaries() {
    +
    604 Fixture fixture;
    +
    605 const std::vector<std::string> endings = {
    +
    606 "BS_\n", "BS_:\n", "BS_ :\n", "BU_\n", "BU_:\n", "BU_ : ECU\n",
    +
    607 "BO_ 1 Frame: 1 ECU\n", "VENDOR_EXTENSION_ data;\n"
    +
    608 };
    +
    609 for (const std::string &ending : endings) {
    +
    610 fixture.Write("NS_ :\n\tSG_MUL_VAL_\n\nBA_\n" + ending + "SIG_VALTYPE_\n");
    +
    611 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    612 CHECK(!result.HasErrors(), ending);
    +
    613 const std::size_t expectedWarnings = ending.find("VENDOR_") == 0U ? 2U : 1U;
    +
    614 QCOMPARE(result.diagnostics.size(), expectedWarnings);
    +
    615 QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(6U));
    +
    616 CHECK(result.diagnostics.back().message.find("SIG_VALTYPE_") != std::string::npos,
    +
    617 "Unsupported keyword outside NS_ must produce a warning");
    +
    618 }
    +
    619 for (const std::string &definition : {std::string("BO_"), std::string("SG_")}) {
    +
    620 fixture.Write("NS_:\n\tBA_\n\t" + definition + '\n');
    +
    621 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    622 CHECK(result.HasErrors(), "Malformed definition ends NS_ instead of being hidden");
    +
    623 QCOMPARE(result.diagnostics.size(), std::size_t(1U));
    +
    624 QCOMPARE(result.diagnostics[0].lineNumber, std::size_t(3U));
    +
    625 }
    +
    626}
    +
    627
    +
    628void DbcParserTest::diagnosticFormatting() {
    +
    629 Fixture fixture;
    +
    630 fixture.path += " with spaces";
    +
    631 const DbcParser parser;
    +
    632 for (const std::string &text : {std::string(), std::string(" \t\r\n\n")}) {
    +
    633 fixture.Write(text);
    +
    634 const DbcParseResult empty = parser.ParseFileWithDiagnostics(fixture.path.string());
    +
    635 CHECK(!empty.HasErrors() && empty.diagnostics.empty() && empty.database.frames.empty(),
    +
    636 "Empty and whitespace-only inputs are valid");
    +
    637 }
    +
    638 fixture.Write("\r\n\tVENDOR_EXTENSION_ data;\r\n\r\nUNKNOWN_");
    +
    639 const std::string relativePath = std::filesystem::relative(fixture.path).string();
    +
    640 const DbcParseResult warnings = parser.ParseFileWithDiagnostics(relativePath);
    +
    641 CHECK(!warnings.HasErrors() && warnings.database.frames.empty(), "Warnings-only input");
    +
    642 QCOMPARE(warnings.diagnostics.size(), std::size_t(2U));
    +
    643 QCOMPARE(warnings.diagnostics[0].lineNumber, std::size_t(2U));
    +
    644 QCOMPARE(warnings.diagnostics[1].lineNumber, std::size_t(4U));
    +
    645 for (const DbcDiagnostic &warning : warnings.diagnostics)
    +
    646 QCOMPARE(warning.filePath, relativePath);
    +
    647
    +
    648 fixture.Write("UNKNOWN_ first;\nBO_ invalid Frame: 1 ECU\n"
    +
    649 "UNKNOWN_ after_error;\nSG_ broken\n");
    +
    650 const DbcParseResult stopped = parser.ParseFileWithDiagnostics(relativePath);
    +
    651 CHECK(stopped.HasErrors() && stopped.database.frames.empty(), "First error stops parsing");
    +
    652 QCOMPARE(stopped.diagnostics.size(), std::size_t(2U));
    +
    653 QCOMPARE(stopped.diagnostics[0].lineNumber, std::size_t(1U));
    +
    654 QCOMPARE(stopped.diagnostics[1].lineNumber, std::size_t(2U));
    +
    655 QCOMPARE(stopped.diagnostics[1].filePath, relativePath);
    +
    656
    +
    657 fixture.Write("VAL_ 1 Missing 0 \"Off\";\nBO_ 1 Frame: 1 ECU\nUNKNOWN_ data;\n");
    +
    658 const DbcParseResult deferred = parser.ParseFileWithDiagnostics(relativePath);
    +
    659 CHECK(deferred.HasErrors() && deferred.database.frames.empty(), "Deferred error rejects database");
    +
    660 QCOMPARE(deferred.diagnostics.size(), std::size_t(2U));
    +
    661 CHECK(deferred.diagnostics[0].severity == DbcDiagnosticSeverity::Warning &&
    +
    662 deferred.diagnostics[1].severity == DbcDiagnosticSeverity::Error,
    +
    663 "Deferred errors follow warnings in detection order");
    +
    664 QCOMPARE(deferred.diagnostics[0].lineNumber, std::size_t(3U));
    +
    665 QCOMPARE(deferred.diagnostics[1].lineNumber, std::size_t(1U));
    +
    666 QCOMPARE(deferred.diagnostics[1].filePath, relativePath);
    +
    667 fixture.Write("BO_ 1 Frame: 1 ECU");
    +
    668 const DbcParseResult recovered = parser.ParseFileWithDiagnostics(relativePath);
    +
    669 CHECK(!recovered.HasErrors() && recovered.diagnostics.empty() && recovered.database.frames.size() == 1U,
    +
    670 "Same parser has clean state after errors and accepts missing final newline");
    +
    671}
    +
    672
    +
    673void DbcParserTest::validFrames() {
    +
    674 Fixture fixture;
    +
    675 struct ValidCase {
    +
    676 const char *line;
    +
    677 std::uint32_t id;
    +
    678 bool extended;
    +
    679 unsigned length;
    +
    680 };
    +
    681 const ValidCase valid[] = {
    +
    682 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
    +
    683 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
    +
    684 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
    +
    685 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
    +
    686 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
    +
    687 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
    +
    688 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
    +
    689 for (const ValidCase &test: valid) {
    +
    690 fixture.Write(std::string(test.line) + '\n');
    691 try {
    -
    692 DbcParser().ParseFile(fixture.path.string());
    -
    693 CHECK(false, "Duplicate signal must be rejected");
    -
    694 } catch (const std::runtime_error &error) {
    -
    695 QCOMPARE(std::string(error.what()), fixture.path.string() +
    -
    696 ":5: Duplicate signal name 'State' in frame 'Frame'.");
    -
    697 }
    -
    698 }
    -
    699}
    -
    700
    -
    701void DbcParserTest::distinctDefinitions() {
    -
    702 Fixture fixture;
    -
    703 fixture.Write("BO_ 1 Shared: 1 ECU\n"
    -
    704 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    705 "BO_ 2147483649 Shared: 1 ECU\n"
    -
    706 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    707 "BO_ 2 Shared: 2 ECU\n"
    -
    708 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    709 "SG_ state : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    710 "CM_ BO_ 1 \"Standard\";\n"
    -
    711 "CM_ BO_ 2147483649 \"Extended\";\n"
    -
    712 "CM_ SG_ 1 State \"Standard state\";\n"
    -
    713 "CM_ SG_ 2147483649 State \"Extended state\";\n");
    -
    714 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    -
    715 QCOMPARE(parsed.frames.size(), std::size_t(3U));
    -
    716 QCOMPARE(parsed.frames[0].canId, parsed.frames[1].canId);
    -
    717 CHECK(!parsed.frames[0].isExtended && parsed.frames[1].isExtended,
    -
    718 "Standard and extended frames with the same numeric ID remain distinct");
    -
    719 QCOMPARE(parsed.frames[0].comment, std::string("Standard"));
    -
    720 QCOMPARE(parsed.frames[1].comment, std::string("Extended"));
    -
    721 QCOMPARE(parsed.frames[0].signals[0].comment, std::string("Standard state"));
    -
    722 QCOMPARE(parsed.frames[1].signals[0].comment, std::string("Extended state"));
    -
    723 QCOMPARE(parsed.frames[2].signals.size(), std::size_t(2U));
    -
    724 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    -
    725 RawCanFrame raw;
    -
    726 raw.canId = 1U;
    -
    727 raw.data = {7U};
    -
    728 const DecodedFrameValue standard = DbcDecoder().Decode(runtime, raw);
    -
    729 QVERIFY(standard.valid);
    -
    730 QCOMPARE(standard.definition->comment, std::string("Standard"));
    -
    731 raw.isExtended = true;
    -
    732 const DecodedFrameValue extended = DbcDecoder().Decode(runtime, raw);
    -
    733 QVERIFY(extended.valid);
    -
    734 QCOMPARE(extended.definition->comment, std::string("Extended"));
    -
    735}
    -
    736
    -
    737void DbcParserTest::comments() {
    -
    738 Fixture fixture;
    -
    739 fixture.Write(
    -
    740 "CM_\tBO_\t1\t\"First\";\r\n"
    -
    741 "CM_\tSG_\t1\tState\t\" Line one \r\n"
    -
    742 "\r\n"
    -
    743 "\tBO_ is text; \\\"quoted\\\" and \\\\slash\"\t;\r\n"
    -
    744 "CM_ BO_ 2147483649 \"Extended\";\r\n"
    -
    745 "CM_ SG_ 2147483649 State \"Extended signal\";\r\n"
    -
    746 "BO_ 1 Standard: 1 ECU\r\n"
    -
    747 "CM_ BO_ 1 \"Last\";\r\n"
    -
    748 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\r\n"
    -
    749 "BO_ 2147483649 Extended: 1 ECU\r\n"
    -
    750 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU");
    -
    751 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    752 QVERIFY(!result.HasErrors());
    -
    753 QVERIFY(result.diagnostics.empty());
    -
    754 QCOMPARE(result.database.frames.size(), std::size_t(2));
    -
    755 QCOMPARE(result.database.frames[0].comment, std::string("Last"));
    -
    756 QCOMPARE(result.database.frames[0].signals[0].comment,
    -
    757 std::string(" Line one \n\n\tBO_ is text; \"quoted\" and \\slash"));
    -
    758 QCOMPARE(result.database.frames[1].comment, std::string("Extended"));
    -
    759 QCOMPARE(result.database.frames[1].signals[0].comment, std::string("Extended signal"));
    +
    692 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    +
    693 QCOMPARE(database.frames.size(), std::size_t(1U));
    +
    694 const FrameInfo &frame = database.frames[0];
    +
    695 QCOMPARE(frame.name, std::string("Frame"));
    +
    696 QCOMPARE(frame.canId, test.id);
    +
    697 QCOMPARE(frame.isExtended, test.extended);
    +
    698 QCOMPARE(static_cast<unsigned>(frame.dlc), test.length);
    +
    699 QCOMPARE(frame.transmitter, std::string("ECU"));
    +
    700 } catch (const std::exception &error) { CHECK(false, error.what()); }
    +
    701 }
    +
    702}
    +
    703
    +
    704void DbcParserTest::invalidFrames() {
    +
    705 Fixture fixture;
    +
    706 const char *invalid[] = {
    +
    707 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
    +
    708 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
    +
    709 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
    +
    710 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
    +
    711 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
    +
    712 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
    +
    713 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
    +
    714 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
    +
    715 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
    +
    716 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
    +
    717 for (const char *line: invalid) {
    +
    718 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
    +
    719 try {
    +
    720 DbcParser().ParseFile(fixture.path.string());
    +
    721 CHECK(false, line);
    +
    722 } catch (const std::runtime_error &error) {
    +
    723 const std::string prefix = fixture.path.string() + ":3: ";
    +
    724 CHECK(std::string(error.what()).find(prefix) == 0U &&
    +
    725 std::string(error.what()).size() > prefix.size(),
    +
    726 line);
    +
    727 }
    +
    728 }
    +
    729}
    +
    730
    +
    731void DbcParserTest::duplicateFrames() {
    +
    732 Fixture fixture;
    +
    733 struct DuplicateCase {
    +
    734 const char *firstId;
    +
    735 const char *duplicateId;
    +
    736 const char *message;
    +
    737 };
    +
    738 const DuplicateCase cases[] = {
    +
    739 {"1", "1", "Duplicate standard frame CAN ID: 1"},
    +
    740 {"2147483649", "2147483649", "Duplicate extended frame CAN ID: 1"},
    +
    741 {"2048", "2147485696", "Duplicate extended frame CAN ID: 2048"},
    +
    742 {"2147485696", "2048", "Duplicate extended frame CAN ID: 2048"},
    +
    743 {"536870911", "2684354559", "Duplicate extended frame CAN ID: 536870911"}
    +
    744 };
    +
    745 const DbcParser parser;
    +
    746 for (const DuplicateCase &test : cases) {
    +
    747 fixture.Write("BO_ " + std::string(test.firstId) + " First: 8 ECU\n"
    +
    748 "BO_ 2 Other: 8 ECU\n\n"
    +
    749 " BO_\t" + test.duplicateId + "\tSecond: 8 ECU\n");
    +
    750 try {
    +
    751 parser.ParseFile(fixture.path.string());
    +
    752 CHECK(false, "Duplicate frame must be rejected");
    +
    753 } catch (const std::runtime_error &error) {
    +
    754 QCOMPARE(std::string(error.what()), fixture.path.string() + ":4: " + test.message);
    +
    755 }
    +
    756 }
    +
    757 fixture.Write("BO_ 1 First: 8 ECU\n");
    +
    758 QCOMPARE(parser.ParseFile(fixture.path.string()).frames.size(), std::size_t(1U));
    +
    759}
    760
    -
    761 const std::string ids[][2] = {
    -
    762 {"0", "0"},
    -
    763 {"2047", "2047"},
    -
    764 {"2048", "2147485696"},
    -
    765 {"536870911", "2684354559"},
    -
    766 {"2684354559", "536870911"}};
    -
    767 for (const std::string(&id)[2]: ids) {
    -
    768 fixture.Write("CM_ BO_ " + id[0] + " \"Frame\";\nCM_ SG_ " + id[0] +
    -
    769 " State \"Signal\";\nBO_ " + id[1] + " Frame: 1 ECU\n"
    -
    770 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n");
    -
    771 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    -
    772 QCOMPARE(database.frames[0].comment, std::string("Frame"));
    -
    773 QCOMPARE(database.frames[0].signals[0].comment, std::string("Signal"));
    -
    774 }
    -
    775 fixture.Write("CM_ BO_ 1 \"Line one\nLine two\";\n"
    -
    776 "BO_ 1 Frame: 0 ECU\nUNKNOWN_ value\nBO_ bad Frame: 0 ECU\n");
    -
    777 const DbcParseResult following = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    778 QVERIFY(following.HasErrors());
    -
    779 QCOMPARE(following.diagnostics.size(), std::size_t(2));
    -
    780 QCOMPARE(following.diagnostics[0].lineNumber, std::size_t(4));
    -
    781 QCOMPARE(following.diagnostics[1].lineNumber, std::size_t(5));
    -
    782}
    -
    783
    -
    784void DbcParserTest::invalidComments_data() {
    -
    785 QTest::addColumn<QString>("statement");
    -
    786 const char *ids[] = {"-1", "+1", "1x", "0x1", "4294967296", "536870912",
    -
    787 "1073741824", "2684354560", "4294967295"};
    -
    788 for (const char *id: ids) {
    -
    789 const std::string frameRow = std::string("frame-id-") + id;
    -
    790 const std::string signalRow = std::string("signal-id-") + id;
    -
    791 QTest::newRow(frameRow.c_str()) << QString::fromStdString("CM_ BO_ " + std::string(id) + " \"Text\";");
    -
    792 QTest::newRow(signalRow.c_str()) << QString::fromStdString("CM_ SG_ " + std::string(id) + " State \"Text\";");
    -
    793 }
    -
    794 QTest::newRow("missing-id") << QStringLiteral("CM_ BO_");
    -
    795 QTest::newRow("missing-signal") << QStringLiteral("CM_ SG_ 1 \"Text\";");
    -
    796 QTest::newRow("missing-quote") << QStringLiteral("CM_ BO_ 1 Text;");
    -
    797 QTest::newRow("unclosed") << QStringLiteral("CM_ SG_ 1 State \"Text\n More");
    -
    798 QTest::newRow("invalid-escape") << QStringLiteral("CM_ BO_ 1 \"bad\\q\";");
    -
    799 QTest::newRow("dangling-escape") << QStringLiteral("CM_ BO_ 1 \"bad\\");
    -
    800 QTest::newRow("missing-semicolon") << QStringLiteral("CM_ SG_ 1 State \"Text\"");
    -
    801 QTest::newRow("trailing-text") << QStringLiteral("CM_ BO_ 1 \"Text\"; garbage");
    -
    802 QTest::newRow("extra-header") << QStringLiteral("CM_ BO_ 1 extra \"Text\";");
    -
    803 QTest::newRow("extra-string") << QStringLiteral("CM_ BO_ 1 \"Text\" \"More\";");
    -
    804 QTest::newRow("missing-frame") << QStringLiteral("CM_ BO_ 2 \"Text\";");
    -
    805 QTest::newRow("missing-signal-frame") << QStringLiteral("CM_ SG_ 2 State \"Text\";");
    -
    806 QTest::newRow("missing-signal-reference") << QStringLiteral("CM_ SG_ 1 Missing \"Text\";");
    -
    807 QTest::newRow("different-frame-type") << QStringLiteral("CM_ BO_ 2147483649 \"Text\";");
    -
    808 QTest::newRow("missing-multiline-reference") << QStringLiteral("CM_ SG_ 1 Missing \"Text\nMore\";");
    -
    809}
    -
    810
    -
    811void DbcParserTest::invalidComments() {
    -
    812 QFETCH(QString, statement);
    -
    813 Fixture fixture;
    -
    814 fixture.Write("BO_ 1 Frame: 1 ECU\nSG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n\n" +
    -
    815 statement.toStdString());
    -
    816 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    817 QVERIFY(result.HasErrors());
    -
    818 QVERIFY(result.database.frames.empty());
    -
    819 QCOMPARE(result.diagnostics.size(), std::size_t(1));
    -
    820 const DbcDiagnostic &error = result.diagnostics[0];
    -
    821 QCOMPARE(error.severity, DbcDiagnosticSeverity::Error);
    -
    822 QCOMPARE(error.code, DbcDiagnosticCode::InvalidStatement);
    -
    823 QCOMPARE(error.filePath, fixture.path.string());
    -
    824 QCOMPARE(error.lineNumber, std::size_t(4));
    -
    825 QVERIFY(!error.message.empty());
    -
    826 try {
    -
    827 DbcParser().ParseFile(fixture.path.string());
    -
    828 QFAIL("Malformed or unresolved comment must throw.");
    -
    829 } catch (const std::runtime_error &exception) {
    -
    830 QVERIFY(std::string(exception.what()).find(fixture.path.string() + ":4: ") == 0U);
    -
    831 }
    -
    832}
    -
    833
    -
    834void DbcParserTest::integration() {
    -
    835 Fixture fixture;
    -
    836 fixture.Write(
    -
    837 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
    -
    838 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
    -
    839 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
    -
    840 "BO_ 257 Second: 8 ECU\n");
    -
    841 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    -
    842 CHECK(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
    -
    843 database.frames[0].comment == "Frame comment" &&
    -
    844 database.frames[0].signals[0].comment == "Signal comment",
    -
    845 "Integration");
    -
    846 fixture.Write("\nSG_ Speed : invalid\n");
    -
    847 try {
    -
    848 DbcParser().ParseFile(fixture.path.string());
    -
    849 CHECK(false, "Signal error location");
    -
    850 } catch (const std::runtime_error &error) {
    -
    851 CHECK(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
    -
    852 "Signal error location");
    -
    853 }
    -
    854}
    -
    855
    -
    856void DbcParserTest::multiplexing() {
    -
    857 Fixture fixture;
    -
    858 const std::string selector = "SG_ Mode M : 0|8@1+ (10,3) [0|255] \"\" ECU\n";
    -
    859 const std::string first = "SG_ First m1 : 8|8@1- (2,0) [-128|127] \"V\" ECU\n";
    -
    860 const std::string second = "SG_ Second m2 : 15|8@0+ (1,0) [0|255] \"\" ECU\n";
    -
    861 const std::string common = "SG_ Common : 16|8@1+ (1,0) [0|255] \"\" ECU\n";
    -
    862 fixture.Write("BO_ 1 Frame: 3 ECU\n" + first + second + common + selector +
    -
    863 "VAL_ 1 First -1 \"Negative\";\n");
    -
    864 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    -
    865 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    -
    866 CHECK(parsed.frames[0].signals[3].multiplexing.role == MultiplexRole::Selector,
    -
    867 "Selector declared after branches");
    -
    868 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
    -
    869 CHECK(tree->GetChild(0U)->GetChild(0U)->GetSignal()->multiplexing.value == 1U,
    -
    870 "Tree preserves multiplexing");
    -
    871 RawCanFrame raw;
    -
    872 raw.canId = 1U;
    -
    873 raw.data = {1U, 255U, 7U};
    -
    874 DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
    -
    875 CHECK(result.signals[0].valid && std::get<std::int64_t>(result.signals[0].rawValue) == -1 &&
    -
    876 result.signals[0].physicalValue == -2 && *result.signals[0].GetValueDescription() == "Negative",
    -
    877 "Active signed branch and VAL_ use exact raw selector");
    -
    878 CHECK(!result.signals[1].valid && result.signals[1].status == SignalDecodeStatus::Inactive &&
    -
    879 result.signals[1].GetValueDescription() == nullptr && result.signals[2].valid,
    -
    880 "Inactive branch and unconditional signal");
    -
    881 raw.data[0] = 2U;
    -
    882 result = DbcDecoder().Decode(runtime, raw);
    -
    883 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive && result.signals[1].valid &&
    -
    884 std::get<std::uint64_t>(result.signals[1].rawValue) == 255U,
    -
    885 "Motorola branch becomes active");
    -
    886 raw.data = {3U};
    -
    887 result = DbcDecoder().Decode(runtime, raw);
    -
    888 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive &&
    -
    889 result.signals[1].status == SignalDecodeStatus::Inactive &&
    -
    890 result.signals[2].status == SignalDecodeStatus::InsufficientPayload,
    -
    891 "Unmapped selector leaves branches inactive even with missing bytes");
    -
    892 raw.data = {1U};
    -
    893 result = DbcDecoder().Decode(runtime, raw);
    -
    894 CHECK(result.signals[0].status == SignalDecodeStatus::InsufficientPayload,
    -
    895 "Active branch requires payload");
    -
    896 raw.data.clear();
    -
    897 result = DbcDecoder().Decode(runtime, raw);
    -
    898 CHECK(result.signals[0].status == SignalDecodeStatus::SelectorUnavailable &&
    -
    899 result.signals[3].status == SignalDecodeStatus::InsufficientPayload,
    -
    900 "Unavailable selector does not imply inactive branch");
    -
    901
    -
    902 const std::vector<std::string> invalid = {
    -
    903 first,
    -
    904 selector + "SG_ Other M : 16|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    905 "SG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
    -
    906 selector + "SG_ TooLarge m256 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    907 selector + first + "SG_ Same m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n",
    -
    908 selector + "SG_ Collision m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    909 selector + first + "SG_ Always : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    -
    910 "SG_MUL_VAL_ 1 First Mode 1-2;\n"
    -
    911 };
    -
    912 for (const std::string &signals : invalid) {
    -
    913 fixture.Write("BO_ 1 Frame: 3 ECU\n" + signals);
    -
    914 bool rejected = false;
    -
    915 try {
    -
    916 DbcParser().ParseFile(fixture.path.string());
    -
    917 } catch (const std::runtime_error &error) {
    -
    918 rejected = std::string(error.what()).find(fixture.path.string() + ":") == 0U;
    -
    919 }
    -
    920 CHECK(rejected, "Invalid multiplexing rejected with location");
    -
    921 }
    -
    922 for (const std::string marker : {"m", "m-1", "m+1", "m1M", "m18446744073709551616", "M m1"})
    -
    923 RejectSignal(fixture, "SG_ Bad " + marker + " : 8|8@1+ (1,0) [0|255] \"\" ECU");
    -
    924}
    -
    925
    -
    926void DbcParserTest::multiplexingBoundaries() {
    -
    927 Fixture fixture;
    -
    928 fixture.Write("BO_ 1 Frame: 9 ECU\n"
    -
    929 "SG_ Branch m18446744073709551615 : 64|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    930 "SG_ Mode M : 7|64@0+ (0,5) [0|1] \"\" ECU\n");
    -
    931 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    -
    932 DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    -
    933 CHECK(runtime.GetFrames()[0].signals[0].multiplexing.value == std::numeric_limits<std::uint64_t>::max(),
    -
    934 "Exact uint64 branch metadata");
    -
    935 RawCanFrame raw;
    -
    936 raw.canId = 1U;
    -
    937 raw.data = std::vector<std::uint8_t>(9U, 255U);
    -
    938 DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
    -
    939 CHECK(result.signals[0].valid && result.signals[1].valid &&
    -
    940 std::get<std::uint64_t>(result.signals[1].rawValue) == std::numeric_limits<std::uint64_t>::max(),
    -
    941 "Motorola uint64 selector compares raw value before zero scaling");
    -
    942 raw.data[7] = 254U;
    -
    943 result = DbcDecoder().Decode(runtime, raw);
    -
    944 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive,
    -
    945 "Adjacent large integers remain distinct");
    -
    946 std::vector<DecodeFrame> definitions = runtime.GetFrames();
    -
    947 definitions[0].signals[1].length = 0U;
    -
    948 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, runtime = DecodeDatabase(definitions));
    -
    949 definitions[0].signals.pop_back();
    -
    950 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, runtime = DecodeDatabase(definitions));
    -
    951 fixture.Write("BO_ 1 Frame: 2 ECU\n\n"
    -
    952 "SG_ Branch m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    953 "SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n");
    -
    954 bool rejected = false;
    -
    955 try {
    -
    956 DbcParser().ParseFile(fixture.path.string());
    -
    957 } catch (const std::runtime_error &error) {
    -
    958 rejected = std::string(error.what()).find(fixture.path.string() + ":3: ") == 0U;
    -
    959 }
    -
    960 CHECK(rejected, "Deferred validation reports branch source line");
    -
    961 fixture.Write("BO_ 1 Frame: 2 ECU\n"
    -
    962 "SG_ A : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    -
    963 "SG_ B : 15|8@0+ (1,0) [0|255] \"\" ECU\n");
    -
    964 rejected = false;
    -
    965 try {
    -
    966 DbcParser().ParseFile(fixture.path.string());
    -
    967 } catch (const std::runtime_error &) {
    -
    968 rejected = true;
    -
    969 }
    -
    970 CHECK(rejected, "Ordinary overlapping signals rejected");
    -
    971}
    -
    972
    -
    973void DbcParserTest::invalidSignals() {
    -
    974 Fixture fixture;
    -
    975 const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
    -
    976 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
    -
    977 "4294967296", "999999999999999999999"}) {
    -
    978 RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255"));
    -
    979 RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255"));
    -
    980 }
    -
    981 for (const std::string length: {"0", "65"})
    -
    982 RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255"));
    -
    983 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
    -
    984 RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255"));
    -
    985 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
    -
    986 RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
    -
    987 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
    -
    988 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
    -
    989 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
    -
    990 }
    -
    991 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
    -
    992 for (const std::string name: {"", "Two Names", "Value m1M"}) {
    -
    993 std::string line = ordinary;
    -
    994 line.replace(4U, 5U, name);
    -
    995 RejectSignal(fixture, line);
    -
    996 }
    -
    997 for (const std::string broken: {
    -
    998 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
    -
    999 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
    -
    1000 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
    -
    1001 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
    -
    1002 RejectSignal(fixture, broken);
    -
    1003 RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1"));
    -
    1004 RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3"));
    -
    1005 RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3"));
    -
    1006 RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
    -
    1007 RejectSignal(fixture, ordinary, 0U);
    -
    1008 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
    -
    1009 std::string line = ordinary;
    -
    1010 line.erase(line.find(delimiter), 1U);
    -
    1011 RejectSignal(fixture, line);
    -
    1012 }
    -
    1013}
    -
    1014
    -
    1015void DbcParserTest::validSignals() {
    -
    1016 Fixture fixture;
    -
    1017 const DbcParser signalParser;
    -
    1018 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
    -
    1019 SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
    -
    1020 SignalLine("8", "8", "1-", "-1", "0", "-255", "0", "Negative") + "\n");
    -
    1021 const DbcDatabase factors = signalParser.ParseFile(fixture.path.string());
    -
    1022 CHECK(factors.frames[0].signals.size() == 2U &&
    -
    1023 factors.frames[0].signals[0].factor == 0.0 &&
    -
    1024 factors.frames[0].signals[1].factor == -1.0,
    -
    1025 "Zero and negative factors and equal range boundaries");
    -
    1026
    -
    1027 struct SignalCase {
    -
    1028 const char *start;
    -
    1029 const char *length;
    -
    1030 const char *order;
    -
    1031 unsigned payload;
    -
    1032 };
    -
    1033 const SignalCase validSignals[] = {
    -
    1034 {"0", "1", "1+", 1U},
    -
    1035 {"7", "1", "0-", 1U},
    -
    1036 {"0", "64", "1+", 8U},
    -
    1037 {"7", "64", "0-", 8U},
    -
    1038 {"63", "1", "1+", 8U},
    -
    1039 {"56", "1", "0+", 8U},
    -
    1040 {"3", "12", "0+", 2U},
    -
    1041 {"2039", "1", "1+", 255U}};
    -
    1042 for (const SignalCase &test: validSignals) {
    -
    1043 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
    -
    1044 SignalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
    -
    1045 try {
    -
    1046 const DbcDatabase parsed = signalParser.ParseFile(fixture.path.string());
    -
    1047 const SignalInfo &signal = parsed.frames.at(0).signals.at(0);
    -
    1048 QCOMPARE(signal.startBit, static_cast<std::uint32_t>(std::stoul(test.start)));
    -
    1049 QCOMPARE(signal.length, static_cast<std::uint32_t>(std::stoul(test.length)));
    -
    1050 QCOMPARE(signal.isLittleEndian, test.order[0] == '1');
    -
    1051 QCOMPARE(signal.isSigned, test.order[1] == '-');
    -
    1052 QCOMPARE(signal.factor, 5.0);
    -
    1053 QCOMPARE(signal.offset, -0.25);
    -
    1054 QCOMPARE(signal.minimum, -1.0);
    -
    1055 QCOMPARE(signal.maximum, 200.0);
    -
    1056 } catch (const std::exception &error) { CHECK(false, error.what()); }
    -
    1057 }
    -
    1058 fixture.Write("BO_ 1 Frame: 8 ECU\n"
    -
    1059 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
    -
    1060 try {
    -
    1061 const DbcDatabase parsed = signalParser.ParseFile(fixture.path.string());
    -
    1062 const SignalInfo &signal = parsed.frames.at(0).signals.at(0);
    -
    1063 CHECK(signal.name == "Value" && signal.unit == "rpm" &&
    -
    1064 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
    -
    1065 "Signal tabs, spaces, and receiver list");
    -
    1066 } catch (const std::exception &error) { CHECK(false, error.what()); }
    -
    1067}
    -
    1068
    -
    1069void DbcParserTest::CheckPhysicalNumbers() {
    -
    1070 Fixture fixture;
    -
    1071 struct PhysicalCase {
    -
    1072 const char *factor;
    -
    1073 const char *offset;
    -
    1074 const char *minimum;
    -
    1075 const char *maximum;
    -
    1076 double expectedFactor;
    -
    1077 double expectedOffset;
    -
    1078 double expectedMinimum;
    -
    1079 double expectedMaximum;
    -
    1080 };
    -
    1081 const PhysicalCase valid[] = {
    -
    1082 {"+1.25", "-0.5", "-2.75", "255.5", 1.25, -0.5, -2.75, 255.5},
    -
    1083 {"+.5e+1", "-2.5E-1", "-1.", "+2e2", 5.0, -0.25, -1.0, 200.0},
    -
    1084 {"0e-999", "+0.", "-.0", ".0e+999", 0.0, 0.0, 0.0, 0.0},
    -
    1085 {"1.7976931348623157e308", "2.2250738585072014e-308", "-1e308", "+1e308",
    -
    1086 std::numeric_limits<double>::max(), std::numeric_limits<double>::min(), -1e308, 1e308}};
    -
    1087 for (const PhysicalCase &test: valid) {
    -
    1088 fixture.Write("BO_ 1 Frame: 1 ECU\n" +
    -
    1089 SignalLine("0", "8", "1+", test.factor, test.offset, test.minimum, test.maximum) + "\n");
    -
    1090 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    -
    1091 QVERIFY(!result.HasErrors());
    -
    1092 QVERIFY(result.diagnostics.empty());
    -
    1093 QCOMPARE(result.database.frames.size(), std::size_t(1));
    -
    1094 const SignalInfo &signal = result.database.frames[0].signals[0];
    -
    1095 QCOMPARE(signal.factor, test.expectedFactor);
    -
    1096 QCOMPARE(signal.offset, test.expectedOffset);
    -
    1097 QCOMPARE(signal.minimum, test.expectedMinimum);
    -
    1098 QCOMPARE(signal.maximum, test.expectedMaximum);
    -
    1099 }
    -
    1100
    -
    1101 const char *invalid[] = {"1,5", "1.234,5", "1,234.5", "1junk", "nan", "inf", "-inf",
    -
    1102 "1e999", "1e-999", "1e-320", "-1e-320", "0x1p2", "1e", "1.2.3"};
    -
    1103 for (const char *value: invalid) {
    -
    1104 RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
    -
    1105 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
    -
    1106 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
    -
    1107 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
    -
    1108 }
    -
    1109 RejectSignal(fixture, SignalLine("0", "8", "1+", "1.25", "0", "2.5", "1.5"));
    -
    1110}
    -
    1111
    -
    1112void DbcParserTest::physicalNumbersCppLocale() {
    -
    1113 const ApplicationLocaleGuard guard;
    -
    1114 std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
    -
    1115 QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
    -
    1116 CheckPhysicalNumbers();
    -
    1117 QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
    -
    1118}
    -
    1119
    -
    1120void DbcParserTest::physicalNumbersCLocale() {
    -
    1121 const ApplicationLocaleGuard guard;
    -
    1122 bool found = false;
    -
    1123 const char *names[] = {"de_DE.UTF-8", "de_DE.utf8", "fr_FR.UTF-8", "fr_FR.utf8",
    -
    1124 "German_Germany.1252", "French_France.1252"};
    -
    1125 for (const char *name: names) {
    -
    1126 if (std::setlocale(LC_NUMERIC, name) && std::string(std::localeconv()->decimal_point) == ",") {
    -
    1127 found = true;
    -
    1128 break;
    -
    1129 }
    -
    1130 }
    -
    1131 if (!found)
    -
    1132 QSKIP("No named comma-decimal C locale is installed; generate de_DE.UTF-8 and set LOCPATH.");
    -
    1133 QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
    -
    1134 CheckPhysicalNumbers();
    -
    1135 QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
    -
    1136}
    -
    1137
    -
    1138void DbcParserTest::dispatch() {
    -
    1139 CountingHandler::instances = 0;
    -
    1140 CountingHandler::calls = 0;
    -
    1141 DbcDatabase dispatchDatabase;
    -
    1142 DbcParseContext context{dispatchDatabase, nullptr};
    -
    1143 DbcStatementDispatcher dispatcher;
    -
    1144 dispatcher.RegisterType<CountingHandler>("TEST_");
    -
    1145 CHECK(dispatcher.Dispatch("TEST_ first", context) &&
    -
    1146 dispatcher.Dispatch("TEST_ second", context) &&
    -
    1147 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
    -
    1148 dispatchDatabase.frames.size() == 2U,
    -
    1149 "Factory dispatch and handler reuse");
    -
    1150 CHECK(!dispatcher.Dispatch("TEST_OTHER data", context) &&
    -
    1151 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
    -
    1152 !dispatcher.Dispatch("VAL_TABLE_ States 0 \"Stopped\";", context) &&
    -
    1153 CountingHandler::calls == 2,
    -
    1154 "Exact and unknown keyword dispatch");
    -
    1155}
    -
    1156
    -
    1157void DbcParserTest::independentSessions() {
    -
    1158 Fixture fixture;
    -
    1159 const DbcParser parser;
    -
    1160 fixture.Write("BO_ 1 First: 8 ECU\n");
    -
    1161 CHECK(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
    -
    1162 fixture.Write("SG_ Speed : invalid\n");
    -
    1163 try {
    -
    1164 parser.ParseFile(fixture.path.string());
    -
    1165 CHECK(false, "Independent parse context");
    -
    1166 } catch (const std::runtime_error &error) {
    -
    1167 CHECK(std::string(error.what()).find("Signal found before any frame") !=
    -
    1168 std::string::npos,
    -
    1169 "Independent parse context");
    -
    1170 }
    -
    1171 fixture.Write("BO_ 2 Second: 8 ECU\n");
    -
    1172 const DbcDatabase recovered = parser.ParseFile(fixture.path.string());
    -
    1173 CHECK(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
    -
    1174 "Fresh parse after error");
    -
    1175}
    -
    1176
    -
    1177
    -
    1178void DbcParserTest::valueDescriptions() {
    -
    1179 Fixture fixture;
    -
    1180 fixture.Write(
    -
    1181 "VAL_\t256\tState\t0\t\"Off\"\t1 \"On\" 2 \"Error with spaces; and \\\"quotes\\\"\";\n"
    -
    1182 "BO_ 256 Status: 8 ECU\n"
    -
    1183 "SG_ State : 0|8@1+ (2,10) [0|520] \"\" ECU\n"
    -
    1184 "VAL_ 256 State 3 \"\";\n"
    -
    1185 "VAL_ 2147483904 State -9223372036854775808 \"Minimum\" -1 \"Negative\" 9223372036854775807 \"Maximum\";\n"
    -
    1186 "BO_ 2147483904 Extended: 8 ECU\n"
    -
    1187 "SG_ State : 0|64@1- (1,0) [-1e20|1e20] \"\" ECU\n"
    -
    1188 "BO_ 2048 Unsigned: 8 ECU\n"
    -
    1189 "SG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n"
    -
    1190 "VAL_ 2147485696 State 9223372036854775808 \"High\" 18446744073709551615 \"Full\";\n");
    -
    1191 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    -
    1192 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    -
    1193 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
    -
    1194 CHECK(tree->GetChild(0)->GetSignal() == nullptr, "Frame node");
    -
    1195 for (std::size_t index = 0; index < parsed.frames.size(); ++index) {
    -
    1196 CHECK(tree->GetChild(index)->GetChild(0)->GetSignal()->valueDescriptions ==
    -
    1197 parsed.frames[index].signals[0].valueDescriptions &&
    -
    1198 runtime.GetFrames()[index].signals[0].valueDescriptions ==
    -
    1199 parsed.frames[index].signals[0].valueDescriptions,
    -
    1200 "All mappings survive both builders");
    -
    1201 }
    -
    1202 CHECK(tree->GetChild(0)->GetChild(0)->GetSignal()->valueDescriptions ==
    -
    1203 runtime.GetFrames()[0].signals[0].valueDescriptions,
    -
    1204 "Both builders preserve descriptions");
    -
    1205 RawCanFrame frame;
    -
    1206 frame.canId = 256;
    -
    1207 frame.data.resize(8);
    -
    1208 const std::string expected[] = {"Off", "On", "Error with spaces; and \"quotes\"", ""};
    -
    1209 for (unsigned value = 0; value < 5; ++value) {
    -
    1210 frame.data[0] = value;
    -
    1211 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    -
    1212 CHECK(decoded.valid && decoded.physicalValue == value * 2 + 10, "Numeric scaling unchanged");
    -
    1213 const std::string *description = decoded.GetValueDescription();
    -
    1214 CHECK(value < 4 ? description && *description == expected[value] : !description,
    -
    1215 "Raw lookup and unknown value");
    -
    1216 }
    -
    1217 frame.isExtended = true;
    -
    1218 struct Boundary {
    -
    1219 std::uint64_t bits;
    -
    1220 const char *description;
    -
    1221 };
    -
    1222 for (const Boundary &test: {Boundary{0x8000000000000000ULL, "Minimum"},
    -
    1223 Boundary{0xFFFFFFFFFFFFFFFFULL, "Negative"},
    -
    1224 Boundary{0x7FFFFFFFFFFFFFFFULL, "Maximum"}}) {
    -
    1225 for (unsigned byte = 0; byte < 8; ++byte)
    -
    1226 frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
    -
    1227 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    -
    1228 CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
    -
    1229 "Signed boundaries and distinct extended frame");
    -
    1230 }
    -
    1231 frame.canId = 2048;
    -
    1232 for (const Boundary &test: {Boundary{0x8000000000000000ULL, "High"},
    -
    1233 Boundary{0xFFFFFFFFFFFFFFFFULL, "Full"}}) {
    -
    1234 for (unsigned byte = 0; byte < 8; ++byte)
    -
    1235 frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
    -
    1236 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    -
    1237 CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
    -
    1238 "Unsigned boundaries");
    -
    1239 }
    -
    1240 CHECK(FindValueDescription(runtime.GetFrames()[0].signals[0].valueDescriptions, std::int64_t(1)) != nullptr,
    -
    1241 "Nonnegative signed lookup matches unsigned key");
    -
    1242 frame.data.clear();
    -
    1243 CHECK(!DbcDecoder().Decode(runtime, frame).signals[0].GetValueDescription(), "Invalid decode has no description");
    -
    1244}
    -
    1245
    -
    1246void DbcParserTest::invalidValueDescriptions() {
    -
    1247 Fixture fixture;
    -
    1248 const std::string definitions = "BO_ 1 Frame: 8 ECU\nSG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n";
    -
    1249 for (const std::string statement: {
    -
    1250 "VAL_", "VAL_ 1 State;", "VAL_ 1 State ;", "VAL_ 1 State 0 \"Off\"",
    -
    1251 "VAL_ 1 State 0 \"Off\"; junk", "VAL_ 1 State 0 Off;",
    -
    1252 "VAL_ 1 State 0 \"Unclosed;", "VAL_ 1 State 0 \"Off\"1 \"On\";",
    -
    1253 "VAL_ 1 State 0 \"Off\" 00 \"Duplicate\";",
    -
    1254 "VAL_ 1 State 0 \"Off\" -0 \"Duplicate\";",
    -
    1255 "VAL_ 1 State 0 \"Off\";\nVAL_ 1 State 0 \"Duplicate\";",
    -
    1256 "VAL_ 2 State 0 \"Missing frame\";", "VAL_ 1 Missing 0 \"Missing signal\";",
    -
    1257 "VAL_ -1 State 0 \"Bad ID\";", "VAL_ 536870912 State 0 \"Bad ID\";",
    -
    1258 "VAL_ 4294967296 State 0 \"Bad ID\";", "VAL_ Environment 0 \"Unsupported\";",
    -
    1259 "VAL_ 1 State 0 \"Bad\\q escape\";"}) {
    -
    1260 fixture.Write(definitions + statement + '\n');
    -
    1261 const int line = statement.find('\n') == std::string::npos ? 3 : 4;
    -
    1262 try {
    -
    1263 DbcParser().ParseFile(fixture.path.string());
    -
    1264 CHECK(false, statement);
    -
    1265 } catch (const std::runtime_error &error) {
    -
    1266 CHECK(std::string(error.what()).find(fixture.path.string() + ":" + std::to_string(line) + ": ") == 0,
    -
    1267 statement + " " + error.what());
    -
    1268 }
    -
    1269 }
    -
    1270 for (const std::string suffix: {
    -
    1271 "BO_ 1 Other: 8 ECU\n", // Duplicate frame definition.
    -
    1272 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n",// Duplicate signal definition.
    -
    1273 ""}) {
    -
    1274 fixture.Write("VAL_ 1 " + std::string(suffix.empty() ? "Missing" : "State") +
    -
    1275 " 0 \"Description\";\n" + definitions + suffix);
    -
    1276 try {
    -
    1277 DbcParser().ParseFile(fixture.path.string());
    -
    1278 CHECK(false, "Missing reference or duplicate definition");
    -
    1279 } catch (const std::runtime_error &error) {
    -
    1280 const std::string line = suffix.empty() ? "1" : "4";
    -
    1281 CHECK(std::string(error.what()).find(fixture.path.string() + ":" + line + ": ") == 0,
    -
    1282 "Error retains the reference or duplicate definition source location");
    -
    1283 }
    -
    1284 }
    -
    1285 for (const std::string number: {"+1", "1x", "0x10", "1.5", "1e2", "--1",
    -
    1286 "-9223372036854775809", "18446744073709551616"}) {
    -
    1287 fixture.Write("VAL_ 1 State " + number + " \"Bad\";\n" + definitions);
    -
    1288 try {
    -
    1289 DbcParser().ParseFile(fixture.path.string());
    -
    1290 CHECK(false, number);
    -
    1291 } catch (const std::runtime_error &error) {
    -
    1292 CHECK(std::string(error.what()).find(fixture.path.string() + ":1: ") == 0, number);
    -
    1293 }
    -
    1294 }
    -
    1295}
    -
    1296
    -
    1297int RunParserTests(int argc, char **argv) {
    -
    1298 DbcParserTest tests;
    -
    1299 return QTest::qExec(&tests, argc, argv);
    -
    1300}
    -
    1301
    -
    1302#include "dbc_parser_test.moc"
    +
    761void DbcParserTest::duplicateSignals() {
    +
    762 Fixture fixture;
    +
    763 const std::string first = "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n";
    +
    764 const std::string duplicates[] = {
    +
    765 first,
    +
    766 " SG_\tState : 16|8@1+ (2,1) [0|511] \"V\" ECU\n",
    +
    767 "SG_ State m1 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    768 };
    +
    769 for (const std::string &duplicate : duplicates) {
    +
    770 fixture.Write("BO_ 1 Frame: 8 ECU\n" + first +
    +
    771 "SG_ Other : 8|8@1+ (1,0) [0|255] \"\" ECU\n\n" + duplicate);
    +
    772 try {
    +
    773 DbcParser().ParseFile(fixture.path.string());
    +
    774 CHECK(false, "Duplicate signal must be rejected");
    +
    775 } catch (const std::runtime_error &error) {
    +
    776 QCOMPARE(std::string(error.what()), fixture.path.string() +
    +
    777 ":5: Duplicate signal name 'State' in frame 'Frame'.");
    +
    778 }
    +
    779 }
    +
    780}
    +
    781
    +
    782void DbcParserTest::distinctDefinitions() {
    +
    783 Fixture fixture;
    +
    784 fixture.Write("BO_ 1 Shared: 1 ECU\n"
    +
    785 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    786 "BO_ 2147483649 Shared: 1 ECU\n"
    +
    787 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    788 "BO_ 2 Shared: 2 ECU\n"
    +
    789 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    790 "SG_ state : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    791 "CM_ BO_ 1 \"Standard\";\n"
    +
    792 "CM_ BO_ 2147483649 \"Extended\";\n"
    +
    793 "CM_ SG_ 1 State \"Standard state\";\n"
    +
    794 "CM_ SG_ 2147483649 State \"Extended state\";\n");
    +
    795 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    +
    796 QCOMPARE(parsed.frames.size(), std::size_t(3U));
    +
    797 QCOMPARE(parsed.frames[0].canId, parsed.frames[1].canId);
    +
    798 CHECK(!parsed.frames[0].isExtended && parsed.frames[1].isExtended,
    +
    799 "Standard and extended frames with the same numeric ID remain distinct");
    +
    800 QCOMPARE(parsed.frames[0].comment, std::string("Standard"));
    +
    801 QCOMPARE(parsed.frames[1].comment, std::string("Extended"));
    +
    802 QCOMPARE(parsed.frames[0].signals[0].comment, std::string("Standard state"));
    +
    803 QCOMPARE(parsed.frames[1].signals[0].comment, std::string("Extended state"));
    +
    804 QCOMPARE(parsed.frames[2].signals.size(), std::size_t(2U));
    +
    805 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    +
    806 RawCanFrame raw;
    +
    807 raw.canId = 1U;
    +
    808 raw.data = {7U};
    +
    809 const DecodedFrameValue standard = DbcDecoder().Decode(runtime, raw);
    +
    810 QVERIFY(standard.valid);
    +
    811 QCOMPARE(standard.definition->comment, std::string("Standard"));
    +
    812 raw.isExtended = true;
    +
    813 const DecodedFrameValue extended = DbcDecoder().Decode(runtime, raw);
    +
    814 QVERIFY(extended.valid);
    +
    815 QCOMPARE(extended.definition->comment, std::string("Extended"));
    +
    816}
    +
    817
    +
    818void DbcParserTest::comments() {
    +
    819 Fixture fixture;
    +
    820 fixture.Write(
    +
    821 "CM_\tBO_\t1\t\"First\";\r\n"
    +
    822 "CM_\tSG_\t1\tState\t\" Line one \r\n"
    +
    823 "\r\n"
    +
    824 "\tBO_ is text; \\\"quoted\\\" and \\\\slash\"\t;\r\n"
    +
    825 "CM_ BO_ 2147483649 \"Extended\";\r\n"
    +
    826 "CM_ SG_ 2147483649 State \"Extended signal\";\r\n"
    +
    827 "BO_ 1 Standard: 1 ECU\r\n"
    +
    828 "CM_ BO_ 1 \"Last\";\r\n"
    +
    829 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\r\n"
    +
    830 "BO_ 2147483649 Extended: 1 ECU\r\n"
    +
    831 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU");
    +
    832 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    833 QVERIFY(!result.HasErrors());
    +
    834 QVERIFY(result.diagnostics.empty());
    +
    835 QCOMPARE(result.database.frames.size(), std::size_t(2));
    +
    836 QCOMPARE(result.database.frames[0].comment, std::string("Last"));
    +
    837 QCOMPARE(result.database.frames[0].signals[0].comment,
    +
    838 std::string(" Line one \n\n\tBO_ is text; \"quoted\" and \\slash"));
    +
    839 QCOMPARE(result.database.frames[1].comment, std::string("Extended"));
    +
    840 QCOMPARE(result.database.frames[1].signals[0].comment, std::string("Extended signal"));
    +
    841
    +
    842 const std::string ids[][2] = {
    +
    843 {"0", "0"},
    +
    844 {"2047", "2047"},
    +
    845 {"2048", "2147485696"},
    +
    846 {"536870911", "2684354559"},
    +
    847 {"2684354559", "536870911"}};
    +
    848 for (const std::string(&id)[2]: ids) {
    +
    849 fixture.Write("CM_ BO_ " + id[0] + " \"Frame\";\nCM_ SG_ " + id[0] +
    +
    850 " State \"Signal\";\nBO_ " + id[1] + " Frame: 1 ECU\n"
    +
    851 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n");
    +
    852 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    +
    853 QCOMPARE(database.frames[0].comment, std::string("Frame"));
    +
    854 QCOMPARE(database.frames[0].signals[0].comment, std::string("Signal"));
    +
    855 }
    +
    856 fixture.Write("CM_ BO_ 1 \"Line one\nLine two\";\n"
    +
    857 "BO_ 1 Frame: 0 ECU\nUNKNOWN_ value\nBO_ bad Frame: 0 ECU\n");
    +
    858 const DbcParseResult following = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    859 QVERIFY(following.HasErrors());
    +
    860 QCOMPARE(following.diagnostics.size(), std::size_t(2));
    +
    861 QCOMPARE(following.diagnostics[0].lineNumber, std::size_t(4));
    +
    862 QCOMPARE(following.diagnostics[1].lineNumber, std::size_t(5));
    +
    863}
    +
    864
    +
    865void DbcParserTest::invalidComments_data() {
    +
    866 QTest::addColumn<QString>("statement");
    +
    867 const char *ids[] = {"-1", "+1", "1x", "0x1", "4294967296", "536870912",
    +
    868 "1073741824", "2684354560", "4294967295"};
    +
    869 for (const char *id: ids) {
    +
    870 const std::string frameRow = std::string("frame-id-") + id;
    +
    871 const std::string signalRow = std::string("signal-id-") + id;
    +
    872 QTest::newRow(frameRow.c_str()) << QString::fromStdString("CM_ BO_ " + std::string(id) + " \"Text\";");
    +
    873 QTest::newRow(signalRow.c_str()) << QString::fromStdString("CM_ SG_ " + std::string(id) + " State \"Text\";");
    +
    874 }
    +
    875 QTest::newRow("missing-id") << QStringLiteral("CM_ BO_");
    +
    876 QTest::newRow("missing-signal") << QStringLiteral("CM_ SG_ 1 \"Text\";");
    +
    877 QTest::newRow("missing-quote") << QStringLiteral("CM_ BO_ 1 Text;");
    +
    878 QTest::newRow("unclosed") << QStringLiteral("CM_ SG_ 1 State \"Text\n More");
    +
    879 QTest::newRow("invalid-escape") << QStringLiteral("CM_ BO_ 1 \"bad\\q\";");
    +
    880 QTest::newRow("dangling-escape") << QStringLiteral("CM_ BO_ 1 \"bad\\");
    +
    881 QTest::newRow("missing-semicolon") << QStringLiteral("CM_ SG_ 1 State \"Text\"");
    +
    882 QTest::newRow("trailing-text") << QStringLiteral("CM_ BO_ 1 \"Text\"; garbage");
    +
    883 QTest::newRow("extra-header") << QStringLiteral("CM_ BO_ 1 extra \"Text\";");
    +
    884 QTest::newRow("extra-string") << QStringLiteral("CM_ BO_ 1 \"Text\" \"More\";");
    +
    885 QTest::newRow("missing-frame") << QStringLiteral("CM_ BO_ 2 \"Text\";");
    +
    886 QTest::newRow("missing-signal-frame") << QStringLiteral("CM_ SG_ 2 State \"Text\";");
    +
    887 QTest::newRow("missing-signal-reference") << QStringLiteral("CM_ SG_ 1 Missing \"Text\";");
    +
    888 QTest::newRow("different-frame-type") << QStringLiteral("CM_ BO_ 2147483649 \"Text\";");
    +
    889 QTest::newRow("missing-multiline-reference") << QStringLiteral("CM_ SG_ 1 Missing \"Text\nMore\";");
    +
    890}
    +
    891
    +
    892void DbcParserTest::invalidComments() {
    +
    893 QFETCH(QString, statement);
    +
    894 Fixture fixture;
    +
    895 fixture.Write("BO_ 1 Frame: 1 ECU\nSG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n\n" +
    +
    896 statement.toStdString());
    +
    897 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    898 QVERIFY(result.HasErrors());
    +
    899 QVERIFY(result.database.frames.empty());
    +
    900 QCOMPARE(result.diagnostics.size(), std::size_t(1));
    +
    901 const DbcDiagnostic &error = result.diagnostics[0];
    +
    902 QCOMPARE(error.severity, DbcDiagnosticSeverity::Error);
    +
    903 QCOMPARE(error.code, DbcDiagnosticCode::InvalidStatement);
    +
    904 QCOMPARE(error.filePath, fixture.path.string());
    +
    905 QCOMPARE(error.lineNumber, std::size_t(4));
    +
    906 QVERIFY(!error.message.empty());
    +
    907 try {
    +
    908 DbcParser().ParseFile(fixture.path.string());
    +
    909 QFAIL("Malformed or unresolved comment must throw.");
    +
    910 } catch (const std::runtime_error &exception) {
    +
    911 QVERIFY(std::string(exception.what()).find(fixture.path.string() + ":4: ") == 0U);
    +
    912 }
    +
    913}
    +
    914
    +
    915void DbcParserTest::integration() {
    +
    916 Fixture fixture;
    +
    917 fixture.Write(
    +
    918 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
    +
    919 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
    +
    920 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
    +
    921 "BO_ 257 Second: 8 ECU\n");
    +
    922 const DbcDatabase database = DbcParser().ParseFile(fixture.path.string());
    +
    923 CHECK(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
    +
    924 database.frames[0].comment == "Frame comment" &&
    +
    925 database.frames[0].signals[0].comment == "Signal comment",
    +
    926 "Integration");
    +
    927 fixture.Write("\nSG_ Speed : invalid\n");
    +
    928 try {
    +
    929 DbcParser().ParseFile(fixture.path.string());
    +
    930 CHECK(false, "Signal error location");
    +
    931 } catch (const std::runtime_error &error) {
    +
    932 CHECK(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
    +
    933 "Signal error location");
    +
    934 }
    +
    935}
    +
    936
    +
    937void DbcParserTest::multiplexing() {
    +
    938 Fixture fixture;
    +
    939 const std::string selector = "SG_ Mode M : 0|8@1+ (10,3) [0|255] \"\" ECU\n";
    +
    940 const std::string first = "SG_ First m1 : 8|8@1- (2,0) [-128|127] \"V\" ECU\n";
    +
    941 const std::string second = "SG_ Second m2 : 15|8@0+ (1,0) [0|255] \"\" ECU\n";
    +
    942 const std::string common = "SG_ Common : 16|8@1+ (1,0) [0|255] \"\" ECU\n";
    +
    943 fixture.Write("BO_ 1 Frame: 3 ECU\n" + first + second + common + selector +
    +
    944 "VAL_ 1 First -1 \"Negative\";\n");
    +
    945 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    +
    946 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    +
    947 CHECK(parsed.frames[0].signals[3].multiplexing.role == MultiplexRole::Selector,
    +
    948 "Selector declared after branches");
    +
    949 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
    +
    950 CHECK(tree->GetChild(0U)->GetChild(0U)->GetSignal()->multiplexing.value == 1U,
    +
    951 "Tree preserves multiplexing");
    +
    952 RawCanFrame raw;
    +
    953 raw.canId = 1U;
    +
    954 raw.data = {1U, 255U, 7U};
    +
    955 DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
    +
    956 CHECK(result.signals[0].valid && std::get<std::int64_t>(result.signals[0].rawValue) == -1 &&
    +
    957 result.signals[0].physicalValue == -2 && *result.signals[0].GetValueDescription() == "Negative",
    +
    958 "Active signed branch and VAL_ use exact raw selector");
    +
    959 CHECK(!result.signals[1].valid && result.signals[1].status == SignalDecodeStatus::Inactive &&
    +
    960 result.signals[1].GetValueDescription() == nullptr && result.signals[2].valid,
    +
    961 "Inactive branch and unconditional signal");
    +
    962 raw.data[0] = 2U;
    +
    963 result = DbcDecoder().Decode(runtime, raw);
    +
    964 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive && result.signals[1].valid &&
    +
    965 std::get<std::uint64_t>(result.signals[1].rawValue) == 255U,
    +
    966 "Motorola branch becomes active");
    +
    967 raw.data = {3U};
    +
    968 result = DbcDecoder().Decode(runtime, raw);
    +
    969 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive &&
    +
    970 result.signals[1].status == SignalDecodeStatus::Inactive &&
    +
    971 result.signals[2].status == SignalDecodeStatus::InsufficientPayload,
    +
    972 "Unmapped selector leaves branches inactive even with missing bytes");
    +
    973 raw.data = {1U};
    +
    974 result = DbcDecoder().Decode(runtime, raw);
    +
    975 CHECK(result.signals[0].status == SignalDecodeStatus::InsufficientPayload,
    +
    976 "Active branch requires payload");
    +
    977 raw.data.clear();
    +
    978 result = DbcDecoder().Decode(runtime, raw);
    +
    979 CHECK(result.signals[0].status == SignalDecodeStatus::SelectorUnavailable &&
    +
    980 result.signals[3].status == SignalDecodeStatus::InsufficientPayload,
    +
    981 "Unavailable selector does not imply inactive branch");
    +
    982
    +
    983 const std::vector<std::string> invalid = {
    +
    984 first,
    +
    985 selector + "SG_ Other M : 16|8@1- (1,0) [-128|127] \"\" ECU\n",
    +
    986 "SG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
    +
    987 selector + "SG_ TooLarge m256 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    988 selector + first + "SG_ Same m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n",
    +
    989 selector + "SG_ Collision m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    990 selector + first + "SG_ Always : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
    +
    991 "SG_MUL_VAL_ 1 First Mode 1-2;\n"};
    +
    992 for (const std::string &signals : invalid) {
    +
    993 fixture.Write("BO_ 1 Frame: 3 ECU\n" + signals);
    +
    994 bool rejected = false;
    +
    995 try {
    +
    996 DbcParser().ParseFile(fixture.path.string());
    +
    997 } catch (const std::runtime_error &error) {
    +
    998 rejected = std::string(error.what()).find(fixture.path.string() + ":") == 0U;
    +
    999 }
    +
    1000 CHECK(rejected, "Invalid multiplexing rejected with location");
    +
    1001 }
    +
    1002 for (const std::string marker : {"m", "m-1", "m+1", "m1M", "m18446744073709551616", "M m1"})
    +
    1003 RejectSignal(fixture, "SG_ Bad " + marker + " : 8|8@1+ (1,0) [0|255] \"\" ECU");
    +
    1004}
    +
    1005
    +
    1006void DbcParserTest::multiplexingBoundaries() {
    +
    1007 Fixture fixture;
    +
    1008 fixture.Write("BO_ 1 Frame: 9 ECU\n"
    +
    1009 "SG_ Branch m18446744073709551615 : 64|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1010 "SG_ Mode M : 7|64@0+ (0,5) [0|1] \"\" ECU\n");
    +
    1011 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    +
    1012 DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    +
    1013 CHECK(runtime.GetFrames()[0].signals[0].multiplexing.value == std::numeric_limits<std::uint64_t>::max(),
    +
    1014 "Exact uint64 branch metadata");
    +
    1015 RawCanFrame raw;
    +
    1016 raw.canId = 1U;
    +
    1017 raw.data = std::vector<std::uint8_t>(9U, 255U);
    +
    1018 DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
    +
    1019 CHECK(result.signals[0].valid && result.signals[1].valid &&
    +
    1020 std::get<std::uint64_t>(result.signals[1].rawValue) == std::numeric_limits<std::uint64_t>::max(),
    +
    1021 "Motorola uint64 selector compares raw value before zero scaling");
    +
    1022 raw.data[7] = 254U;
    +
    1023 result = DbcDecoder().Decode(runtime, raw);
    +
    1024 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive,
    +
    1025 "Adjacent large integers remain distinct");
    +
    1026 std::vector<DecodeFrame> definitions = runtime.GetFrames();
    +
    1027 definitions[0].signals[1].length = 0U;
    +
    1028 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, runtime = DecodeDatabase(definitions));
    +
    1029 definitions[0].signals.pop_back();
    +
    1030 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, runtime = DecodeDatabase(definitions));
    +
    1031 fixture.Write("BO_ 1 Frame: 2 ECU\n\n"
    +
    1032 "SG_ Branch m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1033 "SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n");
    +
    1034 bool rejected = false;
    +
    1035 try {
    +
    1036 DbcParser().ParseFile(fixture.path.string());
    +
    1037 } catch (const std::runtime_error &error) {
    +
    1038 rejected = std::string(error.what()).find(fixture.path.string() + ":3: ") == 0U;
    +
    1039 }
    +
    1040 CHECK(rejected, "Deferred validation reports branch source line");
    +
    1041 fixture.Write("BO_ 1 Frame: 2 ECU\n"
    +
    1042 "SG_ A : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1043 "SG_ B : 15|8@0+ (1,0) [0|255] \"\" ECU\n");
    +
    1044 rejected = false;
    +
    1045 try {
    +
    1046 DbcParser().ParseFile(fixture.path.string());
    +
    1047 } catch (const std::runtime_error &) {
    +
    1048 rejected = true;
    +
    1049 }
    +
    1050 CHECK(rejected, "Ordinary overlapping signals rejected");
    +
    1051}
    +
    1052
    +
    1053void DbcParserTest::invalidSignals() {
    +
    1054 Fixture fixture;
    +
    1055 const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
    +
    1056 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
    +
    1057 "4294967296", "999999999999999999999"}) {
    +
    1058 RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255"));
    +
    1059 RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255"));
    +
    1060 }
    +
    1061 for (const std::string length: {"0", "65"})
    +
    1062 RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255"));
    +
    1063 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
    +
    1064 RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255"));
    +
    1065 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
    +
    1066 RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
    +
    1067 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
    +
    1068 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
    +
    1069 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
    +
    1070 }
    +
    1071 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
    +
    1072 for (const std::string name: {"", "Two Names", "Value m1M"}) {
    +
    1073 std::string line = ordinary;
    +
    1074 line.replace(4U, 5U, name);
    +
    1075 RejectSignal(fixture, line);
    +
    1076 }
    +
    1077 for (const std::string broken: {
    +
    1078 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
    +
    1079 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
    +
    1080 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
    +
    1081 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
    +
    1082 RejectSignal(fixture, broken);
    +
    1083 RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1"));
    +
    1084 RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3"));
    +
    1085 RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3"));
    +
    1086 RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
    +
    1087 RejectSignal(fixture, ordinary, 0U);
    +
    1088 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
    +
    1089 std::string line = ordinary;
    +
    1090 line.erase(line.find(delimiter), 1U);
    +
    1091 RejectSignal(fixture, line);
    +
    1092 }
    +
    1093}
    +
    1094
    +
    1095void DbcParserTest::validSignals() {
    +
    1096 Fixture fixture;
    +
    1097 const DbcParser signalParser;
    +
    1098 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
    +
    1099 SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
    +
    1100 SignalLine("8", "8", "1-", "-1", "0", "-255", "0", "Negative") + "\n");
    +
    1101 const DbcDatabase factors = signalParser.ParseFile(fixture.path.string());
    +
    1102 CHECK(factors.frames[0].signals.size() == 2U &&
    +
    1103 factors.frames[0].signals[0].factor == 0.0 &&
    +
    1104 factors.frames[0].signals[1].factor == -1.0,
    +
    1105 "Zero and negative factors and equal range boundaries");
    +
    1106
    +
    1107 struct SignalCase {
    +
    1108 const char *start;
    +
    1109 const char *length;
    +
    1110 const char *order;
    +
    1111 unsigned payload;
    +
    1112 };
    +
    1113 const SignalCase validSignals[] = {
    +
    1114 {"0", "1", "1+", 1U},
    +
    1115 {"7", "1", "0-", 1U},
    +
    1116 {"0", "64", "1+", 8U},
    +
    1117 {"7", "64", "0-", 8U},
    +
    1118 {"63", "1", "1+", 8U},
    +
    1119 {"56", "1", "0+", 8U},
    +
    1120 {"3", "12", "0+", 2U},
    +
    1121 {"2039", "1", "1+", 255U}};
    +
    1122 for (const SignalCase &test: validSignals) {
    +
    1123 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
    +
    1124 SignalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
    +
    1125 try {
    +
    1126 const DbcDatabase parsed = signalParser.ParseFile(fixture.path.string());
    +
    1127 const SignalInfo &signal = parsed.frames.at(0).signals.at(0);
    +
    1128 QCOMPARE(signal.startBit, static_cast<std::uint32_t>(std::stoul(test.start)));
    +
    1129 QCOMPARE(signal.length, static_cast<std::uint32_t>(std::stoul(test.length)));
    +
    1130 QCOMPARE(signal.isLittleEndian, test.order[0] == '1');
    +
    1131 QCOMPARE(signal.isSigned, test.order[1] == '-');
    +
    1132 QCOMPARE(signal.factor, 5.0);
    +
    1133 QCOMPARE(signal.offset, -0.25);
    +
    1134 QCOMPARE(signal.minimum, -1.0);
    +
    1135 QCOMPARE(signal.maximum, 200.0);
    +
    1136 } catch (const std::exception &error) { CHECK(false, error.what()); }
    +
    1137 }
    +
    1138 fixture.Write("BO_ 1 Frame: 8 ECU\n"
    +
    1139 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
    +
    1140 try {
    +
    1141 const DbcDatabase parsed = signalParser.ParseFile(fixture.path.string());
    +
    1142 const SignalInfo &signal = parsed.frames.at(0).signals.at(0);
    +
    1143 CHECK(signal.name == "Value" && signal.unit == "rpm" &&
    +
    1144 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
    +
    1145 "Signal tabs, spaces, and receiver list");
    +
    1146 } catch (const std::exception &error) { CHECK(false, error.what()); }
    +
    1147}
    +
    1148
    +
    1149void DbcParserTest::CheckPhysicalNumbers() {
    +
    1150 Fixture fixture;
    +
    1151 struct PhysicalCase {
    +
    1152 const char *factor;
    +
    1153 const char *offset;
    +
    1154 const char *minimum;
    +
    1155 const char *maximum;
    +
    1156 double expectedFactor;
    +
    1157 double expectedOffset;
    +
    1158 double expectedMinimum;
    +
    1159 double expectedMaximum;
    +
    1160 };
    +
    1161 const PhysicalCase valid[] = {
    +
    1162 {"+1.25", "-0.5", "-2.75", "255.5", 1.25, -0.5, -2.75, 255.5},
    +
    1163 {"+.5e+1", "-2.5E-1", "-1.", "+2e2", 5.0, -0.25, -1.0, 200.0},
    +
    1164 {"0e-999", "+0.", "-.0", ".0e+999", 0.0, 0.0, 0.0, 0.0},
    +
    1165 {"1.7976931348623157e308", "2.2250738585072014e-308", "-1e308", "+1e308",
    +
    1166 std::numeric_limits<double>::max(), std::numeric_limits<double>::min(), -1e308, 1e308}};
    +
    1167 for (const PhysicalCase &test: valid) {
    +
    1168 fixture.Write("BO_ 1 Frame: 1 ECU\n" +
    +
    1169 SignalLine("0", "8", "1+", test.factor, test.offset, test.minimum, test.maximum) + "\n");
    +
    1170 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    1171 QVERIFY(!result.HasErrors());
    +
    1172 QVERIFY(result.diagnostics.empty());
    +
    1173 QCOMPARE(result.database.frames.size(), std::size_t(1));
    +
    1174 const SignalInfo &signal = result.database.frames[0].signals[0];
    +
    1175 QCOMPARE(signal.factor, test.expectedFactor);
    +
    1176 QCOMPARE(signal.offset, test.expectedOffset);
    +
    1177 QCOMPARE(signal.minimum, test.expectedMinimum);
    +
    1178 QCOMPARE(signal.maximum, test.expectedMaximum);
    +
    1179 }
    +
    1180
    +
    1181 const char *invalid[] = {"1,5", "1.234,5", "1,234.5", "1junk", "nan", "inf", "-inf",
    +
    1182 "1e999", "1e-999", "1e-320", "-1e-320", "0x1p2", "1e", "1.2.3"};
    +
    1183 for (const char *value: invalid) {
    +
    1184 RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
    +
    1185 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
    +
    1186 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
    +
    1187 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
    +
    1188 }
    +
    1189 RejectSignal(fixture, SignalLine("0", "8", "1+", "1.25", "0", "2.5", "1.5"));
    +
    1190}
    +
    1191
    +
    1192void DbcParserTest::physicalNumbersCppLocale() {
    +
    1193 const ApplicationLocaleGuard guard;
    +
    1194 std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
    +
    1195 QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
    +
    1196 CheckPhysicalNumbers();
    +
    1197 QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
    +
    1198}
    +
    1199
    +
    1200void DbcParserTest::physicalNumbersCLocale() {
    +
    1201 const ApplicationLocaleGuard guard;
    +
    1202 bool found = false;
    +
    1203 const char *names[] = {"de_DE.UTF-8", "de_DE.utf8", "fr_FR.UTF-8", "fr_FR.utf8",
    +
    1204 "German_Germany.1252", "French_France.1252"};
    +
    1205 for (const char *name: names) {
    +
    1206 if (std::setlocale(LC_NUMERIC, name) && std::string(std::localeconv()->decimal_point) == ",") {
    +
    1207 found = true;
    +
    1208 break;
    +
    1209 }
    +
    1210 }
    +
    1211 if (!found)
    +
    1212 QSKIP("No named comma-decimal C locale is installed; generate de_DE.UTF-8 and set LOCPATH.");
    +
    1213 QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
    +
    1214 CheckPhysicalNumbers();
    +
    1215 QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
    +
    1216}
    +
    1217
    +
    1218void DbcParserTest::dispatch() {
    +
    1219 CountingHandler::instances = 0;
    +
    1220 CountingHandler::calls = 0;
    +
    1221 DbcDatabase dispatchDatabase;
    +
    1222 DbcParseContext context{dispatchDatabase, nullptr};
    +
    1223 DbcStatementDispatcher dispatcher;
    +
    1224 dispatcher.RegisterType<CountingHandler>("TEST_");
    +
    1225 CHECK(dispatcher.Dispatch("TEST_ first", context) &&
    +
    1226 dispatcher.Dispatch("TEST_ second", context) &&
    +
    1227 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
    +
    1228 dispatchDatabase.frames.size() == 2U,
    +
    1229 "Factory dispatch and handler reuse");
    +
    1230 CHECK(!dispatcher.Dispatch("TEST_OTHER data", context) &&
    +
    1231 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
    +
    1232 !dispatcher.Dispatch("VAL_TABLE_ States 0 \"Stopped\";", context) &&
    +
    1233 CountingHandler::calls == 2,
    +
    1234 "Exact and unknown keyword dispatch");
    +
    1235}
    +
    1236
    +
    1237void DbcParserTest::independentSessions() {
    +
    1238 Fixture fixture;
    +
    1239 const DbcParser parser;
    +
    1240 fixture.Write("BO_ 1 First: 8 ECU\n");
    +
    1241 CHECK(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
    +
    1242 fixture.Write("SG_ Speed : invalid\n");
    +
    1243 try {
    +
    1244 parser.ParseFile(fixture.path.string());
    +
    1245 CHECK(false, "Independent parse context");
    +
    1246 } catch (const std::runtime_error &error) {
    +
    1247 CHECK(std::string(error.what()).find("Signal found before any frame") !=
    +
    1248 std::string::npos,
    +
    1249 "Independent parse context");
    +
    1250 }
    +
    1251 fixture.Write("BO_ 2 Second: 8 ECU\n");
    +
    1252 const DbcDatabase recovered = parser.ParseFile(fixture.path.string());
    +
    1253 CHECK(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
    +
    1254 "Fresh parse after error");
    +
    1255}
    +
    1256
    +
    1257
    +
    1258void DbcParserTest::valueDescriptions() {
    +
    1259 Fixture fixture;
    +
    1260 fixture.Write(
    +
    1261 "VAL_\t256\tState\t0\t\"Off\"\t1 \"On\" 2 \"Error with spaces; and \\\"quotes\\\"\";\n"
    +
    1262 "BO_ 256 Status: 8 ECU\n"
    +
    1263 "SG_ State : 0|8@1+ (2,10) [0|520] \"\" ECU\n"
    +
    1264 "VAL_ 256 State 3 \"\";\n"
    +
    1265 "VAL_ 2147483904 State -9223372036854775808 \"Minimum\" -1 \"Negative\" 9223372036854775807 \"Maximum\";\n"
    +
    1266 "BO_ 2147483904 Extended: 8 ECU\n"
    +
    1267 "SG_ State : 0|64@1- (1,0) [-1e20|1e20] \"\" ECU\n"
    +
    1268 "BO_ 2048 Unsigned: 8 ECU\n"
    +
    1269 "SG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n"
    +
    1270 "VAL_ 2147485696 State 9223372036854775808 \"High\" 18446744073709551615 \"Full\";\n");
    +
    1271 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    +
    1272 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    +
    1273 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
    +
    1274 CHECK(tree->GetChild(0)->GetSignal() == nullptr, "Frame node");
    +
    1275 for (std::size_t index = 0; index < parsed.frames.size(); ++index) {
    +
    1276 CHECK(tree->GetChild(index)->GetChild(0)->GetSignal()->valueDescriptions ==
    +
    1277 parsed.frames[index].signals[0].valueDescriptions &&
    +
    1278 runtime.GetFrames()[index].signals[0].valueDescriptions ==
    +
    1279 parsed.frames[index].signals[0].valueDescriptions,
    +
    1280 "All mappings survive both builders");
    +
    1281 }
    +
    1282 CHECK(tree->GetChild(0)->GetChild(0)->GetSignal()->valueDescriptions ==
    +
    1283 runtime.GetFrames()[0].signals[0].valueDescriptions,
    +
    1284 "Both builders preserve descriptions");
    +
    1285 RawCanFrame frame;
    +
    1286 frame.canId = 256;
    +
    1287 frame.data.resize(8);
    +
    1288 const std::string expected[] = {"Off", "On", "Error with spaces; and \"quotes\"", ""};
    +
    1289 for (unsigned value = 0; value < 5; ++value) {
    +
    1290 frame.data[0] = value;
    +
    1291 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    +
    1292 CHECK(decoded.valid && decoded.physicalValue == value * 2 + 10, "Numeric scaling unchanged");
    +
    1293 const std::string *description = decoded.GetValueDescription();
    +
    1294 CHECK(value < 4 ? description && *description == expected[value] : !description,
    +
    1295 "Raw lookup and unknown value");
    +
    1296 }
    +
    1297 frame.isExtended = true;
    +
    1298 struct Boundary {
    +
    1299 std::uint64_t bits;
    +
    1300 const char *description;
    +
    1301 };
    +
    1302 for (const Boundary &test: {Boundary{0x8000000000000000ULL, "Minimum"},
    +
    1303 Boundary{0xFFFFFFFFFFFFFFFFULL, "Negative"},
    +
    1304 Boundary{0x7FFFFFFFFFFFFFFFULL, "Maximum"}}) {
    +
    1305 for (unsigned byte = 0; byte < 8; ++byte)
    +
    1306 frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
    +
    1307 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    +
    1308 CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
    +
    1309 "Signed boundaries and distinct extended frame");
    +
    1310 }
    +
    1311 frame.canId = 2048;
    +
    1312 for (const Boundary &test: {Boundary{0x8000000000000000ULL, "High"},
    +
    1313 Boundary{0xFFFFFFFFFFFFFFFFULL, "Full"}}) {
    +
    1314 for (unsigned byte = 0; byte < 8; ++byte)
    +
    1315 frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
    +
    1316 const DecodedSignalValue decoded = DbcDecoder().Decode(runtime, frame).signals[0];
    +
    1317 CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
    +
    1318 "Unsigned boundaries");
    +
    1319 }
    +
    1320 CHECK(FindValueDescription(runtime.GetFrames()[0].signals[0].valueDescriptions, std::int64_t(1)) != nullptr,
    +
    1321 "Nonnegative signed lookup matches unsigned key");
    +
    1322 frame.data.clear();
    +
    1323 CHECK(!DbcDecoder().Decode(runtime, frame).signals[0].GetValueDescription(), "Invalid decode has no description");
    +
    1324}
    +
    1325
    +
    1326void DbcParserTest::invalidValueDescriptions() {
    +
    1327 Fixture fixture;
    +
    1328 const std::string definitions = "BO_ 1 Frame: 8 ECU\nSG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n";
    +
    1329 for (const std::string statement: {
    +
    1330 "VAL_", "VAL_ 1 State;", "VAL_ 1 State ;", "VAL_ 1 State 0 \"Off\"",
    +
    1331 "VAL_ 1 State 0 \"Off\"; junk", "VAL_ 1 State 0 Off;",
    +
    1332 "VAL_ 1 State 0 \"Unclosed;", "VAL_ 1 State 0 \"Off\"1 \"On\";",
    +
    1333 "VAL_ 1 State 0 \"Off\" 00 \"Duplicate\";",
    +
    1334 "VAL_ 1 State 0 \"Off\" -0 \"Duplicate\";",
    +
    1335 "VAL_ 1 State 0 \"Off\";\nVAL_ 1 State 0 \"Duplicate\";",
    +
    1336 "VAL_ 2 State 0 \"Missing frame\";", "VAL_ 1 Missing 0 \"Missing signal\";",
    +
    1337 "VAL_ -1 State 0 \"Bad ID\";", "VAL_ 536870912 State 0 \"Bad ID\";",
    +
    1338 "VAL_ 4294967296 State 0 \"Bad ID\";", "VAL_ Environment 0 \"Unsupported\";",
    +
    1339 "VAL_ 1 State 0 \"Bad\\q escape\";"}) {
    +
    1340 fixture.Write(definitions + statement + '\n');
    +
    1341 const int line = statement.find('\n') == std::string::npos ? 3 : 4;
    +
    1342 try {
    +
    1343 DbcParser().ParseFile(fixture.path.string());
    +
    1344 CHECK(false, statement);
    +
    1345 } catch (const std::runtime_error &error) {
    +
    1346 CHECK(std::string(error.what()).find(fixture.path.string() + ":" + std::to_string(line) + ": ") == 0,
    +
    1347 statement + " " + error.what());
    +
    1348 }
    +
    1349 }
    +
    1350 for (const std::string suffix: {
    +
    1351 "BO_ 1 Other: 8 ECU\n", // Duplicate frame definition.
    +
    1352 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n",// Duplicate signal definition.
    +
    1353 ""}) {
    +
    1354 fixture.Write("VAL_ 1 " + std::string(suffix.empty() ? "Missing" : "State") +
    +
    1355 " 0 \"Description\";\n" + definitions + suffix);
    +
    1356 try {
    +
    1357 DbcParser().ParseFile(fixture.path.string());
    +
    1358 CHECK(false, "Missing reference or duplicate definition");
    +
    1359 } catch (const std::runtime_error &error) {
    +
    1360 const std::string line = suffix.empty() ? "1" : "4";
    +
    1361 CHECK(std::string(error.what()).find(fixture.path.string() + ":" + line + ": ") == 0,
    +
    1362 "Error retains the reference or duplicate definition source location");
    +
    1363 }
    +
    1364 }
    +
    1365 for (const std::string number: {"+1", "1x", "0x10", "1.5", "1e2", "--1",
    +
    1366 "-9223372036854775809", "18446744073709551616"}) {
    +
    1367 fixture.Write("VAL_ 1 State " + number + " \"Bad\";\n" + definitions);
    +
    1368 try {
    +
    1369 DbcParser().ParseFile(fixture.path.string());
    +
    1370 CHECK(false, number);
    +
    1371 } catch (const std::runtime_error &error) {
    +
    1372 CHECK(std::string(error.what()).find(fixture.path.string() + ":1: ") == 0, number);
    +
    1373 }
    +
    1374 }
    +
    1375}
    +
    1376
    +
    1377
    +
    1378void DbcParserTest::extendedMultiplexing() {
    +
    1379 Fixture fixture;
    +
    1380 // Forward references, multiple ranges, repeated range statements, and nested siblings.
    +
    1381 fixture.Write(
    +
    1382 "SG_MUL_VAL_ 1 Child Root 1-2, 4-4;\n"
    +
    1383 "SG_MUL_VAL_ 1 Leaf Child 3-5;\n"
    +
    1384 "SG_MUL_VAL_ 1 Leaf Child 7-7;\n"
    +
    1385 "SG_MUL_VAL_ 1 Sibling Root 6-6;\n"
    +
    1386 "SG_MUL_VAL_ 1 Other Sibling 3-5;\n"
    +
    1387 "BO_ 1 Frame: 4 ECU\n"
    +
    1388 "SG_ Leaf m99 : 16|8@1- (2,1) [-128|127] \"\" ECU\n"
    +
    1389 "SG_ Other m0 : 23|8@0+ (1,0) [0|255] \"\" ECU\n"
    +
    1390 "SG_ Child m1M : 8|8@1+ (10,3) [0|255] \"\" ECU\n"
    +
    1391 "SG_ Sibling m6M : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
    +
    1392 "SG_ Root M : 0|8@1+ (10,3) [0|255] \"\" ECU\n"
    +
    1393 "SG_ Common : 24|8@1+ (1,0) [0|255] \"\" ECU\n");
    +
    1394 const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
    +
    1395 const DecodeDatabase database = DbcDecodeBuilder().Build(parsed);
    +
    1396 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
    +
    1397 const Multiplexing &metadata = tree->GetChild(0U)->GetChild(0U)->GetSignal()->multiplexing;
    +
    1398 CHECK(metadata.selector == "Child" && metadata.ranges.size() == 2U &&
    +
    1399 metadata.ranges[1].minimum == 7U,
    +
    1400 "Tree preserves ranges and selector name");
    +
    1401 CHECK(database.GetFrames()[0].signals[2].multiplexing.role == MultiplexRole::BranchSelector,
    +
    1402 "Runtime preserves nested selector role");
    +
    1403 RawCanFrame raw;
    +
    1404 raw.canId = 1U;
    +
    1405 raw.data = {2U, 4U, 255U, 8U};
    +
    1406 DecodedFrameValue result = DbcDecoder().Decode(database, raw);
    +
    1407 CHECK(result.signals[0].valid && result.signals[0].physicalValue == -1.0 &&
    +
    1408 result.signals[1].status == SignalDecodeStatus::Inactive && result.signals[2].valid &&
    +
    1409 result.signals[3].status == SignalDecodeStatus::Inactive && result.signals[5].valid,
    +
    1410 "Nested raw conditions select one path and preserve definition order");
    +
    1411 const std::vector<SignalKey> selection = {SignalKey(FrameKey(1U, false), "Leaf")};
    +
    1412 result = DbcDecoder().Decode(database, raw, selection);
    +
    1413 CHECK(result.signals.size() == 1U && result.signals[0].valid,
    +
    1414 "Selection reads all ancestors internally");
    +
    1415 for (std::uint8_t root: {1U, 2U, 4U}) {
    +
    1416 for (std::uint8_t child: {3U, 5U, 7U}) {
    +
    1417 raw.data = {root, child, 9U, 8U};
    +
    1418 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].valid,
    +
    1419 "Inclusive endpoints and separated ranges");
    +
    1420 }
    +
    1421 }
    +
    1422 raw.data = {6U, 4U, 9U, 8U};
    +
    1423 result = DbcDecoder().Decode(database, raw);
    +
    1424 CHECK(result.signals[0].status == SignalDecodeStatus::Inactive && result.signals[1].valid &&
    +
    1425 result.signals[3].valid,
    +
    1426 "Overlapping sibling selector path becomes active");
    +
    1427 raw.data = {0U};
    +
    1428 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::Inactive,
    +
    1429 "Inactive root does not require child selector bytes");
    +
    1430 raw.data = {1U};
    +
    1431 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::SelectorUnavailable,
    +
    1432 "Active root with missing child selector");
    +
    1433 raw.data = {1U, 3U};
    +
    1434 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::InsufficientPayload,
    +
    1435 "Active nested leaf needs its bytes");
    +
    1436 raw.data = {1U, 6U};
    +
    1437 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::Inactive,
    +
    1438 "Gap between explicit ranges does not fall back to mN");
    +
    1439 raw.data.clear();
    +
    1440 CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::SelectorUnavailable,
    +
    1441 "Missing root selector");
    +
    1442
    +
    1443 fixture.Write("BO_ 1 Frame: 9 ECU\n"
    +
    1444 "SG_ Root M : 0|64@1+ (1,0) [0|1] \"\" ECU\n"
    +
    1445 "SG_ Leaf m0 : 64|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1446 "SG_MUL_VAL_ 1 Leaf Root 18446744073709551614-18446744073709551615;\n");
    +
    1447 raw.data.assign(9U, 255U);
    +
    1448 CHECK(DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw).signals[1].valid,
    +
    1449 "64-bit ranges retain exact UINT64_MAX without expansion");
    +
    1450
    +
    1451 fixture.Write("BO_ 1 Frame: 4 ECU\n"
    +
    1452 "SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1453 "SG_ Second M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1454 "SG_ A m0 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1455 "SG_ B m0 : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1456 "SG_MUL_VAL_ 1 A Root 1-1;\nSG_MUL_VAL_ 1 B Second 2-2;\n");
    +
    1457 raw.data = {1U, 2U, 9U, 10U};
    +
    1458 result = DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw);
    +
    1459 CHECK(result.signals[2].valid && result.signals[3].valid, "Independent explicit selectors");
    +
    1460
    +
    1461 fixture.Write("BO_ 1 Deep: 5 ECU\n"
    +
    1462 "SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1463 "SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1464 "SG_ Grandchild m2M : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1465 "SG_ Leaf : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1466 "SG_MUL_VAL_ 1 Grandchild Child 2-2;\n"
    +
    1467 "SG_MUL_VAL_ 1 Leaf Grandchild 3-3;\n");
    +
    1468 const DecodeDatabase deep = DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string()));
    +
    1469 raw.data = {1U, 2U, 3U, 9U, 0U};
    +
    1470 CHECK(DbcDecoder().Decode(deep, raw).signals[3].valid, "Three selector levels and an unmarked extended branch");
    +
    1471 raw.data = {1U, 0U};
    +
    1472 CHECK(DbcDecoder().Decode(deep, raw).signals[3].status == SignalDecodeStatus::Inactive,
    +
    1473 "Inactive middle ancestor skips missing descendant bytes");
    +
    1474
    +
    1475 // Marker fallback also works on a nested selector without its own SG_MUL_VAL_.
    +
    1476 fixture.Write("BO_ 1 Frame: 3 ECU\n"
    +
    1477 "SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1478 "SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1479 "SG_ Leaf m2 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1480 "SG_MUL_VAL_ 1 Leaf Child 2-2;\n");
    +
    1481 raw.data = {1U, 2U, 9U};
    +
    1482 CHECK(DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw).signals[2].valid,
    +
    1483 "mNM retains implicit root fallback");
    +
    1484}
    +
    1485
    +
    1486void DbcParserTest::extendedMultiplexingErrors() {
    +
    1487 Fixture fixture;
    +
    1488 const std::string definitions =
    +
    1489 "BO_ 1 Frame: 3 ECU\n"
    +
    1490 "SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1491 "SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1492 "SG_ Leaf m2 : 16|8@1+ (1,0) [0|255] \"\" ECU\n";
    +
    1493 for (const std::string statement: {
    +
    1494 "SG_MUL_VAL_ 1 Leaf Root 3-2;", "SG_MUL_VAL_ 1 Leaf Root -1-2;",
    +
    1495 "SG_MUL_VAL_ 1 Leaf Root 1-256;", "SG_MUL_VAL_ 1 Leaf Root 1-2,;",
    +
    1496 "SG_MUL_VAL_ 1 Leaf Root 1-2 trailing;", "SG_MUL_VAL_ 1 Leaf Root 1-2",
    +
    1497 "SG_MUL_VAL_ 1 Leaf Root 0-18446744073709551616;",
    +
    1498 "SG_MUL_VAL_ 1 Leaf Missing 1-2;", "SG_MUL_VAL_ 1 Missing Root 1-2;",
    +
    1499 "SG_MUL_VAL_ 2 Leaf Root 1-2;", "SG_MUL_VAL_ 1 Leaf Leaf 1-2;"}) {
    +
    1500 fixture.Write(statement + "\n" + definitions);
    +
    1501 const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    1502 CHECK(result.HasErrors() && result.database.frames.empty(), statement);
    +
    1503 CHECK(result.diagnostics.back().code == DbcDiagnosticCode::InvalidMultiplexing &&
    +
    1504 result.diagnostics.back().lineNumber == 1U,
    +
    1505 "Extended error retains source statement location");
    +
    1506 }
    +
    1507 for (const std::string statements: {
    +
    1508 "SG_MUL_VAL_ 1 Root Child 1-1;\nSG_MUL_VAL_ 1 Child Root 1-1;\n",
    +
    1509 "SG_MUL_VAL_ 1 Child Child 1-1;\n",
    +
    1510 "SG_MUL_VAL_ 1 Leaf Root 1-1;\nSG_MUL_VAL_ 1 Leaf Child 1-1;\n"}) {
    +
    1511 fixture.Write(definitions + statements);
    +
    1512 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(), "Cyclic or conflicting parents rejected");
    +
    1513 }
    +
    1514 // Range intersection and inherited root conditions must both protect overlaps.
    +
    1515 const std::string overlapping =
    +
    1516 "BO_ 1 Frame: 4 ECU\n"
    +
    1517 "SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1518 "SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1519 "SG_ A m0 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1520 "SG_ B m0 : 23|8@0+ (1,0) [0|255] \"\" ECU\n"
    +
    1521 "SG_MUL_VAL_ 1 A Child 2-4;\n"
    +
    1522 "SG_MUL_VAL_ 1 Child Root 1-1;\n";
    +
    1523 for (const std::string condition: {"SG_MUL_VAL_ 1 B Child 4-6;\n",
    +
    1524 "SG_MUL_VAL_ 1 B Root 1-1;\n"}) {
    +
    1525 fixture.Write(overlapping + condition);
    +
    1526 CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
    +
    1527 "Overlapping ranges or compatible ancestors cannot share bits");
    +
    1528 }
    +
    1529 fixture.Write(overlapping + "SG_MUL_VAL_ 1 B Child 5-6;\n");
    +
    1530 CHECK(!DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
    +
    1531 "Disjoint adjacent ranges may share bits");
    +
    1532 fixture.Write(overlapping + "SG_ Second M : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
    +
    1533 "SG_MUL_VAL_ 1 B Second 2-4;\n");
    +
    1534 const DbcParseResult independent = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
    +
    1535 CHECK(independent.HasErrors() && independent.diagnostics.back().message ==
    +
    1536 "Signals overlap without mutually exclusive multiplexing conditions.",
    +
    1537 "Independent selector conditions do not imply exclusion");
    +
    1538
    +
    1539 // Validate manually constructed runtime graphs with the same rules.
    +
    1540 fixture.Write(definitions + "SG_MUL_VAL_ 1 Leaf Child 2-3;\n");
    +
    1541 const DecodeDatabase valid = DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string()));
    +
    1542 for (unsigned kind = 0U; kind < 6U; ++kind) {
    +
    1543 std::vector<DecodeFrame> frames = valid.GetFrames();
    +
    1544 Multiplexing &leaf = frames[0].signals[2].multiplexing;
    +
    1545 switch (kind) {
    +
    1546 case 0:
    +
    1547 leaf.selector = "Missing";
    +
    1548 break;
    +
    1549 case 1:
    +
    1550 leaf.ranges[0] = {4U, 3U};
    +
    1551 break;
    +
    1552 case 2:
    +
    1553 leaf.ranges[0] = {0U, 256U};
    +
    1554 break;
    +
    1555 case 3:
    +
    1556 leaf.ranges.clear();
    +
    1557 break;
    +
    1558 case 4:
    +
    1559 frames[0].signals[0].multiplexing.selector = "Child";
    +
    1560 frames[0].signals[0].multiplexing.ranges = {{1U, 1U}};
    +
    1561 break;
    +
    1562 case 5:
    +
    1563 frames[0].signals[1].valueType = ValueType::Signed;
    +
    1564 break;
    +
    1565 }
    +
    1566 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase(frames));
    +
    1567 }
    +
    1568}
    +
    1569
    +
    1570int RunParserTests(int argc, char **argv) {
    +
    1571 DbcParserTest tests;
    +
    1572 return QTest::qExec(&tests, argc, argv);
    +
    1573}
    +
    1574
    +
    1575#include "dbc_parser_test.moc"
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    - -
    void RegisterType(const std::string &keyword)
    Register or replace a handler and create its reusable instance.
    -
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    -
    Interface for processing a registered DBC statement.
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    + +
    void RegisterType(const std::string &keyword)
    Register or replace a handler and create its reusable instance.
    +
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    +
    Interface for processing a registered DBC statement.
    virtual void Handle(const std::string &line, DbcParseContext &context) const =0
    Process a trimmed statement using state belonging to this parse.
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    const std::vector< DecodeFrame > & GetFrames() const
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    const std::vector< DecodeFrame > & GetFrames() const
    Runtime decode database builder.
    CAN frame decoding API and result types.
    DBC file parser and interpretation options.
    @@ -1431,30 +1704,34 @@ $(document).ready(function(){initNavTree('dbc__parser__test_8cpp_source.html',''
    DbcDiagnosticCode code
    std::string filePath
    std::size_t lineNumber
    - - + +
    Parsed database and diagnostics; the database is empty on error.
    std::vector< DbcDiagnostic > diagnostics
    bool HasErrors() const
    Return whether any diagnostic has error severity.
    DbcDatabase database
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    - -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    - - -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    + +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    + + +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    std::string transmitter
    Definition frame_info.h:32
    std::uint8_t dlc
    Definition frame_info.h:31
    std::string name
    Definition frame_info.h:26
    std::uint32_t canId
    Definition frame_info.h:27
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    Stable frame identifier: normalized CAN ID and frame type.
    +
    Basic markers and optional explicit extended multiplexing condition.
    +
    std::vector< MultiplexRange > ranges
    +
    std::string selector
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string unit
    Definition signal_info.h:36
    @@ -1467,6 +1744,7 @@ $(document).ready(function(){initNavTree('dbc__parser__test_8cpp_source.html',''
    double maximum
    Definition signal_info.h:35
    double factor
    Definition signal_info.h:32
    bool isLittleEndian
    Definition signal_info.h:30
    +
    diff --git a/docs/html/dbc__pipeline__test_8cpp_source.html b/docs/html/dbc__pipeline__test_8cpp_source.html index f68c510..859fd9b 100644 --- a/docs/html/dbc__pipeline__test_8cpp_source.html +++ b/docs/html/dbc__pipeline__test_8cpp_source.html @@ -143,7 +143,7 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    43 standard.comment = "Standard frame comment";
    44 SignalInfo mode;
    45 mode.name = "Mode";
    -
    46 mode.multiplexing.role = MultiplexRole::Selector;
    +
    46 mode.multiplexing.role = MultiplexRole::Selector;
    47 mode.length = 8U;
    48 mode.maximum = 255;
    49 mode.receivers = {"ReceiverA"};
    @@ -151,7 +151,7 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    51 mode.valueDescriptions = {{std::uint64_t(3), "Selected"}};
    52 SignalInfo state;
    53 state.name = "State";
    -
    54 state.multiplexing.role = MultiplexRole::Branch;
    +
    54 state.multiplexing.role = MultiplexRole::Branch;
    55 state.multiplexing.value = 3U;
    56 state.startBit = 8U;
    57 state.length = 8U;
    @@ -210,7 +210,7 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    110 QVERIFY(actual.receivers == expected.receivers);
    111 QCOMPARE(actual.comment, expected.comment);
    112 QVERIFY(actual.valueDescriptions == expected.valueDescriptions);
    -
    113 QCOMPARE(actual.multiplexing.role, expected.multiplexing.role);
    +
    113 QCOMPARE(actual.multiplexing.role, expected.multiplexing.role);
    114 QCOMPARE(actual.multiplexing.value, expected.multiplexing.value);
    115 }
    116
    @@ -491,15 +491,15 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    391#include "dbc_pipeline_test.moc"
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    Tree node for later use in model/view or other hierarchy consumers.
    Definition tree_node.h:37
    const SignalInfo * GetSignal() const
    Get signal payload if node is signal.
    Definition tree_node.cpp:71
    const TreeNode * GetChild(std::size_t index) const
    Get child by index.
    Definition tree_node.cpp:45
    @@ -513,8 +513,8 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    CAN frame decoding API and result types.
    DBC file parser and interpretation options.
    Metadata tree builder.
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    -
    ValueType
    Signal numeric type.
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ValueType
    Signal numeric type.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    Parsed database and diagnostics; the database is empty on error.
    @@ -522,22 +522,22 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    bool HasErrors() const
    Return whether any diagnostic has error severity.
    DbcDatabase database
    Definition dbc_parser.h:20
    -
    Runtime-ready signal definition.
    -
    ValueType valueType
    -
    ByteOrder byteOrder
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    FrameKey key
    Definition dbc_decoder.h:75
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    -
    SignalKey key
    Definition dbc_decoder.h:56
    -
    RawSignalValue rawValue
    Definition dbc_decoder.h:57
    -
    double physicalValue
    Definition dbc_decoder.h:58
    -
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:55
    -
    SignalDecodeStatus status
    Definition dbc_decoder.h:60
    -
    bool valid
    Definition dbc_decoder.h:59
    -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    Runtime-ready signal definition.
    +
    ValueType valueType
    +
    ByteOrder byteOrder
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    FrameKey key
    Definition dbc_decoder.h:76
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    +
    SignalKey key
    Definition dbc_decoder.h:57
    +
    RawSignalValue rawValue
    Definition dbc_decoder.h:58
    +
    double physicalValue
    Definition dbc_decoder.h:59
    +
    std::shared_ptr< const DecodeSignal > definition
    Definition dbc_decoder.h:56
    +
    SignalDecodeStatus status
    Definition dbc_decoder.h:61
    +
    bool valid
    Definition dbc_decoder.h:60
    +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    bool hasPgn
    Definition frame_info.h:30
    @@ -548,13 +548,12 @@ $(document).ready(function(){initNavTree('dbc__pipeline__test_8cpp_source.html',
    std::uint32_t pgn
    Definition frame_info.h:29
    std::uint32_t canId
    Definition frame_info.h:27
    Stable frame identifier: normalized CAN ID and frame type.
    -
    -
    MultiplexRole role
    -
    std::uint64_t value
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    Basic markers and optional explicit extended multiplexing condition.
    +
    std::uint64_t value
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string unit
    Definition signal_info.h:36
    diff --git a/docs/html/dbc__statement__handler_8cpp_source.html b/docs/html/dbc__statement__handler_8cpp_source.html index 4f14eea..2855aa5 100644 --- a/docs/html/dbc__statement__handler_8cpp_source.html +++ b/docs/html/dbc__statement__handler_8cpp_source.html @@ -101,575 +101,603 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8cpp_source.ht
    1// SPDX-License-Identifier: MIT
    2#include "dbc_statement_handler.h"
    3#include "j1939.h"
    -
    4#include "text_utils.h"
    +
    4#include "multiplex_graph.h"
    5#include "signal_layout.h"
    -
    6#include <charconv>
    -
    7#include <cmath>
    -
    8#include <limits>
    -
    9#include <regex>
    -
    10#include <sstream>
    -
    11#include <stdexcept>
    -
    12
    -
    13namespace {
    -
    14 std::uint32_t ParseDecimal(const std::string &text,
    -
    15 std::uint32_t maximum,
    -
    16 const char *field) {
    -
    17 std::uint32_t value = 0U;
    -
    18 const std::from_chars_result parsed = std::from_chars(text.data(), text.data() + text.size(), value);
    -
    19 if (text.empty() || parsed.ec != std::errc() ||
    -
    20 parsed.ptr != text.data() + text.size() || value > maximum)
    -
    21 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    -
    22 return value;
    -
    23 }
    -
    24
    -
    25 std::uint32_t ParseCanId(const std::string &text) {
    -
    26 const std::uint32_t rawId = ParseDecimal(
    -
    27 text, std::numeric_limits<std::uint32_t>::max(), "CAN ID");
    -
    28 // Only bit 31 may accompany the actual 29-bit identifier.
    -
    29 if ((rawId & 0x60000000U) != 0U)
    -
    30 throw std::runtime_error("CAN ID exceeds the 29-bit identifier range.");
    -
    31 return rawId;
    -
    32 }
    -
    33
    -
    34 double ParsePhysicalValue(const std::string &text, const char *field) {
    -
    35 static const std::regex number(
    -
    36 R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)");
    -
    37 if (!std::regex_match(text, number))
    -
    38 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    -
    39 // Floating-point from_chars is locale-independent and does not accept
    -
    40 // a leading '+', which the DBC numeric grammar permits.
    -
    41 const char *begin = text.data();
    -
    42 const char *end = begin + text.size();
    -
    43 if (*begin == '+')
    -
    44 ++begin;
    -
    45 double value = 0.0;
    -
    46 const std::from_chars_result parsed =
    -
    47 std::from_chars(begin, end, value, std::chars_format::general);
    -
    48 // Keep the existing rejection of conversion underflow into subnormal values.
    -
    49 if (parsed.ec != std::errc() || parsed.ptr != end || !std::isfinite(value) ||
    -
    50 std::fpclassify(value) == FP_SUBNORMAL)
    -
    51 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    -
    52 return value;
    -
    53 }
    -
    54
    -
    55 Multiplexing ParseMultiplexingMarker(const std::string &marker) {
    -
    56 Multiplexing result;
    -
    57 if (marker == "M")
    -
    58 result.role = MultiplexRole::Selector;
    -
    59 else if (!marker.empty()) {
    -
    60 if (marker[0] != 'm')
    -
    61 throw std::runtime_error("Unsupported multiplexing marker.");
    -
    62 const std::string value = marker.substr(1U);
    -
    63 const std::from_chars_result parsed =
    -
    64 std::from_chars(value.data(), value.data() + value.size(), result.value);
    -
    65 if (value.empty() || parsed.ec != std::errc() || parsed.ptr != value.data() + value.size())
    -
    66 throw std::runtime_error("Invalid or unsupported multiplexing marker.");
    -
    67 result.role = MultiplexRole::Branch;
    -
    68 }
    -
    69
    -
    70 return result;
    -
    71 }
    -
    72
    -
    73 RawSignalValue ParseValueKey(const std::string &number) {
    -
    74 RawSignalValue key;
    -
    75 if (!number.empty() && number[0] == '-') {
    -
    76 std::int64_t value = 0;
    -
    77 const std::from_chars_result parsed =
    -
    78 std::from_chars(number.data(), number.data() + number.size(), value);
    -
    79 if (parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
    -
    80 throw std::runtime_error("Invalid VAL_ integer: " + number);
    -
    81 key = NormalizeValueKey(RawSignalValue(value));
    -
    82 } else {
    -
    83 std::uint64_t value = 0;
    -
    84 const std::from_chars_result parsed =
    -
    85 std::from_chars(number.data(), number.data() + number.size(), value);
    -
    86 if (number.empty() || parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
    -
    87 throw std::runtime_error("Invalid VAL_ integer: " + number);
    -
    88 key = value;
    -
    89 }
    -
    90 return key;
    -
    91 }
    -
    92
    -
    93 std::string UnescapeDescription(const std::string &quoted) {
    -
    94 std::string description;
    -
    95 for (std::size_t i = 0; i < quoted.size(); ++i) {
    -
    96 if (quoted[i] == '\\')
    -
    97 ++i;
    -
    98 description += quoted[i];
    -
    99 }
    -
    100 return description;
    -
    101 }
    -
    102
    -
    103 FrameInfo *FindUniqueFrame(DbcDatabase &database, std::uint32_t canId, bool isExtended) {
    -
    104 FrameInfo *frame = nullptr;
    -
    105 for (FrameInfo &candidate : database.frames) {
    -
    106 if (candidate.canId == canId && candidate.isExtended == isExtended) {
    -
    107 if (frame)
    -
    108 throw std::runtime_error("Ambiguous VAL_ frame reference.");
    -
    109 frame = &candidate;
    -
    110 }
    -
    111 }
    -
    112 if (!frame)
    -
    113 throw std::runtime_error("Unresolved VAL_ frame reference.");
    -
    114 return frame;
    -
    115 }
    -
    116
    -
    117 SignalInfo *FindUniqueSignal(FrameInfo &frame, const std::string &signalName) {
    -
    118 SignalInfo *signal = nullptr;
    -
    119 for (SignalInfo &candidate : frame.signals) {
    -
    120 if (candidate.name == signalName) {
    -
    121 if (signal)
    -
    122 throw std::runtime_error("Ambiguous VAL_ signal reference: " + signalName);
    -
    123 signal = &candidate;
    -
    124 }
    -
    125 }
    -
    126 if (!signal)
    -
    127 throw std::runtime_error("Unresolved VAL_ signal reference: " + signalName);
    -
    128 return signal;
    -
    129 }
    -
    130
    -
    131 std::uint64_t NextSignalBit(std::uint64_t bit, bool isLittleEndian) {
    -
    132 if (isLittleEndian)
    -
    133 return bit + 1U;
    -
    134 // From bit 0, Motorola continues at bit 7 of the next byte (0 -> 15).
    -
    135 return bit % 8U == 0U ? bit + 15U : bit - 1U;
    -
    136 }
    -
    137
    -
    138 FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool);
    -
    139 SignalInfo *FindSignalByName(FrameInfo &, const std::string &);
    -
    140} // namespace
    -
    141
    -
    142namespace {
    -
    143 std::vector<std::string> SplitReceivers(const std::string &text) {
    -
    144 std::vector<std::string> receivers;
    -
    145 std::string token;
    -
    146 std::istringstream stream(text);
    -
    147
    -
    148 while (std::getline(stream, token, ',')) {
    -
    149 token = dbc_detail::TrimText(token);
    -
    150 if (!token.empty())
    -
    151 receivers.push_back(token);
    -
    152 }
    -
    153
    -
    154 return receivers;
    -
    155 }
    -
    156
    -
    157 void NormalizeCanId(std::uint32_t rawCanId, std::uint32_t &normalizedCanId, bool &isExtended) {
    -
    158 /*
    -
    159 * DBC commonly stores extended identifiers with bit 31 set.
    -
    160 * Example:
    -
    161 * raw id = 0x80000000 | actual_29_bit_id
    -
    162 */
    -
    163 isExtended = (rawCanId & 0x80000000U) != 0U || rawCanId > 0x7FFU;
    -
    164 normalizedCanId = rawCanId & 0x1FFFFFFFU;
    -
    165 }
    -
    166} // namespace
    -
    167
    -
    168FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
    -
    169 /*
    -
    170 * Example:
    -
    171 * BO_ 256 EngineData: 8 EEC1
    -
    172 */
    -
    173
    -
    174 std::istringstream stream(line);
    -
    175 std::string keyword;
    -
    176 std::string idText;
    -
    177 if (!(stream >> keyword >> idText) || keyword != "BO_")
    -
    178 throw std::runtime_error("Missing CAN ID in frame definition.");
    -
    179
    -
    180 const std::uint32_t rawCanId = ParseCanId(idText);
    +
    6#include "text_utils.h"
    +
    7#include <charconv>
    +
    8#include <cmath>
    +
    9#include <limits>
    +
    10#include <regex>
    +
    11#include <sstream>
    +
    12#include <stdexcept>
    +
    13
    +
    14namespace {
    +
    15 std::uint32_t ParseDecimal(const std::string &text,
    +
    16 std::uint32_t maximum,
    +
    17 const char *field) {
    +
    18 std::uint32_t value = 0U;
    +
    19 const std::from_chars_result parsed = std::from_chars(text.data(), text.data() + text.size(), value);
    +
    20 if (text.empty() || parsed.ec != std::errc() ||
    +
    21 parsed.ptr != text.data() + text.size() || value > maximum)
    +
    22 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    +
    23 return value;
    +
    24 }
    +
    25
    +
    26 std::uint32_t ParseCanId(const std::string &text) {
    +
    27 const std::uint32_t rawId = ParseDecimal(
    +
    28 text, std::numeric_limits<std::uint32_t>::max(), "CAN ID");
    +
    29 // Only bit 31 may accompany the actual 29-bit identifier.
    +
    30 if ((rawId & 0x60000000U) != 0U)
    +
    31 throw std::runtime_error("CAN ID exceeds the 29-bit identifier range.");
    +
    32 return rawId;
    +
    33 }
    +
    34
    +
    35 double ParsePhysicalValue(const std::string &text, const char *field) {
    +
    36 static const std::regex number(
    +
    37 R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)");
    +
    38 if (!std::regex_match(text, number))
    +
    39 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    +
    40 // Floating-point from_chars is locale-independent and does not accept
    +
    41 // a leading '+', which the DBC numeric grammar permits.
    +
    42 const char *begin = text.data();
    +
    43 const char *end = begin + text.size();
    +
    44 if (*begin == '+')
    +
    45 ++begin;
    +
    46 double value = 0.0;
    +
    47 const std::from_chars_result parsed =
    +
    48 std::from_chars(begin, end, value, std::chars_format::general);
    +
    49 // Keep the existing rejection of conversion underflow into subnormal values.
    +
    50 if (parsed.ec != std::errc() || parsed.ptr != end || !std::isfinite(value) ||
    +
    51 std::fpclassify(value) == FP_SUBNORMAL)
    +
    52 throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
    +
    53 return value;
    +
    54 }
    +
    55
    +
    56 Multiplexing ParseMultiplexingMarker(const std::string &marker) {
    +
    57 Multiplexing result;
    +
    58 if (marker == "M")
    +
    59 result.role = MultiplexRole::Selector;
    +
    60 else if (!marker.empty()) {
    +
    61 if (marker[0] != 'm')
    +
    62 throw std::runtime_error("Unsupported multiplexing marker.");
    +
    63 const bool nested = marker.back() == 'M';
    +
    64 const std::string value = marker.substr(1U, marker.size() - (nested ? 2U : 1U));
    +
    65 const std::from_chars_result parsed =
    +
    66 std::from_chars(value.data(), value.data() + value.size(), result.value);
    +
    67 if (value.empty() || parsed.ec != std::errc() || parsed.ptr != value.data() + value.size())
    +
    68 throw std::runtime_error("Invalid or unsupported multiplexing marker.");
    +
    69 result.role = nested ? MultiplexRole::BranchSelector : MultiplexRole::Branch;
    +
    70 }
    +
    71
    +
    72 return result;
    +
    73 }
    +
    74
    +
    75 RawSignalValue ParseValueKey(const std::string &number) {
    +
    76 RawSignalValue key;
    +
    77 if (!number.empty() && number[0] == '-') {
    +
    78 std::int64_t value = 0;
    +
    79 const std::from_chars_result parsed =
    +
    80 std::from_chars(number.data(), number.data() + number.size(), value);
    +
    81 if (parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
    +
    82 throw std::runtime_error("Invalid VAL_ integer: " + number);
    +
    83 key = NormalizeValueKey(RawSignalValue(value));
    +
    84 } else {
    +
    85 std::uint64_t value = 0;
    +
    86 const std::from_chars_result parsed =
    +
    87 std::from_chars(number.data(), number.data() + number.size(), value);
    +
    88 if (number.empty() || parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
    +
    89 throw std::runtime_error("Invalid VAL_ integer: " + number);
    +
    90 key = value;
    +
    91 }
    +
    92 return key;
    +
    93 }
    +
    94
    +
    95 std::string UnescapeDescription(const std::string &quoted) {
    +
    96 std::string description;
    +
    97 for (std::size_t i = 0; i < quoted.size(); ++i) {
    +
    98 if (quoted[i] == '\\')
    +
    99 ++i;
    +
    100 description += quoted[i];
    +
    101 }
    +
    102 return description;
    +
    103 }
    +
    104
    +
    105 FrameInfo *FindUniqueFrame(DbcDatabase &database, std::uint32_t canId, bool isExtended, const std::string &statement = "VAL_") {
    +
    106 FrameInfo *frame = nullptr;
    +
    107 for (FrameInfo &candidate : database.frames) {
    +
    108 if (candidate.canId == canId && candidate.isExtended == isExtended) {
    +
    109 if (frame)
    +
    110 throw std::runtime_error("Ambiguous " + statement + " frame reference.");
    +
    111 frame = &candidate;
    +
    112 }
    +
    113 }
    +
    114 if (!frame)
    +
    115 throw std::runtime_error("Unresolved " + statement + " frame reference.");
    +
    116 return frame;
    +
    117 }
    +
    118
    +
    119 SignalInfo *FindUniqueSignal(FrameInfo &frame, const std::string &signalName, const std::string &statement = "VAL_") {
    +
    120 SignalInfo *signal = nullptr;
    +
    121 for (SignalInfo &candidate : frame.signals) {
    +
    122 if (candidate.name == signalName) {
    +
    123 if (signal)
    +
    124 throw std::runtime_error("Ambiguous " + statement + " signal reference: " + signalName);
    +
    125 signal = &candidate;
    +
    126 }
    +
    127 }
    +
    128 if (!signal)
    +
    129 throw std::runtime_error("Unresolved " + statement + " signal reference: " + signalName);
    +
    130 return signal;
    +
    131 }
    +
    132
    +
    133 std::uint64_t NextSignalBit(std::uint64_t bit, bool isLittleEndian) {
    +
    134 if (isLittleEndian)
    +
    135 return bit + 1U;
    +
    136 // From bit 0, Motorola continues at bit 7 of the next byte (0 -> 15).
    +
    137 return bit % 8U == 0U ? bit + 15U : bit - 1U;
    +
    138 }
    +
    139
    +
    140 FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool);
    +
    141 SignalInfo *FindSignalByName(FrameInfo &, const std::string &);
    +
    142} // namespace
    +
    143
    +
    144namespace {
    +
    145 std::vector<std::string> SplitReceivers(const std::string &text) {
    +
    146 std::vector<std::string> receivers;
    +
    147 std::string token;
    +
    148 std::istringstream stream(text);
    +
    149
    +
    150 while (std::getline(stream, token, ',')) {
    +
    151 token = dbc_detail::TrimText(token);
    +
    152 if (!token.empty())
    +
    153 receivers.push_back(token);
    +
    154 }
    +
    155
    +
    156 return receivers;
    +
    157 }
    +
    158
    +
    159 void NormalizeCanId(std::uint32_t rawCanId, std::uint32_t &normalizedCanId, bool &isExtended) {
    +
    160 /*
    +
    161 * DBC commonly stores extended identifiers with bit 31 set.
    +
    162 * Example:
    +
    163 * raw id = 0x80000000 | actual_29_bit_id
    +
    164 */
    +
    165 isExtended = (rawCanId & 0x80000000U) != 0U || rawCanId > 0x7FFU;
    +
    166 normalizedCanId = rawCanId & 0x1FFFFFFFU;
    +
    167 }
    +
    168} // namespace
    +
    169
    +
    170FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
    +
    171 /*
    +
    172 * Example:
    +
    173 * BO_ 256 EngineData: 8 EEC1
    +
    174 */
    +
    175
    +
    176 std::istringstream stream(line);
    +
    177 std::string keyword;
    +
    178 std::string idText;
    +
    179 if (!(stream >> keyword >> idText) || keyword != "BO_")
    +
    180 throw std::runtime_error("Missing CAN ID in frame definition.");
    181
    -
    182 std::string nameText;
    -
    183 if (!std::getline(stream, nameText, ':') || stream.eof())
    -
    184 throw std::runtime_error("Missing ':' in frame definition.");
    -
    185 std::istringstream nameStream(nameText);
    -
    186 FrameInfo frame;
    -
    187 std::string extra;
    -
    188 if (!(nameStream >> frame.name) || (nameStream >> extra))
    -
    189 throw std::runtime_error("Missing or invalid frame name.");
    -
    190
    -
    191 std::string lengthText;
    -
    192 if (!(stream >> lengthText))
    -
    193 throw std::runtime_error("Missing payload length in frame definition.");
    -
    194 frame.dlc = static_cast<std::uint8_t>(ParseDecimal(
    -
    195 lengthText, std::numeric_limits<std::uint8_t>::max(), "payload length"));
    -
    196 if (!(stream >> frame.transmitter))
    -
    197 throw std::runtime_error("Missing transmitter in frame definition.");
    -
    198 if (stream >> extra)
    -
    199 throw std::runtime_error("Unexpected trailing field in frame definition: " + extra);
    -
    200
    -
    201 NormalizeCanId(rawCanId, frame.canId, frame.isExtended);
    +
    182 const std::uint32_t rawCanId = ParseCanId(idText);
    +
    183
    +
    184 std::string nameText;
    +
    185 if (!std::getline(stream, nameText, ':') || stream.eof())
    +
    186 throw std::runtime_error("Missing ':' in frame definition.");
    +
    187 std::istringstream nameStream(nameText);
    +
    188 FrameInfo frame;
    +
    189 std::string extra;
    +
    190 if (!(nameStream >> frame.name) || (nameStream >> extra))
    +
    191 throw std::runtime_error("Missing or invalid frame name.");
    +
    192
    +
    193 std::string lengthText;
    +
    194 if (!(stream >> lengthText))
    +
    195 throw std::runtime_error("Missing payload length in frame definition.");
    +
    196 frame.dlc = static_cast<std::uint8_t>(ParseDecimal(
    +
    197 lengthText, std::numeric_limits<std::uint8_t>::max(), "payload length"));
    +
    198 if (!(stream >> frame.transmitter))
    +
    199 throw std::runtime_error("Missing transmitter in frame definition.");
    +
    200 if (stream >> extra)
    +
    201 throw std::runtime_error("Unexpected trailing field in frame definition: " + extra);
    202
    -
    203 return frame;
    -
    204}
    -
    205
    -
    206SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
    -
    207 // Match the complete statement before converting any numeric fields.
    -
    208 enum Field {
    -
    209 NameAndMarker = 1, StartBit, BitLength, ByteOrder, Signedness,
    -
    210 Factor, Offset, Minimum, Maximum, Unit, Receivers
    -
    211 };
    -
    212 static const std::regex syntax(
    -
    213 // Name and optional multiplexing marker.
    -
    214 R"dbc(^SG_[ \t]+([^:]+):[ \t]*)dbc"
    -
    215 // Bit position, length, byte order and signedness.
    -
    216 R"dbc(([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*)dbc"
    -
    217 // Scaling factor and offset.
    -
    218 R"dbc(\‍([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*)dbc"
    -
    219 // Physical range.
    -
    220 R"dbc(\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*)dbc"
    -
    221 // Unit and receivers.
    -
    222 R"dbc("([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
    -
    223 std::smatch fields;
    -
    224 if (!std::regex_match(line, fields, syntax))
    -
    225 throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
    -
    226
    -
    227 SignalInfo signal;
    -
    228 std::istringstream nameFields(fields[NameAndMarker].str());
    -
    229 std::string marker;
    -
    230 std::string extra;
    -
    231 nameFields >> signal.name >> marker;
    -
    232 if (signal.name.empty() || (nameFields >> extra))
    -
    233 throw std::runtime_error("Invalid signal name or multiplexing marker.");
    -
    234 signal.multiplexing = ParseMultiplexingMarker(marker);
    -
    235
    -
    236 signal.startBit = ParseDecimal(fields[StartBit].str(),
    -
    237 std::numeric_limits<std::uint32_t>::max(), "signal start bit");
    -
    238 signal.length = ParseDecimal(fields[BitLength].str(), 64U, "signal length");
    -
    239 if (signal.length == 0U)
    -
    240 throw std::runtime_error("Signal length must be within 1..64 bits.");
    -
    241 signal.isLittleEndian = fields[ByteOrder].str() == "1";
    -
    242 signal.isSigned = fields[Signedness].str() == "-";
    -
    243
    -
    244 signal.factor = ParsePhysicalValue(fields[Factor].str(), "signal factor");
    -
    245 signal.offset = ParsePhysicalValue(fields[Offset].str(), "signal offset");
    -
    246 signal.minimum = ParsePhysicalValue(fields[Minimum].str(), "signal minimum");
    -
    247 signal.maximum = ParsePhysicalValue(fields[Maximum].str(), "signal maximum");
    -
    248 if (signal.minimum > signal.maximum)
    -
    249 throw std::runtime_error("Signal minimum exceeds maximum.");
    -
    250 signal.unit = fields[Unit].str();
    -
    251 signal.receivers = SplitReceivers(fields[Receivers].str());
    -
    252 return signal;
    -
    253}
    -
    254
    -
    255
    -
    256namespace {
    -
    257 FrameInfo *FindFrameById(DbcDatabase &database,
    -
    258 std::uint32_t canId,
    -
    259 bool isExtended) {
    -
    260 for (FrameInfo &frame : database.frames) {
    -
    261 if (frame.canId == canId && frame.isExtended == isExtended)
    -
    262 return &frame;
    -
    263 }
    -
    264
    -
    265 return nullptr;
    -
    266 }
    -
    267
    -
    268 SignalInfo *FindSignalByName(FrameInfo &frame, const std::string &signalName) {
    -
    269 for (SignalInfo &signal : frame.signals) {
    -
    270 if (signal.name == signalName)
    -
    271 return &signal;
    -
    272 }
    -
    273
    -
    274 return nullptr;
    -
    275 }
    -
    276}// namespace
    -
    277
    -
    -
    278void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const {
    -
    279 FrameInfo frame = ParseFrameLine(line);
    -
    280 if (context.enableJ1939 && frame.isExtended) {
    -
    281 frame.hasPgn = true;
    -
    282 frame.pgn = ExtractJ1939Pgn(frame.canId);
    -
    283 }
    -
    284 if (FindFrameById(context.database, frame.canId, frame.isExtended) != nullptr)
    -
    285 throw std::runtime_error("Duplicate " + std::string(frame.isExtended ? "extended" : "standard") +
    -
    286 " frame CAN ID: " + std::to_string(frame.canId));
    -
    287 context.database.frames.push_back(std::move(frame));
    -
    288 context.currentFrame = &context.database.frames.back();
    -
    289 context.signalLines.emplace_back();
    -
    290}
    +
    203 NormalizeCanId(rawCanId, frame.canId, frame.isExtended);
    +
    204
    +
    205 return frame;
    +
    206}
    +
    207
    +
    208SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
    +
    209 // Match the complete statement before converting any numeric fields.
    +
    210 enum Field {
    +
    211 NameAndMarker = 1, StartBit, BitLength, ByteOrder, Signedness,
    +
    212 Factor, Offset, Minimum, Maximum, Unit, Receivers
    +
    213 };
    +
    214 static const std::regex syntax(
    +
    215 // Name and optional multiplexing marker.
    +
    216 R"dbc(^SG_[ \t]+([^:]+):[ \t]*)dbc"
    +
    217 // Bit position, length, byte order and signedness.
    +
    218 R"dbc(([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*)dbc"
    +
    219 // Scaling factor and offset.
    +
    220 R"dbc(\‍([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*)dbc"
    +
    221 // Physical range.
    +
    222 R"dbc(\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*)dbc"
    +
    223 // Unit and receivers.
    +
    224 R"dbc("([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
    +
    225 std::smatch fields;
    +
    226 if (!std::regex_match(line, fields, syntax))
    +
    227 throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
    +
    228
    +
    229 SignalInfo signal;
    +
    230 std::istringstream nameFields(fields[NameAndMarker].str());
    +
    231 std::string marker;
    +
    232 std::string extra;
    +
    233 nameFields >> signal.name >> marker;
    +
    234 if (signal.name.empty() || (nameFields >> extra))
    +
    235 throw std::runtime_error("Invalid signal name or multiplexing marker.");
    +
    236 signal.multiplexing = ParseMultiplexingMarker(marker);
    +
    237
    +
    238 signal.startBit = ParseDecimal(fields[StartBit].str(),
    +
    239 std::numeric_limits<std::uint32_t>::max(), "signal start bit");
    +
    240 signal.length = ParseDecimal(fields[BitLength].str(), 64U, "signal length");
    +
    241 if (signal.length == 0U)
    +
    242 throw std::runtime_error("Signal length must be within 1..64 bits.");
    +
    243 signal.isLittleEndian = fields[ByteOrder].str() == "1";
    +
    244 signal.isSigned = fields[Signedness].str() == "-";
    +
    245
    +
    246 signal.factor = ParsePhysicalValue(fields[Factor].str(), "signal factor");
    +
    247 signal.offset = ParsePhysicalValue(fields[Offset].str(), "signal offset");
    +
    248 signal.minimum = ParsePhysicalValue(fields[Minimum].str(), "signal minimum");
    +
    249 signal.maximum = ParsePhysicalValue(fields[Maximum].str(), "signal maximum");
    +
    250 if (signal.minimum > signal.maximum)
    +
    251 throw std::runtime_error("Signal minimum exceeds maximum.");
    +
    252 signal.unit = fields[Unit].str();
    +
    253 signal.receivers = SplitReceivers(fields[Receivers].str());
    +
    254 return signal;
    +
    255}
    +
    256
    +
    257
    +
    258namespace {
    +
    259 FrameInfo *FindFrameById(DbcDatabase &database,
    +
    260 std::uint32_t canId,
    +
    261 bool isExtended) {
    +
    262 for (FrameInfo &frame : database.frames) {
    +
    263 if (frame.canId == canId && frame.isExtended == isExtended)
    +
    264 return &frame;
    +
    265 }
    +
    266
    +
    267 return nullptr;
    +
    268 }
    +
    269
    +
    270 SignalInfo *FindSignalByName(FrameInfo &frame, const std::string &signalName) {
    +
    271 for (SignalInfo &signal : frame.signals) {
    +
    272 if (signal.name == signalName)
    +
    273 return &signal;
    +
    274 }
    +
    275
    +
    276 return nullptr;
    +
    277 }
    +
    278}// namespace
    +
    279
    +
    +
    280void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    281 FrameInfo frame = ParseFrameLine(line);
    +
    282 if (context.enableJ1939 && frame.isExtended) {
    +
    283 frame.hasPgn = true;
    +
    284 frame.pgn = ExtractJ1939Pgn(frame.canId);
    +
    285 }
    +
    286 if (FindFrameById(context.database, frame.canId, frame.isExtended) != nullptr)
    +
    287 throw std::runtime_error("Duplicate " + std::string(frame.isExtended ? "extended" : "standard") +
    +
    288 " frame CAN ID: " + std::to_string(frame.canId));
    +
    289 context.database.frames.push_back(std::move(frame));
    +
    290 context.currentFrame = &context.database.frames.back();
    +
    291 context.signalLines.emplace_back();
    +
    292}
    -
    291
    -
    -
    292void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const {
    -
    293 if (context.currentFrame == nullptr)
    -
    294 throw std::runtime_error("Signal found before any frame definition.");
    -
    295 SignalInfo signal = ParseSignalLine(line);
    -
    296 if (FindSignalByName(*context.currentFrame, signal.name) != nullptr)
    -
    297 throw std::runtime_error("Duplicate signal name '" + signal.name +
    -
    298 "' in frame '" + context.currentFrame->name + "'.");
    -
    299 if (!IsValidSignalLayout(signal.startBit, signal.length, signal.isLittleEndian,
    -
    300 context.currentFrame->dlc))
    -
    301 throw std::runtime_error("Signal exceeds the frame payload length.");
    -
    302 context.currentFrame->signals.push_back(std::move(signal));
    -
    303 context.signalLines.back().push_back(context.lineNumber);
    -
    304}
    +
    293
    +
    +
    294void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    295 if (context.currentFrame == nullptr)
    +
    296 throw std::runtime_error("Signal found before any frame definition.");
    +
    297 SignalInfo signal = ParseSignalLine(line);
    +
    298 if (FindSignalByName(*context.currentFrame, signal.name) != nullptr)
    +
    299 throw std::runtime_error("Duplicate signal name '" + signal.name +
    +
    300 "' in frame '" + context.currentFrame->name + "'.");
    +
    301 if (!IsValidSignalLayout(signal.startBit, signal.length, signal.isLittleEndian,
    +
    302 context.currentFrame->dlc))
    +
    303 throw std::runtime_error("Signal exceeds the frame payload length.");
    +
    304 context.currentFrame->signals.push_back(std::move(signal));
    +
    305 context.signalLines.back().push_back(context.lineNumber);
    +
    306}
    -
    305
    -
    -
    306void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const {
    -
    307 std::istringstream stream(line);
    -
    308 std::string keyword;
    -
    309 std::string target;
    -
    310 stream >> keyword >> target;
    -
    311 if (keyword != "CM_" || (target != "BO_" && target != "SG_"))
    -
    312 return;
    -
    313
    -
    314 PendingComment pending;
    -
    315 pending.isSignal = target == "SG_";
    -
    316 pending.lineNumber = context.lineNumber;
    -
    317 std::string idText;
    -
    318 if (!(stream >> idText))
    -
    319 throw std::runtime_error("Missing CAN ID in CM_ statement.");
    -
    320 NormalizeCanId(ParseCanId(idText), pending.canId, pending.isExtended);
    -
    321 if (pending.isSignal && (!(stream >> pending.signalName) ||
    -
    322 pending.signalName.find_first_of("\";") != std::string::npos))
    -
    323 throw std::runtime_error("Missing or invalid signal name in CM_ statement.");
    -
    324
    -
    325 stream >> std::ws;
    -
    326 if (stream.get() != '"')
    -
    327 throw std::runtime_error("Missing opening quote in CM_ statement.");
    -
    328 bool closed = false;
    -
    329 char character;
    -
    330 while (stream.get(character)) {
    -
    331 if (character == '"') {
    -
    332 closed = true;
    -
    333 break;
    -
    334 }
    -
    335 if (character == '\\') {
    -
    336 if (!stream.get(character) || (character != '"' && character != '\\'))
    -
    337 throw std::runtime_error("Invalid escape in CM_ statement.");
    -
    338 }
    -
    339 pending.comment += character;
    -
    340 }
    -
    341 if (!closed)
    -
    342 throw std::runtime_error("Unterminated CM_ comment.");
    -
    343 stream >> std::ws;
    -
    344 if (stream.get() != ';')
    -
    345 throw std::runtime_error("Missing semicolon in CM_ statement.");
    -
    346 stream >> std::ws;
    -
    347 if (!stream.eof())
    -
    348 throw std::runtime_error("Unexpected trailing text in CM_ statement.");
    -
    349 context.pendingComments.push_back(std::move(pending));
    -
    350}
    +
    307
    +
    +
    308void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    309 std::istringstream stream(line);
    +
    310 std::string keyword;
    +
    311 std::string target;
    +
    312 stream >> keyword >> target;
    +
    313 if (keyword != "CM_" || (target != "BO_" && target != "SG_"))
    +
    314 return;
    +
    315
    +
    316 PendingComment pending;
    +
    317 pending.isSignal = target == "SG_";
    +
    318 pending.lineNumber = context.lineNumber;
    +
    319 std::string idText;
    +
    320 if (!(stream >> idText))
    +
    321 throw std::runtime_error("Missing CAN ID in CM_ statement.");
    +
    322 NormalizeCanId(ParseCanId(idText), pending.canId, pending.isExtended);
    +
    323 if (pending.isSignal && (!(stream >> pending.signalName) ||
    +
    324 pending.signalName.find_first_of("\";") != std::string::npos))
    +
    325 throw std::runtime_error("Missing or invalid signal name in CM_ statement.");
    +
    326
    +
    327 stream >> std::ws;
    +
    328 if (stream.get() != '"')
    +
    329 throw std::runtime_error("Missing opening quote in CM_ statement.");
    +
    330 bool closed = false;
    +
    331 char character;
    +
    332 while (stream.get(character)) {
    +
    333 if (character == '"') {
    +
    334 closed = true;
    +
    335 break;
    +
    336 }
    +
    337 if (character == '\\') {
    +
    338 if (!stream.get(character) || (character != '"' && character != '\\'))
    +
    339 throw std::runtime_error("Invalid escape in CM_ statement.");
    +
    340 }
    +
    341 pending.comment += character;
    +
    342 }
    +
    343 if (!closed)
    +
    344 throw std::runtime_error("Unterminated CM_ comment.");
    +
    345 stream >> std::ws;
    +
    346 if (stream.get() != ';')
    +
    347 throw std::runtime_error("Missing semicolon in CM_ statement.");
    +
    348 stream >> std::ws;
    +
    349 if (!stream.eof())
    +
    350 throw std::runtime_error("Unexpected trailing text in CM_ statement.");
    +
    351 context.pendingComments.push_back(std::move(pending));
    +
    352}
    -
    351
    -
    -
    352void DbcParseContext::ResolveComments(const std::string &filePath) {
    -
    353 for (const PendingComment &pending: pendingComments) {
    -
    354 FrameInfo *frame = FindFrameById(database, pending.canId, pending.isExtended);
    -
    355 if (!frame)
    -
    356 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidStatement, filePath,
    -
    357 pending.lineNumber, "Unresolved CM_ frame reference.");
    -
    358 if (pending.isSignal) {
    -
    359 SignalInfo *signal = FindSignalByName(*frame, pending.signalName);
    -
    360 if (!signal)
    -
    361 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidStatement, filePath,
    -
    362 pending.lineNumber, "Unresolved CM_ signal reference: " + pending.signalName);
    -
    363 signal->comment = pending.comment;
    -
    364 } else {
    -
    365 frame->comment = pending.comment;
    -
    366 }
    -
    367 }
    -
    368}
    +
    353
    +
    +
    354void DbcParseContext::ResolveComments(const std::string &filePath) {
    +
    355 for (const PendingComment &pending: pendingComments) {
    +
    356 FrameInfo *frame = FindFrameById(database, pending.canId, pending.isExtended);
    +
    357 if (!frame)
    +
    358 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidStatement, filePath,
    +
    359 pending.lineNumber, "Unresolved CM_ frame reference.");
    +
    360 if (pending.isSignal) {
    +
    361 SignalInfo *signal = FindSignalByName(*frame, pending.signalName);
    +
    362 if (!signal)
    +
    363 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidStatement, filePath,
    +
    364 pending.lineNumber, "Unresolved CM_ signal reference: " + pending.signalName);
    +
    365 signal->comment = pending.comment;
    +
    366 } else {
    +
    367 frame->comment = pending.comment;
    +
    368 }
    +
    369 }
    +
    370}
    -
    369
    -
    - -
    371 RegisterType<DbcHeaderHandler>("VERSION");
    -
    372 RegisterType<DbcHeaderHandler>("NS_");
    -
    373 RegisterType<DbcHeaderHandler>("NS_:");
    -
    374 RegisterType<DbcHeaderHandler>("BS_");
    -
    375 RegisterType<DbcHeaderHandler>("BS_:");
    -
    376 RegisterType<DbcHeaderHandler>("BU_");
    -
    377 RegisterType<DbcHeaderHandler>("BU_:");
    -
    378 RegisterType<DbcUnsupportedMultiplexingHandler>("SG_MUL_VAL_");
    -
    379 RegisterType<DbcFrameHandler>("BO_");
    -
    380 RegisterType<DbcSignalHandler>("SG_");
    -
    381 RegisterType<DbcCommentHandler>("CM_");
    -
    382 RegisterType<DbcValueDescriptionHandler>("VAL_");
    -
    383 RegisterType<DbcAttributeHandler>("BA_DEF_");
    -
    384 RegisterType<DbcAttributeHandler>("BA_DEF_DEF_");
    -
    385 RegisterType<DbcAttributeHandler>("BA_");
    -
    386}
    +
    371
    +
    + +
    373 RegisterType<DbcHeaderHandler>("VERSION");
    +
    374 RegisterType<DbcHeaderHandler>("NS_");
    +
    375 RegisterType<DbcHeaderHandler>("NS_:");
    +
    376 RegisterType<DbcHeaderHandler>("BS_");
    +
    377 RegisterType<DbcHeaderHandler>("BS_:");
    +
    378 RegisterType<DbcHeaderHandler>("BU_");
    +
    379 RegisterType<DbcHeaderHandler>("BU_:");
    +
    380 RegisterType<DbcMultiplexingHandler>("SG_MUL_VAL_");
    +
    381 RegisterType<DbcFrameHandler>("BO_");
    +
    382 RegisterType<DbcSignalHandler>("SG_");
    +
    383 RegisterType<DbcCommentHandler>("CM_");
    +
    384 RegisterType<DbcValueDescriptionHandler>("VAL_");
    +
    385 RegisterType<DbcAttributeHandler>("BA_DEF_");
    +
    386 RegisterType<DbcAttributeHandler>("BA_DEF_DEF_");
    +
    387 RegisterType<DbcAttributeHandler>("BA_");
    +
    388}
    -
    387
    -
    388void DbcHeaderHandler::Handle(const std::string &, DbcParseContext &) const {}
    389
    -
    -
    390bool DbcStatementDispatcher::Dispatch(const std::string &line,
    -
    391 DbcParseContext &context) const {
    -
    392 std::istringstream stream(line);
    -
    393 std::string keyword;
    -
    394 stream >> keyword;
    -
    395 const HandlerMap::const_iterator handler = m_handlers.find(keyword);
    -
    396 if (handler == m_handlers.end())
    -
    397 return false;
    -
    398 handler->second->Handle(line, context);
    -
    399 return true;
    -
    400}
    +
    390void DbcHeaderHandler::Handle(const std::string &, DbcParseContext &) const {}
    +
    391
    +
    +
    392bool DbcStatementDispatcher::Dispatch(const std::string &line,
    +
    393 DbcParseContext &context) const {
    +
    394 std::istringstream stream(line);
    +
    395 std::string keyword;
    +
    396 stream >> keyword;
    +
    397 const HandlerMap::const_iterator handler = m_handlers.find(keyword);
    +
    398 if (handler == m_handlers.end())
    +
    399 return false;
    +
    400 handler->second->Handle(line, context);
    +
    401 return true;
    +
    402}
    -
    401
    -
    -
    402void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext &context) const {
    -
    403 static const std::regex header(R"(^VAL_[ \t]+([^ \t]+)[ \t]+([^ \t;]+)[ \t]+(.*)$)");
    -
    404 static const std::regex pair(R"dbc(^([^ \t]+)[ \t]+"((?:[^"\\]|\\["\\])*)")dbc");
    -
    405 std::smatch fields;
    -
    406 if (!std::regex_match(line, fields, header))
    -
    407 throw std::runtime_error("Malformed or unsupported VAL_ statement.");
    -
    408 const std::uint32_t rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
    -
    409 if ((rawId & 0x60000000U) != 0U)
    -
    410 throw std::runtime_error("VAL_ CAN ID exceeds the 29-bit identifier range.");
    - -
    412 NormalizeCanId(rawId, pending.canId, pending.isExtended);
    -
    413 pending.signalName = fields[2].str();
    -
    414 pending.lineNumber = context.lineNumber;
    -
    415 std::string rest = fields[3].str();
    -
    416 while (rest != ";") {
    -
    417 if (!std::regex_search(rest, fields, pair))
    -
    418 throw std::runtime_error("Malformed VAL_ value/description pair or missing semicolon.");
    -
    419 const std::string number = fields[1].str();
    -
    420 const RawSignalValue key = ParseValueKey(number);
    -
    421 const std::string description = UnescapeDescription(fields[2].str());
    -
    422 if (!pending.descriptions.emplace(key, description).second)
    -
    423 throw std::runtime_error("Duplicate VAL_ value key: " + number);
    -
    424 const std::size_t consumed = static_cast<std::size_t>(fields.length());
    -
    425 rest.erase(0, consumed);
    -
    426 if (!rest.empty() && rest[0] != ';' && rest[0] != ' ' && rest[0] != '\t')
    -
    427 throw std::runtime_error("Missing whitespace between VAL_ pairs.");
    -
    428 rest = dbc_detail::TrimText(rest);
    -
    429 }
    -
    430 if (pending.descriptions.empty())
    -
    431 throw std::runtime_error("VAL_ requires at least one value/description pair.");
    -
    432 context.pendingValues.push_back(std::move(pending));
    -
    433}
    +
    403
    +
    +
    404void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    405 static const std::regex header(R"(^VAL_[ \t]+([^ \t]+)[ \t]+([^ \t;]+)[ \t]+(.*)$)");
    +
    406 static const std::regex pair(R"dbc(^([^ \t]+)[ \t]+"((?:[^"\\]|\\["\\])*)")dbc");
    +
    407 std::smatch fields;
    +
    408 if (!std::regex_match(line, fields, header))
    +
    409 throw std::runtime_error("Malformed or unsupported VAL_ statement.");
    +
    410 const std::uint32_t rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
    +
    411 if ((rawId & 0x60000000U) != 0U)
    +
    412 throw std::runtime_error("VAL_ CAN ID exceeds the 29-bit identifier range.");
    + +
    414 NormalizeCanId(rawId, pending.canId, pending.isExtended);
    +
    415 pending.signalName = fields[2].str();
    +
    416 pending.lineNumber = context.lineNumber;
    +
    417 std::string rest = fields[3].str();
    +
    418 while (rest != ";") {
    +
    419 if (!std::regex_search(rest, fields, pair))
    +
    420 throw std::runtime_error("Malformed VAL_ value/description pair or missing semicolon.");
    +
    421 const std::string number = fields[1].str();
    +
    422 const RawSignalValue key = ParseValueKey(number);
    +
    423 const std::string description = UnescapeDescription(fields[2].str());
    +
    424 if (!pending.descriptions.emplace(key, description).second)
    +
    425 throw std::runtime_error("Duplicate VAL_ value key: " + number);
    +
    426 const std::size_t consumed = static_cast<std::size_t>(fields.length());
    +
    427 rest.erase(0, consumed);
    +
    428 if (!rest.empty() && rest[0] != ';' && rest[0] != ' ' && rest[0] != '\t')
    +
    429 throw std::runtime_error("Missing whitespace between VAL_ pairs.");
    +
    430 rest = dbc_detail::TrimText(rest);
    +
    431 }
    +
    432 if (pending.descriptions.empty())
    +
    433 throw std::runtime_error("VAL_ requires at least one value/description pair.");
    +
    434 context.pendingValues.push_back(std::move(pending));
    +
    435}
    -
    434
    -
    -
    435void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
    -
    436 for (const PendingValueDescriptions &pending: pendingValues) {
    -
    437 try {
    -
    438 FrameInfo *frame = FindUniqueFrame(database, pending.canId, pending.isExtended);
    -
    439 SignalInfo *signal = FindUniqueSignal(*frame, pending.signalName);
    -
    440 for (const ValueDescriptions::value_type &entry: pending.descriptions) {
    -
    441 if (!signal->valueDescriptions.insert(entry).second)
    -
    442 throw std::runtime_error("Duplicate VAL_ value key for signal: " + pending.signalName);
    -
    443 }
    -
    444 } catch (const std::exception &error) {
    -
    445 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidValueDescription,
    -
    446 filePath, pending.lineNumber, error.what());
    -
    447 }
    -
    448 }
    -
    449}
    +
    436
    +
    +
    437void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
    +
    438 for (const PendingValueDescriptions &pending: pendingValues) {
    +
    439 try {
    +
    440 FrameInfo *frame = FindUniqueFrame(database, pending.canId, pending.isExtended);
    +
    441 SignalInfo *signal = FindUniqueSignal(*frame, pending.signalName);
    +
    442 for (const ValueDescriptions::value_type &entry: pending.descriptions) {
    +
    443 if (!signal->valueDescriptions.insert(entry).second)
    +
    444 throw std::runtime_error("Duplicate VAL_ value key for signal: " + pending.signalName);
    +
    445 }
    +
    446 } catch (const std::exception &error) {
    +
    447 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidValueDescription,
    +
    448 filePath, pending.lineNumber, error.what());
    +
    449 }
    +
    450 }
    +
    451}
    -
    450
    -
    - -
    452 throw std::runtime_error("Extended and nested multiplexing are unsupported.");
    -
    453}
    +
    452
    +
    +
    453void DbcMultiplexingHandler::Handle(const std::string &line, DbcParseContext &context) const {
    +
    454 static const std::regex syntax(R"(^SG_MUL_VAL_[ \t]+([0-9]+)[ \t]+([^ \t;]+)[ \t]+([^ \t;]+)[ \t]+(.+);[ \t]*$)");
    +
    455 static const std::regex rangeSyntax(R"(^[ \t]*([0-9]+)[ \t]*-[ \t]*([0-9]+)[ \t]*$)");
    +
    456 std::smatch fields;
    +
    457 if (!std::regex_match(line, fields, syntax))
    +
    458 throw std::runtime_error("Malformed SG_MUL_VAL_ statement.");
    +
    459 PendingMultiplexing pending;
    +
    460 NormalizeCanId(ParseCanId(fields[1].str()), pending.canId, pending.isExtended);
    +
    461 pending.signalName = fields[2].str();
    +
    462 pending.selectorName = fields[3].str();
    +
    463 pending.lineNumber = context.lineNumber;
    +
    464 const std::string list = fields[4].str();
    +
    465 std::size_t begin = 0U;
    +
    466 for (;;) {
    +
    467 const std::size_t comma = list.find(',', begin);
    +
    468 const std::string item = list.substr(begin, comma == std::string::npos ? comma : comma - begin);
    +
    469 if (!std::regex_match(item, fields, rangeSyntax))
    +
    470 throw std::runtime_error("Malformed multiplex range.");
    +
    471 MultiplexRange range;
    +
    472 const std::string lower = fields[1].str();
    +
    473 const std::string upper = fields[2].str();
    +
    474 const std::from_chars_result low = std::from_chars(lower.data(), lower.data() + lower.size(), range.minimum);
    +
    475 const std::from_chars_result high = std::from_chars(upper.data(), upper.data() + upper.size(), range.maximum);
    +
    476 if (low.ec != std::errc() || high.ec != std::errc() || range.minimum > range.maximum)
    +
    477 throw std::runtime_error("Invalid multiplex range.");
    +
    478 pending.ranges.push_back(range);
    +
    479 if (comma == std::string::npos)
    +
    480 break;
    +
    481 begin = comma + 1U;
    +
    482 }
    +
    483 context.pendingMultiplexing.push_back(std::move(pending));
    +
    484}
    -
    454
    -
    455namespace {
    -
    456 std::vector<std::uint64_t> SignalBits(const SignalInfo &signal) {
    -
    457 std::vector<std::uint64_t> bits;
    -
    458 std::uint64_t bit = signal.startBit;
    -
    459 for (std::uint32_t index = 0U; index < signal.length; ++index) {
    -
    460 bits.push_back(bit);
    -
    461 bit = NextSignalBit(bit, signal.isLittleEndian);
    -
    462 }
    -
    463 return bits;
    -
    464 }
    -
    465
    -
    466 bool AreMutuallyExclusive(const SignalInfo &first, const SignalInfo &second) {
    -
    467 return first.multiplexing.role == MultiplexRole::Branch &&
    -
    468 second.multiplexing.role == MultiplexRole::Branch &&
    -
    469 first.multiplexing.value != second.multiplexing.value;
    -
    470 }
    -
    471
    -
    472 std::string ValidateBranch(const SignalInfo &signal, const SignalInfo *selector) {
    -
    473 if (signal.multiplexing.role != MultiplexRole::Branch)
    -
    474 return {};
    -
    475 if (selector == nullptr)
    -
    476 return "Multiplexed branch has no selector.";
    -
    477 if (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length))
    -
    478 return "Branch value exceeds selector raw range.";
    -
    479 return {};
    -
    480 }
    -
    481
    -
    482 const SignalInfo *FindSelector(const FrameInfo &frame,
    -
    483 const std::vector<std::size_t> &lines,
    -
    484 const std::string &filePath) {
    -
    485 const SignalInfo *selector = nullptr;
    -
    486 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
    -
    487 const SignalInfo &signal = frame.signals[index];
    -
    488 if (signal.multiplexing.role != MultiplexRole::Selector)
    -
    489 continue;
    -
    490 if (selector != nullptr || signal.isSigned)
    -
    491 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidMultiplexing,
    -
    492 filePath, lines[index],
    -
    493 "Multiplexing requires one unsigned selector per frame.");
    -
    494 selector = &signal;
    -
    495 }
    -
    496 return selector;
    -
    497 }
    -
    498
    -
    499 bool SignalsOverlap(const SignalInfo &first, const SignalInfo &second) {
    -
    500 const std::vector<std::uint64_t> firstBits = SignalBits(first);
    -
    501 const std::vector<std::uint64_t> secondBits = SignalBits(second);
    -
    502 for (const std::uint64_t firstBit : firstBits) {
    -
    503 for (const std::uint64_t secondBit : secondBits) {
    -
    504 if (firstBit == secondBit)
    -
    505 return true;
    -
    506 }
    -
    507 }
    -
    508 return false;
    +
    485
    +
    486void DbcParseContext::ResolveMultiplexing(const std::string &filePath) {
    +
    487 for (const PendingMultiplexing &pending: pendingMultiplexing) {
    +
    488 try {
    +
    489 FrameInfo *frame = FindUniqueFrame(database, pending.canId, pending.isExtended, "SG_MUL_VAL_");
    +
    490 SignalInfo *signal = FindUniqueSignal(*frame, pending.signalName, "SG_MUL_VAL_");
    +
    491 SignalInfo *selector = FindUniqueSignal(*frame, pending.selectorName, "SG_MUL_VAL_");
    +
    492 if (!IsMultiplexSelector(selector->multiplexing.role) || selector->isSigned)
    +
    493 throw std::runtime_error("Referenced signal must be an unsigned multiplex selector.");
    +
    494 if (!signal->multiplexing.selector.empty() && signal->multiplexing.selector != pending.selectorName)
    +
    495 throw std::runtime_error("Multiple parent selectors for one signal are unsupported.");
    +
    496 for (const MultiplexRange &range: pending.ranges) {
    +
    497 if (selector->length < 64U && range.maximum >= (std::uint64_t(1U) << selector->length))
    +
    498 throw std::runtime_error("Branch value exceeds selector raw range.");
    +
    499 }
    +
    500 signal->multiplexing.selector = pending.selectorName;
    +
    501 signal->multiplexing.ranges.insert(signal->multiplexing.ranges.end(), pending.ranges.begin(), pending.ranges.end());
    +
    502 if (!IsMultiplexSelector(signal->multiplexing.role))
    +
    503 signal->multiplexing.role = MultiplexRole::Branch;
    +
    504 else
    +
    505 signal->multiplexing.role = MultiplexRole::BranchSelector;
    +
    506 } catch (const std::exception &error) {
    +
    507 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidMultiplexing, filePath, pending.lineNumber, error.what());
    +
    508 }
    509 }
    510}
    511
    -
    -
    512void DbcParseContext::ValidateMultiplexing(const std::string &filePath) const {
    -
    513 for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) {
    -
    514 const FrameInfo &frame = database.frames[frameIndex];
    -
    515 const SignalInfo *selector = FindSelector(frame, signalLines[frameIndex], filePath);
    -
    516 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
    -
    517 const SignalInfo &signal = frame.signals[index];
    -
    518 std::string error = ValidateBranch(signal, selector);
    -
    519 for (std::size_t previous = 0U; previous < index && error.empty(); ++previous) {
    -
    520 const SignalInfo &other = frame.signals[previous];
    -
    521 if (!AreMutuallyExclusive(signal, other) && SignalsOverlap(signal, other))
    -
    522 error = "Signals overlap without mutually exclusive multiplexing conditions.";
    -
    523 }
    -
    524 if (!error.empty())
    -
    525 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidMultiplexing,
    -
    526 filePath, signalLines[frameIndex][index], error);
    -
    527 }
    -
    528 }
    -
    529}
    +
    512namespace {
    +
    513 std::vector<std::uint64_t> SignalBits(const SignalInfo &signal) {
    +
    514 std::vector<std::uint64_t> bits;
    +
    515 std::uint64_t bit = signal.startBit;
    +
    516 for (std::uint32_t index = 0U; index < signal.length; ++index) {
    +
    517 bits.push_back(bit);
    +
    518 bit = NextSignalBit(bit, signal.isLittleEndian);
    +
    519 }
    +
    520 return bits;
    +
    521 }
    +
    522
    +
    523 bool SignalsOverlap(const SignalInfo &first, const SignalInfo &second) {
    +
    524 const std::vector<std::uint64_t> firstBits = SignalBits(first);
    +
    525 const std::vector<std::uint64_t> secondBits = SignalBits(second);
    +
    526 for (const std::uint64_t firstBit : firstBits) {
    +
    527 for (const std::uint64_t secondBit : secondBits) {
    +
    528 if (firstBit == secondBit)
    +
    529 return true;
    +
    530 }
    +
    531 }
    +
    532 return false;
    +
    533 }
    +
    534}
    +
    535
    +
    +
    536void DbcParseContext::ValidateMultiplexing(const std::string &filePath) const {
    +
    537 for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) {
    +
    538 const FrameInfo &frame = database.frames[frameIndex];
    +
    539 try {
    +
    540 const dbc_detail::MultiplexGraph graph(frame.signals);
    +
    541 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
    +
    542 const SignalInfo &signal = frame.signals[index];
    +
    543 if (IsMultiplexSelector(signal.multiplexing.role) && signal.isSigned)
    +
    544 throw dbc_detail::MultiplexError(index, "Multiplex selectors must be unsigned.");
    +
    545 for (std::size_t previous = 0U; previous < index; ++previous) {
    +
    546 if (!graph.AreMutuallyExclusive(index, previous) && SignalsOverlap(signal, frame.signals[previous]))
    +
    547 throw dbc_detail::MultiplexError(index, "Signals overlap without mutually exclusive multiplexing conditions.");
    +
    548 }
    +
    549 }
    +
    550 } catch (const dbc_detail::MultiplexError &error) {
    +
    551 throw DbcDiagnosticError(DbcDiagnosticCode::InvalidMultiplexing, filePath,
    +
    552 signalLines[frameIndex][error.index], error.what());
    +
    553 }
    +
    554 }
    +
    555}
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    DbcStatementDispatcher()
    Register supported statement handlers through TypeFactory.
    -
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    DbcStatementDispatcher()
    Register supported statement handlers through TypeFactory.
    +
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    + + +
    ByteOrder
    Signal byte order used for runtime decoding.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    - - - -
    std::vector< PendingComment > pendingComments
    -
    void ValidateMultiplexing(const std::string &filePath) const
    Validate selectors, branch ranges, and signal overlap.
    - -
    void ResolveValueDescriptions(const std::string &filePath)
    Resolve deferred raw descriptions against unique targets.
    -
    std::vector< PendingValueDescriptions > pendingValues
    -
    void ResolveComments(const std::string &filePath)
    Resolve deferred comments after all definitions are known.
    - -
    std::vector< std::vector< std::size_t > > signalLines
    + + + +
    std::vector< PendingComment > pendingComments
    +
    void ValidateMultiplexing(const std::string &filePath) const
    Validate selectors, branch ranges, and signal overlap.
    + +
    void ResolveValueDescriptions(const std::string &filePath)
    Resolve deferred raw descriptions against unique targets.
    +
    std::vector< PendingValueDescriptions > pendingValues
    +
    void ResolveComments(const std::string &filePath)
    Resolve deferred comments after all definitions are known.
    + +
    std::vector< std::vector< std::size_t > > signalLines
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    bool hasPgn
    Definition frame_info.h:30
    @@ -679,9 +707,11 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8cpp_source.ht
    std::string comment
    Definition frame_info.h:33
    std::uint32_t pgn
    Definition frame_info.h:29
    std::uint32_t canId
    Definition frame_info.h:27
    - -
    MultiplexRole role
    -
    std::uint64_t value
    +
    Inclusive raw selector range, without expanding individual values.
    +
    Basic markers and optional explicit extended multiplexing condition.
    +
    std::uint64_t value
    +
    std::vector< MultiplexRange > ranges
    +
    std::string selector
    Deferred frame or signal comment and its source location.
    @@ -689,6 +719,7 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8cpp_source.ht +
    Deferred extended multiplexing condition and source location.
    Deferred raw value descriptions and their target.
    diff --git a/docs/html/dbc__statement__handler_8h_source.html b/docs/html/dbc__statement__handler_8h_source.html index 5c2850e..9bc0d9f 100644 --- a/docs/html/dbc__statement__handler_8h_source.html +++ b/docs/html/dbc__statement__handler_8h_source.html @@ -152,153 +152,167 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8h_source.html
    48
    - - - -
    53 bool enableJ1939 = false;
    -
    54 std::size_t lineNumber = 0U;
    -
    55 std::vector<PendingValueDescriptions> pendingValues = {};
    -
    57 std::vector<std::vector<std::size_t>> signalLines = {};
    -
    59 void ValidateMultiplexing(const std::string &filePath) const;
    -
    60
    -
    61 std::vector<PendingComment> pendingComments = {};
    -
    63 void ResolveComments(const std::string &filePath);
    -
    64
    -
    65 std::vector<PendingAttribute> pendingAttributes = {};
    -
    67 void ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics);
    -
    68
    -
    70 void ResolveValueDescriptions(const std::string &filePath);
    -
    71};
    + +
    51 std::uint32_t canId;
    +
    52 bool isExtended;
    +
    53 std::string signalName;
    +
    54 std::string selectorName;
    +
    55 std::vector<MultiplexRange> ranges;
    +
    56 std::size_t lineNumber;
    +
    57};
    -
    72
    -
    - -
    75public:
    -
    76 virtual ~DbcStatementHandler() = default;
    -
    78 virtual void Handle(const std::string &line, DbcParseContext &context) const = 0;
    -
    79};
    +
    58
    +
    + + + +
    63 bool enableJ1939 = false;
    +
    64 std::size_t lineNumber = 0U;
    +
    65 std::vector<PendingValueDescriptions> pendingValues = {};
    +
    67 std::vector<PendingMultiplexing> pendingMultiplexing = {};
    +
    68 void ResolveMultiplexing(const std::string &filePath);
    +
    69
    +
    70 std::vector<std::vector<std::size_t>> signalLines = {};
    +
    72 void ValidateMultiplexing(const std::string &filePath) const;
    +
    73
    +
    74 std::vector<PendingComment> pendingComments = {};
    +
    76 void ResolveComments(const std::string &filePath);
    +
    77
    +
    78 std::vector<PendingAttribute> pendingAttributes = {};
    +
    80 void ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics);
    +
    81
    +
    83 void ResolveValueDescriptions(const std::string &filePath);
    +
    84};
    -
    80
    -
    - -
    83public:
    -
    84 void Handle(const std::string &line, DbcParseContext &context) const override;
    85
    -
    86private:
    -
    87 static FrameInfo ParseFrameLine(const std::string &line);
    -
    88};
    -
    -
    89
    -
    - -
    92public:
    -
    93 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    94
    -
    95private:
    -
    96 static SignalInfo ParseSignalLine(const std::string &line);
    -
    97};
    +
    + +
    88public:
    +
    89 virtual ~DbcStatementHandler() = default;
    +
    91 virtual void Handle(const std::string &line, DbcParseContext &context) const = 0;
    +
    92};
    +
    93
    +
    + +
    96public:
    +
    97 void Handle(const std::string &line, DbcParseContext &context) const override;
    98
    -
    - -
    101public:
    -
    102 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    103};
    +
    99private:
    +
    100 static FrameInfo ParseFrameLine(const std::string &line);
    +
    101};
    -
    104
    -
    - -
    107public:
    -
    108 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    109};
    +
    102
    +
    + +
    105public:
    +
    106 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    107
    +
    108private:
    +
    109 static SignalInfo ParseSignalLine(const std::string &line);
    +
    110};
    -
    110
    -
    - -
    113public:
    -
    114 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    115};
    +
    111
    +
    + +
    114public:
    +
    115 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    116};
    -
    116
    -
    - -
    119public:
    -
    120 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    121};
    +
    117
    +
    + +
    120public:
    +
    121 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    122};
    -
    122
    -
    - -
    125public:
    -
    126 void Handle(const std::string &line, DbcParseContext &context) const override;
    -
    127};
    +
    123
    +
    + +
    126public:
    +
    127 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    128};
    -
    128
    -
    - -
    131public:
    - -
    134
    -
    136 template<class Handler>
    -
    -
    137 void RegisterType(const std::string &keyword) {
    -
    138 m_factory.registerType<Handler>(keyword);
    -
    139 m_handlers.insert_or_assign(keyword, m_factory.create(keyword));
    -
    140 }
    +
    129
    +
    + +
    132public:
    +
    133 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    134};
    +
    +
    135
    +
    + +
    138public:
    +
    139 void Handle(const std::string &line, DbcParseContext &context) const override;
    +
    140};
    141
    -
    143 bool Dispatch(const std::string &line, DbcParseContext &context) const;
    -
    144
    -
    145private:
    -
    146 using HandlerMap = std::unordered_map<std::string, std::shared_ptr<DbcStatementHandler>>;
    - -
    148 HandlerMap m_handlers;
    -
    149};
    +
    + +
    144public:
    + +
    147
    +
    149 template<class Handler>
    +
    +
    150 void RegisterType(const std::string &keyword) {
    +
    151 m_factory.registerType<Handler>(keyword);
    +
    152 m_handlers.insert_or_assign(keyword, m_factory.create(keyword));
    +
    153 }
    -
    150
    -
    151#endif /* DBC_STATEMENT_HANDLER_H */
    -
    Defer typed attribute statements for resolution.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    Defer frame and signal comments for target resolution.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    154
    +
    156 bool Dispatch(const std::string &line, DbcParseContext &context) const;
    +
    157
    +
    158private:
    +
    159 using HandlerMap = std::unordered_map<std::string, std::shared_ptr<DbcStatementHandler>>;
    + +
    161 HandlerMap m_handlers;
    +
    162};
    +
    +
    163
    +
    164#endif /* DBC_STATEMENT_HANDLER_H */
    +
    Defer typed attribute statements for resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Defer frame and signal comments for target resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    DbcDiagnosticError(DbcDiagnosticCode code, const std::string &filePath, std::size_t lineNumber, const std::string &message)
    Create an exception with a structured source diagnostic.
    -
    Parse and append frame definitions.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    - -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    Parse and append signals to the current frame.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    - -
    void RegisterType(const std::string &keyword)
    Register or replace a handler and create its reusable instance.
    -
    DbcStatementDispatcher()
    Register supported statement handlers through TypeFactory.
    -
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    -
    Interface for processing a registered DBC statement.
    +
    Parse and append frame definitions.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    + +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Parse extended multiplexing conditions for deferred resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Parse and append signals to the current frame.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    + +
    void RegisterType(const std::string &keyword)
    Register or replace a handler and create its reusable instance.
    +
    DbcStatementDispatcher()
    Register supported statement handlers through TypeFactory.
    +
    bool Dispatch(const std::string &line, DbcParseContext &context) const
    +
    Interface for processing a registered DBC statement.
    virtual void Handle(const std::string &line, DbcParseContext &context) const =0
    Process a trimmed statement using state belonging to this parse.
    -
    Reject unsupported extended multiplexing statements.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    -
    Defer raw value descriptions for target resolution.
    -
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    +
    Defer raw value descriptions for target resolution.
    +
    void Handle(const std::string &line, DbcParseContext &context) const override
    Process a trimmed statement using state belonging to this parse.
    Registry-based factory for creating objects by runtime identifier.
    Definition typefactory.h:59
    BasePtr create(const ClassId &id, Args... args) const
    Creates an instance for the given id using provided arguments.
    Definition typefactory.h:99
    void registerType(const ClassId &id)
    Registers a Derived type under the given id.
    Definition typefactory.h:78
    Parsed DBC database and attribute metadata.
    Parsed DBC content stored in a simple internal form.
    Diagnostic message and physical source location.
    - -
    void ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)
    Resolve definitions, defaults, then assignments; append format warnings.
    - - -
    std::vector< PendingComment > pendingComments
    -
    void ValidateMultiplexing(const std::string &filePath) const
    Validate selectors, branch ranges, and signal overlap.
    - -
    void ResolveValueDescriptions(const std::string &filePath)
    Resolve deferred raw descriptions against unique targets.
    -
    std::vector< PendingValueDescriptions > pendingValues
    -
    void ResolveComments(const std::string &filePath)
    Resolve deferred comments after all definitions are known.
    - -
    std::vector< std::vector< std::size_t > > signalLines
    -
    std::vector< PendingAttribute > pendingAttributes
    + +
    void ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)
    Resolve definitions, defaults, then assignments; append format warnings.
    + + +
    std::vector< PendingComment > pendingComments
    +
    void ValidateMultiplexing(const std::string &filePath) const
    Validate selectors, branch ranges, and signal overlap.
    + +
    void ResolveValueDescriptions(const std::string &filePath)
    Resolve deferred raw descriptions against unique targets.
    +
    std::vector< PendingValueDescriptions > pendingValues
    +
    void ResolveComments(const std::string &filePath)
    Resolve deferred comments after all definitions are known.
    + +
    std::vector< std::vector< std::size_t > > signalLines
    +
    std::vector< PendingAttribute > pendingAttributes
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    Attribute statement retained for ordered resolution.
    @@ -310,6 +324,7 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8h_source.html +
    Deferred extended multiplexing condition and source location.
    Deferred raw value descriptions and their target.
    diff --git a/docs/html/dbc__tree__model_8cpp_source.html b/docs/html/dbc__tree__model_8cpp_source.html index e8eabb4..2679b2d 100644 --- a/docs/html/dbc__tree__model_8cpp_source.html +++ b/docs/html/dbc__tree__model_8cpp_source.html @@ -279,7 +279,7 @@ $(document).ready(function(){initNavTree('dbc__tree__model_8cpp_source.html','')
    std::size_t GetRow() const
    Definition tree_node.cpp:79
    NodeType GetType() const
    Get node type.
    Definition tree_node.cpp:59
    const FrameInfo * GetFrame() const
    Get frame payload if node is frame.
    Definition tree_node.cpp:67
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    std::uint8_t dlc
    Definition frame_info.h:31
    diff --git a/docs/html/dbc__tree__model_8h_source.html b/docs/html/dbc__tree__model_8h_source.html index 13b31f7..244fca1 100644 --- a/docs/html/dbc__tree__model_8h_source.html +++ b/docs/html/dbc__tree__model_8h_source.html @@ -163,7 +163,7 @@ $(document).ready(function(){initNavTree('dbc__tree__model_8h_source.html','');
    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
    Return display text or typed metadata for an index.
    QModelIndex parent(const QModelIndex &child) const override
    Return the parent in column zero, or an invalid index for frames.
    Tree node for later use in model/view or other hierarchy consumers.
    Definition tree_node.h:37
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    Qt-independent metadata tree nodes.
    diff --git a/docs/html/dbc__tree__model__test_8cpp_source.html b/docs/html/dbc__tree__model__test_8cpp_source.html index a926825..458bcfc 100644 --- a/docs/html/dbc__tree__model__test_8cpp_source.html +++ b/docs/html/dbc__tree__model__test_8cpp_source.html @@ -313,7 +313,7 @@ $(document).ready(function(){initNavTree('dbc__tree__model__test_8cpp_source.htm
    213 return QTest::qExec(&tests, argc, argv);
    214}
    215#include "dbc_tree_model_test.moc"
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    diff --git a/docs/html/dbc__validation__test_8cpp_source.html b/docs/html/dbc__validation__test_8cpp_source.html index 5a5dd96..1771595 100644 --- a/docs/html/dbc__validation__test_8cpp_source.html +++ b/docs/html/dbc__validation__test_8cpp_source.html @@ -253,298 +253,298 @@ $(document).ready(function(){initNavTree('dbc__validation__test_8cpp_source.html
    153 signal.valueType = static_cast<ValueType>(99);
    154 break;
    155 case 16:
    -
    156 signal.multiplexing.role = static_cast<MultiplexRole>(99);
    +
    156 signal.multiplexing.role = static_cast<MultiplexRole>(99);
    157 break;
    158 case 17:
    -
    159 signal.multiplexing.role = MultiplexRole::Branch;
    +
    159 signal.multiplexing.role = MultiplexRole::Branch;
    160 break;
    161 case 18:
    -
    162 signal.multiplexing.role = MultiplexRole::Selector;
    +
    162 signal.multiplexing.role = MultiplexRole::Selector;
    163 signal.valueType = ValueType::Signed;
    164 break;
    165 case 19:
    -
    166 signal.multiplexing.role = MultiplexRole::Selector;
    -
    167 other.multiplexing.role = MultiplexRole::Selector;
    -
    168 other.startBit = 8U;
    -
    169 frame.signals.push_back(other);
    -
    170 break;
    -
    171 case 20:
    -
    172 case 23:
    -
    173 case 24:
    -
    174 signal.multiplexing.role = MultiplexRole::Selector;
    -
    175 other.multiplexing.role = MultiplexRole::Branch;
    -
    176 other.startBit = kind == 24 ? 0U : 8U;
    -
    177 other.multiplexing.value = kind == 20 ? 256U : 1U;
    -
    178 frame.signals.push_back(other);
    -
    179 if (kind == 23) {
    -
    180 other.name = "Third";
    -
    181 frame.signals.push_back(other);
    -
    182 }
    -
    183 break;
    -
    184 case 21:
    -
    185 frame.signals.push_back(other);
    -
    186 break;
    -
    187 case 22:
    -
    188 other.byteOrder = ByteOrder::Motorola;
    -
    189 other.startBit = 7U;
    -
    190 frame.signals.push_back(other);
    -
    191 break;
    -
    192 case 25:
    -
    193 frame.canId = std::numeric_limits<std::uint32_t>::max();
    -
    194 break;
    -
    195 }
    -
    196 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase(frames));
    -
    197 // Parsed metadata uses bools for byte order and signedness, so invalid enum
    -
    198 // values exist only in direct runtime definitions.
    -
    199 if (kind != 14 && kind != 15)
    -
    200 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DbcDecodeBuilder().Build(ParsedDefinitions(frames)));
    -
    201}
    -
    202
    -
    203void DbcValidationTest::numericParameters_data() {
    -
    204 QTest::addColumn<int>("field");
    -
    205 QTest::addColumn<double>("value");
    -
    206 const double values[] = {std::numeric_limits<double>::quiet_NaN(),
    -
    207 std::numeric_limits<double>::infinity(),
    -
    208 -std::numeric_limits<double>::infinity()};
    -
    209 for (int field = 0; field < 4; ++field) {
    -
    210 for (int index = 0; index < 3; ++index) {
    -
    211 const QByteArray name = QByteArray::number(field) + "-" + QByteArray::number(index);
    -
    212 QTest::newRow(name.constData()) << field << values[index];
    -
    213 }
    -
    214 }
    -
    215}
    -
    216
    -
    217void DbcValidationTest::numericParameters() {
    -
    218 QFETCH(int, field);
    -
    219 QFETCH(double, value);
    -
    220 DecodeFrame frame = ValidFrame();
    -
    221 DecodeSignal &signal = frame.signals[0];
    -
    222 switch (field) {
    -
    223 case 0:
    -
    224 signal.factor = value;
    -
    225 break;
    -
    226 case 1:
    -
    227 signal.offset = value;
    -
    228 break;
    -
    229 case 2:
    -
    230 signal.minimum = value;
    -
    231 break;
    -
    232 case 3:
    -
    233 signal.maximum = value;
    -
    234 break;
    -
    235 }
    -
    236 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase({frame}));
    -
    237 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DbcDecodeBuilder().Build(ParsedDefinitions({frame})));
    -
    238}
    -
    239
    -
    240void DbcValidationTest::validBoundaries() {
    -
    241 for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) {
    -
    242 for (std::uint8_t dlc: {std::uint8_t(8U), std::uint8_t(64U), std::uint8_t(255U)}) {
    -
    243 DecodeFrame standard = ValidFrame();
    -
    244 standard.canId = 0x7FFU;
    -
    245 standard.dlc = dlc;
    -
    246 DecodeSignal &signal = standard.signals[0];
    -
    247 signal.byteOrder = order;
    -
    248 signal.startBit = (std::uint32_t(dlc) - 8U) * 8U + (order == ByteOrder::Intel ? 0U : 7U);
    -
    249 signal.length = 64U;
    -
    250 signal.factor = -2.0;
    -
    251 signal.offset = std::numeric_limits<double>::max();
    -
    252 signal.minimum = -std::numeric_limits<double>::max();
    -
    253 signal.maximum = std::numeric_limits<double>::max();
    -
    254 DecodeFrame extended = standard;
    -
    255 extended.isExtended = true;
    -
    256 DecodeFrame maximum = extended;
    -
    257 maximum.canId = 0x1FFFFFFFU;
    -
    258 const std::vector<DecodeFrame> frames = {standard, extended, maximum};
    -
    259 const DecodeDatabase direct(frames);
    -
    260 const DecodeDatabase built = DbcDecodeBuilder().Build(ParsedDefinitions(frames));
    -
    261 for (const DecodeFrame &frame: frames) {
    -
    262 QVERIFY(direct.FindFrame(frame.GetKey()));
    -
    263 QVERIFY(built.FindSignal(SignalKey(frame.GetKey(), "Value")));
    -
    264 }
    -
    265 }
    -
    266 }
    -
    267 DecodeFrame empty;
    -
    268 empty.canId = 0U;
    -
    269 QVERIFY(DecodeDatabase({empty}).FindFrame(empty.GetKey()));
    -
    270 QVERIFY(DbcDecodeBuilder().Build(DbcDatabase()).GetFrames().empty());
    -
    271}
    -
    272
    -
    273void DbcValidationTest::layoutBoundaries() {
    -
    274 // Compare the shared coordinate calculation with independent DBC bit traversal.
    -
    275 for (const std::uint8_t dlc: {std::uint8_t(0U), std::uint8_t(1U), std::uint8_t(8U),
    -
    276 std::uint8_t(64U), std::uint8_t(255U)}) {
    -
    277 const std::uint64_t payloadBits = std::uint64_t(dlc) * 8U;
    -
    278 for (const bool littleEndian: {true, false}) {
    -
    279 for (std::uint32_t start = 0U; start < payloadBits + 8U; ++start) {
    -
    280 std::uint64_t bit = start;
    -
    281 bool fits = true;
    -
    282 QVERIFY(!IsValidSignalLayout(start, 0U, littleEndian, dlc));
    -
    283 for (std::uint32_t length = 1U; length <= 64U; ++length) {
    -
    284 fits = fits && bit < payloadBits;
    -
    285 QCOMPARE(IsValidSignalLayout(start, length, littleEndian, dlc), fits);
    -
    286 if (littleEndian)
    -
    287 ++bit;
    -
    288 else
    -
    289 bit = bit % 8U == 0U ? bit + 15U : bit - 1U;
    -
    290 }
    -
    291 QVERIFY(!IsValidSignalLayout(start, 65U, littleEndian, dlc));
    -
    292 }
    -
    293 const std::uint32_t maximum = std::numeric_limits<std::uint32_t>::max();
    -
    294 QVERIFY(!IsValidSignalLayout(maximum, 1U, littleEndian, dlc));
    -
    295 QVERIFY(!IsValidSignalLayout(maximum, maximum, littleEndian, dlc));
    -
    296 QVERIFY(!IsValidSignalLayout(0U, maximum, littleEndian, dlc));
    -
    297 }
    -
    298 }
    -
    299}
    -
    300
    -
    301void DbcValidationTest::builderSnapshot() {
    -
    302 DbcDatabase source = ParsedDefinitions({ValidFrame()});
    -
    303 source.frames[0].signals[0].valueDescriptions.emplace(std::uint64_t(1U), "One");
    -
    304 const FrameKey key(source.frames[0].canId, source.frames[0].isExtended);
    -
    305 const DecodeDatabase database = DbcDecodeBuilder().Build(source);
    -
    306 source.frames[0].canId = 0x800U;
    -
    307 source.frames[0].signals[0].name = "Changed";
    -
    308 source.frames[0].signals[0].valueDescriptions.begin()->second = "Changed";
    -
    309 source.frames.clear();
    -
    310 const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(SignalKey(key, "Value"));
    -
    311 QVERIFY(signal);
    -
    312 QCOMPARE(signal->valueDescriptions.begin()->second, std::string("One"));
    -
    313 QVERIFY(database.FindFrame(key));
    -
    314 QVERIFY(!database.FindFrame(FrameKey(0x800U, false)));
    -
    315}
    -
    316
    -
    317void DbcValidationTest::multiplexingBoundaries() {
    -
    318 DecodeFrame frame = ValidFrame();
    -
    319 frame.dlc = 9U;
    -
    320 DecodeSignal &selector = frame.signals[0];
    -
    321 selector.length = 64U;
    -
    322 selector.multiplexing.role = MultiplexRole::Selector;
    -
    323 DecodeSignal first;
    -
    324 first.name = "First";
    -
    325 first.startBit = 64U;
    -
    326 first.length = 8U;
    -
    327 first.multiplexing.role = MultiplexRole::Branch;
    -
    328 first.multiplexing.value = std::numeric_limits<std::uint64_t>::max();
    -
    329 DecodeSignal second = first;
    -
    330 second.name = "Second";
    -
    331 second.byteOrder = ByteOrder::Motorola;
    -
    332 second.startBit = 71U;
    -
    333 second.multiplexing.value = 0U;
    -
    334 frame.signals.push_back(first);
    -
    335 frame.signals.push_back(second);
    -
    336 const DecodeDatabase direct({frame});
    -
    337 const DecodeDatabase built = DbcDecodeBuilder().Build(ParsedDefinitions({frame}));
    -
    338 RawCanFrame raw;
    -
    339 raw.canId = frame.canId;
    -
    340 raw.data.assign(9U, 255U);
    -
    341 for (const DecodeDatabase &database: {direct, built}) {
    -
    342 const DecodedFrameValue result = DbcDecoder().Decode(database, raw);
    -
    343 QCOMPARE(result.signals[1].status, SignalDecodeStatus::Valid);
    -
    344 QCOMPARE(result.signals[2].status, SignalDecodeStatus::Inactive);
    -
    345 }
    -
    346}
    -
    347
    -
    348void DbcValidationTest::independentSnapshot() {
    -
    349 std::vector<DecodeFrame> frames = {ValidFrame()};
    -
    350 DecodeFrame &alias = frames[0];
    -
    351 DecodeSignal &signalAlias = alias.signals[0];
    -
    352 signalAlias.valueDescriptions.emplace(std::uint64_t(1U), "One");
    -
    353 std::string &descriptionAlias = signalAlias.valueDescriptions.begin()->second;
    -
    354 const FrameKey key = alias.GetKey();
    -
    355 const DecodeDatabase database(std::move(frames));
    -
    356 alias.canId = 456U;
    -
    357 signalAlias.name = "Changed";
    -
    358 signalAlias.startBit = std::numeric_limits<std::uint32_t>::max();
    -
    359 descriptionAlias = "Changed";
    -
    360 const std::shared_ptr<const DecodeFrame> saved = database.FindFrame(key);
    -
    361 QVERIFY(saved);
    -
    362 QCOMPARE(saved->canId, key.canId);
    -
    363 QVERIFY(!database.FindFrame(FrameKey(456U, false)));
    -
    364 const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(SignalKey(key, "Value"));
    -
    365 QVERIFY(signal);
    -
    366 QCOMPARE(signal->startBit, 0U);
    -
    367 QCOMPARE(signal->valueDescriptions.begin()->second, std::string("One"));
    -
    368}
    -
    369
    -
    370void DbcValidationTest::failedReplacement() {
    -
    371 const DecodeFrame valid = ValidFrame();
    -
    372 DecodeDatabase database({valid});
    -
    373 const std::shared_ptr<const DecodeFrame> original = database.FindFrame(valid.GetKey());
    -
    374 DecodeFrame invalid = valid;
    -
    375 invalid.canId = 0x800U;
    -
    376 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, database = DecodeDatabase({invalid}));
    -
    377 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    -
    378 invalid = valid;
    -
    379 invalid.signals[0].factor = std::numeric_limits<double>::infinity();
    -
    380 QVERIFY_THROWS_EXCEPTION(std::invalid_argument,
    -
    381 database = DbcDecodeBuilder().Build(ParsedDefinitions({invalid})));
    -
    382 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    -
    383 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, database = DecodeDatabase({valid, valid}));
    -
    384 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    -
    385 invalid = valid;
    -
    386 invalid.signals.push_back(invalid.signals[0]);
    -
    387 QVERIFY_THROWS_EXCEPTION(std::invalid_argument,
    -
    388 database = DbcDecodeBuilder().Build(ParsedDefinitions({invalid})));
    -
    389 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    -
    390 QVERIFY(database.FindSignal(SignalKey(valid.GetKey(), "Value")));
    -
    391 QCOMPARE(database.GetFrames().size(), std::size_t(1U));
    -
    392 database = DecodeDatabase();
    -
    393 QVERIFY(database.GetFrames().empty());
    -
    394 QVERIFY(!database.FindFrame(valid.GetKey()));
    -
    395 QVERIFY(original);
    -
    396}
    -
    397
    -
    398int RunValidationTests(int argc, char **argv) {
    -
    399 DbcValidationTest tests;
    -
    400 return QTest::qExec(&tests, argc, argv);
    -
    401}
    -
    402
    -
    403#include "dbc_validation_test.moc"
    +
    166 signal.multiplexing.role = MultiplexRole::Selector;
    +
    167 other.multiplexing.role = MultiplexRole::Selector;
    +
    168 other.valueType = ValueType::Signed;
    +
    169 other.startBit = 8U;
    +
    170 frame.signals.push_back(other);
    +
    171 break;
    +
    172 case 20:
    +
    173 case 23:
    +
    174 case 24:
    +
    175 signal.multiplexing.role = MultiplexRole::Selector;
    +
    176 other.multiplexing.role = MultiplexRole::Branch;
    +
    177 other.startBit = kind == 24 ? 0U : 8U;
    +
    178 other.multiplexing.value = kind == 20 ? 256U : 1U;
    +
    179 frame.signals.push_back(other);
    +
    180 if (kind == 23) {
    +
    181 other.name = "Third";
    +
    182 frame.signals.push_back(other);
    +
    183 }
    +
    184 break;
    +
    185 case 21:
    +
    186 frame.signals.push_back(other);
    +
    187 break;
    +
    188 case 22:
    +
    189 other.byteOrder = ByteOrder::Motorola;
    +
    190 other.startBit = 7U;
    +
    191 frame.signals.push_back(other);
    +
    192 break;
    +
    193 case 25:
    +
    194 frame.canId = std::numeric_limits<std::uint32_t>::max();
    +
    195 break;
    +
    196 }
    +
    197 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase(frames));
    +
    198 // Parsed metadata uses bools for byte order and signedness, so invalid enum
    +
    199 // values exist only in direct runtime definitions.
    +
    200 if (kind != 14 && kind != 15)
    +
    201 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DbcDecodeBuilder().Build(ParsedDefinitions(frames)));
    +
    202}
    +
    203
    +
    204void DbcValidationTest::numericParameters_data() {
    +
    205 QTest::addColumn<int>("field");
    +
    206 QTest::addColumn<double>("value");
    +
    207 const double values[] = {std::numeric_limits<double>::quiet_NaN(),
    +
    208 std::numeric_limits<double>::infinity(),
    +
    209 -std::numeric_limits<double>::infinity()};
    +
    210 for (int field = 0; field < 4; ++field) {
    +
    211 for (int index = 0; index < 3; ++index) {
    +
    212 const QByteArray name = QByteArray::number(field) + "-" + QByteArray::number(index);
    +
    213 QTest::newRow(name.constData()) << field << values[index];
    +
    214 }
    +
    215 }
    +
    216}
    +
    217
    +
    218void DbcValidationTest::numericParameters() {
    +
    219 QFETCH(int, field);
    +
    220 QFETCH(double, value);
    +
    221 DecodeFrame frame = ValidFrame();
    +
    222 DecodeSignal &signal = frame.signals[0];
    +
    223 switch (field) {
    +
    224 case 0:
    +
    225 signal.factor = value;
    +
    226 break;
    +
    227 case 1:
    +
    228 signal.offset = value;
    +
    229 break;
    +
    230 case 2:
    +
    231 signal.minimum = value;
    +
    232 break;
    +
    233 case 3:
    +
    234 signal.maximum = value;
    +
    235 break;
    +
    236 }
    +
    237 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase({frame}));
    +
    238 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DbcDecodeBuilder().Build(ParsedDefinitions({frame})));
    +
    239}
    +
    240
    +
    241void DbcValidationTest::validBoundaries() {
    +
    242 for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) {
    +
    243 for (std::uint8_t dlc: {std::uint8_t(8U), std::uint8_t(64U), std::uint8_t(255U)}) {
    +
    244 DecodeFrame standard = ValidFrame();
    +
    245 standard.canId = 0x7FFU;
    +
    246 standard.dlc = dlc;
    +
    247 DecodeSignal &signal = standard.signals[0];
    +
    248 signal.byteOrder = order;
    +
    249 signal.startBit = (std::uint32_t(dlc) - 8U) * 8U + (order == ByteOrder::Intel ? 0U : 7U);
    +
    250 signal.length = 64U;
    +
    251 signal.factor = -2.0;
    +
    252 signal.offset = std::numeric_limits<double>::max();
    +
    253 signal.minimum = -std::numeric_limits<double>::max();
    +
    254 signal.maximum = std::numeric_limits<double>::max();
    +
    255 DecodeFrame extended = standard;
    +
    256 extended.isExtended = true;
    +
    257 DecodeFrame maximum = extended;
    +
    258 maximum.canId = 0x1FFFFFFFU;
    +
    259 const std::vector<DecodeFrame> frames = {standard, extended, maximum};
    +
    260 const DecodeDatabase direct(frames);
    +
    261 const DecodeDatabase built = DbcDecodeBuilder().Build(ParsedDefinitions(frames));
    +
    262 for (const DecodeFrame &frame: frames) {
    +
    263 QVERIFY(direct.FindFrame(frame.GetKey()));
    +
    264 QVERIFY(built.FindSignal(SignalKey(frame.GetKey(), "Value")));
    +
    265 }
    +
    266 }
    +
    267 }
    +
    268 DecodeFrame empty;
    +
    269 empty.canId = 0U;
    +
    270 QVERIFY(DecodeDatabase({empty}).FindFrame(empty.GetKey()));
    +
    271 QVERIFY(DbcDecodeBuilder().Build(DbcDatabase()).GetFrames().empty());
    +
    272}
    +
    273
    +
    274void DbcValidationTest::layoutBoundaries() {
    +
    275 // Compare the shared coordinate calculation with independent DBC bit traversal.
    +
    276 for (const std::uint8_t dlc: {std::uint8_t(0U), std::uint8_t(1U), std::uint8_t(8U),
    +
    277 std::uint8_t(64U), std::uint8_t(255U)}) {
    +
    278 const std::uint64_t payloadBits = std::uint64_t(dlc) * 8U;
    +
    279 for (const bool littleEndian: {true, false}) {
    +
    280 for (std::uint32_t start = 0U; start < payloadBits + 8U; ++start) {
    +
    281 std::uint64_t bit = start;
    +
    282 bool fits = true;
    +
    283 QVERIFY(!IsValidSignalLayout(start, 0U, littleEndian, dlc));
    +
    284 for (std::uint32_t length = 1U; length <= 64U; ++length) {
    +
    285 fits = fits && bit < payloadBits;
    +
    286 QCOMPARE(IsValidSignalLayout(start, length, littleEndian, dlc), fits);
    +
    287 if (littleEndian)
    +
    288 ++bit;
    +
    289 else
    +
    290 bit = bit % 8U == 0U ? bit + 15U : bit - 1U;
    +
    291 }
    +
    292 QVERIFY(!IsValidSignalLayout(start, 65U, littleEndian, dlc));
    +
    293 }
    +
    294 const std::uint32_t maximum = std::numeric_limits<std::uint32_t>::max();
    +
    295 QVERIFY(!IsValidSignalLayout(maximum, 1U, littleEndian, dlc));
    +
    296 QVERIFY(!IsValidSignalLayout(maximum, maximum, littleEndian, dlc));
    +
    297 QVERIFY(!IsValidSignalLayout(0U, maximum, littleEndian, dlc));
    +
    298 }
    +
    299 }
    +
    300}
    +
    301
    +
    302void DbcValidationTest::builderSnapshot() {
    +
    303 DbcDatabase source = ParsedDefinitions({ValidFrame()});
    +
    304 source.frames[0].signals[0].valueDescriptions.emplace(std::uint64_t(1U), "One");
    +
    305 const FrameKey key(source.frames[0].canId, source.frames[0].isExtended);
    +
    306 const DecodeDatabase database = DbcDecodeBuilder().Build(source);
    +
    307 source.frames[0].canId = 0x800U;
    +
    308 source.frames[0].signals[0].name = "Changed";
    +
    309 source.frames[0].signals[0].valueDescriptions.begin()->second = "Changed";
    +
    310 source.frames.clear();
    +
    311 const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(SignalKey(key, "Value"));
    +
    312 QVERIFY(signal);
    +
    313 QCOMPARE(signal->valueDescriptions.begin()->second, std::string("One"));
    +
    314 QVERIFY(database.FindFrame(key));
    +
    315 QVERIFY(!database.FindFrame(FrameKey(0x800U, false)));
    +
    316}
    +
    317
    +
    318void DbcValidationTest::multiplexingBoundaries() {
    +
    319 DecodeFrame frame = ValidFrame();
    +
    320 frame.dlc = 9U;
    +
    321 DecodeSignal &selector = frame.signals[0];
    +
    322 selector.length = 64U;
    +
    323 selector.multiplexing.role = MultiplexRole::Selector;
    +
    324 DecodeSignal first;
    +
    325 first.name = "First";
    +
    326 first.startBit = 64U;
    +
    327 first.length = 8U;
    +
    328 first.multiplexing.role = MultiplexRole::Branch;
    +
    329 first.multiplexing.value = std::numeric_limits<std::uint64_t>::max();
    +
    330 DecodeSignal second = first;
    +
    331 second.name = "Second";
    +
    332 second.byteOrder = ByteOrder::Motorola;
    +
    333 second.startBit = 71U;
    +
    334 second.multiplexing.value = 0U;
    +
    335 frame.signals.push_back(first);
    +
    336 frame.signals.push_back(second);
    +
    337 const DecodeDatabase direct({frame});
    +
    338 const DecodeDatabase built = DbcDecodeBuilder().Build(ParsedDefinitions({frame}));
    +
    339 RawCanFrame raw;
    +
    340 raw.canId = frame.canId;
    +
    341 raw.data.assign(9U, 255U);
    +
    342 for (const DecodeDatabase &database: {direct, built}) {
    +
    343 const DecodedFrameValue result = DbcDecoder().Decode(database, raw);
    +
    344 QCOMPARE(result.signals[1].status, SignalDecodeStatus::Valid);
    +
    345 QCOMPARE(result.signals[2].status, SignalDecodeStatus::Inactive);
    +
    346 }
    +
    347}
    +
    348
    +
    349void DbcValidationTest::independentSnapshot() {
    +
    350 std::vector<DecodeFrame> frames = {ValidFrame()};
    +
    351 DecodeFrame &alias = frames[0];
    +
    352 DecodeSignal &signalAlias = alias.signals[0];
    +
    353 signalAlias.valueDescriptions.emplace(std::uint64_t(1U), "One");
    +
    354 std::string &descriptionAlias = signalAlias.valueDescriptions.begin()->second;
    +
    355 const FrameKey key = alias.GetKey();
    +
    356 const DecodeDatabase database(std::move(frames));
    +
    357 alias.canId = 456U;
    +
    358 signalAlias.name = "Changed";
    +
    359 signalAlias.startBit = std::numeric_limits<std::uint32_t>::max();
    +
    360 descriptionAlias = "Changed";
    +
    361 const std::shared_ptr<const DecodeFrame> saved = database.FindFrame(key);
    +
    362 QVERIFY(saved);
    +
    363 QCOMPARE(saved->canId, key.canId);
    +
    364 QVERIFY(!database.FindFrame(FrameKey(456U, false)));
    +
    365 const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(SignalKey(key, "Value"));
    +
    366 QVERIFY(signal);
    +
    367 QCOMPARE(signal->startBit, 0U);
    +
    368 QCOMPARE(signal->valueDescriptions.begin()->second, std::string("One"));
    +
    369}
    +
    370
    +
    371void DbcValidationTest::failedReplacement() {
    +
    372 const DecodeFrame valid = ValidFrame();
    +
    373 DecodeDatabase database({valid});
    +
    374 const std::shared_ptr<const DecodeFrame> original = database.FindFrame(valid.GetKey());
    +
    375 DecodeFrame invalid = valid;
    +
    376 invalid.canId = 0x800U;
    +
    377 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, database = DecodeDatabase({invalid}));
    +
    378 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    +
    379 invalid = valid;
    +
    380 invalid.signals[0].factor = std::numeric_limits<double>::infinity();
    +
    381 QVERIFY_THROWS_EXCEPTION(std::invalid_argument,
    +
    382 database = DbcDecodeBuilder().Build(ParsedDefinitions({invalid})));
    +
    383 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    +
    384 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, database = DecodeDatabase({valid, valid}));
    +
    385 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    +
    386 invalid = valid;
    +
    387 invalid.signals.push_back(invalid.signals[0]);
    +
    388 QVERIFY_THROWS_EXCEPTION(std::invalid_argument,
    +
    389 database = DbcDecodeBuilder().Build(ParsedDefinitions({invalid})));
    +
    390 QCOMPARE(database.FindFrame(valid.GetKey()).get(), original.get());
    +
    391 QVERIFY(database.FindSignal(SignalKey(valid.GetKey(), "Value")));
    +
    392 QCOMPARE(database.GetFrames().size(), std::size_t(1U));
    +
    393 database = DecodeDatabase();
    +
    394 QVERIFY(database.GetFrames().empty());
    +
    395 QVERIFY(!database.FindFrame(valid.GetKey()));
    +
    396 QVERIFY(original);
    +
    397}
    +
    398
    +
    399int RunValidationTests(int argc, char **argv) {
    +
    400 DbcValidationTest tests;
    +
    401 return QTest::qExec(&tests, argc, argv);
    +
    402}
    +
    403
    +
    404#include "dbc_validation_test.moc"
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    Runtime decode database builder.
    CAN frame decoding API and result types.
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    -
    ValueType
    Signal numeric type.
    +
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ValueType
    Signal numeric type.
    Parsed DBC content stored in a simple internal form.
    std::vector< FrameInfo > frames
    -
    Runtime-ready frame definition.
    -
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    - -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    Runtime-ready signal definition.
    - - - -
    std::string name
    -
    ValueDescriptions valueDescriptions
    - -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    Multiplexing multiplexing
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    FrameDecodeStatus status
    Definition dbc_decoder.h:78
    +
    Runtime-ready frame definition.
    +
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    + +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    Runtime-ready signal definition.
    + + + +
    std::string name
    +
    ValueDescriptions valueDescriptions
    + +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    Multiplexing multiplexing
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    FrameDecodeStatus status
    Definition dbc_decoder.h:79
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    std::uint8_t dlc
    Definition frame_info.h:31
    std::uint32_t canId
    Definition frame_info.h:27
    Stable frame identifier: normalized CAN ID and frame type.
    std::uint32_t canId
    -
    MultiplexRole role
    -
    std::uint64_t value
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    +
    std::uint64_t value
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string name
    Definition signal_info.h:27
    diff --git a/docs/html/decode__database_8cpp_source.html b/docs/html/decode__database_8cpp_source.html index ac2a324..15c0bcc 100644 --- a/docs/html/decode__database_8cpp_source.html +++ b/docs/html/decode__database_8cpp_source.html @@ -103,196 +103,191 @@ $(document).ready(function(){initNavTree('decode__database_8cpp_source.html','')
    3
    4#include "decode_database.h"
    5#include "j1939.h"
    -
    6#include "signal_layout.h"
    -
    7#include <bitset>
    -
    8#include <cmath>
    -
    9#include <limits>
    -
    10#include <stdexcept>
    -
    11#include <unordered_set>
    -
    12
    -
    13namespace {
    -
    14 constexpr std::size_t MaximumPayloadBits = std::numeric_limits<std::uint8_t>::max() * 8U;
    -
    15 using SignalBits = std::bitset<MaximumPayloadBits>;
    -
    16
    -
    17 void ValidateSignal(const DecodeSignal &signal, std::uint8_t dlc) {
    -
    18 if (signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola)
    -
    19 throw std::invalid_argument("Invalid signal byte order: " + signal.name);
    -
    20 if (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed)
    -
    21 throw std::invalid_argument("Invalid signal value type: " + signal.name);
    -
    22 if (signal.multiplexing.role != MultiplexRole::Unconditional &&
    -
    23 signal.multiplexing.role != MultiplexRole::Selector &&
    -
    24 signal.multiplexing.role != MultiplexRole::Branch)
    -
    25 throw std::invalid_argument("Invalid multiplexing role: " + signal.name);
    -
    26 if (!IsValidSignalLayout(signal.startBit, signal.length,
    -
    27 signal.byteOrder == ByteOrder::Intel, dlc))
    -
    28 throw std::invalid_argument("Invalid signal length or payload position: " + signal.name);
    -
    29 if (!std::isfinite(signal.factor) || !std::isfinite(signal.offset) ||
    -
    30 !std::isfinite(signal.minimum) || !std::isfinite(signal.maximum) ||
    -
    31 signal.minimum > signal.maximum)
    -
    32 throw std::invalid_argument("Invalid signal numeric parameters: " + signal.name);
    -
    33 }
    -
    34
    -
    35 SignalBits GetSignalBits(const DecodeSignal &signal) {
    -
    36 SignalBits bits;
    -
    37 const bool littleEndian = signal.byteOrder == ByteOrder::Intel;
    -
    38 const std::uint64_t start = SignalStartCoordinate(signal.startBit, littleEndian);
    -
    39 for (std::uint32_t index = 0U; index < signal.length; ++index) {
    -
    40 const std::uint64_t coordinate = start + index;
    -
    41 const std::uint64_t bit = littleEndian ? coordinate
    -
    42 : coordinate / 8U * 8U + 7U - coordinate % 8U;
    -
    43 bits.set(static_cast<std::size_t>(bit));
    -
    44 }
    -
    45 return bits;
    -
    46 }
    -
    47
    -
    48 bool AreMutuallyExclusive(const DecodeSignal &first, const DecodeSignal &second) {
    -
    49 return first.multiplexing.role == MultiplexRole::Branch &&
    -
    50 second.multiplexing.role == MultiplexRole::Branch &&
    -
    51 first.multiplexing.value != second.multiplexing.value;
    -
    52 }
    -
    53
    -
    54 void ValidateFrame(const DecodeFrame &frame) {
    -
    55 const std::uint32_t maximumId = frame.isExtended ? 0x1FFFFFFFU : 0x7FFU;
    -
    56 if (frame.canId > maximumId)
    -
    57 throw std::invalid_argument("Invalid normalized CAN ID: " + std::to_string(frame.canId));
    -
    58
    -
    59 if (frame.hasPgn && (!frame.isExtended || frame.pgn != ExtractJ1939Pgn(frame.canId)))
    -
    60 throw std::invalid_argument("Invalid J1939 PGN metadata: " + frame.name);
    -
    61
    -
    62 std::unordered_set<std::string> names;
    -
    63 const DecodeSignal *selector = nullptr;
    -
    64 for (const DecodeSignal &signal: frame.signals) {
    -
    65 if (!names.insert(signal.name).second)
    -
    66 throw std::invalid_argument("Duplicate runtime signal key: " + signal.name);
    -
    67 ValidateSignal(signal, frame.dlc);
    -
    68 if (signal.multiplexing.role == MultiplexRole::Selector) {
    -
    69 if (selector != nullptr || signal.valueType != ValueType::Unsigned)
    -
    70 throw std::invalid_argument("Multiplexing requires one unsigned selector per frame");
    -
    71 selector = &signal;
    -
    72 }
    -
    73 }
    -
    74
    -
    75 std::vector<SignalBits> layouts;
    -
    76 layouts.reserve(frame.signals.size());
    -
    77 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
    -
    78 const DecodeSignal &signal = frame.signals[index];
    -
    79 if (signal.multiplexing.role == MultiplexRole::Branch &&
    -
    80 (selector == nullptr ||
    -
    81 (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length))))
    -
    82 throw std::invalid_argument("Missing selector or branch value outside selector range: " + signal.name);
    -
    83 const SignalBits bits = GetSignalBits(signal);
    -
    84 for (std::size_t previous = 0U; previous < index; ++previous) {
    -
    85 if (!AreMutuallyExclusive(signal, frame.signals[previous]) && (bits & layouts[previous]).any())
    -
    86 throw std::invalid_argument("Overlapping signals: " + signal.name);
    -
    87 }
    -
    88 layouts.push_back(bits);
    -
    89 }
    -
    90 }
    -
    91}// namespace
    -
    92
    -
    93DecodeDatabase::Storage::Storage(const std::vector<DecodeFrame> &definitions)
    -
    94 : frames(definitions) {
    -
    95 // Validate the complete snapshot before creating its lookup index.
    -
    96 std::unordered_set<FrameKey, FrameKeyHasher> keys;
    -
    97 keys.reserve(frames.size());
    -
    98 for (const DecodeFrame &frame: frames) {
    -
    99 ValidateFrame(frame);
    -
    100 if (!keys.insert(frame.GetKey()).second)
    -
    101 throw std::invalid_argument("Duplicate runtime frame key");
    -
    102 }
    -
    103 frameIndexByKey.reserve(frames.size());
    -
    104 for (std::size_t index = 0U; index < frames.size(); ++index) {
    -
    105 frameIndexByKey.emplace(frames[index].GetKey(), index);
    -
    106 if (frames[index].hasPgn)
    -
    107 frameIndicesByPgn[frames[index].pgn].push_back(index);
    -
    108 }
    -
    109}
    -
    110
    -
    -
    111DecodeDatabase::DecodeDatabase(const std::vector<DecodeFrame> &frames)
    -
    112 : storage(std::make_shared<const Storage>(frames)) {
    -
    113}
    +
    6#include "multiplex_graph.h"
    +
    7#include "signal_layout.h"
    +
    8#include <bitset>
    +
    9#include <cmath>
    +
    10#include <limits>
    +
    11#include <stdexcept>
    +
    12#include <unordered_set>
    +
    13
    +
    14namespace {
    +
    15 constexpr std::size_t MaximumPayloadBits = std::numeric_limits<std::uint8_t>::max() * 8U;
    +
    16 using SignalBits = std::bitset<MaximumPayloadBits>;
    +
    17
    +
    18 void ValidateSignal(const DecodeSignal &signal, std::uint8_t dlc) {
    +
    19 if (signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola)
    +
    20 throw std::invalid_argument("Invalid signal byte order: " + signal.name);
    +
    21 if (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed)
    +
    22 throw std::invalid_argument("Invalid signal value type: " + signal.name);
    +
    23 if (signal.multiplexing.role != MultiplexRole::Unconditional &&
    +
    24 signal.multiplexing.role != MultiplexRole::Selector &&
    +
    25 signal.multiplexing.role != MultiplexRole::Branch &&
    +
    26 signal.multiplexing.role != MultiplexRole::BranchSelector)
    +
    27 throw std::invalid_argument("Invalid multiplexing role: " + signal.name);
    +
    28 if (!IsValidSignalLayout(signal.startBit, signal.length,
    +
    29 signal.byteOrder == ByteOrder::Intel, dlc))
    +
    30 throw std::invalid_argument("Invalid signal length or payload position: " + signal.name);
    +
    31 if (!std::isfinite(signal.factor) || !std::isfinite(signal.offset) ||
    +
    32 !std::isfinite(signal.minimum) || !std::isfinite(signal.maximum) ||
    +
    33 signal.minimum > signal.maximum)
    +
    34 throw std::invalid_argument("Invalid signal numeric parameters: " + signal.name);
    +
    35 }
    +
    36
    +
    37 SignalBits GetSignalBits(const DecodeSignal &signal) {
    +
    38 SignalBits bits;
    +
    39 const bool littleEndian = signal.byteOrder == ByteOrder::Intel;
    +
    40 const std::uint64_t start = SignalStartCoordinate(signal.startBit, littleEndian);
    +
    41 for (std::uint32_t index = 0U; index < signal.length; ++index) {
    +
    42 const std::uint64_t coordinate = start + index;
    +
    43 const std::uint64_t bit = littleEndian ? coordinate
    +
    44 : coordinate / 8U * 8U + 7U - coordinate % 8U;
    +
    45 bits.set(static_cast<std::size_t>(bit));
    +
    46 }
    +
    47 return bits;
    +
    48 }
    +
    49
    +
    50 dbc_detail::MultiplexGraph ValidateFrame(const DecodeFrame &frame) {
    +
    51 const std::uint32_t maximumId = frame.isExtended ? 0x1FFFFFFFU : 0x7FFU;
    +
    52 if (frame.canId > maximumId)
    +
    53 throw std::invalid_argument("Invalid normalized CAN ID: " + std::to_string(frame.canId));
    +
    54
    +
    55 if (frame.hasPgn && (!frame.isExtended || frame.pgn != ExtractJ1939Pgn(frame.canId)))
    +
    56 throw std::invalid_argument("Invalid J1939 PGN metadata: " + frame.name);
    +
    57
    +
    58 std::unordered_set<std::string> names;
    +
    59
    +
    60 for (const DecodeSignal &signal: frame.signals) {
    +
    61 if (!names.insert(signal.name).second)
    +
    62 throw std::invalid_argument("Duplicate runtime signal key: " + signal.name);
    +
    63 ValidateSignal(signal, frame.dlc);
    +
    64 if (IsMultiplexSelector(signal.multiplexing.role) && signal.valueType != ValueType::Unsigned)
    +
    65 throw std::invalid_argument("Multiplex selectors must be unsigned.");
    +
    66 }
    +
    67 const dbc_detail::MultiplexGraph graph(frame.signals);
    +
    68
    +
    69 std::vector<SignalBits> layouts;
    +
    70 layouts.reserve(frame.signals.size());
    +
    71 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
    +
    72 const DecodeSignal &signal = frame.signals[index];
    +
    73 const SignalBits bits = GetSignalBits(signal);
    +
    74 for (std::size_t previous = 0U; previous < index; ++previous) {
    +
    75 if (!graph.AreMutuallyExclusive(index, previous) && (bits & layouts[previous]).any())
    +
    76 throw std::invalid_argument("Overlapping signals: " + signal.name);
    +
    77 }
    +
    78 layouts.push_back(bits);
    +
    79 }
    +
    80 return graph;
    +
    81 }
    +
    82}// namespace
    +
    83
    +
    84DecodeDatabase::Storage::Storage(const std::vector<DecodeFrame> &definitions)
    +
    85 : frames(definitions) {
    +
    86 // Validate the complete snapshot before creating its lookup index.
    +
    87 std::unordered_set<FrameKey, FrameKeyHasher> keys;
    +
    88 keys.reserve(frames.size());
    +
    89 multiplexGraphs.reserve(frames.size());
    +
    90 for (const DecodeFrame &frame: frames) {
    +
    91 multiplexGraphs.push_back(ValidateFrame(frame));
    +
    92 if (!keys.insert(frame.GetKey()).second)
    +
    93 throw std::invalid_argument("Duplicate runtime frame key");
    +
    94 }
    +
    95 frameIndexByKey.reserve(frames.size());
    +
    96 for (std::size_t index = 0U; index < frames.size(); ++index) {
    +
    97 frameIndexByKey.emplace(frames[index].GetKey(), index);
    +
    98 if (frames[index].hasPgn)
    +
    99 frameIndicesByPgn[frames[index].pgn].push_back(index);
    +
    100 }
    +
    101}
    +
    102
    +
    +
    103DecodeDatabase::DecodeDatabase(const std::vector<DecodeFrame> &frames)
    +
    104 : storage(std::make_shared<const Storage>(frames)) {
    +
    105}
    -
    114
    -
    -
    115const std::vector<DecodeFrame> &DecodeDatabase::GetFrames() const {
    -
    116 static const std::vector<DecodeFrame> empty;
    -
    117 return storage ? storage->frames : empty;
    -
    118}
    +
    106
    +
    +
    107const std::vector<DecodeFrame> &DecodeDatabase::GetFrames() const {
    +
    108 static const std::vector<DecodeFrame> empty;
    +
    109 return storage ? storage->frames : empty;
    +
    110}
    -
    119
    -
    -
    120std::shared_ptr<const DecodeFrame> DecodeDatabase::FindFrame(const FrameKey &key) const {
    -
    121 if (!storage)
    -
    122 return nullptr;
    -
    123 const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
    -
    124 storage->frameIndexByKey.find(key);
    -
    125 if (it == storage->frameIndexByKey.end())
    -
    126 return nullptr;
    -
    127 return std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second]);
    -
    128}
    +
    111
    +
    +
    112std::shared_ptr<const DecodeFrame> DecodeDatabase::FindFrame(const FrameKey &key) const {
    +
    113 if (!storage)
    +
    114 return nullptr;
    +
    115 const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
    +
    116 storage->frameIndexByKey.find(key);
    +
    117 if (it == storage->frameIndexByKey.end())
    +
    118 return nullptr;
    +
    119 return std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second]);
    +
    120}
    -
    129
    -
    - -
    131 PgnLookupResult result;
    -
    132 if (!storage)
    -
    133 return result;
    -
    134 const std::unordered_map<std::uint32_t, std::vector<std::size_t>>::const_iterator it =
    -
    135 storage->frameIndicesByPgn.find(pgn);
    -
    136 if (it == storage->frameIndicesByPgn.end())
    -
    137 return result;
    -
    138 if (it->second.size() != 1U) {
    -
    139 result.ambiguous = true;
    -
    140 return result;
    -
    141 }
    -
    142 result.definition = std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second[0]]);
    -
    143 return result;
    -
    144}
    +
    121
    +
    + +
    123 PgnLookupResult result;
    +
    124 if (!storage)
    +
    125 return result;
    +
    126 const std::unordered_map<std::uint32_t, std::vector<std::size_t>>::const_iterator it =
    +
    127 storage->frameIndicesByPgn.find(pgn);
    +
    128 if (it == storage->frameIndicesByPgn.end())
    +
    129 return result;
    +
    130 if (it->second.size() != 1U) {
    +
    131 result.ambiguous = true;
    +
    132 return result;
    +
    133 }
    +
    134 result.definition = std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second[0]]);
    +
    135 return result;
    +
    136}
    -
    145
    -
    -
    146std::shared_ptr<const DecodeSignal> DecodeDatabase::FindSignal(const SignalKey &key) const {
    -
    147 const std::shared_ptr<const DecodeFrame> frame = FindFrame(key.frame);
    -
    148 if (!frame)
    -
    149 return nullptr;
    -
    150 for (const DecodeSignal &signal: frame->signals) {
    -
    151 if (signal.name == key.name)
    -
    152 return std::shared_ptr<const DecodeSignal>(frame, &signal);
    -
    153 }
    -
    154 return nullptr;
    -
    155}
    +
    137
    +
    +
    138std::shared_ptr<const DecodeSignal> DecodeDatabase::FindSignal(const SignalKey &key) const {
    +
    139 const std::shared_ptr<const DecodeFrame> frame = FindFrame(key.frame);
    +
    140 if (!frame)
    +
    141 return nullptr;
    +
    142 for (const DecodeSignal &signal: frame->signals) {
    +
    143 if (signal.name == key.name)
    +
    144 return std::shared_ptr<const DecodeSignal>(frame, &signal);
    +
    145 }
    +
    146 return nullptr;
    +
    147}
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    -
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    +
    148
    +
    149const dbc_detail::MultiplexGraph &DecodeDatabase::GetMultiplexGraph(const FrameKey &key) const {
    +
    150 return storage->multiplexGraphs[storage->frameIndexByKey.at(key)];
    +
    151}
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    +
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    +
    Runtime definitions and immutable indexed database.
    -
    Runtime-ready frame definition.
    -
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    -
    std::uint32_t pgn
    - - -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    std::string name
    -
    Runtime-ready signal definition.
    - - - -
    std::string name
    - -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    Multiplexing multiplexing
    +
    Runtime-ready frame definition.
    +
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    +
    std::uint32_t pgn
    + + +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    std::string name
    +
    Runtime-ready signal definition.
    + + + +
    std::string name
    + +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    Multiplexing multiplexing
    Stable frame identifier: normalized CAN ID and frame type.
    -
    MultiplexRole role
    -
    std::uint64_t value
    - - -
    std::shared_ptr< const DecodeFrame > definition
    + + +
    std::shared_ptr< const DecodeFrame > definition
    FrameKey frame
    std::string name
    diff --git a/docs/html/decode__database_8h.html b/docs/html/decode__database_8h.html index af068db..fa0872f 100644 --- a/docs/html/decode__database_8h.html +++ b/docs/html/decode__database_8h.html @@ -101,6 +101,7 @@ $(document).ready(function(){initNavTree('decode__database_8h.html',''); initRes More...

    #include "attributes.h"
    #include "definition_key.h"
    +#include "multiplex_graph.h"
    #include "multiplexing.h"
    #include "value_descriptions.h"
    #include <cstdint>
    @@ -167,7 +168,7 @@ Enumerations

    Signal byte order used for runtime decoding.

    -

    Definition at line 28 of file decode_database.h.

    +

    Definition at line 29 of file decode_database.h.

    @@ -193,7 +194,7 @@ Enumerations

    Signal numeric type.

    -

    Definition at line 36 of file decode_database.h.

    +

    Definition at line 37 of file decode_database.h.

    diff --git a/docs/html/decode__database_8h_source.html b/docs/html/decode__database_8h_source.html index f549c04..09758cb 100644 --- a/docs/html/decode__database_8h_source.html +++ b/docs/html/decode__database_8h_source.html @@ -104,147 +104,154 @@ $(document).ready(function(){initNavTree('decode__database_8h_source.html','');
    14
    15#include "attributes.h"
    16#include "definition_key.h"
    -
    17#include "multiplexing.h"
    -
    18#include "value_descriptions.h"
    -
    19#include <cstdint>
    -
    20#include <memory>
    -
    21#include <string>
    -
    22#include <unordered_map>
    -
    23#include <vector>
    -
    24
    -
    -
    28enum class ByteOrder {
    -
    29 Intel,
    -
    30 Motorola
    -
    31};
    +
    17#include "multiplex_graph.h"
    +
    18#include "multiplexing.h"
    +
    19#include "value_descriptions.h"
    +
    20#include <cstdint>
    +
    21#include <memory>
    +
    22#include <string>
    +
    23#include <unordered_map>
    +
    24#include <vector>
    +
    25
    +
    +
    29enum class ByteOrder {
    +
    30 Intel,
    +
    31 Motorola
    +
    32};
    -
    32
    -
    -
    36enum class ValueType {
    -
    37 Unsigned,
    -
    38 Signed
    -
    39};
    +
    33
    +
    +
    37enum class ValueType {
    +
    38 Unsigned,
    +
    39 Signed
    +
    40};
    -
    40
    -
    - - -
    46 std::string name;
    -
    47 std::uint32_t startBit = 0U;
    -
    48 std::uint32_t length = 0U;
    -
    49 ByteOrder byteOrder = ByteOrder::Intel;
    -
    50 ValueType valueType = ValueType::Unsigned;
    -
    51 double factor = 1.0;
    -
    52 double offset = 0.0;
    -
    53 double minimum = 0.0;
    -
    54 double maximum = 0.0;
    -
    55 std::string unit;
    -
    56 std::vector<std::string> receivers;
    -
    57 ValueDescriptions valueDescriptions;
    -
    58 std::string comment;
    -
    60 AttributeMap attributes;
    -
    62 DecodeSignal() = default;
    -
    63};
    +
    41
    +
    + + +
    47 std::string name;
    +
    48 std::uint32_t startBit = 0U;
    +
    49 std::uint32_t length = 0U;
    +
    50 ByteOrder byteOrder = ByteOrder::Intel;
    +
    51 ValueType valueType = ValueType::Unsigned;
    +
    52 double factor = 1.0;
    +
    53 double offset = 0.0;
    +
    54 double minimum = 0.0;
    +
    55 double maximum = 0.0;
    +
    56 std::string unit;
    +
    57 std::vector<std::string> receivers;
    +
    58 ValueDescriptions valueDescriptions;
    +
    59 std::string comment;
    +
    61 AttributeMap attributes;
    +
    63 DecodeSignal() = default;
    +
    64};
    -
    64
    -
    - -
    69 std::string name;
    -
    70 std::uint32_t canId = 0U;
    -
    71 bool isExtended = false;
    -
    72 std::uint8_t dlc = 0U;
    -
    73 std::uint32_t pgn = 0U;
    -
    74 bool hasPgn = false;
    -
    75 std::string transmitter;
    -
    76 std::string comment;
    -
    77 std::vector<DecodeSignal> signals;
    -
    79 AttributeMap attributes;
    -
    80 std::optional<std::string> frameFormat;
    -
    81 std::optional<std::uint32_t> cycleTimeMs;
    -
    83 DecodeFrame() = default;
    -
    84
    -
    -
    86 FrameKey GetKey() const {
    -
    87 return FrameKey(canId, isExtended);
    -
    88 }
    +
    65
    +
    + +
    70 std::string name;
    +
    71 std::uint32_t canId = 0U;
    +
    72 bool isExtended = false;
    +
    73 std::uint8_t dlc = 0U;
    +
    74 std::uint32_t pgn = 0U;
    +
    75 bool hasPgn = false;
    +
    76 std::string transmitter;
    +
    77 std::string comment;
    +
    78 std::vector<DecodeSignal> signals;
    +
    80 AttributeMap attributes;
    +
    81 std::optional<std::string> frameFormat;
    +
    82 std::optional<std::uint32_t> cycleTimeMs;
    +
    84 DecodeFrame() = default;
    +
    85
    +
    +
    87 FrameKey GetKey() const {
    +
    88 return FrameKey(canId, isExtended);
    +
    89 }
    -
    89};
    +
    90};
    -
    90
    -
    - -
    93 std::shared_ptr<const DecodeFrame> definition;
    -
    94 bool ambiguous = false;
    -
    95};
    +
    91
    +
    + +
    94 std::shared_ptr<const DecodeFrame> definition;
    +
    95 bool ambiguous = false;
    +
    96};
    -
    96
    -
    - -
    102public:
    -
    103 DecodeDatabase() = default;
    -
    109 explicit DecodeDatabase(const std::vector<DecodeFrame> &frames);
    -
    110
    -
    112 const std::vector<DecodeFrame> &GetFrames() const;
    -
    114 std::shared_ptr<const DecodeFrame> FindFrame(const FrameKey &key) const;
    -
    116 PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const;
    -
    118 std::shared_ptr<const DecodeSignal> FindSignal(const SignalKey &key) const;
    -
    119
    -
    120private:
    -
    121 struct Storage {
    -
    122 std::vector<DecodeFrame> frames;
    -
    123 std::unordered_map<FrameKey, std::size_t, FrameKeyHasher> frameIndexByKey;
    +
    97
    +
    + +
    103public:
    +
    104 DecodeDatabase() = default;
    +
    110 explicit DecodeDatabase(const std::vector<DecodeFrame> &frames);
    +
    111
    +
    113 const std::vector<DecodeFrame> &GetFrames() const;
    +
    115 std::shared_ptr<const DecodeFrame> FindFrame(const FrameKey &key) const;
    +
    117 PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const;
    +
    119 std::shared_ptr<const DecodeSignal> FindSignal(const SignalKey &key) const;
    +
    120
    +
    121private:
    +
    122 friend class DbcDecoder;
    +
    123 const dbc_detail::MultiplexGraph &GetMultiplexGraph(const FrameKey &key) const;
    124
    -
    125 std::unordered_map<std::uint32_t, std::vector<std::size_t>> frameIndicesByPgn;
    -
    126
    -
    127 explicit Storage(const std::vector<DecodeFrame> &definitions);
    -
    128 };
    +
    125 struct Storage {
    +
    126 std::vector<dbc_detail::MultiplexGraph> multiplexGraphs;
    +
    127 std::vector<DecodeFrame> frames;
    +
    128 std::unordered_map<FrameKey, std::size_t, FrameKeyHasher> frameIndexByKey;
    129
    -
    130 std::shared_ptr<const Storage> storage;
    -
    131};
    +
    130 std::unordered_map<std::uint32_t, std::vector<std::size_t>> frameIndicesByPgn;
    +
    131
    +
    132 explicit Storage(const std::vector<DecodeFrame> &definitions);
    +
    133 };
    +
    134
    +
    135 std::shared_ptr<const Storage> storage;
    +
    136};
    -
    132
    -
    133#endif /* DECODE_DATABASE_H */
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    -
    const std::vector< DecodeFrame > & GetFrames() const
    -
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    -
    ByteOrder
    Signal byte order used for runtime decoding.
    -
    ValueType
    Signal numeric type.
    -
    Runtime-ready frame definition.
    -
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    -
    std::uint32_t pgn
    - -
    std::string comment
    - -
    std::optional< std::string > frameFormat
    -
    std::uint8_t dlc
    -
    std::uint32_t canId
    -
    std::optional< std::uint32_t > cycleTimeMs
    -
    std::string name
    -
    AttributeMap attributes
    -
    std::string transmitter
    -
    Runtime-ready signal definition.
    - -
    AttributeMap attributes
    -
    std::string unit
    - - -
    std::string name
    -
    ValueDescriptions valueDescriptions
    - -
    ValueType valueType
    -
    std::uint32_t startBit
    -
    std::vector< std::string > receivers
    -
    ByteOrder byteOrder
    -
    std::uint32_t length
    -
    std::string comment
    -
    Multiplexing multiplexing
    +
    137
    +
    138#endif /* DECODE_DATABASE_H */
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
    +
    const std::vector< DecodeFrame > & GetFrames() const
    +
    PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
    + +
    ByteOrder
    Signal byte order used for runtime decoding.
    +
    ValueType
    Signal numeric type.
    +
    Runtime-ready frame definition.
    +
    FrameKey GetKey() const
    Return the stable normalized frame identifier.
    +
    std::uint32_t pgn
    + +
    std::string comment
    + +
    std::optional< std::string > frameFormat
    +
    std::uint8_t dlc
    +
    std::uint32_t canId
    +
    std::optional< std::uint32_t > cycleTimeMs
    +
    std::string name
    +
    AttributeMap attributes
    +
    std::string transmitter
    +
    Runtime-ready signal definition.
    + +
    AttributeMap attributes
    +
    std::string unit
    + + +
    std::string name
    +
    ValueDescriptions valueDescriptions
    + +
    ValueType valueType
    +
    std::uint32_t startBit
    +
    std::vector< std::string > receivers
    +
    ByteOrder byteOrder
    +
    std::uint32_t length
    +
    std::string comment
    +
    Multiplexing multiplexing
    Stable frame identifier: normalized CAN ID and frame type.
    - - - -
    std::shared_ptr< const DecodeFrame > definition
    +
    Basic markers and optional explicit extended multiplexing condition.
    + + +
    std::shared_ptr< const DecodeFrame > definition
    diff --git a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html index a03594c..44f43c2 100644 --- a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html +++ b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html @@ -145,6 +145,8 @@ Files
    + + diff --git a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js index 5a6d627..1b0cdc0 100644 --- a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js +++ b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js @@ -19,6 +19,7 @@ var dir_4270bfced15e0e73154b13468c7c9ad9 = [ "definition_key.h", "definition__key_8h_source.html", null ], [ "frame_info.h", "frame__info_8h.html", "frame__info_8h" ], [ "j1939.h", "j1939_8h_source.html", null ], + [ "multiplex_graph.h", "multiplex__graph_8h_source.html", null ], [ "multiplexing.h", "multiplexing_8h_source.html", null ], [ "signal_info.h", "signal__info_8h.html", "signal__info_8h" ], [ "signal_layout.h", "signal__layout_8h_source.html", null ], diff --git a/docs/html/examples_2main_8cpp.html b/docs/html/examples_2main_8cpp.html index 5b399b9..b212ae5 100644 --- a/docs/html/examples_2main_8cpp.html +++ b/docs/html/examples_2main_8cpp.html @@ -152,7 +152,7 @@ Functions

    Definition at line 101 of file examples/main.cpp.

    -

    References DbcTreeBuilder::Build(), DbcDecodeBuilder::Build(), RawCanFrame::canId, RawCanFrame::data, DbcDecoder::Decode(), DecodeDatabase::GetFrames(), RawCanFrame::isExtended, main(), and DbcParser::ParseFile().

    +

    References DbcTreeBuilder::Build(), DbcDecodeBuilder::Build(), RawCanFrame::canId, RawCanFrame::data, DbcDecoder::Decode(), DecodeDatabase::GetFrames(), RawCanFrame::isExtended, main(), and DbcParser::ParseFile().

    Referenced by main().

    diff --git a/docs/html/examples_2main_8cpp_source.html b/docs/html/examples_2main_8cpp_source.html index 08cf399..ae64dbc 100644 --- a/docs/html/examples_2main_8cpp_source.html +++ b/docs/html/examples_2main_8cpp_source.html @@ -231,14 +231,14 @@ $(document).ready(function(){initNavTree('examples_2main_8cpp_source.html','');
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    const std::vector< DecodeFrame > & GetFrames() const
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    const std::vector< DecodeFrame > & GetFrames() const
    Tree node for later use in model/view or other hierarchy consumers.
    Definition tree_node.h:37
    const SignalInfo * GetSignal() const
    Get signal payload if node is signal.
    Definition tree_node.cpp:71
    const TreeNode * GetChild(std::size_t index) const
    Get child by index.
    Definition tree_node.cpp:45
    @@ -252,20 +252,20 @@ $(document).ready(function(){initNavTree('examples_2main_8cpp_source.html','');
    Metadata tree builder.
    int main(int argc, char *argv[])
    Parse a DBC file and demonstrate metadata lookup and CAN decoding.
    Parsed DBC content stored in a simple internal form.
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:74
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    std::shared_ptr< const DecodeFrame > definition
    Definition dbc_decoder.h:75
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    Describes one CAN frame from a DBC file.
    Definition frame_info.h:25
    bool isExtended
    Definition frame_info.h:28
    bool hasPgn
    Definition frame_info.h:30
    std::uint8_t dlc
    Definition frame_info.h:31
    std::uint32_t pgn
    Definition frame_info.h:29
    std::uint32_t canId
    Definition frame_info.h:27
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string unit
    Definition signal_info.h:36
    diff --git a/docs/html/files.html b/docs/html/files.html index 5795b0d..146d728 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -115,29 +115,30 @@ $(document).ready(function(){initNavTree('files.html',''); initResizable(); }); - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
     
     j1939.h
     
     multiplex_graph.h
     
     multiplexing.h
     
     signal_info.h
     definition_key.h
     frame_info.hParsed CAN frame metadata
     j1939.h
     multiplexing.h
     signal_info.hParsed CAN signal metadata
     signal_layout.h
     text_utils.h
     tree_node.cppTree node ownership and navigation
     tree_node.hQt-independent metadata tree nodes
     typefactory.h
     value_descriptions.h
     ▼ examples
     main.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
     ▼ qt
     dbc_tree_model.cpp
     dbc_tree_model.h
     ▼ tests
     dbc_coverage_test.cpp
     dbc_decoder_test.cpp
     dbc_lifetime_test.cpp
     dbc_parser_test.cpp
     dbc_pipeline_test.cpp
     dbc_tree_model_test.cpp
     dbc_validation_test.cpp
     main.cpp
     tree_node_test.cpp
     multiplex_graph.h
     multiplexing.h
     signal_info.hParsed CAN signal metadata
     signal_layout.h
     text_utils.h
     tree_node.cppTree node ownership and navigation
     tree_node.hQt-independent metadata tree nodes
     typefactory.h
     value_descriptions.h
     ▼ examples
     main.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
     ▼ qt
     dbc_tree_model.cpp
     dbc_tree_model.h
     ▼ tests
     dbc_coverage_test.cpp
     dbc_decoder_test.cpp
     dbc_lifetime_test.cpp
     dbc_parser_test.cpp
     dbc_pipeline_test.cpp
     dbc_tree_model_test.cpp
     dbc_validation_test.cpp
     main.cpp
     tree_node_test.cpp
    diff --git a/docs/html/functions.html b/docs/html/functions.html index 7485471..83f5e8f 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -181,7 +181,7 @@ $(document).ready(function(){initNavTree('functions.html',''); initResizable();

    - h -


    -

    +

    <tt>DecodedSignalValue</tt>

    Represents one decoded signal result.

    Fields:

    @@ -422,7 +422,7 @@ Decoder Layer
  • status

  • -

    +

    Raw value representation and precision

    DecodedSignalValue::rawValue is a C++17 std::variant<std::int64_t, std::uint64_t>. For a valid signal, signed definitions produce the int64_t alternative and unsigned definitions produce the uint64_t alternative. Raw values remain exact across their full 64-bit ranges. Check valid before using the physical value. Raw data is also available when status == PhysicalConversionFailed; other invalid results have no decoded numeric data.

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

    @@ -434,7 +434,7 @@ Raw value representation and precision

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

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


    -

    +

    <tt>DecodedFrameValue</tt>

    Represents one decoded frame result.

    Fields:

    @@ -464,13 +464,13 @@ Raw value representation and precision

    Short-payload status takes precedence over signal errors; inspect each signal's status for the individual cause. valid retains its existing meaning of a matched definition and does not imply status == FrameDecodeStatus::Valid.

    Payload policy uses dlc 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 dlc are ignored. Signal bit layouts must fit the declared dlc, 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.

    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 PhysicalConversionFailed. The exact raw value and non-finite physicalValue remain available, while signal valid 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.

    -

    +

    Definition ownership and reload

    DecodedFrameValue::definition and DecodedSignalValue::definition are owning std::shared_ptr<const ...> 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.

    Reload by assigning a newly built database. Stored results continue to describe the old DBC, including its units, scaling, comments, and VAL_ 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.

    GetFrames() is a borrowed view. References, iterators, and raw pointers obtained from it or from a handle's .get() 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 GetValueDescription() follows the same rule: keep the signal definition handle alive while using the string.

    Parsed DbcDatabase/FrameInfo/SignalInfo 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.

    -

    +

    Stable frame and signal identifiers

    DecodedFrameValue::key is a FrameKey (normalized canId, isExtended), also available through DecodeFrame::GetKey(). DecodedSignalValue::key is a SignalKey (frame key, exact case-sensitive signal name). Both are value types with equality and hashers (FrameKeyHasher, SignalKeyHasher) for application maps and saved selections. Construct the same keys from parsed metadata when needed; do not use addresses or vector positions as identifiers.

    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 valid/the definition handle to distinguish a matched result; default keys alone do not indicate successful decoding.

    @@ -485,18 +485,18 @@ Stable frame and signal identifiers
    }
    Converts parsed DBC data into runtime decode database.
    DecodeDatabase Build(const DbcDatabase &source) const
    Build runtime decode database.
    -
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:86
    +
    Runtime CAN decoder using prebuilt decode database.
    Definition dbc_decoder.h:87
    DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
    Decode one raw CAN frame.
    -
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    -
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    -
    Fully decoded frame.
    Definition dbc_decoder.h:73
    -
    bool valid
    Definition dbc_decoder.h:77
    -
    One decoded signal value.
    Definition dbc_decoder.h:54
    -
    SignalKey key
    Definition dbc_decoder.h:56
    +
    Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
    +
    std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
    Return an owning signal handle, or an empty handle for a missing key.
    +
    Fully decoded frame.
    Definition dbc_decoder.h:74
    +
    bool valid
    Definition dbc_decoder.h:78
    +
    One decoded signal value.
    Definition dbc_decoder.h:55
    +
    SignalKey key
    Definition dbc_decoder.h:57

    API migration: replace reads of runtime.frames with runtime.GetFrames(). To edit runtime definitions, prepare a vector and construct a new database; frameIndexByKey is now private and built automatically. DbcDecoder::FindFrame and result definition fields now use owning handles instead of raw pointers; definition->name, boolean/null checks, and existing decode calls remain usable. Use .get() only for temporary raw-pointer interoperation with an owner alive.


    -

    +

    <tt>DbcDecoder</tt>

    Main runtime decoder class.

    Responsibilities:

    @@ -513,7 +513,7 @@ Stable frame and signal identifiers
  • Decode(...)

  • -

    +

    Parser Support

    The current parser supports the following DBC elements:

    -

    +

    Structured diagnostics

    ParseFileWithDiagnostics(path) returns DbcParseResult containing database and diagnostics. Each DbcDiagnostic has severity, code, filePath, lineNumber, and message. Paths preserve the caller's supplied spelling. Lines are one-based physical lines, including blank lines; file-level errors use zero.

    const DbcParser parser;
    @@ -537,8 +537,8 @@ Structured diagnostics
    const DecodeDatabase runtime = DbcDecodeBuilder().Build(result.database);
    // Inspect warnings before relying on decoding results.
    }
    -
    Minimal DBC parser.
    Definition dbc_parser.h:41
    -
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    +
    Minimal DBC parser.
    Definition dbc_parser.h:43
    +
    DbcParseResult ParseFileWithDiagnostics(const std::string &filePath) const
    Parse with warnings and a structured first error instead of throwing.
    Diagnostic message and physical source location.
    Parsed database and diagnostics; the database is empty on error.
    bool HasErrors() const
    Return whether any diagnostic has error severity.
    @@ -559,13 +559,13 @@ Structured diagnostics Warning / UnsupportedStatement Unregistered statement skipped; decoding or metadata may be incomplete -Error / UnsupportedStatement Extended multiplexing (SG_MUL_VAL_) rejected +Error / InvalidMultiplexing Invalid SG_MUL_VAL_ syntax, references, ranges, or cycles

    Parsing stops at the first error and returns an empty database, together with any preceding warnings and the error. Deferred comment, VAL_, and multiplexing errors retain their original source lines. Invalid signal markers use InvalidStatement. HasErrors() checks severity; warnings alone do not make a parse fail.

    Unknown statements are reported conservatively, including SIG_VALTYPE_, attribute relation forms (BA_REL_, BA_DEF_REL_), signal types/references, environment variables, named VAL_TABLE_ tables, and vendor extensions. For example, ignoring SIG_VALTYPE_ may decode a floating-point signal as an integer. The parser does not implement the warned features; consumers should review warnings.

    -

    +

    Attributes and frame metadata

    -

    BA_DEF_, BA_DEF_DEF_, and BA_ support database, BO_, SG_, BU_, and EV_ scopes with INT, HEX, FLOAT, STRING, and ENUM definitions. Integer/HEX values use decimal signed 64-bit numbers; floating values are finite and locale independent. ENUM assignments use zero-based indices; defaults accept an index or a quoted label. Strings support escaped quotes and backslashes. Each statement occupies one physical line and ends with ;.

    +

    BA_DEF_, BA_DEF_DEF_, and BA_ support database, BO_, SG_, BU_, and EV_ scopes with INT, HEX, FLOAT, STRING, and ENUM definitions. Integer/HEX values use decimal signed 64-bit numbers; floating values are finite and locale independent. ENUM assignments use zero-based indices; defaults accept an index or a quoted label. Strings support escaped quotes and backslashes. Statements end with ; outside quoted text and may span physical lines, including ENUM lists, defaults, and assignments. Newlines inside quoted strings are preserved; semicolons inside them do not terminate the statement. Attribute errors and format warnings refer to the statement's first physical line.

    BA_DEF_ BO_ "VFrameFormat" ENUM "StandardCAN","ExtendedCAN","StandardCAN_FD";
    BA_DEF_DEF_ "VFrameFormat" "StandardCAN";
    BA_DEF_ BO_ "GenMsgCycleTime" INT 0 10000;
    @@ -577,9 +577,9 @@ Attributes and frame metadata

    Common VERSION, NS_, BS_, and BU_ headers produce no diagnostics. Single-token symbols inside the NS_ 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 (CM_, CM_ BU_, CM_ EV_) are ignored by the comment handler. Frame and signal comments may span physical lines and resolve after definitions are read; other supported statements require one physical line.

    ParseFile(path) remains compatible: it returns the database, discards warnings, and throws std::runtime_error on the first error with the existing path:line: format. Use ParseFileWithDiagnostics to see skipped syntax. Resource failures such as allocation errors may still throw.


    -

    +

    Supported DBC Syntax

    -

    +

    Frame definition

    Example:

    BO_ 256 EngineData: 8 EEC1
    @@ -591,7 +591,7 @@ Frame definition
  • transmitter ECU

  • -

    +

    Frame validation and parse errors

    BO_ 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.

    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 0x7FF are still treated as extended.

    @@ -600,7 +600,7 @@ Frame validation and parse errors
    example.dbc:3: Invalid CAN ID: invalid

    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.


    -

    +

    Signal definition

    Example:

    SG_ EngineSpeed : 0|16@1+ (0.125,0) [0|8000] "rpm" ECU1,ECU2
    @@ -619,24 +619,32 @@ Signal definition
  • receivers

  • -

    +

    Signal validation and parse errors

    SG_ 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 (@0+, @0-, @1+, or @1-). A quoted unit (which may be empty) and a nonempty comma-separated receiver list are required. Unexpected trailing fields are rejected.

    Start bits must be unsigned decimal integers fitting uint32_t; lengths must be within 1..64 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.

    Factor, offset, minimum, and maximum accept signed decimal numbers, fractions, and scientific notation. Conversion is independent of the application's C and C++ locales: the decimal separator is always a dot (.), and comma decimals and digit grouping are rejected. The entire numeric token must be valid; hexadecimal numbers, NaN, infinity, conversion overflow, and conversion underflow (including subnormal values) are rejected. Minimum must not exceed maximum. Zero and negative factors are allowed.

    -

    Basic multiplexing markers M and mN 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.

    +

    Basic and extended multiplexing markers are supported as described below. Overlapping signals are rejected unless their selector conditions prove mutual exclusion. Duplicate frame keys and signal names within a frame are rejected.

    Invalid signal definitions stop parsing with path:line: description, including when the signal exceeds the declared payload length.


    -

    -Basic multiplexing

    +

    +Multiplexing

    BO_ 256 Status: 3 ECU
    SG_ Mode M : 0|8@1+ (1,0) [0|255] "" ECU
    SG_ Temperature m1 : 8|8@1- (1,0) [-128|127] "C" ECU
    SG_ Pressure m2 : 8|8@1+ (2,0) [0|510] "kPa" ECU
    SG_ Counter : 16|8@1+ (1,0) [0|255] "" ECU
    -

    SignalInfo and DecodeSignal contain multiplexing: a MultiplexRole (Unconditional, Selector, or Branch) and an exact uint64_t branch value. Each frame may have one unsigned selector (M); a branch (mN) references that selector implicitly. The selector may appear after its branches. N must contain only decimal digits, fit uint64_t, 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 SG_MUL_VAL_ statements are rejected with the originating path:line. The dispatcher registers the unsupported statement handler through TypeFactory.

    -

    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.

    -

    The shared decoder extracts the selector before processing branches, compares its raw unsigned value, and leaves result order equal to definition order. Factor, offset, and VAL_ descriptions do not influence branch selection. Unconditional signals continue to decode. An unmapped selector value leaves all branches inactive.

    +

    SignalInfo and DecodeSignal contain multiplexing: a MultiplexRole (Unconditional, Selector, Branch, or BranchSelector), an exact uint64_t marker value, and optional parent selector name with inclusive ranges. M declares an unsigned selector; mN declares a branch and mNM declares a branch that is itself a selector. Without explicit ranges, mN/mNM use the unique unconditional M selector and the marker's raw value. If several root selectors exist, branches require explicit references.

    +

    Extended conditions use SG_MUL_VAL_ <message-id> <signal> <selector> <low>-<high>, ...;:

    +
    BO_ 1 Nested: 3 ECU
    +
    SG_ Root M : 0|8@1+ (1,0) [0|255] "" ECU
    +
    SG_ Child m1M : 8|8@1+ (1,0) [0|255] "" ECU
    +
    SG_ Value m0 : 16|8@1+ (1,0) [0|255] "" ECU
    +
    SG_MUL_VAL_ 1 Child Root 1-2, 4-4;
    +
    SG_MUL_VAL_ 1 Value Child 3-5;
    +

    Here Value is active when Root is 1, 2, or 4 and Child is 3 through 5. Explicit ranges override the marker value. Repeated statements for the same signal/selector merge their range alternatives. Each signal has at most one parent selector; conflicting parent references are rejected. Multiple independent root selectors are supported. Statements and selectors may precede or follow their targets. Decimal values retain the full uint64_t range and must fit the parent's bit width. Ranges are stored without expanding individual values. Malformed ranges, unresolved references, signed selectors, ambiguous implicit selectors, and dependency cycles produce InvalidMultiplexing diagnostics. Statement errors retain the SG_MUL_VAL_ source line; graph and overlap errors identify the affected signal declaration.

    +

    Signal bits may overlap only when the complete ancestor conditions prove the signals mutually exclusive: at least one shared selector has disjoint ranges. This includes nested siblings using the same payload bits and independent selectors, whose branches may be active simultaneously. Validation uses Intel or Motorola bit traversal, including mixed byte orders. Metadata survives runtime and tree builders; the optional Qt adapter does not add multiplexing roles yet.

    +

    The decoder checks ancestors from root to leaf using raw unsigned values. An inactive ancestor leaves descendants inactive even if their selector bytes are absent. Missing bytes on an otherwise active selector path produce SelectorUnavailable. Selective decoding reads required ancestors internally; result order remains selection or definition order. Factor, offset, and VAL_ descriptions do not influence branch selection.

    Each result has SignalDecodeStatus status:

    @@ -654,9 +662,9 @@ Basic multiplexing
    PhysicalConversionFailed Raw value is available, but the converted physical value is NaN or infinity
    -

    All statuses except Valid have valid == false and GetValueDescription() returns nullptr. PhysicalConversionFailed preserves extracted raw data and the non-finite conversion result; other invalid statuses have no decoded numeric data. Check status 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.

    +

    All statuses except Valid have valid == false and GetValueDescription() returns nullptr. PhysicalConversionFailed preserves extracted raw data and the non-finite conversion result; other invalid statuses have no decoded numeric data. Check status to distinguish inactive branches from errors. Consumers constructing runtime metadata manually receive the same selector graph and non-overlap validation as parsed files.


    -

    +

    Comments

    Frame comment example:

    CM_ BO_ 256 "Engine data frame";
    @@ -670,7 +678,7 @@ Comments

    Comments accept spaces and tabs between fields, quotes and backslashes escaped with a preceding backslash, and text spanning multiple physical lines. Newlines, blank lines, and indentation inside quoted text are preserved; CRLF becomes LF. Comments may appear before their frame or signal definitions. References use the same decimal CAN ID validation and normalization as BO_, including reserved-bit and overflow checks and distinct standard/extended targets. Repeated comments apply in statement order, so the last comment wins, including empty text.

    Malformed supported comments (including invalid escapes, missing quotes or semicolon, and trailing text) and missing frame/signal references produce an InvalidStatement error at the comment's starting line. Failed parses return an empty database; ParseFile throws with the same source location.


    -

    +

    CAN ID Normalization

    The parser normalizes frame identifiers.

    Common DBC behavior:

    @@ -685,14 +693,14 @@ CAN ID Normalization

    This is important both for correct lookup and for future interoperability with live CAN APIs.


    -

    +

    J1939 Opt-in and PGN Lookup

    Extended CAN identifiers do not imply J1939. The default parser leaves hasPgn false and pgn zero, and decoding uses exact normalized CAN ID and frame type. Enable J1939 interpretation explicitly for a file:

    options.enableJ1939 = true;
    const DbcDatabase parsed = DbcParser(options).ParseFile("vehicle.dbc");
    const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
    -
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    +
    DbcDatabase ParseFile(const std::string &filePath) const
    Parse DBC file.
    Parsed DBC content stored in a simple internal form.
    @@ -707,7 +715,7 @@ J1939 Opt-in and PGN Lookup

    DbcDecoder::FindFrame and both Decode overloads first try the exact ID/type. Only when that fails for a valid normalized extended ID do they try PGN lookup among definitions with hasPgn == true. A unique PGN can therefore match a changed source address or priority, and for PDU1 a changed destination address. A changed PDU2 group extension does not match. Exact matches win even when the PGN is ambiguous, including exact matches to ordinary extended CAN definitions. Multiple PGN candidates are never resolved by order, source, or payload: FindFrame returns null and Decode returns AmbiguousFrame without decoding signals or validating the selection. Missing candidates return UnknownFrame.

    On success, decoded frame/signal keys belong to the matched DBC definition; selected-signal decoding also expects those definition keys. Keep the input RawCanFrame if the received address/ID is needed separately. This feature does not implement transport-protocol reassembly, address claiming, or full J1939 validation.


    -

    +

    Decode Flow

    Typical runtime decode flow:

    RawCanFrame
    @@ -722,7 +730,7 @@ Decode Flow
    ↓
    DecodedFrameValue

    -

    +

    Intel and Motorola Extraction

    The decoder currently has separate extraction paths:

      @@ -733,7 +741,7 @@ Intel and Motorola Extraction

      Intel and Motorola require different bit extraction logic.

      This is one of the main reasons why the runtime decode layer should be explicit and prepared in advance.


      -

      +

      Example Usage

      Include the public headers from the core/ include directory supplied by core/core.pri:

      #include "dbc_parser.h"
      @@ -744,21 +752,21 @@ Example Usage
      CAN frame decoding API and result types.
      DBC file parser and interpretation options.
      Metadata tree builder.
      -

      +

    Parse DBC

    DbcParser parser;
    DbcDatabase database = parser.ParseFile("example.dbc");
    -

    +

    Build UI tree

    DbcTreeBuilder treeBuilder;
    std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
    Builds a simple tree from parsed DBC database.
    std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
    Build tree representation of parsed DBC data.
    -

    +

    Build runtime decode database

    DbcDecodeBuilder decodeBuilder;
    DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
    -

    +

    Decode a raw frame

    RawCanFrame rawFrame;
    rawFrame.canId = 256; // EngineData from the DBC example above
    @@ -767,12 +775,12 @@ Decode a raw frame
    DbcDecoder decoder;
    DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
    -
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:24
    -
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:27
    -
    std::uint32_t canId
    Definition dbc_decoder.h:25
    -
    bool isExtended
    Definition dbc_decoder.h:26
    +
    Raw CAN frame used for runtime or trace decoding.
    Definition dbc_decoder.h:25
    +
    std::vector< std::uint8_t > data
    Definition dbc_decoder.h:28
    +
    std::uint32_t canId
    Definition dbc_decoder.h:26
    +
    bool isExtended
    Definition dbc_decoder.h:27

    -

    +

    Unified Decode Strategy

    A key design goal is that the same decoder should work for both:

    That means this architecture supports:

    -

    +

    live path

    live CAN input
    ↓
    @@ -789,7 +797,7 @@ live path
    DbcDecoder
    ↓
    decoded signal values
    -

    +

    trace path

    trace reader
    ↓
    @@ -800,7 +808,7 @@ trace path
    decoded signal values

    This avoids duplicating decode logic in two separate parts of the application.


    -

    +

    Intended Use in FrameTap

    This module is meant to support at least the following FrameTap workflows:

    That is why DecodeDatabase is a separate layer.


    -

    +

    Statement Handler Factory

    DbcParser owns file reading, trimming, line numbers, and error reporting. Each ParseFile() call creates a fresh DbcParseContext and a DbcStatementDispatcher. The context contains the parsed database and current frame; handlers receive it by reference and retain no parsing state.

    The dispatcher uses TypeFactory<std::string, DbcStatementHandler> to create registered handlers once per parsing session, then reuses them for all matching lines:

    @@ -847,19 +855,19 @@ Statement Handler Factory
  • SG_ → DbcSignalHandler
  • CM_ → DbcCommentHandler
  • VAL_ → DbcValueDescriptionHandler
  • -
  • SG_MUL_VAL_ → DbcUnsupportedMultiplexingHandler
  • +
  • SG_MUL_VAL_ → DbcMultiplexingHandler
  • VERSION, NS_, BS_, BU_ → DbcHeaderHandler (also accepts attached colons)
  • Grammar implementations live in core/dbc_statement_handler.cpp; their interface, context, and dispatcher live in core/dbc_statement_handler.h. core/typefactory.h provides the generic registry and object creation.

    To add a construct, implement a default-constructible handler deriving from DbcStatementHandler with:

    void Handle(const std::string &line, DbcParseContext &context) const override;
    - +

    Register it in the dispatcher constructor:

    RegisterType<MyCustomHandler>("CUSTOM_"); // after implementing MyCustomHandler

    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 BO_TX_BU_ cannot match BO_. Unregistered keywords produce UnsupportedStatement warnings through ParseFileWithDiagnostics. SG_ and CM_ accept spaces and tabs after their keywords.

    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.


    -

    +

    Signal value descriptions (<tt>VAL_</tt>)

    Signal descriptions attach text to exact raw integer values:

    BO_ 256 Status: 8 ECU
    @@ -872,17 +880,17 @@ Signal value descriptions (<tt>VAL_</tt>)
    if (const std::string *description = value.GetValueDescription()) {
    std::cout << *description;
    }
    -
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:63
    +
    const std::string * GetValueDescription() const
    Definition dbc_decoder.h:64

    GetValueDescription() uses the exact raw integer before factor/offset scaling. It returns nullptr for an invalid decode or an unknown value; numeric decoding and physicalValue 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 FindValueDescription(signal.valueDescriptions, rawValue), where rawValue is RawSignalValue (std::variant<std::int64_t, std::uint64_t>). The helper matches nonnegative signed and unsigned values identically and keeps negative values distinct from large unsigned values. Stored keys use negative int64_t and nonnegative uint64_t; when constructing mappings manually, normalize keys with NormalizeValueKey() before insertion.

    Named VAL_TABLE_ tables, environment-variable mappings, multiline statements, are outside this implementation; the optional Qt adapter exposes signal mappings.


    -

    +

    Current Limitations

    This is still a minimal implementation.

    Not supported yet:

    Motorola extraction uses DBC sawtooth numbering: a start bit of 7 traverses 7..0, 15..8, 23..16. Regression tests cover aligned and unaligned signals, byte boundaries, and 64-bit values.


    -

    +

    Recommended Next Steps

    A practical development order would be:

    -

    +

    Stage 1 - already implemented

    -

    +

    Stage 2

    Recommended additions:

    -

    +

    Stage 3

    Recommended additions:

    -

    +

    Stage 4

    Advanced functionality:


    -

    +

    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 core/core_files.pri; no CMake configuration is currently provided.

    Qt-dependent qmake targets share qt/qt_version.pri, which rejects Qt versions other than 6.8.2. The core library remains independent of Qt libraries.

    @@ -959,7 +967,11 @@ Build Integration
    make -j
    make check

    core/core_files.pri lists the library sources and headers. Consumers include core/core.pri for include paths and library linkage; the test source lists live in tests/parser_tests.pri and tests/decoder_tests.pri. When building a consumer separately, pass DBC_CORE_BUILD_DIR=/absolute/path/to/build/core to qmake.

    -

    +

    +Local core regression checks

    +

    Run bash tests/run_core_ci.sh release or bash tests/run_core_ci.sh sanitize to build the core archive with Qt 6.8.2, run all six core QtTest suites (parser, decoder, coverage, lifetime, validation, and pipeline/builder integration), and run both the qmake and standalone Qt-free tree tests. The sanitizer mode uses AddressSanitizer and UndefinedBehaviorSanitizer, with leak detection enabled by default and fatal sanitizer errors.

    +

    See Local regression checks for prerequisites and environment overrides. No automatic CI workflow is configured.

    +

    Build core without Qt libraries

    From the repository root:

    mkdir -p build/core
    @@ -967,7 +979,7 @@ Build core without Qt libraries
    qmake6 ../../core/core.pro
    make -j

    qmake is still the build tool; this target does not link Qt libraries.

    -

    +

    Optional Qt model adapter

    The adapter and its QAbstractItemModelTester 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 offscreen platform when QT_QPA_PLATFORM is unset or empty; no display server is required. An explicit platform setting is preserved.

    @@ -1038,13 +1050,13 @@ Optional Qt model adapter ValueDescriptionsRole Signal QVariantList of QVariantMap entries

    Each value-description entry contains value (qlonglong for negative keys, qulonglong for nonnegative keys) and description (QString). This preserves the full signed/unsigned 64-bit range without converting through double. An unmapped signal returns an empty list. Data comes from SignalInfo::valueDescriptions. Unsupported roles return invalid QVariant.

    -

    +

    Standalone tree tests without Qt

    From the repository root, use only a C++17 compiler:

    c++ -std=c++17 -Icore tests/tree_node_test.cpp core/tree_node.cpp \
    core/dbc_tree_builder.cpp -o /tmp/dbc_tree_node_test
    /tmp/dbc_tree_node_test
    -

    +

    Build and run the demo

    After building core, run these commands from the repository root:

    mkdir -p build/examples
    @@ -1053,23 +1065,23 @@ Build and run the demo
    make -j
    ./dbc_demo /absolute/path/to/example.dbc

    The demo prints the parsed tree and decodes eight zero bytes using the first frame definition. Replace that sample payload in examples/main.cpp to feed live CAN data or trace records.

    -

    +

    Generate API documentation

    With Doxygen installed, run from the repository root:

    doxygen Doxyfile

    Open docs/html/index.html to view the generated reference.


    -

    +

    Regression tests

    See tests/README.md for QtTest build and execution commands. Tests cover frame validation and error locations, Intel and Motorola extraction, signal syntax and payload bounds, VAL_ 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. dbc_pipeline_test.cpp follows temporary DBC fixtures through parsed metadata, runtime frame/signal lookups, decoded raw/physical values and descriptions, and tree nodes. It verifies all supported metadata in both builders, standard and extended frames sharing a numeric ID, empty databases, comments, and replacement with another fixture or an empty database.

    -

    +

    Code review and additional checks

    Attribute numeric parsing shares one locale-independent converter for integer and floating-point values. Default application skips unrelated scopes, CAN ID normalization uses the validated identifier mask, and signal layout validation owns the length checks. Statement handlers continue to use TypeFactory. Core, adapter, example, and test C++ sources use explicit return types and contain no lambdas. Public metadata and parser-state comments use Doxygen descriptions.

    See tests/README.md for attribute boundary regressions, sanitizer commands, and the latest validation results.

    -

    +

    Measuring code coverage

    Coverage instrumentation is separate from the QtTest suite named CoverageTest: that suite runs extra regression checks, but coverage counters require a specially instrumented build. Use a separate build directory for each coverage tool.

    -

    +

    GCC, gcov, and LCOV on Debian/Ubuntu

    Install the build and report tools:

    sudo apt install build-essential qt6-base-dev qt6-base-dev-tools qmake6 lcov
    @@ -1119,7 +1131,7 @@ GCC, gcov, and LCOV on Debian/Ubuntu

    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.

    After adding direct comment-handler and ambiguous VAL_ reference tests, the same configuration measured 98.4% line coverage (728/740) and 71.4% branch coverage (841/1178).

    See GCC instrumentation options and the LCOV project documentation.

    -

    +

    Configure the GCC coverage build in Qt Creator

    1. Open dbc.pro and select a GCC kit with Qt 6.8.2.
    2. @@ -1132,7 +1144,7 @@ Configure the GCC coverage build in Qt Creator
    3. In a terminal in the coverage build directory, compile the standalone test and run the LCOV/report commands above. Set DBC_SOURCE_DIR to the absolute repository path if using a new terminal. make check runs both QtTest executables; the standalone tree executable must be run separately.
    4. View html/index.html in a browser. This workflow produces HTML reports; it does not require a licensed coverage toolchain.
    -

    +

    Configure all build variants in Qt Creator

    The local dbc.pro.user stores machine-specific kit IDs and build/run settings. It is ignored by Git (*.user) and should not be committed or copied between machines. Recreate the configurations below through the UI when setting up a new checkout. The Qt4ProjectManager identifiers inside .user are historical Qt Creator setting names; the project still requires Qt 6.8.2.

    The local configuration set uses these independent build directories:

    diff --git a/docs/html/md_changelog.html b/docs/html/md_changelog.html index 453136e..7a3206a 100644 --- a/docs/html/md_changelog.html +++ b/docs/html/md_changelog.html @@ -97,42 +97,64 @@ $(document).ready(function(){initNavTree('md_changelog.html',''); initResizable(

    Unreleased

    -2026-10-20

    +2026-10-23

    +Added

    + +

    +Testing

    + +

    +Fixed

    + +

    +2026-10-20

    +

    Maintenance

    -

    +

    Added

    -

    +

    Changed

    -

    +

    Added

    -

    +

    Fixed

    -

    +

    2026-10-14

    -

    +

    Fixed

    -

    +

    Changed

    -

    +

    Added

    -

    +

    2026-10-13

    -

    +

    Added

    -

    +

    Changed

    -

    +

    2026-10-11

    -

    +

    Added

    -

    +

    Changed

    -

    +

    2026-10-07

    -

    +

    Added

    -

    +

    Changed

    -

    +

    Fixed

    -

    +

    2026-10-06

    -

    +

    Added

    -

    +

    2026-10-05

    -

    +

    Changed

    -

    +

    Fixed

    -

    +

    Documentation and maintenance

    -

    +

    2026-10-01

    -

    +

    Changed

    -

    +

    Fixed

    -

    +

    v1.0 — 2026-06-14

    Tag v1.0 points to 38ce043 and includes the initial implementation below.

    -

    +

    Documentation

    -

    +

    Initial implementation — 2026-03-13

    -

    +

    Added

    -

    +

    Documentation and maintenance

    -

    For instrumented builds, LCOV HTML reports, and Qt Creator coverage configuration, see Measuring code coverage. For the complete IDE build/run configuration set, see Configure all build variants in Qt Creator. The Coverage configuration uses coverage_report.sh after its instrumented build; the script takes the source and build directories as its two arguments.

    +

    For instrumented builds, LCOV HTML reports, and Qt Creator coverage configuration, see Measuring code coverage. For the complete IDE build/run configuration set, see Configure all build variants in Qt Creator. The Coverage configuration uses coverage_report.sh after its instrumented build; the script takes the source and build directories as its two arguments.

    Open the repository's root dbc.pro in Qt Creator. It contains core (a static C++17 library) and tests (the dbc_tests QtTest executable). Core is built first; tests link its archive rather than compiling its implementation again. Qt Core and Qt Test development packages are required for tests only. The optional model tests also link QtGui, which is provided by Qt base development packages. The adapter library itself still links only QtCore.

    Build from the repository root with the installed Qt 6.8.2:

    mkdir build
    @@ -110,45 +110,56 @@ $(document).ready(function(){initNavTree('md_tests_2README.html',''); initResiza
    make
    make check

    parser_tests.pri and decoder_tests.pri include the original test sources; tests.pro also includes dbc_coverage_test.cpp, dbc_lifetime_test.cpp, dbc_validation_test.cpp, and dbc_pipeline_test.cpp. ../core/core.pri supplies the library include path and linkage.

    -

    +

    +Local regression checks

    +

    run_core_ci.sh builds the core archive, runs all six QtTest suites and the qmake tree target with make check, then compiles and runs the standalone C++17 tree/builder test without Qt. A failed command returns a nonzero status. The sanitize mode applies ASan/UBSan flags to core, tests, and the standalone executable, with leak detection enabled by default and sanitizer errors fatal. The optional adapter is not built. No automatic CI workflow is configured.

    +

    From the repository root, with Qt 6.8.2 available:

    +
    bash tests/run_core_ci.sh release
    +
    bash tests/run_core_ci.sh sanitize
    +

    Build directories default to build-ci/release and build-ci/sanitize; an optional second argument selects another directory. Always use separate build directories for the two modes. QMAKE, CXX, and JOBS override the qmake executable, standalone compiler, and build parallelism (default 4). Generate the locale as described below and set LOCPATH locally to run without locale skips. On hosts where LeakSanitizer cannot work under a tracer, run with ASAN_OPTIONS=detect_leaks=0:halt_on_error=1; this disables local leak checking only. Test output is written to the terminal.

    +

    Validation of this script used clean builds in /tmp/dbc-ci-release and /tmp/dbc-ci-sanitize with Qt 6.8.2 and the generated German locale. Each mode passed 2,397 QtTest checks with no failures or skips, the qmake tree test, and the standalone tree test. The sanitizer run used detect_leaks=0 because an explicit leak-enabled run failed with LeakSanitizer's ptrace restriction. Shell syntax, invalid-mode handling, and nonzero propagation of a failed qmake command were also checked.

    +

    Decoder coverage

    Coverage includes Motorola bit numbering within and across bytes, unaligned signals, signed values, scaling, 64-bit extraction, signed/unsigned boundary values (including INT64_MIN, INT64_MAX, and UINT64_MAX), numeric output, invalid lengths, insufficient payloads, and Intel regression cases. Frame validity means the definition was found; frame status reports unknown frames, short payloads, and signal errors. Tests exercise empty/short/exact/long payloads, ignored trailing bytes, signals outside declared DLC, invalid enum metadata and overflowing start bits rejected at construction, and preservation of successful signals on partial payloads. Physical conversion checks cover NaN/Inf parameters rejected at construction, multiplication/addition overflow, finite limits, signed/unsigned raw retention, and raw selector activation after physical conversion failure.

    -

    +

    Parser coverage

    Structured diagnostic tests cover severity, code, supplied path, and physical line numbers for skipped syntax and immediate/deferred errors; warnings preceding an error are retained, and failed parses return an empty database. Common headers and namespace symbol lists stay quiet. Tests also check file-open errors, fresh parse sessions, and compatibility with the legacy throwing API. The diagnostic audit also covers 13 unsupported-statement variants, all namespace termination forms, CRLF and missing final newlines, relative paths with spaces, first-error stopping, deferred diagnostic ordering, duplicate definitions/values, selector ranges, overlaps, and preservation of supported decoding and metadata. On Linux, reading a directory exercises the distinct FileReadError path.

    -

    Parser tests cover standard and extended CAN IDs, whitespace, payload storage boundaries, missing fields, malformed and overflowing numbers, reserved ID bits, error paths and line numbers, and integration with signals and comments. Comment regressions cover tabs, escaped quotes/backslashes, multiline text with blank lines and indentation, CRLF, missing final newlines, comments preceding frame/signal definitions, last-wins and empty overwrites, normalized ID boundaries, standard/extended separation, malformed syntax/IDs, and missing targets. Errors verify both structured diagnostics and the throwing API at the starting line. Duplicate definitions are rejected at their source lines, including equivalent extended ID encodings and repeated signal names within a frame. Standard and extended frames may share a numeric ID, and separate frames may reuse signal names. Signal tests cover complete syntax and numeric validation, scientific notation, finite physical parameters and ordered ranges, spaces and tabs, receiver lists, unsupported multiplexing, and Intel/Motorola declared-payload boundaries. Physical-number tests apply a custom comma-decimal C++ locale and an available named comma-decimal C numeric locale. They check all four physical fields, leading signs, fractions, scientific notation, finite boundaries, zero, malformed numbers, comma/grouped numbers, overflow/underflow, and reversed ranges. Locale changes are restored after each test. The named C locale case skips if none of the supported locale names are installed; the custom C++ locale case always runs. On Linux with locale sources and localedef, run both cases without installing a system locale:

    +

    Parser tests cover standard and extended CAN IDs, whitespace, payload storage boundaries, missing fields, malformed and overflowing numbers, reserved ID bits, error paths and line numbers, and integration with signals and comments. Comment regressions cover tabs, escaped quotes/backslashes, multiline text with blank lines and indentation, CRLF, missing final newlines, comments preceding frame/signal definitions, last-wins and empty overwrites, normalized ID boundaries, standard/extended separation, malformed syntax/IDs, and missing targets. Errors verify both structured diagnostics and the throwing API at the starting line. Duplicate definitions are rejected at their source lines, including equivalent extended ID encodings and repeated signal names within a frame. Standard and extended frames may share a numeric ID, and separate frames may reuse signal names. Signal tests cover complete syntax and numeric validation, scientific notation, finite physical parameters and ordered ranges, spaces and tabs, receiver lists, invalid multiplexing, and Intel/Motorola declared-payload boundaries. Physical-number tests apply a custom comma-decimal C++ locale and an available named comma-decimal C numeric locale. They check all four physical fields, leading signs, fractions, scientific notation, finite boundaries, zero, malformed numbers, comma/grouped numbers, overflow/underflow, and reversed ranges. Locale changes are restored after each test. The named C locale case skips if none of the supported locale names are installed; the custom C++ locale case always runs. On Linux with locale sources and localedef, run both cases without installing a system locale:

    mkdir -p /tmp/dbc-test-locales
    localedef --no-archive -i de_DE -f UTF-8 /tmp/dbc-test-locales/de_DE.UTF-8
    LOCPATH=/tmp/dbc-test-locales make check

    Run make check from the build directory as usual. Value-description tests cover full VAL_ syntax, whitespace, escaped quotes, empty text, exact integer boundaries, duplicate keys within and across statements, deferred and normalized frame references, missing targets, error locations, raw lookup with scaling, unknown/invalid values, and both database builders. Temporary DBC fixtures are created in the system temporary directory and removed automatically.

    Dispatch tests also verify exact keyword matching, handler construction and reuse, unknown statements, and independent parsing sessions, including recovery after errors.

    -

    +

    Tree and optional model tests

    tree_node_test.cpp is a standalone C++17 executable without Qt; see the root README for its compiler command. It is also built as dbc_tree_tests and run by qmake's make check, without Qt linkage. It checks empty trees, parent/child round trips, sibling positions, const/mutable bounds, null children, vector growth, and unique_ptr transfer. Compile-time checks reject node copying and movement. Self/ancestor insertion must throw without consuming ownership or changing links. Key tests cover frame/signal identity, standard/extended separation, repeated signal names across frames, missing keys, source replacement, and row-independent identity.

    Enable CONFIG+=dbc_qt in the root qmake invocation to build dbc_qt and dbc_model_tests alongside existing tests. Qt 6.8.2 is required. make check runs all suites. Model tests parse a temporary DBC fixture and use QAbstractItemModelTester, verify navigation across columns, invalid/foreign indexes, metadata and exact VAL_ integers, and persistent-index invalidation when reloading or clearing the tree. Their QGuiApplication registers graphical metatypes used by QAbstractItemModelTester, avoiding the invalid QPixmap type warning in Qt 6.8.2. The test executable defaults to QT_QPA_PLATFORM=offscreen when the variable is unset or empty, so no display server is needed. An explicit platform setting is preserved.

    -

    Basic multiplexing coverage includes selector declarations after branches, Intel/Motorola branch overlap, signed active values and VAL_ lookup, unconditional signals, inactive branches, missing selector/branch payloads, exact UINT64_MAX selector matching, malformed runtime selectors, source locations, and rejection of invalid markers, selector references/ranges, overlaps, and SG_MUL_VAL_.

    -

    +

    Basic multiplexing coverage includes selector declarations after branches, Intel/Motorola branch overlap, signed active values and VAL_ lookup, unconditional signals, inactive branches, missing selector/branch payloads, exact UINT64_MAX selector matching, malformed runtime selectors, source locations, and rejection of invalid markers, selector references/ranges, and overlaps.

    +

    Extended and nested multiplexing coverage includes deferred SG_MUL_VAL_ references, inclusive and separated ranges, repeated range statements, explicit range precedence over markers, mNM fallback, independent selectors, nested siblings sharing Intel/Motorola payload bits, raw selection with scaling, and 64-bit boundaries. Tests verify metadata through tree/runtime builders, selective decoding with ancestor dependencies, inactive paths with missing bytes, missing selectors versus leaf payload, malformed ranges, unknown targets, cycles, conflicting parents, and invalid manually constructed runtime graphs. The extended multiplexing change was verified with the root qmake build, make -j4, make check (2,398 passed, no failures, one existing named C-locale check skipped because the locale is unavailable), and the standalone tree test.

    +

    Additional regression coverage

    dbc_coverage_test.cpp runs as part of dbc_tests. It covers signed boundaries below 64 bits, deterministic extraction comparisons for both byte orders across lengths 1–64, frame lookup failures, exact decode statuses, construction rejection of malformed runtime multiplexing, PGN boundaries, comment handling, file formatting, metadata copying and source lifetime, physical conversion, and TypeFactory registration/creation. Direct resolver tests construct ambiguous databases through the public metadata API, verify source locations, and check that ambiguous targets receive no values.

    J1939 regressions in dbc_coverage_test.cpp verify explicit parser opt-in and ordinary extended CAN defaults, PF 239/240 and all data-page combinations, PGN zero, PDU1 destination exclusion, PDU2 group-extension matching, changed source and priority, standard/invalid-ID exclusion, and inconsistent manual metadata. They also cover exact-ID precedence, order-independent ambiguous PGNs for both PDU formats, mixed ordinary/J1939 definitions, selected-signal definition keys, raw/physical values, and owning PGN handles across snapshot replacement. The pipeline fixture explicitly enables J1939 through the diagnostic parser API. Verified in build/ with qmake6 ../dbc.pro, make -j4, and make check: all six QtTest suites and the Qt-free tree target passed. The existing named comma-decimal C locale regression skipped because that locale is not installed.

    All QtTest targets use Qt 6.8.2 and QVERIFY_THROWS_EXCEPTION. Exception tests explicitly discard nodiscard results when only the exception is being checked. The standalone tree test requires only a C++17 compiler.

    -

    +

    Definition lifetime and reload coverage

    dbc_lifetime_test.cpp checks retained definitions and value-description strings across reload, clear, and destruction; independently saved signal results; copied/moved results and database copies; owning lookup handles; and release of the old snapshot after its final owner is removed. Compile-time checks enforce const access to runtime metadata. Reload fixtures change ordering, frame names, scaling, units, and descriptions, remove definitions, and rename signals.

    Key tests check equality and hashing, standard/extended separation, the same signal name in different frames, and missing lookups. Constructor tests reject duplicate runtime keys, including manually supplied parsed metadata. Failed reload leaves the active database intact; empty reload clears it. Invalid/unknown results and insufficient payloads retain their documented ownership and status behavior. Inactive branches and unavailable selectors also retain definitions across reload.

    -

    +

    Database validation coverage

    dbc_validation_test.cpp checks direct construction and manually assembled DbcDatabase input to DbcDecodeBuilder: standard/extended CAN ID limits, encoded/reserved ID bits, duplicate keys, lengths 0/1–64/65/UINT32_MAX, Intel/Motorola payload boundaries and overflowing start bits, invalid enums, NaN and both infinities in every numeric parameter, and reversed physical ranges. Selector tests include missing, duplicate, and signed selectors, branch ranges, UINT64_MAX selection, mixed-order overlaps, and exclusive branches sharing bits. Valid definitions cover the full byte-count storage range, including zero-byte frames without signals and 255-byte frames. Existing extraction tests cover lengths 1–64. Snapshot tests mutate retained frame, signal, and description aliases after rvalue construction, and verify unchanged lookups and metadata. Failed constructor/builder replacement preserves the active snapshot; clear removes its index while saved handles remain alive.

    Layout validation is also compared with independent DBC bit traversal for every start position through one byte beyond payload sizes 0, 1, 8, 64, and 255, and all lengths 1–64, for both byte orders. Zero/65-bit lengths and uint32 maximum inputs are rejected. Builder snapshots survive input mutation and destruction; failed replacement with duplicate frame or signal keys preserves the existing frame and signal lookups.

    -

    +

    End-to-end pipeline coverage

    -

    dbc_pipeline_test.cpp parses temporary DBC files and checks independent expected metadata against the parser, runtime builder, and tree builder. It exercises standard and extended frames with the same numeric ID and signal name, Intel and signed Motorola decoding, scaling, raw value descriptions, basic multiplexing, PGN metadata, receivers, units, ranges, and frame/signal comments. Tree checks include node types, payloads, parents, rows, names, and child counts.

    +

    dbc_pipeline_test.cpp parses temporary DBC files and checks independent expected metadata against the parser, runtime builder, and tree builder. It exercises standard and extended frames with the same numeric ID and signal name, Intel and signed Motorola decoding, scaling, raw value descriptions, basic and extended multiplexing, PGN metadata, receivers, units, ranges, and frame/signal comments. Tree checks include node types, payloads, parents, rows, names, and child counts.

    Empty and headers-only fixtures produce an empty runtime database and a valid empty tree root. Replacement fixtures change definitions, metadata and decoded values, remove old lookup keys, and then clear both outputs through an empty fixture. Saved decoded results and trees retain their original metadata.

    -

    +

    Attribute coverage

    +

    multilineAttributes checks multiline definitions, defaults and assignments, deferred cycle times, frame format overrides, quoted newlines/semicolons and escapes, CRLF input, and warning locations for defaults and explicit values. invalidMultilineAttributes checks malformed ENUM lists/ranges, missing terminators, unterminated strings, undefined names, trailing fields, and error locations at the first physical line through both parser APIs.

    +

    The multiline changes passed a clean qmake build and make check in /tmp/dbc-attributes-build with Qt 6.8.2: 2,396 QtTest cases and the qmake tree target passed. The standalone C++17 tree test also passed. One existing C locale test skipped because no named comma-decimal locale is installed.

    Parser slots attributes, invalidAttributes, and attributeWarnings cover all five scopes and types, deferred definitions/defaults/targets, explicit values overriding defaults, repeated assignments, escaped strings, typed range/scope errors, duplicate definitions/defaults, unknown attributes and missing targets. They check source diagnostics and the throwing API, distinct standard/extended targets, frame cycle times and enum labels, unsupported formats and ID conflicts, unchanged J1939 opt-in, and runtime/tree propagation. Existing unsupported-statement checks now use relation forms, which remain unsupported, instead of supported attribute forms.

    Attribute changes were verified with qmake6 ../dbc.pro, make -j4, and make check in build/: all six QtTest suites and the qmake tree target passed. The standalone C++17 tree test also passed. The existing named comma-decimal C locale test skipped because the locale is not installed.

    -

    +

    Extended validation

    attributeNumbers checks signed 64-bit limits, leading plus signs, decimal HEX values, FLOAT fractions/exponents, and default overrides under a comma-decimal C++ locale. Node/environment defaults remain on definitions without becoming database attributes. invalidAttributeNumbers supplies 39 data rows, each checked in both definition bounds, a default, and an explicit assignment. The throwing and diagnostic APIs must reject malformed signs, trailing text, hexadecimal notation, non-finite values, overflow, and underflow with the correct error line. Additional malformed-attribute cases cover token separators, scope/type names, reversed FLOAT bounds, value types/ranges, and invalid CAN references.

    Run AddressSanitizer and UndefinedBehaviorSanitizer in a separate directory:

    diff --git a/docs/html/multiplex__graph_8h_source.html b/docs/html/multiplex__graph_8h_source.html new file mode 100644 index 0000000..b1179d8 --- /dev/null +++ b/docs/html/multiplex__graph_8h_source.html @@ -0,0 +1,221 @@ + + + + + + + +DBC Framework: multiplex_graph.h Source File + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    multiplex_graph.h
    +
    +
    +
    1// SPDX-License-Identifier: MIT
    +
    2#ifndef MULTIPLEX_GRAPH_H
    +
    3#define MULTIPLEX_GRAPH_H
    +
    4
    +
    5#include "multiplexing.h"
    +
    6#include <cstddef>
    +
    7#include <stdexcept>
    +
    8
    +
    9namespace dbc_detail {
    +
    +
    11 class MultiplexError : public std::invalid_argument {
    +
    12 public:
    +
    13 MultiplexError(std::size_t signalIndex, const std::string &message)
    +
    14 : std::invalid_argument(message), index(signalIndex) {}
    +
    15 std::size_t index;
    +
    16 };
    +
    +
    17
    +
    + +
    20 public:
    +
    21 template<class Signal>
    +
    22 explicit MultiplexGraph(const std::vector<Signal> &signals)
    +
    23 : parents(signals.size(), signals.size()), ranges(signals.size()) {
    +
    24 const std::size_t count = signals.size();
    +
    25 for (std::size_t index = 0U; index < count; ++index) {
    +
    26 const Multiplexing &mux = signals[index].multiplexing;
    +
    27 if (mux.role != MultiplexRole::Unconditional && mux.role != MultiplexRole::Selector &&
    +
    28 mux.role != MultiplexRole::Branch && mux.role != MultiplexRole::BranchSelector)
    +
    29 throw MultiplexError(index, "Invalid multiplexing role.");
    +
    30 if (mux.selector.empty() != mux.ranges.empty())
    +
    31 throw MultiplexError(index, "Selector name and ranges must be supplied together.");
    +
    32 if (mux.selector.empty() && !IsMultiplexBranch(mux.role))
    +
    33 continue;
    +
    34 std::size_t parent = count;
    +
    35 for (std::size_t candidate = 0U; candidate < count; ++candidate) {
    +
    36 const Multiplexing &other = signals[candidate].multiplexing;
    +
    37 const bool matches = !mux.selector.empty()
    +
    38 ? signals[candidate].name == mux.selector
    +
    39 : other.role == MultiplexRole::Selector && other.selector.empty();
    +
    40 if (!matches)
    +
    41 continue;
    +
    42 if (parent != count)
    +
    43 throw MultiplexError(index, "Ambiguous multiplex selector; use SG_MUL_VAL_.");
    +
    44 parent = candidate;
    +
    45 }
    +
    46 if (parent == count)
    +
    47 throw MultiplexError(index, "Multiplexed branch has no selector.");
    +
    48 if (!IsMultiplexSelector(signals[parent].multiplexing.role))
    +
    49 throw MultiplexError(index, "Referenced signal is not a multiplex selector.");
    +
    50 parents[index] = parent;
    +
    51 ranges[index] = mux.selector.empty() ? std::vector<MultiplexRange>{{mux.value, mux.value}} : mux.ranges;
    +
    52 for (const MultiplexRange &range: ranges[index]) {
    +
    53 if (range.minimum > range.maximum)
    +
    54 throw MultiplexError(index, "Reversed multiplex range.");
    +
    55 if (signals[parent].length < 64U && range.maximum >= (std::uint64_t(1U) << signals[parent].length))
    +
    56 throw MultiplexError(index, "Branch value exceeds selector raw range.");
    +
    57 }
    +
    58 }
    +
    59 for (std::size_t index = 0U; index < count; ++index) {
    +
    60 std::size_t current = index;
    +
    61 for (std::size_t depth = 0U; current != count; ++depth) {
    +
    62 if (depth >= count)
    +
    63 throw MultiplexError(index, "Cyclic multiplex selector dependency.");
    +
    64 current = parents[current];
    +
    65 }
    +
    66 }
    +
    67 }
    +
    68
    +
    69 bool Matches(std::size_t index, std::uint64_t value) const {
    +
    70 for (const MultiplexRange &range: ranges[index]) {
    +
    71 if (range.minimum <= value && value <= range.maximum)
    +
    72 return true;
    +
    73 }
    +
    74 return false;
    +
    75 }
    +
    76
    +
    77 bool AreMutuallyExclusive(std::size_t first, std::size_t second) const {
    +
    78 const std::size_t count = parents.size();
    +
    79 for (std::size_t left = first; parents[left] != count; left = parents[left]) {
    +
    80 for (std::size_t right = second; parents[right] != count; right = parents[right]) {
    +
    81 if (parents[left] != parents[right])
    +
    82 continue;
    +
    83 bool intersects = false;
    +
    84 for (const MultiplexRange &a: ranges[left]) {
    +
    85 for (const MultiplexRange &b: ranges[right]) {
    +
    86 if (a.minimum <= b.maximum && b.minimum <= a.maximum)
    +
    87 intersects = true;
    +
    88 }
    +
    89 }
    +
    90 if (!intersects)
    +
    91 return true;
    +
    92 }
    +
    93 }
    +
    94 return false;
    +
    95 }
    +
    96
    +
    97 std::vector<std::size_t> parents;
    +
    98 std::vector<std::vector<MultiplexRange>> ranges;
    +
    99 };
    +
    +
    100}// namespace dbc_detail
    +
    101#endif
    + + +
    Inclusive raw selector range, without expanding individual values.
    +
    Basic markers and optional explicit extended multiplexing condition.
    +
    std::uint64_t value
    +
    std::vector< MultiplexRange > ranges
    +
    std::string selector
    +
    +
    + + + + diff --git a/docs/html/multiplexing_8h_source.html b/docs/html/multiplexing_8h_source.html index 042bc17..406736b 100644 --- a/docs/html/multiplexing_8h_source.html +++ b/docs/html/multiplexing_8h_source.html @@ -103,24 +103,46 @@ $(document).ready(function(){initNavTree('multiplexing_8h_source.html',''); init
    3#define MULTIPLEXING_H
    4
    5#include <cstdint>
    -
    6
    -
    8enum class MultiplexRole {
    -
    9 Unconditional,
    -
    10 Selector,
    -
    11 Branch
    -
    12};
    -
    13
    -
    - -
    16 MultiplexRole role = MultiplexRole::Unconditional;
    -
    17 std::uint64_t value = 0U;
    -
    18};
    +
    6#include <string>
    +
    7#include <vector>
    +
    8
    +
    10enum class MultiplexRole {
    +
    11 Unconditional,
    +
    12 Selector,
    +
    13 Branch,
    +
    14 BranchSelector
    +
    15};
    +
    16
    +
    + +
    19 std::uint64_t minimum = 0U;
    +
    20 std::uint64_t maximum = 0U;
    +
    21};
    -
    19
    -
    20#endif
    - -
    MultiplexRole role
    -
    std::uint64_t value
    +
    22
    +
    + +
    25 MultiplexRole role = MultiplexRole::Unconditional;
    +
    26 std::uint64_t value = 0U;
    +
    27 std::string selector;
    +
    28 std::vector<MultiplexRange> ranges;
    +
    29};
    +
    +
    30
    +
    31inline bool IsMultiplexSelector(MultiplexRole role) {
    +
    32 return role == MultiplexRole::Selector || role == MultiplexRole::BranchSelector;
    +
    33}
    +
    34
    +
    35inline bool IsMultiplexBranch(MultiplexRole role) {
    +
    36 return role == MultiplexRole::Branch || role == MultiplexRole::BranchSelector;
    +
    37}
    +
    38
    +
    39#endif
    +
    Inclusive raw selector range, without expanding individual values.
    +
    Basic markers and optional explicit extended multiplexing condition.
    +
    std::uint64_t value
    +
    std::vector< MultiplexRange > ranges
    +
    std::string selector
    diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 95c5774..584e63e 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -34,147 +34,154 @@ var NAVTREE = ] ], [ "Changelog", "md_changelog.html", [ [ "Unreleased", "md_changelog.html#autotoc_md7", [ - [ "2026-10-20", "md_changelog.html#autotoc_md8", [ - [ "Maintenance", "md_changelog.html#autotoc_md9", null ], - [ "Added", "md_changelog.html#autotoc_md10", null ], - [ "Changed", "md_changelog.html#autotoc_md11", null ], - [ "Added", "md_changelog.html#autotoc_md12", null ], - [ "Fixed", "md_changelog.html#autotoc_md13", null ] + [ "2026-10-23", "md_changelog.html#autotoc_md8", [ + [ "Added", "md_changelog.html#autotoc_md9", null ], + [ "Testing", "md_changelog.html#autotoc_md10", null ], + [ "Fixed", "md_changelog.html#autotoc_md11", null ] ] ], - [ "2026-10-14", "md_changelog.html#autotoc_md14", [ - [ "Fixed", "md_changelog.html#autotoc_md15", null ], - [ "Changed", "md_changelog.html#autotoc_md16", null ], - [ "Added", "md_changelog.html#autotoc_md17", null ] + [ "2026-10-20", "md_changelog.html#autotoc_md12", [ + [ "Maintenance", "md_changelog.html#autotoc_md13", null ], + [ "Added", "md_changelog.html#autotoc_md14", null ], + [ "Changed", "md_changelog.html#autotoc_md15", null ], + [ "Added", "md_changelog.html#autotoc_md16", null ], + [ "Fixed", "md_changelog.html#autotoc_md17", null ] ] ], - [ "2026-10-13", "md_changelog.html#autotoc_md18", [ - [ "Added", "md_changelog.html#autotoc_md19", null ], - [ "Changed", "md_changelog.html#autotoc_md20", null ] + [ "2026-10-14", "md_changelog.html#autotoc_md18", [ + [ "Fixed", "md_changelog.html#autotoc_md19", null ], + [ "Changed", "md_changelog.html#autotoc_md20", null ], + [ "Added", "md_changelog.html#autotoc_md21", null ] ] ], - [ "2026-10-11", "md_changelog.html#autotoc_md21", [ - [ "Added", "md_changelog.html#autotoc_md22", null ], - [ "Changed", "md_changelog.html#autotoc_md23", null ] + [ "2026-10-13", "md_changelog.html#autotoc_md22", [ + [ "Added", "md_changelog.html#autotoc_md23", null ], + [ "Changed", "md_changelog.html#autotoc_md24", null ] ] ], - [ "2026-10-07", "md_changelog.html#autotoc_md24", [ - [ "Added", "md_changelog.html#autotoc_md25", null ], - [ "Changed", "md_changelog.html#autotoc_md26", null ], - [ "Fixed", "md_changelog.html#autotoc_md27", null ] + [ "2026-10-11", "md_changelog.html#autotoc_md25", [ + [ "Added", "md_changelog.html#autotoc_md26", null ], + [ "Changed", "md_changelog.html#autotoc_md27", null ] ] ], - [ "2026-10-06", "md_changelog.html#autotoc_md28", [ - [ "Added", "md_changelog.html#autotoc_md29", null ] + [ "2026-10-07", "md_changelog.html#autotoc_md28", [ + [ "Added", "md_changelog.html#autotoc_md29", null ], + [ "Changed", "md_changelog.html#autotoc_md30", null ], + [ "Fixed", "md_changelog.html#autotoc_md31", null ] ] ], - [ "2026-10-05", "md_changelog.html#autotoc_md30", [ - [ "Changed", "md_changelog.html#autotoc_md31", null ], - [ "Fixed", "md_changelog.html#autotoc_md32", null ], - [ "Documentation and maintenance", "md_changelog.html#autotoc_md33", null ] + [ "2026-10-06", "md_changelog.html#autotoc_md32", [ + [ "Added", "md_changelog.html#autotoc_md33", null ] ] ], - [ "2026-10-01", "md_changelog.html#autotoc_md34", [ + [ "2026-10-05", "md_changelog.html#autotoc_md34", [ [ "Changed", "md_changelog.html#autotoc_md35", null ], - [ "Fixed", "md_changelog.html#autotoc_md36", null ] + [ "Fixed", "md_changelog.html#autotoc_md36", null ], + [ "Documentation and maintenance", "md_changelog.html#autotoc_md37", null ] + ] ], + [ "2026-10-01", "md_changelog.html#autotoc_md38", [ + [ "Changed", "md_changelog.html#autotoc_md39", null ], + [ "Fixed", "md_changelog.html#autotoc_md40", null ] ] ] ] ], - [ "v1.0 — 2026-06-14", "md_changelog.html#autotoc_md37", [ - [ "Documentation", "md_changelog.html#autotoc_md38", null ], - [ "Initial implementation — 2026-03-13", "md_changelog.html#autotoc_md39", [ - [ "Added", "md_changelog.html#autotoc_md40", null ], - [ "Documentation and maintenance", "md_changelog.html#autotoc_md41", null ] + [ "v1.0 — 2026-06-14", "md_changelog.html#autotoc_md41", [ + [ "Documentation", "md_changelog.html#autotoc_md42", null ], + [ "Initial implementation — 2026-03-13", "md_changelog.html#autotoc_md43", [ + [ "Added", "md_changelog.html#autotoc_md44", null ], + [ "Documentation and maintenance", "md_changelog.html#autotoc_md45", null ] ] ] ] ] ] ], [ "DBC Parser and Runtime Decode Module Documentation", "md_README.html", [ - [ "Overview", "md_README.html#autotoc_md43", null ], - [ "High-Level Architecture", "md_README.html#autotoc_md45", [ - [ "1. Parse and UI path", "md_README.html#autotoc_md46", null ], - [ "2. Runtime decode path", "md_README.html#autotoc_md47", null ] + [ "Overview", "md_README.html#autotoc_md47", null ], + [ "High-Level Architecture", "md_README.html#autotoc_md49", [ + [ "1. Parse and UI path", "md_README.html#autotoc_md50", null ], + [ "2. Runtime decode path", "md_README.html#autotoc_md51", null ] ] ], - [ "Why the Runtime Decode Layer Exists", "md_README.html#autotoc_md49", null ], - [ "Module Layout", "md_README.html#autotoc_md51", null ], - [ "Parsed Data Structures", "md_README.html#autotoc_md53", null ], - [ "SignalInfo", "md_README.html#autotoc_md54", null ], - [ "FrameInfo", "md_README.html#autotoc_md56", null ], - [ "DbcDatabase", "md_README.html#autotoc_md58", null ], - [ "UI Tree Layer", "md_README.html#autotoc_md60", null ], - [ "TreeNode", "md_README.html#autotoc_md61", null ], - [ "Runtime Decode Layer", "md_README.html#autotoc_md63", null ], - [ "Purpose", "md_README.html#autotoc_md64", null ], - [ "ByteOrder", "md_README.html#autotoc_md66", null ], - [ "ValueType", "md_README.html#autotoc_md68", null ], - [ "DecodeSignal", "md_README.html#autotoc_md70", null ], - [ "DecodeFrame", "md_README.html#autotoc_md72", null ], - [ "FrameKey", "md_README.html#autotoc_md74", null ], - [ "DecodeDatabase", "md_README.html#autotoc_md76", null ], - [ "Decoder Layer", "md_README.html#autotoc_md78", null ], - [ "RawCanFrame", "md_README.html#autotoc_md79", null ], - [ "DecodedSignalValue", "md_README.html#autotoc_md81", [ - [ "Raw value representation and precision", "md_README.html#autotoc_md83", null ] + [ "Why the Runtime Decode Layer Exists", "md_README.html#autotoc_md53", null ], + [ "Module Layout", "md_README.html#autotoc_md55", null ], + [ "Parsed Data Structures", "md_README.html#autotoc_md57", null ], + [ "SignalInfo", "md_README.html#autotoc_md58", null ], + [ "FrameInfo", "md_README.html#autotoc_md60", null ], + [ "DbcDatabase", "md_README.html#autotoc_md62", null ], + [ "UI Tree Layer", "md_README.html#autotoc_md64", null ], + [ "TreeNode", "md_README.html#autotoc_md65", null ], + [ "Runtime Decode Layer", "md_README.html#autotoc_md67", null ], + [ "Purpose", "md_README.html#autotoc_md68", null ], + [ "ByteOrder", "md_README.html#autotoc_md70", null ], + [ "ValueType", "md_README.html#autotoc_md72", null ], + [ "DecodeSignal", "md_README.html#autotoc_md74", null ], + [ "DecodeFrame", "md_README.html#autotoc_md76", null ], + [ "FrameKey", "md_README.html#autotoc_md78", null ], + [ "DecodeDatabase", "md_README.html#autotoc_md80", null ], + [ "Decoder Layer", "md_README.html#autotoc_md82", null ], + [ "RawCanFrame", "md_README.html#autotoc_md83", null ], + [ "DecodedSignalValue", "md_README.html#autotoc_md85", [ + [ "Raw value representation and precision", "md_README.html#autotoc_md87", null ] ] ], - [ "DecodedFrameValue", "md_README.html#autotoc_md85", [ - [ "Definition ownership and reload", "md_README.html#autotoc_md86", null ], - [ "Stable frame and signal identifiers", "md_README.html#autotoc_md87", null ] + [ "DecodedFrameValue", "md_README.html#autotoc_md89", [ + [ "Definition ownership and reload", "md_README.html#autotoc_md90", null ], + [ "Stable frame and signal identifiers", "md_README.html#autotoc_md91", null ] ] ], - [ "DbcDecoder", "md_README.html#autotoc_md89", null ], - [ "Parser Support", "md_README.html#autotoc_md91", [ - [ "Structured diagnostics", "md_README.html#autotoc_md92", null ], - [ "Attributes and frame metadata", "md_README.html#autotoc_md93", null ] + [ "DbcDecoder", "md_README.html#autotoc_md93", null ], + [ "Parser Support", "md_README.html#autotoc_md95", [ + [ "Structured diagnostics", "md_README.html#autotoc_md96", null ], + [ "Attributes and frame metadata", "md_README.html#autotoc_md97", null ] ] ], - [ "Supported DBC Syntax", "md_README.html#autotoc_md95", null ], - [ "Frame definition", "md_README.html#autotoc_md96", [ - [ "Frame validation and parse errors", "md_README.html#autotoc_md98", null ] + [ "Supported DBC Syntax", "md_README.html#autotoc_md99", null ], + [ "Frame definition", "md_README.html#autotoc_md100", [ + [ "Frame validation and parse errors", "md_README.html#autotoc_md102", null ] ] ], - [ "Signal definition", "md_README.html#autotoc_md100", [ - [ "Signal validation and parse errors", "md_README.html#autotoc_md102", null ] + [ "Signal definition", "md_README.html#autotoc_md104", [ + [ "Signal validation and parse errors", "md_README.html#autotoc_md106", null ] ] ], - [ "Basic multiplexing", "md_README.html#autotoc_md104", null ], - [ "Comments", "md_README.html#autotoc_md106", null ], - [ "CAN ID Normalization", "md_README.html#autotoc_md108", null ], - [ "J1939 Opt-in and PGN Lookup", "md_README.html#autotoc_md110", null ], - [ "Decode Flow", "md_README.html#autotoc_md112", null ], - [ "Intel and Motorola Extraction", "md_README.html#autotoc_md114", null ], - [ "Example Usage", "md_README.html#autotoc_md116", [ - [ "Parse DBC", "md_README.html#autotoc_md117", null ], - [ "Build UI tree", "md_README.html#autotoc_md118", null ], - [ "Build runtime decode database", "md_README.html#autotoc_md119", null ], - [ "Decode a raw frame", "md_README.html#autotoc_md120", null ] + [ "Multiplexing", "md_README.html#autotoc_md108", null ], + [ "Comments", "md_README.html#autotoc_md110", null ], + [ "CAN ID Normalization", "md_README.html#autotoc_md112", null ], + [ "J1939 Opt-in and PGN Lookup", "md_README.html#autotoc_md114", null ], + [ "Decode Flow", "md_README.html#autotoc_md116", null ], + [ "Intel and Motorola Extraction", "md_README.html#autotoc_md118", null ], + [ "Example Usage", "md_README.html#autotoc_md120", [ + [ "Parse DBC", "md_README.html#autotoc_md121", null ], + [ "Build UI tree", "md_README.html#autotoc_md122", null ], + [ "Build runtime decode database", "md_README.html#autotoc_md123", null ], + [ "Decode a raw frame", "md_README.html#autotoc_md124", null ] ] ], - [ "Unified Decode Strategy", "md_README.html#autotoc_md122", [ - [ "live path", "md_README.html#autotoc_md123", null ], - [ "trace path", "md_README.html#autotoc_md124", null ] + [ "Unified Decode Strategy", "md_README.html#autotoc_md126", [ + [ "live path", "md_README.html#autotoc_md127", null ], + [ "trace path", "md_README.html#autotoc_md128", null ] ] ], - [ "Intended Use in FrameTap", "md_README.html#autotoc_md126", null ], - [ "Why the Tree Is Not Enough", "md_README.html#autotoc_md128", null ], - [ "Statement Handler Factory", "md_README.html#autotoc_md130", null ], - [ "Signal value descriptions (VAL_)", "md_README.html#autotoc_md132", null ], - [ "Current Limitations", "md_README.html#autotoc_md134", null ], - [ "Recommended Next Steps", "md_README.html#autotoc_md136", [ - [ "Stage 1 - already implemented", "md_README.html#autotoc_md137", null ], - [ "Stage 2", "md_README.html#autotoc_md138", null ], - [ "Stage 3", "md_README.html#autotoc_md139", null ], - [ "Stage 4", "md_README.html#autotoc_md140", null ] + [ "Intended Use in FrameTap", "md_README.html#autotoc_md130", null ], + [ "Why the Tree Is Not Enough", "md_README.html#autotoc_md132", null ], + [ "Statement Handler Factory", "md_README.html#autotoc_md134", null ], + [ "Signal value descriptions (VAL_)", "md_README.html#autotoc_md136", null ], + [ "Current Limitations", "md_README.html#autotoc_md138", null ], + [ "Recommended Next Steps", "md_README.html#autotoc_md140", [ + [ "Stage 1 - already implemented", "md_README.html#autotoc_md141", null ], + [ "Stage 2", "md_README.html#autotoc_md142", null ], + [ "Stage 3", "md_README.html#autotoc_md143", null ], + [ "Stage 4", "md_README.html#autotoc_md144", null ] ] ], - [ "Build Integration", "md_README.html#autotoc_md142", [ - [ "Build core without Qt libraries", "md_README.html#autotoc_md143", null ], - [ "Optional Qt model adapter", "md_README.html#autotoc_md144", null ], - [ "Standalone tree tests without Qt", "md_README.html#autotoc_md145", null ], - [ "Build and run the demo", "md_README.html#autotoc_md146", null ], - [ "Generate API documentation", "md_README.html#autotoc_md147", null ] + [ "Build Integration", "md_README.html#autotoc_md146", [ + [ "Local core regression checks", "md_README.html#autotoc_md147", null ], + [ "Build core without Qt libraries", "md_README.html#autotoc_md148", null ], + [ "Optional Qt model adapter", "md_README.html#autotoc_md149", null ], + [ "Standalone tree tests without Qt", "md_README.html#autotoc_md150", null ], + [ "Build and run the demo", "md_README.html#autotoc_md151", null ], + [ "Generate API documentation", "md_README.html#autotoc_md152", null ] ] ], - [ "Regression tests", "md_README.html#autotoc_md149", null ], - [ "Code review and additional checks", "md_README.html#autotoc_md150", null ], - [ "Measuring code coverage", "md_README.html#autotoc_md151", [ - [ "GCC, gcov, and LCOV on Debian/Ubuntu", "md_README.html#autotoc_md152", null ], - [ "Configure the GCC coverage build in Qt Creator", "md_README.html#autotoc_md153", null ], - [ "Configure all build variants in Qt Creator", "md_README.html#autotoc_md154", null ] + [ "Regression tests", "md_README.html#autotoc_md154", null ], + [ "Code review and additional checks", "md_README.html#autotoc_md155", null ], + [ "Measuring code coverage", "md_README.html#autotoc_md156", [ + [ "GCC, gcov, and LCOV on Debian/Ubuntu", "md_README.html#autotoc_md157", null ], + [ "Configure the GCC coverage build in Qt Creator", "md_README.html#autotoc_md158", null ], + [ "Configure all build variants in Qt Creator", "md_README.html#autotoc_md159", null ] ] ] ] ], [ "QtTest regression tests", "md_tests_2README.html", [ - [ "Decoder coverage", "md_tests_2README.html#autotoc_md156", null ], - [ "Parser coverage", "md_tests_2README.html#autotoc_md157", null ], - [ "Tree and optional model tests", "md_tests_2README.html#autotoc_md158", null ], - [ "Additional regression coverage", "md_tests_2README.html#autotoc_md159", null ], - [ "Definition lifetime and reload coverage", "md_tests_2README.html#autotoc_md160", null ], - [ "Database validation coverage", "md_tests_2README.html#autotoc_md161", null ], - [ "End-to-end pipeline coverage", "md_tests_2README.html#autotoc_md162", null ], - [ "Attribute coverage", "md_tests_2README.html#autotoc_md163", null ], - [ "Extended validation", "md_tests_2README.html#autotoc_md164", null ] + [ "Local regression checks", "md_tests_2README.html#autotoc_md161", null ], + [ "Decoder coverage", "md_tests_2README.html#autotoc_md162", null ], + [ "Parser coverage", "md_tests_2README.html#autotoc_md163", null ], + [ "Tree and optional model tests", "md_tests_2README.html#autotoc_md164", null ], + [ "Additional regression coverage", "md_tests_2README.html#autotoc_md165", null ], + [ "Definition lifetime and reload coverage", "md_tests_2README.html#autotoc_md166", null ], + [ "Database validation coverage", "md_tests_2README.html#autotoc_md167", null ], + [ "End-to-end pipeline coverage", "md_tests_2README.html#autotoc_md168", null ], + [ "Attribute coverage", "md_tests_2README.html#autotoc_md169", null ], + [ "Extended validation", "md_tests_2README.html#autotoc_md170", null ] ] ], [ "Classes", "annotated.html", [ [ "Class List", "annotated.html", "annotated_dup" ], @@ -202,7 +209,7 @@ var NAVTREE = var NAVTREEINDEX = [ "annotated.html", -"md_README.html#autotoc_md92" +"md_README.html#autotoc_md89" ]; var SYNCONMSG = 'click to disable panel synchronisation'; diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index 4cc7e05..aca3818 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -2,104 +2,106 @@ var NAVTREEINDEX0 = { "annotated.html":[4,0], "attributes_8h_source.html":[5,0,0,0], -"classDbcAttributeHandler.html":[4,0,2], -"classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83":[4,0,2,0], -"classDbcCommentHandler.html":[4,0,3], -"classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6":[4,0,3,0], -"classDbcDecodeBuilder.html":[4,0,5], -"classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b":[4,0,5,0], -"classDbcDecoder.html":[4,0,6], -"classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7":[4,0,6,1], -"classDbcDecoder.html#a4005c4311f57b7faf21c0cb31463039c":[4,0,6,0], -"classDbcDecoder.html#ade48a94b6fcda6563bd1b2c6ff49439e":[4,0,6,2], -"classDbcDiagnosticError.html":[4,0,8], -"classDbcDiagnosticError.html#aa9997368f79a9a0723481aaeffc44618":[4,0,8,0], -"classDbcDiagnosticError.html#ab3965082f01d66b6d5c20525af44235d":[4,0,8,1], -"classDbcFrameHandler.html":[4,0,9], -"classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89":[4,0,9,0], -"classDbcHeaderHandler.html":[4,0,10], -"classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693":[4,0,10,0], -"classDbcParser.html":[4,0,12], -"classDbcParser.html#a0e915ce79c2e3d4c95a5aaf2bf0409bc":[4,0,12,2], -"classDbcParser.html#a46bc3afcd103e704dc58bb4b073da73c":[4,0,12,0], -"classDbcParser.html#aef72826942c9095d653fafa435855e56":[4,0,12,1], -"classDbcSignalHandler.html":[4,0,15], -"classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b":[4,0,15,0], -"classDbcStatementDispatcher.html":[4,0,16], -"classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d":[4,0,16,1], -"classDbcStatementDispatcher.html#a2f064359b59d8644b8a8196653d47482":[4,0,16,0], -"classDbcStatementDispatcher.html#a495c2d5c7ebb8103b1987cdd87c142ed":[4,0,16,2], -"classDbcStatementHandler.html":[4,0,17], -"classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739":[4,0,17,0], -"classDbcTreeBuilder.html":[4,0,18], -"classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b":[4,0,18,0], -"classDbcTreeModel.html":[4,0,19], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfd":[4,0,19,1], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda155fbc1aa36cd7f15711f4461720fa1d":[4,0,19,1,10], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda55cc6538817898e455ae2cbd4cd7e755":[4,0,19,1,7], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda66d77c4244f1fcbae2ff66aff2be85d4":[4,0,19,1,1], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda716858f9cb0b60a665214362afd210ca":[4,0,19,1,4], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda8a5d5985c970c7c04290a7b0f3aa05f0":[4,0,19,1,9], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda9df090ff74d5110d75df22a0b2e507e8":[4,0,19,1,5], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdabe2c2768f230f994534963c6d32230d7":[4,0,19,1,0], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdad1c30e9d3e9ade5edbc5262a2131007b":[4,0,19,1,6], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdae702dc1611c58e76e36ee280091be1d8":[4,0,19,1,3], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdaee6045bcb658e9feefff87ca7d9e57ff":[4,0,19,1,8], -"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdaf8574caf8d0986f7d6d6d7923a7bdaa0":[4,0,19,1,2], -"classDbcTreeModel.html#a30bed0d65342917c19d9183da55af452":[4,0,19,6], -"classDbcTreeModel.html#a397f885e7fd45c387825b4357b875c10":[4,0,19,7], -"classDbcTreeModel.html#a4f7214b727d812885bf077352ec9ece1":[4,0,19,2], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069ae":[4,0,19,0], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea01cbc280578dad3fea144b98755b7ef3":[4,0,19,0,8], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea391e0095b1fac0d05fde0d5cb5edda85":[4,0,19,0,5], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea58500e460c83ab951d9271b3b795f234":[4,0,19,0,9], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea5baf88846401000c49679f46e619ef87":[4,0,19,0,6], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea656b55f10472395261871ff7ef3f4484":[4,0,19,0,0], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea657c7487a591debd704e4f7e4536b207":[4,0,19,0,4], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea8bc7de06cffddca5470da004741ed939":[4,0,19,0,2], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa154ab92b4d4ef65526238428ae3cace":[4,0,19,0,7], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa74a27fd4ea0e2d561c6ba9b15640010":[4,0,19,0,1], -"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa87659982bb22d7598c49cc08cd36c65":[4,0,19,0,3], -"classDbcTreeModel.html#a8caeb5ec6141eb3e446e48df3c70b3ad":[4,0,19,4], -"classDbcTreeModel.html#a8cb5a81d456cdead42b75fd3462ee00a":[4,0,19,3], -"classDbcTreeModel.html#a8f7842a79144bdb24fa9c5fbdcd37295":[4,0,19,10], -"classDbcTreeModel.html#aad5834e8edb00808cbfa498ea8c63fe9":[4,0,19,9], -"classDbcTreeModel.html#aca81d05c81cc48c1185fc36659e96e5b":[4,0,19,8], -"classDbcTreeModel.html#ae40bb8b8a26d205f178c6dd1134ff4b3":[4,0,19,5], -"classDbcUnsupportedMultiplexingHandler.html":[4,0,20], -"classDbcUnsupportedMultiplexingHandler.html#a9853fd67465f92ef587792986ea179ac":[4,0,20,0], -"classDbcValueDescriptionHandler.html":[4,0,21], -"classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a":[4,0,21,0], -"classDecodeDatabase.html":[4,0,22], -"classDecodeDatabase.html#a0af5b15b9953a4f6551c27ee9ae8b514":[4,0,22,4], -"classDecodeDatabase.html#a51a44cf7c3f23c98ec8781afe0097c0c":[4,0,22,0], -"classDecodeDatabase.html#a780d6e747a48b10a5eb0ab85448d2970":[4,0,22,2], -"classDecodeDatabase.html#aa034c1510984a85f60ad6c0bd744d6e8":[4,0,22,1], -"classDecodeDatabase.html#aa96b62b4f3fff68ab651674760f60d6d":[4,0,22,3], -"classTreeNode.html":[4,0,39], -"classTreeNode.html#a1eb94f7b6e7962c9d867a120772dfe6e":[4,0,39,7], -"classTreeNode.html#a226518612d0d00b5988a2c44fc21d3f1":[4,0,39,14], -"classTreeNode.html#a4727ff801a2d1b9323c5ae50a35457a6":[4,0,39,9], -"classTreeNode.html#a81047bd7d2a4cc96b9ef5e20d0d63b5f":[4,0,39,10], -"classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc":[4,0,39,1], -"classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d":[4,0,39,0], -"classTreeNode.html#aa48fbc17903eb8cfa40353e29f853c6f":[4,0,39,4], -"classTreeNode.html#aaac5b8d9dc9e5ae1f367d1adbcf20e18":[4,0,39,12], -"classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae":[4,0,39,2], -"classTreeNode.html#abdd82460187dca8d3e5d66f5d5c529ea":[4,0,39,8], -"classTreeNode.html#ad501f97eeec7f7d3353bfae838fbb6a8":[4,0,39,5], -"classTreeNode.html#af4e6e916c48c024a3dfeadac8174b527":[4,0,39,6], -"classTreeNode.html#af87331684d4b40240aec75e3286921d3":[4,0,39,3], -"classTreeNode.html#afa2f4b0aafa12d3d41ed00df8e0250c9":[4,0,39,11], -"classTreeNode.html#afc503b40004764163605d6dbdb4ef811":[4,0,39,13], -"classTypeFactory.html":[4,0,40], -"classTypeFactory.html#a1a119ad2956abe146213c6ca124d8dd4":[4,0,40,5], -"classTypeFactory.html#a33b404da3e19ea7e1245b8a4975721bf":[4,0,40,0], -"classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f":[4,0,40,4], -"classTypeFactory.html#a5f119fe61c1cb9f4725ce746e4a047b3":[4,0,40,6], -"classTypeFactory.html#a650022aac1e2f30af5bc554a5663939f":[4,0,40,1], -"classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3":[4,0,40,2], -"classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473":[4,0,40,3], +"classDbcAttributeHandler.html":[4,0,3], +"classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83":[4,0,3,0], +"classDbcCommentHandler.html":[4,0,4], +"classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6":[4,0,4,0], +"classDbcDecodeBuilder.html":[4,0,6], +"classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b":[4,0,6,0], +"classDbcDecoder.html":[4,0,7], +"classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7":[4,0,7,1], +"classDbcDecoder.html#a4005c4311f57b7faf21c0cb31463039c":[4,0,7,0], +"classDbcDecoder.html#ade48a94b6fcda6563bd1b2c6ff49439e":[4,0,7,2], +"classDbcDiagnosticError.html":[4,0,9], +"classDbcDiagnosticError.html#aa9997368f79a9a0723481aaeffc44618":[4,0,9,0], +"classDbcDiagnosticError.html#ab3965082f01d66b6d5c20525af44235d":[4,0,9,1], +"classDbcFrameHandler.html":[4,0,10], +"classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89":[4,0,10,0], +"classDbcHeaderHandler.html":[4,0,11], +"classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693":[4,0,11,0], +"classDbcMultiplexingHandler.html":[4,0,12], +"classDbcMultiplexingHandler.html#a16f9e9f898640200477d2dcc8bab442e":[4,0,12,0], +"classDbcParser.html":[4,0,14], +"classDbcParser.html#a0e915ce79c2e3d4c95a5aaf2bf0409bc":[4,0,14,2], +"classDbcParser.html#a46bc3afcd103e704dc58bb4b073da73c":[4,0,14,0], +"classDbcParser.html#aef72826942c9095d653fafa435855e56":[4,0,14,1], +"classDbcSignalHandler.html":[4,0,17], +"classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b":[4,0,17,0], +"classDbcStatementDispatcher.html":[4,0,18], +"classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d":[4,0,18,1], +"classDbcStatementDispatcher.html#a2f064359b59d8644b8a8196653d47482":[4,0,18,0], +"classDbcStatementDispatcher.html#a495c2d5c7ebb8103b1987cdd87c142ed":[4,0,18,2], +"classDbcStatementHandler.html":[4,0,19], +"classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739":[4,0,19,0], +"classDbcTreeBuilder.html":[4,0,20], +"classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b":[4,0,20,0], +"classDbcTreeModel.html":[4,0,21], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfd":[4,0,21,1], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda155fbc1aa36cd7f15711f4461720fa1d":[4,0,21,1,10], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda55cc6538817898e455ae2cbd4cd7e755":[4,0,21,1,7], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda66d77c4244f1fcbae2ff66aff2be85d4":[4,0,21,1,1], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda716858f9cb0b60a665214362afd210ca":[4,0,21,1,4], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda8a5d5985c970c7c04290a7b0f3aa05f0":[4,0,21,1,9], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfda9df090ff74d5110d75df22a0b2e507e8":[4,0,21,1,5], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdabe2c2768f230f994534963c6d32230d7":[4,0,21,1,0], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdad1c30e9d3e9ade5edbc5262a2131007b":[4,0,21,1,6], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdae702dc1611c58e76e36ee280091be1d8":[4,0,21,1,3], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdaee6045bcb658e9feefff87ca7d9e57ff":[4,0,21,1,8], +"classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfdaf8574caf8d0986f7d6d6d7923a7bdaa0":[4,0,21,1,2], +"classDbcTreeModel.html#a30bed0d65342917c19d9183da55af452":[4,0,21,6], +"classDbcTreeModel.html#a397f885e7fd45c387825b4357b875c10":[4,0,21,7], +"classDbcTreeModel.html#a4f7214b727d812885bf077352ec9ece1":[4,0,21,2], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069ae":[4,0,21,0], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea01cbc280578dad3fea144b98755b7ef3":[4,0,21,0,8], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea391e0095b1fac0d05fde0d5cb5edda85":[4,0,21,0,5], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea58500e460c83ab951d9271b3b795f234":[4,0,21,0,9], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea5baf88846401000c49679f46e619ef87":[4,0,21,0,6], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea656b55f10472395261871ff7ef3f4484":[4,0,21,0,0], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea657c7487a591debd704e4f7e4536b207":[4,0,21,0,4], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aea8bc7de06cffddca5470da004741ed939":[4,0,21,0,2], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa154ab92b4d4ef65526238428ae3cace":[4,0,21,0,7], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa74a27fd4ea0e2d561c6ba9b15640010":[4,0,21,0,1], +"classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069aeaa87659982bb22d7598c49cc08cd36c65":[4,0,21,0,3], +"classDbcTreeModel.html#a8caeb5ec6141eb3e446e48df3c70b3ad":[4,0,21,4], +"classDbcTreeModel.html#a8cb5a81d456cdead42b75fd3462ee00a":[4,0,21,3], +"classDbcTreeModel.html#a8f7842a79144bdb24fa9c5fbdcd37295":[4,0,21,10], +"classDbcTreeModel.html#aad5834e8edb00808cbfa498ea8c63fe9":[4,0,21,9], +"classDbcTreeModel.html#aca81d05c81cc48c1185fc36659e96e5b":[4,0,21,8], +"classDbcTreeModel.html#ae40bb8b8a26d205f178c6dd1134ff4b3":[4,0,21,5], +"classDbcValueDescriptionHandler.html":[4,0,22], +"classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a":[4,0,22,0], +"classDecodeDatabase.html":[4,0,23], +"classDecodeDatabase.html#a0af5b15b9953a4f6551c27ee9ae8b514":[4,0,23,4], +"classDecodeDatabase.html#a51a44cf7c3f23c98ec8781afe0097c0c":[4,0,23,0], +"classDecodeDatabase.html#a780d6e747a48b10a5eb0ab85448d2970":[4,0,23,2], +"classDecodeDatabase.html#aa034c1510984a85f60ad6c0bd744d6e8":[4,0,23,1], +"classDecodeDatabase.html#aa96b62b4f3fff68ab651674760f60d6d":[4,0,23,3], +"classTreeNode.html":[4,0,42], +"classTreeNode.html#a1eb94f7b6e7962c9d867a120772dfe6e":[4,0,42,7], +"classTreeNode.html#a226518612d0d00b5988a2c44fc21d3f1":[4,0,42,14], +"classTreeNode.html#a4727ff801a2d1b9323c5ae50a35457a6":[4,0,42,9], +"classTreeNode.html#a81047bd7d2a4cc96b9ef5e20d0d63b5f":[4,0,42,10], +"classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc":[4,0,42,1], +"classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d":[4,0,42,0], +"classTreeNode.html#aa48fbc17903eb8cfa40353e29f853c6f":[4,0,42,4], +"classTreeNode.html#aaac5b8d9dc9e5ae1f367d1adbcf20e18":[4,0,42,12], +"classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae":[4,0,42,2], +"classTreeNode.html#abdd82460187dca8d3e5d66f5d5c529ea":[4,0,42,8], +"classTreeNode.html#ad501f97eeec7f7d3353bfae838fbb6a8":[4,0,42,5], +"classTreeNode.html#af4e6e916c48c024a3dfeadac8174b527":[4,0,42,6], +"classTreeNode.html#af87331684d4b40240aec75e3286921d3":[4,0,42,3], +"classTreeNode.html#afa2f4b0aafa12d3d41ed00df8e0250c9":[4,0,42,11], +"classTreeNode.html#afc503b40004764163605d6dbdb4ef811":[4,0,42,13], +"classTypeFactory.html":[4,0,43], +"classTypeFactory.html#a1a119ad2956abe146213c6ca124d8dd4":[4,0,43,5], +"classTypeFactory.html#a33b404da3e19ea7e1245b8a4975721bf":[4,0,43,0], +"classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f":[4,0,43,4], +"classTypeFactory.html#a5f119fe61c1cb9f4725ce746e4a047b3":[4,0,43,6], +"classTypeFactory.html#a650022aac1e2f30af5bc554a5663939f":[4,0,43,1], +"classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3":[4,0,43,2], +"classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473":[4,0,43,3], +"classdbc__detail_1_1MultiplexError.html":[4,0,0,0], +"classdbc__detail_1_1MultiplexGraph.html":[4,0,0,1], "classes.html":[4,1], "dbc__attributes_8cpp_source.html":[5,0,0,1], "dbc__coverage__test_8cpp_source.html":[5,0,3,0], @@ -183,71 +185,69 @@ var NAVTREEINDEX0 = "md_AGENTS.html#autotoc_md4":[0,3], "md_AGENTS.html#autotoc_md5":[0,4], "md_README.html":[2], -"md_README.html#autotoc_md100":[2,26], -"md_README.html#autotoc_md102":[2,26,0], -"md_README.html#autotoc_md104":[2,27], -"md_README.html#autotoc_md106":[2,28], -"md_README.html#autotoc_md108":[2,29], -"md_README.html#autotoc_md110":[2,30], -"md_README.html#autotoc_md112":[2,31], -"md_README.html#autotoc_md114":[2,32], -"md_README.html#autotoc_md116":[2,33], -"md_README.html#autotoc_md117":[2,33,0], -"md_README.html#autotoc_md118":[2,33,1], -"md_README.html#autotoc_md119":[2,33,2], -"md_README.html#autotoc_md120":[2,33,3], -"md_README.html#autotoc_md122":[2,34], -"md_README.html#autotoc_md123":[2,34,0], -"md_README.html#autotoc_md124":[2,34,1], -"md_README.html#autotoc_md126":[2,35], -"md_README.html#autotoc_md128":[2,36], -"md_README.html#autotoc_md130":[2,37], -"md_README.html#autotoc_md132":[2,38], -"md_README.html#autotoc_md134":[2,39], -"md_README.html#autotoc_md136":[2,40], -"md_README.html#autotoc_md137":[2,40,0], -"md_README.html#autotoc_md138":[2,40,1], -"md_README.html#autotoc_md139":[2,40,2], -"md_README.html#autotoc_md140":[2,40,3], -"md_README.html#autotoc_md142":[2,41], -"md_README.html#autotoc_md143":[2,41,0], -"md_README.html#autotoc_md144":[2,41,1], -"md_README.html#autotoc_md145":[2,41,2], -"md_README.html#autotoc_md146":[2,41,3], -"md_README.html#autotoc_md147":[2,41,4], -"md_README.html#autotoc_md149":[2,42], -"md_README.html#autotoc_md150":[2,43], -"md_README.html#autotoc_md151":[2,44], -"md_README.html#autotoc_md152":[2,44,0], -"md_README.html#autotoc_md153":[2,44,1], -"md_README.html#autotoc_md154":[2,44,2], -"md_README.html#autotoc_md43":[2,0], -"md_README.html#autotoc_md45":[2,1], -"md_README.html#autotoc_md46":[2,1,0], -"md_README.html#autotoc_md47":[2,1,1], -"md_README.html#autotoc_md49":[2,2], -"md_README.html#autotoc_md51":[2,3], -"md_README.html#autotoc_md53":[2,4], -"md_README.html#autotoc_md54":[2,5], -"md_README.html#autotoc_md56":[2,6], -"md_README.html#autotoc_md58":[2,7], -"md_README.html#autotoc_md60":[2,8], -"md_README.html#autotoc_md61":[2,9], -"md_README.html#autotoc_md63":[2,10], -"md_README.html#autotoc_md64":[2,11], -"md_README.html#autotoc_md66":[2,12], -"md_README.html#autotoc_md68":[2,13], -"md_README.html#autotoc_md70":[2,14], -"md_README.html#autotoc_md72":[2,15], -"md_README.html#autotoc_md74":[2,16], -"md_README.html#autotoc_md76":[2,17], -"md_README.html#autotoc_md78":[2,18], -"md_README.html#autotoc_md79":[2,19], -"md_README.html#autotoc_md81":[2,20], -"md_README.html#autotoc_md83":[2,20,0], -"md_README.html#autotoc_md85":[2,21], -"md_README.html#autotoc_md86":[2,21,0], -"md_README.html#autotoc_md87":[2,21,1], -"md_README.html#autotoc_md89":[2,22], -"md_README.html#autotoc_md91":[2,23] +"md_README.html#autotoc_md100":[2,25], +"md_README.html#autotoc_md102":[2,25,0], +"md_README.html#autotoc_md104":[2,26], +"md_README.html#autotoc_md106":[2,26,0], +"md_README.html#autotoc_md108":[2,27], +"md_README.html#autotoc_md110":[2,28], +"md_README.html#autotoc_md112":[2,29], +"md_README.html#autotoc_md114":[2,30], +"md_README.html#autotoc_md116":[2,31], +"md_README.html#autotoc_md118":[2,32], +"md_README.html#autotoc_md120":[2,33], +"md_README.html#autotoc_md121":[2,33,0], +"md_README.html#autotoc_md122":[2,33,1], +"md_README.html#autotoc_md123":[2,33,2], +"md_README.html#autotoc_md124":[2,33,3], +"md_README.html#autotoc_md126":[2,34], +"md_README.html#autotoc_md127":[2,34,0], +"md_README.html#autotoc_md128":[2,34,1], +"md_README.html#autotoc_md130":[2,35], +"md_README.html#autotoc_md132":[2,36], +"md_README.html#autotoc_md134":[2,37], +"md_README.html#autotoc_md136":[2,38], +"md_README.html#autotoc_md138":[2,39], +"md_README.html#autotoc_md140":[2,40], +"md_README.html#autotoc_md141":[2,40,0], +"md_README.html#autotoc_md142":[2,40,1], +"md_README.html#autotoc_md143":[2,40,2], +"md_README.html#autotoc_md144":[2,40,3], +"md_README.html#autotoc_md146":[2,41], +"md_README.html#autotoc_md147":[2,41,0], +"md_README.html#autotoc_md148":[2,41,1], +"md_README.html#autotoc_md149":[2,41,2], +"md_README.html#autotoc_md150":[2,41,3], +"md_README.html#autotoc_md151":[2,41,4], +"md_README.html#autotoc_md152":[2,41,5], +"md_README.html#autotoc_md154":[2,42], +"md_README.html#autotoc_md155":[2,43], +"md_README.html#autotoc_md156":[2,44], +"md_README.html#autotoc_md157":[2,44,0], +"md_README.html#autotoc_md158":[2,44,1], +"md_README.html#autotoc_md159":[2,44,2], +"md_README.html#autotoc_md47":[2,0], +"md_README.html#autotoc_md49":[2,1], +"md_README.html#autotoc_md50":[2,1,0], +"md_README.html#autotoc_md51":[2,1,1], +"md_README.html#autotoc_md53":[2,2], +"md_README.html#autotoc_md55":[2,3], +"md_README.html#autotoc_md57":[2,4], +"md_README.html#autotoc_md58":[2,5], +"md_README.html#autotoc_md60":[2,6], +"md_README.html#autotoc_md62":[2,7], +"md_README.html#autotoc_md64":[2,8], +"md_README.html#autotoc_md65":[2,9], +"md_README.html#autotoc_md67":[2,10], +"md_README.html#autotoc_md68":[2,11], +"md_README.html#autotoc_md70":[2,12], +"md_README.html#autotoc_md72":[2,13], +"md_README.html#autotoc_md74":[2,14], +"md_README.html#autotoc_md76":[2,15], +"md_README.html#autotoc_md78":[2,16], +"md_README.html#autotoc_md80":[2,17], +"md_README.html#autotoc_md82":[2,18], +"md_README.html#autotoc_md83":[2,19], +"md_README.html#autotoc_md85":[2,20], +"md_README.html#autotoc_md87":[2,20,0] }; diff --git a/docs/html/navtreeindex1.js b/docs/html/navtreeindex1.js index 13a45b3..e194942 100644 --- a/docs/html/navtreeindex1.js +++ b/docs/html/navtreeindex1.js @@ -1,231 +1,243 @@ var NAVTREEINDEX1 = { -"md_README.html#autotoc_md92":[2,23,0], -"md_README.html#autotoc_md93":[2,23,1], -"md_README.html#autotoc_md95":[2,24], -"md_README.html#autotoc_md96":[2,25], -"md_README.html#autotoc_md98":[2,25,0], +"md_README.html#autotoc_md89":[2,21], +"md_README.html#autotoc_md90":[2,21,0], +"md_README.html#autotoc_md91":[2,21,1], +"md_README.html#autotoc_md93":[2,22], +"md_README.html#autotoc_md95":[2,23], +"md_README.html#autotoc_md96":[2,23,0], +"md_README.html#autotoc_md97":[2,23,1], +"md_README.html#autotoc_md99":[2,24], "md_changelog.html":[1], "md_changelog.html#autotoc_md10":[1,0,0,1], "md_changelog.html#autotoc_md11":[1,0,0,2], -"md_changelog.html#autotoc_md12":[1,0,0,3], -"md_changelog.html#autotoc_md13":[1,0,0,4], -"md_changelog.html#autotoc_md14":[1,0,1], -"md_changelog.html#autotoc_md15":[1,0,1,0], -"md_changelog.html#autotoc_md16":[1,0,1,1], -"md_changelog.html#autotoc_md17":[1,0,1,2], +"md_changelog.html#autotoc_md12":[1,0,1], +"md_changelog.html#autotoc_md13":[1,0,1,0], +"md_changelog.html#autotoc_md14":[1,0,1,1], +"md_changelog.html#autotoc_md15":[1,0,1,2], +"md_changelog.html#autotoc_md16":[1,0,1,3], +"md_changelog.html#autotoc_md17":[1,0,1,4], "md_changelog.html#autotoc_md18":[1,0,2], "md_changelog.html#autotoc_md19":[1,0,2,0], "md_changelog.html#autotoc_md20":[1,0,2,1], -"md_changelog.html#autotoc_md21":[1,0,3], -"md_changelog.html#autotoc_md22":[1,0,3,0], -"md_changelog.html#autotoc_md23":[1,0,3,1], -"md_changelog.html#autotoc_md24":[1,0,4], -"md_changelog.html#autotoc_md25":[1,0,4,0], -"md_changelog.html#autotoc_md26":[1,0,4,1], -"md_changelog.html#autotoc_md27":[1,0,4,2], +"md_changelog.html#autotoc_md21":[1,0,2,2], +"md_changelog.html#autotoc_md22":[1,0,3], +"md_changelog.html#autotoc_md23":[1,0,3,0], +"md_changelog.html#autotoc_md24":[1,0,3,1], +"md_changelog.html#autotoc_md25":[1,0,4], +"md_changelog.html#autotoc_md26":[1,0,4,0], +"md_changelog.html#autotoc_md27":[1,0,4,1], "md_changelog.html#autotoc_md28":[1,0,5], "md_changelog.html#autotoc_md29":[1,0,5,0], -"md_changelog.html#autotoc_md30":[1,0,6], -"md_changelog.html#autotoc_md31":[1,0,6,0], -"md_changelog.html#autotoc_md32":[1,0,6,1], -"md_changelog.html#autotoc_md33":[1,0,6,2], +"md_changelog.html#autotoc_md30":[1,0,5,1], +"md_changelog.html#autotoc_md31":[1,0,5,2], +"md_changelog.html#autotoc_md32":[1,0,6], +"md_changelog.html#autotoc_md33":[1,0,6,0], "md_changelog.html#autotoc_md34":[1,0,7], "md_changelog.html#autotoc_md35":[1,0,7,0], "md_changelog.html#autotoc_md36":[1,0,7,1], -"md_changelog.html#autotoc_md37":[1,1], -"md_changelog.html#autotoc_md38":[1,1,0], -"md_changelog.html#autotoc_md39":[1,1,1], -"md_changelog.html#autotoc_md40":[1,1,1,0], -"md_changelog.html#autotoc_md41":[1,1,1,1], +"md_changelog.html#autotoc_md37":[1,0,7,2], +"md_changelog.html#autotoc_md38":[1,0,8], +"md_changelog.html#autotoc_md39":[1,0,8,0], +"md_changelog.html#autotoc_md40":[1,0,8,1], +"md_changelog.html#autotoc_md41":[1,1], +"md_changelog.html#autotoc_md42":[1,1,0], +"md_changelog.html#autotoc_md43":[1,1,1], +"md_changelog.html#autotoc_md44":[1,1,1,0], +"md_changelog.html#autotoc_md45":[1,1,1,1], "md_changelog.html#autotoc_md7":[1,0], "md_changelog.html#autotoc_md8":[1,0,0], "md_changelog.html#autotoc_md9":[1,0,0,0], "md_tests_2README.html":[3], -"md_tests_2README.html#autotoc_md156":[3,0], -"md_tests_2README.html#autotoc_md157":[3,1], -"md_tests_2README.html#autotoc_md158":[3,2], -"md_tests_2README.html#autotoc_md159":[3,3], -"md_tests_2README.html#autotoc_md160":[3,4], -"md_tests_2README.html#autotoc_md161":[3,5], -"md_tests_2README.html#autotoc_md162":[3,6], -"md_tests_2README.html#autotoc_md163":[3,7], -"md_tests_2README.html#autotoc_md164":[3,8], -"multiplexing_8h_source.html":[5,0,0,19], +"md_tests_2README.html#autotoc_md161":[3,0], +"md_tests_2README.html#autotoc_md162":[3,1], +"md_tests_2README.html#autotoc_md163":[3,2], +"md_tests_2README.html#autotoc_md164":[3,3], +"md_tests_2README.html#autotoc_md165":[3,4], +"md_tests_2README.html#autotoc_md166":[3,5], +"md_tests_2README.html#autotoc_md167":[3,6], +"md_tests_2README.html#autotoc_md168":[3,7], +"md_tests_2README.html#autotoc_md169":[3,8], +"md_tests_2README.html#autotoc_md170":[3,9], +"multiplex__graph_8h_source.html":[5,0,0,19], +"multiplexing_8h_source.html":[5,0,0,20], "pages.html":[], -"signal__info_8h.html":[5,0,0,20], -"signal__info_8h_source.html":[5,0,0,20], -"signal__layout_8h_source.html":[5,0,0,21], -"structAttributeAssignment.html":[4,0,0], -"structAttributeAssignment.html#a024a249cc63dbfbf337eea395fe3471e":[4,0,0,3], -"structAttributeAssignment.html#a330ae1a34c342b0352115a83dd31aab8":[4,0,0,2], -"structAttributeAssignment.html#a50059e42e5e5b944050f3290ce84ac66":[4,0,0,4], -"structAttributeAssignment.html#a50405e8db9e4536015f9adc5ba360270":[4,0,0,1], -"structAttributeAssignment.html#a93de8c51c5154219bf18beadcec5708f":[4,0,0,5], -"structAttributeAssignment.html#aa8707eddd2d3a2de559fe44354a514cc":[4,0,0,0], -"structAttributeDefinition.html":[4,0,1], -"structAttributeDefinition.html#a18245dba995929a61fd6de1fcdbc8a89":[4,0,1,4], -"structAttributeDefinition.html#a547fe17f6cfc631528f9156e4a509c66":[4,0,1,6], -"structAttributeDefinition.html#a5ca8f41ea3e921f54d81b8760c1dcfb3":[4,0,1,3], -"structAttributeDefinition.html#a5de5484174a8c5f6b309041089d20afc":[4,0,1,1], -"structAttributeDefinition.html#a5f109f0ec94eb04c3f52c116366aefdf":[4,0,1,0], -"structAttributeDefinition.html#aa02fe74b5420c2e67c13e610b6bc9713":[4,0,1,5], -"structAttributeDefinition.html#aaf87153bac0b228ad87b88e96f303210":[4,0,1,2], -"structAttributeDefinition.html#ae0949edf67f9d4e60e4cb376a95da4f2":[4,0,1,7], -"structDbcDatabase.html":[4,0,4], -"structDbcDatabase.html#a14862245081989f2abf126b5ea6dfdfa":[4,0,4,1], -"structDbcDatabase.html#a2cade5d0234ee816132127542f8c612b":[4,0,4,0], -"structDbcDatabase.html#a321839ad81af176444358eb23114eaee":[4,0,4,3], -"structDbcDatabase.html#aa7bdf56eb8b7ab5b873e1c096b46d8b6":[4,0,4,2], -"structDbcDiagnostic.html":[4,0,7], -"structDbcDiagnostic.html#a124bae82eebeaef46426bd124685ef1b":[4,0,7,4], -"structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d":[4,0,7,0], -"structDbcDiagnostic.html#aa315a4a40b15f2e8cb34264d94a0f914":[4,0,7,1], -"structDbcDiagnostic.html#ac9f02705ed6a633cbb9526d0e392fb95":[4,0,7,2], -"structDbcDiagnostic.html#adb201de8d32b768d5f559bed21e8f819":[4,0,7,3], -"structDbcParseContext.html":[4,0,11], -"structDbcParseContext.html#a1ac7f4a54550aaddef08749806f87001":[4,0,11,2], -"structDbcParseContext.html#a57f5a7f613ecd0dadbafa7af736b7e54":[4,0,11,7], -"structDbcParseContext.html#a79bad0b8302e2156670461bab529259c":[4,0,11,4], -"structDbcParseContext.html#a854abba7bbf4adfc948554c254156e60":[4,0,11,10], -"structDbcParseContext.html#a908056de0a97316a4ebecb3f99cc400b":[4,0,11,0], -"structDbcParseContext.html#a93f8ece0f3d16bd79f631ae07afa7b54":[4,0,11,6], -"structDbcParseContext.html#ab5552dad944fde7fa6add6464ddb5369":[4,0,11,3], -"structDbcParseContext.html#ac22cba614ada3a28c7dcc1ea338b0e01":[4,0,11,8], -"structDbcParseContext.html#aeae343c57a244634489a0e0b960155d7":[4,0,11,1], -"structDbcParseContext.html#af31b56247edff7f025957ae023a56913":[4,0,11,5], -"structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546":[4,0,11,9], -"structDbcParseContext.html#afbfa4b26a58b41ada3dabc619066035c":[4,0,11,11], -"structDbcParseResult.html":[4,0,13], -"structDbcParseResult.html#a3a1987b4381bb1e0a34dc09e31483679":[4,0,13,2], -"structDbcParseResult.html#a4da8641de3f6b55c7447c4421e05d20d":[4,0,13,0], -"structDbcParseResult.html#abfa765d29a4397e8ddaf771bae21993e":[4,0,13,1], -"structDbcParserOptions.html":[4,0,14], -"structDbcParserOptions.html#ab31534f5c0853461b46cbb38149c33f9":[4,0,14,0], -"structDecodeFrame.html":[4,0,25], -"structDecodeFrame.html#a05e3d1c6143367553c2c3beba82a5c34":[4,0,25,0], -"structDecodeFrame.html#a1d3c54055c0cbceb73adf551f7067f23":[4,0,25,5], -"structDecodeFrame.html#a2551102670c4a540fced4c71da0b369d":[4,0,25,6], -"structDecodeFrame.html#a25819ef907a32391af5c9f7cae9cdb22":[4,0,25,8], -"structDecodeFrame.html#a3ee2348d781f8f15aaf87e8dcf57ec41":[4,0,25,3], -"structDecodeFrame.html#a475e669f390491a4d99383d3fee51300":[4,0,25,11], -"structDecodeFrame.html#a51111ac13988be372d5673d12cf3e060":[4,0,25,4], -"structDecodeFrame.html#a52e10215388db7df8b541b9d9909edcf":[4,0,25,2], -"structDecodeFrame.html#a732c2f6853d55ce8253db61207fc21d3":[4,0,25,12], -"structDecodeFrame.html#a7f4e71bbdec3f424b625e724e3dfbf14":[4,0,25,9], -"structDecodeFrame.html#aa0a7f8fd5bfde2148dfd0d838328f579":[4,0,25,1], -"structDecodeFrame.html#ad506b03108a40df7e8005638c9c59653":[4,0,25,10], -"structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9":[4,0,25,7], -"structDecodeSignal.html":[4,0,26], -"structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25":[4,0,26,8], -"structDecodeSignal.html#a204f65c7ea45a2c148f19c12d922f99b":[4,0,26,14], -"structDecodeSignal.html#a38eed9ca7581423fd8bfbedcffc12092":[4,0,26,10], -"structDecodeSignal.html#a428c39913a366a8476dd291061354391":[4,0,26,6], -"structDecodeSignal.html#a4a6ba87142a9badbf0ca830e9e709cb7":[4,0,26,9], -"structDecodeSignal.html#a58cf5844f2272a23dcb9687d912e4780":[4,0,26,1], -"structDecodeSignal.html#a822155d9bf4ed5f3300c9e9befe606ff":[4,0,26,12], -"structDecodeSignal.html#a92db637af4e224a0ae70173050dc3f74":[4,0,26,7], -"structDecodeSignal.html#a9d37638129263b8902ba5be59baf39a8":[4,0,26,5], -"structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d":[4,0,26,2], -"structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa":[4,0,26,11], -"structDecodeSignal.html#abdc4c4bb4a67a6d61d6ca81e8a52833d":[4,0,26,4], -"structDecodeSignal.html#acd4ef5ee30421d117b5756854302debb":[4,0,26,3], -"structDecodeSignal.html#ae28c905d4a2bc86419c2a8361bfea473":[4,0,26,13], -"structDecodeSignal.html#aea41c055cb255fe7bd178ed5727f28c9":[4,0,26,0], -"structDecodedFrameValue.html":[4,0,23], -"structDecodedFrameValue.html#a32143efe2023a1ecd977a9ae93e50b73":[4,0,23,1], -"structDecodedFrameValue.html#a33e971ba10030506007aa201c89f351d":[4,0,23,0], -"structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0":[4,0,23,3], -"structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9":[4,0,23,4], -"structDecodedFrameValue.html#adae123ac7fbb4a5c314b64b01109f4a8":[4,0,23,2], -"structDecodedSignalValue.html":[4,0,24], -"structDecodedSignalValue.html#a33df0fcd92b23b3e08539906fc6b4c4a":[4,0,24,2], -"structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28":[4,0,24,3], -"structDecodedSignalValue.html#a6847d05b3cb00d5e0f6c611968f57978":[4,0,24,4], -"structDecodedSignalValue.html#a828b5ef7faefc14fbf5dbd46249bcad2":[4,0,24,1], -"structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6":[4,0,24,6], -"structDecodedSignalValue.html#aac0ed361af545cde48d0e6f41a859686":[4,0,24,5], -"structDecodedSignalValue.html#affc38af1bf31bcb6f2c33044bce92bd2":[4,0,24,0], -"structFrameInfo.html":[4,0,27], -"structFrameInfo.html#a099f02a77adfb9ac23e286ce75f4eef4":[4,0,27,10], -"structFrameInfo.html#a34b726afaad2ac5c697fdb2ac070cdaf":[4,0,27,2], -"structFrameInfo.html#a35bf839519ef3f48b5f52dd9bcd7e9ac":[4,0,27,9], -"structFrameInfo.html#a3f7e25d67ddae22f2ed50823a5a26084":[4,0,27,8], -"structFrameInfo.html#a4737a5420213ad4304724e39f3a4e55d":[4,0,27,4], -"structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8":[4,0,27,6], -"structFrameInfo.html#a9ef2736053b593cf34ba2608cf8275c0":[4,0,27,11], -"structFrameInfo.html#aa2b198ea0f55e560c123d35e7b3ecab9":[4,0,27,5], -"structFrameInfo.html#abb53a7f93ed7abc0ea1ae4a8ccafcdcb":[4,0,27,0], -"structFrameInfo.html#ace75121294f9d89b762080ab5643293c":[4,0,27,7], -"structFrameInfo.html#aee518b33f1000bf0b7f6e4a87474c943":[4,0,27,3], -"structFrameInfo.html#af470b0742c05bfbffc31c51a68f5c05e":[4,0,27,1], -"structFrameKey.html":[4,0,28], -"structFrameKey.html#a022917652b4d3c2f2dfcc5a13ab7caa4":[4,0,28,2], -"structFrameKey.html#a33bde405c7ea53000d54b3dd6e058670":[4,0,28,0], -"structFrameKey.html#aa3179b709d02ef70cf0e736f040a2145":[4,0,28,3], -"structFrameKey.html#aaaec9f914e127787247fcda5e183b01f":[4,0,28,1], -"structFrameKeyHasher.html":[4,0,29], -"structFrameKeyHasher.html#a1612ce56b513790e3ed4c06ec7d28b9f":[4,0,29,0], -"structMultiplexing.html":[4,0,30], -"structMultiplexing.html#a62b70a0e3f2a9c7a457b3694ce8625c3":[4,0,30,0], -"structMultiplexing.html#a79158d4fdbfd68a3d51a8ce79d34fd67":[4,0,30,1], -"structPendingAttribute.html":[4,0,31], -"structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8":[4,0,31,0], -"structPendingAttribute.html#a9a68a0a54c313c3e43dfdcd6e7a55da9":[4,0,31,1], -"structPendingComment.html":[4,0,32], -"structPendingComment.html#a29a3733e0a4c8ae341695db3d21d9249":[4,0,32,5], -"structPendingComment.html#a6d1c3b1e149bb602a95224446709c771":[4,0,32,0], -"structPendingComment.html#a9abd7e15ed59eb4534c66ff74f276e07":[4,0,32,1], -"structPendingComment.html#aa344393f67770e12449a4f14f6fcf10b":[4,0,32,4], -"structPendingComment.html#ac03903ffb042d27ad66012eb18ea1437":[4,0,32,2], -"structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27":[4,0,32,3], -"structPendingValueDescriptions.html":[4,0,33], -"structPendingValueDescriptions.html#a10ecbaeaed2cc3ac82fada73e7e041dd":[4,0,33,3], -"structPendingValueDescriptions.html#a5c19cff09b0e83bd3cd6085213c17da8":[4,0,33,4], -"structPendingValueDescriptions.html#a5f0082ceeaee77e2f823661547aad844":[4,0,33,0], -"structPendingValueDescriptions.html#a60f185e8d91010927c4aa3b4a750c9f4":[4,0,33,1], -"structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90":[4,0,33,2], -"structPgnLookupResult.html":[4,0,34], -"structPgnLookupResult.html#a6158833782348b3cc26037c2091fcc36":[4,0,34,1], -"structPgnLookupResult.html#aa5b79b61d2aef48fd6ae070cf5f901c1":[4,0,34,0], -"structRawCanFrame.html":[4,0,35], -"structRawCanFrame.html#a0acb487612104c99c9907344c035df83":[4,0,35,2], -"structRawCanFrame.html#a2d0e7fa0e3d5c20bbed55ed8f7888ff4":[4,0,35,0], -"structRawCanFrame.html#a462193d275adc1dba8bd18ffa0e36bb7":[4,0,35,1], -"structSignalInfo.html":[4,0,36], -"structSignalInfo.html#a1008b5201f71848177217bd52fb84baa":[4,0,36,3], -"structSignalInfo.html#a1f214f03e94ef5794de2d3367bfcbd01":[4,0,36,10], -"structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3":[4,0,36,11], -"structSignalInfo.html#a379e422a00cad56f896cacf60455b088":[4,0,36,1], -"structSignalInfo.html#a43f47d0433d0cc39076bd7278b46af9c":[4,0,36,12], -"structSignalInfo.html#a52a52b320eef92fbcb4626307f9a498f":[4,0,36,5], -"structSignalInfo.html#a781766eddbf6641071623c8e5b9acb4a":[4,0,36,14], -"structSignalInfo.html#a8a2e29f307c75926a1bd824266d23ca8":[4,0,36,0], -"structSignalInfo.html#ab7d0769f47aa540656b22e4e49db517e":[4,0,36,7], -"structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5":[4,0,36,13], -"structSignalInfo.html#ace290724f9801521609aedaa946d61f1":[4,0,36,2], -"structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b":[4,0,36,8], -"structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52":[4,0,36,9], -"structSignalInfo.html#ae4f78d99a2750aa564d7eba860171499":[4,0,36,6], -"structSignalInfo.html#af363b1563fb4c7cc8973f9a80c06846c":[4,0,36,4], -"structSignalKey.html":[4,0,37], -"structSignalKey.html#a17525dc0116be7f4f58f3c3fae1022e2":[4,0,37,1], -"structSignalKey.html#a25f4ece1bf685791b576f68e23d8ccc7":[4,0,37,2], -"structSignalKey.html#aa4221b34e75469bf5aa939976c334f46":[4,0,37,0], -"structSignalKey.html#abab371cce740f05111fd3b4013ca6944":[4,0,37,3], -"structSignalKeyHasher.html":[4,0,38], -"structSignalKeyHasher.html#af8869bcb714857af7ad005fbd13bea80":[4,0,38,0], +"signal__info_8h.html":[5,0,0,21], +"signal__info_8h_source.html":[5,0,0,21], +"signal__layout_8h_source.html":[5,0,0,22], +"structAttributeAssignment.html":[4,0,1], +"structAttributeAssignment.html#a024a249cc63dbfbf337eea395fe3471e":[4,0,1,3], +"structAttributeAssignment.html#a330ae1a34c342b0352115a83dd31aab8":[4,0,1,2], +"structAttributeAssignment.html#a50059e42e5e5b944050f3290ce84ac66":[4,0,1,4], +"structAttributeAssignment.html#a50405e8db9e4536015f9adc5ba360270":[4,0,1,1], +"structAttributeAssignment.html#a93de8c51c5154219bf18beadcec5708f":[4,0,1,5], +"structAttributeAssignment.html#aa8707eddd2d3a2de559fe44354a514cc":[4,0,1,0], +"structAttributeDefinition.html":[4,0,2], +"structAttributeDefinition.html#a18245dba995929a61fd6de1fcdbc8a89":[4,0,2,4], +"structAttributeDefinition.html#a547fe17f6cfc631528f9156e4a509c66":[4,0,2,6], +"structAttributeDefinition.html#a5ca8f41ea3e921f54d81b8760c1dcfb3":[4,0,2,3], +"structAttributeDefinition.html#a5de5484174a8c5f6b309041089d20afc":[4,0,2,1], +"structAttributeDefinition.html#a5f109f0ec94eb04c3f52c116366aefdf":[4,0,2,0], +"structAttributeDefinition.html#aa02fe74b5420c2e67c13e610b6bc9713":[4,0,2,5], +"structAttributeDefinition.html#aaf87153bac0b228ad87b88e96f303210":[4,0,2,2], +"structAttributeDefinition.html#ae0949edf67f9d4e60e4cb376a95da4f2":[4,0,2,7], +"structDbcDatabase.html":[4,0,5], +"structDbcDatabase.html#a14862245081989f2abf126b5ea6dfdfa":[4,0,5,1], +"structDbcDatabase.html#a2cade5d0234ee816132127542f8c612b":[4,0,5,0], +"structDbcDatabase.html#a321839ad81af176444358eb23114eaee":[4,0,5,3], +"structDbcDatabase.html#aa7bdf56eb8b7ab5b873e1c096b46d8b6":[4,0,5,2], +"structDbcDiagnostic.html":[4,0,8], +"structDbcDiagnostic.html#a124bae82eebeaef46426bd124685ef1b":[4,0,8,4], +"structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d":[4,0,8,0], +"structDbcDiagnostic.html#aa315a4a40b15f2e8cb34264d94a0f914":[4,0,8,1], +"structDbcDiagnostic.html#ac9f02705ed6a633cbb9526d0e392fb95":[4,0,8,2], +"structDbcDiagnostic.html#adb201de8d32b768d5f559bed21e8f819":[4,0,8,3], +"structDbcParseContext.html":[4,0,13], +"structDbcParseContext.html#a1ac7f4a54550aaddef08749806f87001":[4,0,13,2], +"structDbcParseContext.html#a57f5a7f613ecd0dadbafa7af736b7e54":[4,0,13,7], +"structDbcParseContext.html#a79bad0b8302e2156670461bab529259c":[4,0,13,4], +"structDbcParseContext.html#a854abba7bbf4adfc948554c254156e60":[4,0,13,10], +"structDbcParseContext.html#a908056de0a97316a4ebecb3f99cc400b":[4,0,13,0], +"structDbcParseContext.html#a93f8ece0f3d16bd79f631ae07afa7b54":[4,0,13,6], +"structDbcParseContext.html#ab5552dad944fde7fa6add6464ddb5369":[4,0,13,3], +"structDbcParseContext.html#ac22cba614ada3a28c7dcc1ea338b0e01":[4,0,13,8], +"structDbcParseContext.html#aeae343c57a244634489a0e0b960155d7":[4,0,13,1], +"structDbcParseContext.html#af31b56247edff7f025957ae023a56913":[4,0,13,5], +"structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546":[4,0,13,9], +"structDbcParseContext.html#afbfa4b26a58b41ada3dabc619066035c":[4,0,13,11], +"structDbcParseResult.html":[4,0,15], +"structDbcParseResult.html#a3a1987b4381bb1e0a34dc09e31483679":[4,0,15,2], +"structDbcParseResult.html#a4da8641de3f6b55c7447c4421e05d20d":[4,0,15,0], +"structDbcParseResult.html#abfa765d29a4397e8ddaf771bae21993e":[4,0,15,1], +"structDbcParserOptions.html":[4,0,16], +"structDbcParserOptions.html#ab31534f5c0853461b46cbb38149c33f9":[4,0,16,0], +"structDecodeFrame.html":[4,0,26], +"structDecodeFrame.html#a05e3d1c6143367553c2c3beba82a5c34":[4,0,26,0], +"structDecodeFrame.html#a1d3c54055c0cbceb73adf551f7067f23":[4,0,26,5], +"structDecodeFrame.html#a2551102670c4a540fced4c71da0b369d":[4,0,26,6], +"structDecodeFrame.html#a25819ef907a32391af5c9f7cae9cdb22":[4,0,26,8], +"structDecodeFrame.html#a3ee2348d781f8f15aaf87e8dcf57ec41":[4,0,26,3], +"structDecodeFrame.html#a475e669f390491a4d99383d3fee51300":[4,0,26,11], +"structDecodeFrame.html#a51111ac13988be372d5673d12cf3e060":[4,0,26,4], +"structDecodeFrame.html#a52e10215388db7df8b541b9d9909edcf":[4,0,26,2], +"structDecodeFrame.html#a732c2f6853d55ce8253db61207fc21d3":[4,0,26,12], +"structDecodeFrame.html#a7f4e71bbdec3f424b625e724e3dfbf14":[4,0,26,9], +"structDecodeFrame.html#aa0a7f8fd5bfde2148dfd0d838328f579":[4,0,26,1], +"structDecodeFrame.html#ad506b03108a40df7e8005638c9c59653":[4,0,26,10], +"structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9":[4,0,26,7], +"structDecodeSignal.html":[4,0,27], +"structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25":[4,0,27,8], +"structDecodeSignal.html#a204f65c7ea45a2c148f19c12d922f99b":[4,0,27,14], +"structDecodeSignal.html#a38eed9ca7581423fd8bfbedcffc12092":[4,0,27,10], +"structDecodeSignal.html#a428c39913a366a8476dd291061354391":[4,0,27,6], +"structDecodeSignal.html#a4a6ba87142a9badbf0ca830e9e709cb7":[4,0,27,9], +"structDecodeSignal.html#a58cf5844f2272a23dcb9687d912e4780":[4,0,27,1], +"structDecodeSignal.html#a822155d9bf4ed5f3300c9e9befe606ff":[4,0,27,12], +"structDecodeSignal.html#a92db637af4e224a0ae70173050dc3f74":[4,0,27,7], +"structDecodeSignal.html#a9d37638129263b8902ba5be59baf39a8":[4,0,27,5], +"structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d":[4,0,27,2], +"structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa":[4,0,27,11], +"structDecodeSignal.html#abdc4c4bb4a67a6d61d6ca81e8a52833d":[4,0,27,4], +"structDecodeSignal.html#acd4ef5ee30421d117b5756854302debb":[4,0,27,3], +"structDecodeSignal.html#ae28c905d4a2bc86419c2a8361bfea473":[4,0,27,13], +"structDecodeSignal.html#aea41c055cb255fe7bd178ed5727f28c9":[4,0,27,0], +"structDecodedFrameValue.html":[4,0,24], +"structDecodedFrameValue.html#a32143efe2023a1ecd977a9ae93e50b73":[4,0,24,1], +"structDecodedFrameValue.html#a33e971ba10030506007aa201c89f351d":[4,0,24,0], +"structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0":[4,0,24,3], +"structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9":[4,0,24,4], +"structDecodedFrameValue.html#adae123ac7fbb4a5c314b64b01109f4a8":[4,0,24,2], +"structDecodedSignalValue.html":[4,0,25], +"structDecodedSignalValue.html#a33df0fcd92b23b3e08539906fc6b4c4a":[4,0,25,2], +"structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28":[4,0,25,3], +"structDecodedSignalValue.html#a6847d05b3cb00d5e0f6c611968f57978":[4,0,25,4], +"structDecodedSignalValue.html#a828b5ef7faefc14fbf5dbd46249bcad2":[4,0,25,1], +"structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6":[4,0,25,6], +"structDecodedSignalValue.html#aac0ed361af545cde48d0e6f41a859686":[4,0,25,5], +"structDecodedSignalValue.html#affc38af1bf31bcb6f2c33044bce92bd2":[4,0,25,0], +"structFrameInfo.html":[4,0,28], +"structFrameInfo.html#a099f02a77adfb9ac23e286ce75f4eef4":[4,0,28,10], +"structFrameInfo.html#a34b726afaad2ac5c697fdb2ac070cdaf":[4,0,28,2], +"structFrameInfo.html#a35bf839519ef3f48b5f52dd9bcd7e9ac":[4,0,28,9], +"structFrameInfo.html#a3f7e25d67ddae22f2ed50823a5a26084":[4,0,28,8], +"structFrameInfo.html#a4737a5420213ad4304724e39f3a4e55d":[4,0,28,4], +"structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8":[4,0,28,6], +"structFrameInfo.html#a9ef2736053b593cf34ba2608cf8275c0":[4,0,28,11], +"structFrameInfo.html#aa2b198ea0f55e560c123d35e7b3ecab9":[4,0,28,5], +"structFrameInfo.html#abb53a7f93ed7abc0ea1ae4a8ccafcdcb":[4,0,28,0], +"structFrameInfo.html#ace75121294f9d89b762080ab5643293c":[4,0,28,7], +"structFrameInfo.html#aee518b33f1000bf0b7f6e4a87474c943":[4,0,28,3], +"structFrameInfo.html#af470b0742c05bfbffc31c51a68f5c05e":[4,0,28,1], +"structFrameKey.html":[4,0,29], +"structFrameKey.html#a022917652b4d3c2f2dfcc5a13ab7caa4":[4,0,29,2], +"structFrameKey.html#a33bde405c7ea53000d54b3dd6e058670":[4,0,29,0], +"structFrameKey.html#aa3179b709d02ef70cf0e736f040a2145":[4,0,29,3], +"structFrameKey.html#aaaec9f914e127787247fcda5e183b01f":[4,0,29,1], +"structFrameKeyHasher.html":[4,0,30], +"structFrameKeyHasher.html#a1612ce56b513790e3ed4c06ec7d28b9f":[4,0,30,0], +"structMultiplexRange.html":[4,0,32], +"structMultiplexing.html":[4,0,31], +"structMultiplexing.html#a79158d4fdbfd68a3d51a8ce79d34fd67":[4,0,31,0], +"structMultiplexing.html#aa174ac4a3af9b361d2de7517dfd4b69e":[4,0,31,2], +"structMultiplexing.html#aa91e54403c78a663686b2fd22282afaf":[4,0,31,1], +"structPendingAttribute.html":[4,0,33], +"structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8":[4,0,33,0], +"structPendingAttribute.html#a9a68a0a54c313c3e43dfdcd6e7a55da9":[4,0,33,1], +"structPendingComment.html":[4,0,34], +"structPendingComment.html#a29a3733e0a4c8ae341695db3d21d9249":[4,0,34,5], +"structPendingComment.html#a6d1c3b1e149bb602a95224446709c771":[4,0,34,0], +"structPendingComment.html#a9abd7e15ed59eb4534c66ff74f276e07":[4,0,34,1], +"structPendingComment.html#aa344393f67770e12449a4f14f6fcf10b":[4,0,34,4], +"structPendingComment.html#ac03903ffb042d27ad66012eb18ea1437":[4,0,34,2], +"structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27":[4,0,34,3], +"structPendingMultiplexing.html":[4,0,35], +"structPendingValueDescriptions.html":[4,0,36], +"structPendingValueDescriptions.html#a10ecbaeaed2cc3ac82fada73e7e041dd":[4,0,36,3], +"structPendingValueDescriptions.html#a5c19cff09b0e83bd3cd6085213c17da8":[4,0,36,4], +"structPendingValueDescriptions.html#a5f0082ceeaee77e2f823661547aad844":[4,0,36,0], +"structPendingValueDescriptions.html#a60f185e8d91010927c4aa3b4a750c9f4":[4,0,36,1], +"structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90":[4,0,36,2], +"structPgnLookupResult.html":[4,0,37], +"structPgnLookupResult.html#a6158833782348b3cc26037c2091fcc36":[4,0,37,1], +"structPgnLookupResult.html#aa5b79b61d2aef48fd6ae070cf5f901c1":[4,0,37,0], +"structRawCanFrame.html":[4,0,38], +"structRawCanFrame.html#a0acb487612104c99c9907344c035df83":[4,0,38,2], +"structRawCanFrame.html#a2d0e7fa0e3d5c20bbed55ed8f7888ff4":[4,0,38,0], +"structRawCanFrame.html#a462193d275adc1dba8bd18ffa0e36bb7":[4,0,38,1], +"structSignalInfo.html":[4,0,39], +"structSignalInfo.html#a1008b5201f71848177217bd52fb84baa":[4,0,39,3], +"structSignalInfo.html#a1f214f03e94ef5794de2d3367bfcbd01":[4,0,39,10], +"structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3":[4,0,39,11], +"structSignalInfo.html#a379e422a00cad56f896cacf60455b088":[4,0,39,1], +"structSignalInfo.html#a43f47d0433d0cc39076bd7278b46af9c":[4,0,39,12], +"structSignalInfo.html#a52a52b320eef92fbcb4626307f9a498f":[4,0,39,5], +"structSignalInfo.html#a781766eddbf6641071623c8e5b9acb4a":[4,0,39,14], +"structSignalInfo.html#a8a2e29f307c75926a1bd824266d23ca8":[4,0,39,0], +"structSignalInfo.html#ab7d0769f47aa540656b22e4e49db517e":[4,0,39,7], +"structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5":[4,0,39,13], +"structSignalInfo.html#ace290724f9801521609aedaa946d61f1":[4,0,39,2], +"structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b":[4,0,39,8], +"structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52":[4,0,39,9], +"structSignalInfo.html#ae4f78d99a2750aa564d7eba860171499":[4,0,39,6], +"structSignalInfo.html#af363b1563fb4c7cc8973f9a80c06846c":[4,0,39,4], +"structSignalKey.html":[4,0,40], +"structSignalKey.html#a17525dc0116be7f4f58f3c3fae1022e2":[4,0,40,1], +"structSignalKey.html#a25f4ece1bf685791b576f68e23d8ccc7":[4,0,40,2], +"structSignalKey.html#aa4221b34e75469bf5aa939976c334f46":[4,0,40,0], +"structSignalKey.html#abab371cce740f05111fd3b4013ca6944":[4,0,40,3], +"structSignalKeyHasher.html":[4,0,41], +"structSignalKeyHasher.html#af8869bcb714857af7ad005fbd13bea80":[4,0,41,0], "tests_2main_8cpp_source.html":[5,0,3,7], -"text__utils_8h_source.html":[5,0,0,22], -"tree__node_8cpp.html":[5,0,0,23], -"tree__node_8cpp_source.html":[5,0,0,23], -"tree__node_8h.html":[5,0,0,24], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16":[5,0,0,24,1], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a085fea7abdc5d904fe69a3081efd7398":[5,0,0,24,1,2], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a3bb3e8c8a24891ba0f7608bcc96f8b0a":[5,0,0,24,1,1], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16afa03eb688ad8aa1db593d33dabd89bad":[5,0,0,24,1,0], -"tree__node_8h_source.html":[5,0,0,24], +"text__utils_8h_source.html":[5,0,0,23], +"tree__node_8cpp.html":[5,0,0,24], +"tree__node_8cpp_source.html":[5,0,0,24], +"tree__node_8h.html":[5,0,0,25], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16":[5,0,0,25,1], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a085fea7abdc5d904fe69a3081efd7398":[5,0,0,25,1,2], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a3bb3e8c8a24891ba0f7608bcc96f8b0a":[5,0,0,25,1,1], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16afa03eb688ad8aa1db593d33dabd89bad":[5,0,0,25,1,0], +"tree__node_8h_source.html":[5,0,0,25], "tree__node__test_8cpp_source.html":[5,0,3,8], -"typefactory_8h_source.html":[5,0,0,25], -"value__descriptions_8h_source.html":[5,0,0,26] +"typefactory_8h_source.html":[5,0,0,26], +"value__descriptions_8h_source.html":[5,0,0,27] }; diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js index 7c8683e..1adb66c 100644 --- a/docs/html/search/all_0.js +++ b/docs/html/search/all_0.js @@ -1,10 +1,10 @@ var searchData= [ - ['0_20—_202026_2006_2014_0',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md37',1,'']]], - ['01_1',['2026-10-01',['../md_changelog.html#autotoc_md34',1,'']]], - ['03_2013_2',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md39',1,'']]], - ['05_3',['2026-10-05',['../md_changelog.html#autotoc_md30',1,'']]], - ['06_4',['2026-10-06',['../md_changelog.html#autotoc_md28',1,'']]], - ['06_2014_5',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md37',1,'']]], - ['07_6',['2026-10-07',['../md_changelog.html#autotoc_md24',1,'']]] + ['0_20—_202026_2006_2014_0',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md41',1,'']]], + ['01_1',['2026-10-01',['../md_changelog.html#autotoc_md38',1,'']]], + ['03_2013_2',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md43',1,'']]], + ['05_3',['2026-10-05',['../md_changelog.html#autotoc_md34',1,'']]], + ['06_4',['2026-10-06',['../md_changelog.html#autotoc_md32',1,'']]], + ['06_2014_5',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md41',1,'']]], + ['07_6',['2026-10-07',['../md_changelog.html#autotoc_md28',1,'']]] ]; diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js index 557e2f6..6f55bde 100644 --- a/docs/html/search/all_1.js +++ b/docs/html/search/all_1.js @@ -1,16 +1,17 @@ var searchData= [ - ['1_20already_20implemented_0',['Stage 1 - already implemented',['../md_README.html#autotoc_md137',1,'']]], - ['1_20parse_20and_20ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md46',1,'']]], - ['10_2001_2',['2026-10-01',['../md_changelog.html#autotoc_md34',1,'']]], - ['10_2005_3',['2026-10-05',['../md_changelog.html#autotoc_md30',1,'']]], - ['10_2006_4',['2026-10-06',['../md_changelog.html#autotoc_md28',1,'']]], - ['10_2007_5',['2026-10-07',['../md_changelog.html#autotoc_md24',1,'']]], - ['10_2011_6',['2026-10-11',['../md_changelog.html#autotoc_md21',1,'']]], - ['10_2013_7',['2026-10-13',['../md_changelog.html#autotoc_md18',1,'']]], - ['10_2014_8',['2026-10-14',['../md_changelog.html#autotoc_md14',1,'']]], - ['10_2020_9',['2026-10-20',['../md_changelog.html#autotoc_md8',1,'']]], - ['11_10',['2026-10-11',['../md_changelog.html#autotoc_md21',1,'']]], - ['13_11',['13',['../md_changelog.html#autotoc_md18',1,'2026-10-13'],['../md_changelog.html#autotoc_md39',1,'Initial implementation — 2026-03-13']]], - ['14_12',['14',['../md_changelog.html#autotoc_md14',1,'2026-10-14'],['../md_changelog.html#autotoc_md37',1,'v1.0 — 2026-06-14']]] + ['1_20already_20implemented_0',['Stage 1 - already implemented',['../md_README.html#autotoc_md141',1,'']]], + ['1_20parse_20and_20ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md50',1,'']]], + ['10_2001_2',['2026-10-01',['../md_changelog.html#autotoc_md38',1,'']]], + ['10_2005_3',['2026-10-05',['../md_changelog.html#autotoc_md34',1,'']]], + ['10_2006_4',['2026-10-06',['../md_changelog.html#autotoc_md32',1,'']]], + ['10_2007_5',['2026-10-07',['../md_changelog.html#autotoc_md28',1,'']]], + ['10_2011_6',['2026-10-11',['../md_changelog.html#autotoc_md25',1,'']]], + ['10_2013_7',['2026-10-13',['../md_changelog.html#autotoc_md22',1,'']]], + ['10_2014_8',['2026-10-14',['../md_changelog.html#autotoc_md18',1,'']]], + ['10_2020_9',['2026-10-20',['../md_changelog.html#autotoc_md12',1,'']]], + ['10_2023_10',['2026-10-23',['../md_changelog.html#autotoc_md8',1,'']]], + ['11_11',['2026-10-11',['../md_changelog.html#autotoc_md25',1,'']]], + ['13_12',['13',['../md_changelog.html#autotoc_md22',1,'2026-10-13'],['../md_changelog.html#autotoc_md43',1,'Initial implementation — 2026-03-13']]], + ['14_13',['14',['../md_changelog.html#autotoc_md18',1,'2026-10-14'],['../md_changelog.html#autotoc_md41',1,'v1.0 — 2026-06-14']]] ]; diff --git a/docs/html/search/all_10.js b/docs/html/search/all_10.js index 8c2397b..0766dae 100644 --- a/docs/html/search/all_10.js +++ b/docs/html/search/all_10.js @@ -1,15 +1,17 @@ var searchData= [ - ['layer_0',['layer',['../md_README.html#autotoc_md78',1,'Decoder Layer'],['../md_README.html#autotoc_md63',1,'Runtime Decode Layer'],['../md_README.html#autotoc_md60',1,'UI Tree Layer']]], - ['layer_20exists_1',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], - ['layout_2',['Module Layout',['../md_README.html#autotoc_md51',1,'']]], - ['lcov_20on_20debian_20ubuntu_3',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], + ['layer_0',['layer',['../md_README.html#autotoc_md82',1,'Decoder Layer'],['../md_README.html#autotoc_md67',1,'Runtime Decode Layer'],['../md_README.html#autotoc_md64',1,'UI Tree Layer']]], + ['layer_20exists_1',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], + ['layout_2',['Module Layout',['../md_README.html#autotoc_md55',1,'']]], + ['lcov_20on_20debian_20ubuntu_3',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], ['length_4',['length',['../structSignalInfo.html#a1008b5201f71848177217bd52fb84baa',1,'SignalInfo::length'],['../structDecodeSignal.html#acd4ef5ee30421d117b5756854302debb',1,'DecodeSignal::length']]], - ['level_20architecture_5',['High-Level Architecture',['../md_README.html#autotoc_md45',1,'']]], - ['libraries_6',['Build core without Qt libraries',['../md_README.html#autotoc_md143',1,'']]], - ['lifetime_20and_20reload_20coverage_7',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md160',1,'']]], - ['limitations_8',['Current Limitations',['../md_README.html#autotoc_md134',1,'']]], + ['level_20architecture_5',['High-Level Architecture',['../md_README.html#autotoc_md49',1,'']]], + ['libraries_6',['Build core without Qt libraries',['../md_README.html#autotoc_md148',1,'']]], + ['lifetime_20and_20reload_20coverage_7',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md166',1,'']]], + ['limitations_8',['Current Limitations',['../md_README.html#autotoc_md138',1,'']]], ['linenumber_9',['linenumber',['../structDbcParseContext.html#a57f5a7f613ecd0dadbafa7af736b7e54',1,'DbcParseContext::lineNumber'],['../structPendingAttribute.html#a9a68a0a54c313c3e43dfdcd6e7a55da9',1,'PendingAttribute::lineNumber'],['../structPendingComment.html#a29a3733e0a4c8ae341695db3d21d9249',1,'PendingComment::lineNumber'],['../structPendingValueDescriptions.html#a5c19cff09b0e83bd3cd6085213c17da8',1,'PendingValueDescriptions::lineNumber'],['../structDbcDiagnostic.html#adb201de8d32b768d5f559bed21e8f819',1,'DbcDiagnostic::lineNumber']]], - ['live_20path_10',['live path',['../md_README.html#autotoc_md123',1,'']]], - ['lookup_11',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]] + ['live_20path_10',['live path',['../md_README.html#autotoc_md127',1,'']]], + ['local_20core_20regression_20checks_11',['Local core regression checks',['../md_README.html#autotoc_md147',1,'']]], + ['local_20regression_20checks_12',['Local regression checks',['../md_tests_2README.html#autotoc_md161',1,'']]], + ['lookup_13',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]] ]; diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index 4cad4de..18a1b68 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -1,16 +1,19 @@ var searchData= [ ['main_0',['main',['../examples_2main_8cpp.html#a0ddf1224851353fc92bfbff6f499fa97',1,'main.cpp']]], - ['maintenance_1',['maintenance',['../md_changelog.html#autotoc_md33',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md41',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md9',1,'Maintenance']]], + ['maintenance_1',['maintenance',['../md_changelog.html#autotoc_md45',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md37',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md13',1,'Maintenance']]], ['maximum_2',['maximum',['../structAttributeDefinition.html#aa02fe74b5420c2e67c13e610b6bc9713',1,'AttributeDefinition::maximum'],['../structDecodeSignal.html#a4a6ba87142a9badbf0ca830e9e709cb7',1,'DecodeSignal::maximum'],['../structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52',1,'SignalInfo::maximum']]], - ['measuring_20code_20coverage_3',['Measuring code coverage',['../md_README.html#autotoc_md151',1,'']]], + ['measuring_20code_20coverage_3',['Measuring code coverage',['../md_README.html#autotoc_md156',1,'']]], ['message_4',['message',['../structDbcDiagnostic.html#a124bae82eebeaef46426bd124685ef1b',1,'DbcDiagnostic']]], - ['metadata_5',['Attributes and frame metadata',['../md_README.html#autotoc_md93',1,'']]], - ['minimum_6',['minimum',['../structAttributeDefinition.html#a18245dba995929a61fd6de1fcdbc8a89',1,'AttributeDefinition::minimum'],['../structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25',1,'DecodeSignal::minimum'],['../structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b',1,'SignalInfo::minimum']]], - ['model_20adapter_7',['Optional Qt model adapter',['../md_README.html#autotoc_md144',1,'']]], - ['model_20tests_8',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md158',1,'']]], + ['metadata_5',['Attributes and frame metadata',['../md_README.html#autotoc_md97',1,'']]], + ['minimum_6',['minimum',['../structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b',1,'SignalInfo::minimum'],['../structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25',1,'DecodeSignal::minimum'],['../structAttributeDefinition.html#a18245dba995929a61fd6de1fcdbc8a89',1,'AttributeDefinition::minimum']]], + ['model_20adapter_7',['Optional Qt model adapter',['../md_README.html#autotoc_md149',1,'']]], + ['model_20tests_8',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md164',1,'']]], ['module_20documentation_9',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['module_20layout_10',['Module Layout',['../md_README.html#autotoc_md51',1,'']]], - ['motorola_20extraction_11',['Intel and Motorola Extraction',['../md_README.html#autotoc_md114',1,'']]], - ['multiplexing_12',['multiplexing',['../md_README.html#autotoc_md104',1,'Basic multiplexing'],['../structSignalInfo.html#a8a2e29f307c75926a1bd824266d23ca8',1,'SignalInfo::multiplexing'],['../structDecodeSignal.html#aea41c055cb255fe7bd178ed5727f28c9',1,'DecodeSignal::multiplexing'],['../structMultiplexing.html',1,'Multiplexing']]] + ['module_20layout_10',['Module Layout',['../md_README.html#autotoc_md55',1,'']]], + ['motorola_20extraction_11',['Intel and Motorola Extraction',['../md_README.html#autotoc_md118',1,'']]], + ['multiplexerror_12',['MultiplexError',['../classdbc__detail_1_1MultiplexError.html',1,'dbc_detail']]], + ['multiplexgraph_13',['MultiplexGraph',['../classdbc__detail_1_1MultiplexGraph.html',1,'dbc_detail']]], + ['multiplexing_14',['multiplexing',['../md_README.html#autotoc_md108',1,'Multiplexing'],['../structSignalInfo.html#a8a2e29f307c75926a1bd824266d23ca8',1,'SignalInfo::multiplexing'],['../structDecodeSignal.html#aea41c055cb255fe7bd178ed5727f28c9',1,'DecodeSignal::multiplexing'],['../structMultiplexing.html',1,'Multiplexing']]], + ['multiplexrange_15',['MultiplexRange',['../structMultiplexRange.html',1,'']]] ]; diff --git a/docs/html/search/all_12.js b/docs/html/search/all_12.js index 79c88d9..26fc0c0 100644 --- a/docs/html/search/all_12.js +++ b/docs/html/search/all_12.js @@ -1,8 +1,8 @@ var searchData= [ ['name_0',['name',['../structAttributeAssignment.html#aa8707eddd2d3a2de559fe44354a514cc',1,'AttributeAssignment::name'],['../structDecodeSignal.html#a58cf5844f2272a23dcb9687d912e4780',1,'DecodeSignal::name'],['../structDecodeFrame.html#aa0a7f8fd5bfde2148dfd0d838328f579',1,'DecodeFrame::name'],['../structSignalKey.html#abab371cce740f05111fd3b4013ca6944',1,'SignalKey::name'],['../structFrameInfo.html#abb53a7f93ed7abc0ea1ae4a8ccafcdcb',1,'FrameInfo::name'],['../structSignalInfo.html#a379e422a00cad56f896cacf60455b088',1,'SignalInfo::name']]], - ['next_20steps_1',['Recommended Next Steps',['../md_README.html#autotoc_md136',1,'']]], + ['next_20steps_1',['Recommended Next Steps',['../md_README.html#autotoc_md140',1,'']]], ['nodetype_2',['NodeType',['../tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16',1,'tree_node.h']]], - ['normalization_3',['CAN ID Normalization',['../md_README.html#autotoc_md108',1,'']]], - ['not_20enough_4',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]] + ['normalization_3',['CAN ID Normalization',['../md_README.html#autotoc_md112',1,'']]], + ['not_20enough_4',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]] ]; diff --git a/docs/html/search/all_13.js b/docs/html/search/all_13.js index 9961e80..3c32ba0 100644 --- a/docs/html/search/all_13.js +++ b/docs/html/search/all_13.js @@ -1,12 +1,12 @@ var searchData= [ ['offset_0',['offset',['../structDecodeSignal.html#a92db637af4e224a0ae70173050dc3f74',1,'DecodeSignal::offset'],['../structSignalInfo.html#ab7d0769f47aa540656b22e4e49db517e',1,'SignalInfo::offset']]], - ['on_20debian_20ubuntu_1',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], + ['on_20debian_20ubuntu_1',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], ['operator_28_29_2',['operator()',['../structFrameKeyHasher.html#a1612ce56b513790e3ed4c06ec7d28b9f',1,'FrameKeyHasher::operator()()'],['../structSignalKeyHasher.html#af8869bcb714857af7ad005fbd13bea80',1,'SignalKeyHasher::operator()()']]], ['operator_3d_3d_3',['operator==',['../structFrameKey.html#aaaec9f914e127787247fcda5e183b01f',1,'FrameKey::operator==()'],['../structSignalKey.html#a17525dc0116be7f4f58f3c3fae1022e2',1,'SignalKey::operator==()']]], - ['opt_20in_20and_20pgn_20lookup_4',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]], - ['optional_20model_20tests_5',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md158',1,'']]], - ['optional_20qt_20model_20adapter_6',['Optional Qt model adapter',['../md_README.html#autotoc_md144',1,'']]], - ['overview_7',['Overview',['../md_README.html#autotoc_md43',1,'']]], - ['ownership_20and_20reload_8',['Definition ownership and reload',['../md_README.html#autotoc_md86',1,'']]] + ['opt_20in_20and_20pgn_20lookup_4',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]], + ['optional_20model_20tests_5',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md164',1,'']]], + ['optional_20qt_20model_20adapter_6',['Optional Qt model adapter',['../md_README.html#autotoc_md149',1,'']]], + ['overview_7',['Overview',['../md_README.html#autotoc_md47',1,'']]], + ['ownership_20and_20reload_8',['Definition ownership and reload',['../md_README.html#autotoc_md90',1,'']]] ]; diff --git a/docs/html/search/all_14.js b/docs/html/search/all_14.js index 59860d0..a8966b5 100644 --- a/docs/html/search/all_14.js +++ b/docs/html/search/all_14.js @@ -1,28 +1,29 @@ var searchData= [ ['parent_0',['parent',['../classDbcTreeModel.html#ae40bb8b8a26d205f178c6dd1134ff4b3',1,'DbcTreeModel']]], - ['parse_20and_20ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md46',1,'']]], - ['parse_20dbc_2',['Parse DBC',['../md_README.html#autotoc_md117',1,'']]], - ['parse_20errors_3',['parse errors',['../md_README.html#autotoc_md98',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md102',1,'Signal validation and parse errors']]], - ['parsed_20data_20structures_4',['Parsed Data Structures',['../md_README.html#autotoc_md53',1,'']]], + ['parse_20and_20ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md50',1,'']]], + ['parse_20dbc_2',['Parse DBC',['../md_README.html#autotoc_md121',1,'']]], + ['parse_20errors_3',['parse errors',['../md_README.html#autotoc_md102',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md106',1,'Signal validation and parse errors']]], + ['parsed_20data_20structures_4',['Parsed Data Structures',['../md_README.html#autotoc_md57',1,'']]], ['parsefile_5',['ParseFile',['../classDbcParser.html#aef72826942c9095d653fafa435855e56',1,'DbcParser']]], ['parsefilewithdiagnostics_6',['ParseFileWithDiagnostics',['../classDbcParser.html#a0e915ce79c2e3d4c95a5aaf2bf0409bc',1,'DbcParser']]], ['parser_20and_20runtime_20decode_20module_20documentation_7',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['parser_20coverage_8',['Parser coverage',['../md_tests_2README.html#autotoc_md157',1,'']]], - ['parser_20support_9',['Parser Support',['../md_README.html#autotoc_md91',1,'']]], - ['path_10',['path',['../md_README.html#autotoc_md46',1,'1. Parse and UI path'],['../md_README.html#autotoc_md47',1,'2. Runtime decode path'],['../md_README.html#autotoc_md123',1,'live path'],['../md_README.html#autotoc_md124',1,'trace path']]], + ['parser_20coverage_8',['Parser coverage',['../md_tests_2README.html#autotoc_md163',1,'']]], + ['parser_20support_9',['Parser Support',['../md_README.html#autotoc_md95',1,'']]], + ['path_10',['path',['../md_README.html#autotoc_md50',1,'1. Parse and UI path'],['../md_README.html#autotoc_md51',1,'2. Runtime decode path'],['../md_README.html#autotoc_md127',1,'live path'],['../md_README.html#autotoc_md128',1,'trace path']]], ['pendingattribute_11',['PendingAttribute',['../structPendingAttribute.html',1,'']]], ['pendingattributes_12',['pendingAttributes',['../structDbcParseContext.html#afbfa4b26a58b41ada3dabc619066035c',1,'DbcParseContext']]], ['pendingcomment_13',['PendingComment',['../structPendingComment.html',1,'']]], ['pendingcomments_14',['pendingComments',['../structDbcParseContext.html#a854abba7bbf4adfc948554c254156e60',1,'DbcParseContext']]], - ['pendingvaluedescriptions_15',['PendingValueDescriptions',['../structPendingValueDescriptions.html',1,'']]], - ['pendingvalues_16',['pendingValues',['../structDbcParseContext.html#ac22cba614ada3a28c7dcc1ea338b0e01',1,'DbcParseContext']]], - ['pgn_17',['pgn',['../structFrameInfo.html#aee518b33f1000bf0b7f6e4a87474c943',1,'FrameInfo::pgn'],['../structDecodeFrame.html#a1d3c54055c0cbceb73adf551f7067f23',1,'DecodeFrame::pgn']]], - ['pgn_20lookup_18',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]], - ['pgnlookupresult_19',['PgnLookupResult',['../structPgnLookupResult.html',1,'']]], - ['physicalvalue_20',['physicalValue',['../structDecodedSignalValue.html#a6847d05b3cb00d5e0f6c611968f57978',1,'DecodedSignalValue']]], - ['pipeline_20coverage_21',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md162',1,'']]], - ['precision_22',['Raw value representation and precision',['../md_README.html#autotoc_md83',1,'']]], - ['public_23',['public',['../structFrameInfo.html#a3f7e25d67ddae22f2ed50823a5a26084',1,'FrameInfo::public'],['../structDecodeFrame.html#a7f4e71bbdec3f424b625e724e3dfbf14',1,'DecodeFrame::public'],['../structDecodedFrameValue.html#adae123ac7fbb4a5c314b64b01109f4a8',1,'DecodedFrameValue::public']]], - ['purpose_24',['Purpose',['../md_README.html#autotoc_md64',1,'']]] + ['pendingmultiplexing_15',['PendingMultiplexing',['../structPendingMultiplexing.html',1,'']]], + ['pendingvaluedescriptions_16',['PendingValueDescriptions',['../structPendingValueDescriptions.html',1,'']]], + ['pendingvalues_17',['pendingValues',['../structDbcParseContext.html#ac22cba614ada3a28c7dcc1ea338b0e01',1,'DbcParseContext']]], + ['pgn_18',['pgn',['../structFrameInfo.html#aee518b33f1000bf0b7f6e4a87474c943',1,'FrameInfo::pgn'],['../structDecodeFrame.html#a1d3c54055c0cbceb73adf551f7067f23',1,'DecodeFrame::pgn']]], + ['pgn_20lookup_19',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]], + ['pgnlookupresult_20',['PgnLookupResult',['../structPgnLookupResult.html',1,'']]], + ['physicalvalue_21',['physicalValue',['../structDecodedSignalValue.html#a6847d05b3cb00d5e0f6c611968f57978',1,'DecodedSignalValue']]], + ['pipeline_20coverage_22',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md168',1,'']]], + ['precision_23',['Raw value representation and precision',['../md_README.html#autotoc_md87',1,'']]], + ['public_24',['public',['../structFrameInfo.html#a3f7e25d67ddae22f2ed50823a5a26084',1,'FrameInfo::public'],['../structDecodeFrame.html#a7f4e71bbdec3f424b625e724e3dfbf14',1,'DecodeFrame::public'],['../structDecodedFrameValue.html#adae123ac7fbb4a5c314b64b01109f4a8',1,'DecodedFrameValue::public']]], + ['purpose_25',['Purpose',['../md_README.html#autotoc_md68',1,'']]] ]; diff --git a/docs/html/search/all_15.js b/docs/html/search/all_15.js index d18cb30..b6dacda 100644 --- a/docs/html/search/all_15.js +++ b/docs/html/search/all_15.js @@ -1,8 +1,8 @@ var searchData= [ - ['qt_0',['Standalone tree tests without Qt',['../md_README.html#autotoc_md145',1,'']]], - ['qt_20creator_1',['qt creator',['../md_README.html#autotoc_md154',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md153',1,'Configure the GCC coverage build in Qt Creator']]], - ['qt_20libraries_2',['Build core without Qt libraries',['../md_README.html#autotoc_md143',1,'']]], - ['qt_20model_20adapter_3',['Optional Qt model adapter',['../md_README.html#autotoc_md144',1,'']]], + ['qt_0',['Standalone tree tests without Qt',['../md_README.html#autotoc_md150',1,'']]], + ['qt_20creator_1',['qt creator',['../md_README.html#autotoc_md159',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md158',1,'Configure the GCC coverage build in Qt Creator']]], + ['qt_20libraries_2',['Build core without Qt libraries',['../md_README.html#autotoc_md148',1,'']]], + ['qt_20model_20adapter_3',['Optional Qt model adapter',['../md_README.html#autotoc_md149',1,'']]], ['qttest_20regression_20tests_4',['QtTest regression tests',['../md_tests_2README.html',1,'']]] ]; diff --git a/docs/html/search/all_16.js b/docs/html/search/all_16.js index dbac0ed..fd17ede 100644 --- a/docs/html/search/all_16.js +++ b/docs/html/search/all_16.js @@ -1,28 +1,30 @@ var searchData= [ - ['raw_20frame_0',['Decode a raw frame',['../md_README.html#autotoc_md120',1,'']]], - ['raw_20value_20representation_20and_20precision_1',['Raw value representation and precision',['../md_README.html#autotoc_md83',1,'']]], - ['rawcanframe_2',['RawCanFrame',['../structRawCanFrame.html',1,'']]], - ['rawcanframe_20tt_3',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md79',1,'']]], - ['rawvalue_4',['rawValue',['../structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28',1,'DecodedSignalValue']]], - ['receivers_5',['receivers',['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers'],['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers']]], - ['recommended_20next_20steps_6',['Recommended Next Steps',['../md_README.html#autotoc_md136',1,'']]], - ['registertype_7',['registertype',['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory::registerType()'],['../classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d',1,'DbcStatementDispatcher::RegisterType()']]], - ['regression_20coverage_8',['Additional regression coverage',['../md_tests_2README.html#autotoc_md159',1,'']]], - ['regression_20tests_9',['regression tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md149',1,'Regression tests']]], - ['reload_10',['Definition ownership and reload',['../md_README.html#autotoc_md86',1,'']]], - ['reload_20coverage_11',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md160',1,'']]], - ['representation_20and_20precision_12',['Raw value representation and precision',['../md_README.html#autotoc_md83',1,'']]], - ['resolveattributes_13',['ResolveAttributes',['../structDbcParseContext.html#a1ac7f4a54550aaddef08749806f87001',1,'DbcParseContext']]], - ['resolvecomments_14',['ResolveComments',['../structDbcParseContext.html#aeae343c57a244634489a0e0b960155d7',1,'DbcParseContext']]], - ['resolvevaluedescriptions_15',['ResolveValueDescriptions',['../structDbcParseContext.html#ab5552dad944fde7fa6add6464ddb5369',1,'DbcParseContext']]], - ['review_20and_20additional_20checks_16',['Code review and additional checks',['../md_README.html#autotoc_md150',1,'']]], - ['role_17',['role',['../classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfd',1,'DbcTreeModel::Role'],['../structMultiplexing.html#a62b70a0e3f2a9c7a457b3694ce8625c3',1,'Multiplexing::role']]], - ['rowcount_18',['rowCount',['../classDbcTreeModel.html#a30bed0d65342917c19d9183da55af452',1,'DbcTreeModel']]], - ['run_20the_20demo_19',['Build and run the demo',['../md_README.html#autotoc_md146',1,'']]], - ['runtime_20decode_20database_20',['Build runtime decode database',['../md_README.html#autotoc_md119',1,'']]], - ['runtime_20decode_20layer_21',['Runtime Decode Layer',['../md_README.html#autotoc_md63',1,'']]], - ['runtime_20decode_20layer_20exists_22',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], - ['runtime_20decode_20module_20documentation_23',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['runtime_20decode_20path_24',['2. Runtime decode path',['../md_README.html#autotoc_md47',1,'']]] + ['ranges_0',['ranges',['../structMultiplexing.html#aa174ac4a3af9b361d2de7517dfd4b69e',1,'Multiplexing']]], + ['raw_20frame_1',['Decode a raw frame',['../md_README.html#autotoc_md124',1,'']]], + ['raw_20value_20representation_20and_20precision_2',['Raw value representation and precision',['../md_README.html#autotoc_md87',1,'']]], + ['rawcanframe_3',['RawCanFrame',['../structRawCanFrame.html',1,'']]], + ['rawcanframe_20tt_4',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md83',1,'']]], + ['rawvalue_5',['rawValue',['../structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28',1,'DecodedSignalValue']]], + ['receivers_6',['receivers',['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers'],['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers']]], + ['recommended_20next_20steps_7',['Recommended Next Steps',['../md_README.html#autotoc_md140',1,'']]], + ['registertype_8',['registertype',['../classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d',1,'DbcStatementDispatcher::RegisterType()'],['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory::registerType()']]], + ['regression_20checks_9',['regression checks',['../md_README.html#autotoc_md147',1,'Local core regression checks'],['../md_tests_2README.html#autotoc_md161',1,'Local regression checks']]], + ['regression_20coverage_10',['Additional regression coverage',['../md_tests_2README.html#autotoc_md165',1,'']]], + ['regression_20tests_11',['regression tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md154',1,'Regression tests']]], + ['reload_12',['Definition ownership and reload',['../md_README.html#autotoc_md90',1,'']]], + ['reload_20coverage_13',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md166',1,'']]], + ['representation_20and_20precision_14',['Raw value representation and precision',['../md_README.html#autotoc_md87',1,'']]], + ['resolveattributes_15',['ResolveAttributes',['../structDbcParseContext.html#a1ac7f4a54550aaddef08749806f87001',1,'DbcParseContext']]], + ['resolvecomments_16',['ResolveComments',['../structDbcParseContext.html#aeae343c57a244634489a0e0b960155d7',1,'DbcParseContext']]], + ['resolvevaluedescriptions_17',['ResolveValueDescriptions',['../structDbcParseContext.html#ab5552dad944fde7fa6add6464ddb5369',1,'DbcParseContext']]], + ['review_20and_20additional_20checks_18',['Code review and additional checks',['../md_README.html#autotoc_md155',1,'']]], + ['role_19',['Role',['../classDbcTreeModel.html#a0f360d424848c6c39f2312e6209b0dfd',1,'DbcTreeModel']]], + ['rowcount_20',['rowCount',['../classDbcTreeModel.html#a30bed0d65342917c19d9183da55af452',1,'DbcTreeModel']]], + ['run_20the_20demo_21',['Build and run the demo',['../md_README.html#autotoc_md151',1,'']]], + ['runtime_20decode_20database_22',['Build runtime decode database',['../md_README.html#autotoc_md123',1,'']]], + ['runtime_20decode_20layer_23',['Runtime Decode Layer',['../md_README.html#autotoc_md67',1,'']]], + ['runtime_20decode_20layer_20exists_24',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], + ['runtime_20decode_20module_20documentation_25',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], + ['runtime_20decode_20path_26',['2. Runtime decode path',['../md_README.html#autotoc_md51',1,'']]] ]; diff --git a/docs/html/search/all_17.js b/docs/html/search/all_17.js index 89d3df5..7a40ca7 100644 --- a/docs/html/search/all_17.js +++ b/docs/html/search/all_17.js @@ -1,35 +1,36 @@ var searchData= [ ['scope_0',['scope',['../structAttributeDefinition.html#a5f109f0ec94eb04c3f52c116366aefdf',1,'AttributeDefinition::scope'],['../structAttributeAssignment.html#a50405e8db9e4536015f9adc5ba360270',1,'AttributeAssignment::scope']]], - ['settree_1',['SetTree',['../classDbcTreeModel.html#a8cb5a81d456cdead42b75fd3462ee00a',1,'DbcTreeModel']]], - ['severity_2',['severity',['../structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d',1,'DbcDiagnostic']]], - ['signal_20definition_3',['Signal definition',['../md_README.html#autotoc_md100',1,'']]], - ['signal_20identifiers_4',['Stable frame and signal identifiers',['../md_README.html#autotoc_md87',1,'']]], - ['signal_20validation_20and_20parse_20errors_5',['Signal validation and parse errors',['../md_README.html#autotoc_md102',1,'']]], - ['signal_20value_20descriptions_20tt_20val_5f_20tt_6',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md132',1,'']]], - ['signal_5finfo_2eh_7',['signal_info.h',['../signal__info_8h.html',1,'']]], - ['signaldecodestatus_8',['SignalDecodeStatus',['../dbc__decoder_8h.html#a5f4a41ee2810487020135b45e8d7559a',1,'dbc_decoder.h']]], - ['signalinfo_9',['SignalInfo',['../structSignalInfo.html',1,'']]], - ['signalinfo_20tt_10',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md54',1,'']]], - ['signalkey_11',['signalkey',['../structSignalKey.html#aa4221b34e75469bf5aa939976c334f46',1,'SignalKey::SignalKey()'],['../structSignalKey.html',1,'SignalKey']]], - ['signalkeyhasher_12',['SignalKeyHasher',['../structSignalKeyHasher.html',1,'']]], - ['signallines_13',['signalLines',['../structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546',1,'DbcParseContext']]], - ['signalname_14',['signalname',['../structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27',1,'PendingComment::signalName'],['../structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90',1,'PendingValueDescriptions::signalName']]], - ['stable_20frame_20and_20signal_20identifiers_15',['Stable frame and signal identifiers',['../md_README.html#autotoc_md87',1,'']]], - ['stage_201_20already_20implemented_16',['Stage 1 - already implemented',['../md_README.html#autotoc_md137',1,'']]], - ['stage_202_17',['Stage 2',['../md_README.html#autotoc_md138',1,'']]], - ['stage_203_18',['Stage 3',['../md_README.html#autotoc_md139',1,'']]], - ['stage_204_19',['Stage 4',['../md_README.html#autotoc_md140',1,'']]], - ['standalone_20tree_20tests_20without_20qt_20',['Standalone tree tests without Qt',['../md_README.html#autotoc_md145',1,'']]], - ['startbit_21',['startbit',['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit'],['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit']]], - ['statement_22',['statement',['../structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8',1,'PendingAttribute']]], - ['statement_20handler_20factory_23',['Statement Handler Factory',['../md_README.html#autotoc_md130',1,'']]], - ['status_24',['status',['../structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9',1,'DecodedFrameValue::status'],['../structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6',1,'DecodedSignalValue::status']]], - ['steps_25',['Recommended Next Steps',['../md_README.html#autotoc_md136',1,'']]], - ['strategy_26',['Unified Decode Strategy',['../md_README.html#autotoc_md122',1,'']]], - ['structured_20diagnostics_27',['Structured diagnostics',['../md_README.html#autotoc_md92',1,'']]], - ['structures_28',['Parsed Data Structures',['../md_README.html#autotoc_md53',1,'']]], - ['support_29',['Parser Support',['../md_README.html#autotoc_md91',1,'']]], - ['supported_20dbc_20syntax_30',['Supported DBC Syntax',['../md_README.html#autotoc_md95',1,'']]], - ['syntax_31',['Supported DBC Syntax',['../md_README.html#autotoc_md95',1,'']]] + ['selector_1',['selector',['../structMultiplexing.html#aa91e54403c78a663686b2fd22282afaf',1,'Multiplexing']]], + ['settree_2',['SetTree',['../classDbcTreeModel.html#a8cb5a81d456cdead42b75fd3462ee00a',1,'DbcTreeModel']]], + ['severity_3',['severity',['../structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d',1,'DbcDiagnostic']]], + ['signal_20definition_4',['Signal definition',['../md_README.html#autotoc_md104',1,'']]], + ['signal_20identifiers_5',['Stable frame and signal identifiers',['../md_README.html#autotoc_md91',1,'']]], + ['signal_20validation_20and_20parse_20errors_6',['Signal validation and parse errors',['../md_README.html#autotoc_md106',1,'']]], + ['signal_20value_20descriptions_20tt_20val_5f_20tt_7',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md136',1,'']]], + ['signal_5finfo_2eh_8',['signal_info.h',['../signal__info_8h.html',1,'']]], + ['signaldecodestatus_9',['SignalDecodeStatus',['../dbc__decoder_8h.html#a5f4a41ee2810487020135b45e8d7559a',1,'dbc_decoder.h']]], + ['signalinfo_10',['SignalInfo',['../structSignalInfo.html',1,'']]], + ['signalinfo_20tt_11',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md58',1,'']]], + ['signalkey_12',['signalkey',['../structSignalKey.html',1,'SignalKey'],['../structSignalKey.html#aa4221b34e75469bf5aa939976c334f46',1,'SignalKey::SignalKey()']]], + ['signalkeyhasher_13',['SignalKeyHasher',['../structSignalKeyHasher.html',1,'']]], + ['signallines_14',['signalLines',['../structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546',1,'DbcParseContext']]], + ['signalname_15',['signalname',['../structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27',1,'PendingComment::signalName'],['../structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90',1,'PendingValueDescriptions::signalName']]], + ['stable_20frame_20and_20signal_20identifiers_16',['Stable frame and signal identifiers',['../md_README.html#autotoc_md91',1,'']]], + ['stage_201_20already_20implemented_17',['Stage 1 - already implemented',['../md_README.html#autotoc_md141',1,'']]], + ['stage_202_18',['Stage 2',['../md_README.html#autotoc_md142',1,'']]], + ['stage_203_19',['Stage 3',['../md_README.html#autotoc_md143',1,'']]], + ['stage_204_20',['Stage 4',['../md_README.html#autotoc_md144',1,'']]], + ['standalone_20tree_20tests_20without_20qt_21',['Standalone tree tests without Qt',['../md_README.html#autotoc_md150',1,'']]], + ['startbit_22',['startbit',['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit'],['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit']]], + ['statement_23',['statement',['../structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8',1,'PendingAttribute']]], + ['statement_20handler_20factory_24',['Statement Handler Factory',['../md_README.html#autotoc_md134',1,'']]], + ['status_25',['status',['../structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9',1,'DecodedFrameValue::status'],['../structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6',1,'DecodedSignalValue::status']]], + ['steps_26',['Recommended Next Steps',['../md_README.html#autotoc_md140',1,'']]], + ['strategy_27',['Unified Decode Strategy',['../md_README.html#autotoc_md126',1,'']]], + ['structured_20diagnostics_28',['Structured diagnostics',['../md_README.html#autotoc_md96',1,'']]], + ['structures_29',['Parsed Data Structures',['../md_README.html#autotoc_md57',1,'']]], + ['support_30',['Parser Support',['../md_README.html#autotoc_md95',1,'']]], + ['supported_20dbc_20syntax_31',['Supported DBC Syntax',['../md_README.html#autotoc_md99',1,'']]], + ['syntax_32',['Supported DBC Syntax',['../md_README.html#autotoc_md99',1,'']]] ]; diff --git a/docs/html/search/all_18.js b/docs/html/search/all_18.js index bc3eaa8..71c8324 100644 --- a/docs/html/search/all_18.js +++ b/docs/html/search/all_18.js @@ -1,40 +1,41 @@ var searchData= [ ['targetname_0',['targetName',['../structAttributeAssignment.html#a50059e42e5e5b944050f3290ce84ac66',1,'AttributeAssignment']]], - ['tests_1',['tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md149',1,'Regression tests'],['../md_tests_2README.html#autotoc_md158',1,'Tree and optional model tests']]], - ['tests_20without_20qt_2',['Standalone tree tests without Qt',['../md_README.html#autotoc_md145',1,'']]], - ['the_20demo_3',['Build and run the demo',['../md_README.html#autotoc_md146',1,'']]], - ['the_20gcc_20coverage_20build_20in_20qt_20creator_4',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md153',1,'']]], - ['the_20runtime_20decode_20layer_20exists_5',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], - ['the_20tree_20is_20not_20enough_6',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]], - ['to_20end_20pipeline_20coverage_7',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md162',1,'']]], - ['trace_20path_8',['trace path',['../md_README.html#autotoc_md124',1,'']]], - ['transmitter_9',['transmitter',['../structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9',1,'DecodeFrame::transmitter'],['../structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8',1,'FrameInfo::transmitter']]], - ['tree_10',['Build UI tree',['../md_README.html#autotoc_md118',1,'']]], - ['tree_20and_20optional_20model_20tests_11',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md158',1,'']]], - ['tree_20is_20not_20enough_12',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]], - ['tree_20layer_13',['UI Tree Layer',['../md_README.html#autotoc_md60',1,'']]], - ['tree_20tests_20without_20qt_14',['Standalone tree tests without Qt',['../md_README.html#autotoc_md145',1,'']]], - ['tree_5fnode_2ecpp_15',['tree_node.cpp',['../tree__node_8cpp.html',1,'']]], - ['tree_5fnode_2eh_16',['tree_node.h',['../tree__node_8h.html',1,'']]], - ['treenode_17',['treenode',['../classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc',1,'TreeNode::TreeNode(const FrameInfo &frame)'],['../classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d',1,'TreeNode::TreeNode()'],['../classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae',1,'TreeNode::TreeNode(const SignalInfo &signal)'],['../classTreeNode.html',1,'TreeNode']]], - ['treenode_20tt_18',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md61',1,'']]], - ['tt_20byteorder_20tt_19',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md66',1,'']]], - ['tt_20dbcdatabase_20tt_20',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md58',1,'']]], - ['tt_20dbcdecoder_20tt_21',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md89',1,'']]], - ['tt_20decodedatabase_20tt_22',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md76',1,'']]], - ['tt_20decodedframevalue_20tt_23',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md85',1,'']]], - ['tt_20decodedsignalvalue_20tt_24',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md81',1,'']]], - ['tt_20decodeframe_20tt_25',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md72',1,'']]], - ['tt_20decodesignal_20tt_26',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md70',1,'']]], - ['tt_20frameinfo_20tt_27',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md56',1,'']]], - ['tt_20framekey_20tt_28',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md74',1,'']]], - ['tt_20rawcanframe_20tt_29',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md79',1,'']]], - ['tt_20signalinfo_20tt_30',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md54',1,'']]], - ['tt_20treenode_20tt_31',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md61',1,'']]], - ['tt_20val_5f_20tt_32',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md132',1,'']]], - ['tt_20valuetype_20tt_33',['<tt>ValueType</tt>',['../md_README.html#autotoc_md68',1,'']]], - ['type_34',['type',['../structAttributeDefinition.html#a5de5484174a8c5f6b309041089d20afc',1,'AttributeDefinition']]], - ['typefactory_35',['TypeFactory',['../classTypeFactory.html',1,'']]], - ['typefactory_3c_20std_3a_3astring_2c_20dbcstatementhandler_20_3e_36',['TypeFactory< std::string, DbcStatementHandler >',['../classTypeFactory.html',1,'']]] + ['testing_1',['Testing',['../md_changelog.html#autotoc_md10',1,'']]], + ['tests_2',['tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md154',1,'Regression tests'],['../md_tests_2README.html#autotoc_md164',1,'Tree and optional model tests']]], + ['tests_20without_20qt_3',['Standalone tree tests without Qt',['../md_README.html#autotoc_md150',1,'']]], + ['the_20demo_4',['Build and run the demo',['../md_README.html#autotoc_md151',1,'']]], + ['the_20gcc_20coverage_20build_20in_20qt_20creator_5',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md158',1,'']]], + ['the_20runtime_20decode_20layer_20exists_6',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], + ['the_20tree_20is_20not_20enough_7',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]], + ['to_20end_20pipeline_20coverage_8',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md168',1,'']]], + ['trace_20path_9',['trace path',['../md_README.html#autotoc_md128',1,'']]], + ['transmitter_10',['transmitter',['../structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9',1,'DecodeFrame::transmitter'],['../structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8',1,'FrameInfo::transmitter']]], + ['tree_11',['Build UI tree',['../md_README.html#autotoc_md122',1,'']]], + ['tree_20and_20optional_20model_20tests_12',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md164',1,'']]], + ['tree_20is_20not_20enough_13',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]], + ['tree_20layer_14',['UI Tree Layer',['../md_README.html#autotoc_md64',1,'']]], + ['tree_20tests_20without_20qt_15',['Standalone tree tests without Qt',['../md_README.html#autotoc_md150',1,'']]], + ['tree_5fnode_2ecpp_16',['tree_node.cpp',['../tree__node_8cpp.html',1,'']]], + ['tree_5fnode_2eh_17',['tree_node.h',['../tree__node_8h.html',1,'']]], + ['treenode_18',['treenode',['../classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae',1,'TreeNode::TreeNode(const SignalInfo &signal)'],['../classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc',1,'TreeNode::TreeNode(const FrameInfo &frame)'],['../classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d',1,'TreeNode::TreeNode()'],['../classTreeNode.html',1,'TreeNode']]], + ['treenode_20tt_19',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md65',1,'']]], + ['tt_20byteorder_20tt_20',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md70',1,'']]], + ['tt_20dbcdatabase_20tt_21',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md62',1,'']]], + ['tt_20dbcdecoder_20tt_22',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md93',1,'']]], + ['tt_20decodedatabase_20tt_23',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md80',1,'']]], + ['tt_20decodedframevalue_20tt_24',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md89',1,'']]], + ['tt_20decodedsignalvalue_20tt_25',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md85',1,'']]], + ['tt_20decodeframe_20tt_26',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md76',1,'']]], + ['tt_20decodesignal_20tt_27',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md74',1,'']]], + ['tt_20frameinfo_20tt_28',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md60',1,'']]], + ['tt_20framekey_20tt_29',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md78',1,'']]], + ['tt_20rawcanframe_20tt_30',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md83',1,'']]], + ['tt_20signalinfo_20tt_31',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md58',1,'']]], + ['tt_20treenode_20tt_32',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md65',1,'']]], + ['tt_20val_5f_20tt_33',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md136',1,'']]], + ['tt_20valuetype_20tt_34',['<tt>ValueType</tt>',['../md_README.html#autotoc_md72',1,'']]], + ['type_35',['type',['../structAttributeDefinition.html#a5de5484174a8c5f6b309041089d20afc',1,'AttributeDefinition']]], + ['typefactory_36',['TypeFactory',['../classTypeFactory.html',1,'']]], + ['typefactory_3c_20std_3a_3astring_2c_20dbcstatementhandler_20_3e_37',['TypeFactory< std::string, DbcStatementHandler >',['../classTypeFactory.html',1,'']]] ]; diff --git a/docs/html/search/all_19.js b/docs/html/search/all_19.js index 2ebc53c..c39e66f 100644 --- a/docs/html/search/all_19.js +++ b/docs/html/search/all_19.js @@ -1,12 +1,12 @@ var searchData= [ - ['ubuntu_0',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], - ['ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md46',1,'']]], - ['ui_20tree_2',['Build UI tree',['../md_README.html#autotoc_md118',1,'']]], - ['ui_20tree_20layer_3',['UI Tree Layer',['../md_README.html#autotoc_md60',1,'']]], - ['unified_20decode_20strategy_4',['Unified Decode Strategy',['../md_README.html#autotoc_md122',1,'']]], + ['ubuntu_0',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], + ['ui_20path_1',['1. Parse and UI path',['../md_README.html#autotoc_md50',1,'']]], + ['ui_20tree_2',['Build UI tree',['../md_README.html#autotoc_md122',1,'']]], + ['ui_20tree_20layer_3',['UI Tree Layer',['../md_README.html#autotoc_md64',1,'']]], + ['unified_20decode_20strategy_4',['Unified Decode Strategy',['../md_README.html#autotoc_md126',1,'']]], ['unit_5',['unit',['../structDecodeSignal.html#a38eed9ca7581423fd8bfbedcffc12092',1,'DecodeSignal::unit'],['../structSignalInfo.html#a1f214f03e94ef5794de2d3367bfcbd01',1,'SignalInfo::unit']]], ['unreleased_6',['Unreleased',['../md_changelog.html#autotoc_md7',1,'']]], - ['usage_7',['Example Usage',['../md_README.html#autotoc_md116',1,'']]], - ['use_20in_20frametap_8',['Intended Use in FrameTap',['../md_README.html#autotoc_md126',1,'']]] + ['usage_7',['Example Usage',['../md_README.html#autotoc_md120',1,'']]], + ['use_20in_20frametap_8',['Intended Use in FrameTap',['../md_README.html#autotoc_md130',1,'']]] ]; diff --git a/docs/html/search/all_1a.js b/docs/html/search/all_1a.js index c1ae1f6..f67f2e4 100644 --- a/docs/html/search/all_1a.js +++ b/docs/html/search/all_1a.js @@ -1,17 +1,17 @@ var searchData= [ - ['v1_200_20—_202026_2006_2014_0',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md37',1,'']]], - ['val_5f_20tt_1',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md132',1,'']]], + ['v1_200_20—_202026_2006_2014_0',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md41',1,'']]], + ['val_5f_20tt_1',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md136',1,'']]], ['valid_2',['valid',['../structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0',1,'DecodedFrameValue::valid'],['../structDecodedSignalValue.html#aac0ed361af545cde48d0e6f41a859686',1,'DecodedSignalValue::valid']]], ['validatemultiplexing_3',['ValidateMultiplexing',['../structDbcParseContext.html#a908056de0a97316a4ebecb3f99cc400b',1,'DbcParseContext']]], - ['validation_4',['Extended validation',['../md_tests_2README.html#autotoc_md164',1,'']]], - ['validation_20and_20parse_20errors_5',['validation and parse errors',['../md_README.html#autotoc_md98',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md102',1,'Signal validation and parse errors']]], - ['validation_20coverage_6',['Database validation coverage',['../md_tests_2README.html#autotoc_md161',1,'']]], + ['validation_4',['Extended validation',['../md_tests_2README.html#autotoc_md170',1,'']]], + ['validation_20and_20parse_20errors_5',['validation and parse errors',['../md_README.html#autotoc_md102',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md106',1,'Signal validation and parse errors']]], + ['validation_20coverage_6',['Database validation coverage',['../md_tests_2README.html#autotoc_md167',1,'']]], ['value_7',['value',['../structAttributeAssignment.html#a93de8c51c5154219bf18beadcec5708f',1,'AttributeAssignment::value'],['../structMultiplexing.html#a79158d4fdbfd68a3d51a8ce79d34fd67',1,'Multiplexing::value']]], - ['value_20descriptions_20tt_20val_5f_20tt_8',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md132',1,'']]], - ['value_20representation_20and_20precision_9',['Raw value representation and precision',['../md_README.html#autotoc_md83',1,'']]], + ['value_20descriptions_20tt_20val_5f_20tt_8',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md136',1,'']]], + ['value_20representation_20and_20precision_9',['Raw value representation and precision',['../md_README.html#autotoc_md87',1,'']]], ['valuedescriptions_10',['valuedescriptions',['../structDecodeSignal.html#a822155d9bf4ed5f3300c9e9befe606ff',1,'DecodeSignal::valueDescriptions'],['../structSignalInfo.html#a43f47d0433d0cc39076bd7278b46af9c',1,'SignalInfo::valueDescriptions']]], ['valuetype_11',['valuetype',['../structDecodeSignal.html#a9d37638129263b8902ba5be59baf39a8',1,'DecodeSignal::valueType'],['../decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1',1,'ValueType: decode_database.h']]], - ['valuetype_20tt_12',['<tt>ValueType</tt>',['../md_README.html#autotoc_md68',1,'']]], - ['variants_20in_20qt_20creator_13',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md154',1,'']]] + ['valuetype_20tt_12',['<tt>ValueType</tt>',['../md_README.html#autotoc_md72',1,'']]], + ['variants_20in_20qt_20creator_13',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md159',1,'']]] ]; diff --git a/docs/html/search/all_1b.js b/docs/html/search/all_1b.js index 7c0a1cd..11d3db3 100644 --- a/docs/html/search/all_1b.js +++ b/docs/html/search/all_1b.js @@ -1,7 +1,7 @@ var searchData= [ - ['why_20the_20runtime_20decode_20layer_20exists_0',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], - ['why_20the_20tree_20is_20not_20enough_1',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]], - ['without_20qt_2',['Standalone tree tests without Qt',['../md_README.html#autotoc_md145',1,'']]], - ['without_20qt_20libraries_3',['Build core without Qt libraries',['../md_README.html#autotoc_md143',1,'']]] + ['why_20the_20runtime_20decode_20layer_20exists_0',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], + ['why_20the_20tree_20is_20not_20enough_1',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]], + ['without_20qt_2',['Standalone tree tests without Qt',['../md_README.html#autotoc_md150',1,'']]], + ['without_20qt_20libraries_3',['Build core without Qt libraries',['../md_README.html#autotoc_md148',1,'']]] ]; diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js index f1818a7..0921dcd 100644 --- a/docs/html/search/all_2.js +++ b/docs/html/search/all_2.js @@ -1,16 +1,18 @@ var searchData= [ - ['2_0',['Stage 2',['../md_README.html#autotoc_md138',1,'']]], - ['2_20runtime_20decode_20path_1',['2. Runtime decode path',['../md_README.html#autotoc_md47',1,'']]], - ['20_2',['2026-10-20',['../md_changelog.html#autotoc_md8',1,'']]], - ['2026_2003_2013_3',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md39',1,'']]], - ['2026_2006_2014_4',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md37',1,'']]], - ['2026_2010_2001_5',['2026-10-01',['../md_changelog.html#autotoc_md34',1,'']]], - ['2026_2010_2005_6',['2026-10-05',['../md_changelog.html#autotoc_md30',1,'']]], - ['2026_2010_2006_7',['2026-10-06',['../md_changelog.html#autotoc_md28',1,'']]], - ['2026_2010_2007_8',['2026-10-07',['../md_changelog.html#autotoc_md24',1,'']]], - ['2026_2010_2011_9',['2026-10-11',['../md_changelog.html#autotoc_md21',1,'']]], - ['2026_2010_2013_10',['2026-10-13',['../md_changelog.html#autotoc_md18',1,'']]], - ['2026_2010_2014_11',['2026-10-14',['../md_changelog.html#autotoc_md14',1,'']]], - ['2026_2010_2020_12',['2026-10-20',['../md_changelog.html#autotoc_md8',1,'']]] + ['2_0',['Stage 2',['../md_README.html#autotoc_md142',1,'']]], + ['2_20runtime_20decode_20path_1',['2. Runtime decode path',['../md_README.html#autotoc_md51',1,'']]], + ['20_2',['2026-10-20',['../md_changelog.html#autotoc_md12',1,'']]], + ['2026_2003_2013_3',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md43',1,'']]], + ['2026_2006_2014_4',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md41',1,'']]], + ['2026_2010_2001_5',['2026-10-01',['../md_changelog.html#autotoc_md38',1,'']]], + ['2026_2010_2005_6',['2026-10-05',['../md_changelog.html#autotoc_md34',1,'']]], + ['2026_2010_2006_7',['2026-10-06',['../md_changelog.html#autotoc_md32',1,'']]], + ['2026_2010_2007_8',['2026-10-07',['../md_changelog.html#autotoc_md28',1,'']]], + ['2026_2010_2011_9',['2026-10-11',['../md_changelog.html#autotoc_md25',1,'']]], + ['2026_2010_2013_10',['2026-10-13',['../md_changelog.html#autotoc_md22',1,'']]], + ['2026_2010_2014_11',['2026-10-14',['../md_changelog.html#autotoc_md18',1,'']]], + ['2026_2010_2020_12',['2026-10-20',['../md_changelog.html#autotoc_md12',1,'']]], + ['2026_2010_2023_13',['2026-10-23',['../md_changelog.html#autotoc_md8',1,'']]], + ['23_14',['2026-10-23',['../md_changelog.html#autotoc_md8',1,'']]] ]; diff --git a/docs/html/search/all_26.js b/docs/html/search/all_26.js index c6bbc0c..206e69c 100644 --- a/docs/html/search/all_26.js +++ b/docs/html/search/all_26.js @@ -1,5 +1,5 @@ var searchData= [ - ['—_202026_2003_2013_0',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md39',1,'']]], - ['—_202026_2006_2014_1',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md37',1,'']]] + ['—_202026_2003_2013_0',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md43',1,'']]], + ['—_202026_2006_2014_1',['v1.0 — 2026-06-14',['../md_changelog.html#autotoc_md41',1,'']]] ]; diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index 83df580..af05ae6 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['3_0',['Stage 3',['../md_README.html#autotoc_md139',1,'']]] + ['3_0',['Stage 3',['../md_README.html#autotoc_md143',1,'']]] ]; diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js index dad824d..59833f8 100644 --- a/docs/html/search/all_4.js +++ b/docs/html/search/all_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['4_0',['Stage 4',['../md_README.html#autotoc_md140',1,'']]] + ['4_0',['Stage 4',['../md_README.html#autotoc_md144',1,'']]] ]; diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js index 6e4cfb3..4c3cc13 100644 --- a/docs/html/search/all_5.js +++ b/docs/html/search/all_5.js @@ -1,36 +1,36 @@ var searchData= [ - ['a_20raw_20frame_0',['Decode a raw frame',['../md_README.html#autotoc_md120',1,'']]], - ['adapter_1',['Optional Qt model adapter',['../md_README.html#autotoc_md144',1,'']]], + ['a_20raw_20frame_0',['Decode a raw frame',['../md_README.html#autotoc_md124',1,'']]], + ['adapter_1',['Optional Qt model adapter',['../md_README.html#autotoc_md149',1,'']]], ['addchild_2',['AddChild',['../classTreeNode.html#af87331684d4b40240aec75e3286921d3',1,'TreeNode']]], - ['added_3',['added',['../md_changelog.html#autotoc_md29',1,'Added'],['../md_changelog.html#autotoc_md40',1,'Added'],['../md_changelog.html#autotoc_md25',1,'Added'],['../md_changelog.html#autotoc_md22',1,'Added'],['../md_changelog.html#autotoc_md19',1,'Added'],['../md_changelog.html#autotoc_md17',1,'Added'],['../md_changelog.html#autotoc_md12',1,'Added'],['../md_changelog.html#autotoc_md10',1,'Added']]], - ['additional_20checks_4',['Code review and additional checks',['../md_README.html#autotoc_md150',1,'']]], - ['additional_20regression_20coverage_5',['Additional regression coverage',['../md_tests_2README.html#autotoc_md159',1,'']]], - ['all_20build_20variants_20in_20qt_20creator_6',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md154',1,'']]], - ['already_20implemented_7',['Stage 1 - already implemented',['../md_README.html#autotoc_md137',1,'']]], + ['added_3',['added',['../md_changelog.html#autotoc_md29',1,'Added'],['../md_changelog.html#autotoc_md44',1,'Added'],['../md_changelog.html#autotoc_md33',1,'Added'],['../md_changelog.html#autotoc_md26',1,'Added'],['../md_changelog.html#autotoc_md23',1,'Added'],['../md_changelog.html#autotoc_md21',1,'Added'],['../md_changelog.html#autotoc_md16',1,'Added'],['../md_changelog.html#autotoc_md14',1,'Added'],['../md_changelog.html#autotoc_md9',1,'Added']]], + ['additional_20checks_4',['Code review and additional checks',['../md_README.html#autotoc_md155',1,'']]], + ['additional_20regression_20coverage_5',['Additional regression coverage',['../md_tests_2README.html#autotoc_md165',1,'']]], + ['all_20build_20variants_20in_20qt_20creator_6',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md159',1,'']]], + ['already_20implemented_7',['Stage 1 - already implemented',['../md_README.html#autotoc_md141',1,'']]], ['ambiguous_8',['ambiguous',['../structPgnLookupResult.html#a6158833782348b3cc26037c2091fcc36',1,'PgnLookupResult']]], - ['and_20additional_20checks_9',['Code review and additional checks',['../md_README.html#autotoc_md150',1,'']]], - ['and_20frame_20metadata_10',['Attributes and frame metadata',['../md_README.html#autotoc_md93',1,'']]], - ['and_20lcov_20on_20debian_20ubuntu_11',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], - ['and_20maintenance_12',['and maintenance',['../md_changelog.html#autotoc_md33',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md41',1,'Documentation and maintenance']]], - ['and_20motorola_20extraction_13',['Intel and Motorola Extraction',['../md_README.html#autotoc_md114',1,'']]], - ['and_20optional_20model_20tests_14',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md158',1,'']]], - ['and_20parse_20errors_15',['and parse errors',['../md_README.html#autotoc_md98',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md102',1,'Signal validation and parse errors']]], - ['and_20pgn_20lookup_16',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]], - ['and_20precision_17',['Raw value representation and precision',['../md_README.html#autotoc_md83',1,'']]], - ['and_20reload_18',['Definition ownership and reload',['../md_README.html#autotoc_md86',1,'']]], - ['and_20reload_20coverage_19',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md160',1,'']]], - ['and_20run_20the_20demo_20',['Build and run the demo',['../md_README.html#autotoc_md146',1,'']]], + ['and_20additional_20checks_9',['Code review and additional checks',['../md_README.html#autotoc_md155',1,'']]], + ['and_20frame_20metadata_10',['Attributes and frame metadata',['../md_README.html#autotoc_md97',1,'']]], + ['and_20lcov_20on_20debian_20ubuntu_11',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], + ['and_20maintenance_12',['and maintenance',['../md_changelog.html#autotoc_md37',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md45',1,'Documentation and maintenance']]], + ['and_20motorola_20extraction_13',['Intel and Motorola Extraction',['../md_README.html#autotoc_md118',1,'']]], + ['and_20optional_20model_20tests_14',['Tree and optional model tests',['../md_tests_2README.html#autotoc_md164',1,'']]], + ['and_20parse_20errors_15',['and parse errors',['../md_README.html#autotoc_md102',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md106',1,'Signal validation and parse errors']]], + ['and_20pgn_20lookup_16',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]], + ['and_20precision_17',['Raw value representation and precision',['../md_README.html#autotoc_md87',1,'']]], + ['and_20reload_18',['Definition ownership and reload',['../md_README.html#autotoc_md90',1,'']]], + ['and_20reload_20coverage_19',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md166',1,'']]], + ['and_20run_20the_20demo_20',['Build and run the demo',['../md_README.html#autotoc_md151',1,'']]], ['and_20runtime_20decode_20module_20documentation_21',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['and_20signal_20identifiers_22',['Stable frame and signal identifiers',['../md_README.html#autotoc_md87',1,'']]], - ['and_20ui_20path_23',['1. Parse and UI path',['../md_README.html#autotoc_md46',1,'']]], - ['api_20documentation_24',['Generate API documentation',['../md_README.html#autotoc_md147',1,'']]], - ['architecture_25',['High-Level Architecture',['../md_README.html#autotoc_md45',1,'']]], - ['attribute_20coverage_26',['Attribute coverage',['../md_tests_2README.html#autotoc_md163',1,'']]], + ['and_20signal_20identifiers_22',['Stable frame and signal identifiers',['../md_README.html#autotoc_md91',1,'']]], + ['and_20ui_20path_23',['1. Parse and UI path',['../md_README.html#autotoc_md50',1,'']]], + ['api_20documentation_24',['Generate API documentation',['../md_README.html#autotoc_md152',1,'']]], + ['architecture_25',['High-Level Architecture',['../md_README.html#autotoc_md49',1,'']]], + ['attribute_20coverage_26',['Attribute coverage',['../md_tests_2README.html#autotoc_md169',1,'']]], ['attributeassignment_27',['AttributeAssignment',['../structAttributeAssignment.html',1,'']]], ['attributeassignments_28',['attributeAssignments',['../structDbcDatabase.html#aa7bdf56eb8b7ab5b873e1c096b46d8b6',1,'DbcDatabase']]], ['attributedefinition_29',['AttributeDefinition',['../structAttributeDefinition.html',1,'']]], ['attributedefinitions_30',['attributeDefinitions',['../structDbcDatabase.html#a14862245081989f2abf126b5ea6dfdfa',1,'DbcDatabase']]], ['attributes_31',['attributes',['../structSignalInfo.html#a781766eddbf6641071623c8e5b9acb4a',1,'SignalInfo::attributes'],['../structFrameInfo.html#a9ef2736053b593cf34ba2608cf8275c0',1,'FrameInfo::attributes'],['../structDecodeFrame.html#ad506b03108a40df7e8005638c9c59653',1,'DecodeFrame::attributes'],['../structDecodeSignal.html#a204f65c7ea45a2c148f19c12d922f99b',1,'DecodeSignal::attributes'],['../structDbcDatabase.html#a321839ad81af176444358eb23114eaee',1,'DbcDatabase::attributes']]], - ['attributes_20and_20frame_20metadata_32',['Attributes and frame metadata',['../md_README.html#autotoc_md93',1,'']]] + ['attributes_20and_20frame_20metadata_32',['Attributes and frame metadata',['../md_README.html#autotoc_md97',1,'']]] ]; diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js index 07ec2e1..028ce86 100644 --- a/docs/html/search/all_6.js +++ b/docs/html/search/all_6.js @@ -1,15 +1,14 @@ var searchData= [ ['baseptr_0',['BasePtr',['../classTypeFactory.html#a33b404da3e19ea7e1245b8a4975721bf',1,'TypeFactory']]], - ['basic_20multiplexing_1',['Basic multiplexing',['../md_README.html#autotoc_md104',1,'']]], - ['build_2',['build',['../classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b',1,'DbcDecodeBuilder::Build()'],['../classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b',1,'DbcTreeBuilder::Build()']]], - ['build_20and_20run_20the_20demo_3',['Build and run the demo',['../md_README.html#autotoc_md146',1,'']]], - ['build_20core_20without_20qt_20libraries_4',['Build core without Qt libraries',['../md_README.html#autotoc_md143',1,'']]], - ['build_20in_20qt_20creator_5',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md153',1,'']]], - ['build_20integration_6',['Build Integration',['../md_README.html#autotoc_md142',1,'']]], - ['build_20runtime_20decode_20database_7',['Build runtime decode database',['../md_README.html#autotoc_md119',1,'']]], - ['build_20ui_20tree_8',['Build UI tree',['../md_README.html#autotoc_md118',1,'']]], - ['build_20variants_20in_20qt_20creator_9',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md154',1,'']]], - ['byteorder_10',['byteorder',['../structDecodeSignal.html#abdc4c4bb4a67a6d61d6ca81e8a52833d',1,'DecodeSignal::byteOrder'],['../decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142b',1,'ByteOrder: decode_database.h']]], - ['byteorder_20tt_11',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md66',1,'']]] + ['build_1',['build',['../classDbcDecodeBuilder.html#a2bc6386dfb5e58976c42e22c19ec471b',1,'DbcDecodeBuilder::Build()'],['../classDbcTreeBuilder.html#a7e57d067d831b14b383947fd125edd4b',1,'DbcTreeBuilder::Build()']]], + ['build_20and_20run_20the_20demo_2',['Build and run the demo',['../md_README.html#autotoc_md151',1,'']]], + ['build_20core_20without_20qt_20libraries_3',['Build core without Qt libraries',['../md_README.html#autotoc_md148',1,'']]], + ['build_20in_20qt_20creator_4',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md158',1,'']]], + ['build_20integration_5',['Build Integration',['../md_README.html#autotoc_md146',1,'']]], + ['build_20runtime_20decode_20database_6',['Build runtime decode database',['../md_README.html#autotoc_md123',1,'']]], + ['build_20ui_20tree_7',['Build UI tree',['../md_README.html#autotoc_md122',1,'']]], + ['build_20variants_20in_20qt_20creator_8',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md159',1,'']]], + ['byteorder_9',['byteorder',['../structDecodeSignal.html#abdc4c4bb4a67a6d61d6ca81e8a52833d',1,'DecodeSignal::byteOrder'],['../decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142b',1,'ByteOrder: decode_database.h']]], + ['byteorder_20tt_10',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md70',1,'']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index 7f053fd..eb5f3ac 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -1,28 +1,29 @@ var searchData= [ - ['can_20id_20normalization_0',['CAN ID Normalization',['../md_README.html#autotoc_md108',1,'']]], + ['can_20id_20normalization_0',['CAN ID Normalization',['../md_README.html#autotoc_md112',1,'']]], ['canid_1',['canid',['../structRawCanFrame.html#a2d0e7fa0e3d5c20bbed55ed8f7888ff4',1,'RawCanFrame::canId'],['../structPendingValueDescriptions.html#a5f0082ceeaee77e2f823661547aad844',1,'PendingValueDescriptions::canId'],['../structPendingComment.html#a6d1c3b1e149bb602a95224446709c771',1,'PendingComment::canId'],['../structDecodeFrame.html#a52e10215388db7df8b541b9d9909edcf',1,'DecodeFrame::canId'],['../structFrameKey.html#a022917652b4d3c2f2dfcc5a13ab7caa4',1,'FrameKey::canId'],['../structFrameInfo.html#af470b0742c05bfbffc31c51a68f5c05e',1,'FrameInfo::canId'],['../structAttributeAssignment.html#a330ae1a34c342b0352115a83dd31aab8',1,'AttributeAssignment::canId']]], - ['changed_2',['changed',['../md_changelog.html#autotoc_md16',1,'Changed'],['../md_changelog.html#autotoc_md35',1,'Changed'],['../md_changelog.html#autotoc_md31',1,'Changed'],['../md_changelog.html#autotoc_md26',1,'Changed'],['../md_changelog.html#autotoc_md23',1,'Changed'],['../md_changelog.html#autotoc_md20',1,'Changed'],['../md_changelog.html#autotoc_md11',1,'Changed']]], + ['changed_2',['changed',['../md_changelog.html#autotoc_md27',1,'Changed'],['../md_changelog.html#autotoc_md39',1,'Changed'],['../md_changelog.html#autotoc_md35',1,'Changed'],['../md_changelog.html#autotoc_md30',1,'Changed'],['../md_changelog.html#autotoc_md24',1,'Changed'],['../md_changelog.html#autotoc_md20',1,'Changed'],['../md_changelog.html#autotoc_md15',1,'Changed']]], ['changelog_3',['Changelog',['../md_changelog.html',1,'']]], - ['checks_4',['Code review and additional checks',['../md_README.html#autotoc_md150',1,'']]], + ['checks_4',['checks',['../md_README.html#autotoc_md155',1,'Code review and additional checks'],['../md_README.html#autotoc_md147',1,'Local core regression checks'],['../md_tests_2README.html#autotoc_md161',1,'Local regression checks']]], ['classes_5',['classes',['../classTypeFactory.html#a5f119fe61c1cb9f4725ce746e4a047b3',1,'TypeFactory']]], ['code_6',['code',['../structDbcDiagnostic.html#aa315a4a40b15f2e8cb34264d94a0f914',1,'DbcDiagnostic']]], - ['code_20coverage_7',['Measuring code coverage',['../md_README.html#autotoc_md151',1,'']]], - ['code_20review_20and_20additional_20checks_8',['Code review and additional checks',['../md_README.html#autotoc_md150',1,'']]], + ['code_20coverage_7',['Measuring code coverage',['../md_README.html#autotoc_md156',1,'']]], + ['code_20review_20and_20additional_20checks_8',['Code review and additional checks',['../md_README.html#autotoc_md155',1,'']]], ['column_9',['Column',['../classDbcTreeModel.html#a5e31be609fae4d7dfdd79140f56069ae',1,'DbcTreeModel']]], ['columncount_10',['columnCount',['../classDbcTreeModel.html#a397f885e7fd45c387825b4357b875c10',1,'DbcTreeModel']]], - ['comment_11',['comment',['../structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5',1,'SignalInfo::comment'],['../structFrameInfo.html#ace75121294f9d89b762080ab5643293c',1,'FrameInfo::comment'],['../structDecodeFrame.html#a25819ef907a32391af5c9f7cae9cdb22',1,'DecodeFrame::comment'],['../structDecodeSignal.html#ae28c905d4a2bc86419c2a8361bfea473',1,'DecodeSignal::comment'],['../structPendingComment.html#aa344393f67770e12449a4f14f6fcf10b',1,'PendingComment::comment']]], - ['comments_12',['Comments',['../md_README.html#autotoc_md106',1,'']]], - ['configure_20all_20build_20variants_20in_20qt_20creator_13',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md154',1,'']]], - ['configure_20the_20gcc_20coverage_20build_20in_20qt_20creator_14',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md153',1,'']]], + ['comment_11',['comment',['../structDecodeFrame.html#a25819ef907a32391af5c9f7cae9cdb22',1,'DecodeFrame::comment'],['../structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5',1,'SignalInfo::comment'],['../structPendingComment.html#aa344393f67770e12449a4f14f6fcf10b',1,'PendingComment::comment'],['../structDecodeSignal.html#ae28c905d4a2bc86419c2a8361bfea473',1,'DecodeSignal::comment'],['../structFrameInfo.html#ace75121294f9d89b762080ab5643293c',1,'FrameInfo::comment']]], + ['comments_12',['Comments',['../md_README.html#autotoc_md110',1,'']]], + ['configure_20all_20build_20variants_20in_20qt_20creator_13',['Configure all build variants in Qt Creator',['../md_README.html#autotoc_md159',1,'']]], + ['configure_20the_20gcc_20coverage_20build_20in_20qt_20creator_14',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md158',1,'']]], ['contains_15',['contains',['../classTypeFactory.html#a1a119ad2956abe146213c6ca124d8dd4',1,'TypeFactory']]], - ['core_20without_20qt_20libraries_16',['Build core without Qt libraries',['../md_README.html#autotoc_md143',1,'']]], - ['coverage_17',['coverage',['../md_tests_2README.html#autotoc_md159',1,'Additional regression coverage'],['../md_tests_2README.html#autotoc_md163',1,'Attribute coverage'],['../md_tests_2README.html#autotoc_md161',1,'Database validation coverage'],['../md_tests_2README.html#autotoc_md156',1,'Decoder coverage'],['../md_tests_2README.html#autotoc_md160',1,'Definition lifetime and reload coverage'],['../md_tests_2README.html#autotoc_md162',1,'End-to-end pipeline coverage'],['../md_README.html#autotoc_md151',1,'Measuring code coverage'],['../md_tests_2README.html#autotoc_md157',1,'Parser coverage']]], - ['coverage_20build_20in_20qt_20creator_18',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md153',1,'']]], - ['create_19',['create',['../classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f',1,'TypeFactory']]], - ['creator_20',['creator',['../md_README.html#autotoc_md154',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md153',1,'Configure the GCC coverage build in Qt Creator'],['../classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473',1,'TypeFactory::creator(const ClassId &id) const']]], - ['creatorfn_21',['CreatorFn',['../classTypeFactory.html#a650022aac1e2f30af5bc554a5663939f',1,'TypeFactory']]], - ['current_20limitations_22',['Current Limitations',['../md_README.html#autotoc_md134',1,'']]], - ['currentframe_23',['currentFrame',['../structDbcParseContext.html#af31b56247edff7f025957ae023a56913',1,'DbcParseContext']]], - ['cycletimems_24',['cycletimems',['../structFrameInfo.html#a099f02a77adfb9ac23e286ce75f4eef4',1,'FrameInfo::cycleTimeMs'],['../structDecodeFrame.html#a732c2f6853d55ce8253db61207fc21d3',1,'DecodeFrame::cycleTimeMs']]] + ['core_20regression_20checks_16',['Local core regression checks',['../md_README.html#autotoc_md147',1,'']]], + ['core_20without_20qt_20libraries_17',['Build core without Qt libraries',['../md_README.html#autotoc_md148',1,'']]], + ['coverage_18',['coverage',['../md_tests_2README.html#autotoc_md165',1,'Additional regression coverage'],['../md_tests_2README.html#autotoc_md169',1,'Attribute coverage'],['../md_tests_2README.html#autotoc_md167',1,'Database validation coverage'],['../md_tests_2README.html#autotoc_md162',1,'Decoder coverage'],['../md_tests_2README.html#autotoc_md166',1,'Definition lifetime and reload coverage'],['../md_tests_2README.html#autotoc_md168',1,'End-to-end pipeline coverage'],['../md_README.html#autotoc_md156',1,'Measuring code coverage'],['../md_tests_2README.html#autotoc_md163',1,'Parser coverage']]], + ['coverage_20build_20in_20qt_20creator_19',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md158',1,'']]], + ['create_20',['create',['../classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f',1,'TypeFactory']]], + ['creator_21',['creator',['../md_README.html#autotoc_md159',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md158',1,'Configure the GCC coverage build in Qt Creator'],['../classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473',1,'TypeFactory::creator(const ClassId &id) const']]], + ['creatorfn_22',['CreatorFn',['../classTypeFactory.html#a650022aac1e2f30af5bc554a5663939f',1,'TypeFactory']]], + ['current_20limitations_23',['Current Limitations',['../md_README.html#autotoc_md138',1,'']]], + ['currentframe_24',['currentFrame',['../structDbcParseContext.html#af31b56247edff7f025957ae023a56913',1,'DbcParseContext']]], + ['cycletimems_25',['cycletimems',['../structDecodeFrame.html#a732c2f6853d55ce8253db61207fc21d3',1,'DecodeFrame::cycleTimeMs'],['../structFrameInfo.html#a099f02a77adfb9ac23e286ce75f4eef4',1,'FrameInfo::cycleTimeMs']]] ]; diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js index 6d3457e..40a7440 100644 --- a/docs/html/search/all_8.js +++ b/docs/html/search/all_8.js @@ -1,12 +1,12 @@ var searchData= [ ['data_0',['data',['../structRawCanFrame.html#a0acb487612104c99c9907344c035df83',1,'RawCanFrame::data'],['../classDbcTreeModel.html#aca81d05c81cc48c1185fc36659e96e5b',1,'DbcTreeModel::data()']]], - ['data_20structures_1',['Parsed Data Structures',['../md_README.html#autotoc_md53',1,'']]], - ['database_2',['database',['../md_README.html#autotoc_md119',1,'Build runtime decode database'],['../structDbcParseContext.html#a79bad0b8302e2156670461bab529259c',1,'DbcParseContext::database'],['../structDbcParseResult.html#abfa765d29a4397e8ddaf771bae21993e',1,'DbcParseResult::database']]], - ['database_20validation_20coverage_3',['Database validation coverage',['../md_tests_2README.html#autotoc_md161',1,'']]], - ['dbc_4',['Parse DBC',['../md_README.html#autotoc_md117',1,'']]], + ['data_20structures_1',['Parsed Data Structures',['../md_README.html#autotoc_md57',1,'']]], + ['database_2',['database',['../md_README.html#autotoc_md123',1,'Build runtime decode database'],['../structDbcParseContext.html#a79bad0b8302e2156670461bab529259c',1,'DbcParseContext::database'],['../structDbcParseResult.html#abfa765d29a4397e8ddaf771bae21993e',1,'DbcParseResult::database']]], + ['database_20validation_20coverage_3',['Database validation coverage',['../md_tests_2README.html#autotoc_md167',1,'']]], + ['dbc_4',['Parse DBC',['../md_README.html#autotoc_md121',1,'']]], ['dbc_20parser_20and_20runtime_20decode_20module_20documentation_5',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['dbc_20syntax_6',['Supported DBC Syntax',['../md_README.html#autotoc_md95',1,'']]], + ['dbc_20syntax_6',['Supported DBC Syntax',['../md_README.html#autotoc_md99',1,'']]], ['dbc_5fdatabase_2eh_7',['dbc_database.h',['../dbc__database_8h.html',1,'']]], ['dbc_5fdecode_5fbuilder_2ecpp_8',['dbc_decode_builder.cpp',['../dbc__decode__builder_8cpp.html',1,'']]], ['dbc_5fdecode_5fbuilder_2eh_9',['dbc_decode_builder.h',['../dbc__decode__builder_8h.html',1,'']]], @@ -19,59 +19,59 @@ var searchData= ['dbcattributehandler_16',['DbcAttributeHandler',['../classDbcAttributeHandler.html',1,'']]], ['dbccommenthandler_17',['DbcCommentHandler',['../classDbcCommentHandler.html',1,'']]], ['dbcdatabase_18',['DbcDatabase',['../structDbcDatabase.html',1,'']]], - ['dbcdatabase_20tt_19',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md58',1,'']]], + ['dbcdatabase_20tt_19',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md62',1,'']]], ['dbcdecodebuilder_20',['DbcDecodeBuilder',['../classDbcDecodeBuilder.html',1,'']]], ['dbcdecoder_21',['DbcDecoder',['../classDbcDecoder.html',1,'']]], - ['dbcdecoder_20tt_22',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md89',1,'']]], + ['dbcdecoder_20tt_22',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md93',1,'']]], ['dbcdiagnostic_23',['DbcDiagnostic',['../structDbcDiagnostic.html',1,'']]], ['dbcdiagnosticerror_24',['dbcdiagnosticerror',['../classDbcDiagnosticError.html',1,'DbcDiagnosticError'],['../classDbcDiagnosticError.html#aa9997368f79a9a0723481aaeffc44618',1,'DbcDiagnosticError::DbcDiagnosticError()']]], ['dbcframehandler_25',['DbcFrameHandler',['../classDbcFrameHandler.html',1,'']]], ['dbcheaderhandler_26',['DbcHeaderHandler',['../classDbcHeaderHandler.html',1,'']]], - ['dbcparsecontext_27',['DbcParseContext',['../structDbcParseContext.html',1,'']]], - ['dbcparser_28',['dbcparser',['../classDbcParser.html',1,'DbcParser'],['../classDbcParser.html#a46bc3afcd103e704dc58bb4b073da73c',1,'DbcParser::DbcParser()']]], - ['dbcparseresult_29',['DbcParseResult',['../structDbcParseResult.html',1,'']]], - ['dbcparseroptions_30',['DbcParserOptions',['../structDbcParserOptions.html',1,'']]], - ['dbcsignalhandler_31',['DbcSignalHandler',['../classDbcSignalHandler.html',1,'']]], - ['dbcstatementdispatcher_32',['dbcstatementdispatcher',['../classDbcStatementDispatcher.html',1,'DbcStatementDispatcher'],['../classDbcStatementDispatcher.html#a2f064359b59d8644b8a8196653d47482',1,'DbcStatementDispatcher::DbcStatementDispatcher()']]], - ['dbcstatementhandler_33',['DbcStatementHandler',['../classDbcStatementHandler.html',1,'']]], - ['dbctreebuilder_34',['DbcTreeBuilder',['../classDbcTreeBuilder.html',1,'']]], - ['dbctreemodel_35',['dbctreemodel',['../classDbcTreeModel.html#a4f7214b727d812885bf077352ec9ece1',1,'DbcTreeModel::DbcTreeModel()'],['../classDbcTreeModel.html',1,'DbcTreeModel']]], - ['dbcunsupportedmultiplexinghandler_36',['DbcUnsupportedMultiplexingHandler',['../classDbcUnsupportedMultiplexingHandler.html',1,'']]], + ['dbcmultiplexinghandler_27',['DbcMultiplexingHandler',['../classDbcMultiplexingHandler.html',1,'']]], + ['dbcparsecontext_28',['DbcParseContext',['../structDbcParseContext.html',1,'']]], + ['dbcparser_29',['dbcparser',['../classDbcParser.html',1,'DbcParser'],['../classDbcParser.html#a46bc3afcd103e704dc58bb4b073da73c',1,'DbcParser::DbcParser()']]], + ['dbcparseresult_30',['DbcParseResult',['../structDbcParseResult.html',1,'']]], + ['dbcparseroptions_31',['DbcParserOptions',['../structDbcParserOptions.html',1,'']]], + ['dbcsignalhandler_32',['DbcSignalHandler',['../classDbcSignalHandler.html',1,'']]], + ['dbcstatementdispatcher_33',['dbcstatementdispatcher',['../classDbcStatementDispatcher.html',1,'DbcStatementDispatcher'],['../classDbcStatementDispatcher.html#a2f064359b59d8644b8a8196653d47482',1,'DbcStatementDispatcher::DbcStatementDispatcher()']]], + ['dbcstatementhandler_34',['DbcStatementHandler',['../classDbcStatementHandler.html',1,'']]], + ['dbctreebuilder_35',['DbcTreeBuilder',['../classDbcTreeBuilder.html',1,'']]], + ['dbctreemodel_36',['dbctreemodel',['../classDbcTreeModel.html#a4f7214b727d812885bf077352ec9ece1',1,'DbcTreeModel::DbcTreeModel()'],['../classDbcTreeModel.html',1,'DbcTreeModel']]], ['dbcvaluedescriptionhandler_37',['DbcValueDescriptionHandler',['../classDbcValueDescriptionHandler.html',1,'']]], - ['debian_20ubuntu_38',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], + ['debian_20ubuntu_38',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], ['decode_39',['decode',['../classDbcDecoder.html#a345951ffe5d943a70d3a1ea1f39e74f7',1,'DbcDecoder::Decode(const DecodeDatabase &database, const RawCanFrame &frame) const'],['../classDbcDecoder.html#ade48a94b6fcda6563bd1b2c6ff49439e',1,'DbcDecoder::Decode(const DecodeDatabase &database, const RawCanFrame &frame, const std::vector< SignalKey > &selection) const']]], - ['decode_20a_20raw_20frame_40',['Decode a raw frame',['../md_README.html#autotoc_md120',1,'']]], - ['decode_20database_41',['Build runtime decode database',['../md_README.html#autotoc_md119',1,'']]], - ['decode_20flow_42',['Decode Flow',['../md_README.html#autotoc_md112',1,'']]], - ['decode_20layer_43',['Runtime Decode Layer',['../md_README.html#autotoc_md63',1,'']]], - ['decode_20layer_20exists_44',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], + ['decode_20a_20raw_20frame_40',['Decode a raw frame',['../md_README.html#autotoc_md124',1,'']]], + ['decode_20database_41',['Build runtime decode database',['../md_README.html#autotoc_md123',1,'']]], + ['decode_20flow_42',['Decode Flow',['../md_README.html#autotoc_md116',1,'']]], + ['decode_20layer_43',['Runtime Decode Layer',['../md_README.html#autotoc_md67',1,'']]], + ['decode_20layer_20exists_44',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], ['decode_20module_20documentation_45',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['decode_20path_46',['2. Runtime decode path',['../md_README.html#autotoc_md47',1,'']]], - ['decode_20strategy_47',['Unified Decode Strategy',['../md_README.html#autotoc_md122',1,'']]], + ['decode_20path_46',['2. Runtime decode path',['../md_README.html#autotoc_md51',1,'']]], + ['decode_20strategy_47',['Unified Decode Strategy',['../md_README.html#autotoc_md126',1,'']]], ['decode_5fdatabase_2eh_48',['decode_database.h',['../decode__database_8h.html',1,'']]], ['decodedatabase_49',['decodedatabase',['../classDecodeDatabase.html',1,'DecodeDatabase'],['../classDecodeDatabase.html#a51a44cf7c3f23c98ec8781afe0097c0c',1,'DecodeDatabase::DecodeDatabase()']]], - ['decodedatabase_20tt_50',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md76',1,'']]], + ['decodedatabase_20tt_50',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md80',1,'']]], ['decodedframevalue_51',['DecodedFrameValue',['../structDecodedFrameValue.html',1,'']]], - ['decodedframevalue_20tt_52',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md85',1,'']]], + ['decodedframevalue_20tt_52',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md89',1,'']]], ['decodedsignalvalue_53',['DecodedSignalValue',['../structDecodedSignalValue.html',1,'']]], - ['decodedsignalvalue_20tt_54',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md81',1,'']]], + ['decodedsignalvalue_20tt_54',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md85',1,'']]], ['decodeframe_55',['DecodeFrame',['../structDecodeFrame.html',1,'']]], - ['decodeframe_20tt_56',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md72',1,'']]], - ['decoder_20coverage_57',['Decoder coverage',['../md_tests_2README.html#autotoc_md156',1,'']]], - ['decoder_20layer_58',['Decoder Layer',['../md_README.html#autotoc_md78',1,'']]], + ['decodeframe_20tt_56',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md76',1,'']]], + ['decoder_20coverage_57',['Decoder coverage',['../md_tests_2README.html#autotoc_md162',1,'']]], + ['decoder_20layer_58',['Decoder Layer',['../md_README.html#autotoc_md82',1,'']]], ['decodesignal_59',['DecodeSignal',['../structDecodeSignal.html',1,'']]], - ['decodesignal_20tt_60',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md70',1,'']]], + ['decodesignal_20tt_60',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md74',1,'']]], ['defaultvalue_61',['defaultValue',['../structAttributeDefinition.html#ae0949edf67f9d4e60e4cb376a95da4f2',1,'AttributeDefinition']]], - ['definition_62',['definition',['../structDecodedSignalValue.html#a828b5ef7faefc14fbf5dbd46249bcad2',1,'DecodedSignalValue::definition'],['../structDecodedFrameValue.html#a33e971ba10030506007aa201c89f351d',1,'DecodedFrameValue::definition'],['../structPgnLookupResult.html#aa5b79b61d2aef48fd6ae070cf5f901c1',1,'PgnLookupResult::definition'],['../md_README.html#autotoc_md96',1,'Frame definition'],['../md_README.html#autotoc_md100',1,'Signal definition']]], - ['definition_20lifetime_20and_20reload_20coverage_63',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md160',1,'']]], - ['definition_20ownership_20and_20reload_64',['Definition ownership and reload',['../md_README.html#autotoc_md86',1,'']]], - ['demo_65',['Build and run the demo',['../md_README.html#autotoc_md146',1,'']]], + ['definition_62',['definition',['../structDecodedSignalValue.html#a828b5ef7faefc14fbf5dbd46249bcad2',1,'DecodedSignalValue::definition'],['../structDecodedFrameValue.html#a33e971ba10030506007aa201c89f351d',1,'DecodedFrameValue::definition'],['../structPgnLookupResult.html#aa5b79b61d2aef48fd6ae070cf5f901c1',1,'PgnLookupResult::definition'],['../md_README.html#autotoc_md100',1,'Frame definition'],['../md_README.html#autotoc_md104',1,'Signal definition']]], + ['definition_20lifetime_20and_20reload_20coverage_63',['Definition lifetime and reload coverage',['../md_tests_2README.html#autotoc_md166',1,'']]], + ['definition_20ownership_20and_20reload_64',['Definition ownership and reload',['../md_README.html#autotoc_md90',1,'']]], + ['demo_65',['Build and run the demo',['../md_README.html#autotoc_md151',1,'']]], ['descriptions_66',['descriptions',['../structPendingValueDescriptions.html#a10ecbaeaed2cc3ac82fada73e7e041dd',1,'PendingValueDescriptions']]], - ['descriptions_20tt_20val_5f_20tt_67',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md132',1,'']]], + ['descriptions_20tt_20val_5f_20tt_67',['Signal value descriptions (<tt>VAL_</tt>)',['../md_README.html#autotoc_md136',1,'']]], ['diagnostic_68',['diagnostic',['../classDbcDiagnosticError.html#ab3965082f01d66b6d5c20525af44235d',1,'DbcDiagnosticError']]], - ['diagnostics_69',['diagnostics',['../structDbcParseResult.html#a3a1987b4381bb1e0a34dc09e31483679',1,'DbcParseResult::diagnostics'],['../md_README.html#autotoc_md92',1,'Structured diagnostics']]], + ['diagnostics_69',['diagnostics',['../structDbcParseResult.html#a3a1987b4381bb1e0a34dc09e31483679',1,'DbcParseResult::diagnostics'],['../md_README.html#autotoc_md96',1,'Structured diagnostics']]], ['dispatch_70',['Dispatch',['../classDbcStatementDispatcher.html#a495c2d5c7ebb8103b1987cdd87c142ed',1,'DbcStatementDispatcher']]], ['dlc_71',['dlc',['../structDecodeFrame.html#a51111ac13988be372d5673d12cf3e060',1,'DecodeFrame::dlc'],['../structFrameInfo.html#aa2b198ea0f55e560c123d35e7b3ecab9',1,'FrameInfo::dlc']]], - ['documentation_72',['documentation',['../md_README.html',1,'DBC Parser and Runtime Decode Module Documentation'],['../md_changelog.html#autotoc_md38',1,'Documentation'],['../md_README.html#autotoc_md147',1,'Generate API documentation']]], - ['documentation_20and_20maintenance_73',['documentation and maintenance',['../md_changelog.html#autotoc_md33',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md41',1,'Documentation and maintenance']]] + ['documentation_72',['documentation',['../md_README.html',1,'DBC Parser and Runtime Decode Module Documentation'],['../md_changelog.html#autotoc_md42',1,'Documentation'],['../md_README.html#autotoc_md152',1,'Generate API documentation']]], + ['documentation_20and_20maintenance_73',['documentation and maintenance',['../md_changelog.html#autotoc_md37',1,'Documentation and maintenance'],['../md_changelog.html#autotoc_md45',1,'Documentation and maintenance']]] ]; diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js index c541a1c..7fb6c21 100644 --- a/docs/html/search/all_9.js +++ b/docs/html/search/all_9.js @@ -1,14 +1,14 @@ var searchData= [ ['enablej1939_0',['enablej1939',['../structDbcParserOptions.html#ab31534f5c0853461b46cbb38149c33f9',1,'DbcParserOptions::enableJ1939'],['../structDbcParseContext.html#a93f8ece0f3d16bd79f631ae07afa7b54',1,'DbcParseContext::enableJ1939']]], - ['end_20pipeline_20coverage_1',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md162',1,'']]], - ['end_20to_20end_20pipeline_20coverage_2',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md162',1,'']]], - ['enough_3',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]], + ['end_20pipeline_20coverage_1',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md168',1,'']]], + ['end_20to_20end_20pipeline_20coverage_2',['End-to-end pipeline coverage',['../md_tests_2README.html#autotoc_md168',1,'']]], + ['enough_3',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]], ['enumvalues_4',['enumValues',['../structAttributeDefinition.html#a547fe17f6cfc631528f9156e4a509c66',1,'AttributeDefinition']]], - ['errors_5',['errors',['../md_README.html#autotoc_md98',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md102',1,'Signal validation and parse errors']]], - ['example_20usage_6',['Example Usage',['../md_README.html#autotoc_md116',1,'']]], + ['errors_5',['errors',['../md_README.html#autotoc_md102',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md106',1,'Signal validation and parse errors']]], + ['example_20usage_6',['Example Usage',['../md_README.html#autotoc_md120',1,'']]], ['examples_2fmain_2ecpp_7',['main.cpp',['../examples_2main_8cpp.html',1,'']]], - ['exists_8',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md49',1,'']]], - ['extended_20validation_9',['Extended validation',['../md_tests_2README.html#autotoc_md164',1,'']]], - ['extraction_10',['Intel and Motorola Extraction',['../md_README.html#autotoc_md114',1,'']]] + ['exists_8',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md53',1,'']]], + ['extended_20validation_9',['Extended validation',['../md_tests_2README.html#autotoc_md170',1,'']]], + ['extraction_10',['Intel and Motorola Extraction',['../md_README.html#autotoc_md118',1,'']]] ]; diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js index ccb642e..3d9a39d 100644 --- a/docs/html/search/all_a.js +++ b/docs/html/search/all_a.js @@ -1,27 +1,27 @@ var searchData= [ ['factor_0',['factor',['../structDecodeSignal.html#a428c39913a366a8476dd291061354391',1,'DecodeSignal::factor'],['../structSignalInfo.html#ae4f78d99a2750aa564d7eba860171499',1,'SignalInfo::factor']]], - ['factory_1',['Statement Handler Factory',['../md_README.html#autotoc_md130',1,'']]], + ['factory_1',['Statement Handler Factory',['../md_README.html#autotoc_md134',1,'']]], ['filepath_2',['filePath',['../structDbcDiagnostic.html#ac9f02705ed6a633cbb9526d0e392fb95',1,'DbcDiagnostic']]], ['findframe_3',['findframe',['../classDbcDecoder.html#a4005c4311f57b7faf21c0cb31463039c',1,'DbcDecoder::FindFrame()'],['../classDecodeDatabase.html#a780d6e747a48b10a5eb0ab85448d2970',1,'DecodeDatabase::FindFrame(const FrameKey &key) const']]], ['findframebypgn_4',['FindFrameByPgn',['../classDecodeDatabase.html#aa96b62b4f3fff68ab651674760f60d6d',1,'DecodeDatabase']]], ['findsignal_5',['FindSignal',['../classDecodeDatabase.html#a0af5b15b9953a4f6551c27ee9ae8b514',1,'DecodeDatabase']]], - ['fixed_6',['fixed',['../md_changelog.html#autotoc_md13',1,'Fixed'],['../md_changelog.html#autotoc_md15',1,'Fixed'],['../md_changelog.html#autotoc_md27',1,'Fixed'],['../md_changelog.html#autotoc_md32',1,'Fixed'],['../md_changelog.html#autotoc_md36',1,'Fixed']]], + ['fixed_6',['fixed',['../md_changelog.html#autotoc_md40',1,'Fixed'],['../md_changelog.html#autotoc_md36',1,'Fixed'],['../md_changelog.html#autotoc_md31',1,'Fixed'],['../md_changelog.html#autotoc_md19',1,'Fixed'],['../md_changelog.html#autotoc_md17',1,'Fixed'],['../md_changelog.html#autotoc_md11',1,'Fixed']]], ['flags_7',['flags',['../classDbcTreeModel.html#a8f7842a79144bdb24fa9c5fbdcd37295',1,'DbcTreeModel']]], - ['flow_8',['Decode Flow',['../md_README.html#autotoc_md112',1,'']]], - ['frame_9',['frame',['../md_README.html#autotoc_md120',1,'Decode a raw frame'],['../structSignalKey.html#a25f4ece1bf685791b576f68e23d8ccc7',1,'SignalKey::frame']]], - ['frame_20and_20signal_20identifiers_10',['Stable frame and signal identifiers',['../md_README.html#autotoc_md87',1,'']]], - ['frame_20definition_11',['Frame definition',['../md_README.html#autotoc_md96',1,'']]], - ['frame_20metadata_12',['Attributes and frame metadata',['../md_README.html#autotoc_md93',1,'']]], - ['frame_20validation_20and_20parse_20errors_13',['Frame validation and parse errors',['../md_README.html#autotoc_md98',1,'']]], + ['flow_8',['Decode Flow',['../md_README.html#autotoc_md116',1,'']]], + ['frame_9',['frame',['../md_README.html#autotoc_md124',1,'Decode a raw frame'],['../structSignalKey.html#a25f4ece1bf685791b576f68e23d8ccc7',1,'SignalKey::frame']]], + ['frame_20and_20signal_20identifiers_10',['Stable frame and signal identifiers',['../md_README.html#autotoc_md91',1,'']]], + ['frame_20definition_11',['Frame definition',['../md_README.html#autotoc_md100',1,'']]], + ['frame_20metadata_12',['Attributes and frame metadata',['../md_README.html#autotoc_md97',1,'']]], + ['frame_20validation_20and_20parse_20errors_13',['Frame validation and parse errors',['../md_README.html#autotoc_md102',1,'']]], ['frame_5finfo_2eh_14',['frame_info.h',['../frame__info_8h.html',1,'']]], ['framedecodestatus_15',['FrameDecodeStatus',['../dbc__decoder_8h.html#a855b2bc36cb18bfbae5ff30a2394e961',1,'dbc_decoder.h']]], ['frameformat_16',['frameformat',['../structFrameInfo.html#a35bf839519ef3f48b5f52dd9bcd7e9ac',1,'FrameInfo::frameFormat'],['../structDecodeFrame.html#a475e669f390491a4d99383d3fee51300',1,'DecodeFrame::frameFormat']]], ['frameinfo_17',['FrameInfo',['../structFrameInfo.html',1,'']]], - ['frameinfo_20tt_18',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md56',1,'']]], - ['framekey_19',['framekey',['../structFrameKey.html',1,'FrameKey'],['../structFrameKey.html#a33bde405c7ea53000d54b3dd6e058670',1,'FrameKey::FrameKey()']]], - ['framekey_20tt_20',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md74',1,'']]], + ['frameinfo_20tt_18',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md60',1,'']]], + ['framekey_19',['framekey',['../structFrameKey.html#a33bde405c7ea53000d54b3dd6e058670',1,'FrameKey::FrameKey()'],['../structFrameKey.html',1,'FrameKey']]], + ['framekey_20tt_20',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md78',1,'']]], ['framekeyhasher_21',['FrameKeyHasher',['../structFrameKeyHasher.html',1,'']]], ['frames_22',['frames',['../structDbcDatabase.html#a2cade5d0234ee816132127542f8c612b',1,'DbcDatabase']]], - ['frametap_23',['Intended Use in FrameTap',['../md_README.html#autotoc_md126',1,'']]] + ['frametap_23',['Intended Use in FrameTap',['../md_README.html#autotoc_md130',1,'']]] ]; diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js index 029b961..3628138 100644 --- a/docs/html/search/all_b.js +++ b/docs/html/search/all_b.js @@ -1,9 +1,9 @@ var searchData= [ - ['gcc_20coverage_20build_20in_20qt_20creator_0',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md153',1,'']]], - ['gcc_20gcov_20and_20lcov_20on_20debian_20ubuntu_1',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], - ['gcov_20and_20lcov_20on_20debian_20ubuntu_2',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md152',1,'']]], - ['generate_20api_20documentation_3',['Generate API documentation',['../md_README.html#autotoc_md147',1,'']]], + ['gcc_20coverage_20build_20in_20qt_20creator_0',['Configure the GCC coverage build in Qt Creator',['../md_README.html#autotoc_md158',1,'']]], + ['gcc_20gcov_20and_20lcov_20on_20debian_20ubuntu_1',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], + ['gcov_20and_20lcov_20on_20debian_20ubuntu_2',['GCC, gcov, and LCOV on Debian/Ubuntu',['../md_README.html#autotoc_md157',1,'']]], + ['generate_20api_20documentation_3',['Generate API documentation',['../md_README.html#autotoc_md152',1,'']]], ['getchild_4',['getchild',['../classTreeNode.html#a81047bd7d2a4cc96b9ef5e20d0d63b5f',1,'TreeNode::GetChild(std::size_t index)'],['../classTreeNode.html#a4727ff801a2d1b9323c5ae50a35457a6',1,'TreeNode::GetChild(std::size_t index) const']]], ['getchildcount_5',['GetChildCount',['../classTreeNode.html#abdd82460187dca8d3e5d66f5d5c529ea',1,'TreeNode']]], ['getframe_6',['GetFrame',['../classTreeNode.html#afc503b40004764163605d6dbdb4ef811',1,'TreeNode']]], diff --git a/docs/html/search/all_c.js b/docs/html/search/all_c.js index 2987215..2401cb4 100644 --- a/docs/html/search/all_c.js +++ b/docs/html/search/all_c.js @@ -1,9 +1,9 @@ var searchData= [ - ['handle_0',['handle',['../classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739',1,'DbcStatementHandler::Handle()'],['../classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89',1,'DbcFrameHandler::Handle()'],['../classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b',1,'DbcSignalHandler::Handle()'],['../classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6',1,'DbcCommentHandler::Handle()'],['../classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83',1,'DbcAttributeHandler::Handle()'],['../classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a',1,'DbcValueDescriptionHandler::Handle()'],['../classDbcUnsupportedMultiplexingHandler.html#a9853fd67465f92ef587792986ea179ac',1,'DbcUnsupportedMultiplexingHandler::Handle()'],['../classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693',1,'DbcHeaderHandler::Handle()']]], - ['handler_20factory_1',['Statement Handler Factory',['../md_README.html#autotoc_md130',1,'']]], + ['handle_0',['handle',['../classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739',1,'DbcStatementHandler::Handle()'],['../classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89',1,'DbcFrameHandler::Handle()'],['../classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b',1,'DbcSignalHandler::Handle()'],['../classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6',1,'DbcCommentHandler::Handle()'],['../classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83',1,'DbcAttributeHandler::Handle()'],['../classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a',1,'DbcValueDescriptionHandler::Handle()'],['../classDbcMultiplexingHandler.html#a16f9e9f898640200477d2dcc8bab442e',1,'DbcMultiplexingHandler::Handle()'],['../classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693',1,'DbcHeaderHandler::Handle()']]], + ['handler_20factory_1',['Statement Handler Factory',['../md_README.html#autotoc_md134',1,'']]], ['haserrors_2',['HasErrors',['../structDbcParseResult.html#a4da8641de3f6b55c7447c4421e05d20d',1,'DbcParseResult']]], ['haspgn_3',['haspgn',['../structDecodeFrame.html#a2551102670c4a540fced4c71da0b369d',1,'DecodeFrame::hasPgn'],['../structFrameInfo.html#a4737a5420213ad4304724e39f3a4e55d',1,'FrameInfo::hasPgn']]], ['headerdata_4',['headerData',['../classDbcTreeModel.html#aad5834e8edb00808cbfa498ea8c63fe9',1,'DbcTreeModel']]], - ['high_20level_20architecture_5',['High-Level Architecture',['../md_README.html#autotoc_md45',1,'']]] + ['high_20level_20architecture_5',['High-Level Architecture',['../md_README.html#autotoc_md49',1,'']]] ]; diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js index b3d8824..2134cbd 100644 --- a/docs/html/search/all_d.js +++ b/docs/html/search/all_d.js @@ -1,20 +1,20 @@ var searchData= [ - ['id_20normalization_0',['CAN ID Normalization',['../md_README.html#autotoc_md108',1,'']]], - ['identifiers_1',['Stable frame and signal identifiers',['../md_README.html#autotoc_md87',1,'']]], - ['implementation_20—_202026_2003_2013_2',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md39',1,'']]], - ['implemented_3',['Stage 1 - already implemented',['../md_README.html#autotoc_md137',1,'']]], - ['in_20and_20pgn_20lookup_4',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]], - ['in_20frametap_5',['Intended Use in FrameTap',['../md_README.html#autotoc_md126',1,'']]], - ['in_20qt_20creator_6',['in qt creator',['../md_README.html#autotoc_md154',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md153',1,'Configure the GCC coverage build in Qt Creator']]], + ['id_20normalization_0',['CAN ID Normalization',['../md_README.html#autotoc_md112',1,'']]], + ['identifiers_1',['Stable frame and signal identifiers',['../md_README.html#autotoc_md91',1,'']]], + ['implementation_20—_202026_2003_2013_2',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md43',1,'']]], + ['implemented_3',['Stage 1 - already implemented',['../md_README.html#autotoc_md141',1,'']]], + ['in_20and_20pgn_20lookup_4',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]], + ['in_20frametap_5',['Intended Use in FrameTap',['../md_README.html#autotoc_md130',1,'']]], + ['in_20qt_20creator_6',['in qt creator',['../md_README.html#autotoc_md159',1,'Configure all build variants in Qt Creator'],['../md_README.html#autotoc_md158',1,'Configure the GCC coverage build in Qt Creator']]], ['index_7',['index',['../classDbcTreeModel.html#a8caeb5ec6141eb3e446e48df3c70b3ad',1,'DbcTreeModel']]], - ['initial_20implementation_20—_202026_2003_2013_8',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md39',1,'']]], + ['initial_20implementation_20—_202026_2003_2013_8',['Initial implementation — 2026-03-13',['../md_changelog.html#autotoc_md43',1,'']]], ['integermaximum_9',['integerMaximum',['../structAttributeDefinition.html#a5ca8f41ea3e921f54d81b8760c1dcfb3',1,'AttributeDefinition']]], ['integerminimum_10',['integerMinimum',['../structAttributeDefinition.html#aaf87153bac0b228ad87b88e96f303210',1,'AttributeDefinition']]], - ['integration_11',['Build Integration',['../md_README.html#autotoc_md142',1,'']]], - ['intel_20and_20motorola_20extraction_12',['Intel and Motorola Extraction',['../md_README.html#autotoc_md114',1,'']]], - ['intended_20use_20in_20frametap_13',['Intended Use in FrameTap',['../md_README.html#autotoc_md126',1,'']]], - ['is_20not_20enough_14',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md128',1,'']]], + ['integration_11',['Build Integration',['../md_README.html#autotoc_md146',1,'']]], + ['intel_20and_20motorola_20extraction_12',['Intel and Motorola Extraction',['../md_README.html#autotoc_md118',1,'']]], + ['intended_20use_20in_20frametap_13',['Intended Use in FrameTap',['../md_README.html#autotoc_md130',1,'']]], + ['is_20not_20enough_14',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md132',1,'']]], ['isextended_15',['isextended',['../structFrameInfo.html#a34b726afaad2ac5c697fdb2ac070cdaf',1,'FrameInfo::isExtended'],['../structFrameKey.html#aa3179b709d02ef70cf0e736f040a2145',1,'FrameKey::isExtended'],['../structDecodeFrame.html#a3ee2348d781f8f15aaf87e8dcf57ec41',1,'DecodeFrame::isExtended'],['../structPendingComment.html#a9abd7e15ed59eb4534c66ff74f276e07',1,'PendingComment::isExtended'],['../structPendingValueDescriptions.html#a60f185e8d91010927c4aa3b4a750c9f4',1,'PendingValueDescriptions::isExtended'],['../structRawCanFrame.html#a462193d275adc1dba8bd18ffa0e36bb7',1,'RawCanFrame::isExtended'],['../structAttributeAssignment.html#a024a249cc63dbfbf337eea395fe3471e',1,'AttributeAssignment::isExtended']]], ['islittleendian_16',['isLittleEndian',['../structSignalInfo.html#af363b1563fb4c7cc8973f9a80c06846c',1,'SignalInfo']]], ['issignal_17',['isSignal',['../structPendingComment.html#ac03903ffb042d27ad66012eb18ea1437',1,'PendingComment']]], diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index ba11adf..51bea2d 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -1,4 +1,4 @@ var searchData= [ - ['j1939_20opt_20in_20and_20pgn_20lookup_0',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md110',1,'']]] + ['j1939_20opt_20in_20and_20pgn_20lookup_0',['J1939 Opt-in and PGN Lookup',['../md_README.html#autotoc_md114',1,'']]] ]; diff --git a/docs/html/search/classes_1.js b/docs/html/search/classes_1.js index b58041c..78daa12 100644 --- a/docs/html/search/classes_1.js +++ b/docs/html/search/classes_1.js @@ -9,16 +9,16 @@ var searchData= ['dbcdiagnosticerror_6',['DbcDiagnosticError',['../classDbcDiagnosticError.html',1,'']]], ['dbcframehandler_7',['DbcFrameHandler',['../classDbcFrameHandler.html',1,'']]], ['dbcheaderhandler_8',['DbcHeaderHandler',['../classDbcHeaderHandler.html',1,'']]], - ['dbcparsecontext_9',['DbcParseContext',['../structDbcParseContext.html',1,'']]], - ['dbcparser_10',['DbcParser',['../classDbcParser.html',1,'']]], - ['dbcparseresult_11',['DbcParseResult',['../structDbcParseResult.html',1,'']]], - ['dbcparseroptions_12',['DbcParserOptions',['../structDbcParserOptions.html',1,'']]], - ['dbcsignalhandler_13',['DbcSignalHandler',['../classDbcSignalHandler.html',1,'']]], - ['dbcstatementdispatcher_14',['DbcStatementDispatcher',['../classDbcStatementDispatcher.html',1,'']]], - ['dbcstatementhandler_15',['DbcStatementHandler',['../classDbcStatementHandler.html',1,'']]], - ['dbctreebuilder_16',['DbcTreeBuilder',['../classDbcTreeBuilder.html',1,'']]], - ['dbctreemodel_17',['DbcTreeModel',['../classDbcTreeModel.html',1,'']]], - ['dbcunsupportedmultiplexinghandler_18',['DbcUnsupportedMultiplexingHandler',['../classDbcUnsupportedMultiplexingHandler.html',1,'']]], + ['dbcmultiplexinghandler_9',['DbcMultiplexingHandler',['../classDbcMultiplexingHandler.html',1,'']]], + ['dbcparsecontext_10',['DbcParseContext',['../structDbcParseContext.html',1,'']]], + ['dbcparser_11',['DbcParser',['../classDbcParser.html',1,'']]], + ['dbcparseresult_12',['DbcParseResult',['../structDbcParseResult.html',1,'']]], + ['dbcparseroptions_13',['DbcParserOptions',['../structDbcParserOptions.html',1,'']]], + ['dbcsignalhandler_14',['DbcSignalHandler',['../classDbcSignalHandler.html',1,'']]], + ['dbcstatementdispatcher_15',['DbcStatementDispatcher',['../classDbcStatementDispatcher.html',1,'']]], + ['dbcstatementhandler_16',['DbcStatementHandler',['../classDbcStatementHandler.html',1,'']]], + ['dbctreebuilder_17',['DbcTreeBuilder',['../classDbcTreeBuilder.html',1,'']]], + ['dbctreemodel_18',['DbcTreeModel',['../classDbcTreeModel.html',1,'']]], ['dbcvaluedescriptionhandler_19',['DbcValueDescriptionHandler',['../classDbcValueDescriptionHandler.html',1,'']]], ['decodedatabase_20',['DecodeDatabase',['../classDecodeDatabase.html',1,'']]], ['decodedframevalue_21',['DecodedFrameValue',['../structDecodedFrameValue.html',1,'']]], diff --git a/docs/html/search/classes_3.js b/docs/html/search/classes_3.js index 731f810..b1abc26 100644 --- a/docs/html/search/classes_3.js +++ b/docs/html/search/classes_3.js @@ -1,4 +1,7 @@ var searchData= [ - ['multiplexing_0',['Multiplexing',['../structMultiplexing.html',1,'']]] + ['multiplexerror_0',['MultiplexError',['../classdbc__detail_1_1MultiplexError.html',1,'dbc_detail']]], + ['multiplexgraph_1',['MultiplexGraph',['../classdbc__detail_1_1MultiplexGraph.html',1,'dbc_detail']]], + ['multiplexing_2',['Multiplexing',['../structMultiplexing.html',1,'']]], + ['multiplexrange_3',['MultiplexRange',['../structMultiplexRange.html',1,'']]] ]; diff --git a/docs/html/search/classes_4.js b/docs/html/search/classes_4.js index 34a0261..aec83fb 100644 --- a/docs/html/search/classes_4.js +++ b/docs/html/search/classes_4.js @@ -2,6 +2,7 @@ var searchData= [ ['pendingattribute_0',['PendingAttribute',['../structPendingAttribute.html',1,'']]], ['pendingcomment_1',['PendingComment',['../structPendingComment.html',1,'']]], - ['pendingvaluedescriptions_2',['PendingValueDescriptions',['../structPendingValueDescriptions.html',1,'']]], - ['pgnlookupresult_3',['PgnLookupResult',['../structPgnLookupResult.html',1,'']]] + ['pendingmultiplexing_2',['PendingMultiplexing',['../structPendingMultiplexing.html',1,'']]], + ['pendingvaluedescriptions_3',['PendingValueDescriptions',['../structPendingValueDescriptions.html',1,'']]], + ['pgnlookupresult_4',['PgnLookupResult',['../structPgnLookupResult.html',1,'']]] ]; diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js index 4c76e30..62b5854 100644 --- a/docs/html/search/functions_6.js +++ b/docs/html/search/functions_6.js @@ -1,6 +1,6 @@ var searchData= [ - ['handle_0',['handle',['../classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739',1,'DbcStatementHandler::Handle()'],['../classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89',1,'DbcFrameHandler::Handle()'],['../classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b',1,'DbcSignalHandler::Handle()'],['../classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6',1,'DbcCommentHandler::Handle()'],['../classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83',1,'DbcAttributeHandler::Handle()'],['../classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a',1,'DbcValueDescriptionHandler::Handle()'],['../classDbcUnsupportedMultiplexingHandler.html#a9853fd67465f92ef587792986ea179ac',1,'DbcUnsupportedMultiplexingHandler::Handle()'],['../classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693',1,'DbcHeaderHandler::Handle()']]], + ['handle_0',['handle',['../classDbcStatementHandler.html#a3de86e1e27e9bcb0fe6f1460a8ba5739',1,'DbcStatementHandler::Handle()'],['../classDbcFrameHandler.html#a0d3f43bbcc5e191460bc31827e74ce89',1,'DbcFrameHandler::Handle()'],['../classDbcSignalHandler.html#ad7d891ec1414fb645f85ccd410f2737b',1,'DbcSignalHandler::Handle()'],['../classDbcCommentHandler.html#aa4fce77b585a441d251d8535ef7a51a6',1,'DbcCommentHandler::Handle()'],['../classDbcAttributeHandler.html#a397f23259b7ff79abb4b5141489caa83',1,'DbcAttributeHandler::Handle()'],['../classDbcValueDescriptionHandler.html#a653e13364f396b54244edc2c0fdd831a',1,'DbcValueDescriptionHandler::Handle()'],['../classDbcMultiplexingHandler.html#a16f9e9f898640200477d2dcc8bab442e',1,'DbcMultiplexingHandler::Handle()'],['../classDbcHeaderHandler.html#a1e43a9dcf157f4d4418032d9e9711693',1,'DbcHeaderHandler::Handle()']]], ['haserrors_1',['HasErrors',['../structDbcParseResult.html#a4da8641de3f6b55c7447c4421e05d20d',1,'DbcParseResult']]], ['headerdata_2',['headerData',['../classDbcTreeModel.html#aad5834e8edb00808cbfa498ea8c63fe9',1,'DbcTreeModel']]] ]; diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js index be5983e..539f29d 100644 --- a/docs/html/search/functions_b.js +++ b/docs/html/search/functions_b.js @@ -1,6 +1,6 @@ var searchData= [ - ['registertype_0',['registertype',['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory::registerType()'],['../classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d',1,'DbcStatementDispatcher::RegisterType()']]], + ['registertype_0',['registertype',['../classDbcStatementDispatcher.html#a2c6e9a614ed747275d43bcccc50d0b2d',1,'DbcStatementDispatcher::RegisterType()'],['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory::registerType()']]], ['resolveattributes_1',['ResolveAttributes',['../structDbcParseContext.html#a1ac7f4a54550aaddef08749806f87001',1,'DbcParseContext']]], ['resolvecomments_2',['ResolveComments',['../structDbcParseContext.html#aeae343c57a244634489a0e0b960155d7',1,'DbcParseContext']]], ['resolvevaluedescriptions_3',['ResolveValueDescriptions',['../structDbcParseContext.html#ab5552dad944fde7fa6add6464ddb5369',1,'DbcParseContext']]], diff --git a/docs/html/search/variables_e.js b/docs/html/search/variables_e.js index 90d9513..ef61cda 100644 --- a/docs/html/search/variables_e.js +++ b/docs/html/search/variables_e.js @@ -1,6 +1,6 @@ var searchData= [ - ['rawvalue_0',['rawValue',['../structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28',1,'DecodedSignalValue']]], - ['receivers_1',['receivers',['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers'],['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers']]], - ['role_2',['role',['../structMultiplexing.html#a62b70a0e3f2a9c7a457b3694ce8625c3',1,'Multiplexing']]] + ['ranges_0',['ranges',['../structMultiplexing.html#aa174ac4a3af9b361d2de7517dfd4b69e',1,'Multiplexing']]], + ['rawvalue_1',['rawValue',['../structDecodedSignalValue.html#a503c90b4b1a610b8252c45e466367c28',1,'DecodedSignalValue']]], + ['receivers_2',['receivers',['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers'],['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers']]] ]; diff --git a/docs/html/search/variables_f.js b/docs/html/search/variables_f.js index f2ede46..54edc6a 100644 --- a/docs/html/search/variables_f.js +++ b/docs/html/search/variables_f.js @@ -1,10 +1,11 @@ var searchData= [ ['scope_0',['scope',['../structAttributeDefinition.html#a5f109f0ec94eb04c3f52c116366aefdf',1,'AttributeDefinition::scope'],['../structAttributeAssignment.html#a50405e8db9e4536015f9adc5ba360270',1,'AttributeAssignment::scope']]], - ['severity_1',['severity',['../structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d',1,'DbcDiagnostic']]], - ['signallines_2',['signalLines',['../structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546',1,'DbcParseContext']]], - ['signalname_3',['signalname',['../structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90',1,'PendingValueDescriptions::signalName'],['../structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27',1,'PendingComment::signalName']]], - ['startbit_4',['startbit',['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit'],['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit']]], - ['statement_5',['statement',['../structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8',1,'PendingAttribute']]], - ['status_6',['status',['../structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6',1,'DecodedSignalValue::status'],['../structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9',1,'DecodedFrameValue::status']]] + ['selector_1',['selector',['../structMultiplexing.html#aa91e54403c78a663686b2fd22282afaf',1,'Multiplexing']]], + ['severity_2',['severity',['../structDbcDiagnostic.html#a75040a94f0313a606478020b0491f81d',1,'DbcDiagnostic']]], + ['signallines_3',['signalLines',['../structDbcParseContext.html#af8b411c938a2ea9100c4aaae452e6546',1,'DbcParseContext']]], + ['signalname_4',['signalname',['../structPendingValueDescriptions.html#ac35446db10ebda5a12349759613f8c90',1,'PendingValueDescriptions::signalName'],['../structPendingComment.html#ae7b5aea9c252a4ab87e02915d24fee27',1,'PendingComment::signalName']]], + ['startbit_5',['startbit',['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit'],['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit']]], + ['statement_6',['statement',['../structPendingAttribute.html#a0ec62fc577e3a2d5f63d926f829e2ab8',1,'PendingAttribute']]], + ['status_7',['status',['../structDecodedSignalValue.html#a94161a80412b3961da8fd2fec43c25f6',1,'DecodedSignalValue::status'],['../structDecodedFrameValue.html#a645f433798d48a2787e7f00dfbb7dff9',1,'DecodedFrameValue::status']]] ]; diff --git a/docs/html/signal__info_8h_source.html b/docs/html/signal__info_8h_source.html index 63647fc..f6456e9 100644 --- a/docs/html/signal__info_8h_source.html +++ b/docs/html/signal__info_8h_source.html @@ -131,7 +131,7 @@ $(document).ready(function(){initNavTree('signal__info_8h_source.html',''); init
    45
    46#endif /* SIGNAL_INFO_H */
    -
    +
    Basic markers and optional explicit extended multiplexing condition.
    Describes one signal inside a DBC frame.
    Definition signal_info.h:25
    std::uint32_t length
    Definition signal_info.h:29
    std::string unit
    Definition signal_info.h:36
    diff --git a/docs/html/structAttributeAssignment.html b/docs/html/structAttributeAssignment.html index 3b8f173..214c892 100644 --- a/docs/html/structAttributeAssignment.html +++ b/docs/html/structAttributeAssignment.html @@ -138,7 +138,7 @@ Public Attributes

    Definition at line 60 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -157,7 +157,7 @@ Public Attributes

    Definition at line 61 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -176,7 +176,7 @@ Public Attributes

    Definition at line 62 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -195,7 +195,7 @@ Public Attributes

    Definition at line 63 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -214,7 +214,7 @@ Public Attributes

    Definition at line 64 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -233,7 +233,7 @@ Public Attributes

    Definition at line 65 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    diff --git a/docs/html/structAttributeDefinition.html b/docs/html/structAttributeDefinition.html index 13b6d44..6572a4a 100644 --- a/docs/html/structAttributeDefinition.html +++ b/docs/html/structAttributeDefinition.html @@ -141,7 +141,7 @@ Public Attributes

    Definition at line 43 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -262,7 +262,7 @@ Public Attributes

    Definition at line 50 of file attributes.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    diff --git a/docs/html/structDbcDatabase.html b/docs/html/structDbcDatabase.html index 7902c73..13310b9 100644 --- a/docs/html/structDbcDatabase.html +++ b/docs/html/structDbcDatabase.html @@ -133,7 +133,7 @@ Public Attributes

    Definition at line 23 of file dbc_database.h.

    -

    Referenced by DbcTreeBuilder::Build(), DbcDecodeBuilder::Build(), DbcFrameHandler::Handle(), DbcParseContext::ResolveAttributes(), and DbcParseContext::ValidateMultiplexing().

    +

    Referenced by DbcTreeBuilder::Build(), DbcDecodeBuilder::Build(), DbcFrameHandler::Handle(), DbcParseContext::ResolveAttributes(), and DbcParseContext::ValidateMultiplexing().

    @@ -152,7 +152,7 @@ Public Attributes

    Definition at line 24 of file dbc_database.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    @@ -171,7 +171,7 @@ Public Attributes

    Definition at line 25 of file dbc_database.h.

    -

    Referenced by DbcParseContext::ResolveAttributes().

    +

    Referenced by DbcParseContext::ResolveAttributes().

    diff --git a/docs/html/structDbcParseContext-members.html b/docs/html/structDbcParseContext-members.html index 98fdcad..61bfdf7 100644 --- a/docs/html/structDbcParseContext-members.html +++ b/docs/html/structDbcParseContext-members.html @@ -102,9 +102,11 @@ $(document).ready(function(){initNavTree('structDbcParseContext.html',''); initR lineNumberDbcParseContext pendingAttributesDbcParseContext pendingCommentsDbcParseContext - pendingValuesDbcParseContext - ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)DbcParseContext - ResolveComments(const std::string &filePath)DbcParseContext + pendingMultiplexing (defined in DbcParseContext)DbcParseContext + pendingValuesDbcParseContext + ResolveAttributes(const std::string &filePath, std::vector< DbcDiagnostic > &diagnostics)DbcParseContext + ResolveComments(const std::string &filePath)DbcParseContext + ResolveMultiplexing(const std::string &filePath) (defined in DbcParseContext)DbcParseContext ResolveValueDescriptions(const std::string &filePath)DbcParseContext signalLinesDbcParseContext ValidateMultiplexing(const std::string &filePath) constDbcParseContext diff --git a/docs/html/structDbcParseContext.html b/docs/html/structDbcParseContext.html index 3f48e49..4c10ee2 100644 --- a/docs/html/structDbcParseContext.html +++ b/docs/html/structDbcParseContext.html @@ -102,6 +102,8 @@ $(document).ready(function(){initNavTree('structDbcParseContext.html',''); initR + + @@ -127,6 +129,8 @@ Public Attributes + + @@ -137,8 +141,28 @@ Public Attributes

    Detailed Description

    Mutable state belonging to one file parse. Handlers do not retain it.

    -

    Definition at line 50 of file dbc_statement_handler.h.

    +

    Definition at line 60 of file dbc_statement_handler.h.

    Member Function Documentation

    + +

    ◆ ResolveMultiplexing()

    + +
    +
    +

    Public Member Functions

    void ResolveMultiplexing (const std::string &filePath)
     
    void ValidateMultiplexing (const std::string &filePath) const
     Validate selectors, branch ranges, and signal overlap.
     
     
    std::vector< PendingValueDescriptions > pendingValues = {}
     
    std::vector< PendingMultiplexing > pendingMultiplexing = {}
     
    std::vector< std::vector< std::size_t > > signalLines = {}
     
    std::vector< PendingComment > pendingComments = {}
    + + + + + + + +
    void DbcParseContext::ResolveMultiplexing (const std::string & filePath)
    +
    + +

    Definition at line 486 of file dbc_statement_handler.cpp.

    + +
    +

    ◆ ValidateMultiplexing()

    @@ -157,9 +181,9 @@ Public Attributes

    Validate selectors, branch ranges, and signal overlap.

    -

    Definition at line 512 of file dbc_statement_handler.cpp.

    +

    Definition at line 536 of file dbc_statement_handler.cpp.

    -

    References database, DbcDatabase::frames, and signalLines.

    +

    References database, DbcDatabase::frames, SignalInfo::isSigned, SignalInfo::multiplexing, and signalLines.

    @@ -181,9 +205,9 @@ Public Attributes

    Resolve deferred comments after all definitions are known.

    -

    Definition at line 352 of file dbc_statement_handler.cpp.

    +

    Definition at line 354 of file dbc_statement_handler.cpp.

    -

    References FrameInfo::comment, SignalInfo::comment, database, and pendingComments.

    +

    References FrameInfo::comment, SignalInfo::comment, database, and pendingComments.

    @@ -215,9 +239,9 @@ Public Attributes

    Resolve definitions, defaults, then assignments; append format warnings.

    -

    Definition at line 255 of file dbc_attributes.cpp.

    +

    Definition at line 259 of file dbc_attributes.cpp.

    -

    References DbcDatabase::attributeAssignments, DbcDatabase::attributeDefinitions, AttributeAssignment::canId, database, AttributeDefinition::defaultValue, DbcDatabase::frames, AttributeAssignment::isExtended, AttributeAssignment::name, pendingAttributes, AttributeDefinition::scope, AttributeAssignment::scope, AttributeAssignment::targetName, and AttributeAssignment::value.

    +

    References DbcDatabase::attributeAssignments, DbcDatabase::attributeDefinitions, AttributeAssignment::canId, database, AttributeDefinition::defaultValue, DbcDatabase::frames, AttributeAssignment::isExtended, AttributeAssignment::name, pendingAttributes, AttributeDefinition::scope, AttributeAssignment::scope, AttributeAssignment::targetName, and AttributeAssignment::value.

    @@ -239,9 +263,9 @@ Public Attributes

    Resolve deferred raw descriptions against unique targets.

    -

    Definition at line 435 of file dbc_statement_handler.cpp.

    +

    Definition at line 437 of file dbc_statement_handler.cpp.

    -

    References database, pendingValues, and SignalInfo::valueDescriptions.

    +

    References database, pendingValues, and SignalInfo::valueDescriptions.

    @@ -259,9 +283,9 @@ Public Attributes

    Parsed metadata under construction.

    -

    Definition at line 51 of file dbc_statement_handler.h.

    +

    Definition at line 61 of file dbc_statement_handler.h.

    -

    Referenced by DbcFrameHandler::Handle(), ResolveAttributes(), ResolveComments(), ResolveValueDescriptions(), and ValidateMultiplexing().

    +

    Referenced by DbcFrameHandler::Handle(), ResolveAttributes(), ResolveComments(), ResolveValueDescriptions(), and ValidateMultiplexing().

    @@ -278,9 +302,9 @@ Public Attributes

    Current frame for following signal definitions.

    -

    Definition at line 52 of file dbc_statement_handler.h.

    +

    Definition at line 62 of file dbc_statement_handler.h.

    -

    Referenced by DbcFrameHandler::Handle(), and DbcSignalHandler::Handle().

    +

    Referenced by DbcFrameHandler::Handle(), and DbcSignalHandler::Handle().

    @@ -297,9 +321,9 @@ Public Attributes

    Explicit interpretation option for extended frames.

    -

    Definition at line 53 of file dbc_statement_handler.h.

    +

    Definition at line 63 of file dbc_statement_handler.h.

    -

    Referenced by DbcFrameHandler::Handle().

    +

    Referenced by DbcFrameHandler::Handle().

    @@ -316,9 +340,9 @@ Public Attributes

    Physical line of the current statement.

    -

    Definition at line 54 of file dbc_statement_handler.h.

    +

    Definition at line 64 of file dbc_statement_handler.h.

    -

    Referenced by DbcSignalHandler::Handle(), DbcCommentHandler::Handle(), DbcAttributeHandler::Handle(), and DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcSignalHandler::Handle(), DbcCommentHandler::Handle(), DbcAttributeHandler::Handle(), DbcValueDescriptionHandler::Handle(), and DbcMultiplexingHandler::Handle().

    @@ -335,9 +359,25 @@ Public Attributes

    Unresolved raw value descriptions.

    -

    Definition at line 55 of file dbc_statement_handler.h.

    +

    Definition at line 65 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle(), and ResolveValueDescriptions().

    +

    Referenced by DbcValueDescriptionHandler::Handle(), and ResolveValueDescriptions().

    + +
    + + +

    ◆ pendingMultiplexing

    + +
    +
    + + + + +
    std::vector<PendingMultiplexing> DbcParseContext::pendingMultiplexing = {}
    +
    + +

    Definition at line 67 of file dbc_statement_handler.h.

    @@ -354,9 +394,9 @@ Public Attributes

    Signal definition lines grouped by frame.

    -

    Definition at line 57 of file dbc_statement_handler.h.

    +

    Definition at line 70 of file dbc_statement_handler.h.

    -

    Referenced by DbcFrameHandler::Handle(), DbcSignalHandler::Handle(), and ValidateMultiplexing().

    +

    Referenced by DbcFrameHandler::Handle(), DbcSignalHandler::Handle(), and ValidateMultiplexing().

    @@ -373,9 +413,9 @@ Public Attributes

    Unresolved comments in source order.

    -

    Definition at line 61 of file dbc_statement_handler.h.

    +

    Definition at line 74 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle(), and ResolveComments().

    +

    Referenced by DbcCommentHandler::Handle(), and ResolveComments().

    @@ -392,9 +432,9 @@ Public Attributes

    Unresolved attributes in source order.

    -

    Definition at line 65 of file dbc_statement_handler.h.

    +

    Definition at line 78 of file dbc_statement_handler.h.

    -

    Referenced by DbcAttributeHandler::Handle(), and ResolveAttributes().

    +

    Referenced by DbcAttributeHandler::Handle(), and ResolveAttributes().

    diff --git a/docs/html/structDbcParseResult.html b/docs/html/structDbcParseResult.html index 59323e0..884644c 100644 --- a/docs/html/structDbcParseResult.html +++ b/docs/html/structDbcParseResult.html @@ -168,7 +168,7 @@ Public Attributes

    Definition at line 39 of file dbc_diagnostic.h.

    -

    Referenced by DbcParser::ParseFile(), and DbcParser::ParseFileWithDiagnostics().

    +

    Referenced by DbcParser::ParseFile(), and DbcParser::ParseFileWithDiagnostics().

    @@ -187,7 +187,7 @@ Public Attributes

    Definition at line 40 of file dbc_diagnostic.h.

    -

    Referenced by HasErrors(), DbcParser::ParseFile(), and DbcParser::ParseFileWithDiagnostics().

    +

    Referenced by HasErrors(), DbcParser::ParseFile(), and DbcParser::ParseFileWithDiagnostics().

    diff --git a/docs/html/structDbcParserOptions.html b/docs/html/structDbcParserOptions.html index e400804..067b0a4 100644 --- a/docs/html/structDbcParserOptions.html +++ b/docs/html/structDbcParserOptions.html @@ -124,7 +124,7 @@ Public Attributes

    Definition at line 21 of file dbc_parser.h.

    -

    Referenced by DbcParser::ParseFileWithDiagnostics().

    +

    Referenced by DbcParser::ParseFileWithDiagnostics().

    diff --git a/docs/html/structDecodeFrame.html b/docs/html/structDecodeFrame.html index 6b4b1ac..368ef4a 100644 --- a/docs/html/structDecodeFrame.html +++ b/docs/html/structDecodeFrame.html @@ -139,7 +139,7 @@ Public Attributes

    Detailed Description

    Runtime-ready frame definition.

    -

    Definition at line 68 of file decode_database.h.

    +

    Definition at line 69 of file decode_database.h.

    Member Function Documentation

    ◆ GetKey()

    @@ -166,9 +166,9 @@ Public Attributes

    Return the stable normalized frame identifier.

    -

    Definition at line 86 of file decode_database.h.

    +

    Definition at line 87 of file decode_database.h.

    -

    References canId, and isExtended.

    +

    References canId, and isExtended.

    @@ -186,7 +186,7 @@ Public Attributes

    Frame name.

    -

    Definition at line 69 of file decode_database.h.

    +

    Definition at line 70 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -205,9 +205,9 @@ Public Attributes

    Normalized CAN ID.

    -

    Definition at line 70 of file decode_database.h.

    +

    Definition at line 71 of file decode_database.h.

    -

    Referenced by DbcDecodeBuilder::Build(), and GetKey().

    +

    Referenced by DbcDecodeBuilder::Build(), and GetKey().

    @@ -224,9 +224,9 @@ Public Attributes

    true for extended frame.

    -

    Definition at line 71 of file decode_database.h.

    +

    Definition at line 72 of file decode_database.h.

    -

    Referenced by DbcDecodeBuilder::Build(), and GetKey().

    +

    Referenced by DbcDecodeBuilder::Build(), and GetKey().

    @@ -243,7 +243,7 @@ Public Attributes

    Payload length.

    -

    Definition at line 72 of file decode_database.h.

    +

    Definition at line 73 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -262,7 +262,7 @@ Public Attributes

    PGN if available.

    -

    Definition at line 73 of file decode_database.h.

    +

    Definition at line 74 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -281,7 +281,7 @@ Public Attributes

    Explicit J1939 opt-in; pgn must match canId.

    -

    Definition at line 74 of file decode_database.h.

    +

    Definition at line 75 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -300,7 +300,7 @@ Public Attributes

    Transmitter ECU.

    -

    Definition at line 75 of file decode_database.h.

    +

    Definition at line 76 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -319,7 +319,7 @@ Public Attributes

    Frame comment.

    -

    Definition at line 76 of file decode_database.h.

    +

    Definition at line 77 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -338,7 +338,7 @@ Public Attributes

    Signal definitions.

    -

    Definition at line 77 of file decode_database.h.

    +

    Definition at line 78 of file decode_database.h.

    @@ -355,7 +355,7 @@ Public Attributes

    Effective attributes after defaults and overrides.

    -

    Definition at line 79 of file decode_database.h.

    +

    Definition at line 80 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -374,7 +374,7 @@ Public Attributes

    VFrameFormat label, when declared.

    -

    Definition at line 80 of file decode_database.h.

    +

    Definition at line 81 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -393,7 +393,7 @@ Public Attributes

    GenMsgCycleTime in milliseconds, when declared.

    -

    Definition at line 81 of file decode_database.h.

    +

    Definition at line 82 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    diff --git a/docs/html/structDecodeSignal.html b/docs/html/structDecodeSignal.html index e72e8c0..8c5f651 100644 --- a/docs/html/structDecodeSignal.html +++ b/docs/html/structDecodeSignal.html @@ -138,7 +138,7 @@ Public Attributes

    Detailed Description

    Runtime-ready signal definition.

    -

    Definition at line 44 of file decode_database.h.

    +

    Definition at line 45 of file decode_database.h.

    Member Data Documentation

    ◆ multiplexing

    @@ -151,9 +151,9 @@ Public Attributes
    -

    Selector role and branch value.

    +

    Selector role, parent, and raw branch ranges.

    -

    Definition at line 45 of file decode_database.h.

    +

    Definition at line 46 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -172,9 +172,9 @@ Public Attributes

    Signal name.

    -

    Definition at line 46 of file decode_database.h.

    +

    Definition at line 47 of file decode_database.h.

    -

    Referenced by DbcDecodeBuilder::Build(), and DecodeDatabase::FindSignal().

    +

    Referenced by DbcDecodeBuilder::Build(), and DecodeDatabase::FindSignal().

    @@ -191,7 +191,7 @@ Public Attributes

    DBC start bit.

    -

    Definition at line 47 of file decode_database.h.

    +

    Definition at line 48 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -210,7 +210,7 @@ Public Attributes

    Signal length in bits.

    -

    Definition at line 48 of file decode_database.h.

    +

    Definition at line 49 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -229,7 +229,7 @@ Public Attributes

    Intel or Motorola.

    -

    Definition at line 49 of file decode_database.h.

    +

    Definition at line 50 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -248,7 +248,7 @@ Public Attributes

    Signed or unsigned.

    -

    Definition at line 50 of file decode_database.h.

    +

    Definition at line 51 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -267,7 +267,7 @@ Public Attributes

    Scaling factor.

    -

    Definition at line 51 of file decode_database.h.

    +

    Definition at line 52 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -286,7 +286,7 @@ Public Attributes

    Physical offset.

    -

    Definition at line 52 of file decode_database.h.

    +

    Definition at line 53 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -305,7 +305,7 @@ Public Attributes

    Minimum physical value.

    -

    Definition at line 53 of file decode_database.h.

    +

    Definition at line 54 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -324,7 +324,7 @@ Public Attributes

    Maximum physical value.

    -

    Definition at line 54 of file decode_database.h.

    +

    Definition at line 55 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -343,7 +343,7 @@ Public Attributes

    Physical unit.

    -

    Definition at line 55 of file decode_database.h.

    +

    Definition at line 56 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -362,7 +362,7 @@ Public Attributes

    Receivers.

    -

    Definition at line 56 of file decode_database.h.

    +

    Definition at line 57 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -381,7 +381,7 @@ Public Attributes

    Raw integer state descriptions.

    -

    Definition at line 57 of file decode_database.h.

    +

    Definition at line 58 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -400,7 +400,7 @@ Public Attributes

    Comment.

    -

    Definition at line 58 of file decode_database.h.

    +

    Definition at line 59 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    @@ -419,7 +419,7 @@ Public Attributes

    Effective attributes after defaults and overrides.

    -

    Definition at line 60 of file decode_database.h.

    +

    Definition at line 61 of file decode_database.h.

    Referenced by DbcDecodeBuilder::Build().

    diff --git a/docs/html/structDecodedFrameValue.html b/docs/html/structDecodedFrameValue.html index 0961705..03e2a68 100644 --- a/docs/html/structDecodedFrameValue.html +++ b/docs/html/structDecodedFrameValue.html @@ -118,7 +118,7 @@ Public Attributes

    Detailed Description

    Fully decoded frame.

    -

    Definition at line 73 of file dbc_decoder.h.

    +

    Definition at line 74 of file dbc_decoder.h.

    Member Data Documentation

    ◆ definition

    @@ -133,7 +133,7 @@ Public Attributes

    Owning immutable definition.

    -

    Definition at line 74 of file dbc_decoder.h.

    +

    Definition at line 75 of file dbc_decoder.h.

    @@ -150,7 +150,7 @@ Public Attributes

    Matched definition key; received key if unmatched.

    -

    Definition at line 75 of file dbc_decoder.h.

    +

    Definition at line 76 of file dbc_decoder.h.

    @@ -167,7 +167,7 @@ Public Attributes

    Decoded signal values.

    -

    Definition at line 76 of file dbc_decoder.h.

    +

    Definition at line 77 of file dbc_decoder.h.

    @@ -184,7 +184,7 @@ Public Attributes

    true if frame was matched.

    -

    Definition at line 77 of file dbc_decoder.h.

    +

    Definition at line 78 of file dbc_decoder.h.

    @@ -201,7 +201,7 @@ Public Attributes

    Inspect signals for individual failures.

    -

    Definition at line 78 of file dbc_decoder.h.

    +

    Definition at line 79 of file dbc_decoder.h.

    diff --git a/docs/html/structDecodedSignalValue.html b/docs/html/structDecodedSignalValue.html index f4ca269..607498d 100644 --- a/docs/html/structDecodedSignalValue.html +++ b/docs/html/structDecodedSignalValue.html @@ -126,7 +126,7 @@ Public Attributes

    Detailed Description

    One decoded signal value.

    -

    Definition at line 54 of file dbc_decoder.h.

    +

    Definition at line 55 of file dbc_decoder.h.

    Member Function Documentation

    ◆ GetValueDescription()

    @@ -152,9 +152,9 @@ Public Attributes

    Lookup using the raw integer; nullptr for invalid or unmapped values.

    -

    Definition at line 63 of file dbc_decoder.h.

    +

    Definition at line 64 of file dbc_decoder.h.

    -

    References definition, rawValue, and valid.

    +

    References definition, rawValue, and valid.

    @@ -172,9 +172,9 @@ Public Attributes

    Owning immutable definition.

    -

    Definition at line 55 of file dbc_decoder.h.

    +

    Definition at line 56 of file dbc_decoder.h.

    -

    Referenced by GetValueDescription().

    +

    Referenced by GetValueDescription().

    @@ -191,7 +191,7 @@ Public Attributes

    Stable application identifier.

    -

    Definition at line 56 of file dbc_decoder.h.

    +

    Definition at line 57 of file dbc_decoder.h.

    @@ -208,9 +208,9 @@ Public Attributes

    Exact raw value for Valid or PhysicalConversionFailed.

    -

    Definition at line 57 of file dbc_decoder.h.

    +

    Definition at line 58 of file dbc_decoder.h.

    -

    Referenced by GetValueDescription().

    +

    Referenced by GetValueDescription().

    @@ -227,7 +227,7 @@ Public Attributes

    Conversion result, possibly NaN/Inf on failure.

    -

    Definition at line 58 of file dbc_decoder.h.

    +

    Definition at line 59 of file dbc_decoder.h.

    @@ -244,9 +244,9 @@ Public Attributes

    true if decoding succeeded.

    -

    Definition at line 59 of file dbc_decoder.h.

    +

    Definition at line 60 of file dbc_decoder.h.

    -

    Referenced by GetValueDescription().

    +

    Referenced by GetValueDescription().

    @@ -263,7 +263,7 @@ Public Attributes

    Detailed signal outcome.

    -

    Definition at line 60 of file dbc_decoder.h.

    +

    Definition at line 61 of file dbc_decoder.h.

    diff --git a/docs/html/structFrameInfo.html b/docs/html/structFrameInfo.html index 9d04ac9..a89d843 100644 --- a/docs/html/structFrameInfo.html +++ b/docs/html/structFrameInfo.html @@ -149,7 +149,7 @@ Public Attributes

    Definition at line 26 of file frame_info.h.

    -

    Referenced by DbcSignalHandler::Handle().

    +

    Referenced by DbcSignalHandler::Handle().

    @@ -168,7 +168,7 @@ Public Attributes

    Definition at line 27 of file frame_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcFrameHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcFrameHandler::Handle().

    @@ -187,7 +187,7 @@ Public Attributes

    Definition at line 28 of file frame_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcFrameHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcFrameHandler::Handle().

    @@ -206,7 +206,7 @@ Public Attributes

    Definition at line 29 of file frame_info.h.

    -

    Referenced by DbcFrameHandler::Handle().

    +

    Referenced by DbcFrameHandler::Handle().

    @@ -225,7 +225,7 @@ Public Attributes

    Definition at line 30 of file frame_info.h.

    -

    Referenced by DbcFrameHandler::Handle().

    +

    Referenced by DbcFrameHandler::Handle().

    @@ -244,7 +244,7 @@ Public Attributes

    Definition at line 31 of file frame_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    @@ -280,7 +280,7 @@ Public Attributes

    Definition at line 33 of file frame_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveComments().

    +

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveComments().

    diff --git a/docs/html/structMultiplexRange-members.html b/docs/html/structMultiplexRange-members.html new file mode 100644 index 0000000..ac801bf --- /dev/null +++ b/docs/html/structMultiplexRange-members.html @@ -0,0 +1,110 @@ + + + + + + + +DBC Framework: Member List + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    MultiplexRange Member List
    +
    +
    + +

    This is the complete list of members for MultiplexRange, including all inherited members.

    + + + +
    maximum (defined in MultiplexRange)MultiplexRange
    minimum (defined in MultiplexRange)MultiplexRange
    +
    + + + + diff --git a/docs/html/structMultiplexRange.html b/docs/html/structMultiplexRange.html new file mode 100644 index 0000000..b22fc0b --- /dev/null +++ b/docs/html/structMultiplexRange.html @@ -0,0 +1,162 @@ + + + + + + + +DBC Framework: MultiplexRange Struct Reference + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    MultiplexRange Struct Reference
    +
    +
    + +

    Inclusive raw selector range, without expanding individual values. + More...

    + +

    #include <multiplexing.h>

    + + + + + + +

    +Public Attributes

    std::uint64_t minimum = 0U
     
    std::uint64_t maximum = 0U
     
    +

    Detailed Description

    +

    Inclusive raw selector range, without expanding individual values.

    + +

    Definition at line 18 of file multiplexing.h.

    +

    Member Data Documentation

    + +

    ◆ minimum

    + +
    +
    + + + + +
    std::uint64_t MultiplexRange::minimum = 0U
    +
    + +

    Definition at line 19 of file multiplexing.h.

    + +
    +
    + +

    ◆ maximum

    + +
    +
    + + + + +
    std::uint64_t MultiplexRange::maximum = 0U
    +
    + +

    Definition at line 20 of file multiplexing.h.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/docs/html/structMultiplexing-members.html b/docs/html/structMultiplexing-members.html index 20de77f..5776e2a 100644 --- a/docs/html/structMultiplexing-members.html +++ b/docs/html/structMultiplexing-members.html @@ -96,7 +96,9 @@ $(document).ready(function(){initNavTree('structMultiplexing.html',''); initResi

    This is the complete list of members for Multiplexing, including all inherited members.

    - + + +
    roleMultiplexing
    rangesMultiplexing
    role (defined in Multiplexing)Multiplexing
    selectorMultiplexing
    valueMultiplexing
    diff --git a/docs/html/structMultiplexing.html b/docs/html/structMultiplexing.html index 8298b5c..8a0c340 100644 --- a/docs/html/structMultiplexing.html +++ b/docs/html/structMultiplexing.html @@ -97,6 +97,9 @@ $(document).ready(function(){initNavTree('structMultiplexing.html',''); initResi
    +

    Basic markers and optional explicit extended multiplexing condition. + More...

    +

    #include <multiplexing.h>

    + + + +

    @@ -105,11 +108,15 @@ Public Attributes

     
    std::uint64_t value = 0U
     
    std::string selector
     
    std::vector< MultiplexRange > ranges
     

    Detailed Description

    -

    Basic multiplexing: one unsigned selector per frame, one raw value per branch.

    +

    Basic markers and optional explicit extended multiplexing condition.

    -

    Definition at line 15 of file multiplexing.h.

    +

    Definition at line 24 of file multiplexing.h.

    Member Data Documentation

    ◆ role

    @@ -122,9 +129,8 @@ Public Attributes
    -

    Signal participation in multiplexing.

    -

    Definition at line 16 of file multiplexing.h.

    +

    Definition at line 25 of file multiplexing.h.

    @@ -139,9 +145,43 @@ Public Attributes
    -

    Required raw selector value; used only by branches.

    +

    mN fallback when no explicit ranges are supplied.

    -

    Definition at line 17 of file multiplexing.h.

    +

    Definition at line 26 of file multiplexing.h.

    + +
    + + +

    ◆ selector

    + +
    +
    + + + + +
    std::string Multiplexing::selector
    +
    +

    Parent selector name within the same frame.

    + +

    Definition at line 27 of file multiplexing.h.

    + +
    +
    + +

    ◆ ranges

    + +
    +
    + + + + +
    std::vector<MultiplexRange> Multiplexing::ranges
    +
    +

    Alternatives for the named selector; override mN.

    + +

    Definition at line 28 of file multiplexing.h.

    diff --git a/docs/html/structMultiplexing.js b/docs/html/structMultiplexing.js index 53dc9ce..69aca58 100644 --- a/docs/html/structMultiplexing.js +++ b/docs/html/structMultiplexing.js @@ -1,5 +1,6 @@ var structMultiplexing = [ - [ "role", "structMultiplexing.html#a62b70a0e3f2a9c7a457b3694ce8625c3", null ], - [ "value", "structMultiplexing.html#a79158d4fdbfd68a3d51a8ce79d34fd67", null ] + [ "value", "structMultiplexing.html#a79158d4fdbfd68a3d51a8ce79d34fd67", null ], + [ "selector", "structMultiplexing.html#aa91e54403c78a663686b2fd22282afaf", null ], + [ "ranges", "structMultiplexing.html#aa174ac4a3af9b361d2de7517dfd4b69e", null ] ]; \ No newline at end of file diff --git a/docs/html/structPendingComment.html b/docs/html/structPendingComment.html index 4f3eab2..4a493e7 100644 --- a/docs/html/structPendingComment.html +++ b/docs/html/structPendingComment.html @@ -137,7 +137,7 @@ Public Attributes

    Definition at line 23 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    @@ -156,7 +156,7 @@ Public Attributes

    Definition at line 24 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    @@ -175,7 +175,7 @@ Public Attributes

    Definition at line 25 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    @@ -194,7 +194,7 @@ Public Attributes

    Definition at line 26 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    @@ -213,7 +213,7 @@ Public Attributes

    Definition at line 27 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    @@ -232,7 +232,7 @@ Public Attributes

    Definition at line 28 of file dbc_statement_handler.h.

    -

    Referenced by DbcCommentHandler::Handle().

    +

    Referenced by DbcCommentHandler::Handle().

    diff --git a/docs/html/structPendingMultiplexing-members.html b/docs/html/structPendingMultiplexing-members.html new file mode 100644 index 0000000..d0a9a32 --- /dev/null +++ b/docs/html/structPendingMultiplexing-members.html @@ -0,0 +1,114 @@ + + + + + + + +DBC Framework: Member List + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    PendingMultiplexing Member List
    +
    +
    + +

    This is the complete list of members for PendingMultiplexing, including all inherited members.

    + + + + + + + +
    canId (defined in PendingMultiplexing)PendingMultiplexing
    isExtended (defined in PendingMultiplexing)PendingMultiplexing
    lineNumber (defined in PendingMultiplexing)PendingMultiplexing
    ranges (defined in PendingMultiplexing)PendingMultiplexing
    selectorName (defined in PendingMultiplexing)PendingMultiplexing
    signalName (defined in PendingMultiplexing)PendingMultiplexing
    +
    + + + + diff --git a/docs/html/structPendingMultiplexing.html b/docs/html/structPendingMultiplexing.html new file mode 100644 index 0000000..ae0fe28 --- /dev/null +++ b/docs/html/structPendingMultiplexing.html @@ -0,0 +1,234 @@ + + + + + + + +DBC Framework: PendingMultiplexing Struct Reference + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    PendingMultiplexing Struct Reference
    +
    +
    + +

    Deferred extended multiplexing condition and source location. + More...

    + +

    #include <dbc_statement_handler.h>

    + + + + + + + + + + + + + + +

    +Public Attributes

    std::uint32_t canId
     
    bool isExtended
     
    std::string signalName
     
    std::string selectorName
     
    std::vector< MultiplexRange > ranges
     
    std::size_t lineNumber
     
    +

    Detailed Description

    +

    Deferred extended multiplexing condition and source location.

    + +

    Definition at line 50 of file dbc_statement_handler.h.

    +

    Member Data Documentation

    + +

    ◆ canId

    + +
    +
    + + + + +
    std::uint32_t PendingMultiplexing::canId
    +
    + +

    Definition at line 51 of file dbc_statement_handler.h.

    + +
    +
    + +

    ◆ isExtended

    + +
    +
    + + + + +
    bool PendingMultiplexing::isExtended
    +
    + +

    Definition at line 52 of file dbc_statement_handler.h.

    + +
    +
    + +

    ◆ signalName

    + +
    +
    + + + + +
    std::string PendingMultiplexing::signalName
    +
    + +

    Definition at line 53 of file dbc_statement_handler.h.

    + +
    +
    + +

    ◆ selectorName

    + +
    +
    + + + + +
    std::string PendingMultiplexing::selectorName
    +
    + +

    Definition at line 54 of file dbc_statement_handler.h.

    + +
    +
    + +

    ◆ ranges

    + +
    +
    + + + + +
    std::vector<MultiplexRange> PendingMultiplexing::ranges
    +
    + +

    Definition at line 55 of file dbc_statement_handler.h.

    + +
    +
    + +

    ◆ lineNumber

    + +
    +
    + + + + +
    std::size_t PendingMultiplexing::lineNumber
    +
    + +

    Definition at line 56 of file dbc_statement_handler.h.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/docs/html/structPendingValueDescriptions.html b/docs/html/structPendingValueDescriptions.html index 9d96929..9cce7b7 100644 --- a/docs/html/structPendingValueDescriptions.html +++ b/docs/html/structPendingValueDescriptions.html @@ -135,7 +135,7 @@ Public Attributes

    Definition at line 14 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcValueDescriptionHandler::Handle().

    @@ -154,7 +154,7 @@ Public Attributes

    Definition at line 15 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcValueDescriptionHandler::Handle().

    @@ -173,7 +173,7 @@ Public Attributes

    Definition at line 16 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcValueDescriptionHandler::Handle().

    @@ -192,7 +192,7 @@ Public Attributes

    Definition at line 17 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcValueDescriptionHandler::Handle().

    @@ -211,7 +211,7 @@ Public Attributes

    Definition at line 18 of file dbc_statement_handler.h.

    -

    Referenced by DbcValueDescriptionHandler::Handle().

    +

    Referenced by DbcValueDescriptionHandler::Handle().

    diff --git a/docs/html/structPgnLookupResult.html b/docs/html/structPgnLookupResult.html index bc592a7..a04cdd5 100644 --- a/docs/html/structPgnLookupResult.html +++ b/docs/html/structPgnLookupResult.html @@ -109,7 +109,7 @@ Public Attributes

    Detailed Description

    A PGN lookup rejects multiple definitions rather than choosing by order.

    -

    Definition at line 92 of file decode_database.h.

    +

    Definition at line 93 of file decode_database.h.

    Member Data Documentation

    ◆ definition

    @@ -124,9 +124,9 @@ Public Attributes

    Owning matched definition; empty if missing or ambiguous.

    -

    Definition at line 93 of file decode_database.h.

    +

    Definition at line 94 of file decode_database.h.

    -

    Referenced by DbcDecoder::FindFrame(), and DecodeDatabase::FindFrameByPgn().

    +

    Referenced by DbcDecoder::FindFrame(), and DecodeDatabase::FindFrameByPgn().

    @@ -143,9 +143,9 @@ Public Attributes

    True when multiple definitions share the requested PGN.

    -

    Definition at line 94 of file decode_database.h.

    +

    Definition at line 95 of file decode_database.h.

    -

    Referenced by DecodeDatabase::FindFrameByPgn().

    +

    Referenced by DecodeDatabase::FindFrameByPgn().

    diff --git a/docs/html/structRawCanFrame.html b/docs/html/structRawCanFrame.html index e054567..0d5ab37 100644 --- a/docs/html/structRawCanFrame.html +++ b/docs/html/structRawCanFrame.html @@ -114,7 +114,7 @@ Public Attributes

    Detailed Description

    Raw CAN frame used for runtime or trace decoding.

    -

    Definition at line 24 of file dbc_decoder.h.

    +

    Definition at line 25 of file dbc_decoder.h.

    Member Data Documentation

    ◆ canId

    @@ -129,7 +129,7 @@ Public Attributes

    Normalized CAN ID.

    -

    Definition at line 25 of file dbc_decoder.h.

    +

    Definition at line 26 of file dbc_decoder.h.

    Referenced by main().

    @@ -148,7 +148,7 @@ Public Attributes

    true for extended frame.

    -

    Definition at line 26 of file dbc_decoder.h.

    +

    Definition at line 27 of file dbc_decoder.h.

    Referenced by main().

    @@ -167,7 +167,7 @@ Public Attributes

    Payload bytes.

    -

    Definition at line 27 of file dbc_decoder.h.

    +

    Definition at line 28 of file dbc_decoder.h.

    Referenced by main().

    diff --git a/docs/html/structSignalInfo.html b/docs/html/structSignalInfo.html index f7cacbb..54d3a20 100644 --- a/docs/html/structSignalInfo.html +++ b/docs/html/structSignalInfo.html @@ -151,10 +151,12 @@ Public Attributes
    -

    Selector role and branch value.

    +

    Selector role, parent, and raw branch ranges.

    Definition at line 26 of file signal_info.h.

    +

    Referenced by DbcParseContext::ValidateMultiplexing().

    +
    @@ -172,7 +174,7 @@ Public Attributes

    Definition at line 27 of file signal_info.h.

    -

    Referenced by DbcSignalHandler::Handle().

    +

    Referenced by DbcSignalHandler::Handle().

    @@ -191,7 +193,7 @@ Public Attributes

    Definition at line 28 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    @@ -210,7 +212,7 @@ Public Attributes

    Definition at line 29 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    @@ -229,7 +231,7 @@ Public Attributes

    Definition at line 30 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    +

    Referenced by DbcTreeModel::data(), and DbcSignalHandler::Handle().

    @@ -248,7 +250,7 @@ Public Attributes

    Definition at line 31 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data().

    +

    Referenced by DbcTreeModel::data(), and DbcParseContext::ValidateMultiplexing().

    @@ -371,7 +373,7 @@ Public Attributes

    Definition at line 38 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveValueDescriptions().

    +

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveValueDescriptions().

    @@ -390,7 +392,7 @@ Public Attributes

    Definition at line 39 of file signal_info.h.

    -

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveComments().

    +

    Referenced by DbcTreeModel::data(), and DbcParseContext::ResolveComments().

    diff --git a/docs/html/structSignalKey.html b/docs/html/structSignalKey.html index 50864c1..c4eed23 100644 --- a/docs/html/structSignalKey.html +++ b/docs/html/structSignalKey.html @@ -210,7 +210,7 @@ Public Attributes

    Definition at line 46 of file definition_key.h.

    -

    Referenced by DecodeDatabase::FindSignal(), SignalKeyHasher::operator()(), and operator==().

    +

    Referenced by DecodeDatabase::FindSignal(), SignalKeyHasher::operator()(), and operator==().

    @@ -229,7 +229,7 @@ Public Attributes

    Definition at line 47 of file definition_key.h.

    -

    Referenced by DecodeDatabase::FindSignal(), SignalKeyHasher::operator()(), and operator==().

    +

    Referenced by DecodeDatabase::FindSignal(), SignalKeyHasher::operator()(), and operator==().