2026-05-28 13:24:16 +02:00
|
|
|
import 'package:nmea/nmea.dart';
|
2026-06-06 23:16:03 +02:00
|
|
|
import 'package:terepi_seged/models/satellite_info.dart';
|
2026-05-28 13:24:16 +02:00
|
|
|
|
|
|
|
|
/// GSA — GNSS DOP és aktív műholdak
|
|
|
|
|
///
|
|
|
|
|
/// Formátum:
|
|
|
|
|
/// $GNGSA,A,3,01,02,03,04,05,06,07,08,09,10,11,12,2.1,1.2,1.7*XX
|
|
|
|
|
/// │ │ └─────────── 12 db PRN ────────┘ │ │ │
|
|
|
|
|
/// │ └── Fix típus: 1=nincs, 2=2D, 3=3D │ │ └─ VDOP
|
|
|
|
|
/// └──── Mód: M=kézi, A=auto │ └───── HDOP
|
|
|
|
|
/// └───────── PDOP
|
|
|
|
|
///
|
|
|
|
|
/// NMEA 4.1+: opcionális rendszer azonosító (fields[18])
|
|
|
|
|
/// Minden rendszerhez érkezik egy-egy GSA mondat.
|
|
|
|
|
class Gngsa extends TalkerSentence {
|
|
|
|
|
static const String id = 'GNGSA';
|
|
|
|
|
|
|
|
|
|
Gngsa({required super.raw});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
bool get valid => super.valid && fields.length >= 18;
|
|
|
|
|
|
|
|
|
|
/// Módválasztás: 'M' = kézi, 'A' = automatikus
|
|
|
|
|
String get selectionMode => fields[1];
|
|
|
|
|
|
|
|
|
|
/// Fix típus: 1 = nincs, 2 = 2D, 3 = 3D
|
|
|
|
|
int get fixType => int.tryParse(fields[2]) ?? 1;
|
|
|
|
|
|
|
|
|
|
/// Fixben használt műholdak PRN számai (max 12, üres mezők kihagyva)
|
|
|
|
|
List<int> get activeSatellitePrns {
|
|
|
|
|
final prns = <int>[];
|
|
|
|
|
for (int i = 3; i <= 14; i++) {
|
|
|
|
|
if (i >= fields.length) break;
|
|
|
|
|
final prn = int.tryParse(fields[i]);
|
|
|
|
|
if (prn != null && prn > 0) prns.add(prn);
|
|
|
|
|
}
|
|
|
|
|
return prns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// PDOP — 3D pozíció pontossági szorzó
|
|
|
|
|
double get pdop => _parseDouble(fields[15]);
|
|
|
|
|
|
|
|
|
|
/// HDOP — vízszintes pontossági szorzó
|
|
|
|
|
double get hdop => _parseDouble(fields[16]);
|
|
|
|
|
|
|
|
|
|
/// VDOP — függőleges pontossági szorzó
|
|
|
|
|
/// Az utolsó mező checksum előtti részét veszi
|
|
|
|
|
double get vdop {
|
|
|
|
|
if (fields.length <= 17) return 0.0;
|
|
|
|
|
return _parseDouble(fields[17].split('*').first);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// GDOP számítása: √(PDOP² + TDOP²)
|
|
|
|
|
/// Közelítés TDOP nélkül: GDOP ≈ PDOP * 1.1
|
|
|
|
|
double get gdopApprox => pdop * 1.1;
|
|
|
|
|
|
|
|
|
|
/// Talker azonosító — rendszer meghatározásához
|
|
|
|
|
/// GP=GPS, GL=GLONASS, GA=Galileo, GB/BD=BeiDou, GN=vegyes
|
|
|
|
|
String get talkerId => raw.length >= 3 ? raw.substring(1, 3) : 'GN';
|
|
|
|
|
|
|
|
|
|
/// Rendszer neve a talker alapján
|
|
|
|
|
String get systemName => switch (talkerId) {
|
|
|
|
|
'GP' => 'GPS',
|
|
|
|
|
'GL' => 'GLONASS',
|
|
|
|
|
'GA' => 'Galileo',
|
|
|
|
|
'GB' || 'BD' => 'BeiDou',
|
|
|
|
|
'GN' => 'Mixed',
|
|
|
|
|
_ => 'Unknown',
|
|
|
|
|
};
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
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;
|
|
|
|
|
|
2026-05-28 13:24:16 +02:00
|
|
|
double _parseDouble(String? s) {
|
|
|
|
|
if (s == null || s.isEmpty) return 0.0;
|
|
|
|
|
return double.tryParse(s) ?? 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|