QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GPSCorrectionSelector.cc
Go to the documentation of this file.
2
3#include <algorithm>
4
5#include "MonotonicClock.h"
6
7int GPSCorrectionSelector::_index(GPSCorrectionSettings::CorrectionSource source)
8{
9 const int index = static_cast<int>(source);
10 return index >= 0 && index < GPS_CORRECTION_SOURCE_COUNT ? index : -1;
11}
12
13bool GPSCorrectionSelector::_fresh(const Category& category, qint64 now) const
14{
15 const auto age =
16 MonotonicClock::age(std::chrono::milliseconds(category.lastRoutableMs), std::chrono::milliseconds(now));
17 return category.begun && age && *age < FRESHNESS_TIMEOUT;
18}
19
20bool GPSCorrectionSelector::_eligible(int index, qint64 now) const
21{
22 if (index <= 0 || !_fresh(_categories[index], now)) {
23 return false;
24 }
25 return _configuredSource == GPSCorrectionSettings::HighestPriority || index == static_cast<int>(_configuredSource);
26}
27
28void GPSCorrectionSelector::_select(qint64 now)
29{
30 int best = -1;
31 for (int index = 1; index < GPS_CORRECTION_SOURCE_COUNT && best < 0; ++index) {
32 if (_eligible(index, now)) {
33 best = index;
34 }
35 }
36 if (!_eligible(_active, now)) {
37 _active = best;
38 _candidate = -1;
39 return;
40 }
41 if (best < 0 || best >= _active) {
42 _candidate = -1;
43 return;
44 }
45 if (_candidate != best) {
46 _candidate = best;
47 _candidateSinceMs = now;
48 } else if (const auto held =
49 MonotonicClock::age(std::chrono::milliseconds(_candidateSinceMs), std::chrono::milliseconds(now));
50 held && *held >= SWITCH_HOLD_DOWN) {
51 _active = _candidate;
52 _candidate = -1;
53 }
54}
55
57{
58 if (_shutdown || _index(source) < 0 || source == _configuredSource) {
59 return;
60 }
61 _configuredSource = source;
62 _active = -1;
63 _candidate = -1;
64 _select(now);
65}
66
68{
69 const int index = _index(source);
70 if (_shutdown || index <= 0) {
71 return;
72 }
73 endSource(source, now);
74 _categories[index].begun = true;
75}
76
78{
79 const int index = _index(source);
80 if (index <= 0) {
81 return;
82 }
83 _categories[index] = {};
84 _select(now);
85}
86
88 qint64 receivedAtMs, qint64 now)
89{
90 const int index = _index(source);
91 if (_shutdown || index <= 0 || !_categories[index].begun) {
92 return false;
93 }
94 const auto age = MonotonicClock::age(std::chrono::milliseconds(receivedAtMs), std::chrono::milliseconds(now));
95 if (!age || *age >= FRESHNESS_TIMEOUT) {
96 return false;
97 }
98 Category& category = _categories[index];
99 if (category.instance != instance) {
100 // The category keeps following its instance until that goes stale.
101 if (_fresh(category, now)) {
102 return false;
103 }
104 category.instance = instance;
105 }
106 category.lastRoutableMs = (std::max) (category.lastRoutableMs, receivedAtMs);
107 _select(now);
108 return _active == index;
109}
110
112{
113 return std::ranges::any_of(_categories, &Category::begun);
114}
115
116std::optional<GPSCorrectionStream> GPSCorrectionSelector::selectedStream(qint64 now) const
117{
118 if (!_eligible(_active, now)) {
119 return std::nullopt;
120 }
121 return GPSCorrectionStream{.source = _active, .instanceId = _categories[_active].instance};
122}
123
125{
126 _shutdown = true;
127 _categories = {};
128 _active = -1;
129 _candidate = -1;
130}
constexpr int GPS_CORRECTION_SOURCE_COUNT
static constexpr std::chrono::milliseconds SWITCH_HOLD_DOWN
bool hasSources() const
Whether any source is begun.
bool submit(GPSCorrectionSettings::CorrectionSource source, const QString &instance, qint64 receivedAtMs, qint64 now)
void beginSource(GPSCorrectionSettings::CorrectionSource source, qint64 now)
Starts source. A category has one source at a time, which ends itself before a replacement begins.
std::optional< GPSCorrectionStream > selectedStream(qint64 now) const
The selected fresh stream, if any.
void endSource(GPSCorrectionSettings::CorrectionSource source, qint64 now)
Stops routing source.
static constexpr std::chrono::milliseconds FRESHNESS_TIMEOUT
Age at which a frame is no longer routed and its stream stops being eligible for selection.
void configure(GPSCorrectionSettings::CorrectionSource source, qint64 now)
Routes only source, or selects automatically for HighestPriority. A valid, changed source reselects a...
CorrectionSource
Persisted values of correctionSource. The storage type keeps any saved value a valid enum value.
constexpr std::optional< std::chrono::duration< Rep, Period > > age(std::chrono::duration< Rep, Period > timestamp, std::chrono::duration< Rep, Period > now)
Age of timestamp at now, both in the same unit; empty for a missing or future timestamp.
The stream vehicles receive: its source category and the instance within it.