GNSS szervíz refraktorálás, hibajavítás, PhoneGpsConnection osztály
This commit is contained in:
parent
ee0f90e247
commit
24a6b7d513
@ -3,11 +3,9 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
// import 'package:flutter_map_geojson/flutter_map_geojson.dart';
|
// import 'package:flutter_map_geojson/flutter_map_geojson.dart';
|
||||||
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
||||||
@ -16,25 +14,16 @@ import 'package:get/get.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
// import 'package:location/location.dart';
|
// import 'package:location/location.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:nmea/nmea.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart'
|
|
||||||
as permission_handler;
|
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
import 'package:terepi_seged/controls/geoid_grid.dart';
|
import 'package:terepi_seged/controls/geoid_grid.dart';
|
||||||
import 'package:terepi_seged/eov/convert_coordinate.dart';
|
import 'package:terepi_seged/eov/convert_coordinate.dart';
|
||||||
import 'package:terepi_seged/eov/eov.dart';
|
import 'package:terepi_seged/eov/eov.dart';
|
||||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
|
||||||
import 'package:terepi_seged/gnss_sentences/gngst.dart';
|
|
||||||
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
|
|
||||||
import 'package:terepi_seged/models/measured_point.dart';
|
|
||||||
import 'package:terepi_seged/models/point_to_measure.dart';
|
import 'package:terepi_seged/models/point_to_measure.dart';
|
||||||
import 'package:terepi_seged/models/point_with_description_model.dart';
|
import 'package:terepi_seged/models/point_with_description_model.dart';
|
||||||
import 'package:proj4dart/proj4dart.dart' as proj4;
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:terepi_seged/pages/map_survey/presentations/views/measured_points_table_dialog.dart';
|
import 'package:terepi_seged/pages/map_survey/presentations/views/measured_points_table_dialog.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:terepi_seged/services/coord_converter_service.dart';
|
import 'package:terepi_seged/services/coord_converter_service.dart';
|
||||||
import 'package:terepi_seged/services/gnss/gnss_connection.dart';
|
import 'package:terepi_seged/services/gnss/gnss_connection.dart';
|
||||||
import 'package:terepi_seged/services/gnss/gnss_device_service.dart';
|
import 'package:terepi_seged/services/gnss/gnss_device_service.dart';
|
||||||
@ -195,7 +184,6 @@ class MapSurveyController extends GetxController {
|
|||||||
void onReady() async {
|
void onReady() async {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
|
|
||||||
await _initPhoneGps();
|
|
||||||
await _initStorage();
|
await _initStorage();
|
||||||
|
|
||||||
gpsHeightController.text = '1.8';
|
gpsHeightController.text = '1.8';
|
||||||
@ -255,11 +243,6 @@ class MapSurveyController extends GetxController {
|
|||||||
currentLongitude.value = lon;
|
currentLongitude.value = lon;
|
||||||
_updateCurrentLocationMarker();
|
_updateCurrentLocationMarker();
|
||||||
|
|
||||||
// Telefon GPS leállítása ha külső GPS van
|
|
||||||
if (_phoneLocationSub != null) {
|
|
||||||
_stopPhoneGps();
|
|
||||||
}
|
|
||||||
|
|
||||||
// NTRIP GGA küldés
|
// NTRIP GGA küldés
|
||||||
NtripService.to.onGgaReceived(
|
NtripService.to.onGgaReceived(
|
||||||
_gnss.lastGgaLine.value,
|
_gnss.lastGgaLine.value,
|
||||||
@ -271,66 +254,6 @@ class MapSurveyController extends GetxController {
|
|||||||
// Telefon GPS fallback
|
// Telefon GPS fallback
|
||||||
// ─────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _initPhoneGps() async {
|
|
||||||
// Egyszeri kezdő pozíció
|
|
||||||
try {
|
|
||||||
final last = await Geolocator.getLastKnownPosition();
|
|
||||||
if (last != null) {
|
|
||||||
currentLatitude.value = last.latitude;
|
|
||||||
currentLongitude.value = last.longitude;
|
|
||||||
GnssService.to.latitude.value = last.latitude;
|
|
||||||
GnssService.to.longitude.value = last.longitude;
|
|
||||||
GnssService.to.gpsQuality.value = 1;
|
|
||||||
mapController.move(
|
|
||||||
LatLng(last.latitude, last.longitude),
|
|
||||||
currentZoom.value,
|
|
||||||
);
|
|
||||||
_updateCurrentLocationMarker();
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// Folyamatos stream ha nincs külső GPS
|
|
||||||
if (_gnss.connectionState.value != GnssConnectionState.connected) {
|
|
||||||
await _startPhoneGps();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _startPhoneGps() async {
|
|
||||||
if (_phoneLocationSub != null) return;
|
|
||||||
|
|
||||||
final permission = await Geolocator.checkPermission();
|
|
||||||
if (permission == LocationPermission.denied ||
|
|
||||||
permission == LocationPermission.deniedForever) return;
|
|
||||||
|
|
||||||
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
|
||||||
if (!serviceEnabled) return;
|
|
||||||
|
|
||||||
_phoneLocationSub = Geolocator.getPositionStream(
|
|
||||||
locationSettings: const LocationSettings(
|
|
||||||
accuracy: LocationAccuracy.high,
|
|
||||||
distanceFilter: 0,
|
|
||||||
),
|
|
||||||
).listen((pos) {
|
|
||||||
// Leáll ha közben csatlakozott a külső GPS
|
|
||||||
if (_gnss.connectionState.value == GnssConnectionState.connected) {
|
|
||||||
_stopPhoneGps();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentLatitude.value = pos.latitude;
|
|
||||||
currentLongitude.value = pos.longitude;
|
|
||||||
GnssService.to.latitude.value = pos.latitude;
|
|
||||||
GnssService.to.longitude.value = pos.longitude;
|
|
||||||
GnssService.to.gpsQuality.value = 1;
|
|
||||||
_updateCurrentLocationMarker();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _stopPhoneGps() {
|
|
||||||
_phoneLocationSub?.cancel();
|
|
||||||
_phoneLocationSub = null;
|
|
||||||
GnssService.to.gpsQuality.value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────
|
||||||
// Térkép vezérlők
|
// Térkép vezérlők
|
||||||
// ─────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
// lib/services/gnss/ble_gnss_connection.dart
|
// lib/services/gnss/ble_gnss_connection.dart
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'gnss_connection.dart';
|
import 'gnss_connection.dart';
|
||||||
import 'gnss_device_service.dart';
|
import 'gnss_device_service.dart';
|
||||||
|
|
||||||
@ -24,6 +27,7 @@ class BleGnssConnection implements GnssConnection {
|
|||||||
BluetoothDevice? _device;
|
BluetoothDevice? _device;
|
||||||
StreamSubscription? _notifySub;
|
StreamSubscription? _notifySub;
|
||||||
String _lineBuffer = '';
|
String _lineBuffer = '';
|
||||||
|
BluetoothCharacteristic? _rxChar;
|
||||||
|
|
||||||
final _nmeaController = StreamController<String>.broadcast();
|
final _nmeaController = StreamController<String>.broadcast();
|
||||||
final _stateController = StreamController<GnssConnectionState>.broadcast();
|
final _stateController = StreamController<GnssConnectionState>.broadcast();
|
||||||
@ -46,6 +50,10 @@ class BleGnssConnection implements GnssConnection {
|
|||||||
autoConnect: false,
|
autoConnect: false,
|
||||||
license: License.free);
|
license: License.free);
|
||||||
|
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
await _device!.requestMtu(512);
|
||||||
|
}
|
||||||
|
|
||||||
// Kapcsolat megszakadás figyelése
|
// Kapcsolat megszakadás figyelése
|
||||||
_device!.connectionState.listen((state) {
|
_device!.connectionState.listen((state) {
|
||||||
if (state == BluetoothConnectionState.disconnected) {
|
if (state == BluetoothConnectionState.disconnected) {
|
||||||
@ -68,6 +76,10 @@ class BleGnssConnection implements GnssConnection {
|
|||||||
orElse: () => throw Exception('TX char nem található: $txCharUuid'),
|
orElse: () => throw Exception('TX char nem található: $txCharUuid'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_rxChar = gnssService.characteristics.firstWhere((c) =>
|
||||||
|
c.characteristicUuid.str.toLowerCase() ==
|
||||||
|
_nusRxCharUuid.toLowerCase());
|
||||||
|
|
||||||
// Notify engedélyezése
|
// Notify engedélyezése
|
||||||
await txChar.setNotifyValue(true);
|
await txChar.setNotifyValue(true);
|
||||||
|
|
||||||
@ -109,4 +121,14 @@ class BleGnssConnection implements GnssConnection {
|
|||||||
_nmeaController.close();
|
_nmeaController.close();
|
||||||
_stateController.close();
|
_stateController.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendData(Uint8List data) {
|
||||||
|
if (_rxChar == null) return;
|
||||||
|
|
||||||
|
_rxChar!.write(data, withoutResponse: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Position> get positionStream => const Stream.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'gnss_connection.dart';
|
import 'gnss_connection.dart';
|
||||||
import 'gnss_device_service.dart';
|
import 'gnss_device_service.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
class BtSerialGnssConnection implements GnssConnection {
|
class BtSerialGnssConnection implements GnssConnection {
|
||||||
@override
|
@override
|
||||||
@ -11,6 +14,7 @@ class BtSerialGnssConnection implements GnssConnection {
|
|||||||
|
|
||||||
BluetoothConnection? _connection;
|
BluetoothConnection? _connection;
|
||||||
String _messageBuffer = '';
|
String _messageBuffer = '';
|
||||||
|
String _lineBuffer = '';
|
||||||
|
|
||||||
final _nmeaController = StreamController<String>.broadcast();
|
final _nmeaController = StreamController<String>.broadcast();
|
||||||
final _stateController = StreamController<GnssConnectionState>.broadcast();
|
final _stateController = StreamController<GnssConnectionState>.broadcast();
|
||||||
@ -48,41 +52,24 @@ class BtSerialGnssConnection implements GnssConnection {
|
|||||||
|
|
||||||
// A meglévő _onDataReceived logika változatlanul
|
// A meglévő _onDataReceived logika változatlanul
|
||||||
void _onData(Uint8List data) {
|
void _onData(Uint8List data) {
|
||||||
int backspacesCounter = 0;
|
_lineBuffer += utf8.decode(data, allowMalformed: true);
|
||||||
for (var byte in data) {
|
|
||||||
if (byte == 8 || byte == 127) backspacesCounter++;
|
final lines = const LineSplitter().convert(_lineBuffer);
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.length - 1; i++) {
|
||||||
|
final sentence = lines[i].trim();
|
||||||
|
if (sentence.isNotEmpty) {
|
||||||
|
_nmeaController.add(sentence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint8List buffer = Uint8List(data.length - backspacesCounter);
|
if (_lineBuffer.endsWith('\n')) {
|
||||||
int bufferIndex = buffer.length;
|
if (lines.isNotEmpty && lines.last.trim().isNotEmpty) {
|
||||||
backspacesCounter = 0;
|
_nmeaController.add(lines.last.trim());
|
||||||
|
}
|
||||||
for (int i = data.length - 1; i >= 0; i--) {
|
_lineBuffer = '';
|
||||||
if (data[i] == 8 || data[i] == 127) {
|
|
||||||
backspacesCounter++;
|
|
||||||
} else if (backspacesCounter > 0) {
|
|
||||||
backspacesCounter--;
|
|
||||||
} else {
|
} else {
|
||||||
buffer[--bufferIndex] = data[i];
|
_lineBuffer = lines.isNotEmpty ? lines.last : _lineBuffer;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final dataString = String.fromCharCodes(buffer);
|
|
||||||
final index = buffer.indexOf(13); // \r
|
|
||||||
|
|
||||||
String sentence;
|
|
||||||
if (~index != 0) {
|
|
||||||
sentence = _messageBuffer + dataString.substring(0, index);
|
|
||||||
_messageBuffer = dataString.substring(index);
|
|
||||||
} else {
|
|
||||||
_messageBuffer += dataString;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Soronként kibocsátjuk
|
|
||||||
for (final line in sentence.split('\n')) {
|
|
||||||
final trimmed = line.trim();
|
|
||||||
if (trimmed.isNotEmpty) _nmeaController.add(trimmed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,4 +83,7 @@ class BtSerialGnssConnection implements GnssConnection {
|
|||||||
void sendData(Uint8List data) {
|
void sendData(Uint8List data) {
|
||||||
_connection?.output.add(data);
|
_connection?.output.add(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Position> get positionStream => const Stream.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
// lib/services/gnss/gnss_connection.dart
|
// lib/services/gnss/gnss_connection.dart
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
|
||||||
import 'gnss_device_service.dart';
|
import 'gnss_device_service.dart';
|
||||||
|
|
||||||
enum GnssConnectionState { disconnected, connecting, connected, error }
|
enum GnssConnectionState { disconnected, connecting, connected, error }
|
||||||
@ -9,6 +13,7 @@ abstract class GnssConnection {
|
|||||||
|
|
||||||
/// NMEA sorok stream-je — mindkét implementáció ezt adja
|
/// NMEA sorok stream-je — mindkét implementáció ezt adja
|
||||||
Stream<String> get nmeaLines;
|
Stream<String> get nmeaLines;
|
||||||
|
Stream<Position> get positionStream;
|
||||||
|
|
||||||
/// Kapcsolat állapota
|
/// Kapcsolat állapota
|
||||||
Stream<GnssConnectionState> get connectionState;
|
Stream<GnssConnectionState> get connectionState;
|
||||||
@ -17,4 +22,6 @@ abstract class GnssConnection {
|
|||||||
Future<void> disconnect();
|
Future<void> disconnect();
|
||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
|
void sendData(Uint8List data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
enum GnssConnectionType { btSerial, ble, phoneGps }
|
enum GnssConnectionType { none, btSerial, ble, phoneGps }
|
||||||
|
|
||||||
class GnssDevice {
|
class GnssDevice {
|
||||||
final String address;
|
final String address;
|
||||||
@ -23,6 +23,7 @@ class GnssDevice {
|
|||||||
GnssConnectionType.btSerial => 'BT Serial',
|
GnssConnectionType.btSerial => 'BT Serial',
|
||||||
GnssConnectionType.ble => 'BLE',
|
GnssConnectionType.ble => 'BLE',
|
||||||
GnssConnectionType.phoneGps => 'Telefon GPS',
|
GnssConnectionType.phoneGps => 'Telefon GPS',
|
||||||
|
GnssConnectionType.none => 'Kikapcsolva',
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
|||||||
@ -2,9 +2,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.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 '../../gnss_sentences/gngga.dart';
|
import '../../gnss_sentences/gngga.dart';
|
||||||
import '../../gnss_sentences/gngst.dart';
|
import '../../gnss_sentences/gngst.dart';
|
||||||
@ -50,9 +52,13 @@ class GnssService extends GetxService {
|
|||||||
final NmeaDecoder _decoder = NmeaDecoder();
|
final NmeaDecoder _decoder = NmeaDecoder();
|
||||||
StreamSubscription? _nmeaSub;
|
StreamSubscription? _nmeaSub;
|
||||||
StreamSubscription? _stateSub;
|
StreamSubscription? _stateSub;
|
||||||
|
StreamSubscription<Position>? _positionSub;
|
||||||
|
|
||||||
String _utcTime = '';
|
String _utcTime = '';
|
||||||
String _utcDate = '';
|
String _utcDate = '';
|
||||||
|
|
||||||
|
bool _intentionalDisconnection = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@ -86,16 +92,28 @@ class GnssService extends GetxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Eszközváltás — GnssDevicePicker hívja.
|
/// Eszközváltás — GnssDevicePicker hívja.
|
||||||
Future<void> onDeviceChanged(GnssDevice device) async {
|
Future<void> onDeviceChanged(GnssDevice? device) async {
|
||||||
|
if (device == null) {
|
||||||
|
await _disconnect();
|
||||||
|
activeConnectionType.value = GnssConnectionType.none;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (device.type) {
|
switch (device.type) {
|
||||||
|
case GnssConnectionType.none:
|
||||||
|
await _disconnect();
|
||||||
|
activeConnectionType.value = GnssConnectionType.none;
|
||||||
|
break;
|
||||||
case GnssConnectionType.btSerial:
|
case GnssConnectionType.btSerial:
|
||||||
await connectBtSerial(device.address);
|
await connectBtSerial(device.address);
|
||||||
case GnssConnectionType.ble:
|
case GnssConnectionType.ble:
|
||||||
await connectBle(device.address);
|
await connectBle(device.address);
|
||||||
case GnssConnectionType.phoneGps:
|
case GnssConnectionType.phoneGps:
|
||||||
await _disconnect();
|
await _disconnect();
|
||||||
connectionState.value = GnssConnectionState.disconnected;
|
_connection = PhoneGpsConnection();
|
||||||
|
//connectionState.value = GnssConnectionState.disconnected;
|
||||||
activeConnectionType.value = GnssConnectionType.phoneGps;
|
activeConnectionType.value = GnssConnectionType.phoneGps;
|
||||||
|
await _doConnect('iternal');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +127,40 @@ 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 &&
|
||||||
|
_intentionalDisconnection == false) {
|
||||||
|
Future.delayed(const Duration(seconds: 3), () => reconnect());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_nmeaSub = _connection!.nmeaLines.listen(_parseNmea);
|
_nmeaSub = _connection!.nmeaLines.listen(_parseNmea);
|
||||||
|
_positionSub = _connection!.positionStream.listen(_parseDirectPosition);
|
||||||
|
|
||||||
|
_intentionalDisconnection = false;
|
||||||
await _connection!.connect(address);
|
await _connection!.connect(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _parseDirectPosition(Position pos) {
|
||||||
|
latitude.value = pos.latitude;
|
||||||
|
longitude.value = pos.longitude;
|
||||||
|
altitude.value = pos.altitude;
|
||||||
|
|
||||||
|
gpsQuality.value = 1; // 1 = Standard (nem-RTK) minőség
|
||||||
|
satelliteCount.value = 0; // A Geolocator nem ad műholdszámot direktben
|
||||||
|
|
||||||
|
// A Geolocator a pontosságot (accuracy) méterben adja vissza
|
||||||
|
latitudeError.value = pos.accuracy;
|
||||||
|
longitudeError.value = pos.accuracy;
|
||||||
|
altitudeError.value = pos.altitudeAccuracy ?? 0.0;
|
||||||
|
|
||||||
|
// Az RMC (idő) adatait is beállítjuk a telefon idejéből
|
||||||
|
gpsDateTime.value = pos.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _disconnect() async {
|
Future<void> _disconnect() async {
|
||||||
|
_intentionalDisconnection = true;
|
||||||
await _nmeaSub?.cancel();
|
await _nmeaSub?.cancel();
|
||||||
|
await _positionSub?.cancel();
|
||||||
await _stateSub?.cancel();
|
await _stateSub?.cancel();
|
||||||
await _connection?.disconnect();
|
await _connection?.disconnect();
|
||||||
_connection?.dispose();
|
_connection?.dispose();
|
||||||
@ -129,7 +174,7 @@ class GnssService extends GetxService {
|
|||||||
void sendToReceiver(Uint8List data) {
|
void sendToReceiver(Uint8List data) {
|
||||||
if (_connection == null) return;
|
if (_connection == null) return;
|
||||||
if (connectionState.value != GnssConnectionState.connected) return;
|
if (connectionState.value != GnssConnectionState.connected) return;
|
||||||
(_connection as BtSerialGnssConnection?)?.sendData(data);
|
_connection?.sendData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── NMEA parsing ──────────────────────────────────────────────────
|
// ── NMEA parsing ──────────────────────────────────────────────────
|
||||||
@ -196,4 +241,36 @@ class GnssService extends GetxService {
|
|||||||
_disconnect();
|
_disconnect();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> determineInitialPosition() async {
|
||||||
|
// 1. Ha már van élő adatunk (pl. a külső vevő már küldött koordinátát),
|
||||||
|
// akkor nincs szükség extra lekérdezésre.
|
||||||
|
if (latitude.value != 0 && longitude.value != 0) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2. Gyors lekérdezés: megkérdezzük a telefont, hol voltunk utoljára.
|
||||||
|
// Ez szinte azonnal visszatér, nem pörgeti fel a GPS chipet.
|
||||||
|
final lastPosition = await Geolocator.getLastKnownPosition();
|
||||||
|
|
||||||
|
if (lastPosition != null) {
|
||||||
|
latitude.value = lastPosition.latitude;
|
||||||
|
longitude.value = lastPosition.longitude;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Ha nincs utolsó ismert pozíció (pl. friss telepítés),
|
||||||
|
// kérünk egy friss pozíciót, de alacsony pontossággal, hogy gyors legyen.
|
||||||
|
final currentPosition = await Geolocator.getCurrentPosition(
|
||||||
|
desiredAccuracy: LocationAccuracy.low,
|
||||||
|
timeLimit: const Duration(seconds: 3), // Ne akassza meg az appot sokáig
|
||||||
|
);
|
||||||
|
|
||||||
|
latitude.value = currentPosition.latitude;
|
||||||
|
longitude.value = currentPosition.longitude;
|
||||||
|
} catch (e) {
|
||||||
|
// Engedélyhiány vagy kikapcsolt helymeghatározás esetén a térkép
|
||||||
|
// marad a (0,0)-n vagy egy alapértelmezett (pl. budapesti) koordinátán.
|
||||||
|
print('Nem sikerült lekérni a kezdőpozíciót: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
lib/services/gnss/phone_gps_connection.dart
Normal file
74
lib/services/gnss/phone_gps_connection.dart
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// lib/services/gnss/phone_gps_connection.dart
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'gnss_connection.dart';
|
||||||
|
import 'gnss_device_service.dart';
|
||||||
|
|
||||||
|
class PhoneGpsConnection implements GnssConnection {
|
||||||
|
@override
|
||||||
|
GnssConnectionType get type => GnssConnectionType.phoneGps;
|
||||||
|
|
||||||
|
final _stateController = StreamController<GnssConnectionState>.broadcast();
|
||||||
|
final _positionController = StreamController<Position>.broadcast();
|
||||||
|
StreamSubscription<Position>? _positionSub;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<String> get nmeaLines => const Stream.empty(); // Nincs NMEA
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Position> get positionStream => _positionController.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<GnssConnectionState> get connectionState => _stateController.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> connect(String address) async {
|
||||||
|
_stateController.add(GnssConnectionState.connecting);
|
||||||
|
|
||||||
|
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||||
|
if (!serviceEnabled) {
|
||||||
|
_stateController.add(GnssConnectionState.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationPermission permission = await Geolocator.checkPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
permission = await Geolocator.requestPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
_stateController.add(GnssConnectionState.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stateController.add(GnssConnectionState.connected);
|
||||||
|
|
||||||
|
// Belső GPS folyamatos olvasása
|
||||||
|
_positionSub = Geolocator.getPositionStream(
|
||||||
|
locationSettings: const LocationSettings(
|
||||||
|
accuracy: LocationAccuracy.high,
|
||||||
|
distanceFilter: 0, // Folyamatos frissítés
|
||||||
|
),
|
||||||
|
).listen((Position pos) {
|
||||||
|
_positionController.add(pos);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> disconnect() async {
|
||||||
|
await _positionSub?.cancel();
|
||||||
|
_stateController.add(GnssConnectionState.disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendData(Uint8List data) {
|
||||||
|
// A telefon beépített GPS-e nem fogad RTCM adatokat
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_positionSub?.cancel();
|
||||||
|
_positionController.close();
|
||||||
|
_stateController.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -55,7 +55,18 @@ class GnssDevicePickerDialog extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Telefon GPS opció
|
// 1. ÚJ: GPS kikapcsolása opció
|
||||||
|
_DeviceTile(
|
||||||
|
device: const GnssDevice(
|
||||||
|
address: 'none',
|
||||||
|
name: 'GPS kikapcsolása (Térkép mód)',
|
||||||
|
type: GnssConnectionType.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
|
// 2. Telefon GPS opció
|
||||||
_DeviceTile(
|
_DeviceTile(
|
||||||
device: const GnssDevice(
|
device: const GnssDevice(
|
||||||
address: 'phone',
|
address: 'phone',
|
||||||
@ -210,7 +221,9 @@ class _DeviceTile extends StatelessWidget {
|
|||||||
style: const TextStyle(fontSize: 11, color: Colors.grey),
|
style: const TextStyle(fontSize: 11, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (device.type != GnssConnectionType.phoneGps)
|
// A "none" és a "phoneGps" esetén ne írjunk ki kamucímeket (mint a "phone" vagy "none")
|
||||||
|
if (device.type != GnssConnectionType.phoneGps &&
|
||||||
|
device.type != GnssConnectionType.none)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 6),
|
padding: const EdgeInsets.only(left: 6),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -231,10 +244,12 @@ class _DeviceTile extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bővítettük a switch utasítást a none opcióval
|
||||||
IconData _iconFor(GnssConnectionType type) => switch (type) {
|
IconData _iconFor(GnssConnectionType type) => switch (type) {
|
||||||
GnssConnectionType.btSerial => Icons.bluetooth,
|
GnssConnectionType.btSerial => Icons.bluetooth,
|
||||||
GnssConnectionType.ble => Icons.bluetooth_searching,
|
GnssConnectionType.ble => Icons.bluetooth_searching,
|
||||||
GnssConnectionType.phoneGps => Icons.phone_android,
|
GnssConnectionType.phoneGps => Icons.phone_android,
|
||||||
|
GnssConnectionType.none => Icons.gps_off,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user