Reference
The details that do not belong anywhere else.
Log formats
| Format | Notes |
|---|---|
| SavvyCAN CSV | GVRET and SavvyCAN exports. Handles both the hex byte format real exports use and older decimal ones, and the trailing comma SavvyCAN writes after the last data byte. |
candump .log | candump -l output, including CAN FD lines. |
| pcap / pcapng | Linux SocketCAN, link type 227, via dpkt. |
| Vector BLF | Through python-can's reader. |
| Vector ASC | Through python-can's reader. |
MDF4 .mf4 / .mdf | CANedge and similar. Needs asammdf. |
openpilot rlog / qlog | Plain, .bz2 or .zst. Needs canlab[openpilot]; the schema ships with CanLab. Frames the panda sent itself are kept apart from the car's traffic. |
Every parser produces the same columns, so the rest of the application does
not care where a capture came from: Timestamp, ID, Bus, DLC,
Extended, B0..B7, plus a per-ID Delta.
Where things live
| Path | What |
|---|---|
~/.canlab/plugins/ | Plugins you have installed. |
~/.canlab/opendbc_cache/ | Cached opendbc index, so matching works offline after the first fetch. |
~/.canlab/memory.json | AI engine memory across sessions. |
canlab/sample_data/ | The bundled sample capture, its generator, and an example seed-key script. |
docs/AUDIT_FIXES.md | The full list of defects fixed in the deep-audit pass, each with a regression test. |
Settings
Nine panels: API KEYS, CAN ADAPTERS, VEHICLE, REST API, MCP, BACKEND, MULTI-BUS, PLUGINS and frame cap. The ones you will actually touch are CAN ADAPTERS (add, detect and test your hardware), API KEYS if you want the AI features, MCP to connect an assistant, and PLUGINS to approve anything you have installed. Everything persists across restarts.
Validated against real captures
Separately from the unit suite, the whole application is run end to end over real vehicle recordings, because synthetic data agrees with whatever the code assumes. Two corpora, ninety checks.
| Corpus | What it is | Checks |
|---|---|---|
| SavvyCAN examples | 12,974 frames, 180 IDs, 11-bit, one bus | 36 |
| CANedge recordings and python-can format files | 2 to 154,896 frames, native MDF4, 11-bit and 29-bit, dual-bus, CAN FD and error frames | 54 |
The second corpus is other people's hardware output, none of it produced here: five CANedge logger recordings in native MDF4 from CSS Electronics. They are different kinds of bus: a 145,534-frame J1939 log that is 29-bit end to end, a 22.8-minute two-channel car recording of 154,896 11-bit frames, and a 9,600-frame marine bus that is NMEA 2000. Plus Vector BLF and ASC written by python-can's own writers covering CAN FD, 64-byte FD, error frames and a comma-decimal locale. One real log is then written out in all five formats and read back by every parser, which all have to agree about the same traffic.
A third run pushes the size rather than the variety: the 145,534-frame J1939 truck log and the 154,896-frame two-channel car log are merged into one 300,430-frame capture with 11-bit and 29-bit identifiers on three bus tags, and every stage is timed against a budget. 29 checks, all passing: parsing at 200,912 frames/s, the merged capture into the running window in 8.1 s at 691 MB resident, the frame table refreshing in 65 ms, the sniffer folding the capture in 128 ms, and 145,534 frames written out and read back through five formats with every payload byte equal. Engine speed decodes to 913 to 1762 rpm over 19,584 frames, which is external evidence rather than the code agreeing with itself. That run also found a real defect: the PGN scan crashed on any log carrying an active fault code, and this truck sends 196 of them.
It found defects the older corpus could not reach. The openpilot DBC
exporter wrote a bare 29-bit frame id, so every J1939 capture exported a
file cantools refuses. The sniffer aged a loaded capture against wall-clock
time, so every row expired the moment a file opened. The PGN decoder read
the marine bus with J1939 tables and named nothing. All are fixed and
pinned by tests. A narrated recording of the run is in the
repository as docs/canlab-realdata-validation.mp4.
Testing
The suite runs headless:
QT_QPA_PLATFORM=offscreen python -m pytest -q # 753 passed
Tests that need an optional dependency skip cleanly when it is absent: the
MDF4 importer without asammdf, the transport tests without the
MCP SDK, the Lua dissector without a Lua runtime.
It covers the log parsers against fixtures in the real formats, DBC encode and decode round trips through cantools, the ARM TX gate on every transmit path including that disarming mid-run stops a worker, ISO-TP and UDS wire format, DTC and PID decoding, the REST authentication and NaN-safe JSON, and an import smoke test of every tab.
Limitations
- Not validated on many real vehicles. Signal identification is heuristic. Verify every result before trusting it.
- ARM TX covers the transmit features, not diagnostic reads. See the gate for exactly which paths it covers.
- ARXML export is experimental and is not validated against the AUTOSAR schema.
- openpilot logs need pycapnp
(
canlab[openpilot]); the schema ships with CanLab. - MDF4 needs
asammdf. - CAN FD is parsed, decoded, injected and replayed end to end, but has been tested on a virtual bus, not on FD hardware.
- No real ECU. UDS, ISO-TP, security access and OBD-II are tested against scripted responders and independent implementations, not against a vehicle's modules.
- The gateway needs two hardware channels.
- The prebuilt binary is Linux x86_64 and unsigned. No macOS or Windows build; run from source there.
Getting help
Bugs and questions belong in the issue tracker. A capture that reproduces the problem helps enormously; the sample format is plain CSV and easy to trim.
Credits
The calibration refinements in core/calibrate_refine.py,
sentinel masking and scale snapping, are adapted from CSS Electronics'
CAN
bus reverse engineering skills (MIT). The OEM checksum algorithms in
core/checksums.py follow
commaai/opendbc (MIT).
NMEA 2000 definitions are distilled from canboat (Apache 2.0). openpilot logs are read with comma.ai's cereal schema (MIT), and the real-car calibration checks use comma.ai's comma2k19 segment (MIT) and a drive from openpilot's public CI routes. The interoperability tests run against can-isotp, udsoncan and can-j1939 (all MIT).
Built on python-can, cantools, PyQt6, pandas, NumPy and pyqtgraph.