DirectCAN ist eine Android-App zur Analyse und Überwachung von CAN-Bus-Daten. Die App verbindet sich über USB-Serial mit CAN-Bus-Adaptern und bietet Funktionen wie DBC-Dekodierung, KI-gestützte Analyse, TX-Scripting und Echtzeit-Visualisierung.
- Features
- Hardware-Anforderungen
- Installation
- Schnellstart
- Screens & Funktionen
- DBC-Format
- TX Script Sprache
- USB-Protokoll
- Architektur
- Build & Development
- Lizenz
- USB-Serial CAN-Adapter Support - Verbindung mit Feather M4 CAN und kompatiblen Adaptern
- Echtzeit CAN-Bus Monitoring - Live-Anzeige aller CAN-Frames mit bis zu 2 Mbit/s
- DBC-Datei Support - Import/Export und Echtzeit-Signal-Dekodierung
- Multi-Screen Analyse - Monitor, Sniffer und Signal-Ansichten
- Frame-Filtering - Globaler Filter für alle Ansichten
- TX Script Engine - Eigene Scripting-Sprache für CAN-Sequenzen
- Gemini AI Integration - KI-gestützte CAN-Analyse und DBC-Generierung
- Signal-Graphen - Echtzeit-Visualisierung von bis zu 8 Signalen
- Snapshot & Logging - Speichern und Analysieren von CAN-Daten
- Chat-Export - AI-Chats als Markdown, Text oder JSON exportieren
- Material 3 Design - Moderne Android-UI
- Mehrsprachig - Deutsch und Englisch
- Dark/Light Mode - System-Theme-Unterstützung
- Tablet-optimiert - Responsive Layout
- Android Version: 8.0 (API 26) oder höher
- USB-Host Support: Erforderlich (USB OTG)
- Empfohlen: Tablet für beste Übersicht
DirectCAN ist optimiert für den Adafruit Feather M4 CAN Express mit angepasster Firmware:
| Komponente | Spezifikation |
|---|---|
| Mikrocontroller | ATSAMD51 (Feather M4) |
| CAN-Transceiver | MCP2515 / TJA1051 |
| Baudrate USB | 2.000.000 bps |
| CAN-Baudraten | 125, 250, 500, 1000 kbit/s |
Andere kompatible Adapter:
- Jeder USB-Serial-zu-CAN Adapter mit kompatiblem Textprotokoll
- ESP32-CAN mit entsprechender Firmware
- Arduino-basierte CAN-Lösungen
- APK-Datei auf das Android-Gerät übertragen
- Installation aus unbekannten Quellen erlauben
- APK installieren
git clone https://github.com/your-repo/directcan.git
cd directcan
./gradlew assembleDebug
# APK in app/build/outputs/apk/debug/- CAN-Adapter per USB-OTG mit dem Android-Gerät verbinden
- USB-Permission bestätigen
- Im Home-Screen auf "Verbinden" tippen
- Zu DBC Manager navigieren
- DBC-Datei importieren
- Zurück zum Monitor für dekodierte Daten
- Monitor-Screen öffnen
- Frames werden automatisch angezeigt
- Filter über die Sidebar konfigurieren
Der Home-Screen bietet eine Übersicht über den Verbindungsstatus und Quick-Actions.
- Geräte-Dropdown: Verfügbare USB-Geräte
- Verbinden/Trennen: Button zum Herstellen/Beenden der Verbindung
- Status-Anzeige: Verbunden/Getrennt/Verbinde...
- Zeigt die aktuell aktive DBC-Datei
- Quick-Link zum DBC Manager
- Firmware Info: Sendet
iBefehl zur Firmware - Status: Sendet
Status?Befehl
- Auto-Start Logging: Automatisches Logging bei Verbindung
- Statistiken zurücksetzen: Alle Daten löschen
Der Monitor ist das Herzstück der App - eine SavvyCAN-ähnliche Ansicht für CAN-Frames.
| Spalte | Beschreibung |
|---|---|
| # | Frame-Index |
| Time | Zeitstempel (ms) |
| ID | CAN-ID (Hex) |
| Len | Datenlänge (0-8) |
| Data | Hex-Bytes |
| ASCII | ASCII-Darstellung |
| Decoded | Signal-Werte (bei aktiver DBC) |
- Overwrite Mode: Zeigt nur die letzten N Frames pro ID (Standard)
- Append Mode: Zeigt alle Frames chronologisch
Das ausklappbare Send-Panel ermöglicht das Senden von CAN-Frames:
| Feld | Beschreibung |
|---|---|
| En | Aktiviert wiederholtes Senden |
| Bus | Bus-Nummer (für Multi-Bus) |
| ID | CAN-ID in Hex (z.B. 7DF) |
| Ext | Extended ID (29-bit) |
| RTR | Remote Transmission Request |
| Data | Hex-Bytes (z.B. 02 01 00) |
| Interval | Wiederholungsintervall (ms, 0=manuell) |
| Count | Anzahl Wiederholungen (0=endlos) |
| Sent | Gesendete Frames |
Buttons:
- Zeile hinzufügen: Neue Send-Zeile
- Script einhängen: TX Script Panel öffnen
- Send (➤): Einzelnen Frame senden
- Delete (🗑): Zeile löschen
Im Monitor kann ein TX Script direkt ausgeführt werden:
- "Script einhängen" klicken
- Script aus Dropdown wählen
- Play-Button zum Starten
- Pause/Stop für Kontrolle
- Error-Badge zeigt Fehler an
- Statistiken: Total Frames, FPS
- Logging: Start/Stop Capturing
- Clear: Frames löschen
- Filter: IDs ein-/ausblenden
Der Sniffer analysiert CAN-Frames auf Byte-Ebene mit Änderungserkennung.
- Grün: Wert erhöht sich
- Rot: Wert verringert sich
- Fade-Out: Nach konfigurierbarer Zeit
- Bytes View: Hex-Bytes mit Farbmarkierung
- Bits View: Einzelne Bits anzeigen
- ASCII: Lesbare Zeichen
| Einstellung | Beschreibung |
|---|---|
| Highlight Duration | Dauer der Farbmarkierung (0-1000ms) |
| Never Expire | IDs bleiben auch ohne neue Frames |
| Mute Notched | Bits ohne Änderung ausblenden |
Die Signal-Ansicht zeigt dekodierte Werte aus der aktiven DBC.
- Echtzeit-Updates: Live-Werte aller Signale
- Suche: Nach Signal, Message oder ID suchen
- Nur geändert: Nur aktive Signale anzeigen
- Gruppierung: Nach Message gruppiert
[Message-Name] 0x123
├── Signal1: 1234.5 rpm [▓▓▓▓▓▓░░░░]
├── Signal2: 45.2 °C [▓▓▓░░░░░░░]
└── Signal3: ON [Grün]
Echtzeit-Graphen für bis zu 8 Signale gleichzeitig.
- Signale aus der Liste auswählen (Checkbox)
- Graph zeigt Verlauf der letzten 2000 Samples
- Auto-Update kann pausiert werden
- Multi-Color: Jedes Signal in eigener Farbe
- Y-Achse: Automatische Skalierung
- X-Achse: Zeit in Samples
- Legende: Zeigt aktive Signale
Verwaltung von DBC-Dateien (Database Container für CAN-Definitionen).
- Import über Datei-Picker
- Export für Backup/Sharing
- Aktivieren/Deaktivieren pro DBC
- Löschen
- Messages: Anzahl definierter Messages
- Signals: Gesamtzahl Signale
- Nodes: Definierte ECU-Knoten
Vollständiger Editor für DBC-Inhalte.
| Feld | Beschreibung |
|---|---|
| ID | CAN-ID (Hex) |
| Name | Message-Bezeichnung |
| Length | Datenlänge (1-8 Bytes) |
| Transmitter | Sendender Knoten |
| Extended | 29-bit ID |
| Description | Beschreibung |
| Feld | Beschreibung |
|---|---|
| Name | Signal-Bezeichnung |
| Start Bit | Startposition (0-63) |
| Length | Bit-Länge |
| Byte Order | Little/Big Endian |
| Value Type | Signed/Unsigned |
| Factor | Skalierungsfaktor |
| Offset | Offset-Wert |
| Min/Max | Wertebereich |
| Unit | Einheit (z.B. "rpm") |
| Value Descriptions | Lookup-Tabelle |
Verwaltung und Ausführung von TX Scripts.
- Erstellen: Neues leeres Script
- Importieren: .txs Datei laden
- Exportieren: Script als Datei speichern
- Duplizieren: Kopie erstellen
- Umbenennen: Namen ändern
- Löschen: Script entfernen
- Syntax-Validierung: Echtzeit-Fehleranzeige
- Zeilennummern: Mit Fehlermarkierung
- Speichern: Änderungen sichern
- Validieren: Syntax prüfen
- Play: Script starten
- Pause: Temporär anhalten
- Resume: Fortsetzen
- Stop: Beenden und zurücksetzen
- Errors: Fehlerlog anzeigen
KI-gestützte CAN-Analyse mit verschiedenen Anbietern.
- OpenRouter - Viele kostenlose Modelle! (Llama, Gemma, Mistral, etc.)
- Google Gemini - gemini-1.5-flash, gemini-1.5-pro, etc.
- OpenAI - gpt-4o, gpt-4o-mini, gpt-4-turbo, etc.
- Anthropic Claude - claude-3-5-sonnet, claude-3-opus, etc.
- Llama 3.2 3B
- Gemma 2 9B
- Mistral 7B
- Zephyr 7B
- OpenChat 7B
- Nous Capybara 7B
- Settings → AI Chat öffnen
- Provider auswählen (OpenRouter, Gemini, OpenAI, Claude)
- API-Key eingeben (OpenRouter: openrouter.ai - kostenlos!)
- Modell auswählen
- Verbindung testen
- Snapshot-Analyse: CAN-Daten an AI senden
- DBC-Generierung: AI erstellt Signal-Definitionen
- Chat-History: Mehrere Gespräche verwalten
- Delta-Mode: Nur Änderungen senden (Token-sparend)
Chats können in verschiedenen Formaten exportiert werden:
- Markdown (.md): Formatiert mit Emojis und collapsible Sections
- Text (.txt): Einfaches Textformat
- JSON (.json): Vollständige Daten für Import/Backup
Export-Optionen:
- Einzelner Chat: Share-Button in der Chat-Ansicht
- Alle Chats: "Exportieren"-Button in den Gemini Settings
- Teilen: Direkt an andere Apps senden
Die AI kann DBC-Befehle generieren:
{
"commands": [
{"type": "addMessage", "id": 513, "name": "EngineData", "length": 8},
{"type": "addSignal", "messageId": 513, "name": "RPM", "startBit": 0, "length": 16}
]
}Diese werden automatisch geparst und zur DBC hinzugefügt.
Zentrale Einstellungen der App.
| Einstellung | Beschreibung |
|---|---|
| Baudrate | CAN-Bus Geschwindigkeit |
| Auto-Connect | Automatisch verbinden |
| Loopback | Test-Modus (Echo) |
| Einstellung | Beschreibung |
|---|---|
| Sprache | System/Deutsch/English |
| Einstellung | Beschreibung |
|---|---|
| Log-Speicherort | Ordner für Log-Dateien |
| Snapshot Manager | Gespeicherte Snapshots verwalten |
| Einstellung | Beschreibung |
|---|---|
| TX Script Manager | Scripts verwalten |
| Einstellung | Beschreibung |
|---|---|
| AI Chat | Provider, API-Key und Modell konfigurieren |
| Einstellung | Beschreibung |
|---|---|
| Status-Logging | Debug-Logs aktivieren |
| Log-Intervall | Intervall für Dev-Logs |
DirectCAN unterstützt das Standard-DBC-Format für CAN-Datenbanken.
VERSION "1.0"
NS_ :
BS_:
BU_: ECU Cluster Gateway
BO_ 201 EngineRPM: 8 ECU
SG_ RPM : 0|16@1+ (0.25,0) [0|16383.75] "rpm" Cluster
SG_ EngineRunning : 16|1@1+ (1,0) [0|1] "" Cluster
SG_ EngineTemp : 24|8@1+ (1,-40) [-40|215] "C" Cluster
BO_ 180 VehicleSpeed: 8 ECU
SG_ Speed : 0|16@1+ (0.01,0) [0|655.35] "km/h" Cluster
CM_ BO_ 201 "Engine status message";
CM_ SG_ 201 RPM "Engine revolutions per minute";
VAL_ 201 EngineRunning 0 "Off" 1 "Running" ;
- Little Endian (Intel):
@1+- LSB first - Big Endian (Motorola):
@0+- MSB first
- Unsigned:
+am Ende - Signed:
-am Ende
Physical Value = (Raw Value × Factor) + Offset
Signal: RPM : 0|16@1+ (0.25,0) [0|16383.75] "rpm"
Raw Data: 0x30 0x75 ...
Raw Value: 0x7530 = 30000
Physical: 30000 × 0.25 + 0 = 7500 rpm
DirectCAN bietet eine eigene Domain-Specific Language (DSL) für CAN-Sequenzen.
- Endung:
.txs - Encoding: UTF-8
- Kommentare:
//(Zeile) oder/* */(Block)
// Standard CAN-ID mit Daten
send(0x7DF, [02, 01, 00])
// Extended ID (29-bit)
send(0x18DAF110, [02, 3E, 00], ext)
// Mit Variablen
var diagId = 0x7DF
var data = [02, 01, 0C]
send(diagId, data)
delay(100) // 100 Millisekunden
delay(2s) // 2 Sekunden
// Feste Anzahl
repeat(5) {
send(0x7DF, [02, 01, 0D])
delay(100)
}
// Endlos (bis Stop)
loop {
send(0x7DF, [02, 01, 00])
delay(500)
}
if (response.id == 0x7E8) {
send(0x7DF, [02, 01, 0C])
} else {
send(0x7DF, [02, 01, 00])
}
// Auf bestimmte ID warten
wait_for(0x7E8, timeout: 1000)
// Mit Daten-Pattern (* = Wildcard)
wait_for(0x7E8, data: [41, 01, *])
// Variablen
var diagId = 0x7DF
var responseId = 0x7E8
var ecuData = [02, 01, 00]
// Berechnungen
var rpm = (response.data[3] * 256 + response.data[4]) / 4
var checksum = (data[0] + data[1] + data[2]) & 0xFF
// Zufallswerte
var randomByte = random(0x00, 0xFF)
var randomData = random_bytes(8)
// Definition
function requestPID(pid) {
send(0x7DF, [02, 01, pid])
wait_for(0x7E8, timeout: 500)
return response.data[3]
}
// Aufruf
var speed = requestPID(0x0D)
print("Speed: ", speed)
// Bei Empfang einer ID
on_receive(0x123) {
send(0x456, [01, 02, 03])
}
// Periodisch
on_interval(1000) {
send(0x7DF, [02, 01, 00])
}
| Variable | Beschreibung |
|---|---|
response |
Letzter empfangener Frame |
response.id |
ID des Frames |
response.data |
Daten-Array |
response.data[n] |
n-tes Byte |
response.timestamp |
Zeitstempel |
now |
Aktuelle Zeit (ms) |
iteration |
Schleifenzähler |
| Kategorie | Operatoren |
|---|---|
| Arithmetik | + - * / % |
| Vergleich | == != < <= > >= |
| Logik | && || ! |
| Bitweise | & | ^ ~ << >> |
// OBD-II Fahrzeug-Diagnose Script
var diagId = 0x7DF
var timeout = 1000
function queryPID(pid) {
send(diagId, [02, 01, pid])
wait_for(0x7E8, timeout: timeout)
return response
}
// Motor-RPM abfragen
repeat(10) {
queryPID(0x0C)
if (response.data[0] == 0x41) {
var rpm = (response.data[3] * 256 + response.data[4]) / 4
print("RPM: ", rpm)
}
delay(500)
}
// Diagnose-Session aufrecht erhalten
loop {
send(0x7E0, [02, 3E, 00])
delay(2000)
}
DirectCAN kommuniziert über ein textbasiertes Protokoll mit dem CAN-Adapter.
t<TIMESTAMP> <ID>[X][R] <LENGTH> <DATA_BYTES>
Beispiele:
t12345 123 8 01 02 03 04 05 06 07 08
t12346 7DFX 3 02 01 00 // Extended ID
t12347 123R 0 // Remote Frame
| Feld | Beschreibung |
|---|---|
| t | Frame-Präfix |
| TIMESTAMP | Zeitstempel in ms |
| ID | CAN-ID (Hex, ohne 0x) |
| X | Extended ID Marker (optional) |
| R | Remote Frame Marker (optional) |
| LENGTH | Datenlänge (0-8) |
| DATA_BYTES | Hex-Bytes mit Leerzeichen |
// CAN-Frame senden
s<ID>[X] <LENGTH> <DATA_BYTES>
// Beispiele:
s7DF 3 02 01 00 // Standard ID
s18DAF110X 3 02 3E 00 // Extended ID
// Konfiguration
i // Firmware Info
Status? // Status abfragen
Die USB-Serial-Verbindung verwendet 2.000.000 bps (2 Mbit/s).
app/src/main/java/at/planqton/directcan/
├── DirectCanApplication.kt # App-Singleton mit Repositories
├── MainActivity.kt # Navigation Host
│
├── data/
│ ├── can/
│ │ ├── CanModels.kt # CanFrame, DecodedFrame
│ │ ├── CanDataRepository.kt # Zentrale Datenverarbeitung
│ │ └── CanSimulator.kt # Test-Simulation
│ │
│ ├── dbc/
│ │ ├── DbcModels.kt # DbcFile, DbcMessage, DbcSignal
│ │ ├── DbcParser.kt # DBC-Datei Parser
│ │ └── DbcRepository.kt # DBC-Verwaltung
│ │
│ ├── usb/
│ │ └── UsbSerialManager.kt # USB-Kommunikation
│ │
│ ├── settings/
│ │ └── SettingsRepository.kt # DataStore Einstellungen
│ │
│ ├── gemini/
│ │ ├── GeminiRepository.kt # AI API Client
│ │ ├── GeminiResponseParser.kt
│ │ └── DbcCommands.kt # AI-generierte DBC-Befehle
│ │
│ └── txscript/
│ ├── TxScriptModels.kt # Script-Datenmodelle
│ ├── TxScriptState.kt # Ausführungszustand
│ ├── TxScriptCommands.kt # AST-Definitionen
│ ├── TxScriptRepository.kt # Script-Verwaltung
│ ├── TxScriptExecutor.kt # Script-Ausführung
│ └── parser/
│ ├── TxScriptLexer.kt # Tokenizer
│ └── TxScriptParser.kt # Parser
│
├── ui/
│ ├── navigation/
│ │ └── Navigation.kt # Screen-Definitionen
│ │
│ ├── screens/
│ │ ├── home/
│ │ │ └── HomeScreen.kt
│ │ ├── monitor/
│ │ │ └── MonitorScreen.kt
│ │ ├── sniffer/
│ │ │ └── SnifferScreen.kt
│ │ ├── signals/
│ │ │ ├── SignalViewerScreen.kt
│ │ │ └── SignalGraphScreen.kt
│ │ ├── dbc/
│ │ │ ├── DbcManagerScreen.kt
│ │ │ ├── DbcEditorScreen.kt
│ │ │ ├── MessageEditorDialog.kt
│ │ │ └── SignalEditorDialog.kt
│ │ ├── settings/
│ │ │ └── SettingsScreen.kt
│ │ ├── logs/
│ │ │ └── LogManagerScreen.kt
│ │ ├── gemini/
│ │ │ ├── GeminiSettingsScreen.kt
│ │ │ └── GeminiChatScreen.kt
│ │ └── txscript/
│ │ ├── TxScriptManagerScreen.kt
│ │ ├── ScriptEditorScreen.kt
│ │ ├── ScriptErrorLogDialog.kt
│ │ └── components/
│ │ └── ScriptControlPanel.kt
│ │
│ └── theme/
│ └── Theme.kt
│
├── service/
│ └── CanLoggingService.kt # Hintergrund-Logging
│
└── util/
└── LocaleHelper.kt # Sprachverwaltung
┌─────────────────────────────────────────────────────────────┐
│ USB CAN Adapter │
└─────────────────────────┬───────────────────────────────────┘
│ USB Serial (2 Mbit/s)
▼
┌─────────────────────────────────────────────────────────────┐
│ UsbSerialManager │
│ • Verbindungsmanagement │
│ • Frame-Parsing (CanFrame.fromTextLine) │
│ • receivedLines: SharedFlow<String> │
└─────────────────────────┬───────────────────────────────────┘
│ Flow Collection
▼
┌─────────────────────────────────────────────────────────────┐
│ CanDataRepository │
│ • processFrame() - Zentrale Verarbeitung │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │monitorFrames│ │snifferFrames│ │signalValues/History │ │
│ │ List<> │ │ Map<> │ │ Map<> │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
└─────────┼───────────────┼───────────────────┼───────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌────────────────────┐
│ Monitor │ │ Sniffer │ │ Signals/Graph │
│ Screen │ │ Screen │ │ Screens │
└──────────┘ └──────────┘ └────────────────────┘
Die App verwendet Kotlin Coroutines mit StateFlow für reaktive Updates:
// Repository
private val _frames = MutableStateFlow<List<CanFrame>>(emptyList())
val frames: StateFlow<List<CanFrame>> = _frames.asStateFlow()
// UI (Composable)
val frames by repository.frames.collectAsState()Manuelle DI über DirectCanApplication Singleton:
class DirectCanApplication : Application() {
lateinit var usbSerialManager: UsbSerialManager
lateinit var dbcRepository: DbcRepository
lateinit var canDataRepository: CanDataRepository
// ...
companion object {
lateinit var instance: DirectCanApplication
}
}
// Usage
val repository = DirectCanApplication.instance.canDataRepository- Android Studio: Arctic Fox oder neuer
- JDK: 17
- Android SDK: API 26-34
# Debug Build
./gradlew assembleDebug
# Release Build (signiert)
./gradlew assembleRelease
# Tests
./gradlew test| Library | Version | Verwendung |
|---|---|---|
| Jetpack Compose | 1.5+ | UI Framework |
| Material 3 | 1.1+ | Design System |
| Kotlin Coroutines | 1.7+ | Async/Flow |
| Kotlin Serialization | 1.6+ | JSON |
| usb-serial-for-android | 3.7+ | USB Serial |
| Vico | 2.0+ | Charts |
| Google Generative AI | 0.9+ | Gemini API |
| DataStore | 1.0+ | Preferences |
| Navigation Compose | 2.7+ | Navigation |
- Kotlin: Offizielle Kotlin Coding Conventions
- Compose: Single-State-Hoisting Pattern
- Repository Pattern: Für Datenzugriff
Copyright (c) 2024 Planqton
Dieses Projekt ist unter der MIT-Lizenz lizenziert.
Siehe LICENSE-Datei für Details.
- Issues: GitHub Issues
- Dokumentation: Diese README
- Email: support@planqton.at
Entwickelt für die CAN-Bus Community
