Új nmea mondatok: gsa, gsv, műhold info osztály

This commit is contained in:
2026-05-28 13:24:16 +02:00
parent 3d4c937b71
commit 9347e22843
4 changed files with 236 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
import 'package:nmea/nmea.dart';
/// 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',
};
double _parseDouble(String? s) {
if (s == null || s.isEmpty) return 0.0;
return double.tryParse(s) ?? 0.0;
}
}
+92
View File
@@ -0,0 +1,92 @@
// ─── 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;
/// Ezen mondat sorszáma (1-től indul)
int get messageNumber => int.tryParse(fields[2]) ?? 1;
/// Összes látható műhold száma (az epochban, nem csak ebben a mondatban)
int get totalSatellitesInView => int.tryParse(fields[3]) ?? 0;
/// Ez az utolsó mondat az adott rendszer GSV sorozatában?
bool get isLastMessage => messageNumber == totalMessages;
// ── Műholdak ebben a mondatban ───────────────────────────────────
/// A mondatban szereplő műholdak listája (max 4)
List<SatelliteInfo> get satellites {
final sats = <SatelliteInfo>[];
final system = systemName;
// 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(fields[base] ?? '');
final elev = int.tryParse(fields[base + 1] ?? '') ?? 0;
final az = int.tryParse(fields[base + 2] ?? '') ?? 0;
// SNR az utolsó mezőben checksum lehet (*XX)
final snrRaw = (fields[base + 3] ?? '').split('*').first;
final snr = int.tryParse(snrRaw) ?? 0;
if (prn != null && prn > 0) {
sats.add(SatelliteInfo(
prn: prn,
elevation: elev,
azimuth: az,
snr: snr,
system: system,
));
}
}
return sats;
}
// ── Rendszer azonosítás ───────────────────────────────────────────
/// Talker azonosító a nyers mondatból
String get talkerId => raw.length >= 3 ? raw.substring(1, 3) : 'GN';
/// Rendszer neve a talker azonosítóból
String get systemName => switch (talkerId) {
'GP' => 'GPS',
'GL' => 'GLONASS',
'GA' => 'Galileo',
'GB' || 'BD' => 'BeiDou',
'GN' => 'Mixed',
_ => 'Unknown',
};
}