QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
NTRIPSourceTable.cc
Go to the documentation of this file.
1#include "NTRIPSourceTable.h"
2
3#include <QtCore/qnumeric.h>
4#include <algorithm>
5
7
8QGC_LOGGING_CATEGORY(NTRIPSourceTableLog, "GPS.NTRIPSourceTable")
9
10bool NTRIPMountpoint::fromSourceTableLine(const QString& line, NTRIPMountpoint& out)
11{
12 // Need >= 18 fields; split keeps empty fields, so a trailing ';' is harmless
13 // (the extra empty field parses as 0 / "" for its column).
14 const QStringList fields = line.split(';');
15 if (fields.size() < 18 || fields.at(0).trimmed().toUpper() != QStringLiteral("STR")) {
16 return false;
17 }
18
20 mp.mountpoint = fields.at(1).trimmed();
21 mp.identifier = fields.at(2).trimmed();
22 mp.format = fields.at(3).trimmed();
23 mp.formatDetails = fields.at(4).trimmed();
24 mp.carrier = fields.at(5).trimmed().toInt();
25 mp.navSystem = fields.at(6).trimmed();
26 mp.network = fields.at(7).trimmed();
27 mp.country = fields.at(8).trimmed();
28 // Caster-supplied coordinates are untrusted; out-of-range/non-finite values
29 // collapse to 0.0, which updateDistance() treats as "unknown" and skips.
30 const auto parseCoord = [](const QString& s, double limit) -> double {
31 bool ok = false;
32 const double v = s.trimmed().toDouble(&ok);
33 return (ok && qIsFinite(v) && qAbs(v) <= limit) ? v : 0.0;
34 };
35 mp.latitude = parseCoord(fields.at(9), 90.0);
36 mp.longitude = parseCoord(fields.at(10), 180.0);
37 mp.nmea = fields.at(11).trimmed() == QStringLiteral("1");
38 mp.solution = fields.at(12).trimmed() == QStringLiteral("1");
39 mp.generator = fields.at(13).trimmed();
40 mp.compression = fields.at(14).trimmed();
41 mp.authentication = fields.at(15).trimmed();
42 mp.fee = fields.at(16).trimmed() == QStringLiteral("Y");
43 mp.bitrate = fields.at(17).trimmed().toInt();
44
45 out = mp;
46 return true;
47}
48
49void NTRIPMountpoint::updateDistance(const QGeoCoordinate& from)
50{
51 if (!from.isValid() || (latitude == 0.0 && longitude == 0.0)) {
52 return;
53 }
54 const QGeoCoordinate mountCoord(latitude, longitude);
55 distanceKm = from.distanceTo(mountCoord) / 1000.0;
56}
57
58// ---------------------------------------------------------------------------
59// NTRIPSourceTableModel
60// ---------------------------------------------------------------------------
61
62NTRIPSourceTableModel::NTRIPSourceTableModel(QObject* parent) : QAbstractListModel(parent) {}
63
64int NTRIPSourceTableModel::rowCount(const QModelIndex& parent) const
65{
66 return parent.isValid() ? 0 : count();
67}
68
69QVariant NTRIPSourceTableModel::data(const QModelIndex& index, int role) const
70{
71 if (index.row() < 0 || index.row() >= _mountpoints.size()) {
72 return {};
73 }
74 const NTRIPMountpoint& mp = _mountpoints.at(index.row());
75 switch (role) {
76 case MountpointRole:
77 return mp.mountpoint;
78 case IdentifierRole:
79 return mp.identifier;
80 case FormatRole:
81 return mp.format;
83 return mp.formatDetails;
84 case CarrierRole:
85 return mp.carrier;
86 case NavSystemRole:
87 return mp.navSystem;
88 case NetworkRole:
89 return mp.network;
90 case CountryRole:
91 return mp.country;
92 case LatitudeRole:
93 return mp.latitude;
94 case LongitudeRole:
95 return mp.longitude;
96 case NmeaRole:
97 return mp.nmea;
98 case SolutionRole:
99 return mp.solution;
100 case GeneratorRole:
101 return mp.generator;
102 case CompressionRole:
103 return mp.compression;
105 return mp.authentication;
106 case FeeRole:
107 return mp.fee;
108 case BitrateRole:
109 return mp.bitrate;
110 case DistanceKmRole:
111 return mp.distanceKm;
112 default:
113 return {};
114 }
115}
116
117QHash<int, QByteArray> NTRIPSourceTableModel::roleNames() const
118{
119 return {
120 {MountpointRole, "mountpoint"},
121 {IdentifierRole, "identifier"},
122 {FormatRole, "format"},
123 {FormatDetailsRole, "formatDetails"},
124 {CarrierRole, "carrier"},
125 {NavSystemRole, "navSystem"},
126 {NetworkRole, "network"},
127 {CountryRole, "country"},
128 {LatitudeRole, "latitude"},
129 {LongitudeRole, "longitude"},
130 {NmeaRole, "nmea"},
131 {SolutionRole, "solution"},
132 {GeneratorRole, "generator"},
133 {CompressionRole, "compression"},
134 {AuthenticationRole, "authentication"},
135 {FeeRole, "fee"},
136 {BitrateRole, "bitrate"},
137 {DistanceKmRole, "distanceKm"},
138 };
139}
140
142{
143 beginResetModel();
144 _mountpoints.clear();
145
146 const QStringList lines = raw.split('\n');
147 for (const QString& line : lines) {
148 const QString trimmed = line.trimmed();
149 if (trimmed.isEmpty() || trimmed.startsWith(QStringLiteral("ENDSOURCETABLE"))) {
150 continue;
151 }
153 if (NTRIPMountpoint::fromSourceTableLine(trimmed, mp)) {
154 _mountpoints.append(mp);
155 }
156 }
157
158 endResetModel();
159 emit countChanged();
160}
161
162void NTRIPSourceTableModel::updateDistances(const QGeoCoordinate& from)
163{
164 for (NTRIPMountpoint& mp : _mountpoints) {
165 mp.updateDistance(from);
166 }
168}
169
171{
172 if (_mountpoints.size() < 2) {
173 return;
174 }
175
176 // Distance ordering: known distances ascending, unknown (negative) last.
177 const auto less = [](const NTRIPMountpoint& a, const NTRIPMountpoint& b) {
178 if (a.distanceKm < 0 && b.distanceKm < 0)
179 return false;
180 if (a.distanceKm < 0)
181 return false; // a unknown → sorts after known b
182 if (b.distanceKm < 0)
183 return true; // b unknown → known a sorts before
184 return a.distanceKm < b.distanceKm;
185 };
186
187 beginResetModel();
188 std::stable_sort(_mountpoints.begin(), _mountpoints.end(), less);
189 endResetModel();
190 // No countChanged() here: a sort reorders rows but never changes the count.
191}
192
194{
195 if (_mountpoints.isEmpty()) {
196 return;
197 }
198 beginResetModel();
199 _mountpoints.clear();
200 endResetModel();
201 emit countChanged();
202}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QHash< int, QByteArray > roleNames() const override
QVariant data(const QModelIndex &index, int role) const override
void updateDistances(const QGeoCoordinate &from)
NTRIPSourceTableModel(QObject *parent=nullptr)
void parseSourceTable(const QString &raw)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void updateDistance(const QGeoCoordinate &from)
static bool fromSourceTableLine(const QString &line, NTRIPMountpoint &out)