Skip to content

feat: add data_load_blf — Vector BLF CAN-log loader (+ shared can_decoder)#181

Open
facontidavide wants to merge 5 commits into
feat/mf4-pluginfrom
feat/blf-plugin
Open

feat: add data_load_blf — Vector BLF CAN-log loader (+ shared can_decoder)#181
facontidavide wants to merge 5 commits into
feat/mf4-pluginfrom
feat/blf-plugin

Conversation

@facontidavide

Copy link
Copy Markdown
Contributor

What

Adds data_load_blf — a Vector BLF (Binary Logging Format) CAN-log
DataSource — and extracts the CAN/DBC decoder into a shared common/ lib so the
MF4 and BLF loaders share one copy.

Stacked on #180 (feat/mf4-plugin). Base branch is feat/mf4-plugin
because the shared decoder is extracted from that (unmerged) work — please
merge #180 first, then rebase this onto main.

Motivated by comparing against the reference tool CANScope: BLF was the
biggest automotive CAN log we lacked, and a BLF importer is ~80% reuse of the
DBC decoder built for MF4.

Approach

  1. refactor(can) — move can_decoder out of data_load_mf4 into
    common/can_dbc (target pj_can_dbc), with the dbc_parser_cpp+fast_float
    CPM blocks; dbc stays PRIVATE behind the pImpl. Root CMake adds it (both
    modes), gated to its consumers. Behaviour-neutral: MF4 stays green.
  2. data_load_blfblf_frames (lblf → CanFrame adapter), blf_source
    (orchestrator, per-channel DBC mapping), blf_dialog (a DBC file-picker
    per channel).

Library: PetStr/lblf (MIT, C++20,
zlib-only) vendored via CPM. Technica/vector_blf was rejected (GPL-3.0).

Features

  • Classic CAN (CAN_MESSAGE/CAN_MESSAGE2), including zlib-compressed containers
  • Per-channel DBC mapping (BLF is multi-bus): one CanDecoder per channel;
    decoded signals → one topic per (channel, message) (CAN/ch{N}/{message})
  • Standard/extended (29-bit J1939) disambiguation; unmatched frames + channels
    without a DBC counted and reported
  • Interactive dialog: a DBC file picker per channel (1-4, via onFileSelected) +
    a preview of which channels the file contains
  • Absolute timestamps: measurement-start SYSTEMTIME (→ epoch ns) + per-object
    relative time (10 µs / 1 ns unit bit)

Verification

  • Tests: blf_frames (fixture frames), an end-to-end BLF→DBC decode
    (Speed=100 km/h), and the relocated pj_can_dbc_test — all green
  • -Werror clean on gcc 15; ASAN-clean (leak detection) on the fixture;
    self-contained .so (system libs only in DT_NEEDED; both data_source +
    dialog vtables)
  • Hermetic fixture: a committed 250-byte python-can BLF (test_data/, +
    gen_blf.py) — no third-party binary

Planning

Designed via a written plan plus an independent Codex plan run in parallel;
the two converged (same library choice, common/ extraction, CAN-FD-out scope,
python-can fixtures), which is why this shipped quickly and cleanly.

Scope / limitations (documented in the README)

  • CAN FD out of v1 — lblf has no CAN-FD parse struct and the DBC decoder
    rejects >8-byte payloads; CAN-FD/LIN objects are counted as skipped
  • Multiplexed CAN signals not decoded (dbc_parser_cpp limitation)
  • Dialog exposes channels 1-4; more via the saved channel_dbcs config

Before merge

🤖 Generated with Claude Code

facontidavide and others added 5 commits July 1, 2026 22:07
…_dbc)

Move the DBC CAN decoder out of data_load_mf4 into a shared common/ static lib
(target pj_can_dbc) so the upcoming data_load_blf plugin can reuse it. The
dbc_parser_cpp + fast_float CPM blocks move with it; dbc stays PRIVATE-linked
behind the can_decoder pImpl. Root CMakeLists adds common/can_dbc (both modes),
gated to its consumers (data_load_mf4, data_load_blf) since it has a CPM
download side-effect, like arrow_helpers. data_load_mf4 now links pj_can_dbc.

Behavior-neutral: mf4 builds -Werror clean, self-contained (.so still bundles
dbc, no new DT_NEEDED); tests split into pj_can_dbc_test (7) + mf4_source_test
(13, real fixtures included) = same 20 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…_dbc

New data_load_blf plugin (Vector BLF CAN logs). lblf (PetStr/lblf, MIT) via
CPM DOWNLOAD_ONLY, pinned by commit+SHA256; static blf lib from its two library
sources (blf_reader.cc + print.cc — the rest carry main()). Plugin stub links
pj_can_dbc (shared DBC decoder) + blf. Committed a 250-byte python-can BLF
fixture (+ gen_blf.py) and a scaffold test that reads it via lblf. Wired into
both root CMake blocks. Builds -Werror clean, self-contained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
blf_core static lib: readCanFrames() iterates lblf objects, emits classic-CAN
frames (CAN_MESSAGE/CAN_MESSAGE2) as CanFrame{ts_ns, channel, can_id, extended,
data}; CAN FD/LIN/other objects counted in BlfStats.skipped. id bit31 = extended
(masked to 11/29-bit); absolute ts = measurement-start (SYSTEMTIME->epoch ns via
std::chrono) + object timestamp. lblf stays in the .cpp (blf_frames.hpp
lblf-free). Test asserts the 3 fixture frames; Phase-2 scaffold test removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
blf_source importData(): per-channel DBC mapping (config channel_dbcs) -> one
CanDecoder per CAN channel; each frame decoded with its channel decoder;
decoded signals emitted as one topic per (channel, message)
"CAN/ch{N}/{name-or-hexid}". Counts unmatched frames, channels without a DBC,
and non-CAN objects; progress via file_size; cancellation via a bool frame
callback. New end-to-end test decodes a fixture frame through CanDecoder
(Speed=100 km/h). Plugin builds -Werror clean, self-contained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BlfDialog (PJ::DialogPluginTyped): a DBC file-picker per CAN channel (1-4) via
the onFileSelected/file_picker dialog API, plus a preview of which channels the
file contains (a capped metadata scan). Picked databases round-trip through
saveConfig as channel_dbcs. Wired into blf_source (kCapabilityHasDialog +
getDialog + setFilePath; PJ_DIALOG_PLUGIN) -> .so exports both data_source and
dialog vtables. Plugin README added. ASAN-clean on the fixture; -Werror clean;
self-contained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@facontidavide facontidavide self-assigned this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant