Automatisierte Screenshot Aufnahme per [SCREENSHOT] datei implementiert

This commit is contained in:
2026-08-26 01:22:13 +02:00
parent 36923e1646
commit ef335f2d9e
16 changed files with 365 additions and 52 deletions

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(UARTScope VERSION 1.1.0 LANGUAGES CXX) project(UARTScope VERSION 1.2.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)

144
README.md
View File

@@ -8,21 +8,25 @@ Ein moderner UART-Monitor für Linux mit Qt6-Oberfläche. Gebaut als vollwertige
| Feature | Beschreibung | | Feature | Beschreibung |
|---|---| |---|---|
| **Unbegrenzter Verlauf** | Kein Zeilenlimit keine Daten gehen verloren, egal wie viel der Pi sendet | | **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 | | **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 | | **Auto-Scroll** | Standardmäßig aktiv springt automatisch ans Ende neuer Ausgaben |
| **H + V Scrolling** | Kein Zeilenumbruch, voller horizontaler Scrollbalken | | **H + V Scrolling** | Kein Zeilenumbruch, voller horizontaler Scrollbalken |
| **Live-Logging** | Alle empfangenen Zeilen werden mit Timestamp in eine Datei geschrieben | | **Live-Logging** | Alle empfangenen Zeilen werden mit Timestamp in eine Datei geschrieben |
| **Tag-Monitor** | Zeilen mit `[TAG]` werden in eigenen Panels angezeigt und aktualisiert | | **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 | | **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 | | **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 | | **Tabellenansicht** | CSV-formatierte UART-Zeilen werden in einer Tabelle dargestellt |
| **Suche** | Inkrementelle Volltextsuche im Raw-View | | **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) | | **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 | | **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 haben einen „📋 Copy"-Button | | **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 | | **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 | | **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 | | **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 | | **Fensterlayout** | Fenstergröße, Position, Splitter-Positionen und Tag-Filter werden beim Beenden gespeichert |
@@ -32,16 +36,18 @@ Ein moderner UART-Monitor für Linux mit Qt6-Oberfläche. Gebaut als vollwertige
```bash ```bash
# Arch (empfohlen) # Arch (empfohlen)
sudo pacman -S cmake qt6-base qt6-serialport sudo pacman -S cmake qt6-base qt6-serialport ffmpeg
# Ubuntu / Debian # Ubuntu / Debian
sudo apt install cmake qt6-base-dev qt6-serialport-dev libqt6serialport6-dev sudo apt install cmake qt6-base-dev qt6-serialport-dev libqt6serialport6-dev ffmpeg
# Fedora # Fedora
sudo dnf install cmake qt6-qtbase-devel qt6-qtserialport-devel 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. 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.
--- ---
@@ -62,6 +68,69 @@ 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 ## Berechtigungen
```bash ```bash
@@ -84,9 +153,11 @@ v4l2-ctl -d /dev/video0 --list-formats-ext # unterstützte Formate & Auflösung
## UART-Ausgabe formatieren ## 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) ### Raw-View (immer aktiv)
Jede UART-Zeile erscheint im Raw-View mit Timestamp. Keine besondere Formatierung nötig. 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: **Screen leeren** von der Firmware aus Raw-View, Tabelle, Tag-Monitor und Video-Vorschau gleichzeitig leeren:
```c ```c
@@ -99,10 +170,16 @@ Zeilen mit `[TAGNAME]` werden im Tag-Monitor-Panel angezeigt **und** im Raw-View
**Format:** `[TAGNAME] key1=value1 key2=value2 ...` **Format:** `[TAGNAME] key1=value1 key2=value2 ...`
- Tag-Name: Buchstaben, Ziffern, Underscore z.B. `WDG`, `VIDEO`, `KICKSTART` - Tag-Name: Buchstaben, Ziffern, Underscore **und Bindestrich** z.B. `WDG`, `VIDEO`, `KICKSTART`, `I2C-BUS`
- Key=Value-Paare: Leerzeichen-getrennt, Werte ohne Leerzeichen - Key=Value-Paare: Leerzeichen-getrennt, Werte ohne Leerzeichen
- Ohne Key=Value-Paare wird der rohe String angezeigt - 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: **Listen-Werte:** Ein Wert mit `;`-getrennten Einträgen wird als mehrzeilige Liste unter dem Key dargestellt:
```c ```c
@@ -143,6 +220,14 @@ Optionale Header-Zeile mit `#`, dann CSV-Datenzeilen:
Delimiter per Dropdown umschaltbar: `,` `;` `\t` `|` `Space` 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 ## Tag-Filter
@@ -159,6 +244,7 @@ Beim Beenden werden folgende Einstellungen automatisch gespeichert und beim näc
- Splitter-Positionen (Haupt-Splitter und Tag/Video-Splitter) - Splitter-Positionen (Haupt-Splitter und Tag/Video-Splitter)
- Auto-Reconnect ein/aus und Intervall - Auto-Reconnect ein/aus und Intervall
- Tag-Filter (ausgeblendete Tags) - Tag-Filter (ausgeblendete Tags)
- Screenshot-Ordner für den `[SCREENSHOT]`-Steuertag
Gespeichert unter `~/.config/ChicaDev/UARTScope.conf` (via `QSettings`). Gespeichert unter `~/.config/ChicaDev/UARTScope.conf` (via `QSettings`).
@@ -174,15 +260,15 @@ uartscope/
├── UartscopeLogo.png ├── UartscopeLogo.png
├── uartscope.desktop.in ├── uartscope.desktop.in
├── include/ ├── include/
│ ├── mainwindow.h ← Hauptfenster, koordiniert alle Komponenten │ ├── mainwindow.h ← Hauptfenster, koordiniert alle Komponenten, Screenshot-Ordner-Einstellung
│ ├── serialworker.h ← UART-Empfang im eigenen QThread, Auto-Reconnect, ANSI-Erkennung │ ├── serialworker.h ← Empfang im eigenen QThread (seriell ODER TCP), Auto-Reconnect, ANSI-Erkennung, [SCREENSHOT]-Steuertag
│ ├── rawview.h ← Unbegrenzter Log mit Timestamps, Suche, Copy │ ├── rawview.h ← Unbegrenzter Log mit Timestamps, Suche (Weiter/Zurück, Wrap-Around), Copy
│ ├── tableview.h ← CSV-Parser → QTableWidget │ ├── tableview.h ← CSV-Parser → QTableWidget
│ ├── tagwidget.h ← Container für Tag-Panels │ ├── tagwidget.h ← Container für Tag-Panels
│ ├── tagpanel.h ← Ein Panel pro [TAG], Key=Value-Tabelle mit Listen-Support, Copy │ ├── tagpanel.h ← Ein Panel pro [TAG]: Aktuell-Tab + Verlauf-Tab, Listen-Support, Copy
│ ├── connectdialog.h ← Port-Konfiguration (Port, Baud, Log-Datei) │ ├── connectdialog.h ← Seriell- und Netzwerk(TCP)-Konfiguration, PTY-Erkennung, Log-Datei
│ ├── v4l2worker.h ← V4L2-Capture in std::thread, MJPEG/YUYV/NV12 │ ├── v4l2worker.h ← V4L2-Capture in std::thread, MJPEG/YUYV/NV12
│ └── videowidget.h ← Live-Vorschau, Freeze, Screenshot │ └── videowidget.h ← Live-Vorschau, Freeze, Screenshot (manuell + automatisch via Tag), MP4-Aufzeichnung (ffmpeg)
└── src/ └── src/
├── main.cpp ├── main.cpp
├── mainwindow.cpp ├── mainwindow.cpp
@@ -205,3 +291,25 @@ uartscope/
- **Hex-View**: rohe Bytes als Hex-Dump anzeigen - **Hex-View**: rohe Bytes als Hex-Dump anzeigen
- **Session-Replay**: gespeicherte Log-Dateien abspielen - **Session-Replay**: gespeicherte Log-Dateien abspielen
- **Regex-Filter**: Zeilen im Raw-View per regulärem Ausdruck ein-/ausblenden - **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

View File

@@ -41,8 +41,10 @@ private slots:
void onError(const QString &message); void onError(const QString &message);
void onNewLine(const QString &line); void onNewLine(const QString &line);
void onTagDetected(const QString &tag, const QString &value); void onTagDetected(const QString &tag, const QString &value);
void onScreenshotRequested(const QString &filename);
void showFormatReference(); void showFormatReference();
void configureTagFilter(); void configureTagFilter();
void configureScreenshotDir();
void showAbout(); void showAbout();
private: private:
@@ -53,6 +55,7 @@ private:
void doShutdown(); void doShutdown();
void saveSettings(); void saveSettings();
void restoreSettings(); void restoreSettings();
void updateScreenshotDirTooltip();
QThread *m_thread = nullptr; QThread *m_thread = nullptr;
SerialWorker *m_worker = nullptr; SerialWorker *m_worker = nullptr;
@@ -71,6 +74,7 @@ private:
QAction *m_connectAction = nullptr; QAction *m_connectAction = nullptr;
QAction *m_disconnectAction = nullptr; QAction *m_disconnectAction = nullptr;
QAction *m_screenshotDirAction = nullptr;
// Splitters (saved/restored via QSettings) // Splitters (saved/restored via QSettings)
QSplitter *m_mainSplitter = nullptr; QSplitter *m_mainSplitter = nullptr;
@@ -78,5 +82,6 @@ private:
SerialConfig m_lastConfig; SerialConfig m_lastConfig;
QSet<QString> m_suppressedTags; // tags hidden from Raw view QSet<QString> m_suppressedTags; // tags hidden from Raw view
QString m_screenshotDir; // target folder for [SCREENSHOT] tag captures
bool m_shutdownDone = false; bool m_shutdownDone = false;
}; };

View File

@@ -48,6 +48,11 @@ public slots:
signals: signals:
void newLine(const QString &line); void newLine(const QString &line);
void tagDetected(const QString &tag, const QString &value); void tagDetected(const QString &tag, const QString &value);
// Fired specifically for a [SCREENSHOT] control tag (in addition to the
// normal tagDetected() above, so it still shows up in the Tag Monitor
// history too). `filename` is whatever followed the tag, verbatim -
// the receiver is responsible for sanitizing/defaulting it.
void screenshotRequested(const QString &filename);
void clearScreen(); void clearScreen();
void portOpened(); void portOpened();
void portClosed(); void portClosed();

View File

@@ -27,10 +27,27 @@ public:
public: public:
void shutdown(); // safe to call multiple times, called from MainWindow::closeEvent void shutdown(); // safe to call multiple times, called from MainWindow::closeEvent
// Folder that saveAutoScreenshot() writes into. Empty = not configured
// (saveAutoScreenshot() will report an error instead of silently
// dropping the request).
void setAutoScreenshotDir(const QString &dir) { m_autoScreenshotDir = dir; }
public slots: public slots:
void onNewFrame(const QImage &frame); void onNewFrame(const QImage &frame);
void clearFrame(); // blanks the preview (used on ANSI clear-screen) void clearFrame(); // blanks the preview (used on ANSI clear-screen)
// Saves whichever frame is currently in m_frame under `filename` inside
// m_autoScreenshotDir. Triggered by a [SCREENSHOT] control tag from the
// firmware - the point is to grab the frame that's already in flight
// the instant the tag arrives (no dialog, no user reaction time), e.g.
// to reliably catch a video frame showing a memory dump.
void saveAutoScreenshot(const QString &filename);
signals:
// Emitted after every saveAutoScreenshot() attempt so the caller (the
// main window) can surface a transient status message. Never blocks/
// pops a dialog itself, since this can fire in rapid succession from
// firmware-driven triggers.
void autoScreenshotResult(bool success, const QString &message);
private slots: private slots:
void onStartStop(); void onStartStop();
@@ -76,4 +93,8 @@ private:
QProcess *m_recordProcess = nullptr; QProcess *m_recordProcess = nullptr;
bool m_recording = false; bool m_recording = false;
QSize m_recordSize; QSize m_recordSize;
// Folder for saveAutoScreenshot() ([SCREENSHOT] tag). Set via
// setAutoScreenshotDir(), persisted/restored by MainWindow.
QString m_autoScreenshotDir;
}; };

View File

@@ -7,7 +7,7 @@ int main(int argc, char *argv[])
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
app.setApplicationName("UARTScope"); app.setApplicationName("UARTScope");
app.setApplicationVersion("1.1.0"); app.setApplicationVersion("1.2.0");
app.setOrganizationName("ChicaDev"); app.setOrganizationName("ChicaDev");
app.setStyle(QStyleFactory::create("Fusion")); app.setStyle(QStyleFactory::create("Fusion"));

View File

@@ -3,6 +3,7 @@
#include <QClipboard> #include <QClipboard>
#include <QDialog> #include <QDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QFileDialog>
#include <QGridLayout> #include <QGridLayout>
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
@@ -35,6 +36,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_worker, &SerialWorker::newLine, this, &MainWindow::onNewLine); connect(m_worker, &SerialWorker::newLine, this, &MainWindow::onNewLine);
connect(m_worker, &SerialWorker::tagDetected, this, &MainWindow::onTagDetected); connect(m_worker, &SerialWorker::tagDetected, this, &MainWindow::onTagDetected);
connect(m_worker, &SerialWorker::screenshotRequested, this, &MainWindow::onScreenshotRequested);
connect(m_worker, &SerialWorker::clearScreen, this, &MainWindow::onClearScreen); connect(m_worker, &SerialWorker::clearScreen, this, &MainWindow::onClearScreen);
connect(m_worker, &SerialWorker::portOpened, this, &MainWindow::onPortOpened); connect(m_worker, &SerialWorker::portOpened, this, &MainWindow::onPortOpened);
connect(m_worker, &SerialWorker::portClosed, this, &MainWindow::onPortClosed); connect(m_worker, &SerialWorker::portClosed, this, &MainWindow::onPortClosed);
@@ -100,6 +102,30 @@ void MainWindow::setupUi()
m_videoWidget = new VideoWidget(rightSplitter); m_videoWidget = new VideoWidget(rightSplitter);
m_videoWidget->setMinimumHeight(160); m_videoWidget->setMinimumHeight(160);
connect(m_videoWidget, &VideoWidget::autoScreenshotResult, this,
[this](bool ok, const QString &message) {
statusBar()->showMessage(message, ok ? 4000 : 6000);
// The status bar message disappears after a few seconds and is
// easy to miss (especially right after triggering a capture
// and looking at the video preview, not the status bar). Also
// log it as a normal Raw View line - permanent, scrollable,
// and sitting right next to the [SCREENSHOT] tag line itself
// for context - so a failure (no folder configured, no frame
// yet, etc.) is never silently lost.
m_rawView->appendLine(
QStringLiteral("[UARTSCOPE] %1").arg(message), m_suppressedTags);
// Also surface the outcome directly in the Tag Monitor's
// [SCREENSHOT] panel - both its "Aktuell" tab (so the latest
// status is visible at a glance) and its "Verlauf" history
// (so every past trigger's outcome, success or failure, stays
// reviewable with a timestamp). tagDetected() for the request
// itself is emitted before screenshotRequested() in
// SerialWorker, so this result entry always lands after the
// corresponding request entry.
m_tagWidget->handleTag(QStringLiteral("SCREENSHOT"), message);
});
rightSplitter->addWidget(m_tagWidget); rightSplitter->addWidget(m_tagWidget);
rightSplitter->addWidget(m_videoWidget); rightSplitter->addWidget(m_videoWidget);
rightSplitter->setStretchFactor(0, 1); rightSplitter->setStretchFactor(0, 1);
@@ -168,6 +194,12 @@ void MainWindow::setupToolBar()
tb->addSeparator(); tb->addSeparator();
m_screenshotDirAction = tb->addAction(tr("Screenshot folder…"));
connect(m_screenshotDirAction, &QAction::triggered, this, &MainWindow::configureScreenshotDir);
updateScreenshotDirTooltip();
tb->addSeparator();
auto *helpAction = tb->addAction(tr("Format reference")); auto *helpAction = tb->addAction(tr("Format reference"));
helpAction->setToolTip(tr("Show UARTScope output format guide (copy for AI)")); helpAction->setToolTip(tr("Show UARTScope output format guide (copy for AI)"));
connect(helpAction, &QAction::triggered, this, &MainWindow::showFormatReference); connect(helpAction, &QAction::triggered, this, &MainWindow::showFormatReference);
@@ -309,6 +341,12 @@ void MainWindow::onTagDetected(const QString &tag, const QString &value)
m_tagWidget->handleTag(tag, value); m_tagWidget->handleTag(tag, value);
} }
void MainWindow::onScreenshotRequested(const QString &filename)
{
if (m_videoWidget)
m_videoWidget->saveAutoScreenshot(filename);
}
void MainWindow::clearAllViews() void MainWindow::clearAllViews()
{ {
m_rawView->clear(); m_rawView->clear();
@@ -403,7 +441,33 @@ Every received line is appended with a hh:mm:ss.zzz timestamp.
No special firmware changes needed. No special firmware changes needed.
5. COMPLETE EXAMPLE (Chica / Amiga hardware emulation) 5. AUTOMATIC SCREENSHOT TRIGGER (V4L2 / HDMI grabber tab)
[SCREENSHOT] <filename> is a control tag: the instant this line is
received, UARTScope saves whatever video frame is currently in the V4L2
preview under <filename> - no dialog, no user reaction time needed. This
is meant for catching a fast-changing signal (e.g. a memory dump flashed
on an emulated display for only a moment) at the exact instant the
firmware announces it, rather than relying on manually clicking the
screenshot button and missing the window.
uart_printf("[SCREENSHOT] memdump_%lu.png\n", HAL_GetTick());
Notes:
Configure the target folder once via the toolbar
("Screenshot folder…") - if unset, the trigger is reported but no
file is written.
<filename> may omit the extension (defaults to .png); any directory
components sent by the firmware are stripped for safety - the file
always lands directly in the configured folder.
Reusing the same filename on every trigger is fine: UARTScope
automatically appends _1, _2, instead of overwriting.
The line is also still visible in the Tag Monitor's [SCREENSHOT]
panel (with its own "Verlauf" history tab), so you get a timestamped
log of every capture in addition to the saved image files.
6. COMPLETE EXAMPLE (Chica / Amiga hardware emulation)
void uart_status_update(void) { void uart_status_update(void) {
uart_printf("[WDG] uptime=%lu free=%lu load=%d temp=%d\n", uart_printf("[WDG] uptime=%lu free=%lu load=%d temp=%d\n",
@@ -421,6 +485,12 @@ void uart_status_update(void) {
HAL_GetTick(), vcc_mv / 1000.0f, cpu_load_percent, core_temp_c); HAL_GetTick(), vcc_mv / 1000.0f, cpu_load_percent, core_temp_c);
} }
// Grab the exact video frame when a memory dump is about to be shown:
void trigger_memdump_capture(void) {
uart_printf("[SCREENSHOT] memdump_%lu.png\n", HAL_GetTick());
show_memory_dump_on_screen();
}
// Clear screen from firmware when you want a fresh start: // Clear screen from firmware when you want a fresh start:
// uart_printf("\033[2J\033[H"); // uart_printf("\033[2J\033[H");
)UARTSCOPE"; )UARTSCOPE";
@@ -511,6 +581,35 @@ void MainWindow::configureTagFilter()
dlg->deleteLater(); dlg->deleteLater();
} }
// ── Auto-screenshot folder ──────────────────────────────────────────────────
void MainWindow::configureScreenshotDir()
{
const QString dir = QFileDialog::getExistingDirectory(
this, tr("Auto-screenshot folder for [SCREENSHOT] tag"), m_screenshotDir);
if (dir.isEmpty())
return;
m_screenshotDir = dir;
if (m_videoWidget)
m_videoWidget->setAutoScreenshotDir(m_screenshotDir);
updateScreenshotDirTooltip();
// Persist immediately, consistent with the tag filter dialog above.
saveSettings();
}
void MainWindow::updateScreenshotDirTooltip()
{
if (!m_screenshotDirAction)
return;
m_screenshotDirAction->setToolTip(
m_screenshotDir.isEmpty()
? tr("No folder set yet - click to choose where [SCREENSHOT]-tag "
"captures are saved")
: tr("[SCREENSHOT] tag captures are saved to: %1").arg(m_screenshotDir));
}
// ── About dialog ────────────────────────────────────────────────────────── // ── About dialog ──────────────────────────────────────────────────────────
void MainWindow::showAbout() void MainWindow::showAbout()
@@ -572,7 +671,7 @@ void MainWindow::showAbout()
grid->addWidget(v, row, 1); grid->addWidget(v, row, 1);
}; };
addRow(0, tr("Version"), "1.1.0"); addRow(0, tr("Version"), "1.2.0");
addRow(1, tr("Entwickler"), "Dany Thinnes"); addRow(1, tr("Entwickler"), "Dany Thinnes");
addRow(2, tr("Projekt"), "Projekt Hirnfrei"); addRow(2, tr("Projekt"), "Projekt Hirnfrei");
addRow(3, tr("Framework"), QString("Qt %1").arg(QT_VERSION_STR)); addRow(3, tr("Framework"), QString("Qt %1").arg(QT_VERSION_STR));
@@ -619,6 +718,8 @@ void MainWindow::saveSettings()
tags.sort(); tags.sort();
s.setValue("tagfilter/suppressed", tags); s.setValue("tagfilter/suppressed", tags);
s.setValue("screenshot/autoDir", m_screenshotDir);
s.sync(); // flush to disk immediately (important since we also call s.sync(); // flush to disk immediately (important since we also call
// this mid-session from configureTagFilter()) // this mid-session from configureTagFilter())
} }
@@ -647,4 +748,9 @@ void MainWindow::restoreSettings()
for (const QString &t : tags) for (const QString &t : tags)
if (!t.isEmpty()) if (!t.isEmpty())
m_suppressedTags.insert(t); m_suppressedTags.insert(t);
m_screenshotDir = s.value("screenshot/autoDir").toString();
if (m_videoWidget)
m_videoWidget->setAutoScreenshotDir(m_screenshotDir);
updateScreenshotDirTooltip();
} }

View File

@@ -392,7 +392,24 @@ void SerialWorker::processLine(const QString &line)
if (match.hasMatch()) { if (match.hasMatch()) {
const QString tag = match.captured(1).toUpper(); const QString tag = match.captured(1).toUpper();
const QString value = match.captured(2).trimmed(); const QString value = match.captured(2).trimmed();
// Emit tagDetected() first so the request itself (the filename the
// firmware sent) lands in the Tag Monitor's [SCREENSHOT] history
// before the save outcome does. Both signals are queued to the GUI
// thread; queued events are processed in the order they were
// posted, so emission order here directly determines the order
// the two entries appear in - swap it and the result would show
// up "before" the request that caused it.
emit tagDetected(tag, value); emit tagDetected(tag, value);
// [SCREENSHOT] <filename> is a control tag: fire immediately, as
// close in time as possible to this line arriving, so the caller
// can grab whichever V4L2 frame is currently in flight - e.g. to
// capture the exact video frame showing a memory dump the moment
// the firmware announces it, rather than relying on a human's
// reaction time with the manual screenshot button.
if (tag == QLatin1String("SCREENSHOT"))
emit screenshotRequested(value);
} }
emit newLine(line); emit newLine(line);

View File

@@ -2,6 +2,7 @@
#include <QPainter> #include <QPainter>
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo>
#include <QDir> #include <QDir>
#include <QDateTime> #include <QDateTime>
#include <QStandardPaths> #include <QStandardPaths>
@@ -164,6 +165,55 @@ void VideoWidget::onScreenshot()
m_frame.save(path); m_frame.save(path);
} }
void VideoWidget::saveAutoScreenshot(const QString &filename)
{
if (m_frame.isNull()) {
emit autoScreenshotResult(false,
tr("[SCREENSHOT] tag received, but no video frame is available yet."));
return;
}
if (m_autoScreenshotDir.isEmpty()) {
emit autoScreenshotResult(false,
tr("[SCREENSHOT] tag received, but no auto-screenshot folder is "
"configured (toolbar → \"Screenshot folder…\")."));
return;
}
// Only take the bare filename from what the firmware sent - this
// strips any directory components (incl. attempts at '../' path
// traversal), so the firmware can never dictate where on disk we
// write. Fall back to a timestamp if it sent nothing usable, and
// default to .png if it didn't specify an extension.
QString name = QFileInfo(filename.trimmed()).fileName();
if (name.isEmpty()) {
name = QStringLiteral("screenshot_%1.png")
.arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz"));
} else if (QFileInfo(name).suffix().isEmpty()) {
name += QStringLiteral(".png");
}
const QDir dir(m_autoScreenshotDir);
QString path = dir.filePath(name);
// Don't silently overwrite an earlier capture if the firmware reuses
// the same filename on every trigger (e.g. a generic "dump.png") -
// append a numeric suffix instead so nothing gets lost.
if (QFileInfo::exists(path)) {
const QString base = QFileInfo(name).completeBaseName();
const QString suffix = QFileInfo(name).suffix();
int n = 1;
do {
path = dir.filePath(QStringLiteral("%1_%2.%3").arg(base).arg(n).arg(suffix));
++n;
} while (QFileInfo::exists(path));
}
if (m_frame.save(path))
emit autoScreenshotResult(true, tr("Screenshot saved: %1").arg(path));
else
emit autoScreenshotResult(false, tr("Failed to save screenshot to %1").arg(path));
}
void VideoWidget::onNewFrame(const QImage &frame) void VideoWidget::onNewFrame(const QImage &frame)
{ {
// Feed the recorder regardless of freeze state, so pausing the preview // Feed the recorder regardless of freeze state, so pausing the preview

View File

@@ -1,6 +1,6 @@
# Maintainer: diabolus <your@email.com> # Maintainer: diabolus <your@email.com>
pkgname=uartscope pkgname=uartscope
pkgver=1.0.0.r6.ga942f83 pkgver=1.1.0.r0.g36923e1
pkgrel=1 pkgrel=1
pkgdesc="Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect" pkgdesc="Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')

View File

@@ -1,11 +1,11 @@
format = 2 format = 2
pkgname = uartscope pkgname = uartscope
pkgbase = uartscope pkgbase = uartscope
pkgver = 1.0.0.r6.ga942f83-1 pkgver = 1.1.0.r0.g36923e1-1
pkgarch = x86_64 pkgarch = x86_64
pkgbuild_sha256sum = 838e01d91a8df5c30e4be619acfc3fe42d6b58ec89f227d9df94874ebfbed8c0 pkgbuild_sha256sum = 69ca8218ddee1c9dbe0ee82d052da7cad987dcc52773078209494a1ff8b3c487
packager = Unknown Packager packager = Unknown Packager
builddate = 1787005573 builddate = 1787031398
builddir = /home/diabolus/Arbeit/Projekt-Hirnfrei/uartscope/uartscope-git builddir = /home/diabolus/Arbeit/Projekt-Hirnfrei/uartscope/uartscope-git
startdir = /home/diabolus/Arbeit/Projekt-Hirnfrei/uartscope/uartscope-git startdir = /home/diabolus/Arbeit/Projekt-Hirnfrei/uartscope/uartscope-git
buildtool = makepkg buildtool = makepkg
@@ -242,7 +242,7 @@ installed = compiler-rt20-20.1.8-1-x86_64
installed = compiler-rt21-21.1.8-1-x86_64 installed = compiler-rt21-21.1.8-1-x86_64
installed = composefs-1.0.8-1-x86_64 installed = composefs-1.0.8-1-x86_64
installed = composer-2.10.2-1-any installed = composer-2.10.2-1-any
installed = confuse-3.3-5-x86_64 installed = confuse-3.4-1-x86_64
installed = containerd-2.3.4-1-x86_64 installed = containerd-2.3.4-1-x86_64
installed = convertlit-1.8-13-x86_64 installed = convertlit-1.8-13-x86_64
installed = coolercontrol-4.3.1-2-x86_64 installed = coolercontrol-4.3.1-2-x86_64
@@ -281,7 +281,7 @@ installed = ddcutil-2.2.7-1-x86_64
installed = debhelper-14.3-1-any installed = debhelper-14.3-1-any
installed = debtap-3.6.3-1-any installed = debtap-3.6.3-1-any
installed = debugedit-5.3-2-x86_64 installed = debugedit-5.3-2-x86_64
installed = debuginfod-0.195-8-x86_64 installed = debuginfod-0.196-1-x86_64
installed = default-cursors-3-1-any installed = default-cursors-3-1-any
installed = dejagnu-1.6.3-21-any installed = dejagnu-1.6.3-21-any
installed = deno-2.9.5-1-x86_64 installed = deno-2.9.5-1-x86_64
@@ -303,7 +303,7 @@ installed = docbook-xml-4.5-11-any
installed = docbook-xsl-1.79.2-9-any installed = docbook-xsl-1.79.2-9-any
installed = docker-1:29.7.2-1-x86_64 installed = docker-1:29.7.2-1-x86_64
installed = docker-buildx-0.36.1-1-x86_64 installed = docker-buildx-0.36.1-1-x86_64
installed = docker-compose-5.4.0-1-x86_64 installed = docker-compose-5.5.0-1-x86_64
installed = dolphin-26.04.3-1-x86_64 installed = dolphin-26.04.3-1-x86_64
installed = dos2unix-7.5.6-1-x86_64 installed = dos2unix-7.5.6-1-x86_64
installed = dosbox-0.74.3-4-x86_64 installed = dosbox-0.74.3-4-x86_64
@@ -342,7 +342,7 @@ installed = eigen-5.0.1-2-x86_64
installed = electron-1:43-1-any installed = electron-1:43-1-any
installed = electron43-43.4.0-1-x86_64 installed = electron43-43.4.0-1-x86_64
installed = elementary-icon-theme-8.2.0-2-any installed = elementary-icon-theme-8.2.0-2-any
installed = elfutils-0.195-8-x86_64 installed = elfutils-0.196-1-x86_64
installed = embree-4.4.1-1-x86_64 installed = embree-4.4.1-1-x86_64
installed = enca-1.22-1-x86_64 installed = enca-1.22-1-x86_64
installed = enchant-2.8.15-2-x86_64 installed = enchant-2.8.15-2-x86_64
@@ -393,7 +393,7 @@ installed = flashrom-1.7.0-1-x86_64
installed = flat-remix-gnome-20250926-1-any installed = flat-remix-gnome-20250926-1-any
installed = flatpak-1:1.18.1-1-x86_64 installed = flatpak-1:1.18.1-1-x86_64
installed = flex-2.6.4-6-x86_64 installed = flex-2.6.4-6-x86_64
installed = fltk-1.4.5-1-x86_64 installed = fltk-1.4.5-2-x86_64
installed = fltk1.3-1.3.11-4-x86_64 installed = fltk1.3-1.3.11-4-x86_64
installed = fluidsynth-2.6.0-1-x86_64 installed = fluidsynth-2.6.0-1-x86_64
installed = fmt-12.2.0-1-x86_64 installed = fmt-12.2.0-1-x86_64
@@ -532,7 +532,7 @@ installed = gnupg-2.4.9-3-x86_64
installed = gnutls-3.8.13-2-x86_64 installed = gnutls-3.8.13-2-x86_64
installed = go-2:1.26.6-1-x86_64 installed = go-2:1.26.6-1-x86_64
installed = go-md2man-2.0.7-2-x86_64 installed = go-md2man-2.0.7-2-x86_64
installed = go-tools-4:0.48.0-1-x86_64 installed = go-tools-4:0.49.0-1-x86_64
installed = gobject-introspection-1.86.0-2-x86_64 installed = gobject-introspection-1.86.0-2-x86_64
installed = gobject-introspection-runtime-1.86.0-2-x86_64 installed = gobject-introspection-runtime-1.86.0-2-x86_64
installed = gom-0.5.6-1-x86_64 installed = gom-0.5.6-1-x86_64
@@ -635,7 +635,7 @@ installed = hidapi-0.15.0-1-x86_64
installed = highway-1.4.0-1-x86_64 installed = highway-1.4.0-1-x86_64
installed = hiredis-1.3.0-1-x86_64 installed = hiredis-1.3.0-1-x86_64
installed = hplip-1:3.26.4-1-x86_64 installed = hplip-1:3.26.4-1-x86_64
installed = hspell-1.4-6-x86_64 installed = hspell-1.4-7-x86_64
installed = htdig-3.2.0b6-11.1-x86_64 installed = htdig-3.2.0b6-11.1-x86_64
installed = htop-3.5.3-1-x86_64 installed = htop-3.5.3-1-x86_64
installed = http-parser-2.9.4-2-x86_64 installed = http-parser-2.9.4-2-x86_64
@@ -908,7 +908,7 @@ installed = lib32-libcups-2.4.19-1-x86_64
installed = lib32-libdatrie-0.2.14-1-x86_64 installed = lib32-libdatrie-0.2.14-1-x86_64
installed = lib32-libdrm-2.4.134-1-x86_64 installed = lib32-libdrm-2.4.134-1-x86_64
installed = lib32-libdv-1.0.0-9-x86_64 installed = lib32-libdv-1.0.0-9-x86_64
installed = lib32-libelf-0.195-1-x86_64 installed = lib32-libelf-0.196-1-x86_64
installed = lib32-libepoxy-1.5.10-2-x86_64 installed = lib32-libepoxy-1.5.10-2-x86_64
installed = lib32-libffi-3.8.0-1-x86_64 installed = lib32-libffi-3.8.0-1-x86_64
installed = lib32-libgcrypt-1.12.2-1-x86_64 installed = lib32-libgcrypt-1.12.2-1-x86_64
@@ -1104,7 +1104,7 @@ installed = libebml-1.4.5-3-x86_64
installed = libebur128-1.2.6-2-x86_64 installed = libebur128-1.2.6-2-x86_64
installed = libedit-20260512_3.1-1-x86_64 installed = libedit-20260512_3.1-1-x86_64
installed = libei-1.6.0-1-x86_64 installed = libei-1.6.0-1-x86_64
installed = libelf-0.195-8-x86_64 installed = libelf-0.196-1-x86_64
installed = libepoxy-1.5.10-3-x86_64 installed = libepoxy-1.5.10-3-x86_64
installed = libev-4.33-5-x86_64 installed = libev-4.33-5-x86_64
installed = libevdev-1.13.6-1-x86_64 installed = libevdev-1.13.6-1-x86_64
@@ -1267,7 +1267,7 @@ installed = libofx-0.10.9-2-x86_64
installed = libogg-1.3.6-1-x86_64 installed = libogg-1.3.6-1-x86_64
installed = liboggz-1.1.3-1-x86_64 installed = liboggz-1.1.3-1-x86_64
installed = libomxil-bellagio-0.9.3-5-x86_64 installed = libomxil-bellagio-0.9.3-5-x86_64
installed = libopenmpt-0.8.7-1-x86_64 installed = libopenmpt-0.8.8-1-x86_64
installed = libosinfo-1.12.0-3-x86_64 installed = libosinfo-1.12.0-3-x86_64
installed = libp11-0.4.20-1-x86_64 installed = libp11-0.4.20-1-x86_64
installed = libp11-kit-0.26.5-1-x86_64 installed = libp11-kit-0.26.5-1-x86_64
@@ -1459,7 +1459,7 @@ installed = lightdm-slick-greeter-2.2.7-1-x86_64
installed = lilv-0.28.0-1-x86_64 installed = lilv-0.28.0-1-x86_64
installed = linphone-desktop-appimage-6.1.2-1-x86_64 installed = linphone-desktop-appimage-6.1.2-1-x86_64
installed = linux-7.1.8.arch1-3-x86_64 installed = linux-7.1.8.arch1-3-x86_64
installed = linux-api-headers-7.1-1-x86_64 installed = linux-api-headers-7.2-1-x86_64
installed = linux-firmware-20260810-2-any installed = linux-firmware-20260810-2-any
installed = linux-firmware-amdgpu-20260810-2-any installed = linux-firmware-amdgpu-20260810-2-any
installed = linux-firmware-atheros-20260810-2-any installed = linux-firmware-atheros-20260810-2-any
@@ -1625,7 +1625,7 @@ installed = nettle-4.0-1-x86_64
installed = network-manager-applet-1.36.0-2-x86_64 installed = network-manager-applet-1.36.0-2-x86_64
installed = networkmanager-1.58.0-1-x86_64 installed = networkmanager-1.58.0-1-x86_64
installed = networktablet-1.5-3-x86_64 installed = networktablet-1.5-3-x86_64
installed = nextcloud-34.0.2-1-any installed = nextcloud-34.0.3-1-any
installed = nextcloud-app-spreed-1:24.0.3-1-any installed = nextcloud-app-spreed-1:24.0.3-1-any
installed = nextcloud-app-talk_matterbridge-1.33.1026000-1-any installed = nextcloud-app-talk_matterbridge-1.33.1026000-1-any
installed = nextcloud-client-2:34.0.1-3-x86_64 installed = nextcloud-client-2:34.0.1-3-x86_64
@@ -2001,7 +2001,7 @@ installed = python-html5lib-1.1-18-any
installed = python-httpcore-1.0.9-3-any installed = python-httpcore-1.0.9-3-any
installed = python-httpx-0.28.1-7-any installed = python-httpx-0.28.1-7-any
installed = python-huggingface-hub-1:1.27.0-1-any installed = python-huggingface-hub-1:1.27.0-1-any
installed = python-hypothesis-6.165.3-1-x86_64 installed = python-hypothesis-6.165.5-1-x86_64
installed = python-idna-3.18-1-any installed = python-idna-3.18-1-any
installed = python-imagesize-2.0.0-1-any installed = python-imagesize-2.0.0-1-any
installed = python-importlib-metadata-9.0.0-1-any installed = python-importlib-metadata-9.0.0-1-any
@@ -2021,8 +2021,8 @@ installed = python-jmespath-1.1.0-1-any
installed = python-joblib-1.5.3-1-any installed = python-joblib-1.5.3-1-any
installed = python-kiwisolver-1.5.0-1-x86_64 installed = python-kiwisolver-1.5.0-1-x86_64
installed = python-ko-speech-tools-0.1.0-1-any installed = python-ko-speech-tools-0.1.0-1-any
installed = python-ladybug-core-0.44.54-1-any installed = python-ladybug-core-0.44.56-1-any
installed = python-ladybug-geometry-1.35.2-1-any installed = python-ladybug-geometry-1.35.3-1-any
installed = python-lark-parser-1.3.1-2-any installed = python-lark-parser-1.3.1-2-any
installed = python-lazy-loader-0.5-1-any installed = python-lazy-loader-0.5-1-any
installed = python-legacy-cgi-2.6.4-2-any installed = python-legacy-cgi-2.6.4-2-any
@@ -2074,7 +2074,7 @@ installed = python-pillow-12.3.0-1-x86_64
installed = python-pip-26.2.1-1-any installed = python-pip-26.2.1-1-any
installed = python-pipx-1.15.0-1-any installed = python-pipx-1.15.0-1-any
installed = python-pkg_resources-81.0.0-1-any installed = python-pkg_resources-81.0.0-1-any
installed = python-platformdirs-4.11.2-1-any installed = python-platformdirs-4.11.3-1-any
installed = python-pluggy-1.6.0-3-any installed = python-pluggy-1.6.0-3-any
installed = python-poetry-core-2.4.1-1-any installed = python-poetry-core-2.4.1-1-any
installed = python-pooch-1.9.0-1-any installed = python-pooch-1.9.0-1-any
@@ -2113,8 +2113,8 @@ installed = python-pytest-cov-7.1.0-1-any
installed = python-pytest-freezer-0.4.9-2-any installed = python-pytest-freezer-0.4.9-2-any
installed = python-pytest-subtests-0.15.0-2-any installed = python-pytest-subtests-0.15.0-2-any
installed = python-pytest-sugar-1.1.1-2-any installed = python-pytest-sugar-1.1.1-2-any
installed = python-pytest-timeout-2.4.0-2-any installed = python-pytest-timeout-2.5.0-1-any
installed = python-python-discovery-1.5.1-1-any installed = python-python-discovery-1.5.2-1-any
installed = python-pytokens-0.4.1-1-any installed = python-pytokens-0.4.1-1-any
installed = python-pytorch-cuda-2.13.0-4-x86_64 installed = python-pytorch-cuda-2.13.0-4-x86_64
installed = python-pytz-2026.1-1-any installed = python-pytz-2026.1-1-any
@@ -2192,7 +2192,7 @@ installed = python-tzlocal-1:5.4.4-1-any
installed = python-uc-micro-py-2.0.0-1-any installed = python-uc-micro-py-2.0.0-1-any
installed = python-ujson-5.13.0-1-x86_64 installed = python-ujson-5.13.0-1-x86_64
installed = python-urllib3-2.7.0-1-any installed = python-urllib3-2.7.0-1-any
installed = python-urwid-4.0.9-1-any installed = python-urwid-4.0.10-1-any
installed = python-userpath-1.9.2-4-any installed = python-userpath-1.9.2-4-any
installed = python-uv-build-0.12.5-1-x86_64 installed = python-uv-build-0.12.5-1-x86_64
installed = python-vcs-versioning-2.2.4-1-any installed = python-vcs-versioning-2.2.4-1-any
@@ -2797,7 +2797,7 @@ installed = tinysparql-3.11.1-1-x86_64
installed = tinyxml-2.6.2-13-x86_64 installed = tinyxml-2.6.2-13-x86_64
installed = tinyxml2-11.0.0-2-x86_64 installed = tinyxml2-11.0.0-2-x86_64
installed = tk-8.6.16-1-x86_64 installed = tk-8.6.16-1-x86_64
installed = tmux-3.7_b-1-x86_64 installed = tmux-3.7_c-1-x86_64
installed = topgrade-17.9.0-1-x86_64 installed = topgrade-17.9.0-1-x86_64
installed = tor-0.4.9.11-1-x86_64 installed = tor-0.4.9.11-1-x86_64
installed = torsocks-2.5.0-1-x86_64 installed = torsocks-2.5.0-1-x86_64
@@ -2820,7 +2820,7 @@ installed = ttf-ubuntu-font-family-1:0.83-2-any
installed = tumbler-4.20.2-1-x86_64 installed = tumbler-4.20.2-1-x86_64
installed = twolame-0.4.0-4-x86_64 installed = twolame-0.4.0-4-x86_64
installed = tzdata-2026c-1-x86_64 installed = tzdata-2026c-1-x86_64
installed = uartscope-1.0.0.r5.g1422efd-1-x86_64 installed = uartscope-1.0.0.r6.ga942f83-1-x86_64
installed = uchardet-0.0.8-4-x86_64 installed = uchardet-0.0.8-4-x86_64
installed = udisks2-2.11.2-1-x86_64 installed = udisks2-2.11.2-1-x86_64
installed = unifdef-2.12-4-x86_64 installed = unifdef-2.12-4-x86_64

Binary file not shown.

View File

@@ -3,12 +3,12 @@
pkgname = uartscope pkgname = uartscope
pkgbase = uartscope pkgbase = uartscope
xdata = pkgtype=pkg xdata = pkgtype=pkg
pkgver = 1.0.0.r6.ga942f83-1 pkgver = 1.1.0.r0.g36923e1-1
pkgdesc = Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect pkgdesc = Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect
url = https://git.projekt-hirnfrei.de/diabolus/uartscope url = https://git.projekt-hirnfrei.de/diabolus/uartscope
builddate = 1787005573 builddate = 1787031398
packager = Unknown Packager packager = Unknown Packager
size = 406129 size = 422641
arch = x86_64 arch = x86_64
license = MIT license = MIT
conflict = uartscope conflict = uartscope

Submodule uartscope-git/src/uartscope updated: a942f8385b...36923e1646

View File

@@ -1,2 +1,3 @@
a942f8385b8b05f5ec9a097ebbb3ba61ad0690f6 not-for-merge branch 'main' of https://git.projekt-hirnfrei.de/diabolus/uartscope 36923e16461bc15086c84187790dbcb5f0a5030f not-for-merge branch 'main' of https://git.projekt-hirnfrei.de/diabolus/uartscope
cc102c93eb17f7b910d8e74c3505f198bed77f10 not-for-merge tag 'v1.0.0' of https://git.projekt-hirnfrei.de/diabolus/uartscope cc102c93eb17f7b910d8e74c3505f198bed77f10 not-for-merge tag 'v1.0.0' of https://git.projekt-hirnfrei.de/diabolus/uartscope
36923e16461bc15086c84187790dbcb5f0a5030f not-for-merge tag 'v1.1.0' of https://git.projekt-hirnfrei.de/diabolus/uartscope