200 lines
6.9 KiB
Dart
200 lines
6.9 KiB
Dart
// lib/services/gnss/gnss_service.dart
|
|
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:get/get.dart';
|
|
import 'package:nmea/nmea.dart';
|
|
import 'package:terepi_seged/services/gnss/gnss_device_service.dart';
|
|
|
|
import '../../gnss_sentences/gngga.dart';
|
|
import '../../gnss_sentences/gngst.dart';
|
|
import '../../gnss_sentences/gnrmc.dart';
|
|
import 'bt_serial_gnss_connection.dart';
|
|
import 'ble_gnss_connection.dart';
|
|
import 'gnss_connection.dart';
|
|
|
|
class GnssService extends GetxService {
|
|
static GnssService get to => Get.find();
|
|
|
|
GnssConnection? _connection;
|
|
|
|
// ── Kapcsolat állapot ─────────────────────────────────────────────
|
|
final connectionState = GnssConnectionState.disconnected.obs;
|
|
final activeConnectionType = Rxn<GnssConnectionType>();
|
|
|
|
// ── GGA adatok ────────────────────────────────────────────────────
|
|
final latitude = 0.0.obs;
|
|
final longitude = 0.0.obs;
|
|
final altitude = 0.0.obs; // MSL (ortometrikus)
|
|
final geoidSeparation = 0.0.obs; // N — geoid undulációja
|
|
final gpsQuality = 0.obs;
|
|
final utcFix = ''.obs;
|
|
final satelliteCount = 0.obs;
|
|
final hdop = 0.0.obs;
|
|
|
|
// Utolsó nyers GGA sor — NtripService küldi vissza a casternek
|
|
final lastGgaLine = ''.obs;
|
|
|
|
// ── GST adatok (pontossági hibák) ─────────────────────────────────
|
|
final latitudeError = 0.0.obs;
|
|
final longitudeError = 0.0.obs;
|
|
final altitudeError = 0.0.obs;
|
|
|
|
// ── RMC adatok (dátum/idő) ────────────────────────────────────────
|
|
final gpsDateTime = DateTime(2000).obs;
|
|
|
|
// Segédmező: van-e érvényes adat
|
|
bool get hasValidData => gpsQuality.value > 0;
|
|
|
|
// ── Belső ─────────────────────────────────────────────────────────
|
|
final NmeaDecoder _decoder = NmeaDecoder();
|
|
StreamSubscription? _nmeaSub;
|
|
StreamSubscription? _stateSub;
|
|
String _utcTime = '';
|
|
String _utcDate = '';
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_decoder
|
|
..registerTalkerSentence('GGA', (l) => Gngga(raw: l))
|
|
..registerTalkerSentence('GST', (l) => Gngst(raw: l))
|
|
..registerTalkerSentence('RMC', (l) => Gnrmc(raw: l));
|
|
}
|
|
|
|
// ── Kapcsolódás ───────────────────────────────────────────────────
|
|
|
|
Future<void> connectBtSerial(String macAddress) async {
|
|
await _disconnect();
|
|
_connection = BtSerialGnssConnection();
|
|
activeConnectionType.value = GnssConnectionType.btSerial;
|
|
await _doConnect(macAddress);
|
|
}
|
|
|
|
Future<void> connectBle(
|
|
String deviceId, {
|
|
String? serviceUuid,
|
|
String? txCharUuid,
|
|
}) async {
|
|
await _disconnect();
|
|
_connection = BleGnssConnection(
|
|
serviceUuid: serviceUuid ?? '6e400001-b5b3-f393-e0a9-e50e24dcca9e',
|
|
txCharUuid: txCharUuid ?? '6e400003-b5b3-f393-e0a9-e50e24dcca9e',
|
|
);
|
|
activeConnectionType.value = GnssConnectionType.ble;
|
|
await _doConnect(deviceId);
|
|
}
|
|
|
|
/// Eszközváltás — GnssDevicePicker hívja.
|
|
Future<void> onDeviceChanged(GnssDevice device) async {
|
|
switch (device.type) {
|
|
case GnssConnectionType.btSerial:
|
|
await connectBtSerial(device.address);
|
|
case GnssConnectionType.ble:
|
|
await connectBle(device.address);
|
|
case GnssConnectionType.phoneGps:
|
|
await _disconnect();
|
|
connectionState.value = GnssConnectionState.disconnected;
|
|
activeConnectionType.value = GnssConnectionType.phoneGps;
|
|
}
|
|
}
|
|
|
|
Future<void> reconnect() async {
|
|
final device = GnssDeviceService.to.selectedDevice.value;
|
|
if (device == null) return;
|
|
await _disconnect();
|
|
await onDeviceChanged(device);
|
|
}
|
|
|
|
Future<void> _doConnect(String address) async {
|
|
_stateSub = _connection!.connectionState.listen((s) {
|
|
connectionState.value = s;
|
|
});
|
|
_nmeaSub = _connection!.nmeaLines.listen(_parseNmea);
|
|
await _connection!.connect(address);
|
|
}
|
|
|
|
Future<void> _disconnect() async {
|
|
await _nmeaSub?.cancel();
|
|
await _stateSub?.cancel();
|
|
await _connection?.disconnect();
|
|
_connection?.dispose();
|
|
_connection = null;
|
|
connectionState.value = GnssConnectionState.disconnected;
|
|
}
|
|
|
|
Future<void> disconnect() => _disconnect();
|
|
|
|
/// RTCM adat továbbítása a GNSS vevőnek (NtripService hívja).
|
|
void sendToReceiver(Uint8List data) {
|
|
if (_connection == null) return;
|
|
if (connectionState.value != GnssConnectionState.connected) return;
|
|
(_connection as BtSerialGnssConnection?)?.sendData(data);
|
|
}
|
|
|
|
// ── NMEA parsing ──────────────────────────────────────────────────
|
|
|
|
void _parseNmea(String line) {
|
|
if (line.startsWith('\$GNGGA') || line.startsWith('\$GPGGA')) {
|
|
_parseGga(line);
|
|
} else if (line.startsWith('\$GNGST') && hasValidData) {
|
|
_parseGst(line);
|
|
} else if (line.startsWith('\$GNRMC') && hasValidData) {
|
|
_parseRmc(line);
|
|
}
|
|
}
|
|
|
|
void _parseGga(String line) {
|
|
try {
|
|
final s = _decoder.decode(line);
|
|
if (s == null || !s.valid || s is! Gngga) return;
|
|
if (s.gpsQualityIndicator == 0) return;
|
|
|
|
latitude.value = s.latitude;
|
|
longitude.value = s.longitude;
|
|
altitude.value = s.altitudeAboveMeanSeaLevel;
|
|
geoidSeparation.value = s.geoidSeparation;
|
|
gpsQuality.value = s.gpsQualityIndicator;
|
|
utcFix.value = s.utcOfPositionFix;
|
|
satelliteCount.value = s.numberOfSvsInUse;
|
|
hdop.value = s.hdop;
|
|
lastGgaLine.value = line;
|
|
_utcTime = s.utcOfPositionFix;
|
|
} catch (_) {}
|
|
}
|
|
|
|
void _parseGst(String line) {
|
|
try {
|
|
final s = _decoder.decode(line);
|
|
if (s == null || !s.valid || s is! Gngst) return;
|
|
latitudeError.value = s.latitudeError;
|
|
longitudeError.value = s.longitudeError;
|
|
altitudeError.value = s.heightError;
|
|
} catch (_) {}
|
|
}
|
|
|
|
void _parseRmc(String line) {
|
|
try {
|
|
final s = _decoder.decode(line);
|
|
if (s == null || !s.valid || s is! Gnrmc) return;
|
|
_utcDate = s.date;
|
|
if (_utcDate.length >= 6 && _utcTime.length >= 6) {
|
|
gpsDateTime.value = DateTime(
|
|
2000 + int.parse('${_utcDate[4]}${_utcDate[5]}'),
|
|
int.parse('${_utcDate[2]}${_utcDate[3]}'),
|
|
int.parse('${_utcDate[0]}${_utcDate[1]}'),
|
|
int.parse('${_utcTime[0]}${_utcTime[1]}'),
|
|
int.parse('${_utcTime[2]}${_utcTime[3]}'),
|
|
int.parse('${_utcTime[4]}${_utcTime[5]}'),
|
|
);
|
|
}
|
|
} catch (_) {}
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_disconnect();
|
|
super.onClose();
|
|
}
|
|
}
|