Látható és használt műholdak számának meghatározása és megjelenítése
This commit is contained in:
parent
9347e22843
commit
497821bb41
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -3,5 +3,9 @@
|
||||
"cmake.sourceDirectory": "${workspaceFolder}/linux/flutter",
|
||||
"editor.wordBasedSuggestions": "off",
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.selectionHighlight": false
|
||||
"editor.selectionHighlight": false,
|
||||
"cSpell.words": [
|
||||
"azimut",
|
||||
"eleváció"
|
||||
]
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:terepi_seged/models/satellite_info.dart';
|
||||
|
||||
/// GSA — GNSS DOP és aktív műholdak
|
||||
///
|
||||
@ -67,6 +68,37 @@ class Gngsa extends TalkerSentence {
|
||||
_ => 'Unknown',
|
||||
};
|
||||
|
||||
int? get systemId {
|
||||
if (fields.length <= 18) return null;
|
||||
final rawSys = fields[18].split('*').first.trim();
|
||||
if (rawSys.isEmpty) return null;
|
||||
return int.tryParse(rawSys);
|
||||
}
|
||||
|
||||
GnssConstellation get constellation {
|
||||
switch (systemId) {
|
||||
case 1:
|
||||
return GnssConstellation.gps;
|
||||
case 2:
|
||||
return GnssConstellation.glonass;
|
||||
case 3:
|
||||
return GnssConstellation.galileo;
|
||||
case 4:
|
||||
return GnssConstellation.beidou;
|
||||
case 5:
|
||||
return GnssConstellation.qzss;
|
||||
default:
|
||||
return SatelliteInfo.constellationFromTalker(talkerId);
|
||||
}
|
||||
}
|
||||
|
||||
String get constellationKey => constellation.name;
|
||||
|
||||
List<String> get activeSatelliteKeys =>
|
||||
activeSatellitePrns.map((prn) => '$constellationKey:$prn').toList();
|
||||
|
||||
int get usedSatelliteCount => activeSatellitePrns.length;
|
||||
|
||||
double _parseDouble(String? s) {
|
||||
if (s == null || s.isEmpty) return 0.0;
|
||||
return double.tryParse(s) ?? 0.0;
|
||||
|
||||
@ -29,21 +29,57 @@ class Gngsv extends TalkerSentence {
|
||||
/// Összes GSV mondat ezen rendszerhez ebben az epochban
|
||||
int get totalMessages => int.tryParse(fields[1]) ?? 1;
|
||||
|
||||
/// Ezen mondat sorszáma (1-től indul)
|
||||
/// Az aktuális mondat sorszáma
|
||||
int get messageNumber => int.tryParse(fields[2]) ?? 1;
|
||||
|
||||
/// Összes látható műhold száma (az epochban, nem csak ebben a mondatban)
|
||||
/// Összes látható műhold száma az adott stream-ben
|
||||
int get totalSatellitesInView => int.tryParse(fields[3]) ?? 0;
|
||||
|
||||
/// Ez az utolsó mondat az adott rendszer GSV sorozatában?
|
||||
bool get isLastMessage => messageNumber == totalMessages;
|
||||
|
||||
String get talkerId => raw.length >= 3 ? raw.substring(1, 3) : 'GN';
|
||||
|
||||
GnssConstellation get constellation =>
|
||||
SatelliteInfo.constellationFromTalker(talkerId);
|
||||
|
||||
String get systemName => switch (constellation) {
|
||||
GnssConstellation.gps => 'GPS',
|
||||
GnssConstellation.glonass => 'GLONASS',
|
||||
GnssConstellation.galileo => 'Galileo',
|
||||
GnssConstellation.beidou => 'BeiDou',
|
||||
GnssConstellation.qzss => 'QZSS',
|
||||
GnssConstellation.sbas => 'SBAS',
|
||||
GnssConstellation.navic => 'NavIC',
|
||||
GnssConstellation.mixed => 'Mixed',
|
||||
GnssConstellation.unknown => 'Unknown',
|
||||
};
|
||||
|
||||
/// Opcionális NMEA Signal ID
|
||||
///
|
||||
/// Header: 4 mezo
|
||||
/// Minden muhold: 4 mezo
|
||||
/// Ha marad +1 mezo, az a signalId
|
||||
int? get signalId {
|
||||
final payloadCount = fields.length - 4;
|
||||
if (payloadCount <= 0) return null;
|
||||
|
||||
final hasSignalId = payloadCount % 4 == 1;
|
||||
if (!hasSignalId) return null;
|
||||
|
||||
final rawSignal = fields.last.split('*').first.trim();
|
||||
if (rawSignal.isEmpty) return null;
|
||||
return int.tryParse(rawSignal);
|
||||
}
|
||||
|
||||
/// Egy stream kulcsa: ugyanazon talker, ugyanazon signal
|
||||
String get streamKey => '$talkerId:${signalId ?? -1}';
|
||||
|
||||
// ── Műholdak ebben a mondatban ───────────────────────────────────
|
||||
|
||||
/// A mondatban szereplő műholdak listája (max 4)
|
||||
List<SatelliteInfo> get satellites {
|
||||
final sats = <SatelliteInfo>[];
|
||||
final system = systemName;
|
||||
|
||||
// Minden műhold 4 mezőt foglal: PRN, eleváció, azimut, SNR
|
||||
// fields[4]-től kezdődnek, fields[0] = mondattípus
|
||||
@ -53,13 +89,10 @@ class Gngsv extends TalkerSentence {
|
||||
// Ellenőrzés: van-e elég mező
|
||||
if (base + 3 >= fields.length) break;
|
||||
|
||||
final prn = int.tryParse(fields[base] ?? '');
|
||||
final elev = int.tryParse(fields[base + 1] ?? '') ?? 0;
|
||||
final az = int.tryParse(fields[base + 2] ?? '') ?? 0;
|
||||
|
||||
// SNR az utolsó mezőben checksum lehet (*XX)
|
||||
final snrRaw = (fields[base + 3] ?? '').split('*').first;
|
||||
final snr = int.tryParse(snrRaw) ?? 0;
|
||||
final prn = int.tryParse(_field(base));
|
||||
final elev = int.tryParse(_field(base + 1)) ?? 0;
|
||||
final az = int.tryParse(_field(base + 2)) ?? 0;
|
||||
final snr = int.tryParse(_field(base + 3).split('*').first) ?? 0;
|
||||
|
||||
if (prn != null && prn > 0) {
|
||||
sats.add(SatelliteInfo(
|
||||
@ -67,7 +100,8 @@ class Gngsv extends TalkerSentence {
|
||||
elevation: elev,
|
||||
azimuth: az,
|
||||
snr: snr,
|
||||
system: system,
|
||||
constellation: constellation,
|
||||
signalId: signalId,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -75,18 +109,8 @@ class Gngsv extends TalkerSentence {
|
||||
return sats;
|
||||
}
|
||||
|
||||
// ── Rendszer azonosítás ───────────────────────────────────────────
|
||||
|
||||
/// Talker azonosító a nyers mondatból
|
||||
String get talkerId => raw.length >= 3 ? raw.substring(1, 3) : 'GN';
|
||||
|
||||
/// Rendszer neve a talker azonosítóból
|
||||
String get systemName => switch (talkerId) {
|
||||
'GP' => 'GPS',
|
||||
'GL' => 'GLONASS',
|
||||
'GA' => 'Galileo',
|
||||
'GB' || 'BD' => 'BeiDou',
|
||||
'GN' => 'Mixed',
|
||||
_ => 'Unknown',
|
||||
};
|
||||
String _field(int index) {
|
||||
if (index < 0 || index >= fields.length) return '';
|
||||
return fields[index].trim();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
enum GnssConstellation {
|
||||
gps,
|
||||
glonass,
|
||||
galileo,
|
||||
beidou,
|
||||
qzss,
|
||||
sbas,
|
||||
navic,
|
||||
mixed,
|
||||
unknown,
|
||||
}
|
||||
|
||||
// ─── SatelliteInfo modell ──────────────────────────────────────────────────
|
||||
|
||||
/// Egyetlen látható műhold adatai — a skyplot és az SNR diagram alapja.
|
||||
@ -16,24 +28,49 @@ class SatelliteInfo {
|
||||
/// Jelerősség dB-Hz-ben (0–99, 0 = nem tracking)
|
||||
final int snr;
|
||||
|
||||
/// Rendszer neve: GPS, GLONASS, Galileo, BeiDou, Mixed
|
||||
final String system;
|
||||
/// A műhold konstellációja
|
||||
final GnssConstellation constellation;
|
||||
|
||||
const SatelliteInfo({
|
||||
required this.prn,
|
||||
// Opcionális: NMEA signal ID (pl. L1/L2/E1/...)
|
||||
final int? signalId;
|
||||
|
||||
const SatelliteInfo(
|
||||
{required this.prn,
|
||||
required this.elevation,
|
||||
required this.azimuth,
|
||||
required this.snr,
|
||||
required this.system,
|
||||
});
|
||||
required this.constellation,
|
||||
this.signalId});
|
||||
|
||||
String get system => switch (constellation) {
|
||||
GnssConstellation.gps => 'GPS',
|
||||
GnssConstellation.glonass => 'GLONASS',
|
||||
GnssConstellation.galileo => 'Galileo',
|
||||
GnssConstellation.beidou => 'BeiDou',
|
||||
GnssConstellation.qzss => 'QZSS',
|
||||
GnssConstellation.sbas => 'SBAS',
|
||||
GnssConstellation.navic => 'NavIC',
|
||||
GnssConstellation.mixed => 'Mixed',
|
||||
GnssConstellation.unknown => 'Unknown',
|
||||
};
|
||||
|
||||
/// Egyedi kulcs ugyanazon konstellacio azonos muholdjahoz
|
||||
String get satelliteKey => '${constellation.name}:$prn';
|
||||
|
||||
/// Egyedi kulcs ugyanazon signal streamhez
|
||||
String get signalKey => '${constellation.name}:$prn:${signalId ?? -1}';
|
||||
|
||||
/// Human-readable sav/frekvencia becsles signalId alapjan
|
||||
String get bandLabel => _bandLabel(constellation, signalId);
|
||||
|
||||
// ── Minősítési segédek ────────────────────────────────────────────
|
||||
|
||||
/// Erős jel — fixben megbízhatóan részt vesz
|
||||
bool get isStrong => snr >= 40;
|
||||
|
||||
/// Használható jel — fixben részt vesz
|
||||
bool get isUsed => snr >= 30;
|
||||
/// Jelszint alapjan varhatoan hasznalhato jel.
|
||||
/// A valodi "used in fix" allapotot a GSA mondatok alapjan allapitsuk meg.
|
||||
bool get hasUsableSignal => snr >= 30;
|
||||
|
||||
/// Gyenge de látható jel
|
||||
bool get isWeak => snr > 0 && snr < 30;
|
||||
@ -61,6 +98,128 @@ class SatelliteInfo {
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'SatelliteInfo($system PRN$prn elev=$elevation° az=$azimuth° snr=$snr)';
|
||||
String toString() {
|
||||
final signal = signalId == null ? '-' : signalId.toString();
|
||||
return 'SatelliteInfo($system PRN$prn elev=$elevation az=$azimuth snr=$snr signal=$signal band=$bandLabel)';
|
||||
}
|
||||
|
||||
static GnssConstellation constellationFromTalker(String talkerId) {
|
||||
switch (talkerId) {
|
||||
case 'GP':
|
||||
return GnssConstellation.gps;
|
||||
case 'GL':
|
||||
return GnssConstellation.glonass;
|
||||
case 'GA':
|
||||
return GnssConstellation.galileo;
|
||||
case 'GB':
|
||||
case 'BD':
|
||||
return GnssConstellation.beidou;
|
||||
case 'GQ':
|
||||
case 'QZ':
|
||||
return GnssConstellation.qzss;
|
||||
case 'GI':
|
||||
case 'IN':
|
||||
return GnssConstellation.navic;
|
||||
case 'GN':
|
||||
return GnssConstellation.mixed;
|
||||
default:
|
||||
return GnssConstellation.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static String _bandLabel(GnssConstellation constellation, int? signalId) {
|
||||
if (signalId == null) return 'Unknown';
|
||||
|
||||
switch (constellation) {
|
||||
case GnssConstellation.gps:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'L1 C/A';
|
||||
case 5:
|
||||
return 'L2C';
|
||||
case 6:
|
||||
return 'L5';
|
||||
default:
|
||||
return 'GPS sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.glonass:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'G1';
|
||||
case 3:
|
||||
return 'G2';
|
||||
default:
|
||||
return 'GLO sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.galileo:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'E1';
|
||||
case 6:
|
||||
return 'E5a';
|
||||
case 7:
|
||||
return 'E5b';
|
||||
case 8:
|
||||
return 'E5 AltBOC';
|
||||
default:
|
||||
return 'GAL sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.beidou:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'B1I';
|
||||
case 3:
|
||||
return 'B2I';
|
||||
case 5:
|
||||
return 'B1C';
|
||||
case 7:
|
||||
return 'B2a';
|
||||
default:
|
||||
return 'BDS sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.qzss:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'L1 C/A';
|
||||
case 4:
|
||||
return 'L1S';
|
||||
case 5:
|
||||
return 'L2C';
|
||||
case 6:
|
||||
return 'L5';
|
||||
default:
|
||||
return 'QZSS sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.sbas:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'L1';
|
||||
case 6:
|
||||
return 'L5';
|
||||
default:
|
||||
return 'SBAS sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.navic:
|
||||
switch (signalId) {
|
||||
case 1:
|
||||
return 'L5';
|
||||
case 2:
|
||||
return 'S';
|
||||
default:
|
||||
return 'NavIC sig $signalId';
|
||||
}
|
||||
|
||||
case GnssConstellation.mixed:
|
||||
return 'Mixed sig $signalId';
|
||||
|
||||
case GnssConstellation.unknown:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
// lib/services/gnss/gnss_service.dart
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:googleapis/privateca/v1.dart';
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngsa.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngsv.dart';
|
||||
import 'package:terepi_seged/models/satellite_info.dart';
|
||||
import 'package:terepi_seged/services/gnss/gnss_device_service.dart';
|
||||
import 'package:terepi_seged/services/gnss/phone_gps_connection.dart';
|
||||
|
||||
@ -25,6 +26,17 @@ class GnssService extends GetxService {
|
||||
final connectionState = GnssConnectionState.disconnected.obs;
|
||||
final activeConnectionType = Rxn<GnssConnectionType>();
|
||||
|
||||
final Map<String, List<SatelliteInfo>> _gsvBuffer = {};
|
||||
final Map<String, DateTime> _gsvUpdatedAt = {};
|
||||
static const Duration _gsvTtl = Duration(seconds: 4);
|
||||
|
||||
final Map<String, List<int>> _gsaPrnBuffer = {};
|
||||
final Map<String, DateTime> _gsaUpdatedAt = {};
|
||||
static const Duration _gsaTtl = Duration(seconds: 4);
|
||||
|
||||
final activePrns = <int>[].obs;
|
||||
final activeSatelliteKeys = <String>[].obs;
|
||||
|
||||
// ── GGA adatok ────────────────────────────────────────────────────
|
||||
final latitude = 0.0.obs;
|
||||
final longitude = 0.0.obs;
|
||||
@ -33,7 +45,11 @@ class GnssService extends GetxService {
|
||||
final gpsQuality = 0.obs;
|
||||
final utcFix = ''.obs;
|
||||
final satelliteCount = 0.obs;
|
||||
final gsaUsedSatelliteCount = 0.obs;
|
||||
|
||||
final hdop = 0.0.obs;
|
||||
final pdop = 0.0.obs;
|
||||
final vdop = 0.0.obs;
|
||||
|
||||
// Utolsó nyers GGA sor — NtripService küldi vissza a casternek
|
||||
final lastGgaLine = ''.obs;
|
||||
@ -46,12 +62,37 @@ class GnssService extends GetxService {
|
||||
// ── RMC adatok (dátum/idő) ────────────────────────────────────────
|
||||
final gpsDateTime = DateTime(2000).obs;
|
||||
|
||||
final satellites = <SatelliteInfo>[].obs;
|
||||
final fixType = 0.obs;
|
||||
|
||||
Timer? _reconnectTimer;
|
||||
bool _isClosing = false;
|
||||
|
||||
// Segédmező: van-e érvényes adat
|
||||
bool get hasValidData => gpsQuality.value > 0;
|
||||
|
||||
// Számított DOP minősítés (segéd getter-ek)
|
||||
String get hdopRating => _dopRating(hdop.value);
|
||||
String get vdopRating => _dopRating(vdop.value);
|
||||
String get pdopRating => _dopRating(pdop.value);
|
||||
|
||||
String _dopRating(double dop) {
|
||||
if (dop <= 0) return '–';
|
||||
if (dop <= 1) return 'Ideális';
|
||||
if (dop <= 2) return 'Kiváló';
|
||||
if (dop <= 5) return 'Jó';
|
||||
if (dop <= 10) return 'Közepes';
|
||||
if (dop <= 20) return 'Gyenge';
|
||||
return 'Rossz';
|
||||
}
|
||||
|
||||
int get totalVisibleSatellites => satellites.length;
|
||||
int get totalUsedSatellites => gsaUsedSatelliteCount.value;
|
||||
bool isSatelliteUsed(int prn) => activePrns.contains(prn);
|
||||
bool isSatelliteUsedSatellite(SatelliteInfo sat) {
|
||||
return activeSatelliteKeys.contains(sat.satelliteKey);
|
||||
}
|
||||
|
||||
// ── Belső ─────────────────────────────────────────────────────────
|
||||
final NmeaDecoder _decoder = NmeaDecoder();
|
||||
StreamSubscription? _nmeaSub;
|
||||
@ -74,7 +115,9 @@ class GnssService extends GetxService {
|
||||
_decoder
|
||||
..registerTalkerSentence('GGA', (l) => Gngga(raw: l))
|
||||
..registerTalkerSentence('GST', (l) => Gngst(raw: l))
|
||||
..registerTalkerSentence('RMC', (l) => Gnrmc(raw: l));
|
||||
..registerTalkerSentence('RMC', (l) => Gnrmc(raw: l))
|
||||
..registerTalkerSentence('GSA', (l) => Gngsa(raw: l))
|
||||
..registerTalkerSentence('GSV', (l) => Gngsv(raw: l));
|
||||
}
|
||||
|
||||
// ── Kapcsolódás ───────────────────────────────────────────────────
|
||||
@ -189,6 +232,21 @@ class GnssService extends GetxService {
|
||||
_connection?.dispose();
|
||||
_connection = null;
|
||||
connectionState.value = GnssConnectionState.disconnected;
|
||||
|
||||
_gsaPrnBuffer.clear();
|
||||
_gsaUpdatedAt.clear();
|
||||
_gsvBuffer.clear();
|
||||
_gsvUpdatedAt.clear();
|
||||
activePrns.clear();
|
||||
activeSatelliteKeys.clear();
|
||||
satellites.clear();
|
||||
satelliteCount.value = 0;
|
||||
gsaUsedSatelliteCount.value = 0;
|
||||
pdop.value = 0;
|
||||
hdop.value = 0;
|
||||
vdop.value = 0;
|
||||
fixType.value = 0;
|
||||
lastGgaLine.value = '';
|
||||
}
|
||||
|
||||
Future<void> disconnect() => _disconnect();
|
||||
@ -213,6 +271,10 @@ class GnssService extends GetxService {
|
||||
_parseGst(line);
|
||||
} else if (sentenceType == 'RMC' && hasValidData) {
|
||||
_parseRmc(line);
|
||||
} else if (sentenceType == 'GSA' && hasValidData) {
|
||||
_parseGsa(line);
|
||||
} else if (sentenceType == 'GSV' && hasValidData) {
|
||||
_parseGsv(line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,8 +290,9 @@ class GnssService extends GetxService {
|
||||
geoidSeparation.value = s.geoidSeparation;
|
||||
gpsQuality.value = s.gpsQualityIndicator;
|
||||
utcFix.value = s.utcOfPositionFix;
|
||||
// A GGA altal riportalt, fixben hasznalt muholdszam.
|
||||
satelliteCount.value = s.numberOfSvsInUse;
|
||||
hdop.value = s.hdop;
|
||||
//hdop.value = s.hdop;
|
||||
lastGgaLine.value = line;
|
||||
_utcTime = s.utcOfPositionFix;
|
||||
|
||||
@ -275,6 +338,91 @@ class GnssService extends GetxService {
|
||||
}
|
||||
}
|
||||
|
||||
void _parseGsa(String line) {
|
||||
try {
|
||||
final s = _decoder.decode(line);
|
||||
if (s == null || !s.valid || s is! Gngsa) return;
|
||||
|
||||
final key = s.constellationKey;
|
||||
_gsaPrnBuffer[key] = s.activeSatellitePrns;
|
||||
_gsaUpdatedAt[key] = DateTime.now().toUtc();
|
||||
_purgeStaleGsa();
|
||||
|
||||
final satKeys = <String>{};
|
||||
for (final entry in _gsaPrnBuffer.entries) {
|
||||
for (final prn in entry.value) {
|
||||
satKeys.add('${entry.key}:$prn');
|
||||
}
|
||||
}
|
||||
|
||||
activeSatelliteKeys.assignAll(satKeys);
|
||||
activePrns
|
||||
.assignAll(satKeys.map((k) => int.parse(k.split(':').last)).toSet());
|
||||
|
||||
gsaUsedSatelliteCount.value = activeSatelliteKeys.length;
|
||||
|
||||
if (s.pdop > 0 && (pdop.value == 0 || s.pdop <= pdop.value)) {
|
||||
pdop.value = s.pdop;
|
||||
hdop.value = s.hdop;
|
||||
vdop.value = s.vdop;
|
||||
fixType.value = s.fixType;
|
||||
}
|
||||
} catch (e) {
|
||||
print('GSA parse error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _parseGsv(String line) {
|
||||
try {
|
||||
final s = _decoder.decode(line);
|
||||
if (s == null || !s.valid || s is! Gngsv) return;
|
||||
|
||||
final streamKey = s.streamKey;
|
||||
|
||||
if (s.messageNumber == 1) {
|
||||
_gsvBuffer[streamKey] = <SatelliteInfo>[];
|
||||
}
|
||||
|
||||
_gsvBuffer[streamKey] = [
|
||||
...?_gsvBuffer[streamKey],
|
||||
...s.satellites,
|
||||
];
|
||||
|
||||
_gsvUpdatedAt[streamKey] = DateTime.now().toUtc();
|
||||
_purgeStaleGsv();
|
||||
|
||||
if (s.isLastMessage) {
|
||||
_updateSatelliteList();
|
||||
}
|
||||
} catch (e) {
|
||||
print('GSV parse error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Összes rendszer pufferéből összerakja a teljes műholdlistát.
|
||||
/// Akkor hívódik, amikor egy rendszer utolsó GSV mondata megérkezett.
|
||||
void _updateSatelliteList() {
|
||||
_purgeStaleGsv();
|
||||
|
||||
final allSats = _gsvBuffer.values.expand((list) => list).toList();
|
||||
if (allSats.isEmpty) return;
|
||||
|
||||
final bySatellite = <String, SatelliteInfo>{};
|
||||
|
||||
for (final sat in allSats) {
|
||||
final key = sat.satelliteKey;
|
||||
final prev = bySatellite[key];
|
||||
|
||||
// Ugyanaz a műhold tobb signal stream-ben is johet.
|
||||
// A legerősebb SNR-es bejegyzest tartjuk meg.
|
||||
if (prev == null || sat.snr > prev.snr) {
|
||||
bySatellite[key] = sat;
|
||||
}
|
||||
}
|
||||
|
||||
satellites.assignAll(bySatellite.values);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() async {
|
||||
_isClosing = true;
|
||||
@ -334,4 +482,32 @@ class GnssService extends GetxService {
|
||||
unawaited(reconnect());
|
||||
});
|
||||
}
|
||||
|
||||
void _purgeStaleGsa() {
|
||||
final cutoff = DateTime.now().toUtc().subtract(_gsaTtl);
|
||||
|
||||
final staleKeys = _gsaUpdatedAt.entries
|
||||
.where((e) => e.value.isBefore(cutoff))
|
||||
.map((e) => e.key)
|
||||
.toList(growable: false);
|
||||
|
||||
for (final key in staleKeys) {
|
||||
_gsaUpdatedAt.remove(key);
|
||||
_gsaPrnBuffer.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
void _purgeStaleGsv() {
|
||||
final cutoff = DateTime.now().toUtc().subtract(_gsvTtl);
|
||||
|
||||
final staleKeys = _gsvUpdatedAt.entries
|
||||
.where((e) => e.value.isBefore(cutoff))
|
||||
.map((e) => e.key)
|
||||
.toList(growable: false);
|
||||
|
||||
for (final key in staleKeys) {
|
||||
_gsvUpdatedAt.remove(key);
|
||||
_gsvBuffer.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:get/get_state_manager/get_state_manager.dart';
|
||||
import 'package:get/state_manager.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
import 'package:terepi_seged/pages/shell/presentations/controllers/shell_controller.dart';
|
||||
import 'package:terepi_seged/services/gnss/gnss_service.dart';
|
||||
import 'package:terepi_seged/services/ntrip_service.dart';
|
||||
import 'package:terepi_seged/widgets/gnss_status_chip.dart';
|
||||
import 'package:terepi_seged/widgets/map_mode_menu_anchor.dart';
|
||||
@ -78,13 +79,12 @@ class ShellMapAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
children: [
|
||||
GnssTextStatusChip(),
|
||||
Row(children: [
|
||||
const Text('V:', style: TextStyle(fontSize: 12)),
|
||||
const Icon(Icons.satellite_alt, size: 12),
|
||||
SizedBox(width: 2),
|
||||
Text(controller.verticalAccuracyText,
|
||||
Text(
|
||||
'${GnssService.to.totalVisibleSatellites}/${GnssService.to.totalUsedSatellites}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
_errorColor(controller.gpsAltitudeError.value),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFeatures: const [FontFeature.tabularFigures()]))
|
||||
])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user