// ─── GSV mondatelemző ────────────────────────────────────────────────────── import 'package:nmea/nmea.dart'; import 'package:terepi_seged/models/satellite_info.dart'; /// GSV — GNSS Satellites in View /// /// Formátum (max 4 műhold/mondat): /// $GPGSV,3,1,11,01,70,042,45,03,55,218,48,07,22,085,35,10,35,315,40*73 /// │ │ │ │ │ │ │ /// │ │ │ PRN El Az SNR (×4 max) /// │ │ └── összes látható műhold száma /// │ └───── ezen mondat sorszáma (1-től) /// └─────── összes GSV mondat ebben a ciklusban /// /// Több mondat alkotja az epochot: /// GPGSV (GPS) + GLGSV (GLONASS) + GAGSV (Galileo) + GBGSV (BeiDou) class Gngsv extends TalkerSentence { static const String id = 'GNGSV'; Gngsv({required super.raw}); @override bool get valid => super.valid && fields.length >= 8; // min: típus + 3 fejléc + 1×4 műhold // ── Fejléc mezők ───────────────────────────────────────────────── /// Összes GSV mondat ezen rendszerhez ebben az epochban int get totalMessages => int.tryParse(fields[1]) ?? 1; /// Az aktuális mondat sorszáma int get messageNumber => int.tryParse(fields[2]) ?? 1; /// Ö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 get satellites { final sats = []; // Minden műhold 4 mezőt foglal: PRN, eleváció, azimut, SNR // fields[4]-től kezdődnek, fields[0] = mondattípus for (int i = 0; i < 4; i++) { final base = 4 + i * 4; // Ellenőrzés: van-e elég mező if (base + 3 >= fields.length) break; 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( prn: prn, elevation: elev, azimuth: az, snr: snr, constellation: constellation, signalId: signalId, )); } } return sats; } String _field(int index) { if (index < 0 || index >= fields.length) return ''; return fields[index].trim(); } }