2026-05-28 13:24:16 +02:00
|
|
|
|
// ─── 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;
|
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
|
/// Az aktuális mondat sorszáma
|
2026-05-28 13:24:16 +02:00
|
|
|
|
int get messageNumber => int.tryParse(fields[2]) ?? 1;
|
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
|
/// Összes látható műhold száma az adott stream-ben
|
2026-05-28 13:24:16 +02:00
|
|
|
|
int get totalSatellitesInView => int.tryParse(fields[3]) ?? 0;
|
|
|
|
|
|
|
|
|
|
|
|
/// Ez az utolsó mondat az adott rendszer GSV sorozatában?
|
|
|
|
|
|
bool get isLastMessage => messageNumber == totalMessages;
|
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
|
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}';
|
|
|
|
|
|
|
2026-05-28 13:24:16 +02:00
|
|
|
|
// ── Műholdak ebben a mondatban ───────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
/// A mondatban szereplő műholdak listája (max 4)
|
|
|
|
|
|
List<SatelliteInfo> get satellites {
|
|
|
|
|
|
final sats = <SatelliteInfo>[];
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
|
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;
|
2026-05-28 13:24:16 +02:00
|
|
|
|
|
|
|
|
|
|
if (prn != null && prn > 0) {
|
|
|
|
|
|
sats.add(SatelliteInfo(
|
|
|
|
|
|
prn: prn,
|
|
|
|
|
|
elevation: elev,
|
|
|
|
|
|
azimuth: az,
|
|
|
|
|
|
snr: snr,
|
2026-06-06 23:16:03 +02:00
|
|
|
|
constellation: constellation,
|
|
|
|
|
|
signalId: signalId,
|
2026-05-28 13:24:16 +02:00
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sats;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-06 23:16:03 +02:00
|
|
|
|
String _field(int index) {
|
|
|
|
|
|
if (index < 0 || index >= fields.length) return '';
|
|
|
|
|
|
return fields[index].trim();
|
|
|
|
|
|
}
|
2026-05-28 13:24:16 +02:00
|
|
|
|
}
|