QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
NTRIPManager.h
Go to the documentation of this file.
1#pragma once
2
3#include <chrono>
4#include <functional>
5#include <memory>
6
7#include <QtCore/QObject>
8#include <QtCore/QPointer>
9#include <QtCore/QString>
10#include <QtCore/QVector>
11#include <QtPositioning/QGeoCoordinate>
12#include <QtQmlIntegration/QtQmlIntegration>
13
14#include "ExponentialBackoff.h"
15#include "NTRIPConfiguration.h"
17#include "NTRIPGgaReporter.h"
19#include "NTRIPTransport.h"
20#include "ScheduledTask.h"
21
26
29{
30 QString whitelist;
31 bool operator==(const NTRIPRTCMFilterConfig&) const = default;
32
34 [[nodiscard]] QVector<int> messageIds() const;
35};
36
45
52class NTRIPManager : public QObject
53{
54 Q_OBJECT
55 QML_ELEMENT
56 QML_UNCREATABLE("Provided by the GPS manager")
57 Q_MOC_INCLUDE("NTRIPConnectionStats.h")
59 Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY statusMessageChanged FINAL)
61 Q_PROPERTY(QString connectionStatusText READ connectionStatusText NOTIFY connectionStatusChanged FINAL)
62 Q_PROPERTY(QString securityWarning READ securityWarning NOTIFY securityWarningChanged FINAL)
63 Q_PROPERTY(QString ggaSource READ ggaSource NOTIFY ggaSourceChanged FINAL)
65 Q_PROPERTY(NTRIPConnectionStats* connectionStats READ connectionStats CONSTANT FINAL)
66
67 friend class NTRIPManagerTest;
68
69public:
72 {
73 Disconnected = 0,
74 Connecting = 1,
75 Connected = 2,
76 Reconnecting = 3,
77 Error = 4
78 };
79 Q_ENUM(ConnectionStatus)
80
81
95 Q_ENUM(Event)
96
97
106
108
109 explicit NTRIPManager(QObject* parent = nullptr, RuntimeScheduler* scheduler = nullptr,
110 const Dependencies& dependencies = {});
111 ~NTRIPManager() override;
112
114 void init();
117 void setConfiguration(const Configuration& configuration);
118
119 const Configuration& configuration() const { return _configuration; }
120
121 ConnectionStatus connectionStatus() const { return _connectionStatus; }
122
123 QString connectionStatusText() const;
124
125 QString statusMessage() const { return _statusMessage; }
126
128 QString securityWarning() const;
129
130 QString ggaSource() const { return _ggaReporter.currentSource(); }
131
132 NTRIPSourceTableController* sourceTableController() { return &_sourceTableController; }
133
135
138 Q_INVOKABLE void fetchMountpoints(const QGeoCoordinate& sortCoordinate = QGeoCoordinate());
139
141 using TransportFactory = std::function<NTRIPTransport*(const Configuration& configuration, QObject* parent)>;
142
144 void setTransportFactory(TransportFactory factory) { _transportFactory = std::move(factory); }
145
147
149 Q_INVOKABLE void retryNTRIP();
151 void shutdown();
152
153signals:
161 void certificatePinChanged(const QString& pin);
162
163private:
165 struct Notified
166 {
168 QString message;
169 QString securityWarning;
170 };
171
174 void _publish();
176 void _start();
178 void _stop();
179
182 bool _dispatch(Event ev, const QString& detail = {}, std::chrono::milliseconds retryAfter = {});
183
186 void _enterState(ConnectionStatus to, const QString& detail, std::chrono::milliseconds retryAfter = {});
187
189 void _onEnterState(ConnectionStatus to, std::chrono::milliseconds retryAfter);
190
192 static QString _defaultMessageFor(ConnectionStatus state);
193
196 void _openSession();
198 void _stopStreaming();
199
200 // The single-shot reconnect timer fires ReconnectDue; a failure after the attempt ceiling fires ReconnectGaveUp.
201 static constexpr int MAX_RECONNECT_ATTEMPTS = 100;
202
203 void _scheduleReconnect(std::chrono::milliseconds retryAfter = {});
204
205 void _cancelReconnect();
206
207 bool _shouldWaitForNetwork() const;
208 bool _casterIsLoopback() const;
209 void _waitForNetwork();
210
211 bool _reconnectExhausted() const { return _reconnectBackoff.attempts() >= MAX_RECONNECT_ATTEMPTS; }
212
213 void _onTransportConnected();
214 void _onTransportError(const NTRIPFailure& failure);
215 void _onCertificatePinned(const QString& pin);
216 void _setPinnedCertificate(const QString& pin);
217 void _onCorrectionFrame(const RTCMDecodedFrame& frame);
219 void _applyConfiguration();
220
221 bool _isEnabled() const { return _configuration.enabled; }
222
223 RuntimeScheduler* const _scheduler;
224 ScheduledTask _settingsDebounceTask;
225 ScheduledTask _reconnectTask;
226 NTRIPGgaReporter _ggaReporter;
228
230 QString _statusMessage;
231 Notified _notified;
232
233 TransportFactory _transportFactory;
234 QPointer<NTRIPTransport> _transport;
236 std::unique_ptr<GPSCorrectionSourceHandle> _correctionSource;
237
238 const QPointer<GPSCorrectionManager> _correctionManager;
239 const QPointer<QGCNetworkAvailabilityMonitor> _networkMonitor;
240
241 // Latest supplied configuration, and the one the current transport uses.
242 Configuration _configuration;
243 Configuration _running;
244
245 NTRIPSourceTableController _sourceTableController;
246
247 static constexpr std::chrono::milliseconds SETTINGS_DEBOUNCE{250};
248 ExponentialBackoff _reconnectBackoff{std::chrono::seconds(1), 2, std::chrono::seconds(30),
250 QString _lastFailureDetail;
251 bool _waitingForNetwork = false;
252 bool _initialized = false;
253 bool _shutdown = false;
254};
Retry delays that start at an initial value and grow by a factor per attempt, up to a cap.
constexpr int attempts() const
Attempts counted since construction or the last reset().
A begun correction source and the stream it delivers; destroying it ends the source.
std::function< std::optional< GPSObservation >()> PositionProvider
QString currentSource() const
std::function< NTRIPTransport *(const Configuration &configuration, QObject *parent)> TransportFactory
Creates the transport of one connection attempt, parented to parent; null opens an NTRIPHttpTransport...
void statusMessageChanged()
void setConfiguration(const Configuration &configuration)
ConnectionStatus connectionStatus() const
void certificatePinChanged(const QString &pin)
The trusted self-signed caster certificate changed, or was forgotten (empty); the settings should sto...
ConnectionStatus
Public connection status. Numeric values are stable — QML binds against them.
QString securityWarning() const
Set while a connected stream sends its credentials without TLS.
NTRIPSourceTableController * sourceTableController()
void setGgaPositionProvider(NTRIPGgaReporter::PositionSource source, NTRIPGgaReporter::PositionProvider provider)
void init()
Applies the configuration; call once the position providers are installed.
void ggaSourceChanged()
void enableRequested()
Retrying after an error turns the saved connection on.
QString connectionStatusText() const
Q_INVOKABLE void retryNTRIP()
Retry a user-visible error, preserving the enabled setting for subsequent automatic retries.
void securityWarningChanged()
QString statusMessage() const
@ StartRequested
Settings enable went true, or the user retried an error.
@ ReconnectGaveUp
The reconnect attempt ceiling was reached.
@ HotReconfigure
Transport-affecting setting changed while connected; reconnect in place.
@ TransportFatalError
NTRIPTransport emitted a non-retryable error.
@ ConfigInvalid
Connection configuration failed validation.
@ TransportError
NTRIPTransport emitted a retryable error.
@ TransportConnected
NTRIPTransport emitted connected().
@ StopRequested
Settings enable went false, or the manager shut down.
@ ReconnectDue
The reconnect delay elapsed or the network returned.
QString ggaSource() const
~NTRIPManager() override
void shutdown()
Permanently retire this manager, including deferred settings work.
void connectionStatusChanged()
Q_INVOKABLE void fetchMountpoints(const QGeoCoordinate &sortCoordinate=QGeoCoordinate())
NTRIPConnectionStats * connectionStats()
void setTransportFactory(TransportFactory factory)
An empty factory restores NTRIPHttpTransport for every attempt.
const Configuration & configuration() const
friend class NTRIPManagerTest
Short connection state for compact views.
static constexpr std::chrono::milliseconds MAX_RETRY_AFTER
Longest caster Retry-After hint that may delay a reconnect.
Definition NTRIPError.h:37
Services an NTRIPManager uses, which must outlive it.
QGCNetworkAvailabilityMonitor * network
Reconnects wait for a network while it reports none.
GPSCorrectionManager * corrections
Receives the stream as the NTRIP correction source.
The NTRIP settings as values; the application's settings binding supplies them.
NTRIPRTCMFilterConfig filter
NTRIPGgaReporter::Configuration gga
NTRIPConnectionConfig connection
bool operator==(const Configuration &) const =default
The RTCM message filter as the settings store it: comma-separated message IDs, empty for every messag...
bool operator==(const NTRIPRTCMFilterConfig &) const =default
QVector< int > messageIds() const
The positive message IDs of the whitelist; entries that are not one are skipped.