Kettenöler – CAN Reverse-Engineering Toolkit
Toolsuite (GUI + CLI) zum Analysieren von CAN-Logs im Kettenöler-Format.
Funktionen: Logs splitten (pro CAN-ID), explorative Visualisierung (8-/16-Bit, LE/BE), Batch-Analysen über viele .trace
, Ranking plausibler Signale und Range-Fit (lineare Abbildung phys = raw*scale + offset
), optional unsupervised ohne vorgegebene Range.
Features (Überblick)
-
Einheitliche GUI (
main.py
) mit globalem Header (Workdir, Ordnerstruktur, Log-Auswahl). -
Gemeinsame Trace-Auswahl in allen Trace-Tabs (gleiches Panel, synchronisiert über Tabs):
- ID Explorer (Multi-Select)
- Traces Batch-Analyse (Multi-Select oder kompletter Ordner)
- Range-Fit (Single-Select, supervised oder unsupervised)
-
Splitter: Logs →
.trace
pro CAN-ID (traces/…
, inkl.overview_ids.csv
). -
Einzel-ID-Explorer: Plots aller Byte-Kanäle (8-Bit) und Nachbar-Wortkombis (16-Bit LE/BE) + Kurzstatistik.
-
Batch-Analyzer: Kennzahlen/Plots für alle
.trace
in einem Ordner, globales Ranking. -
Range-/Unsupervised-Fit:
- Supervised: findet
scale
&offset
für Zielbereich[rmin, rmax]
(Offset via Intervall-Überdeckung, Scale aus plausibler Menge). - Unsupervised: identifiziert „ruhige“ physikalische Kandidaten ohne Range (Smoothness/Varianz/Rate/Spannweite).
- Supervised: findet
-
Output-Hygiene: Ergebnisse stets unter
analyze_out/<timestamp>_<tool>/…
, optionale Zeitstempel-Unterordner verhindern Überschreiben. -
Projektdatei (
Projekt.json
): speichert Workdir, Subfolder, Log-Auswahl, aktiven Traces-Ordner, etc. -
„Neuester Split“-Button: springt in den jüngsten Unterordner von
traces/
.
Repository-Komponenten
-
GUI
main.py
– zentrales Frontend mit Tabs (Multi-Log Analyse, ID Explorer, Traces Batch-Analyse, Range-Fit).
-
CLI-Tools
can_split_by_id.py
– Splittet Logs nach CAN-ID →.trace
.id_signal_explorer.py
– Visualisiert/analysiert eine.trace
(8-Bit, 16-Bit LE/BE) +summary_stats.csv
.trace_batch_analyzer.py
– Batch-Analyse für viele.trace
+ globales Ranking.trace_signal_fitter.py
– Range-Fit (scale/offset) oder Unsupervised-Fit (ohne Range).
Optional/Alt:
can_universal_signal_finder.py
– ursprünglicher Multi-Log-Analyzer (Ranking auf Rohdatenebene).
Installation
-
Python ≥ 3.10
-
Abhängigkeiten:
pandas
,numpy
,matplotlib
-
Setup:
python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt
Logformat (Kettenöler)
Eine Zeile pro Frame:
<timestamp_ms> <TX|RX> 0x<ID_HEX> <DLC> <byte0> <byte1> ... <byte7>
Beispiel:
123456 RX 0x208 8 11 22 33 44 55 66 77 88
Projekt-/Ordnerstruktur
Ein Workdir bündelt alles zu einem Fahrzeug/Projekt:
<Workdir>/
Projekt.json # GUI-Einstellungen
logs/ # Input-Logs
traces/ # per-ID .trace (vom Split)
analyze_out/ # Ergebnisse; je Run eigener Timestamp-Unterordner
Namenskonventionen
- Split-Ergebnisse:
traces/<timestamp?>/0x<ID>_<ursprungslog>.trace
- Outputs:
analyze_out/<YYYYMMDD_HHMMSS>_<tool>/…
Modelle-Ordner & Git
Wenn du pro Modell arbeitest, z. B.:
models/
Triumph 2023/
logs/
traces/
analyze_out/
Projekt.json
Lege in models/
folgende .gitignore
ab, damit traces/
und analyze_out/
in jedem Modell-Unterordner ignoriert werden – logs/
und .json
bleiben versioniert:
*/traces/
*/traces/**
*/analyze_out/
*/analyze_out/**
traces/
traces/**
analyze_out/
analyze_out/**
# optional: typos
*/analyze.out/
*/analyze.out/**
analyze.out/
analyze.out/**
Leere Ordner wie logs/
ggf. mit .gitkeep
befüllen.
GUI-Benutzung
python3 main.py
Globaler Header (immer oben)
- Workdir wählen, Logs scannen → Liste aller gefundenen Logfiles (Multi-Select).
- Subfolder einstellen:
logs
,traces
,analyze_out
(alle parallel im Workdir). - Projekt speichern/laden (
Projekt.json
). - Beim Workdir-Wechsel/Projekt-Laden setzt die GUI den aktiven Traces-Ordner automatisch auf
traces/
bzw. den jüngsten Unterordner.
Einheitliches Trace-Panel (in allen Trace-Tabs)
- Links: Liste der
.trace
- Rechts: Traces-Ordner wählen, Workdir/traces, Neuester Split, Refresh, (optional Alle, Keine)
- Änderungen am Ordner/Liste wirken sofort in allen Tabs.
Tab: Multi-Log Analyse
- Ranking direkt aus Logs (Include/Exclude-IDs, optional Range mit
scale/offset
). - Output:
analyze_out/<ts>_multilog/…
- Optional: „Jede Logdatei separat“ → je Log eigener Unterordner.
Tab: ID Explorer
-
Split (aus Header-Logauswahl): Logs →
.trace
nachtraces[/<ts>]
, plusoverview_ids.csv
. Danach wird der neue Traces-Pfad automatisch aktiviert. -
Einzel-ID Analyse (Multi-Select):
- Plots: Byte[0..7] (8-Bit) + LE/BE für Paare (0-1 … 6-7)
summary_stats.csv
pro Trace- Output:
analyze_out/<ts>_id_explore/…
Tab: Traces Batch-Analyse
-
Nutzt die gemeinsame Trace-Liste.
-
Ohne Auswahl → kompletter Ordner; mit Auswahl → es wird ein Subset-Ordner gebaut (Hardlinks/Kopie) und nur dieses analysiert.
-
Parameter:
--rx-only
,scale
,offset
,range-min/max
,top
,--plots
. -
Output:
- je Trace:
*_combostats.csv
(+ Plots), - global:
summary_top_combinations.csv
- unter
analyze_out/<ts>_trace_batch/…
- je Trace:
Tab: Range-Fit (Single-Select)
-
Zwei Modi:
- Supervised (Range-Min/Max gesetzt): findet
scale
&offset
, maximiert Hit-Ratio im Zielbereich. Output:<trace>_encoding_candidates.csv
+ phys-Plots (Top-N). - Unsupervised (Range leer): bewertet Kandidaten nach Smoothness, Spannweite, Varianz, Rate, Uniqueness.
Output:
<trace>_unsupervised_candidates.csv
+ Roh-Plots (Top-N).
- Supervised (Range-Min/Max gesetzt): findet
-
Optionen:
nur RX
,negative Scale erlauben
(nur supervised),Min. Hit-Ratio
,Min. Smoothness
,Plots Top-N
,Output-Label
. -
Output:
analyze_out/<ts>_rangefit/…
CLI-Quickstart
1) Splitten
python3 can_split_by_id.py logs/run1.log logs/run2.log \
--outdir <Workdir>/traces/20250827_1200 \
--rx-only
2) Einzel-ID-Explorer
python3 id_signal_explorer.py <Workdir>/traces/20250827_1200/0x208_run1.trace \
--outdir <Workdir>/analyze_out/20250827_1210_id_explore
3) Batch-Analyse
python3 trace_batch_analyzer.py \
--traces-dir <Workdir>/traces/20250827_1200 \
--outdir <Workdir>/analyze_out/20250827_1220_trace_batch \
--rx-only --plots --top 8 \
--range-min 31 --range-max 80
4) Range-/Unsupervised-Fit (eine .trace
)
# Supervised (z. B. Kühlmittel 31..80°C)
python3 trace_signal_fitter.py <trace> \
--rmin 31 --rmax 80 \
--outdir <Workdir>/analyze_out/20250827_1230_rangefit \
--plots-top 8 --min-hit 0.5 --allow-neg-scale
# Unsupervised (ohne Range)
python3 trace_signal_fitter.py <trace> \
--outdir <Workdir>/analyze_out/20250827_1240_unsupervised \
--plots-top 8 --min-smooth 0.2
Algorithmen & Heuristiken
-
Kombinationen:
- 8-Bit:
D0..D7
- 16-Bit (adjazent): LE & BE für Paare
(0,1)…(6,7)
(32-Bit & bit-gepackte Felder: auf der Roadmap)
- 8-Bit:
-
Prefilter (für „ruhige“ physikalische Größen): Mindestanzahl Samples, nicht (nahezu) konstant, keine exzessiven Sprünge (p95 der |Δ| relativ zur Spannweite).
-
Range-Fit: Für jeden Kandidaten
raw
wird über eine Menge plausibler Scales gesucht; für jedesscale
wird das Offset via Intervall-Überdeckung bestimmt (rmin ≤ scale*raw_i + offset ≤ rmax
). Ranking: Hit-Ratio ↓, dann Glattheit (p95 phys) ↑, Rate ↓, n ↓. -
Unsupervised: Smoothness =
1 − clamp(p95(|Δ|)/span, 0..1)
; zusätzlich span, var, rate, uniq_ratio. Ranking auf diese Metriken.
Tipps & Troubleshooting
- Keine Kandidaten (Range-Fit):
--min-hit
senken,--allow-neg-scale
testen, Range prüfen, längeres/variableres Log nutzen. - Alles wird gefiltert (Unsupervised):
--min-smooth
senken; ggf.--rx-only
aktivieren. - Leere/komische Plots: DLC < 8 → teils keine 16-Bit-Kombis; Frames sehr selten → Rate niedrig.
- Ordner stets sauber: Zeitstempel-Unterordner aktiv lassen; pro Run eigene Artefakte.
Roadmap
- 32-Bit-Kombinationen, bit-gepackte Felder.
- Histogramme, Autokorrelation, Ausreißer-Detektoren.
- vordefinierte Signal-Profile (z. B. WheelSpeed, CoolantTemp).
Lizenz / Haftung
Nur zu Analyse-/Reverse-Engineering-Zwecken. Nutzung auf eigene Verantwortung.