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 (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
# 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
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):
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:
# 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:
ffmpegmuss installiert und imPATHsein (siehe 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]:
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:
- In der Toolbar auf „Screenshot folder…" klicken und den Zielordner wählen
- 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
# UART-Port
sudo usermod -aG dialout $USER
# HDMI-Grabber / V4L2
sudo usermod -aG video $USER
# Einmal ausloggen / neu einloggen
Grabber testen:
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:
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:
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:
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