From 65142fdfe33e439b1035c475d804a2b1d665ecaf Mon Sep 17 00:00:00 2001 From: deeaitch Date: Tue, 6 Oct 2026 16:54:02 -0400 Subject: [PATCH] Closes #27 --- README.md | 221 +++++++++++++++++++++++++-------------------------- changelog.md | 92 +++++++++++++++++++++ 2 files changed, 200 insertions(+), 113 deletions(-) create mode 100644 changelog.md diff --git a/README.md b/README.md index 3c59fb1..b00b758 100644 --- a/README.md +++ b/README.md @@ -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 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 `. +### 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. diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..1e60a7a --- /dev/null +++ b/changelog.md @@ -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` 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`)