Látható és használt műholdak számának meghatározása és megjelenítése
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user