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