MobilApp/lib/gnss_sentences/gngsv.dart

117 lines
4.0 KiB
Dart
Raw Normal View History

// ─── 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<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;
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();
}
}