This commit is contained in:
deeaitch committed 2026-10-06 16:54:02 -04:00
1 parent f17ddb6aad
commit 65142fdfe3
2 files changed
+200 -113

No files matched your search

+108 -113
View File
@@ -20,7 +20,13 @@ The implementation follows a simple and practical design:
- Qt is not required at the parser or decoder level
- 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
### 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:
- `signal_info.h`
- `frame_info.h`
- `dbc_database.h`
These store a readable representation of the parsed DBC file.
### UI tree structures
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.
| Component | Source files |
| --- | --- |
| Parsed metadata | `core/dbc_database.h`, `core/frame_info.h`, `core/signal_info.h` |
| Parser and dispatch | `core/dbc_parser.*`, `core/dbc_statement_handler.*`, `core/typefactory.h` |
| UI tree | `core/tree_node.*`, `core/dbc_tree_builder.*` |
| Runtime database | `core/decode_database.h`, `core/dbc_decode_builder.*` |
| Decoder | `core/dbc_decoder.*` |
| Demo | `examples/main.cpp`, `examples/demo.pro` |
| Build integration | `core/core.pro`, `core/core_files.pri`, `core/core.pri` |
---
@@ -264,7 +229,8 @@ dbc
└── 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`
- `SignalInfo`
@@ -459,7 +425,14 @@ Fields:
- `signals`
- `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
```
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.
---
@@ -683,34 +656,44 @@ This is one of the main reasons why the runtime decode layer should be explicit
## 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
DbcParser parser;
DbcDatabase database = parser.ParseFile("example.dbc");
```
## Build UI tree
### Build UI tree
```cpp
DbcTreeBuilder treeBuilder;
std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
```
## Build runtime decode database
### Build runtime decode database
```cpp
DbcDecodeBuilder decodeBuilder;
DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
```
## Decode a raw frame
### Decode a raw frame
```cpp
RawCanFrame rawFrame;
rawFrame.canId = 0x123;
rawFrame.canId = 256; // EngineData from the DBC example above
rawFrame.isExtended = false;
rawFrame.data = {0x01, 0x02, 0x03, 0x04};
rawFrame.data = {0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
DbcDecoder decoder;
DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
@@ -817,8 +800,8 @@ lines:
- `SG_` → `DbcSignalHandler`
- `CM_` → `DbcCommentHandler`
Grammar implementations live in `dbc_statement_handler.cpp`; their interface,
context, and dispatcher live in `dbc_statement_handler.h`. `typefactory.h`
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
@@ -861,7 +844,18 @@ Not supported yet:
- full J1939 validation
- 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
The module does not depend on any specific build system.
It can be integrated with:
- CMake
- qmake
- Makefile
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.
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.
@@ -945,47 +936,51 @@ 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.
The former demonstration program is preserved in `examples/main.cpp` with
`examples/demo.pro`. Build it separately after building core, using that same
`DBC_CORE_BUILD_DIR` option; run `dbc_demo <file.dbc>`.
### Build core without Qt libraries
---
From the repository root:
## Summary
This module is now split into two intentionally separate layers:
### Parsed representation
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
```sh
mkdir -p build/core
cd build/core
qmake6 ../../core/core.pro
make -j
```
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
See [tests/README.md](tests/README.md) for QtTest build and execution commands.
Tests cover frame validation and error locations, Intel and Motorola extraction,
signed and unsigned 64-bit boundaries,
physical conversion, numeric output, and invalid signal payloads.
signal syntax and payload bounds, statement dispatch, signed and unsigned
64-bit boundaries, physical conversion, numeric output, and invalid signal
payloads.