316 lines
15 KiB
Markdown
316 lines
15 KiB
Markdown
# UARTScope
|
||
|
||
Ein moderner UART-Monitor für Linux mit Qt6-Oberfläche. Gebaut als vollwertiger Ersatz für minicom – besonders nützlich bei der Entwicklung von Baremetal-Projekten wie [Chica](https://git.projekt-hirnfrei.de/diabolus/chica) (Amiga-Hardware-Nachbildung auf dem Raspberry Pi).
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
| Feature | Beschreibung |
|
||
|---|---|
|
||
| **Serieller UND Netzwerk-Input** | Verbindung wahlweise über einen echten/virtuellen seriellen Port **oder** eine reine TCP-Verbindung – praktisch für Emulatoren wie FS-UAE, deren Debug-UART per `socat` auf einen TCP-Port gelegt wird |
|
||
| **PTY-Erkennung** | Pseudo-Terminals unter `/dev/pts/` (z.B. von `qemu -serial pty`) werden im Port-Dropdown automatisch mitgelistet |
|
||
| **Unbegrenzter Verlauf** | Kein Zeilenlimit – keine Daten gehen verloren, egal wie viel gesendet wird |
|
||
| **Timestamps** | Jede Zeile im Raw-View bekommt automatisch einen `hh:mm:ss.zzz`-Timestamp |
|
||
| **Auto-Scroll** | Standardmäßig aktiv – springt automatisch ans Ende neuer Ausgaben |
|
||
| **H + V Scrolling** | Kein Zeilenumbruch, voller horizontaler Scrollbalken |
|
||
| **Live-Logging** | Alle empfangenen Zeilen werden mit Timestamp in eine Datei geschrieben |
|
||
| **Tag-Monitor mit Verlauf** | Zeilen mit `[TAG]` werden in eigenen Panels angezeigt; jedes Panel hat einen „Aktuell"-Tab (Live-Stand) und einen „Verlauf"-Tab (alle je empfangenen Werte, timestamped) |
|
||
| **Listen-Werte** | `;`-getrennte Werte in einem Tag werden als mehrzeilige Liste dargestellt |
|
||
| **Tag-Filter** | Tags können aus dem Raw-View ausgeblendet werden – wird dauerhaft gespeichert; auch Tag-Namen mit Bindestrich (z.B. `I2C-BUS`) werden korrekt erkannt |
|
||
| **Tabellenansicht** | CSV-formatierte UART-Zeilen werden in einer Tabelle dargestellt |
|
||
| **Suche mit Navigation** | Inkrementelle Volltextsuche im Raw-View mit Weiter/Zurück (Buttons, Enter, F3/Shift+F3) und Wrap-Around |
|
||
| **Auto-Reconnect** | Bei Verbindungsabbruch wird automatisch neu verbunden (Intervall einstellbar) – funktioniert für seriell und TCP gleichermaßen |
|
||
| **ANSI Clear-Screen** | `\033[2J\033[H` aus der Firmware leert Raw-View, Tabelle, Tag-Monitor und Video-Vorschau gleichzeitig |
|
||
| **Copy-Buttons** | Raw-View und jedes Tag-Panel (Aktuell- oder Verlauf-Tab) haben einen „📋 Copy"-Button |
|
||
| **V4L2 Live Video** | HDMI-Grabber direkt eingebunden – Live-Vorschau unter dem Tag-Monitor |
|
||
| **Video-Aufzeichnung (MP4)** | Live-Vorschau per Knopfdruck als MP4 aufzeichnen (H.264, via `ffmpeg`) |
|
||
| **Screenshot** | Aktuellen Frame des HDMI-Grabbers als PNG/JPG speichern |
|
||
| **Automatischer Screenshot-Trigger** | `[SCREENSHOT] dateiname` als Steuertag: der Frame wird exakt im Moment des Empfangs gespeichert – ideal um z.B. einen kurz angezeigten Memory-Dump zuverlässig zu erwischen |
|
||
| **Format-Referenz** | Eingebauter Guide (mit Kopieren-Button) für KI-kompatible UART-Formatierung |
|
||
| **Fensterlayout** | Fenstergröße, Position, Splitter-Positionen und Tag-Filter werden beim Beenden gespeichert |
|
||
|
||
---
|
||
|
||
## Voraussetzungen
|
||
|
||
```bash
|
||
# Arch (empfohlen)
|
||
sudo pacman -S cmake qt6-base qt6-serialport ffmpeg
|
||
|
||
# Ubuntu / Debian
|
||
sudo apt install cmake qt6-base-dev qt6-serialport-dev libqt6serialport6-dev ffmpeg
|
||
|
||
# Fedora
|
||
sudo dnf install cmake qt6-qtbase-devel qt6-qtserialport-devel ffmpeg
|
||
```
|
||
|
||
V4L2 benötigt keine zusätzliche Library – `linux/videodev2.h` ist Teil der Standard-Kernel-Header. Das TCP-Netzwerk-Modul (`Qt6::Network`) ist üblicherweise Teil des `qt6-base`-Pakets und braucht keine separate Installation.
|
||
|
||
`ffmpeg` ist **nur** für die Video-Aufzeichnung (MP4) nötig – ohne installiertes `ffmpeg` funktioniert der Rest von UARTScope normal, nur der „⏺ Record"-Button zeigt dann eine Fehlermeldung.
|
||
|
||
---
|
||
|
||
## Build
|
||
|
||
```bash
|
||
git clone https://git.projekt-hirnfrei.de/diabolus/uartscope.git
|
||
cd uartscope
|
||
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||
cmake --build build -j$(nproc)
|
||
|
||
# Ausführen
|
||
./build/uartscope
|
||
|
||
# Systemweit installieren (optional)
|
||
sudo cmake --install build
|
||
```
|
||
|
||
---
|
||
|
||
## Verbindung: Seriell oder Netzwerk (TCP)
|
||
|
||
Im Connect-Dialog gibt es zwei Tabs:
|
||
|
||
### Seriell
|
||
Wie gewohnt: Port aus der Liste wählen (echte Geräte **und** Pseudo-Terminals unter `/dev/pts/` werden angezeigt), Baudrate/Parität/Stopbits/Flow Control einstellen.
|
||
|
||
**Virtuelle serielle Geräte (z.B. QEMU):**
|
||
```bash
|
||
qemu-system-xxx -serial pty ...
|
||
# QEMU gibt im Log den zugewiesenen Pfad aus, z.B.:
|
||
# char device redirected to /dev/pts/4
|
||
```
|
||
Den ausgegebenen Pfad im Seriell-Tab auswählen (ggf. vorher ↻ zum Neuladen der Liste drücken). Baudrate & Co. werden von virtuellen PTYs ignoriert – das ist unschädlich.
|
||
|
||
### Netzwerk (TCP)
|
||
Host/IP und Port angeben statt eines seriellen Ports. Gedacht für Firmware/Emulatoren, die ihre Debug-UART über TCP senden statt über ein echtes serielles Gerät – zum Beispiel FS-UAE, dessen serielle Schnittstelle per `socat` auf einen TCP-Port gelegt wird:
|
||
|
||
```bash
|
||
# Beispiel: FS-UAEs serielle Ausgabe per socat auf TCP-Port 1234 legen
|
||
socat /tmp/fs-uae-serial TCP-LISTEN:1234,reuseaddr,fork
|
||
```
|
||
|
||
Danach im Netzwerk-Tab `localhost` und Port `1234` eintragen und verbinden. Auto-Reconnect funktioniert identisch zum seriellen Modus – bricht die TCP-Verbindung ab, wird automatisch neu verbunden.
|
||
|
||
---
|
||
|
||
## Video-Aufzeichnung (MP4)
|
||
|
||
Die Live-Vorschau im Video-Widget lässt sich per „⏺ Record"-Button als MP4-Datei aufzeichnen. Dazu wird intern ein `ffmpeg`-Prozess gestartet, dem die rohen Frames als BGRA über eine Pipe zugeführt werden; `ffmpeg` encodiert sie zu H.264/MP4.
|
||
|
||
- **Voraussetzung:** `ffmpeg` muss installiert und im `PATH` sein (siehe [Voraussetzungen](#voraussetzungen))
|
||
- Die Aufzeichnung läuft unabhängig vom Freeze-Status weiter – Freeze pausiert nur die Vorschau, nicht die Aufnahme
|
||
- Timestamps basieren auf der Systemuhr (`-use_wallclock_as_timestamps`), damit die Aufnahme auch bei schwankender Framerate des Grabbers die reale Dauer korrekt wiedergibt
|
||
- Ein Auflösungswechsel während der Aufnahme, ein Stopp der Capture oder ein Fehler beenden die Aufzeichnung automatisch sauber
|
||
|
||
---
|
||
|
||
## Automatischer Screenshot-Trigger
|
||
|
||
Manuelles Klicken auf den Screenshot-Button trifft bei schnellen Hardware-Ereignissen (z.B. einem kurz angezeigten Memory-Dump) selten genau den richtigen Moment – menschliche Reaktionszeit liegt bei mehreren hundert Millisekunden, in der Hardware-Welt passieren in dieser Zeit unzählige Instruktionen. Dafür gibt es den Steuertag `[SCREENSHOT]`:
|
||
|
||
```c
|
||
uart_printf("[SCREENSHOT] memdump_%lu.png\n", HAL_GetTick());
|
||
```
|
||
|
||
Sobald diese Zeile empfangen wird, speichert UARTScope **sofort** den Frame, der zu diesem Zeitpunkt im V4L2-Vorschaupuffer liegt – kein Dialog, keine Nutzerinteraktion nötig. Die Verzögerung besteht nur noch aus UART-Übertragungszeit und einem Event-Loop-Tick (typischerweise einstellige Millisekunden), statt aus menschlicher Reaktionszeit.
|
||
|
||
**Einrichtung:**
|
||
1. In der Toolbar auf „Screenshot folder…" klicken und den Zielordner wählen
|
||
2. Die Einstellung wird sofort gespeichert und bei jedem Programmstart wiederhergestellt
|
||
|
||
**Verhalten:**
|
||
- Ohne konfigurierten Ordner wird der Trigger zwar erkannt (erscheint im Tag-Monitor und Raw-View), aber es wird keine Datei geschrieben – das Ergebnis jedes Trigger-Versuchs (Erfolg oder Fehler, z.B. „kein Ordner konfiguriert" oder „noch kein Frame verfügbar") erscheint kurz in der Statusleiste **und** dauerhaft als `[UARTSCOPE] ...`-Zeile im Raw-View, direkt neben der eigentlichen `[SCREENSHOT]`-Zeile – so geht eine Fehlermeldung nie unbemerkt unter
|
||
- `<dateiname>` kann die Endung weglassen (Standard: `.png`); eventuelle Pfadanteile in der Firmware-Angabe werden ignoriert – die Datei landet immer direkt im konfigurierten Ordner (kein Path-Traversal möglich)
|
||
- Wird derselbe Dateiname mehrfach gesendet (z.B. immer `dump.png`), wird nichts überschrieben – UARTScope hängt automatisch `_1`, `_2`, … an
|
||
- Die Zeile erscheint zusätzlich ganz normal im Tag-Monitor unter `[SCREENSHOT]` – inklusive „Verlauf"-Tab, der eine timestamped Liste aller Trigger-Ereignisse **und** deren Ergebnis zeigt: zuerst der angeforderte Dateiname, direkt danach das Resultat („Screenshot saved: /pfad/..." oder eine Fehlermeldung) – beides chronologisch im selben Panel
|
||
- Funktioniert unabhängig vom Freeze-Status der Vorschau (wie der manuelle Screenshot-Button auch)
|
||
|
||
**Falls kein Bild erscheint:** die häufigsten zwei Ursachen sind (1) der Screenshot-Ordner wurde noch nicht gesetzt, oder (2) die V4L2-Vorschau läuft nicht (▶ Start im Video-Widget noch nicht geklickt, es gibt also noch keinen Frame zum Speichern). In beiden Fällen steht die genaue Ursache als `[UARTSCOPE] ...`-Zeile im Raw-View.
|
||
|
||
---
|
||
|
||
## Berechtigungen
|
||
|
||
```bash
|
||
# UART-Port
|
||
sudo usermod -aG dialout $USER
|
||
|
||
# HDMI-Grabber / V4L2
|
||
sudo usermod -aG video $USER
|
||
|
||
# Einmal ausloggen / neu einloggen
|
||
```
|
||
|
||
Grabber testen:
|
||
```bash
|
||
v4l2-ctl --list-devices # alle /dev/video* Geräte
|
||
v4l2-ctl -d /dev/video0 --list-formats-ext # unterstützte Formate & Auflösungen
|
||
```
|
||
|
||
---
|
||
|
||
## UART-Ausgabe formatieren
|
||
|
||
Alles Folgende gilt unabhängig davon, ob die Verbindung über einen seriellen Port oder über TCP läuft (siehe Abschnitt „Verbindung: Seriell oder Netzwerk (TCP)" weiter oben) – UARTScope interpretiert den empfangenen Text in beiden Fällen identisch.
|
||
|
||
### Raw-View (immer aktiv)
|
||
|
||
Jede Zeile erscheint im Raw-View mit Timestamp. Keine besondere Formatierung nötig.
|
||
|
||
**Screen leeren** – von der Firmware aus Raw-View, Tabelle, Tag-Monitor und Video-Vorschau gleichzeitig leeren:
|
||
```c
|
||
uart_printf("\033[2J\033[H");
|
||
```
|
||
|
||
### Tag-Monitor
|
||
|
||
Zeilen mit `[TAGNAME]` werden im Tag-Monitor-Panel angezeigt **und** im Raw-View hervorgehoben (cyan), sofern der Tag nicht über den Tag-Filter ausgeblendet wurde.
|
||
|
||
**Format:** `[TAGNAME] key1=value1 key2=value2 ...`
|
||
|
||
- Tag-Name: Buchstaben, Ziffern, Underscore **und Bindestrich** – z.B. `WDG`, `VIDEO`, `KICKSTART`, `I2C-BUS`
|
||
- Key=Value-Paare: Leerzeichen-getrennt, Werte ohne Leerzeichen
|
||
- Ohne Key=Value-Paare wird der rohe String angezeigt
|
||
|
||
Jedes Tag-Panel hat zwei Tabs:
|
||
- **Aktuell** – der letzte empfangene Stand, aktualisiert sich in-place (wie bisher)
|
||
- **Verlauf** – jeder je empfangene Wert dieses Tags, chronologisch mit Timestamp, mit eigenem „Verlauf leeren"-Button (löscht nur die Historie, das Panel bleibt bestehen)
|
||
|
||
Der Copy-Button kopiert je nach aktivem Tab entweder den aktuellen Stand oder den kompletten Verlauf.
|
||
|
||
**Listen-Werte:** Ein Wert mit `;`-getrennten Einträgen wird als mehrzeilige Liste unter dem Key dargestellt:
|
||
|
||
```c
|
||
uart_printf("[KICKSTART] Devs=trackdisk.device;input.device\n");
|
||
```
|
||
|
||
Im Tag-Monitor erscheint das als:
|
||
|
||
```
|
||
Devs trackdisk.device
|
||
input.device
|
||
```
|
||
|
||
Jeder weitere Eintrag bekommt seine eigene Tabellenzeile, der Key wird nur einmal angezeigt.
|
||
|
||
**Beispiele:**
|
||
```c
|
||
uart_printf("[WDG] uptime=%lu free_heap=%lu temp=%d\n",
|
||
HAL_GetTick(), xPortGetFreeHeapSize(), core_temp);
|
||
|
||
uart_printf("[KICKSTART] Libs=graphics.library;intuition.library;dos.library\n");
|
||
|
||
uart_printf("[VIDEO] line=%d hblank=%d vblank=%d copper=%d\n",
|
||
scanline, hblank_ticks, vblank_ticks, copper_dma);
|
||
```
|
||
|
||
Jeder einzigartige Tag bekommt automatisch ein eigenes Panel. Panels aktualisieren sich in-place – kein Scrollen nötig. Listen-Längen können sich von Update zu Update ändern, die Tabelle passt sich automatisch an.
|
||
|
||
### Tabellenansicht
|
||
|
||
Optionale Header-Zeile mit `#`, dann CSV-Datenzeilen:
|
||
|
||
```
|
||
#time_ms,temperature,voltage,current
|
||
1000,23.5,3.30,0.42
|
||
2000,23.7,3.31,0.41
|
||
```
|
||
|
||
Delimiter per Dropdown umschaltbar: `,` `;` `\t` `|` `Space`
|
||
|
||
### Suche im Raw-View
|
||
|
||
Suchbegriff eingeben – der erste Treffer wird automatisch markiert. Weitere Treffer:
|
||
|
||
- **▼** / `Enter` / `F3` → nächster Treffer
|
||
- **▲** / `Shift+F3` → vorheriger Treffer
|
||
- Ist kein weiterer Treffer in Suchrichtung vorhanden, springt die Suche automatisch an den Anfang (bzw. bei Rückwärtssuche ans Ende) und macht dort weiter (Wrap-Around)
|
||
|
||
---
|
||
|
||
## Tag-Filter
|
||
|
||
Über „Tag filter…" in der Toolbar lassen sich Tags aus dem Raw-View ausblenden, sodass sie nur noch im Tag-Monitor erscheinen. Ein Tag pro Zeile, ohne Klammern (z.B. `WDG`). Groß-/Kleinschreibung spielt keine Rolle. Der Filter wird sofort beim Schließen des Dialogs gespeichert und beim nächsten Programmstart automatisch wiederhergestellt.
|
||
|
||
---
|
||
|
||
## Einstellungen
|
||
|
||
Beim Beenden werden folgende Einstellungen automatisch gespeichert und beim nächsten Start wiederhergestellt:
|
||
|
||
- Fenstergröße und -position
|
||
- Splitter-Positionen (Haupt-Splitter und Tag/Video-Splitter)
|
||
- Auto-Reconnect ein/aus und Intervall
|
||
- Tag-Filter (ausgeblendete Tags)
|
||
- Screenshot-Ordner für den `[SCREENSHOT]`-Steuertag
|
||
|
||
Gespeichert unter `~/.config/ChicaDev/UARTScope.conf` (via `QSettings`).
|
||
|
||
---
|
||
|
||
## Projektstruktur
|
||
|
||
```
|
||
uartscope/
|
||
├── CMakeLists.txt
|
||
├── README.md
|
||
├── resources.qrc
|
||
├── UartscopeLogo.png
|
||
├── uartscope.desktop.in
|
||
├── include/
|
||
│ ├── mainwindow.h ← Hauptfenster, koordiniert alle Komponenten, Screenshot-Ordner-Einstellung
|
||
│ ├── serialworker.h ← Empfang im eigenen QThread (seriell ODER TCP), Auto-Reconnect, ANSI-Erkennung, [SCREENSHOT]-Steuertag
|
||
│ ├── rawview.h ← Unbegrenzter Log mit Timestamps, Suche (Weiter/Zurück, Wrap-Around), Copy
|
||
│ ├── tableview.h ← CSV-Parser → QTableWidget
|
||
│ ├── tagwidget.h ← Container für Tag-Panels
|
||
│ ├── tagpanel.h ← Ein Panel pro [TAG]: Aktuell-Tab + Verlauf-Tab, Listen-Support, Copy
|
||
│ ├── connectdialog.h ← Seriell- und Netzwerk(TCP)-Konfiguration, PTY-Erkennung, Log-Datei
|
||
│ ├── v4l2worker.h ← V4L2-Capture in std::thread, MJPEG/YUYV/NV12
|
||
│ └── videowidget.h ← Live-Vorschau, Freeze, Screenshot (manuell + automatisch via Tag), MP4-Aufzeichnung (ffmpeg)
|
||
└── src/
|
||
├── main.cpp
|
||
├── mainwindow.cpp
|
||
├── serialworker.cpp
|
||
├── rawview.cpp
|
||
├── tableview.cpp
|
||
├── tagwidget.cpp
|
||
├── tagpanel.cpp
|
||
├── connectdialog.cpp
|
||
├── v4l2worker.cpp
|
||
└── videowidget.cpp
|
||
```
|
||
|
||
---
|
||
|
||
## Erweiterungsideen
|
||
|
||
- **Plot-Widget**: numerische Tag-Werte live als Graph darstellen (Qt Charts)
|
||
- **UART senden**: TX-Eingabezeile für bidirektionale Kommunikation
|
||
- **Hex-View**: rohe Bytes als Hex-Dump anzeigen
|
||
- **Session-Replay**: gespeicherte Log-Dateien abspielen
|
||
- **Regex-Filter**: Zeilen im Raw-View per regulärem Ausdruck ein-/ausblenden
|
||
|
||
---
|
||
|
||
## Changelog
|
||
|
||
**1.2.0**
|
||
- Automatischer Screenshot-Trigger via `[SCREENSHOT] dateiname`-Steuertag – speichert den Video-Frame exakt im Moment des Empfangs (z.B. für Memory-Dumps)
|
||
- Neue Toolbar-Option „Screenshot folder…" zur Konfiguration des Zielordners
|
||
- Format-Referenz-Dialog um Dokumentation des neuen Steuertags ergänzt
|
||
- Erfolg/Fehler eines Screenshot-Triggers wird zusätzlich zur Statusleiste dauerhaft als Zeile im Raw-View **und** direkt im `[SCREENSHOT]`-Tag-Panel selbst (Aktuell + Verlauf) protokolliert
|
||
|
||
**1.1.0**
|
||
- Netzwerk-Input (TCP) als Alternative zum seriellen Port, inkl. Auto-Reconnect
|
||
- PTY-Erkennung (`/dev/pts/`) im Seriell-Tab, z.B. für QEMU
|
||
- Video-Aufzeichnung als MP4 (via `ffmpeg`)
|
||
- Tag-Panels: zweiter „Verlauf"-Tab mit vollständiger, timestamped Historie
|
||
- Suche im Raw-View: Weiter/Zurück-Navigation mit Wrap-Around
|
||
- Tag-Namen mit Bindestrich werden jetzt korrekt erkannt und gefiltert
|
||
- Bugfix: letzte Zeile ging bei einem ausbleibenden Folge-Byte-Strom manchmal verloren (Idle-Flush-Timer)
|
||
|
||
**1.0.0**
|
||
- Erste Veröffentlichung
|