Normalize zero-based firmware satellite indices
This commit is contained in:
@@ -224,8 +224,9 @@ without logging out.
|
|||||||
positions are propagated from the cached ephemeris, then smoothly interpolated at 10 FPS.
|
positions are propagated from the cached ephemeris, then smoothly interpolated at 10 FPS.
|
||||||
- The 3D Earth tab includes a `RINEX Guncelle` button for an immediate manual refresh. Its status
|
- The 3D Earth tab includes a `RINEX Guncelle` button for an immediate manual refresh. Its status
|
||||||
line shows the system-local time of the last successful download or cache load.
|
line shows the system-local time of the last successful download or cache load.
|
||||||
- Complete UART channel snapshots such as `tracked satellites=5 prns=[...]` replace the previous
|
- Complete UART channel snapshots such as `tracked satellites=5 prn_indices=[...]` replace the
|
||||||
connected-PRN set, so satellites that were lost no longer remain green.
|
previous connected-PRN set, so satellites that were lost no longer remain green. Firmware
|
||||||
|
channel indices are zero-based and are normalized for display (`0` is GPS PRN `G01`).
|
||||||
- RINEX text is parsed once per download and retained as compact ephemeris records. The static
|
- RINEX text is parsed once per download and retained as compact ephemeris records. The static
|
||||||
globe is cached between camera changes, reducing CPU and allocation load during orbit animation.
|
globe is cached between camera changes, reducing CPU and allocation load during orbit animation.
|
||||||
- The globe uses an embedded Natural Earth coastline mask with terrain-like land colouring,
|
- The globe uses an embedded Natural Earth coastline mask with terrain-like land colouring,
|
||||||
|
|||||||
+22
-8
@@ -234,10 +234,11 @@ QSet<QString> LocationParser::parseGpsPrns(const QString &line)
|
|||||||
QSet<QString> result;
|
QSet<QString> result;
|
||||||
const auto addPrn = [&result](QString value, bool zeroBased = false) {
|
const auto addPrn = [&result](QString value, bool zeroBased = false) {
|
||||||
value = value.trimmed().toUpper();
|
value = value.trimmed().toUpper();
|
||||||
if (value.startsWith(QLatin1Char('G'))) value.remove(0, 1);
|
const bool explicitGpsPrn = value.startsWith(QLatin1Char('G'));
|
||||||
|
if (explicitGpsPrn) value.remove(0, 1);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
int number = value.toInt(&ok);
|
int number = value.toInt(&ok);
|
||||||
if (ok && zeroBased) ++number;
|
if (ok && zeroBased && !explicitGpsPrn) ++number;
|
||||||
if (ok && number >= 1 && number <= 63) {
|
if (ok && number >= 1 && number <= 63) {
|
||||||
result.insert(QStringLiteral("G%1").arg(number, 2, 10, QLatin1Char('0')));
|
result.insert(QStringLiteral("G%1").arg(number, 2, 10, QLatin1Char('0')));
|
||||||
}
|
}
|
||||||
@@ -249,18 +250,31 @@ QSet<QString> LocationParser::parseGpsPrns(const QString &line)
|
|||||||
auto gpsMatches = gpsToken.globalMatch(line);
|
auto gpsMatches = gpsToken.globalMatch(line);
|
||||||
while (gpsMatches.hasNext()) addPrn(gpsMatches.next().captured(QStringLiteral("prn")));
|
while (gpsMatches.hasNext()) addPrn(gpsMatches.next().captured(QStringLiteral("prn")));
|
||||||
|
|
||||||
static const QRegularExpression labeledList(
|
// Current firmware versions called their zero-based hardware channel values
|
||||||
QStringLiteral(R"((?<label>\bPRNS?\b|\bSVS?\b|\bSVNS?\b|\bSVIDS?\b)\s*(?:=|:|->)?\s*[\[(]?\s*(?<list>(?:G?\d{1,2})(?:\s*[,;/| ]\s*G?\d{1,2})*)\s*[\])]?)"),
|
// "prns" in complete tracking snapshots. Keep accepting those messages while
|
||||||
|
// newer firmware uses the unambiguous "prn_indices" label.
|
||||||
|
static const QRegularExpression legacyTrackingIndices(
|
||||||
|
QStringLiteral(R"(\btracked\s+satellites\s*=\s*\d+\s+prns?\s*=)"),
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
static const QRegularExpression number(QStringLiteral(R"(G?(\d{1,2}))"),
|
const bool legacyZeroBasedPrns = legacyTrackingIndices.match(line).hasMatch();
|
||||||
|
|
||||||
|
static const QRegularExpression labeledList(
|
||||||
|
QStringLiteral(R"((?<label>\bPRN[_ -]?INDICES\b|\bPRNS?\b|\bSVS?\b|\bSVNS?\b|\bSVIDS?\b)\s*(?:=|:|->)?\s*[\[(]?\s*(?<list>(?:G?\d{1,2})(?:\s*[,;/| ]\s*G?\d{1,2})*)\s*[\])]?)"),
|
||||||
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
|
static const QRegularExpression number(QStringLiteral(R"(G?\d{1,2})"),
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
auto listMatches = labeledList.globalMatch(line);
|
auto listMatches = labeledList.globalMatch(line);
|
||||||
while (listMatches.hasNext()) {
|
while (listMatches.hasNext()) {
|
||||||
const QRegularExpressionMatch listMatch = listMatches.next();
|
const QRegularExpressionMatch listMatch = listMatches.next();
|
||||||
const bool zeroBased = listMatch.captured(QStringLiteral("label")).startsWith(
|
QString label = listMatch.captured(QStringLiteral("label")).toUpper();
|
||||||
QStringLiteral("SVN"), Qt::CaseInsensitive);
|
label.remove(QLatin1Char('_'));
|
||||||
|
label.remove(QLatin1Char('-'));
|
||||||
|
label.remove(QLatin1Char(' '));
|
||||||
|
const bool zeroBased = label.startsWith(QStringLiteral("SVN"))
|
||||||
|
|| label == QStringLiteral("PRNINDICES")
|
||||||
|
|| (legacyZeroBasedPrns && label.startsWith(QStringLiteral("PRN")));
|
||||||
auto values = number.globalMatch(listMatch.captured(QStringLiteral("list")));
|
auto values = number.globalMatch(listMatch.captured(QStringLiteral("list")));
|
||||||
while (values.hasNext()) addPrn(values.next().captured(1), zeroBased);
|
while (values.hasNext()) addPrn(values.next().captured(0), zeroBased);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -520,7 +520,7 @@ void MainWindow::handleSerialLine(const QString &line)
|
|||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
static const QRegularExpression trackingSnapshotRegex(
|
static const QRegularExpression trackingSnapshotRegex(
|
||||||
QStringLiteral(
|
QStringLiteral(
|
||||||
R"(\btracked\s+satellites\s*=\s*\d+\s+(?:prns?|svns?)\s*=\s*\[[^\]]*\])"),
|
R"(\btracked\s+satellites\s*=\s*\d+\s+(?:prn[_ -]?indices|prns?|svns?)\s*=\s*\[[^\]]*\])"),
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
const bool solveStarted = solveStartRegex.match(line.trimmed()).hasMatch();
|
const bool solveStarted = solveStartRegex.match(line.trimmed()).hasMatch();
|
||||||
const bool trackingSnapshot = trackingSnapshotRegex.match(line).hasMatch();
|
const bool trackingSnapshot = trackingSnapshotRegex.match(line).hasMatch();
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ int main(int argc, char **argv)
|
|||||||
assert(sideSplitter != nullptr);
|
assert(sideSplitter != nullptr);
|
||||||
assert(sideSplitter->orientation() == Qt::Vertical);
|
assert(sideSplitter->orientation() == Qt::Vertical);
|
||||||
|
|
||||||
sendLine(window, QStringLiteral("[TRK] tracked satellites=2 prns=[3,8]"));
|
sendLine(window, QStringLiteral("[TRK] tracked satellites=2 prn_indices=[2,7]"));
|
||||||
assert(map != nullptr);
|
assert(map != nullptr);
|
||||||
auto *globe = window.findChild<GlobeWidget *>();
|
auto *globe = window.findChild<GlobeWidget *>();
|
||||||
assert(globe != nullptr);
|
assert(globe != nullptr);
|
||||||
assert(globe->observedPrns()
|
assert(globe->observedPrns()
|
||||||
== QSet<QString>({QStringLiteral("G03"), QStringLiteral("G08")}));
|
== QSet<QString>({QStringLiteral("G03"), QStringLiteral("G08")}));
|
||||||
sendLine(window, QStringLiteral("[TRK] tracked satellites=1 prns=[14]"));
|
sendLine(window, QStringLiteral("[TRK] tracked satellites=1 prn_indices=[13]"));
|
||||||
assert(globe->observedPrns() == QSet<QString>({QStringLiteral("G14")}));
|
assert(globe->observedPrns() == QSet<QString>({QStringLiteral("G14")}));
|
||||||
|
|
||||||
assert(QMetaObject::invokeMethod(map, "referenceLocationSelected", Qt::DirectConnection,
|
assert(QMetaObject::invokeMethod(map, "referenceLocationSelected", Qt::DirectConnection,
|
||||||
|
|||||||
@@ -186,6 +186,25 @@ int main(int argc, char **argv)
|
|||||||
assert(prns == QSet<QString>({QStringLiteral("G01"), QStringLiteral("G32")}));
|
assert(prns == QSet<QString>({QStringLiteral("G01"), QStringLiteral("G32")}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const QSet<QString> prns = LocationParser::parseGpsPrns(
|
||||||
|
QStringLiteral("[TRK] tracked satellites=3 prn_indices=[0,7,31]"));
|
||||||
|
assert(prns == QSet<QString>({QStringLiteral("G01"), QStringLiteral("G08"),
|
||||||
|
QStringLiteral("G32")}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const QSet<QString> prns = LocationParser::parseGpsPrns(
|
||||||
|
QStringLiteral("[TRK] tracked satellites=2 prns=[0,7]"));
|
||||||
|
assert(prns == QSet<QString>({QStringLiteral("G01"), QStringLiteral("G08")}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const QSet<QString> prns = LocationParser::parseGpsPrns(
|
||||||
|
QStringLiteral("[TRK] tracked satellites=2 prn_indices=[0,G08]"));
|
||||||
|
assert(prns == QSet<QString>({QStringLiteral("G01"), QStringLiteral("G08")}));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto parsed = LocationParser::parseLine(QStringLiteral(
|
const auto parsed = LocationParser::parseLine(QStringLiteral(
|
||||||
"[OK] [NAV] DOP GDOP=7.0907891622 PDOP=5.6333862175 "
|
"[OK] [NAV] DOP GDOP=7.0907891622 PDOP=5.6333862175 "
|
||||||
|
|||||||
Reference in New Issue
Block a user