GnssService javítás, refraktálás

This commit is contained in:
torok.istvan 2026-05-19 00:10:41 +02:00
parent 24a6b7d513
commit 20a8078f3c
3 changed files with 89 additions and 23 deletions

View File

@ -129,6 +129,7 @@ class MapSurveyController extends GetxController {
// Telefon GPS fallback // Telefon GPS fallback
StreamSubscription<Position>? _phoneLocationSub; StreamSubscription<Position>? _phoneLocationSub;
StreamSubscription<void>? _gnssUpdateSub;
// UI controllerek // UI controllerek
final pointIdController = TextEditingController(); final pointIdController = TextEditingController();
@ -161,7 +162,9 @@ class MapSurveyController extends GetxController {
}; };
// GnssService pozíció változás EOV, marker, NTRIP GGA // GnssService pozíció változás EOV, marker, NTRIP GGA
ever(_gnss.gpsQuality, (_) => _onGnssUpdate()); _gnssUpdateSub = _gnss.onDataUpdated.listen((_) {
_onGnssUpdate();
});
// Supabase realtime // Supabase realtime
_supaChannel = Supabase.instance.client _supaChannel = Supabase.instance.client
@ -194,6 +197,7 @@ class MapSurveyController extends GetxController {
super.onClose(); super.onClose();
_phoneLocationSub?.cancel(); _phoneLocationSub?.cancel();
_gnssUpdateSub?.cancel();
await _supaChannel?.unsubscribe(); await _supaChannel?.unsubscribe();
pointIdController.dispose(); pointIdController.dispose();

View File

@ -4,6 +4,7 @@ import 'dart:typed_data';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:googleapis/privateca/v1.dart';
import 'package:nmea/nmea.dart'; import 'package:nmea/nmea.dart';
import 'package:terepi_seged/services/gnss/gnss_device_service.dart'; import 'package:terepi_seged/services/gnss/gnss_device_service.dart';
import 'package:terepi_seged/services/gnss/phone_gps_connection.dart'; import 'package:terepi_seged/services/gnss/phone_gps_connection.dart';
@ -45,6 +46,9 @@ class GnssService extends GetxService {
// RMC adatok (dátum/idő) // RMC adatok (dátum/idő)
final gpsDateTime = DateTime(2000).obs; final gpsDateTime = DateTime(2000).obs;
Timer? _reconnectTimer;
bool _isClosing = false;
// Segédmező: van-e érvényes adat // Segédmező: van-e érvényes adat
bool get hasValidData => gpsQuality.value > 0; bool get hasValidData => gpsQuality.value > 0;
@ -54,11 +58,16 @@ class GnssService extends GetxService {
StreamSubscription? _stateSub; StreamSubscription? _stateSub;
StreamSubscription<Position>? _positionSub; StreamSubscription<Position>? _positionSub;
final _updateController = StreamController<void>.broadcast();
Stream<void> get onDataUpdated => _updateController.stream;
String _utcTime = ''; String _utcTime = '';
String _utcDate = ''; String _utcDate = '';
bool _intentionalDisconnection = false; bool _intentionalDisconnection = false;
String _digitsOnly(String value) => value.replaceAll(RegExp(r'[^0-9]'), '');
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -106,14 +115,17 @@ class GnssService extends GetxService {
break; break;
case GnssConnectionType.btSerial: case GnssConnectionType.btSerial:
await connectBtSerial(device.address); await connectBtSerial(device.address);
break;
case GnssConnectionType.ble: case GnssConnectionType.ble:
await connectBle(device.address); await connectBle(device.address);
break;
case GnssConnectionType.phoneGps: case GnssConnectionType.phoneGps:
await _disconnect(); await _disconnect();
_connection = PhoneGpsConnection(); _connection = PhoneGpsConnection();
//connectionState.value = GnssConnectionState.disconnected; //connectionState.value = GnssConnectionState.disconnected;
activeConnectionType.value = GnssConnectionType.phoneGps; activeConnectionType.value = GnssConnectionType.phoneGps;
await _doConnect('iternal'); await _doConnect('iternal');
break;
} }
} }
@ -127,9 +139,13 @@ class GnssService extends GetxService {
Future<void> _doConnect(String address) async { Future<void> _doConnect(String address) async {
_stateSub = _connection!.connectionState.listen((s) { _stateSub = _connection!.connectionState.listen((s) {
connectionState.value = s; connectionState.value = s;
if (s == GnssConnectionState.disconnected && if (s == GnssConnectionState.connected) {
_intentionalDisconnection == false) { _reconnectTimer?.cancel();
Future.delayed(const Duration(seconds: 3), () => reconnect()); return;
}
if (s == GnssConnectionState.disconnected) {
_scheduleReconnect();
} }
}); });
@ -141,6 +157,8 @@ class GnssService extends GetxService {
} }
void _parseDirectPosition(Position pos) { void _parseDirectPosition(Position pos) {
if (_isClosing) return;
latitude.value = pos.latitude; latitude.value = pos.latitude;
longitude.value = pos.longitude; longitude.value = pos.longitude;
altitude.value = pos.altitude; altitude.value = pos.altitude;
@ -151,17 +169,22 @@ class GnssService extends GetxService {
// A Geolocator a pontosságot (accuracy) méterben adja vissza // A Geolocator a pontosságot (accuracy) méterben adja vissza
latitudeError.value = pos.accuracy; latitudeError.value = pos.accuracy;
longitudeError.value = pos.accuracy; longitudeError.value = pos.accuracy;
altitudeError.value = pos.altitudeAccuracy ?? 0.0; altitudeError.value = pos.altitudeAccuracy;
// Az RMC (idő) adatait is beállítjuk a telefon idejéből // Az RMC (idő) adatait is beállítjuk a telefon idejéből
gpsDateTime.value = pos.timestamp; gpsDateTime.value = pos.timestamp;
_emitUpdate();
} }
Future<void> _disconnect() async { Future<void> _disconnect() async {
_intentionalDisconnection = true; _intentionalDisconnection = true;
_reconnectTimer?.cancel();
await _nmeaSub?.cancel(); await _nmeaSub?.cancel();
await _positionSub?.cancel(); await _positionSub?.cancel();
await _stateSub?.cancel(); await _stateSub?.cancel();
await _connection?.disconnect(); await _connection?.disconnect();
_connection?.dispose(); _connection?.dispose();
_connection = null; _connection = null;
@ -180,11 +203,15 @@ class GnssService extends GetxService {
// NMEA parsing // NMEA parsing
void _parseNmea(String line) { void _parseNmea(String line) {
if (line.startsWith('\$GNGGA') || line.startsWith('\$GPGGA')) { if (_isClosing || line.length < 6 || !line.startsWith(r'$')) return;
final sentenceType = line.substring(3, 6);
if (sentenceType == 'GGA') {
_parseGga(line); _parseGga(line);
} else if (line.startsWith('\$GNGST') && hasValidData) { } else if (sentenceType == 'GST' && hasValidData) {
_parseGst(line); _parseGst(line);
} else if (line.startsWith('\$GNRMC') && hasValidData) { } else if (sentenceType == 'RMC' && hasValidData) {
_parseRmc(line); _parseRmc(line);
} }
} }
@ -205,7 +232,11 @@ class GnssService extends GetxService {
hdop.value = s.hdop; hdop.value = s.hdop;
lastGgaLine.value = line; lastGgaLine.value = line;
_utcTime = s.utcOfPositionFix; _utcTime = s.utcOfPositionFix;
} catch (_) {}
_emitUpdate();
} catch (e) {
print('GGA parsing error: $e');
}
} }
void _parseGst(String line) { void _parseGst(String line) {
@ -215,30 +246,45 @@ class GnssService extends GetxService {
latitudeError.value = s.latitudeError; latitudeError.value = s.latitudeError;
longitudeError.value = s.longitudeError; longitudeError.value = s.longitudeError;
altitudeError.value = s.heightError; altitudeError.value = s.heightError;
} catch (_) {} } catch (e) {
print('GST parse error: $e');
}
} }
void _parseRmc(String line) { void _parseRmc(String line) {
try { try {
final s = _decoder.decode(line); final s = _decoder.decode(line);
if (s == null || !s.valid || s is! Gnrmc) return; if (s == null || !s.valid || s is! Gnrmc) return;
_utcDate = s.date; _utcDate = s.date;
if (_utcDate.length >= 6 && _utcTime.length >= 6) { final date = _digitsOnly(_utcDate);
gpsDateTime.value = DateTime( final time = _digitsOnly(s.utcOfPositionFix);
2000 + int.parse('${_utcDate[4]}${_utcDate[5]}'),
int.parse('${_utcDate[2]}${_utcDate[3]}'), if (date.length >= 6 && time.length >= 6) {
int.parse('${_utcDate[0]}${_utcDate[1]}'), gpsDateTime.value = DateTime.utc(
int.parse('${_utcTime[0]}${_utcTime[1]}'), 2000 + int.parse(date.substring(4, 6)),
int.parse('${_utcTime[2]}${_utcTime[3]}'), int.parse(date.substring(2, 4)),
int.parse('${_utcTime[4]}${_utcTime[5]}'), int.parse(date.substring(0, 2)),
int.parse(time.substring(0, 2)),
int.parse(time.substring(2, 4)),
int.parse(time.substring(4, 6)),
); );
} }
} catch (_) {} } catch (e) {
print('RMC parse error: $e');
}
} }
@override @override
void onClose() { void onClose() async {
_disconnect(); _isClosing = true;
await _disconnect();
if (!_updateController.isClosed) {
_updateController.close();
}
super.onClose(); super.onClose();
} }
@ -273,4 +319,19 @@ class GnssService extends GetxService {
print('Nem sikerült lekérni a kezdőpozíciót: $e'); print('Nem sikerült lekérni a kezdőpozíciót: $e');
} }
} }
void _emitUpdate() {
if (_isClosing || _updateController.isClosed) return;
_updateController.add(null);
}
void _scheduleReconnect() {
if (_intentionalDisconnection || _isClosing) return;
if (_reconnectTimer?.isActive ?? false) return;
_reconnectTimer = Timer(const Duration(seconds: 3), () {
if (_intentionalDisconnection || _isClosing) return;
unawaited(reconnect());
});
}
} }

View File

@ -4,6 +4,7 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
import 'package:terepi_seged/services/ntrip_service.dart'; import 'package:terepi_seged/services/ntrip_service.dart';
import '../services/gnss/gnss_service.dart'; import '../services/gnss/gnss_service.dart';
@ -35,7 +36,7 @@ class CoordinatePanel extends StatelessWidget {
}); });
/// Gyors factory MapSurveyController mezőiből. /// Gyors factory MapSurveyController mezőiből.
factory CoordinatePanel.fromController(dynamic ctrl) { factory CoordinatePanel.fromController(MapSurveyController ctrl) {
final y = RxDouble(0.0); final y = RxDouble(0.0);
final x = RxDouble(0.0); final x = RxDouble(0.0);
// Figyeli az eov változást és frissíti Y/X-et // Figyeli az eov változást és frissíti Y/X-et
@ -45,7 +46,7 @@ class CoordinatePanel extends StatelessWidget {
}); });
return CoordinatePanel( return CoordinatePanel(
eovY: y, eovY: y,
eovX: x, eovX: ctrl.eov.value.X.obs,
horError: ctrl.gpsLatitudeError as RxDouble, horError: ctrl.gpsLatitudeError as RxDouble,
vertError: ctrl.gpsAltitudeError as RxDouble, vertError: ctrl.gpsAltitudeError as RxDouble,
altitudeMsl: ctrl.gpsAltitude as RxDouble, altitudeMsl: ctrl.gpsAltitude as RxDouble,