From 9347e228431f7851cb884f91dd9e5a0ddb1c378b Mon Sep 17 00:00:00 2001 From: "torok.istvan" Date: Thu, 28 May 2026 13:24:16 +0200 Subject: [PATCH] =?UTF-8?q?=C3=9Aj=20nmea=20mondatok:=20gsa,=20gsv,=20m?= =?UTF-8?q?=C5=B1hold=20info=20oszt=C3=A1ly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/gnss_sentences/gngsa.dart | 74 +++++++++++++++ lib/gnss_sentences/gngsv.dart | 92 +++++++++++++++++++ lib/models/satellite_info.dart | 66 +++++++++++++ .../presentations/views/map_survey_view.dart | 4 + 4 files changed, 236 insertions(+) create mode 100644 lib/gnss_sentences/gngsa.dart create mode 100644 lib/gnss_sentences/gngsv.dart create mode 100644 lib/models/satellite_info.dart diff --git a/lib/gnss_sentences/gngsa.dart b/lib/gnss_sentences/gngsa.dart new file mode 100644 index 0000000..9910644 --- /dev/null +++ b/lib/gnss_sentences/gngsa.dart @@ -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 get activeSatellitePrns { + final prns = []; + 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; + } +} diff --git a/lib/gnss_sentences/gngsv.dart b/lib/gnss_sentences/gngsv.dart new file mode 100644 index 0000000..181c648 --- /dev/null +++ b/lib/gnss_sentences/gngsv.dart @@ -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 get satellites { + final sats = []; + 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', + }; +} diff --git a/lib/models/satellite_info.dart b/lib/models/satellite_info.dart new file mode 100644 index 0000000..18efb21 --- /dev/null +++ b/lib/models/satellite_info.dart @@ -0,0 +1,66 @@ +import 'dart:math' as math; + +// ─── SatelliteInfo modell ────────────────────────────────────────────────── + +/// Egyetlen látható műhold adatai — a skyplot és az SNR diagram alapja. +class SatelliteInfo { + /// Műhold PRN/SVID azonosítója + final int prn; + + /// Eleváció fokban (0–90°, 90 = zenit) + final int elevation; + + /// Azimut fokban (0–359°, 0/360 = É, 90 = K) + final int azimuth; + + /// Jelerősség dB-Hz-ben (0–99, 0 = nem tracking) + final int snr; + + /// Rendszer neve: GPS, GLONASS, Galileo, BeiDou, Mixed + final String system; + + const SatelliteInfo({ + required this.prn, + required this.elevation, + required this.azimuth, + required this.snr, + required this.system, + }); + + // ── Minősítési segédek ──────────────────────────────────────────── + + /// Erős jel — fixben megbízhatóan részt vesz + bool get isStrong => snr >= 40; + + /// Használható jel — fixben részt vesz + bool get isUsed => snr >= 30; + + /// Gyenge de látható jel + bool get isWeak => snr > 0 && snr < 30; + + /// Egyáltalán látható-e (snr > 0) + bool get isVisible => snr > 0; + + // ── Polár koordináta számítás a skyplot CustomPainter-hez ──────── + + /// Normalizált sugár (0.0 = zenit, 1.0 = horizont) + double get polarRadius => 1.0 - (elevation / 90.0); + + /// Szög radiánban a polár koordinátához + /// (azimut → matematikai szög: É=felső, K=jobb) + double get polarAngleRad => (azimuth - 90) * math.pi / 180.0; + + /// Polár koordináta pixel pozíciójának kiszámítása + /// [center] a kör középpontja, [radius] a horizont kör sugara + ({double dx, double dy}) toOffset( + double centerX, double centerY, double radius) { + return ( + dx: centerX + radius * polarRadius * math.cos(polarAngleRad), + dy: centerY + radius * polarRadius * math.sin(polarAngleRad), + ); + } + + @override + String toString() => + 'SatelliteInfo($system PRN$prn elev=$elevation° az=$azimuth° snr=$snr)'; +} diff --git a/lib/pages/map_survey/presentations/views/map_survey_view.dart b/lib/pages/map_survey/presentations/views/map_survey_view.dart index fc8e1bb..deb8d5c 100644 --- a/lib/pages/map_survey/presentations/views/map_survey_view.dart +++ b/lib/pages/map_survey/presentations/views/map_survey_view.dart @@ -26,6 +26,10 @@ class MapSurveyView extends GetView { onZoomIn: controller.mapZoomIn, onZoomOut: controller.mapZoomOut, onCenterOnGps: controller.isMapMoveToCenter, + layers: [ + Obx(() => + MarkerLayer(markers: controller.currentLocationMarker.toList())) + ], ), Positioned( top: 8,