MobilApp/lib/pages/rtcm_test/presentation/controllers/rtcm_test_controller.dart

302 lines
9.4 KiB
Dart
Raw Permalink Normal View History

2025-02-21 08:26:27 +01:00
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:nmea/nmea.dart';
import 'package:terepi_seged/eov/convert_coordinate.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';
class RtcmTestController extends GetxController {
String gpsAddress = "E8:31:CD:14:8B:B2";
String gpsName = "TiGNSS Rover-8BB2";
Rx<bool> gpsIsConnected = false.obs;
RxBool ntripIsConnected = false.obs;
RxInt ntripDataPacketNumbers = 0.obs;
String _messageBuffer = "";
late BluetoothConnection connection;
late Socket socket;
late StreamSubscription socketStreamSubscription;
RxInt gpsReceivedData = 0.obs;
RxBool hasGpsValidData = false.obs;
DateTime lastGpsRefreshTime = DateTime.now();
String utcOfPositionFix = "";
String utcDateOfPositionFix = "";
RxInt ntripReceivedData = 0.obs;
final NmeaDecoder nmeaDecoder = NmeaDecoder();
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
RxDouble gpsLatitude = 0.0.obs;
RxString gpsLatitudeDirection = "".obs;
RxDouble gpsLongitude = 0.0.obs;
RxString gpsLongitudeDirection = "".obs;
RxDouble gpsAltitude = 0.0.obs;
RxInt gpsQuality = 0.obs;
RxDouble gpsLatitudeError = 0.0.obs;
RxDouble gpsLongitudeError = 0.0.obs;
RxDouble gpsAltitudeError = 0.0.obs;
Rx<DateTime> gpsDateTime = DateTime(2000).obs;
Rx<Eov> eov = Eov(0, 0).obs;
RxInt latDegree = 0.obs;
RxInt latMin = 0.obs;
RxDouble latSec = 0.0.obs;
RxInt longDegree = 0.obs;
RxInt longMin = 0.obs;
RxDouble longSec = 0.0.obs;
@override
void onInit() {
super.onInit();
//Loading, Success, Error handle with 1 line of code
nmeaDecoder
..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
}
@override
void onClose() {
super.onClose();
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
if (gpsIsConnected.value) {
connection.close();
// connection = null;
print("BluetoothTestController dispose ....");
}
}
void connectToGps() {
if (gpsIsConnected == false) {
BluetoothConnection.toAddress(gpsAddress).then((value) {
connection = value;
gpsIsConnected.value = true;
print("GPS is connected ...");
connection.input!.listen(_onDataReceived);
});
}
}
void disconnectFromGps() {
if (gpsIsConnected.value) {
connection.close();
gpsIsConnected.value = false;
print("GPS is disconnected ....");
}
if (ntripIsConnected.value) {
disconnectFromNtripServer();
}
}
void connectToNtripServer() async {
socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
timeout: const Duration(seconds: 5));
socket.asBroadcastStream;
ntripIsConnected.value = true;
socket.encoding = ascii;
print("Connected to ntrip server ....");
String header = "GET /KOVARIK HTTP/1.1\r\n";
header += "User-Agent: SharpGps iter.dk\r\n";
header += "Accept: */*\r\nConnection: close\r\n";
header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
header += "Host:rtk2go.com:2101\r\n";
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
header += "\r\n";
// listen for responses from the server
socketStreamSubscription = socket.listen(
// handle data from the server
(Uint8List data) {
// "ICY 200 OK" - first response
final serverResponse = String.fromCharCodes(data);
ntripReceivedData.value = data.length;
ntripDataPacketNumbers.value++;
if (gpsIsConnected.value) {
if (data.length > 12) {
connection.output.add(data);
}
}
print('Server: $ntripReceivedData');
},
// handle errors
onError: (error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () async {
print('Server left.');
socketStreamSubscription.cancel();
await socket.flush();
ntripIsConnected.value = false;
ntripReceivedData.value = 0;
socket.destroy();
},
);
socket.add(_convertStringToUint8List(header));
}
void disconnectFromNtripServer() async {
socketStreamSubscription.cancel();
await socket.flush();
socket.close();
socket.destroy();
ntripReceivedData.value = 0;
ntripIsConnected.value = false;
print("Disconnect from ntrip server....");
}
void _onDataReceived(Uint8List data) {
String sentence = "";
print("Bluetooth received -> ${data.length} byte(s)");
String dataString = String.fromCharCodes(data);
int index = data.indexOf(13);
if (~index != 0) {
sentence = _messageBuffer + dataString.substring(0, index);
_messageBuffer = dataString.substring(index);
} else {
_messageBuffer = _messageBuffer + dataString;
}
// print("Message ($count): $sentence");
_processGnssMessage(sentence);
}
String _toBase64(String str) {
final bytes = ascii.encode(str);
final base64Str = base64.encode(bytes);
return base64Str;
}
Uint8List _convertStringToUint8List(String str) {
final List<int> codeUnits = str.codeUnits;
final Uint8List unit8List = Uint8List.fromList(codeUnits);
return unit8List;
}
void _processGnssMessage(String message) {
LineSplitter lineSplitter = const LineSplitter();
List<String> lines = lineSplitter.convert(message);
if (lines.isEmpty) {
return;
}
for (String line in lines) {
if (line.trim().isEmpty) {
continue;
}
if (line.startsWith("\$GNGGA")) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gngga) {
hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
if (hasGpsValidData.value) {
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 2) {
lastGpsRefreshTime = DateTime.now();
utcOfPositionFix = sentence.utcOfPositionFix;
gpsLatitude.value = sentence.latitude;
gpsLatitudeDirection.value = sentence.latitudeDirection;
gpsLongitude.value = sentence.longitude;
gpsLongitudeDirection.value = sentence.longitudeDirection;
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
gpsQuality.value = sentence.gpsQualityIndicator;
eov.value = ConvertCoordinate.ConvertWgsToEov(
gpsLatitude.value, gpsLongitude.value);
latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
}
}
}
}
if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gngst) {
gpsLatitudeError.value = sentence.latitudeError;
gpsLongitudeError.value = sentence.longitudeError;
gpsAltitudeError.value = sentence.heightError;
}
}
if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gnrmc) {
utcDateOfPositionFix = sentence.date;
if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
gpsDateTime.value = DateTime(
2000 +
int.parse(
"${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
int.parse(
"${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
int.parse(
"${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
}
}
}
}
}
String getGpsQualityIndicator({required int quality}) {
String qualityStr = "Invalid";
switch (quality) {
case 0:
{
qualityStr = "Invalid";
}
break;
case 1:
{
qualityStr = "Standard GPS (2D/3D)";
}
break;
case 2:
{
qualityStr = "Differential GPS";
}
break;
case 4:
{
qualityStr = "RTK Fix";
}
break;
case 5:
{
qualityStr = "RTK Float";
}
break;
case 6:
{
qualityStr = "Estimated (DR) Fix";
}
break;
default:
{
qualityStr = "Invalid (-1)";
}
}
return qualityStr;
}
}