Closes #27
This commit is contained in:
1 parent
f17ddb6aad
commit
65142fdfe3
2 files changed
+200
-113
No files matched your search
@@ -20,7 +20,13 @@ The implementation follows a simple and practical design:
|
|||||||
- Qt is not required at the parser or decoder level
|
- Qt is not required at the parser or decoder level
|
||||||
- the same decode engine can be reused for live traffic and trace replay
|
- the same decode engine can be reused for live traffic and trace replay
|
||||||
|
|
||||||
This is **not a full production-grade DBC implementation yet**, but it is a strong architectural base.
|
The core library uses C++17 and has no Qt dependency. Qt Core and Qt Test are
|
||||||
|
required only for the regression tests. Live CAN acquisition, trace-file readers,
|
||||||
|
and a Qt model adapter are left to the consuming application.
|
||||||
|
|
||||||
|
See [changelog.md](changelog.md) for the release and development history,
|
||||||
|
[tests/README.md](tests/README.md) for test instructions, and
|
||||||
|
[generated API documentation](docs/html/index.html) for the API reference.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -105,65 +111,24 @@ This avoids forcing UI-oriented structures into a decode role they were not mean
|
|||||||
|
|
||||||
## Module Layout
|
## Module Layout
|
||||||
|
|
||||||
### Parsed DBC structures
|
```text
|
||||||
|
core/ C++17 parser, statement handlers, metadata, tree, and decoder
|
||||||
|
examples/ Command-line demo (built separately)
|
||||||
|
tests/ QtTest parser and decoder regression suites
|
||||||
|
docs/ Generated Doxygen documentation
|
||||||
|
dbc.pro Root qmake project: core + tests
|
||||||
|
Doxyfile API documentation configuration
|
||||||
|
```
|
||||||
|
|
||||||
Files:
|
| Component | Source files |
|
||||||
|
| --- | --- |
|
||||||
- `signal_info.h`
|
| Parsed metadata | `core/dbc_database.h`, `core/frame_info.h`, `core/signal_info.h` |
|
||||||
- `frame_info.h`
|
| Parser and dispatch | `core/dbc_parser.*`, `core/dbc_statement_handler.*`, `core/typefactory.h` |
|
||||||
- `dbc_database.h`
|
| UI tree | `core/tree_node.*`, `core/dbc_tree_builder.*` |
|
||||||
|
| Runtime database | `core/decode_database.h`, `core/dbc_decode_builder.*` |
|
||||||
These store a readable representation of the parsed DBC file.
|
| Decoder | `core/dbc_decoder.*` |
|
||||||
|
| Demo | `examples/main.cpp`, `examples/demo.pro` |
|
||||||
### UI tree structures
|
| Build integration | `core/core.pro`, `core/core_files.pri`, `core/core.pri` |
|
||||||
|
|
||||||
Files:
|
|
||||||
|
|
||||||
- `tree_node.h`
|
|
||||||
- `tree_node.cpp`
|
|
||||||
- `dbc_tree_builder.h`
|
|
||||||
- `dbc_tree_builder.cpp`
|
|
||||||
|
|
||||||
These convert parsed DBC content into a tree hierarchy suitable for UI and model/view usage later.
|
|
||||||
|
|
||||||
### Runtime decode structures
|
|
||||||
|
|
||||||
Files:
|
|
||||||
|
|
||||||
- `decode_database.h`
|
|
||||||
- `dbc_decode_builder.h`
|
|
||||||
- `dbc_decode_builder.cpp`
|
|
||||||
|
|
||||||
These convert parsed DBC content into a structure optimized for decoding.
|
|
||||||
|
|
||||||
### Runtime decoder
|
|
||||||
|
|
||||||
Files:
|
|
||||||
|
|
||||||
- `dbc_decoder.h`
|
|
||||||
- `dbc_decoder.cpp`
|
|
||||||
|
|
||||||
These perform actual decoding of raw CAN frames using `DecodeDatabase`.
|
|
||||||
|
|
||||||
### Parser
|
|
||||||
|
|
||||||
Files:
|
|
||||||
|
|
||||||
- `dbc_parser.h`
|
|
||||||
- `dbc_parser.cpp`
|
|
||||||
- `dbc_statement_handler.h`
|
|
||||||
- `dbc_statement_handler.cpp`
|
|
||||||
- `typefactory.h`
|
|
||||||
|
|
||||||
The parser reads files and reports errors; registered statement handlers parse DBC constructs.
|
|
||||||
|
|
||||||
### Demo
|
|
||||||
|
|
||||||
File:
|
|
||||||
|
|
||||||
- `main.cpp`
|
|
||||||
|
|
||||||
Used as a small integration example.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -264,7 +229,8 @@ dbc
|
|||||||
└── Odometer
|
└── Odometer
|
||||||
```
|
```
|
||||||
|
|
||||||
Each node stores either:
|
Frame and signal nodes store copies of the corresponding metadata; the root
|
||||||
|
has no metadata payload. The payload types are:
|
||||||
|
|
||||||
- `FrameInfo`
|
- `FrameInfo`
|
||||||
- `SignalInfo`
|
- `SignalInfo`
|
||||||
@@ -459,7 +425,14 @@ Fields:
|
|||||||
- `signals`
|
- `signals`
|
||||||
- `valid`
|
- `valid`
|
||||||
|
|
||||||
This is the decoder output for one raw frame.
|
`valid` means a matching frame definition was found. Check each signal's
|
||||||
|
`valid` separately: insufficient payload data can leave individual signals
|
||||||
|
invalid even when the frame is valid. An unknown frame returns `valid == false`.
|
||||||
|
|
||||||
|
The frame and signal `definition` pointers refer into `DecodeDatabase`. Keep
|
||||||
|
that database alive and avoid changes that invalidate its frame or signal
|
||||||
|
storage while using decoded results. The decoder applies factor and offset;
|
||||||
|
it does not clamp physical values to the declared minimum and maximum.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -536,7 +509,7 @@ one-based physical line number, including blank lines:
|
|||||||
example.dbc:3: Invalid CAN ID: invalid
|
example.dbc:3: Invalid CAN ID: invalid
|
||||||
```
|
```
|
||||||
|
|
||||||
This change validates frame definitions. Signal definitions are also validated as described below; comprehensive
|
Frame and signal definitions are validated as described here; comprehensive
|
||||||
DBC grammar coverage is still planned. File-open errors contain the path but have no line number.
|
DBC grammar coverage is still planned. File-open errors contain the path but have no line number.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -683,34 +656,44 @@ This is one of the main reasons why the runtime decode layer should be explicit
|
|||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
## Parse DBC
|
Include the public headers from the `core/` include directory supplied by
|
||||||
|
`core/core.pri`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "dbc_parser.h"
|
||||||
|
#include "dbc_tree_builder.h"
|
||||||
|
#include "dbc_decode_builder.h"
|
||||||
|
#include "dbc_decoder.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parse DBC
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
DbcParser parser;
|
DbcParser parser;
|
||||||
DbcDatabase database = parser.ParseFile("example.dbc");
|
DbcDatabase database = parser.ParseFile("example.dbc");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build UI tree
|
### Build UI tree
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
DbcTreeBuilder treeBuilder;
|
DbcTreeBuilder treeBuilder;
|
||||||
std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
|
std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build runtime decode database
|
### Build runtime decode database
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
DbcDecodeBuilder decodeBuilder;
|
DbcDecodeBuilder decodeBuilder;
|
||||||
DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
|
DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Decode a raw frame
|
### Decode a raw frame
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
RawCanFrame rawFrame;
|
RawCanFrame rawFrame;
|
||||||
rawFrame.canId = 0x123;
|
rawFrame.canId = 256; // EngineData from the DBC example above
|
||||||
rawFrame.isExtended = false;
|
rawFrame.isExtended = false;
|
||||||
rawFrame.data = {0x01, 0x02, 0x03, 0x04};
|
rawFrame.data = {0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
DbcDecoder decoder;
|
DbcDecoder decoder;
|
||||||
DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
|
DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
|
||||||
@@ -817,8 +800,8 @@ lines:
|
|||||||
- `SG_` → `DbcSignalHandler`
|
- `SG_` → `DbcSignalHandler`
|
||||||
- `CM_` → `DbcCommentHandler`
|
- `CM_` → `DbcCommentHandler`
|
||||||
|
|
||||||
Grammar implementations live in `dbc_statement_handler.cpp`; their interface,
|
Grammar implementations live in `core/dbc_statement_handler.cpp`; their interface,
|
||||||
context, and dispatcher live in `dbc_statement_handler.h`. `typefactory.h`
|
context, and dispatcher live in `core/dbc_statement_handler.h`. `core/typefactory.h`
|
||||||
provides the generic registry and object creation.
|
provides the generic registry and object creation.
|
||||||
|
|
||||||
To add a construct, implement a default-constructible handler deriving from
|
To add a construct, implement a default-constructible handler deriving from
|
||||||
@@ -861,7 +844,18 @@ Not supported yet:
|
|||||||
- full J1939 validation
|
- full J1939 validation
|
||||||
- extensive edge-case handling for unusual DBC formatting
|
- extensive edge-case handling for unusual DBC formatting
|
||||||
|
|
||||||
Motorola extraction is implemented, but it should still be verified carefully against real-world DBC files and expected values.
|
Additional behavior to account for:
|
||||||
|
|
||||||
|
- unregistered DBC keywords are ignored
|
||||||
|
- an `SG_` statement before the first frame is ignored
|
||||||
|
- duplicate frame and signal definitions are not rejected
|
||||||
|
- payload lengths are checked against storage bounds (`0..255`), rather than
|
||||||
|
CAN or CAN FD protocol limits
|
||||||
|
- comment handling is limited to the supported forms and already parsed targets
|
||||||
|
|
||||||
|
Motorola extraction uses DBC sawtooth numbering: a start bit of 7 traverses
|
||||||
|
`7..0, 15..8, 23..16`. Regression tests cover aligned and unaligned signals,
|
||||||
|
byte boundaries, and 64-bit values.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -916,13 +910,10 @@ Advanced functionality:
|
|||||||
|
|
||||||
## Build Integration
|
## Build Integration
|
||||||
|
|
||||||
The module does not depend on any specific build system.
|
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
|
||||||
It can be integrated with:
|
systems can compile the sources listed in `core/core_files.pri`; no CMake
|
||||||
|
configuration is currently provided.
|
||||||
- CMake
|
|
||||||
- qmake
|
|
||||||
- Makefile
|
|
||||||
|
|
||||||
Open `dbc.pro` in Qt Creator to see two subprojects: `core` and `tests`.
|
Open `dbc.pro` in Qt Creator to see two subprojects: `core` and `tests`.
|
||||||
`core/core.pro` builds the C++17 static library `dbc_core` without a Qt dependency.
|
`core/core.pro` builds the C++17 static library `dbc_core` without a Qt dependency.
|
||||||
@@ -945,47 +936,51 @@ source lists live in `tests/parser_tests.pri` and `tests/decoder_tests.pri`.
|
|||||||
When building a consumer separately, pass
|
When building a consumer separately, pass
|
||||||
`DBC_CORE_BUILD_DIR=/absolute/path/to/build/core` to qmake.
|
`DBC_CORE_BUILD_DIR=/absolute/path/to/build/core` to qmake.
|
||||||
|
|
||||||
The former demonstration program is preserved in `examples/main.cpp` with
|
### Build core without Qt libraries
|
||||||
`examples/demo.pro`. Build it separately after building core, using that same
|
|
||||||
`DBC_CORE_BUILD_DIR` option; run `dbc_demo <file.dbc>`.
|
|
||||||
|
|
||||||
---
|
From the repository root:
|
||||||
|
|
||||||
## Summary
|
```sh
|
||||||
|
mkdir -p build/core
|
||||||
This module is now split into two intentionally separate layers:
|
cd build/core
|
||||||
|
qmake6 ../../core/core.pro
|
||||||
### Parsed representation
|
make -j
|
||||||
|
|
||||||
Used for:
|
|
||||||
|
|
||||||
- storing parsed DBC content
|
|
||||||
- browsing
|
|
||||||
- UI tree generation
|
|
||||||
|
|
||||||
### Runtime decode representation
|
|
||||||
|
|
||||||
Used for:
|
|
||||||
|
|
||||||
- fast frame lookup
|
|
||||||
- live CAN decode
|
|
||||||
- trace decode
|
|
||||||
- physical value conversion
|
|
||||||
|
|
||||||
That separation is the main architectural improvement.
|
|
||||||
|
|
||||||
In short, the system now looks like this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
DBC parser → DbcDatabase → DecodeDatabase → DbcDecoder
|
|
||||||
↘ TreeNode → future UI
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This gives FrameTap a much better foundation for real use, because both browsing and decoding are supported without forcing one representation to do the other's job.
|
qmake is still the build tool; this target does not link Qt libraries.
|
||||||
|
|
||||||
|
### Build and run the demo
|
||||||
|
|
||||||
|
After building core, run these commands from the repository root:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p build/examples
|
||||||
|
cd build/examples
|
||||||
|
qmake6 ../../examples/demo.pro DBC_CORE_BUILD_DIR=../core
|
||||||
|
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:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
doxygen Doxyfile
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `docs/html/index.html` to view the generated reference.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Regression tests
|
## Regression tests
|
||||||
|
|
||||||
See [tests/README.md](tests/README.md) for QtTest build and execution commands.
|
See [tests/README.md](tests/README.md) for QtTest build and execution commands.
|
||||||
Tests cover frame validation and error locations, Intel and Motorola extraction,
|
Tests cover frame validation and error locations, Intel and Motorola extraction,
|
||||||
signed and unsigned 64-bit boundaries,
|
signal syntax and payload bounds, statement dispatch, signed and unsigned
|
||||||
physical conversion, numeric output, and invalid signal payloads.
|
64-bit boundaries, physical conversion, numeric output, and invalid signal
|
||||||
|
payloads.
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
This changelog summarizes the Git history through `f17ddb6`. Entries are listed
|
||||||
|
newest first. Dates follow the commit author dates. `v1.0` is the existing Git
|
||||||
|
tag; subsequent changes have no release tag and are listed as unreleased.
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### 2026-10-05
|
||||||
|
|
||||||
|
#### Changed
|
||||||
|
|
||||||
|
- Split the qmake project into a reusable static library in `core/`, a demo in
|
||||||
|
`examples/`, and a combined regression test executable in `tests/`. Added
|
||||||
|
shared `.pri` files and updated build instructions. (`f17ddb6`, #11)
|
||||||
|
- Added `.clang-format` and applied consistent formatting to the source code
|
||||||
|
and tests. (`b91cf4a`, #7)
|
||||||
|
- Replaced lambdas with explicit functions and simpler code in statement
|
||||||
|
handlers, the decoder, the demo, and regression tests. (`03dc8f2`)
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
- Added complete validation of `SG_` signal statements, including syntax,
|
||||||
|
receivers, numeric fields, lengths of 1–64 bits, physical ranges, and signal
|
||||||
|
bounds within the declared frame payload for Intel and Motorola bit order.
|
||||||
|
Invalid definitions report the file path and line number. Multiplexing
|
||||||
|
markers are explicitly rejected. Added regression tests and documentation.
|
||||||
|
(`8d82b13`, #6)
|
||||||
|
|
||||||
|
#### Documentation and maintenance
|
||||||
|
|
||||||
|
- Regenerated Doxygen documentation after code changes and the project
|
||||||
|
restructuring. (`6cd9976`, `0067cb4`, `f17ddb6`)
|
||||||
|
- Removed the temporary signal-validation issue document. (`1163277`)
|
||||||
|
|
||||||
|
### 2026-10-01
|
||||||
|
|
||||||
|
#### Changed
|
||||||
|
|
||||||
|
- Moved DBC statement parsing into `TypeFactory`-registered handlers for
|
||||||
|
`BO_`, `SG_`, and `CM_`, with a shared parse context and keyword dispatcher.
|
||||||
|
Added tests for dispatch and handler replacement, and documented how to
|
||||||
|
register additional handlers. (`88b5883`, #4)
|
||||||
|
- **API change:** `DecodedSignalValue::rawValue` now uses
|
||||||
|
`std::variant<std::int64_t, std::uint64_t>` instead of `int64_t`. Consumers
|
||||||
|
must handle the appropriate variant alternative. Physical values remain
|
||||||
|
`double` and may lose precision for large integers. (`69074e3`, #2)
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
- Corrected Motorola signal extraction within bytes and across byte
|
||||||
|
boundaries using DBC sawtooth bit numbering. Added decoder regression
|
||||||
|
tests and build instructions; introduced the `TypeFactory` utility.
|
||||||
|
(`2c057b6`)
|
||||||
|
- Preserved the full unsigned 64-bit raw-value range, including values above
|
||||||
|
`INT64_MAX`, and updated physical conversion and demo output. Added tests
|
||||||
|
for signed and unsigned boundaries and numeric output. (`69074e3`, #2)
|
||||||
|
- Validated `BO_` frame syntax, CAN identifiers, payload lengths, numeric
|
||||||
|
overflow, and unexpected trailing fields. Parsing errors now include the
|
||||||
|
file path and physical line number. Added parser regression tests.
|
||||||
|
(`3bd9339`, #3)
|
||||||
|
|
||||||
|
## v1.0 — 2026-06-14
|
||||||
|
|
||||||
|
Tag `v1.0` points to `38ce043` and includes the initial implementation below.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Added source-file headers with author information and MIT license
|
||||||
|
references. (`e2ffa97`)
|
||||||
|
- Added and subsequently simplified the Doxygen configuration.
|
||||||
|
(`e2c07dd`, `4c8af9f`)
|
||||||
|
- Generated API documentation and refreshed the generated documentation.
|
||||||
|
(`dfec39d`, `38ce043`)
|
||||||
|
|
||||||
|
### Initial implementation — 2026-03-13
|
||||||
|
|
||||||
|
#### Added
|
||||||
|
|
||||||
|
- Initialized the repository with a README and MIT license. (`4270459`)
|
||||||
|
- Added the DBC parser, frame and signal metadata, a tree representation and
|
||||||
|
builder, a demonstration program, and a qmake project. (`2a90b2d`)
|
||||||
|
- Added runtime decoding through `DbcDecodeBuilder`, `DecodeDatabase`, and
|
||||||
|
`DbcDecoder`, including CAN-frame lookup, Intel and Motorola extraction,
|
||||||
|
signed and unsigned signals, and factor/offset conversion. Updated parser
|
||||||
|
metadata and the demo to support decoding. (`a53a5df`)
|
||||||
|
|
||||||
|
#### Documentation and maintenance
|
||||||
|
|
||||||
|
- Added `.gitignore` and expanded the README with architecture, data
|
||||||
|
structures, parsing behavior, decoding examples, and usage documentation.
|
||||||
|
(`efc57d6`, `f2aa10c`, `cb20f5f`, `f0e7065`)
|
||||||
Reference in new issue
Block a user