A portable, zero-install Windows tool for loading CAN/automotive measurement files, decoding signals with DBC or ARXML (AUTOSAR) databases, and plotting them interactively.
| Format | Extension | Database Required |
|---|---|---|
| Vector Binary Logging Format | .blf |
Yes |
| Vector CANalyzer ASCII Log | .asc |
Yes |
| ASAM MDF4 — bus logging (raw CAN frames) | .mf4 |
Yes — auto-detected |
| ASAM MDF4 / MDF3 — pre-decoded signals | .mf4 / .mdf |
No |
| CSV (narrow or wide columnar) | .csv |
No |
MDF auto-detection: CAN Scope automatically probes each MDF file on open. If it contains raw CAN bus frames (
CAN_DataFrame.*channel groups) it routes through the bus-logging pipeline and requires a database file (.dbcor.arxml). Pre-decoded MDF files load directly without a database.
Both .dbc and .arxml (AUTOSAR System Description) files are accepted wherever
a CAN database is required.
- Open an
.arxmlin the Database Manager exactly as you would a.dbc. - Mixed configurations are supported: some CAN channels can use a
.dbcand others an.arxml. - Supported ARXML variants: AUTOSAR 3.x and AUTOSAR 4.x.
- To convert an existing
.dbcto.arxmlfor testing:cantools convert input.dbc output.arxml
- Multi-format loading — BLF, ASC, MF4 (bus-logged and pre-decoded), MDF3, and CSV in one tool
- Multi-channel database mapping — assign a different
.dbcor.arxmlto each CAN channel via the Database Manager; channel 0 acts as an "All Channels" fallback - Database match quality indicators — the Database Manager shows per-channel decode coverage bars with J1939 PGN fallback scoring
- Streaming decode — signal tree and plots update in real time while large files are still decoding
- Persistent channel config — database-to-channel assignments saved as
.canscope_chJSON and reloaded automatically between sessions
- Normal — all signals share one Y axis
- Multi-Axis — independent Y axis per signal, all on the same X axis
- Stacked — INCA/CANdb-style lanes, one row per signal with independent Y scaling
- Dual cursors — draggable C1 and C2 with live value readout in the signal table
- ΔT display — time delta between C1 and C2 shown in the toolbar
- Fit to Window — rescales X and Y to the full extent of all visible data
- Fit Vertical — rescales Y only to match data in the current X view (X range unchanged)
- Both fit operations work correctly across all three plot modes including multi-axis floating ViewBoxes
- 5-column table — Visibility ☑ | Signal | Cursor 1 | Cursor 2 | Unit
- Signal grouping — assign signals to named groups; collapse/expand groups with the arrow; toggle group visibility via the checkbox in the same column
- Drag-and-drop reorder — drag signals or use Ctrl+Up / Ctrl+Down
- Visibility toggle — check/uncheck individual signals or an entire group; cursor position and all other signal values remain stable during toggle
- Signal name display options — optionally prefix signal names with channel number and/or message name
- Save / Load configuration — fully persists: file paths, channel-DBC mapping, plotted signal list, group assignments, per-signal visibility, signal colors, plot background color, plot mode, cursor state, table column widths, signal name display flags
- Undo — up to 3 levels of undo for plot actions (Ctrl+Z)
- On-disk indexed store — no frame cap; 18 B/frame RAM, 64 B/frame on disk with memory-mapped O(1) access
- Sliding window display — shows 5 000 frames at a time with scroll
- Filter by ID and channel — vectorised numpy mask, no disk access for filtering
- On-demand signal decode — click a frame row to see decoded signals using the per-channel DBC
- Single-folder
.exe— no Python installation required on the target machine - Splash screen — shows loading progress; minimisable, appears in taskbar, responds to Win+D / Show Desktop
- Auto-build CI — GitHub Actions builds and uploads a release ZIP on every
v*.*.*tag push
git clone https://github.com/dinacaran/canscope.git
cd canscope
pip install -r requirements.txt
python app.pyFor MDF bus-logging support (raw CAN frames inside MF4) also install:
pip install canmatrixGo to Releases and download
the latest CANScope_vXX.XX.XX_Windows.zip. Unzip anywhere and run CANScope.exe — no installer needed.
| Step | Action |
|---|---|
| 1 | Open File — select .blf, .asc, .mf4, .mdf, or .csv |
| 2 | Open Database — required for BLF, ASC, and MF4 bus-logged files (.dbc or .arxml) |
| 3 | Database Manager (optional) — assign a different database per CAN channel |
| 4 | Load + Decode — background decode; signal tree populates live |
| 5 | Double-click or drag a signal to plot it, or select and press Space |
| 6 | Drag Cursor 1 to read time and signal value in the table |
| 7 | Toggle Cursor 2 to measure ΔT between two points |
| 8 | Switch between Normal, Multi-Axis, and Stacked plot modes |
| 9 | Fit to Window or Fit Vertical to rescale the view |
| 10 | Save Config (Ctrl+S) — persists file paths, database mapping, plotted signals, and all view state |
| 11 | Export CSV to save selected signal data to a time-aligned file |
| 12 | CAN Trace to browse raw CAN frames (BLF / ASC / MF4 bus-log) |
| Key | Action |
|---|---|
F |
Fit to Window — rescale X and Y to all data |
V |
Fit Vertical — rescale Y only, keep current X |
Space |
Plot selected signal(s) from the signal tree |
Delete |
Remove selected signal from plot |
Ctrl+Z |
Undo last plot action (up to 3 levels) |
Ctrl+S |
Save configuration |
Ctrl+Up |
Move selected signal up |
Ctrl+Down |
Move selected signal down |
Ctrl+Shift+R |
Open Raw CAN Frame viewer |
pip install pyinstaller
pyinstaller CANScope.specOutput in dist/CANScope/. The GitHub Actions workflow (.github/workflows/build.yml)
builds and uploads the ZIP automatically on every tag push matching v*.*.*.
canscope/
├── app.py # Entry point, APP_NAME="CAN Scope", APP_VERSION
├── config/
│ └── diagnostics/
│ ├── motor_control.yaml # Fault rules for motor/inverter domain (user-editable)
│ └── README.md # Rule authoring guide
├── core/
│ ├── models.py # RawFrame, DecodedSignalSample dataclasses
│ ├── channel_config.py # ChannelConfig: {channel → DBC or ARXML}, decoder cache, save/load .canscope_ch
│ ├── load_worker.py # QThread: CAN-raw / bulk-array / sample-loop decode paths
│ ├── signal_store.py # SignalStore, SignalSeries (array.array storage)
│ ├── raw_frame_store.py # On-disk indexed store: 18 B/frame RAM + 64 B/frame disk, mmap
│ ├── dbc_decoder.py # DBCDecoder with 3-level cache — accepts .dbc and .arxml
│ ├── vectorized_decoder.py # Vectorised BLF/ASC decode + cached series refs
│ ├── blf_reader.py # BLFReaderService (wraps python-can)
│ ├── export.py # CSV export
│ ├── readers/
│ │ ├── __init__.py # reader_factory() + dbc_required_for() — format detection
│ │ ├── db_format.py # SUPPORTED_DB_SUFFIXES, is_database_file(), db_format_label()
│ │ ├── base.py # MeasurementReader protocol
│ │ ├── blf_can_reader.py # BLF + DBC/ARXML pipeline
│ │ ├── asc_can_reader.py # ASC + DBC/ARXML pipeline
│ │ ├── mdf_reader.py # MF4/MDF pre-decoded via asammdf + is_bus_logging() probe
│ │ ├── mdf_can_reader.py # MDF4 bus logging via python-can MF4Reader + DBC/ARXML
│ │ └── csv_reader.py # Wide and narrow CSV
│ └── diagnostics/ # AI-powered diagnostics engine (Ctrl+Shift+A)
│ ├── __init__.py
│ ├── config_loader.py # YAML domain parser — infers rule type, auto-generates id/title
│ ├── context.py # DiagnosticContext — read-only SignalStore adapter for rule processors
│ ├── engine.py # DiagnosticEngine — orchestrates rule runs and evidence building
│ ├── evidence.py # EvidenceBuilder — reduces large data to <5 KB LLM snippets
│ ├── models.py # Finding, Severity, AnalysisResult dataclasses
│ ├── rules/
│ │ ├── __init__.py # RULE_PROCESSORS dispatch table
│ │ ├── expression.py # Free-form condition evaluation (>, <, =, !=, and, or)
│ │ ├── fault_signal.py # fault_when operator evaluation
│ │ ├── range_check.py # min/max boundary check
│ │ └── message_loss.py # Gap detection between CAN samples
│ └── llm/
│ ├── __init__.py
│ ├── client.py # GitHubModelsClient — streaming OpenAI-compatible REST
│ └── prompts.py # Analysis and chat follow-up prompt builders
├── gui/
│ ├── main_window.py # MainWindow, toolbar, config save/load, plot_finding()
│ ├── plot_widget.py # PlotPanel: normal / multi-axis / stacked, dual cursors, zoom_to_time()
│ ├── signal_tree.py # SignalTreeWidget with live search
│ ├── raw_frame_dialog.py # Sliding-window CAN Trace (RawFrameStore, no cap)
│ ├── dbc_manager.py # Database Manager dialog: per-channel DBC/ARXML, match quality bars
│ ├── splash.py # CANScopeSplash — minimisable, taskbar-visible splash screen
│ └── diagnostics/ # Diagnostics UI (non-modal window)
│ ├── activation.py # Wires Ctrl+Shift+A shortcut in MainWindow
│ ├── window.py # DiagnosticsWindow — domain selector, run controls, auto-plot on fault
│ ├── findings_panel.py # Left panel — severity-coloured finding list + details pane
│ ├── chat_panel.py # Right panel — streaming LLM chat with status label
│ └── worker.py # AnalysisWorker / LLMWorker (background thread helpers)
├── resources/
│ ├── splashscreen.png # 1635 × 962 splash image
│ ├── CANScope_ICON.png # 1254 × 1254 app icon source
│ └── app_icon.ico # Multi-resolution ICO (256/128/64/48/32/16 px)
├── requirements.txt
├── CANScope.spec # PyInstaller spec, bundles resources/ and config/
└── .github/workflows/build.yml # Auto-build on v*.*.* tag push
| Package | Version | Purpose | License |
|---|---|---|---|
| PySide6 | ≥ 6.7 | GUI framework | LGPL v3 |
| pyqtgraph | ≥ 0.13 | Interactive plots | MIT |
| python-can | ≥ 4.6 | BLF / ASC / MF4 bus-log reading | LGPL v3 |
| cantools | ≥ 39.4 | DBC + ARXML (AUTOSAR 3/4) decoding | MIT |
| numpy | ≥ 1.26 | Array operations | BSD |
| asammdf | ≥ 7.0 | MF4 / MDF pre-decoded signals | MIT |
| canmatrix | any | MF4 bus-log support (optional) | LGPL v3 |
| pyinstaller | ≥ 6.0 | Portable .exe build | GPL v2 (build-only) |
MIT — see LICENSE.


