Files
skyplot/CLAUDE.md
T
2026-07-26 21:22:44 +02:00

50 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.