From f682a97711614ef421ccfb679dbadb76aa09a87a Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sun, 26 Jul 2026 21:22:44 +0200 Subject: [PATCH] commit stale changes --- CLAUDE.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c40d5a5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,49 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Running the application + +```bash +# Activate the virtual environment first +source .venv/bin/activate + +# Run the app +python sky_plot.py +``` + +## Architecture + +This is a PyQt5 desktop app that reads GNSS satellite data from a u-blox receiver (UBX protocol) over serial or TCP/IP and visualizes it in real time. + +### Data flow + +1. `GnssReader` (QThread in `gnss_thread.py`) polls the device in a loop: sends `NAV-SAT` and `NAV-DOP` poll requests, reads 512 bytes, feeds them through `UbxPacketizer`. +2. Decoded frames are passed to `extract_satellites()` in `ubx.py`, which returns a dict with optional keys `'sat'` (list of satellite dicts) and `'dop'` (dict with `p_dop`, `h_dop`, etc.). +3. `GnssReader` emits the `satellites_updated(dict)` signal. +4. `MainWindow._on_satellites()` routes the payload to three widgets: `SkyPlotWidget`, `SatelliteTable`, and `PlotTab`. + +### Module overview + +| File | Responsibility | +|---|---| +| `sky_plot.py` | Entry point; `MainWindow` with three tabs: Connection, Sky View, Plot | +| `gnss_thread.py` | `GnssReader(QThread)` — device I/O loop, emits signals | +| `ubx.py` | UBX protocol: `UbxPacketizer` (byte-stream → frames), `parse_nav_sat`, `parse_nav_dop`, `extract_satellites` | +| `transport.py` | Abstract `GnssTransport` base class | +| `transport_serial.py` | `SerialTransport` — wraps pyserial | +| `transport_network.py` | `TcpTransport` — wraps socket (for ser2net) | +| `connection_panel.py` | `ConnectionPanel(QGroupBox)` — serial/TCP UI, emits `connect_requested(factory, label)` | +| `lru_store.py` | `LruStore` — persists up to 5 recent TCP connections via `QSettings` | +| `sky_plot_widget.py` | `SkyPlotWidget(QWidget)` — polar sky plot, custom `paintEvent` | +| `sat_table.py` | `SatelliteTable(QTableWidget)` — tabular satellite list | +| `plot_tab.py` | `PlotTab` — 2×4 grid of `SinglePlotPanel`s (pyqtgraph), time-series plots with persistent settings | +| `defines.py` | `GNSS_NAMES` and `GNSS_COLORS` shared constants | + +### Key design notes + +- **Transport factory pattern**: `ConnectionPanel` emits a `factory` callable (a lambda that creates a transport). `GnssReader` calls the factory in its thread, keeping socket/serial construction off the main thread. +- **Disabled old code**: `MainWindow.__build_ui` and `MainWindow.__connect` (double-underscore prefix) are the original single-view implementations, effectively disabled by Python name mangling. The active methods are `_build_ui` and `_connect`. +- **`sat_table.py` duplicates** `GNSS_NAMES`/`GNSS_COLORS` from `defines.py` — prefer `defines.py` as the source of truth when extending. +- **Plot settings persistence**: `PlotSettingsStore` saves each panel's selected field and SV filter to `QSettings("gnss_skyplot", "connections")` (same org/app as `LruStore`). +- **History cap**: each `SinglePlotPanel` keeps at most `MAX_HISTORY = 300` data points per satellite/PDOP curve.