5#include <QtCore/QStringList>
10#ifndef QGC_NO_SERIAL_LINK
20 , _configuration(configuration)
21 , _scheduler(scheduler)
26 const bool connectionChanged = !previous.
sameConnection(_configuration);
29 if (connectionChanged || turnedOff) {
36 _keepConnected = _owner == Owner::Saved && !connectionChanged;
40void GPSReceiverConnectionPolicy::_cancelRetries()
43 qCDebug(GPSReceiverConnectionPolicyLog) <<
"Automatic reconnect cancelled";
46 if ((_keepConnected || _retryDeadlineUs) && !_receiver.
hasReceiver()) {
49 _keepConnected =
false;
50 _waitingForPort =
false;
52#ifndef QGC_NO_SERIAL_LINK
53 _waitingPorts.
clear();
55 _retryDeadlineUs.reset();
56 _retryBackoff.
reset();
63 _startPending =
false;
70 _receiver.
setConnectionError(tr(
"Disconnect the current receiver before connecting another."));
75 if (!_connectConfigured(allowPersistentChanges)) {
78 _owner = Owner::Saved;
91 if (_owner == Owner::Saved && _configuration.
autoConnect && !std::exchange(_keepConnected,
true)) {
92 qCDebug(GPSReceiverConnectionPolicyLog) <<
"Automatic reconnect armed for the saved receiver";
94 _waitingForPort =
false;
95 _retryDeadlineUs.reset();
96 _retryBackoff.
reset();
101 if (_owner == Owner::Discovered && _discoveryEnabled()) {
104 _owner = Owner::None;
111 if (_owner == Owner::Saved && _keepConnected) {
113 _waitingForPort =
true;
119 _owner = Owner::None;
124void GPSReceiverConnectionPolicy::_scheduleRetry()
126 const auto delay = _retryBackoff.
next();
127 qCDebug(GPSReceiverConnectionPolicyLog) <<
"Retrying the receiver connection in" << delay.count() <<
"ms";
128 _retryDeadlineUs = _scheduler->
nowUs() +
static_cast<quint64
>(std::chrono::microseconds(delay).count());
136 if (std::exchange(_startPending,
false) && _hasSavedReceiver()) {
137 _owner = Owner::Saved;
138 _keepConnected =
true;
140 if (_keepConnected) {
142 }
else if (_discoveryEnabled()) {
147bool GPSReceiverConnectionPolicy::_hasSavedReceiver()
const
151 return !_configuration.
serialDevice.trimmed().isEmpty();
153 return !_configuration.
tcpHost.trimmed().isEmpty() && _configuration.
tcpPort != 0;
161bool GPSReceiverConnectionPolicy::_discoveryEnabled()
const
163#ifdef QGC_NO_SERIAL_LINK
173void GPSReceiverConnectionPolicy::_updateSaved()
176 if (!_serialDeviceAvailable(_configuration.
serialDevice.trimmed())) {
177 if (!std::exchange(_waitingForPort,
true)) {
180 tr(
"Waiting for the receiver on %1.").arg(_configuration.
serialDevice.trimmed()));
184 if (std::exchange(_waitingForPort,
false)) {
190 if (!_retryDeadlineUs || _scheduler->
nowUs() >= *_retryDeadlineUs) {
195void GPSReceiverConnectionPolicy::_attemptSaved()
197 _retryDeadlineUs.reset();
199 if (!_connectConfigured(
false)) {
204bool GPSReceiverConnectionPolicy::_serialDeviceAvailable([[maybe_unused]]
const QString& device)
const
206#ifdef QGC_NO_SERIAL_LINK
213bool GPSReceiverConnectionPolicy::_connectConfigured(
bool allowPersistentChanges)
224 const QString host = _configuration.
tcpHost.trimmed();
225 const uint tcpPort = _configuration.
tcpPort;
226 if (host.isEmpty() || tcpPort == 0 || tcpPort > 65535) {
230 return _receiver.
connectTcp(host,
static_cast<quint16
>(tcpPort), *type, allowPersistentChanges);
233 const uint udpPort = _configuration.
udpPort;
234 if (configuredBase) {
236 tr(
"A configured base needs a serial or TCP connection. UDP only receives data."));
239 if (udpPort == 0 || udpPort > 65535) {
243 return _receiver.
connectUdp(
static_cast<quint16
>(udpPort), *type);
245#ifndef QGC_NO_SERIAL_LINK
246 const QString device = _configuration.
serialDevice.trimmed();
247 if (!_serialDeviceAvailable(device)) {
248 _receiver.
setConnectionError(tr(
"Select an available serial device that is not a bootloader."));
262 return _receiver.
connectSerial(device, *type, baud, allowPersistentChanges, std::move(claim));
268void GPSReceiverConnectionPolicy::_updateDiscovery()
270#ifndef QGC_NO_SERIAL_LINK
271 if (_owner == Owner::Discovered) {
272 if (_serialDeviceAvailable(_autoPort)) {
273 if (!_retryDeadlineUs || _scheduler->
nowUs() >= *_retryDeadlineUs) {
274 _connectDiscovered(_autoPort);
279 _owner = Owner::None;
283 _waitingPorts.
removeIf([&receivers](
const QString& device) {
return !receivers.contains(device); });
285 for (
const QString& device : receivers) {
286 if (_waitingPorts.
settled(device, nowUs)) {
287 _connectDiscovered(device);
294#ifndef QGC_NO_SERIAL_LINK
295void GPSReceiverConnectionPolicy::_connectDiscovered(
const QString& device)
301 _owner = Owner::Discovered;
303 _waitingPorts.
clear();
304 _retryDeadlineUs.reset();
310 if (!type || !_receiver.
connectSerial(device, *type, 0,
false, std::move(claim))) {
QString gpsReceiverConfigErrorText(GPSReceiverConfigError error)
Translated diagnostic; empty for GPSReceiverConfigError::None.
constexpr bool gpsValidBaudRate(uint32_t baudRate, bool passive)
GPSReceiverSessionOutcome
What the policy does after a receiver session ends; the receiver words the message for it.
@ Unplugged
A discovered receiver was unplugged; discovery connects it again when it returns.
@ None
Nothing reconnects; the receiver's own message for the error applies.
@ AutoRetrying
A discovered receiver failed or was lost; discovery retries it.
@ WaitingForPort
The saved receiver was unplugged; it reconnects when its port returns.
@ Retrying
The saved receiver's connection was lost; a retry is scheduled.
std::optional< GPSType > gpsReceiverTypeForManufacturer(int manufacturer)
The family a persisted manufacturer selects, GPSType::automatic for GPS_AUTOMATIC_MANUFACTURER; empty...
#define QGC_LOGGING_CATEGORY(name, categoryStr)
constexpr Delay next(Delay retryAfter=Delay::zero())
Returns peek(retryAfter) and counts the attempt.
void disconnectConfigured()
Disconnects at the user's request and pauses automatic connection.
GPSReceiverSessionOutcome sessionEnded(bool portRemoved)
void reset()
Forgets connection ownership and pending retries, before another connection replaces it.
void update()
Periodic tick: due automatic connections and USB discovery.
void configurationChanged(const GPSReceiverConfiguration &previous)
The receiver's configuration changed from previous.
bool connectConfigured(bool allowPersistentChanges)
Connects the saved receiver at the user's request and resumes automatic connection.
virtual QStringList rtkReceiverPorts() const =0
virtual GPSSerialClaim claimSerialPort(const QString &device)=0
Claims the device until the last copy is released; empty when it is in use.
virtual bool hasReceiver() const =0
virtual bool serialPortAvailable(const QString &device) const =0
The device is plugged in and not in its bootloader.
virtual void setConnectionError(const QString &message)=0
virtual bool connectSerial(const QString &device, GPSType type, uint32_t baudRate, bool allowPersistentChanges, GPSSerialClaim claim)=0
virtual void endConnection(bool clearError)=0
virtual bool connectUdp(quint16 port, GPSType type)=0
virtual bool connectTcp(const QString &host, quint16 port, GPSType type, bool allowPersistentChanges)=0
virtual quint64 nowUs() const =0
void removeIf(Predicate forget)
Forgets the ports forget returns true for.
bool settled(const QString &port, quint64 nowUs)
Records port as listed at nowUs; true once it has been listed for the settle delay.
The receiver configuration the application's settings binding supplies as values.
RTKSettings::ReceiverRole receiverRole
Only a configured base is written to by QGroundControl.
bool autoConnect
Keep the saved receiver connected, or discover a configured base on USB when no device is saved.
bool sameConnection(const GPSReceiverConfiguration &other) const
RTKSettings::ConnectionType effectiveConnectionType() const
The connection this configuration uses; builds without serial links connect a serial selection over T...
int baseReceiverManufacturer
A GPSReceiverDescriptor manufacturer, or GPS_AUTOMATIC_MANUFACTURER to detect the family on every con...