Skip to content

feat: Enhanced NTRIP positioning with Skyplot and GNSS Status views#7054

Draft
pobsteta wants to merge 42 commits intoopengisch:masterfrom
pobsteta:feature/ntrip-enhanced
Draft

feat: Enhanced NTRIP positioning with Skyplot and GNSS Status views#7054
pobsteta wants to merge 42 commits intoopengisch:masterfrom
pobsteta:feature/ntrip-enhanced

Conversation

@pobsteta
Copy link

@pobsteta pobsteta commented Feb 14, 2026

Summary

This PR adds comprehensive NTRIP RTK correction support and GNSS diagnostic views to QField, enabling centimeter-level positioning with external GNSS receivers.

NTRIP Client

  • Full NTRIP v1/v2 protocol support with chunked transfer encoding
  • Automatic reconnection with exponential backoff (1s–30s), permanent error detection (4xx)
  • RTCM correction forwarding to all receiver types (Bluetooth, TCP, UDP, Serial)
  • GGA sentence forwarding to NTRIP caster for VRS (Virtual Reference Station) support
  • RTCM binary logging alongside NMEA logs

Mountpoint Browser

  • Sourcetable parser fetching mountpoints from any NTRIP caster
  • Distance-based sorting with Haversine calculation, nearest station highlighted
  • Updates sorting when GPS position becomes available after fetch
  • Displays format, country, and distance for each mountpoint

Skyplot Page

  • Polar satellite view with concentric elevation circles (0°/30°/60°)
  • Real-time satellite positioning by azimuth/elevation
  • Shape distinction: filled circles (in-use) vs triangles (tracked-only)
  • Constellation color-coding: GPS (green), GLONASS (red-orange), Galileo (gold), BeiDou (blue)
  • SNR bar chart with dBHz values and constellation-prefixed IDs
  • Info block: UTC, lat/lon, fix type, HDOP, satellite count

GNSS Status Page

  • Scrollable sections: Source/Time, Position, Altitude, Fix, Speed, DOP, Satellites, Precision, NTRIP
  • Color-coded fix quality and accuracy values (cm)
  • NTRIP section with connection state, details, and data transfer stats (↓/↑)
  • Placeholder sections for Differential, Baseline, Battery (future C++ properties)
  • Stale data detection (>30s → em-dash placeholders)

UI Enhancements

  • GNSS button drawer with Skyplot and Status sub-buttons
  • Three badges on GNSS button: accuracy (TopRight), fix type (BottomRight), NTRIP state (TopLeft)
  • Custom SVG icons: satellite (emitter) and antenna (receiver)
  • Shared Theme functions: fixTypeColor, accuracyColor, constellationColor, ntripStateColor
  • SatelliteModel (QAbstractListModel) with constellation-aware roles and Q_PROPERTY(count)

Defaults

  • Centipede network credentials (centipede/centipede) for French RTK positioning
  • NTRIP v1 default, Send NMEA GGA enabled by default

New Files

File Description
src/core/positioning/ntripclient.{h,cpp} High-level NTRIP client with logging
src/core/positioning/ntripsocketclient.{h,cpp} Low-level TCP socket NTRIP protocol
src/core/positioning/mountpointmodel.{h,cpp} Sourcetable fetch, parse, distance sort
src/core/positioning/sourcetableparser.{h,cpp} NTRIP sourcetable STR record parser
src/core/positioning/satellitemodel.{h,cpp} QAbstractListModel for satellite data
src/qml/SkyplotView.qml Full-screen polar satellite view
src/qml/GnssStatusView.qml Full-screen GNSS status page
images/.../ic_gnss_satellite_white_24dp.svg Satellite emitter icon
images/.../ic_gnss_antenna_white_24dp.svg Antenna receiver icon

Test Plan

  • Connect Bluetooth GNSS receiver → verify satellites in Skyplot (polar + SNR bars)
  • Verify GNSS Status shows all metrics with correct units (cm for accuracy)
  • Configure NTRIP (e.g. crtk.net:2101, NEAR, centipede/centipede)
  • Verify NTRIP connects, receives RTCM, forwards corrections to receiver
  • Verify fix transitions: Autonomous → DGPS → RTK Float → RTK Fixed
  • Fetch mountpoints → verify sorted by distance with nearest highlighted
  • Verify Send NMEA GGA toggle works (required for VRS mountpoints)
  • Test NTRIP v1 and v2 protocol
  • Verify badges update in real-time on GNSS button
  • Test reconnection when NTRIP connection drops
  • Test with no GPS position → mountpoints unsorted, no distance shown

🤖 Generated with Claude Code

edgecase14 and others added 27 commits July 29, 2025 22:25
Resolved conflicts:
- Updated mReceiver to use std::unique_ptr (from upstream)
- Preserved NTRIP client functionality (from ntrip-client branch)
- Added onDeviceSocketStateChanged connection for NTRIP support
- Refactor RTCM forwarding via virtual writeRawData() on AbstractGnssReceiver,
  replacing dynamic_cast<BluetoothReceiver*> with a generic interface supporting
  Bluetooth, TCP, UDP, and serial port receivers
- Extend NtripState enum to 5 states (Disconnected/Connecting/Connected/
  Reconnecting/Error) with exponential backoff reconnection (1s-60s)
- Add SatelliteModel (QAbstractListModel) exposing per-satellite data with
  constellation detection via Qgis::SatelliteSystem + PRN range fallback
- Add fix type color tokens in Theme and colored badge on GNSS button
  showing RTK Fixed/Float/DGPS quality indicator
- Fix ntripStatusChanged signal mismatch between Positioning and
  PositioningSource QRemoteObjects mirror

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
QgsSatelliteInfo::satType is a QChar containing the NMEA $GxGSV talker
ID (P=GPS, L=GLONASS, A=Galileo, B=BeiDou, S=SBAS, Q=QZSS), not an
integer enum. This caused a compilation error with static_cast<int>.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qfield-fairy
Copy link
Collaborator

qfield-fairy commented Feb 14, 2026

📱 Android builds

Download an Android arm64 build of this PR for testing.
(Built from commit b3a0973)

Other Android architectures

🍎 MacOS DMG universal builds

Download a MacOS DMG universal build of this PR for testing.
(Built from commit b3a0973)

🪟 Windows builds

Download a Windows build of this PR for testing.
(Built from commit b3a0973)

Classify HTTP errors from NTRIP casters as permanent (4xx, SOURCETABLE)
or transient (5xx, network). Permanent errors go directly to Error state
without scheduling reconnect attempts. Reduce max reconnect backoff from
60s to 30s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@pobsteta
Copy link
Author

Added: Permanent error handling + backoff 30s

Latest commit (b3a0973): feat: Handle permanent NTRIP errors without retry and cap backoff at 30s

Changes:

  • HTTP response parsing: Classifies NTRIP caster responses — 4xx (bad credentials) and SOURCETABLE (invalid mountpoint) are permanent errors that go directly to Error state without retry
  • Transient errors: 5xx, network errors, and unparsable responses continue to trigger reconnection with exponential backoff
  • Backoff cap: Reduced from 60s to 30s (sequence: 1s, 2s, 4s, 8s, 16s, 30s)
  • Double error prevention: mPendingError flag prevents duplicate error emission when abort() triggers onDisconnected()

pobsteta and others added 14 commits February 14, 2026 19:09
Add sourcetable parser and mountpoint browser so users can fetch and
select the correct NTRIP mountpoint from a list instead of typing it
manually. The MountpointModel handles its own TCP fetch and exposes
the parsed STR records as a QAbstractListModel for QML consumption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Haversine distance calculation to MountpointModel, sort mountpoints
by proximity, highlight nearest entry with bold text, and display distance
in km. Mountpoints with missing coordinates (0,0) are skipped and sorted
to the end. Without a valid GPS position, no sorting or distance is shown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NTRIP v2 (HTTP/1.1 + Ntrip-Version: Ntrip/2.0) alongside existing v1.
NtripSocketClient handles chunked Transfer-Encoding via a state machine
parser. Version preference is propagated through PositioningSource,
Positioning, and QML settings. V1 remains the default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add RTCM binary logging to NtripClient, triggered by the same logging
toggle as NMEA. Writes [timestamp_ms][data_length][raw_rtcm_bytes] per
block with periodic flush. Integrated into PositioningSource lifecycle
(setLogging, setLoggingPath, start/stop/reconnect).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a QfToolButtonDrawer in the top-left mainToolbar for accessing GNSS
diagnostic views when an external GNSS receiver is active. The drawer
contains two sub-buttons opening full-screen stub pages (SkyplotView and
GnssStatusView) to be completed in Stories 4.3 and 5.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…g info

Replace the SkyplotView stub with a full-screen diagnostic page featuring:
- Polar grid with concentric elevation circles (0/30/60 deg) and N/S/E/W axes
- Real-time satellite positioning by azimuth/elevation from SatelliteModel
- Shape distinction: filled circles for in-use, triangles for tracked-only
- Constellation color-coding (GPS green, GLONASS red-orange, Galileo gold, BeiDou blue)
- SNR bar chart with dBHz values and constellation-prefixed satellite IDs
- Info block with UTC time, lat/lon, translated fix type, HDOP, satellite count
- Constellation legend with color and shape distinction
- Empty state handling when no satellites available

Adds constellation color tokens and constellationColor() helper to Theme.qml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the stub with a full-screen GNSS Status page showing 7 data
sections (Source/Time, Position, Altitude, Fix, Speed, DOP, Satellites)
using inline QML components for consistent label:value layout. Fix type
is color-coded via qualityDescription. Stale data (>30s) shows em-dash
placeholders. Move fixTypeColor() to Theme.qml as shared utility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…StatusView

Add Precision section with color-coded H/V accuracy (mm), plus placeholder
sections for Differential, Baseline, and Battery for future data sources.
Theme.accuracyColor() shared function for accuracy threshold coloring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify fix type QfBadge to use shared Theme.fixTypeColor() and display
for all quality values (0-6), making No Fix and Autonomous states visible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add visual NTRIP feedback: a color-coded badge (TopLeft) on the GNSS
button showing connection state at a glance, and a detailed NTRIP
section in GnssStatusView with state, details, and data transfer stats.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change NTRIP default credentials to "centipede" (matching the French
Centipede network) to fix connection errors on crtk.net. Replace
generic location/compass icons with dedicated satellite and antenna
SVG icons for the GNSS drawer and skyplot buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The NTRIP caster normally closes the connection after sending the
sourcetable, which triggered a RemoteHostClosedError before the
disconnected signal. This caused the fetch to fail instead of
parsing the received data. Now ignore this expected error and let
onSocketDisconnected() handle the response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add missing `import org.qfield` to SkyplotView and GnssStatusView so
QML can resolve Q_GADGET sub-properties of GnssPositionInformation.
Add explicit Q_PROPERTY(count) to SatelliteModel since QAbstractListModel
does not expose it in Qt 6 QML. Swap drawer/skyplot icons and display
accuracy in cm.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a Connections listener on positionSource so that updatePosition()
is called when GPS fix becomes available after the sourcetable has
already been fetched, ensuring nearest stations are shown on first use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@pobsteta pobsteta changed the title NTRIP enhanced positioning with RTK corrections support feat: Enhanced NTRIP positioning with Skyplot and GNSS Status views Feb 18, 2026
@pobsteta pobsteta marked this pull request as draft February 18, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants