柱状图

This commit is contained in:
tanlinxing 2024-08-01 18:17:57 +08:00
parent f1c566b008
commit 4b57e95def
57 changed files with 216 additions and 3663 deletions

View File

@ -9,6 +9,12 @@ class GnssController extends GetxController {
var locationUpdate = 0.obs; var locationUpdate = 0.obs;
var singnalUpdate = 0.obs; var singnalUpdate = 0.obs;
final startIndex = 0.obs;
updateSlider(double value) {
startIndex.value = value.ceil();
update();
}
Map<String, bool> selectedSignal = { Map<String, bool> selectedSignal = {
"GPS": true, "GPS": true,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:gnssview/quality/chartpart.dart';
// import 'package:gnss/gnss.dart'; // import 'package:gnss/gnss.dart';
import 'sky/sky_plot.dart'; import 'sky/sky_plot.dart';
@ -40,7 +41,7 @@ class _MyAppState extends State<MyApp> {
appBar: AppBar( appBar: AppBar(
title: Text('天空图'), title: Text('天空图'),
), ),
body: SkyInfoPlotPage(), body: ChartPart(),
)); ));
} }
} }

View File

@ -7,7 +7,6 @@ import 'package:gnss/gnss.dart';
import '../Controller/gnss_controller.dart'; import '../Controller/gnss_controller.dart';
const signalNameList = <String>["GPS", "GLONASS", "GALILEO", "BEIDOU", "QZSS"];
const signalPrefixList = <String>["G", "R", "E", "B", "Q"]; const signalPrefixList = <String>["G", "R", "E", "B", "Q"];
const List<Color> signalColorList = [ const List<Color> signalColorList = [
Color.fromARGB(255, 255, 0, 0), Color.fromARGB(255, 255, 0, 0),
@ -17,68 +16,50 @@ const List<Color> signalColorList = [
Color.fromARGB(255, 0, 255, 255) Color.fromARGB(255, 0, 255, 255)
]; ];
class ChartPart extends StatelessWidget { class ChartPart extends GetView<GnssController> {
final List<List<SignalGNSS>?> signalGNSS; ChartPart({super.key});
late final GnssController controller;
final List<Color> signalColorList; //
List<SignalGNSS> signalGPS = []; //
List<bool> QselectedSignal; //
ChartPart({super.key}) {
controller = Get.find<GnssController>();
}
List<BarChartGroupData> checkSVData = []; List<BarChartGroupData> checkSVData = [];
double maxY = 0; double maxY = 0;
int maxX = 10; int maxX = 10;
double xLength = 0; double xLength = 0;
@override
void drawBarChart(
Canvas canvas,
Size size,
int index,
Paint paint,
) {
if(QselectedSignal[0]){
for (final signal in SignalGPS) {
for (int i = 0; i < signal.length; i++) {
SignalGPS signalGPS=signal[i];
if (signalGPS.snrL1 == 0 &&
signalGPS.snrL2 == 0 &&
signalGPS.snrL5 == 0) {
continue;
}
maxX = max(maxX, signalGPS.sn);
List<int> listy = [signalGPS.snrL1, signalGPS.snrL2, signalGPS.snrL5];
int maxItem = listy.reduce(max);
maxY = max(maxY, maxItem.toDouble());
checkSVData.add(makeGroupData(i + 1, listy, signalColorList[0]));
xLength++;}
// svData = List.from(controller.svData) // void drawBarChart(
// ..sort((a, b) => a.sn.compareTo(b.sn)); // Canvas canvas,
// Size size,
// for (int i = 0; i < svData.length; i++) { // int index,
// SvItem item = svData[i]; // Paint paint,
// if (item.l1 == 0 && // ) {
// item.l2 == 0 && // for (int index = 0; index < QselectedSignal.length; index++) {
// item.l3 == 0 && // if (QselectedSignal[index]) {
// item.l4 == 0 && // var snr = signalGNSS[index];
// item.l5 == 0) { // List<int> signal = snr.values.toList(); // snr Map
// print('signal= $signal');
// for (int i = 0; i < signal.length; i++) {
// if (signal[0] == 0 &&
// signal[1] == 0 &&
// signal[2] == 0 &&
// signal[3] == 0 &&
// signal[4] == 0) {
// continue; // continue;
// } // }
// if (signalQualityItem.show && // maxX = max(maxX, 16);
// (selectedIndex == null || // List<int> listy = [
// selectedIndex == // signal[0],
// controller.signalQuality.keys.toList().indexOf(sys))) { // signal[1],
// maxX = max(maxX, item.sn); // signal[2],
// List<int> listy = [item.l1, item.l2, item.l3, item.l4, item.l5]; // signal[3],
// signal[4]
// ];
// int maxItem = listy.reduce(max); // int maxItem = listy.reduce(max);
// maxY = max(maxY, maxItem.toDouble()); // maxY = max(maxY, maxItem.toDouble());
// checkSVData.add(makeGroupData(i + 1, listy, signalQualityItem.color)); // checkSVData.add(makeGroupData(i + 1, listy, signalColorList[0]));
// xLength++; // xLength++;
// } // }
// } // }
// // print('CheckSVData: $checkSVData'); // // }
// if (checkSVData.isNotEmpty) { // if (checkSVData.isNotEmpty) {
// if (controller.startIndex.value < checkSVData.length - 8) { // if (controller.startIndex.value < checkSVData.length - 8) {
// checkSVData = checkSVData.sublist( // checkSVData = checkSVData.sublist(
@ -90,24 +71,19 @@ void drawBarChart(
// } // }
// } // }
// @override @override
// Widget build(BuildContext context) { Widget build(BuildContext context) {
// //
// if (selectedIndex != null) {
// updateSVdata();
// }
// ever(controller.startIndex, (callback) {
// if (svData.length - callback < 8) {
// controller.startIndex.value = max(0, svData.length - 8); // 0
// return;
// }
// updateSVdata();
// });
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final orientation = final orientation =
MediaQuery.of(context).orientation == Orientation.portrait; MediaQuery.of(context).orientation == Orientation.portrait;
return Obx(() {
controller.singnalUpdate.value;
List<SignalGNSS> signalGNSS = controller.signalData == null
? []
: (controller.signalData!['BDS'] ?? []);
//
for (var i = 0; i < signalGNSS.length; i++) {}
return SizedBox( return SizedBox(
width: size.width, width: size.width,
// decoration: const BoxDecoration(color: Colors.white), // decoration: const BoxDecoration(color: Colors.white),
@ -124,9 +100,10 @@ void drawBarChart(
child: Obx(() { child: Obx(() {
controller.startIndex.value; controller.startIndex.value;
return BarChart( return BarChart(
swapAnimationDuration: const Duration(milliseconds: 0), swapAnimationDuration:
const Duration(milliseconds: 0),
BarChartData( BarChartData(
maxY: maxY, // + 20 maxY: 100, // + 20
barTouchData: BarTouchData( barTouchData: BarTouchData(
enabled: false, enabled: false,
touchTooltipData: BarTouchTooltipData( touchTooltipData: BarTouchTooltipData(
@ -196,7 +173,18 @@ void drawBarChart(
borderData: FlBorderData( borderData: FlBorderData(
show: false, show: false,
), ),
barGroups: checkSVData, barGroups:
List.generate(signalGNSS.length, (index) {
List<int> listy = [];
Map snr = signalGNSS[index].snr;
snr.forEach((key, value) {
listy.add(value);
});
return makeGroupData(
index, listy, signalColorList[0]);
}),
gridData: const FlGridData(show: true), gridData: const FlGridData(show: true),
), ),
); );
@ -231,6 +219,7 @@ void drawBarChart(
), ),
), ),
); );
});
} }
Widget leftTitles(double value, TitleMeta meta) { Widget leftTitles(double value, TitleMeta meta) {
@ -264,13 +253,14 @@ void drawBarChart(
Widget bottomTitles(double index, TitleMeta meta) { Widget bottomTitles(double index, TitleMeta meta) {
String text = ""; String text = "";
int intValue = (index - 1).ceil(); int intValue = (index - 1).ceil();
if (svData.isNotEmpty) {
var data = svData[intValue]; // if (signal[].isNotEmpty) {
String? name = svMap[data.name]; // var data = svData[intValue];
if (name != null) { // String? name = svMap[data.name];
text = "${name.substring(0, 1)}${data.sn}"; // if (name != null) {
} // text = "${name.substring(0, 1)}${data.sn}";
} // }
// }
return SideTitleWidget( return SideTitleWidget(
axisSide: meta.axisSide, axisSide: meta.axisSide,

View File

@ -18,7 +18,8 @@ class _SignalQualityState extends State<SignalQuality> {
super.initState(); super.initState();
// //
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
groupColors.add([colors[i % colors.length], colors[(i + 1) % colors.length]]); groupColors
.add([colors[i % colors.length], colors[(i + 1) % colors.length]]);
} }
} }
@ -26,17 +27,19 @@ class _SignalQualityState extends State<SignalQuality> {
setState(() { setState(() {
for (int i = 0; i < groupColors.length; i++) { for (int i = 0; i < groupColors.length; i++) {
// //
groupColors[i] = groupColors[i].first == color ? [color] : [Colors.transparent]; groupColors[i] =
groupColors[i].first == color ? [color] : [Colors.transparent];
} }
}); });
} }
String colorToString(Color color) { String colorToString(Color color) {
// //
if (color == Colors.blue) return 'GPS'; if (color == Color.fromARGB(255, 255, 0, 0)) return 'GPS(G)';
if (color == Colors.red) return 'BDS'; if (color == Color.fromARGB(255, 0, 255, 0)) return 'GLONASS(R)';
if (color == Colors.green) return 'GLO'; if (color == Color.fromARGB(255, 0, 0, 255)) return 'GALILEO(E)';
if (color == Colors.orange) return 'ALS'; if (color == Color.fromARGB(255, 255, 255, 0)) return 'BEIDOU(B)';
if (color == Color.fromARGB(255, 0, 255, 255)) return 'QZSS(Q)';
return 'Unknown Color'; return 'Unknown Color';
} }
@ -50,7 +53,7 @@ class _SignalQualityState extends State<SignalQuality> {
return Column( return Column(
children: [ children: [
SingleButton( SingleButton(
colors: colors, // colors: colors,
onSelectionChanged: (color) { onSelectionChanged: (color) {
setState(() { setState(() {
selectedColor = color; // selectedColor = color; //
@ -60,10 +63,11 @@ class _SignalQualityState extends State<SignalQuality> {
} }
}); });
}, },
signalColorList: [],
), ),
Expanded( Expanded(
child: Center( child: Center(
child: ChartPart(: groupColors), // ChartPart child: ChartPart(), // ChartPart
), ),
), ),
], ],

View File

@ -65,7 +65,7 @@ class SkyInfo extends StatelessWidget {
Color.fromARGB(255, 0, 255, 255) Color.fromARGB(255, 0, 255, 255)
], ],
onSelectionChanged: (int index, bool value) { onSelectionChanged: (int index, bool value) {
controller.selectedSignal[index] = value; // controller.selectedSignal[index] = value;
}, },
), ),
], ],
@ -124,7 +124,6 @@ class FixedWidthText extends StatelessWidget {
} }
class SkyInfoPlotPage extends StatelessWidget { class SkyInfoPlotPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final orientation = MediaQuery.of(context).orientation; final orientation = MediaQuery.of(context).orientation;

View File

@ -331,7 +331,7 @@ class SkyPlotPainter extends CustomPainter {
canvas.drawCircle(Offset(x, y), satelliteRadius, paint); canvas.drawCircle(Offset(x, y), satelliteRadius, paint);
TextPainter( TextPainter(
text: TextSpan( text: TextSpan(
text: signalPrefixList[neme] + signal.prn.toString().padLeft(2, '0'), text: signalPrefixList[neme]! + signal.prn.toString().padLeft(2, '0'),
style: const TextStyle(color: Colors.white, fontSize: 12), style: const TextStyle(color: Colors.white, fontSize: 12),
), ),
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,

View File

@ -1,29 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
build/

View File

@ -1,10 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "b0850beeb25f6d5b10426284f506557f66181b36"
channel: "stable"
project_type: package

View File

@ -1,3 +0,0 @@
## 0.0.1
* TODO: Describe initial release.

View File

@ -1 +0,0 @@
TODO: Add your license here.

View File

@ -1,39 +0,0 @@
<!--
This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
and the Flutter guide for
[developing packages and plugins](https://flutter.dev/developing-packages).
-->
TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.
## Features
TODO: List what your package can do. Maybe include images, gifs, or videos.
## Getting started
TODO: List prerequisites and provide or point to information on how to
start using the package.
## Usage
TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
```dart
const like = 'sample';
```
## Additional information
TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.

View File

@ -1,7 +0,0 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
linter:
rules:
- avoid_print

View File

@ -1,380 +0,0 @@
library gnss;
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
import 'dart:async';
import "package:libserialport/libserialport.dart";
import "nmea/sentence.dart";
import 'nmea/gga.dart';
import 'nmea/rmc.dart';
import 'nmea/vtg.dart';
import 'nmea/gsa.dart';
import 'nmea/gsv.dart';
import 'nmea/heading.dart';
import 'nmea/bestpos.dart';
import "rtk_base.dart";
class LocationData {
double latitude = 0; //
double longitude = 0; //
double speed = 0; //
double baseLength = 0; //线(线)
double heading = 0; //
double pitch = 0; //
double altitude = 0; //
double adop = 0; //
double hdop = 0; //
double vdop = 0; //
double course = 0; //
double diffAge = 0; //
int numberSv = 0; //
int numberSa = 0; //使
String fixQuality = ""; //()
int quality = 0; //()
@override
String toString() {
return "LocationData{latitude=$latitude,longitude=$longitude,speed=$speed,baseLength=$baseLength,heading=$heading,pitch=$pitch,altitude=$altitude,adop=$adop,hdop=$hdop,vdop=$vdop,course=$course,diffAge=$diffAge,numberSv=$numberSv,numberSa=$numberSa,fixQuality=$fixQuality,quality=$quality}";
}
}
const um982Init = [
"version\r\n",
"UNLOGALL\r\n",
"GPRMC 1\r\n", //0.2
"GPGGA 1\r\n",
"GPVTG 1\r\n",
"LOG HEADINGA ONTIME 0.2\r\n",
"LOG BESTPOSA ONTIME 0.2\r\n",
"GPGSV 1\r\n",
"GPGSA 1\r\n",
"SAVECONFIG\r\n"
];
class SignalGPS {
int prn;
double elevation;
double azimuth;
int snrL1;
int snrL2;
int snrL5;
SignalGPS(
{required this.prn,
required this.elevation,
required this.azimuth,
required this.snrL1,
required this.snrL2,
required this.snrL5});
}
class SignalBDS {
int prn;
double elevation;
double azimuth;
int snrB1I;
int snrB2I;
int snrB1C;
int snrB2a;
int snrB3I;
SignalBDS(
{required this.prn,
required this.elevation,
required this.azimuth,
required this.snrB1I,
required this.snrB2I,
required this.snrB1C,
required this.snrB2a,
required this.snrB3I});
}
class SignalGLO {
int prn;
double elevation;
double azimuth;
int snrR1;
int snrR2;
SignalGLO(
{required this.prn,
required this.elevation,
required this.azimuth,
required this.snrR1,
required this.snrR2});
}
class SignalGAL {
int prn;
double elevation;
double azimuth;
int snrE1;
int snrE5a;
int snrE5b;
SignalGAL(
{required this.prn,
required this.elevation,
required this.azimuth,
required this.snrE1,
required this.snrE5a,
required this.snrE5b});
}
class SignalData {
List<SignalGPS> signalsGPS = [];
List<SignalBDS> signalsBDS = [];
List<SignalGLO> signalsGLO = [];
List<SignalGAL> signalsALS = [];
}
class Gnss {
SerialPort? _serialPort;
SerialPortReader? _serialPortReader;
Socket? _socket; // tcp
RtkBase? rtkBase;
LineSplitter lineSplitter = LineSplitter();
SentenceParser sentence = SentenceParser({}, null, null, null);
var locationStreamController = StreamController<LocationData>.broadcast();
var signalStreamController = StreamController<SignalData>.broadcast();
Stream<LocationData> get locationStream => locationStreamController.stream;
Stream<SignalData> get signalStream => signalStreamController.stream;
final LocationData _locationData = LocationData();
final SignalData _signalData = SignalData();
SignalData get signalData => _signalData;
bool locationUpdate = false;
bool signalUpdate = false;
bool _isTCP = false;
String _port = "";
int _baudrate = 0;
String _host = "";
int _portTcp = 0;
Gnss({port = "", baudrate = 115200, host = "", portTCP = 0, isTCP = false}) {
_port = port;
_baudrate = baudrate;
_host = host;
_portTcp = portTCP;
_isTCP = isTCP;
}
start() {
if (_isTCP) {
_connectTcp();
} else {
_connectSerialPort();
}
rtkBase ??= RtkBase();
rtkBase!.connect();
rtkBase!.rtcmStream.listen((rtcmData) {
if (_serialPort != null) {
_serialPort!.write(Uint8List.fromList(rtcmData));
}
});
}
void dispose() {
if (_isTCP) {
if (_socket != null) {
_socket!.close();
_socket = null;
}
} else {
if (_serialPort != null) {
_serialPortReader?.close();
_serialPort!.close();
_serialPort = null;
}
}
}
_connectSerialPort() {
_serialPort = SerialPort(_port);
if (!_serialPort!.openReadWrite()) {
throw Exception(SerialPort.lastError);
}
var config = _serialPort!.config;
config.baudRate = _baudrate;
config.bits = 8;
config.parity = 0;
config.stopBits = 1;
config.setFlowControl(0);
_serialPort!.config = config;
_serialPortReader = SerialPortReader(_serialPort!);
_serialPortReader!.stream.listen(_onData);
if (_serialPort != null) {
int i = 0;
_serialPort!.write(Uint8List.fromList(um982Init[i].codeUnits));
Timer.periodic(const Duration(milliseconds: 100), (timer) {
if (_serialPort != null) {
_serialPort!.write(Uint8List.fromList(um982Init[i].codeUnits));
}
i++;
if (i == um982Init.length - 1) {
timer.cancel();
}
});
}
}
void _connectTcp() {
if (_host == "" || _portTcp == 0) {
return;
}
log("尝试连接$_host:$_port");
Socket.connect(_host, _portTcp).then((socket) {
_socket = socket;
log("连接成功");
socket.listen(_onData);
socket.handleError((error) {
log("error=$error");
});
socket.timeout(const Duration(seconds: 15), onTimeout: (sink) {
log("timeout");
socket.destroy();
_reconnect();
});
}).onError((error, stackTrace) {
log("error=$error");
_socket = null;
_reconnect();
});
}
void _reconnect() {
log("尝试重新连接...");
Future.delayed(const Duration(seconds: 5), () {
_connectTcp();
});
}
_onData(Uint8List data) {
var lines = lineSplitter.pushData(data);
for (int i = 0; i < lines.length; i++) {
try {
var s = sentence.parse(lines[i]);
switch (s.type) {
case TypeBESTPOSA:
var bestpos = BESTPOSA.newBESTPOSA(s);
// log("bestposa=${bestposa.lat},${bestposa.lon}");
_locationData.latitude = bestpos.lat;
_locationData.longitude = bestpos.lon;
_locationData.altitude = bestpos.hgt;
_locationData.adop = bestpos.adop;
_locationData.hdop = bestpos.hdop;
_locationData.vdop = bestpos.vdop;
_locationData.diffAge = bestpos.diffAge;
_locationData.fixQuality = bestpos.fixQuality;
// _locationData.pdop = bestpos.pdop;
break;
case TypeHEADINGA:
var h = HEADINGA.newHEADINGA(s);
// log("heading=${h.heading}");
_locationData.baseLength = h.length;
_locationData.heading = h.heading;
_locationData.pitch = h.pitch;
_locationData.numberSv = h.numberSv;
_locationData.numberSa = h.numberSa;
locationUpdate = true;
break;
case TypeRMC:
var rmc = RMC.newRMC(s);
_locationData.course = rmc.course;
// log("rmc=${rmc.latitude},${rmc.longitude},${rmc.speed}");
break;
case TypeGGA:
var gga = GGA.newGGA(s);
if (rtkBase != null) {
rtkBase!.sendGGA(s.raw);
}
// log("gga=${gga.latitude},${gga.longitude}");
_locationData.quality = gga.quality;
break;
case TypeVTG:
//
var vtg = VTG.newVTG(s);
// log("vtg=${vtg.groundSpeedKnots}");
_locationData.speed = vtg.groundSpeedKnots;
break;
case TypeGSA:
// 使
var gsa = GSA.newGSA(s);
// log("gsa=${gsa.pdop}");
// SV
break;
case TypeGSV:
//
var gsv = GSV.newGSV(s);
// log("gsv=${gsv.numberSVsInView}");
signalUpdate = true;
break;
default:
log('Unhandled sentence type: ${s.type}');
}
} catch (e) {
log("error=$e");
}
}
if (locationUpdate) {
locationStreamController.add(_locationData);
locationUpdate = false;
}
if (signalUpdate) {
signalStreamController.add(_signalData);
signalUpdate = false;
}
}
}
class LineSplitter {
pushData(Uint8List data) {
List<String> sentences = [];
if (endIndex + data.length > dataBuf.length) {
endIndex = 0;
sentenceStart = -1;
}
dataBuf.setAll(endIndex, data);
endIndex = endIndex += data.length;
int index = 0;
while (index < endIndex) {
if (sentenceStart < 0) {
if (startDelimiter.contains(dataBuf[index]) == false) {
index++;
} else {
sentenceStart = index;
seekIndex = index + 1;
}
} else {
for (; seekIndex < endIndex; seekIndex++) {
if (dataBuf[seekIndex] == 0x0a) {
sentences
.add(String.fromCharCodes(dataBuf, sentenceStart, seekIndex));
sentenceStart = -1;
index = seekIndex + 1;
break;
}
}
if (seekIndex == endIndex) {
break;
}
}
}
// log("index=$index,endIndex=$endIndex, data.length=${data.length}");
if (index == endIndex) {
endIndex = 0;
} else if (index > 0) {
dataBuf.setAll(0, dataBuf.sublist(index, endIndex));
sentenceStart = -1;
endIndex -= index;
}
return sentences;
}
int endIndex = 0;
int seekIndex = 0;
int sentenceStart = -1;
Uint8List dataBuf = Uint8List(4096);
static const startDelimiter = [0x24, 0x23]; //$23 #23
}

View File

@ -1,46 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'apb.dart';
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const String TypeAAM = 'AAM';
class AAM {
String statusArrivalCircleEntered;
String statusPerpendicularPassed;
double arrivalCircleRadius;
String arrivalCircleRadiusUnit;
String destinationWaypointID;
AAM(
{required this.statusArrivalCircleEntered,
required this.statusPerpendicularPassed,
required this.arrivalCircleRadius,
required this.arrivalCircleRadiusUnit,
required this.destinationWaypointID});
static AAM newAAM(BaseSentence s) {
var p = Parser(s);
p.assertType(TypeAAM);
return AAM(
statusArrivalCircleEntered: p.enumString(
0,
"arrival circle entered status",
[WPStatusArrivalCircleEnteredA, WPStatusArrivalCircleEnteredV]),
statusPerpendicularPassed: p.enumString(
1,
"perpendicularly passed status",
[WPStatusPerpendicularPassedA, WPStatusPerpendicularPassedV]),
arrivalCircleRadius: p.float64(2, "arrival circle radius"),
arrivalCircleRadiusUnit: p.enumString(3, "arrival circle radius units", [
DistanceUnitKilometre,
DistanceUnitNauticalMile,
DistanceUnitStatuteMile,
DistanceUnitMetre
]),
destinationWaypointID: p.string(4, "destination waypoint ID"),
);
}
}

View File

@ -1,40 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeABM = "ABM";
class ABM {
int numFragments;
int fragmentNumber;
int messageID;
String mmsi;
String channel;
int vdlMessageNumber;
List<int>
payload; // Assuming the byte array is represented as a list of integers
ABM({
required this.numFragments,
required this.fragmentNumber,
required this.messageID,
required this.mmsi,
required this.channel,
required this.vdlMessageNumber,
required this.payload,
});
static ABM newABM(BaseSentence s) {
var p = Parser(s);
return ABM(
numFragments: p.int64(0, 'number of fragments'),
fragmentNumber: p.int64(1, 'fragment number'),
messageID: p.int64(2, 'message ID'),
mmsi: p.string(3, 'MMSI'),
channel: p.string(4, 'channel'),
vdlMessageNumber: p.int64(5, 'VDL message number'),
payload: p.sixBitASCIIArmour(
6, p.int64(7, 'number of padding bits'), 'payload'),
);
}
}

View File

@ -1,20 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const String TypeACK = "ACK";
class ACK {
int alertIdentifier;
ACK({ required this.alertIdentifier});
static ACK newACK(BaseSentence s) {
var p = Parser(s);
return ACK(
alertIdentifier: p.int64(0, 'alert identifier'),
);
}
}

View File

@ -1,40 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeACN = "ACN";
class ACN {
Object time; // Assuming Time is a custom type
String manufacturerMnemonicCode;
int alertIdentifier;
int alertInstance;
String command;
String state;
ACN(
{required this.time,
required this.manufacturerMnemonicCode,
required this.alertIdentifier,
required this.alertInstance,
required this.command,
required this.state});
static ACN newACN(BaseSentence s) {
var p = Parser(s);
return ACN(
time: p.time(0, 'time'),
manufacturerMnemonicCode: p.string(1, 'manufacturer mnemonic code'),
alertIdentifier: p.int64(2, 'alert identifier'),
alertInstance: p.int64(3, 'alert instance'),
command: p.enumString(4, 'alert command', [
'A',
'Q',
'O',
'S'
]), // Assuming AlertCommandAcknowledge, AlertCommandRequestRepeatInformation, AlertCommandResponsibilityTransfer, AlertCommandSilence are represented as 'A', 'Q', 'O', 'S' respectively
state: p.string(5, 'alarm state'),
);
}
}

View File

@ -1,42 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeALA = "ALA";
class ALA {
Time time;
String systemIndicator;
String subSystemIndicator;
int instanceNumber;
int type;
String condition;
String alarmAckState;
String message;
ALA({
required this.time,
required this.systemIndicator,
required this.subSystemIndicator,
required this.instanceNumber,
required this.type,
required this.condition,
required this.alarmAckState,
required this.message,
});
static ALA newALA(BaseSentence s) {
var p = Parser(s);
return ALA(
time: p.time(0, "time"),
systemIndicator: p.string(1, "system indicator"),
subSystemIndicator: p.string(2, "subsystem indicator"),
instanceNumber: p.int64(3, "instance number"),
type: p.int64(4, "type"),
condition: p.string(5, "condition"), // string as there could be more
alarmAckState: p.string(
6, "alarm acknowledgement state"), // string as there could be more
message: p.string(7, "message"),
);
}
}

View File

@ -1,66 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeALC = "ALC";
class ALC {
int numFragments; // 0
int fragmentNumber; // 1
int messageID; // 2
int entriesNumber; // 3
List<ALCAlertEntry> alertEntries;
ALC({
required this.numFragments,
required this.fragmentNumber,
required this.messageID,
required this.entriesNumber,
required this.alertEntries,
});
static ALC newALC(BaseSentence s) {
var p = Parser(s);
var alc = ALC(
numFragments: p.int64(0, "number of fragments"),
fragmentNumber: p.int64(1, "fragment number"),
messageID: p.int64(2, "message ID"),
entriesNumber: p.int64(3, "entries number"),
alertEntries: []);
int fieldCount = s.fields.length;
if (fieldCount == 4) {
return alc;
}
if (fieldCount % 4 != 0) {
return alc;
}
for (int i = 4; i < fieldCount; i = i + 4) {
var tmp = ALCAlertEntry(
manufacturerMnemonicCode:
p.string(i * 4 + 4, "manufacturer mnemonic code"),
alertIdentifier: p.int64(i * 4 + 5, "alert identifier"),
alertInstance: p.int64(i * 4 + 6, "alert instance"),
revisionCounter: p.int64(i * 4 + 7, "revision counter"),
);
alc.alertEntries.add(tmp);
}
return alc;
}
}
class ALCAlertEntry {
String manufacturerMnemonicCode; // i+4
int alertIdentifier; // i+5
int alertInstance; // i+6
int revisionCounter; // i+7
ALCAlertEntry({
required this.manufacturerMnemonicCode,
required this.alertIdentifier,
required this.alertInstance,
required this.revisionCounter,
});
}

View File

@ -1,55 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeALF = "ALF";
class ALF {
int numFragments; // 0
int fragmentNumber; // 1
int messageID; // 2
Time time; // 3
String category; // 4
String priority; // 5
String state; // 6
String manufacturerMnemonicCode; // 7
int alertIdentifier; // 8
int alertInstance; // 9
int revisionCounter; // 10
int escalationCounter; // 11
String text; // 12
ALF(
{required this.numFragments,
required this.fragmentNumber,
required this.messageID,
required this.time,
required this.category,
required this.priority,
required this.state,
required this.manufacturerMnemonicCode,
required this.alertIdentifier,
required this.alertInstance,
required this.revisionCounter,
required this.escalationCounter,
required this.text});
static ALF newALF(BaseSentence s) {
var p = Parser(s);
return ALF(
numFragments: p.int64(0, "number of fragments"),
fragmentNumber: p.int64(1, "fragment number"),
messageID: p.int64(2, "message ID"),
time: p.time(3, "time"),
category: p.enumString(4, "alarm category", ["A", "B", "C"]),
priority: p.enumString(5, "alarm priority", ["E", "A", "C", "W"]),
state: p.enumString(6, "alarm state", ["A", "S", "O", "U", "V", "N"]),
manufacturerMnemonicCode: p.string(7, "manufacturer mnemonic code"),
alertIdentifier: p.int64(8, "alert identifier"),
alertInstance: p.int64(9, "alert instance"),
revisionCounter: p.int64(10, "revision counter"),
escalationCounter: p.int64(11, "escalation counter"),
text: p.string(12, "alert text"),
);
}
}

View File

@ -1,35 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
import 'types.dart';
const TypeALR = "ALR";
class ALR {
Time time; // 0
int alarmIdentifier; // 1
String condition; // 2
String state; // 3
String description; // 4
ALR(
{required this.time,
required this.alarmIdentifier,
required this.condition,
required this.state,
required this.description});
static ALR newALR(BaseSentence s) {
var p = Parser(s);
return ALR(
time: p.time(0, "time"),
alarmIdentifier: p.int64(1, "unique alarm number"),
condition:
p.enumString(2, "alarm condition", [StatusValid, StatusInvalid]),
state: p.enumString(3, "alarm state", [StatusValid, StatusInvalid]),
description: p.string(4, "description"),
);
}
}

View File

@ -1,108 +0,0 @@
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
// ignore_for_file: constant_identifier_names
// Type constants
const String TypeAPB = "APB"; // type of APB sentence for Autopilot Sentence "B"
// Status constants for APB
const String StatusWarningASetAPB = "V"; // LORAN-C Blink or SNR warning
const String StatusWarningAClearORNotUsedAPB =
"A"; // general warning flag or other navigation systems when a reliable fix is not available
const String StatusWarningBSetAPB =
"A"; // Loran-C Cycle Lock warning OK or not used
const String StatusWarningBClearAPB = "V"; // Loran-C Cycle Lock warning flag
// Autopilot related constants (used in APB, APA, AAM)
const String WPStatusPerpendicularPassedA =
"A"; // warning for passing the perpendicular of the course line of waypoint
const String WPStatusPerpendicularPassedV =
"V"; // indicates for not passing of the perpendicular of the course line of waypoint
const String WPStatusArrivalCircleEnteredA =
"A"; // warning of entering to waypoint circle
const String WPStatusArrivalCircleEnteredV =
"V"; // indicates of not yet entered into waypoint circle
class APB {
String statusGeneralWarning;
String statusLockWarning;
double crossTrackErrorMagnitude;
String directionToSteer;
String crossTrackUnits;
String statusArrivalCircleEntered;
String statusPerpendicularPassed;
double bearingOriginToDest;
String bearingOriginToDestType;
String destinationWaypointID;
double bearingPresentToDest;
String bearingPresentToDestType;
double heading;
String headingType;
String ffaMode;
APB({
required this.statusGeneralWarning,
required this.statusLockWarning,
required this.crossTrackErrorMagnitude,
required this.directionToSteer,
required this.crossTrackUnits,
required this.statusArrivalCircleEntered,
required this.statusPerpendicularPassed,
required this.bearingOriginToDest,
required this.bearingOriginToDestType,
required this.destinationWaypointID,
required this.bearingPresentToDest,
required this.bearingPresentToDestType,
required this.heading,
required this.headingType,
this.ffaMode = "",
});
static APB newAPB(BaseSentence s) {
Parser p = Parser(s);
return APB(
statusGeneralWarning: p.enumString(0, "general warning",
[StatusWarningAClearORNotUsedAPB, StatusWarningASetAPB]),
statusLockWarning: p.enumString(
1, "lock warning", [StatusWarningBSetAPB, StatusWarningBClearAPB]),
crossTrackErrorMagnitude: p.float64(2, "cross track error magnitude"),
directionToSteer:
p.enumString(3, "direction to steer", ["Left", "Right"]),
crossTrackUnits: p.enumString(4, "cross track units", [
DistanceUnitKilometre,
DistanceUnitNauticalMile,
DistanceUnitStatuteMile,
DistanceUnitMetre
]),
statusArrivalCircleEntered: p.enumString(
5,
"arrival circle entered status",
[WPStatusArrivalCircleEnteredA, WPStatusArrivalCircleEnteredV]),
statusPerpendicularPassed: p.enumString(
6,
"perpendicularly passed status",
[WPStatusPerpendicularPassedA,
WPStatusPerpendicularPassedV]),
bearingOriginToDest: p.float64(7, "origin bearing to destination"),
bearingOriginToDestType: p.enumString(
8,
"origin bearing to destination type",
["HeadingMagnetic",
"HeadingTrue"]),
destinationWaypointID: p.string(9, "destination waypoint ID"),
bearingPresentToDest: p.float64(10, "present bearing to destination"),
bearingPresentToDestType: p.enumString(
11,
"present bearing to destination type",
["HeadingMagnetic",
"HeadingTrue"]),
heading: p.float64(12, "heading"),
headingType:
p.enumString(13, "heading type", ["HeadingMagnetic", "HeadingTrue"]),
ffaMode: p.string(14,
"FAA mode"), // not enum because some devices have proprietary "non-nmea" values
);
}
}

View File

@ -1,44 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
const TypeARC = "ARC";
const AlertCommandAcknowledge = "A";
// AlertCommandRequestRepeatInformation means request/repeat information
const AlertCommandRequestRepeatInformation = "Q";
// AlertCommandResponsibilityTransfer means responsibility transfer
const AlertCommandResponsibilityTransfer = "O";
// AlertCommandSilence means silence
const AlertCommandSilence = "S";
class ARC {
Time time;
String manufacturerMnemonicCode;
int alertIdentifier;
int alertInstance;
String command;
ARC(
{required this.time,
required this.manufacturerMnemonicCode,
required this.alertIdentifier,
required this.alertInstance,
required this.command});
static ARC newARC(BaseSentence s) {
var p = Parser(s);
return ARC(
time: p.time(0, "time"),
manufacturerMnemonicCode: p.string(1, "manufacturer mnemonic code"),
alertIdentifier: p.int64(2, "alert identifier"),
alertInstance: p.int64(3, "alert instance"),
command: p.enumString(4, "refused alert command", [
AlertCommandAcknowledge,
AlertCommandRequestRepeatInformation,
AlertCommandResponsibilityTransfer,
AlertCommandSilence
]),
);
}
}

View File

@ -1,35 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeBBM = "BBM";
class BBM {
int numFragments;
int fragmentNumber;
int messageID;
String channel; // Assuming default value is an empty string
int vDLMessageNumber;
List<int> payload;
BBM({
required this.numFragments,
required this.fragmentNumber,
required this.messageID,
required this.channel,
required this.vDLMessageNumber,
required this.payload,
});
static BBM newBBM(BaseSentence s) {
var p = Parser(s);
return BBM(
numFragments: p.int64(0, "number of fragments"),
fragmentNumber: p.int64(1, "fragment number"),
messageID: p.int64(2, "message ID"),
channel: p.string(3, "channel"),
vDLMessageNumber: p.int64(4, "VDL message number"),
payload: p.sixBitASCIIArmour(
5, p.int64(6, "number of padding bits"), "payload"),
);
}
}

View File

@ -1,58 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeBEC = "BEC";
class BEC {
Time time; // UTC Time
double latitude; // latitude of waypoint
double longitude; // longitude of waypoint
double bearingTrue; // true bearing in degrees
bool bearingTrueValid; // is unit of true bearing valid
double bearingMagnetic; // magnetic bearing in degrees
bool bearingMagneticValid; // is unit of magnetic bearing valid
double distanceNauticalMiles; // distance to waypoint in nautical miles
bool
distanceNauticalMilesValid; // is unit of distance to waypoint nautical miles valid
String destinationWaypointID; // destination waypoint ID
BEC({
required this.time,
required this.latitude,
required this.longitude,
required this.bearingTrue,
required this.bearingTrueValid,
required this.bearingMagnetic,
required this.bearingMagneticValid,
required this.distanceNauticalMiles,
required this.distanceNauticalMilesValid,
required this.destinationWaypointID,
});
static BEC newBEC(BaseSentence s) {
var p = Parser(s);
return BEC(
time: p.time(0, "time"),
latitude: p.latLong(1, 2, "latitude"),
longitude: p.latLong(3, 4, "longitude"),
bearingTrue: p.float64(5, "true bearing"),
bearingTrueValid:
p.enumString(6, "true bearing unit valid", [BearingTrue]) ==
BearingTrue,
bearingMagnetic: p.float64(7, "magnetic bearing"),
bearingMagneticValid:
p.enumString(8, "magnetic bearing unit valid", [BearingMagnetic]) ==
BearingMagnetic,
distanceNauticalMiles:
p.float64(9, "distance to waypoint is nautical miles"),
distanceNauticalMilesValid: p.enumString(
10,
"is distance to waypoint nautical miles valid",
[DistanceUnitNauticalMile]) ==
DistanceUnitNauticalMile,
destinationWaypointID: p.string(11, "destination waypoint ID"),
);
}
}

View File

@ -1,50 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeBESTPOSA = "BESTPOSA";
class BESTPOSA {
double lat;
double lon;
double hgt;
String fixQuality;
double undulation;
String datum;
double diffAge;
double solAge;
double hdop;
double vdop;
double adop;
String baseId;
BESTPOSA(
{required this.lat,
required this.lon,
required this.hgt,
required this.undulation,
required this.fixQuality,
required this.datum,
required this.diffAge,
required this.solAge,
required this.hdop,
required this.vdop,
required this.adop,
required this.baseId});
static BESTPOSA newBESTPOSA(BaseSentence s) {
var p = Parser(s);
return BESTPOSA(
fixQuality: p.string(9, "fix_quality"),
lat: p.float64(10, "lat"),
lon: p.float64(11, "lon"),
hgt: p.float64(12, "hgt"),
undulation: p.float64(13, "undulation"),
datum: p.string(14, "datum"),
vdop: p.float64(15, "vdop"),
hdop: p.float64(16, "hdop"),
adop: p.float64(17, "adop"),
baseId: p.string(18, "baseId"),
diffAge: p.float64(19, "diff_age"),
solAge: p.float64(20, "sol_age"));
}
}

View File

@ -1,42 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeBOD = "BOD";
class BOD {
double bearingTrue; // true bearing in degrees
String bearingTrueType; // is type of true bearing
double bearingMagnetic; // magnetic bearing in degrees
String bearingMagneticType; // is type of magnetic bearing
String destinationWaypointID; // destination waypoint ID
String originWaypointID; // origin waypoint ID
BOD(
{required this.bearingTrue,
required this.bearingTrueType,
required this.bearingMagnetic,
required this.bearingMagneticType,
required this.destinationWaypointID,
required this.originWaypointID});
static BOD newBOD(BaseSentence s) {
var p = Parser(s);
var bod = BOD(
bearingTrue: p.float64(0, "true bearing"),
bearingTrueType: p.enumString(1, "true bearing type", [BearingTrue]),
bearingMagnetic: p.float64(2, "magnetic bearing"),
bearingMagneticType:
p.enumString(3, "magnetic bearing type", [BearingMagnetic]),
destinationWaypointID: p.string(4, "destination waypoint ID"),
originWaypointID: "",
);
if (s.fields.length > 5) {
bod.originWaypointID = p.string(5, "origin waypoint ID");
}
return bod;
}
}

View File

@ -1,61 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeBWC = "BWC";
class BWC {
Time time; // UTC Time
double latitude; // latitude of waypoint
double longitude; // longitude of waypoint
double bearingTrue; // true bearing in degrees
String bearingTrueType; // is type of true bearing
double bearingMagnetic; // magnetic bearing in degrees
String bearingMagneticType; // is type of magnetic bearing
double distanceNauticalMiles; // distance to waypoint in nautical miles
String
distanceNauticalMilesUnit; // is unit of distance to waypoint nautical miles
String destinationWaypointID; // destination waypoint ID
String ffaMode; // FAA mode indicator (filled in NMEA 2.3 and later)
BWC({
required this.time,
required this.latitude,
required this.longitude,
required this.bearingTrue,
required this.bearingTrueType,
required this.bearingMagnetic,
required this.bearingMagneticType,
required this.distanceNauticalMiles,
required this.distanceNauticalMilesUnit,
required this.destinationWaypointID,
required this.ffaMode,
});
static BWC newBWC(BaseSentence s) {
var p = Parser(s);
var bwc = BWC(
time: p.time(0, "time"),
latitude: p.latLong(1, 2, "latitude"),
longitude: p.latLong(3, 4, "longitude"),
bearingTrue: p.float64(5, "true bearing"),
bearingTrueType: p.enumString(6, "true bearing type", [BearingTrue]),
bearingMagnetic: p.float64(7, "magnetic bearing"),
bearingMagneticType:
p.enumString(8, "magnetic bearing type", [BearingMagnetic]),
distanceNauticalMiles:
p.float64(9, "distance to waypoint is nautical miles"),
distanceNauticalMilesUnit: p.enumString(
10,
"is distance to waypoint nautical miles unit",
[DistanceUnitNauticalMile]),
destinationWaypointID: p.string(11, "destination waypoint ID"),
ffaMode: "");
if (s.fields.length > 12) {
bwc.ffaMode = p.string(12, "FFA mode");
}
return bwc;
}
}

View File

@ -1,61 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
import 'types.dart';
const TypeBWR = "BWR";
class BWR {
Time time; // UTC Time
double latitude; // latitude of waypoint
double longitude; // longitude of waypoint
double bearingTrue; // true bearing in degrees
String bearingTrueType; // is type of true bearing
double bearingMagnetic; // magnetic bearing in degrees
String bearingMagneticType; // is type of magnetic bearing
double distanceNauticalMiles; // distance to waypoint in nautical miles
String
distanceNauticalMilesUnit; // is unit of distance to waypoint nautical miles
String destinationWaypointID; // destination waypoint ID
String ffaMode; // FAA mode indicator (filled in NMEA 2.3 and later)
BWR({
required this.time,
required this.latitude,
required this.longitude,
required this.bearingTrue,
required this.bearingTrueType,
required this.bearingMagnetic,
required this.bearingMagneticType,
required this.distanceNauticalMiles,
required this.distanceNauticalMilesUnit,
required this.destinationWaypointID,
required this.ffaMode,
});
static BWR newBWR(BaseSentence s) {
var p = Parser(s);
var bwr = BWR(
time: p.time(0, "time"),
latitude: p.latLong(1, 2, "latitude"),
longitude: p.latLong(3, 4, "longitude"),
bearingTrue: p.float64(5, "true bearing"),
bearingTrueType: p.enumString(6, "true bearing type", [BearingTrue]),
bearingMagnetic: p.float64(7, "magnetic bearing"),
bearingMagneticType:
p.enumString(8, "magnetic bearing type", [BearingMagnetic]),
distanceNauticalMiles:
p.float64(9, "distance to waypoint is nautical miles"),
distanceNauticalMilesUnit: p.enumString(
10,
"is distance to waypoint nautical miles unit",
[DistanceUnitNauticalMile]),
destinationWaypointID: p.string(11, "destination waypoint ID"),
ffaMode: "");
if (s.fields.length > 12) {
bwr.ffaMode = p.string(12,
"FAA mode"); // not enum because some devices have proprietary "non-nmea" values
}
return bwr;
}
}

View File

@ -1,37 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeBWW = "BWW";
class BWW {
double bearingTrue; // true bearing in degrees
String bearingTrueType; // is type of true bearing
double bearingMagnetic; // magnetic bearing in degrees
String bearingMagneticType; // is type of magnetic bearing
String destinationWaypointID; // destination waypoint ID
String originWaypointID; // origin waypoint ID
BWW({
required this.bearingTrue,
required this.bearingTrueType,
required this.bearingMagnetic,
required this.bearingMagneticType,
required this.destinationWaypointID,
required this.originWaypointID,
});
static BWW newBWW(BaseSentence s) {
var p = Parser(s);
return BWW(
bearingTrue: p.float64(0, "true bearing"),
bearingTrueType: p.enumString(1, "true bearing type", [BearingTrue]),
bearingMagnetic: p.float64(2, "magnetic bearing"),
bearingMagneticType:
p.enumString(3, "magnetic bearing type", [BearingMagnetic]),
destinationWaypointID: p.string(4, "destination waypoint ID"),
originWaypointID: p.string(5, "origin waypoint ID"),
);
}
}

View File

@ -1,38 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeDBK = "DBK";
class DBK {
double depthFeet; // Depth, feet
String depthFeetUnit; // f = feet
double depthMeters; // Depth, meters
String depthMetersUnit; // M = meters
double depthFathoms; // Depth, Fathoms
String depthFathomsUnit; // F = Fathoms
DBK({
required this.depthFeet,
required this.depthFeetUnit,
required this.depthMeters,
required this.depthMetersUnit,
required this.depthFathoms,
required this.depthFathomsUnit,
});
static DBK newDBK(BaseSentence s) {
var p = Parser(s);
return DBK(
depthFeet: p.float64(0, "depth feet"),
depthFeetUnit: p.enumString(1, "depth feet unit", [DistanceUnitFeet]),
depthMeters: p.float64(2, "depth meters"),
depthMetersUnit:
p.enumString(3, "depth meters unit", [DistanceUnitMetre]),
depthFathoms: p.float64(4, "depth fathom"),
depthFathomsUnit:
p.enumString(5, "depth fathom unit", [DistanceUnitFathom]),
);
}
}

View File

@ -1,38 +0,0 @@
// ignore_for_file: non_constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
var TypeDBS = "DBS";
class DBS {
double depthFeet; // Depth, feet
String depthFeetUnit; // f = feet
double depthMeters; // Depth, meters
String depthMeterUnit; // M = meters
double depthFathoms; // Depth, Fathoms
String depthFathomUnit; // F = Fathoms
DBS({
required this.depthFathomUnit,
required this.depthFathoms,
required this.depthFeet,
required this.depthFeetUnit,
required this.depthMeterUnit,
required this.depthMeters,
});
static DBS newDBS(BaseSentence s) {
var p = Parser(s);
return DBS(
depthFeet: p.float64(0, "depth feet"),
depthFeetUnit: p.enumString(1, "depth feet unit", [DistanceUnitFeet]),
depthMeters: p.float64(2, "depth meters"),
depthMeterUnit: p.enumString(3, "depth feet unit", [DistanceUnitMetre]),
depthFathoms: p.float64(4, "depth fathoms"),
depthFathomUnit:
p.enumString(5, "depth fathom unit", [DistanceUnitFathom]),
);
}
}

View File

@ -1,25 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeDBT = "DBT";
class DBT {
double depthFeet;
double depthMeters;
double depthFathoms;
DBT({
required this.depthFeet,
required this.depthMeters,
required this.depthFathoms,
});
static DBT newDBT(BaseSentence s) {
var p = Parser(s);
return DBT(
depthFeet: p.float64(0, "depth_feet"),
depthMeters: p.float64(2, "depth_meters"),
depthFathoms: p.float64(4, "depth_fathoms"),
);
}
}

View File

@ -1,68 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'gga.dart';
import 'gsa.dart';
import 'gll.dart';
import 'gns.dart';
import 'gsv.dart';
import 'hdt.dart';
import 'rmc.dart';
import 'vtg.dart';
import 'zda.dart';
const PrefixGNGNS = "GNGNS";
const PrefixGPGGA = "GPGGA";
const PrefixGPGLL = "GPGLL";
const PrefixGPGSA = "GPGSA";
const PrefixGPRMC = "GPRMC";
const PrefixPGRME = "PGRME";
const PrefixGLGSV = "GLGSV";
const PrefixGNGGA = "GNGGA";
const PrefixGNRMC = "GNRMC";
const PrefixGPGSV = "GPGSV";
const PrefixGPHDT = "GPHDT";
const PrefixGPVTG = "GPVTG";
const PrefixGPZDA = "GPZDA";
// Deprecated: Use GSV instead
typedef GLGSV = GSV;
// Deprecated: Use GSVInfo instead
typedef GLGSVInfo = GSVInfo;
// Deprecated: Use GGA instead
typedef GNGGA = GGA;
// Deprecated: Use GNS instead
typedef GNGNS = GNS;
// Deprecated: Use RCM instead
typedef GNRMC = RMC;
// Deprecated: Use GGA instead
typedef GPGGA = GGA;
// Deprecated: Use GLL instead
typedef GPGLL = GLL;
// Deprecated: Use GSA instead
typedef GPGSA = GSA;
// Deprecated: Use GSV instead
typedef GPGSV = GSV;
// Deprecated: Use GSVInfo instead
typedef GPGSVInfo = GSVInfo;
// Deprecated: Use HDT instead
typedef GPHDT = HDT;
// Deprecated: Use RMC instead
typedef GPRMC = RMC;
// Deprecated: Use VTG instead
typedef GPVTG = VTG;
// Deprecated: Use ZDA instead
typedef GPZDA = ZDA;

View File

@ -1,66 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeDOR = "DOR";
// TypeSingleDoorDOR is type for single door related event
const TypeSingleDoorDOR = "E";
// TypeFaultDOR is type for fault with door
const TypeFaultDOR = "F";
// TypeSectionDOR is type for section of doors related event
const TypeSectionDOR = "S";
// DoorStatusOpenDOR is status for open door
const DoorStatusOpenDOR = "O";
// DoorStatusClosedDOR is status for closed door
const DoorStatusClosedDOR = "C";
// DoorStatusFaultDOR is status for fault with door
const DoorStatusFaultDOR = "X";
// SwitchSettingHarbourModeDOR is setting for Harbour mode (allowed open)
const SwitchSettingHarbourModeDOR = "O";
// SwitchSettingSeaModeDOR is setting for Sea mode (ordered closed)
const SwitchSettingSeaModeDOR = "C";
class DOR {
String type;
Time time;
String systemIndicator;
String divisionIndicator1;
int divisionIndicator2;
int doorNumberOrCount;
String doorStatus;
String switchSetting;
String message;
DOR(
{required this.type,
required this.time,
required this.systemIndicator,
required this.divisionIndicator1,
required this.divisionIndicator2,
required this.doorNumberOrCount,
required this.doorStatus,
required this.switchSetting,
required this.message});
static DOR newDOR(BaseSentence s) {
var p = Parser(s);
return DOR(
type: p.enumString(
0, "message type", [TypeSingleDoorDOR, TypeFaultDOR, TypeSectionDOR]),
time: p.time(1, "time"),
systemIndicator: p.string(2, "system indicator"),
divisionIndicator1: p.string(3, "division indicator 1"),
divisionIndicator2: p.int64(4, "division indicator 2"),
doorNumberOrCount: p.int64(5, "door number or count"),
doorStatus: p.enumString(6, "door state",
[DoorStatusOpenDOR, DoorStatusClosedDOR, DoorStatusFaultDOR]),
switchSetting: p.enumString(7, "switch setting mode",
[SwitchSettingHarbourModeDOR, SwitchSettingSeaModeDOR]),
message: p.string(8, "message"),
);
}
}

View File

@ -1,25 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeDPT = "DPT";
class DPT {
double depth;
double offset;
double? rangeScale; // Optional property
DPT({required this.depth, required this.offset, this.rangeScale});
static DPT newDPT(BaseSentence s) {
var p = Parser(s);
double rangeScale = 0;
if (s.fields.length > 2) {
rangeScale = p.float64(2, "range scale");
}
return DPT(
depth: p.float64(0, "depth"),
offset: p.float64(1, "offset"),
rangeScale: rangeScale);
}
}

View File

@ -1,66 +0,0 @@
// TypeDSC type of DSC sentence for Digital Selective Calling Information
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
const TypeDSC = "DSC";
// AcknowledgementRequestDSC is type for Acknowledge request
const AcknowledgementRequestDSC = "R";
// AcknowledgementDSC is type for Acknowledgement
const AcknowledgementDSC = "B";
// AcknowledgementNeitherDSC is type for Neither (end of sequence)
const AcknowledgementNeitherDSC = "S";
class DSC {
String formatSpecifier;
String address;
String category;
String distressCauseOrTeleCommand1;
String commandTypeOrTeleCommand2;
String positionOrCanal;
String timeOrTelephoneNumber;
String mmsi;
String distressCause;
String acknowledgement;
String expansionIndicator;
DSC({
required this.formatSpecifier,
required this.address,
required this.category,
required this.distressCauseOrTeleCommand1,
required this.commandTypeOrTeleCommand2,
required this.positionOrCanal,
required this.timeOrTelephoneNumber,
required this.mmsi,
required this.distressCause,
required this.acknowledgement,
required this.expansionIndicator,
});
static DSC newDSC(BaseSentence s) {
var p = Parser(s);
return DSC(
formatSpecifier: p.string(0, "format specifier"),
address: p.string(1, "address"),
category: p.string(2, "category"),
distressCauseOrTeleCommand1:
p.string(3, "cause of the distress or first telecommand"),
commandTypeOrTeleCommand2:
p.string(4, "type of communication or second telecommand"),
positionOrCanal: p.string(5, "position or canal"),
timeOrTelephoneNumber: p.string(6, "time or telephone"),
mmsi: p.string(7, "MMSI"),
distressCause: p.string(8, "distress cause"),
acknowledgement: p.enumString(9, "acknowledgement", [
AcknowledgementRequestDSC,
" $AcknowledgementRequestDSC",
AcknowledgementDSC,
" $AcknowledgementDSC",
AcknowledgementNeitherDSC,
" $AcknowledgementNeitherDSC",
]).trim(),
expansionIndicator: p.string(10, "expansion indicator"),
);
}
}

View File

@ -1,32 +0,0 @@
// ignore_for_file: constant_identifier_names
const TypeDSE = "DSE";
// AcknowledgementAutomaticDSE is type for automatic
const AcknowledgementAutomaticDSE = "A";
// AcknowledgementRequestDSE is type for request
const AcknowledgementRequestDSE = "R";
// AcknowledgementQueryDSE is type for query
const AcknowledgementQueryDSE = "Q";
class DSE {
int totalNumber;
int number;
String acknowledgement;
String mmsi;
List<DSEDataSet> dataSets;
DSE(
{required this.totalNumber,
required this.number,
required this.acknowledgement,
required this.mmsi,
required this.dataSets});
}
class DSEDataSet {
String code;
String data;
DSEDataSet(this.code, this.data);
}

View File

@ -1,23 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
const TypeDTM = "DTM";
class DTM {
String localDatumCode;
String localDatumSubcode;
double latitudeOffsetMinute;
double longitudeOffsetMinute;
double altitudeOffsetMeters;
String datumName;
DTM(
{required this.localDatumCode,
required this.localDatumSubcode,
required this.latitudeOffsetMinute,
required this.longitudeOffsetMinute,
required this.altitudeOffsetMeters,
required this.datumName});
static newDTM(BaseSentence s) {}
}

View File

@ -1,75 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeGGA = "GGA";
// Invalid fix quality.
const Invalid = "0";
// GPS fix quality
const GPS = "1";
// DGPS fix quality
const DGPS = "2";
// PPS fix
const PPS = "3";
// RTK real time kinematic fix
const RTK = "4";
// FRTK float RTK fix
const FRTK = "5";
// EST estimated fix.
const EST = "6";
class GGA {
// Time of fix.
Time time;
// Latitude.
double latitude;
// Longitude.
double longitude;
// Quality of fix.
int quality;
// Number of satellites in use.
int numSatellites;
// Horizontal dilution of precision.
double hdop;
// Altitude.
double altitude;
// Geoidal separation.
double separation;
// Age of differential GPD data.
String dgpsAge;
// DGPS reference station ID.
String dgpsId;
// Constructor
GGA(
{required this.time,
required this.latitude,
required this.longitude,
required this.quality,
required this.numSatellites,
required this.hdop,
required this.altitude,
required this.separation,
required this.dgpsAge,
required this.dgpsId});
// Factory method to create GGA from parser
static GGA newGGA(BaseSentence s) {
var p = Parser(s);
return GGA(
time: p.time(0, "time"),
latitude: p.latLong(1, 2, "latitude"),
longitude: p.latLong(3, 4, "longitude"),
// fixQuality: p.enumString(
// 5, "fix quality", [Invalid, GPS, DGPS, PPS, RTK, FRTK, EST]),
quality: p.int64(5, "quality"),
numSatellites: p.int64(6, "number of satellites"),
hdop: p.float64(7, "hdop"),
altitude: p.float64(8, "altitude"),
separation: p.float64(10, "separation"),
dgpsAge: p.string(12, "dgps age"),
dgpsId: p.string(13, "dgps id"),
);
}
}

View File

@ -1,39 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
const TypeGLL = "GLL";
// ValidGLL character
const ValidGLL = "A";
// InvalidGLL character
const InvalidGLL = "V";
class GLL {
double latitude;
double longitude;
Time time;
String validity;
String ffaMode;
GLL(
{required this.latitude,
required this.longitude,
required this.time,
required this.validity,
required this.ffaMode});
static GLL newGLL(BaseSentence s) {
var p = Parser(s);
var ffaMode = "";
if (s.fields.length > 6) {
ffaMode = p.string(6, "FAA mode");
}
return GLL(
latitude: p.latLong(0, 1, "latitude"),
longitude: p.latLong(2, 3, "longitude"),
time: p.time(4, "time"),
validity: p.enumString(5, "validity", [ValidGLL, InvalidGLL]),
ffaMode: ffaMode);
}
}

View File

@ -1,88 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
import 'types.dart';
const TypeGNS = "GNS";
// NoFixGNS Character
const NoFixGNS = "N";
// AutonomousGNS Character
const AutonomousGNS = "A";
// DifferentialGNS Character
const DifferentialGNS = "D";
// PreciseGNS Character
const PreciseGNS = "P";
// RealTimeKinematicGNS Character
const RealTimeKinematicGNS = "R";
// FloatRTKGNS RealTime Kinematic Character
const FloatRTKGNS = "F";
// EstimatedGNS Fix Character
const EstimatedGNS = "E";
// ManualGNS Fix Character
const ManualGNS = "M";
// SimulatorGNS Character
const SimulatorGNS = "S";
class GNS {
Time time;
double latitude;
double longitude;
List<String> mode;
int svs;
double hdop;
double altitude;
double separation;
double age;
int station;
String navStatus;
GNS(
{required this.time,
required this.latitude,
required this.longitude,
required this.mode,
required this.svs,
required this.hdop,
required this.altitude,
required this.separation,
required this.age,
required this.station,
required this.navStatus});
static GNS newGNS(BaseSentence s) {
var p = Parser(s);
var gns = GNS(
time: p.time(0, "time"),
latitude: p.latLong(1, 2, "latitude"),
longitude: p.latLong(3, 4, "longitude"),
mode: p.enumChars(5, "mode", [
NoFixGNS,
AutonomousGNS,
DifferentialGNS,
PreciseGNS,
RealTimeKinematicGNS,
FloatRTKGNS,
EstimatedGNS,
ManualGNS,
SimulatorGNS
]),
svs: p.int64(6, "SVs"),
hdop: p.float64(7, "HDOP"),
altitude: p.float64(8, "altitude"),
separation: p.float64(9, "separation"),
age: p.float64(10, "age"),
station: p.int64(11, "station"),
navStatus: '',
);
if (s.fields.length >= 13) {
gns.navStatus = p.enumString(12, "navigation status", [
NavStatusSafe,
NavStatusCaution,
NavStatusUnsafe,
NavStatusNotValid,
]);
}
return gns;
}
}

View File

@ -1,62 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeGSA = "GSA";
// Auto - Field 1, auto or manual fix.
const Auto = "A";
// Manual - Field 1, auto or manual fix.
const Manual = "M";
// FixNone - Field 2, fix type.
const FixNone = "1";
// Fix2D - Field 2, fix type.
const Fix2D = "2";
// Fix3D - Field 2, fix type.
const Fix3D = "3";
class GSA {
String mode;
String fixType;
List<String> sv;
double pdop;
double hdop;
double vdop;
int systemID;
GSA(
{required this.mode,
required this.fixType,
required this.sv,
required this.pdop,
required this.hdop,
required this.vdop,
required this.systemID});
static GSA newGSA(BaseSentence s) {
var p = Parser(s);
var m = GSA(
mode: p.enumString(0, "selection mode", [Auto, Manual]),
fixType: p.enumString(1, "fix type", [FixNone, Fix2D, Fix3D]),
sv: [],
pdop: 0,
hdop: 0,
vdop: 0,
systemID: 0,
);
for (int i = 2; i < 14; i++) {
var v = p.string(i, "satellite in view");
if (v != "") {
m.sv.add(v);
}
}
m.pdop = p.float64(14, "pdop");
m.hdop = p.float64(15, "hdop");
m.vdop = p.float64(16, "vdop");
if (s.fields.length > 17) {
m.systemID = p.int64(17, "system ID");
}
return m;
}
}

View File

@ -1,69 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeGSV = "GSV";
class GSV {
int totalMessages;
int messageNumber;
int numberSVsInView;
List<GSVInfo> info;
int systemID;
int signalID;
GSV(
{required this.totalMessages,
required this.messageNumber,
required this.numberSVsInView,
required this.info,
required this.systemID,
required this.signalID});
static GSV newGSV(BaseSentence s) {
var p = Parser(s);
var gsv = GSV(
totalMessages: p.int64(0, "total number of messages"),
messageNumber: p.int64(1, "message number"),
numberSVsInView: p.int64(2, "number of SVs in view"),
info: [],
systemID: 0,
signalID: 0,
);
int i = 0;
for (; i < 4; i++) {
if (6 + i * 4 >= s.fields.length) {
break;
}
gsv.info.add(GSVInfo(
svprnNumber: p.int64(3 + i * 4, "SV prn number"),
elevation: p.int64(4 + i * 4, "elevation"),
azimuth: p.int64(5 + i * 4, "azimuth"),
snr: p.int64(6 + i * 4, "SNR"),
));
}
var idxSID = (6 + (i - 1) * 4) + 1;
if (s.fields.length == idxSID + 2) {
gsv.systemID = p.int64(idxSID, "system ID");
gsv.signalID = p.int64(idxSID + 1, "signal ID");
}
if (s.fields.length == idxSID + 1) {
gsv.signalID = p.int64(idxSID, "signal ID");
}
return gsv;
}
}
class GSVInfo {
int svprnNumber;
int elevation;
int azimuth;
int snr;
GSVInfo(
{required this.svprnNumber,
required this.elevation,
required this.azimuth,
required this.snr});
}

View File

@ -1,20 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeHDT = "HDT";
class HDT {
double heading;
bool isTrue;
HDT({required this.heading, required this.isTrue});
static HDT newHDT(BaseSentence s) {
var p = Parser(s);
return HDT(
heading: p.float64(0, "heading"),
isTrue: p.enumString(1, "true", ["T"]) == "T",
);
}
}

View File

@ -1,31 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeHEADINGA = "HEADINGA";
class HEADINGA {
double length;
double heading;
double pitch;
int numberSv;
int numberSa;
HEADINGA(
{required this.length,
required this.heading,
required this.pitch,
required this.numberSv,
required this.numberSa});
// HEADINGA({required this.heading, required this.isTrue});
static HEADINGA newHEADINGA(BaseSentence s) {
var p = Parser(s);
return HEADINGA(
length: p.float64(10, "length"),
heading: p.float64(11, "heading"),
pitch: p.float64(12, "pitch"),
numberSv: p.int64(17, "number of satellites"),
numberSa: p.int64(18, "number of satellites used"),
);
}
}

View File

@ -1,262 +0,0 @@
import 'sentence.dart';
import 'types.dart';
class Parser {
BaseSentence baseSentence;
String? _err;
Parser(this.baseSentence);
void assertType(String typ) {
if (baseSentence.type != typ) {
setErr('type', baseSentence.type);
}
}
String? err() {
return _err;
}
void setErr(String context, String value) {
_err ??= 'nmea: ${baseSentence.prefix()} invalid $context: $value';
}
String string(int i, String context) {
if (_err != null) {
return '';
}
if (i < 0 || i >= baseSentence.fields.length) {
setErr(context, 'index out of range');
return '';
}
return baseSentence.fields[i];
}
List<String> listString(int from, String context) {
if (_err != null) {
return [];
}
if (from < 0 || from >= baseSentence.fields.length) {
setErr(context, 'index out of range');
return [];
}
return baseSentence.fields.sublist(from);
}
String enumString(
int i,
String context,
List<String> options,
) {
String? s = string(i, context);
if (_err != null || s == '') {
return '';
}
if (options.contains(s)) {
return s;
} else {
setErr(context, s);
return '';
}
}
List<String> enumChars(int i, String context, List<String> options) {
String? s = string(i, context);
if (_err != null || s == '') {
return [];
}
List<String> strs = [];
for (int j = 0; j < s.length; j++) {
String rs = s[j];
if (options.contains(rs)) {
strs.add(rs);
}
}
if (strs.length != s.length) {
setErr(context, s);
return [];
}
return strs;
}
int hexInt64(int i, String context) {
String? s = string(i, context);
if (_err != null) {
return 0;
}
if (s == '') {
return 0;
}
int value = int.parse(s, radix: 16);
return value;
}
int int64(int i, String context) {
return nullInt64(i, context).value;
}
Int64 nullInt64(int i, String context) {
String? s = string(i, context);
if (_err != null) {
return Int64(0, false);
}
if (s == '') {
return Int64(0, false);
}
int? v = int.tryParse(s);
if (v == null) {
setErr(context, s);
return Int64(0, false);
}
return Int64(v, true);
}
double float64(int i, String context) {
return nullFloat64(i, context).value;
}
Float64 nullFloat64(int i, String context) {
String? s = string(i, context);
if (_err != null) {
return Float64(0, false);
}
if (s == '') {
return Float64(0, false);
}
double? v = double.tryParse(s);
if (v == null) {
setErr(context, s);
return Float64(0, false);
}
return Float64(v, true);
}
Time time(int i, String context) {
String? s = string(i, context);
if (_err != null) {
return Time(false, 0, 0, 0, 0);
}
try {
return parseTime(s);
} catch (e) {
setErr(context, s);
return Time(false, 0, 0, 0, 0);
}
}
Date date(int i, String context) {
String? s = string(i, context);
if (_err != null) {
return Date(false, 0, 0, 0);
}
try {
return parseDate(s);
} catch (e) {
setErr(context, s);
return Date(false, 0, 0, 0);
}
}
double latLong(int i, int j, String context) {
String a = string(i, context);
String b = string(j, context);
if (_err != null) {
return 0;
}
String s = '$a $b';
double? v = parseLatLong(s);
if ((b == 'North' || b == 'South') && (v < -90.0 || v > 90.0)) {
setErr(context, 'latitude is not in range (-90, 90)');
return 0;
} else if ((b == 'West' || b == 'East') && (v < -180.0 || v > 180.0)) {
setErr(context, 'longitude is not in range (-180, 180)');
return 0;
}
return v;
}
List<int> sixBitASCIIArmour(int i, int fillBits, String context) {
if (_err != null) {
return [];
}
if (fillBits < 0 || fillBits >= 6) {
setErr(context, 'fill bits');
return [];
}
List<int> payload = string(i, 'encoded payload').codeUnits;
int numBits = payload.length * 6 - fillBits;
if (numBits < 0) {
setErr(context, 'num bits');
return [];
}
List<int> result = List.filled(numBits, 0);
int resultIndex = 0;
for (int v in payload) {
if (v < 48 || v >= 120) {
setErr(context, 'data byte');
return [];
}
int d = v - 48;
if (d > 40) {
d -= 8;
}
for (int i = 5; i >= 0 && resultIndex < result.length; i--) {
result[resultIndex] = (d >> i) & 1;
resultIndex++;
}
}
return result;
}
}
class Time {
bool isValid;
int hour;
int minute;
int second;
int millisecond;
Time(this.isValid, this.hour, this.minute, this.second, this.millisecond);
}
Time parseTime(String s) {
if (s == "") {
return Time(false, 0, 0, 0, 0);
}
RegExp timeRe = RegExp(r"^\d{6}(\.\d*)?$");
if (!timeRe.hasMatch(s)) {
throw Exception("parse time: expected hhmmss.ss format, got '$s'");
}
int hour = int.parse(s.substring(0, 2));
int minute = int.parse(s.substring(2, 4));
double second = double.parse(s.substring(4));
int whole = second.floor(); //
double frac = second - whole; //
return Time(true, hour, minute, whole.toInt(), (frac * 1000).round());
}
mixin math {}
class Int64 {
int value;
bool valid;
Int64(this.value, this.valid);
}
class Float64 {
double value;
bool valid;
Float64(this.value, this.valid);
}

View File

@ -1,71 +0,0 @@
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
// ignore_for_file: constant_identifier_names
const TypeRMC = "RMC";
// ValidRMC character
const ValidRMC = "A";
// InvalidRMC character
const InvalidRMC = "V";
class RMC {
BaseSentence sentence; // sentence
Time time; // Time Stamp
String validity; // validity - A-ok, V-invalid
double latitude; // Latitude
double longitude; // Longitude
double speed; // Speed in knots
double course; // True course
Date date; // Date
double variation; // Magnetic variation
String? ffaMode; // FAA mode indicator (filled in NMEA 2.3 and later)
String? navStatus; // Nav Status (NMEA 4.1 and later)
RMC({
required this.sentence,
required this.time,
required this.validity,
required this.latitude,
required this.longitude,
required this.speed,
required this.course,
required this.date,
required this.variation,
this.ffaMode,
this.navStatus,
}) ;
static RMC newRMC(BaseSentence s) {
var p = Parser(s);
var m = RMC(
sentence: s,
time: p.time(0, "time"),
validity: p.enumString(1, "validity", [ValidRMC, InvalidRMC]),
latitude: p.latLong(2, 3, "latitude"),
longitude: p.latLong(4, 5, "longitude"),
speed: p.float64(6, "speed"),
course: p.float64(7, "course"),
date: p.date(8, "date"),
variation: p.float64(9, "variation"),//
);
if (p.enumString(10, "direction", [West, East]) == West) {
m.variation = 0 - m.variation;
}
if (s.fields.length > 11) {
m.ffaMode = p.string(11,
"FAA mode"); // not enum because some devices have proprietary "non-nmea" values
}
if (s.fields.length > 12) {
m.navStatus = p.enumString(12, "navigation status", [
NavStatusSafe,
NavStatusCaution,
NavStatusUnsafe,
NavStatusNotValid,
]);
}
return m;
}
}

View File

@ -1,34 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
import 'types.dart';
const TypeRSA = "RSA";
class RSA {
double starboardRudderAngle;
String starboardRudderAngleStatus;
double portRudderAngle;
String portRudderAngleStatus;
RSA({
required this.starboardRudderAngle,
required this.starboardRudderAngleStatus,
required this.portRudderAngle,
required this.portRudderAngleStatus,
});
static RSA newRSA(BaseSentence s) {
var p = Parser(s);
return RSA(
starboardRudderAngle: p.float64(0, "starboard rudder angle"),
starboardRudderAngleStatus: p.enumString(
1, "starboard rudder angle status", [StatusValid, StatusInvalid]),
portRudderAngle: p.float64(2, "port rudder angle"),
portRudderAngleStatus: p.enumString(
3, "port rudder angle status", [StatusValid, StatusInvalid]),
);
}
}

View File

@ -1,447 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'dart:core';
import 'dart:developer';
import 'tagblock.dart';
// TagBlockSep is the separator (slash `\`) that indicates start and end of tag block
const TagBlockSep = '\\';
// SentenceStart is the token to indicate the start of a sentence.
const SentenceStart = "\$";
// SentenceStartEncapsulated is the token to indicate the start of encapsulated data.
const SentenceStartEncapsulated = "!";
// ProprietarySentencePrefix is the token to indicate the start of parametric sentences.
const ProprietarySentencePrefix = 'P';
// QuerySentencePostfix is the suffix token to indicate the Query sentences.
const QuerySentencePostfix = 'Q';
// FieldSep is the token to delimit fields of a sentence.
const FieldSep = ",";
// ChecksumSep is the token to delimit the checksum of a sentence.
const ChecksumSep = "*";
// Define the interface for all NMEA sentences
abstract class Sentence {
String prefix();
String dataType();
String talkerID();
}
// Define the structure for the NMEA sentence
class BaseSentence implements Sentence {
String talker; // The talker id (e.g GP)
String type; // The data type (e.g GSA)
List<String> fields; // Array of fields
int checksum; // The (raw) Checksum
String raw; // The raw NMEA sentence received
TagBlock tagBlock; // NMEA tagblock
BaseSentence(this.talker, this.type, this.fields, this.checksum, this.raw,
this.tagBlock);
@override
String prefix() {
return talker + type;
}
@override
String dataType() {
return type;
}
@override
String talkerID() {
return talker;
}
String string() {
return raw;
}
}
// Define the callback type used to parse specific sentence variants
typedef ParserFunc = BaseSentence Function(BaseSentence s);
// Define the error returned when a parsed sentence is not supported
class NotSupportedError {
String prefix;
NotSupportedError(this.prefix);
@override
String toString() {
return 'nmea: sentence prefix \'$prefix\' not supported';
}
}
const List<int> aulCrcTable = [
0x00000000,
0x77073096,
0xee0e612c,
0x990951ba,
0x076dc419,
0x706af48f,
0xe963a535,
0x9e6495a3,
0x0edb8832,
0x79dcb8a4,
0xe0d5e91e,
0x97d2d988,
0x09b64c2b,
0x7eb17cbd,
0xe7b82d07,
0x90bf1d91,
0x1db71064,
0x6ab020f2,
0xf3b97148,
0x84be41de,
0x1adad47d,
0x6ddde4eb,
0xf4d4b551,
0x83d385c7,
0x136c9856,
0x646ba8c0,
0xfd62f97a,
0x8a65c9ec,
0x14015c4f,
0x63066cd9,
0xfa0f3d63,
0x8d080df5,
0x3b6e20c8,
0x4c69105e,
0xd56041e4,
0xa2677172,
0x3c03e4d1,
0x4b04d447,
0xd20d85fd,
0xa50ab56b,
0x35b5a8fa,
0x42b2986c,
0xdbbbc9d6,
0xacbcf940,
0x32d86ce3,
0x45df5c75,
0xdcd60dcf,
0xabd13d59,
0x26d930ac,
0x51de003a,
0xc8d75180,
0xbfd06116,
0x21b4f4b5,
0x56b3c423,
0xcfba9599,
0xb8bda50f,
0x2802b89e,
0x5f058808,
0xc60cd9b2,
0xb10be924,
0x2f6f7c87,
0x58684c11,
0xc1611dab,
0xb6662d3d,
0x76dc4190,
0x01db7106,
0x98d220bc,
0xefd5102a,
0x71b18589,
0x06b6b51f,
0x9fbfe4a5,
0xe8b8d433,
0x7807c9a2,
0x0f00f934,
0x9609a88e,
0xe10e9818,
0x7f6a0dbb,
0x086d3d2d,
0x91646c97,
0xe6635c01,
0x6b6b51f4,
0x1c6c6162,
0x856530d8,
0xf262004e,
0x6c0695ed,
0x1b01a57b,
0x8208f4c1,
0xf50fc457,
0x65b0d9c6,
0x12b7e950,
0x8bbeb8ea,
0xfcb9887c,
0x62dd1ddf,
0x15da2d49,
0x8cd37cf3,
0xfbd44c65,
0x4db26158,
0x3ab551ce,
0xa3bc0074,
0xd4bb30e2,
0x4adfa541,
0x3dd895d7,
0xa4d1c46d,
0xd3d6f4fb,
0x4369e96a,
0x346ed9fc,
0xad678846,
0xda60b8d0,
0x44042d73,
0x33031de5,
0xaa0a4c5f,
0xdd0d7cc9,
0x5005713c,
0x270241aa,
0xbe0b1010,
0xc90c2086,
0x5768b525,
0x206f85b3,
0xb966d409,
0xce61e49f,
0x5edef90e,
0x29d9c998,
0xb0d09822,
0xc7d7a8b4,
0x59b33d17,
0x2eb40d81,
0xb7bd5c3b,
0xc0ba6cad,
0xedb88320,
0x9abfb3b6,
0x03b6e20c,
0x74b1d29a,
0xead54739,
0x9dd277af,
0x04db2615,
0x73dc1683,
0xe3630b12,
0x94643b84,
0x0d6d6a3e,
0x7a6a5aa8,
0xe40ecf0b,
0x9309ff9d,
0x0a00ae27,
0x7d079eb1,
0xf00f9344,
0x8708a3d2,
0x1e01f268,
0x6906c2fe,
0xf762575d,
0x806567cb,
0x196c3671,
0x6e6b06e7,
0xfed41b76,
0x89d32be0,
0x10da7a5a,
0x67dd4acc,
0xf9b9df6f,
0x8ebeeff9,
0x17b7be43,
0x60b08ed5,
0xd6d6a3e8,
0xa1d1937e,
0x38d8c2c4,
0x4fdff252,
0xd1bb67f1,
0xa6bc5767,
0x3fb506dd,
0x48b2364b,
0xd80d2bda,
0xaf0a1b4c,
0x36034af6,
0x41047a60,
0xdf60efc3,
0xa867df55,
0x316e8eef,
0x4669be79,
0xcb61b38c,
0xbc66831a,
0x256fd2a0,
0x5268e236,
0xcc0c7795,
0xbb0b4703,
0x220216b9,
0x5505262f,
0xc5ba3bbe,
0xb2bd0b28,
0x2bb45a92,
0x5cb36a04,
0xc2d7ffa7,
0xb5d0cf31,
0x2cd99e8b,
0x5bdeae1d,
0x9b64c2b0,
0xec63f226,
0x756aa39c,
0x026d930a,
0x9c0906a9,
0xeb0e363f,
0x72076785,
0x05005713,
0x95bf4a82,
0xe2b87a14,
0x7bb12bae,
0x0cb61b38,
0x92d28e9b,
0xe5d5be0d,
0x7cdcefb7,
0x0bdbdf21,
0x86d3d2d4,
0xf1d4e242,
0x68ddb3f8,
0x1fda836e,
0x81be16cd,
0xf6b9265b,
0x6fb077e1,
0x18b74777,
0x88085ae6,
0xff0f6a70,
0x66063bca,
0x11010b5c,
0x8f659eff,
0xf862ae69,
0x616bffd3,
0x166ccf45,
0xa00ae278,
0xd70dd2ee,
0x4e048354,
0x3903b3c2,
0xa7672661,
0xd06016f7,
0x4969474d,
0x3e6e77db,
0xaed16a4a,
0xd9d65adc,
0x40df0b66,
0x37d83bf0,
0xa9bcae53,
0xdebb9ec5,
0x47b2cf7f,
0x30b5ffe9,
0xbdbdf21c,
0xcabac28a,
0x53b39330,
0x24b4a3a6,
0xbad03605,
0xcdd70693,
0x54de5729,
0x23d967bf,
0xb3667a2e,
0xc4614ab8,
0x5d681b02,
0x2a6f2b94,
0xb40bbe37,
0xc30c8ea1,
0x5a05df1b,
0x2d02ef8d
];
class SentenceParser {
Map<String, ParserFunc> customParsers;
Function(String)? parsePrefix;
Function(BaseSentence, String)? checkCRC;
Function(TagBlock)? onTagBlock;
SentenceParser(
this.customParsers, this.parsePrefix, this.checkCRC, this.onTagBlock);
BaseSentence parseBaseSentence(String raw) {
// raw = raw.trim();
if (raw.isEmpty) {
throw ArgumentError('nmea: can not parse empty input');
}
TagBlock tagBlock = TagBlock(0, 0, "", "", 0, "", "");
var startIndex = raw.indexOf(RegExp(r'\$|!|#'));
if (startIndex != 0) {
raw;
log("NMEA sentence does not start with a '\$' or '!' or '#'");
}
var checksumSepIndex = raw.indexOf('*');
var rawFields = raw.substring(
startIndex + 1, checksumSepIndex != -1 ? checksumSepIndex : raw.length);
var checksumRaw = -1;
if (checksumSepIndex != -1) {
rawFields = raw.substring(startIndex + 1, checksumSepIndex);
checksumRaw = int.parse(raw.substring(checksumSepIndex + 1), radix: 16);
}
List<String> fields = rawFields.split(',');
String talkerID;
String type;
List<String> result;
if (parsePrefix != null) {
result = parsePrefix!(fields[0]);
} else {
result = _parsePrefix(fields[0]);
}
talkerID = result[0];
type = result[1];
var sentence = BaseSentence(
talkerID, type, fields.sublist(1), checksumRaw, raw, tagBlock);
if (checkCRC != null) {
checkCRC!(sentence, rawFields);
} else {
int checksum;
if (raw[0] == "#") {
//#HEADING,#BESTPOSA
checksum = _calculateCRC32(rawFields);
} else {
checksum = _calculateChecksum(rawFields);
}
if (checksum != sentence.checksum) {
throw ArgumentError(
'nmea: sentence checksum mismatch [$checksum != ${sentence.checksum}]');
}
}
return sentence;
}
int _calculateChecksum(String s) {
var checksum = 0;
for (var i = 0; i < s.length; i++) {
checksum ^= s.codeUnitAt(i);
}
return checksum;
}
// Calculate and return the CRC for String
int _calculateCRC32(String str) {
int crc = 0;
for (int i = 0; i < str.length; i++) {
crc = (aulCrcTable[(crc ^ str.codeUnitAt(i)) & 0xff] ^ (crc >> 8));
}
return crc;
}
List<String> _parsePrefix(String prefix) {
if (prefix.isEmpty) {
log('nmea: sentence prefix is empty');
// throw ArgumentError('nmea: sentence prefix is empty');
return ['', prefix];
}
if (prefix[0] == 'P') {
return ['P', prefix.substring(1)];
}
if (prefix.length == 5) {
if (prefix[4] == 'Q') {
return [prefix.substring(0, 2), 'Q'];
}
return [prefix.substring(0, 2), prefix.substring(2)];
}
return ['', prefix];
}
BaseSentence parse(String raw) {
var s = parseBaseSentence(raw);
if (customParsers.containsKey(s.type)) {
return customParsers[s.type]!(s);
}
return s;
}
}

View File

@ -1,78 +0,0 @@
import 'dart:core';
class TagBlock {
int time; // TypeUnixTime unix timestamp (unit is likely to be s, but might be ms, YMMV), parameter: -c
int relativeTime; // TypeRelativeTime relative time, parameter: -r
String destination; // TypeDestinationID destination identification 15 char max, parameter: -d
String grouping; // TypeGrouping sentence grouping, parameter: -g
int lineCount; // TypeLineCount line count, parameter: -n
String source; // TypeSourceID source identification 15 char max, parameter: -s
String text; // TypeTextString valid character string, parameter -t
TagBlock(this.time, this.relativeTime, this.destination, this.grouping, this.lineCount, this.source, this.text);
}
int parseInt64(String raw) {
return int.parse(raw);
}
// Parse the tag block to create a TagBlock instance
TagBlock parseTagBlock(String tags) {
int sumSepIndex = tags.indexOf('*');
if (sumSepIndex == -1) {
throw ArgumentError('nmea: tagblock does not contain checksum separator');
}
String fieldsRaw = tags.substring(0, sumSepIndex);
String checksumRaw = tags.substring(sumSepIndex + 1).toUpperCase();
String checksum = _calculateChecksum(fieldsRaw);
TagBlock tagBlock = TagBlock(0, 0, "", "", 0, "", "");
if (checksum != checksumRaw) {
throw ArgumentError('nmea: tagblock checksum mismatch [$checksum != $checksumRaw]');
}
List<String> items = tags.substring(0, sumSepIndex).split(',');
for (String item in items) {
List<String> parts = item.split(':');
if (parts.length != 2) {
throw ArgumentError('nmea: tagblock field is malformed (should be <key>:<value>) [$item]');
}
String key = parts[0];
String value = parts[1];
switch (key) {
case 'c': // UNIX timestamp
tagBlock.time = parseInt64(value);
break;
case 'd': // Destination ID
tagBlock.destination = value;
break;
case 'g': // Grouping
tagBlock.grouping = value;
break;
case 'n': // Line count
tagBlock.lineCount = parseInt64(value);
break;
case 'r': // Relative time
tagBlock.relativeTime = parseInt64(value);
break;
case 's': // Source ID
tagBlock.source = value;
break;
case 't': // Text string
tagBlock.text = value;
break;
}
}
return tagBlock;
}
String _calculateChecksum(String s) {
int checksum = 0;
for (int i = 0; i < s.length; i++) {
checksum ^= s.codeUnitAt(i);
}
return checksum.toRadixString(16).toUpperCase().padLeft(2, '0');
}

View File

@ -1,234 +0,0 @@
// ignore_for_file: constant_identifier_names
// Status constants
const String StatusValid = "A";
const String StatusInvalid = "V";
// Unit constants
const String UnitAmpere = "A"; // unit for current in Amperes
const String UnitBars = "B"; // unit for pressure in Bars
const String UnitBinary = "B"; // unit for binary data
const String UnitCelsius = "Celsius"; // unit for temperature in Celsius
const String UnitFahrenheit =
"Fahrenheit"; // unit for temperature in Fahrenheit
const String UnitDegrees = "D"; // unit for angular displacement in Degrees
const String UnitHertz = "H"; // unit for frequency in Hertz
const String UnitLitresPerSecond =
"I"; // unit for volumetric flow in Litres per second
const String UnitKelvin = "Kelvin"; // unit of temperature in Kelvin
const String UnitKilogramPerCubicMetre =
"K"; // unit of density in kilogram per cubic metre
const String UnitMeters = "Meters"; // unit of distance in Meters
const String UnitNewtons = "N"; // unit of force in Newtons (1 kg*m/s2)
const String UnitCubicMeters = "M"; // unit of volume in cubic meters
const String UnitRevolutionsPerMinute =
"R"; // unit of rotational speed or the frequency of rotation around a fixed axis in revolutions per minute (RPM)
const String UnitPercent = "P"; // percent of full range
const String UnitPascal = "P"; // unit of pressure in Pascals
const String UnitPartsPerThousand =
"S"; // in parts-per notation set of pseudo-unit to describe small values of miscellaneous dimensionless quantities, e.g. mole fraction or mass fraction.
const String UnitVolts = "V"; // unit of voltage in Volts
// Speed constants
const String SpeedKnots =
"N"; // unit of speed equal to one nautical mile per hour, approximately 1.852 km/h
const String SpeedMeterPerSecond = "M"; // unit of speed of 1 meter per second
const String SpeedKilometerPerHour =
"K"; // unit of speed of 1 kilometer per hour
// Temperature constants
const String TemperatureCelsius =
"C"; // unit of temperature measured in Celsius
const String TemperatureFahrenheit =
"F"; // unit of temperature measured in Fahrenheit
const String TemperatureKelvin = "K"; // unit of temperature measured in Kelvin
// Heading constants
const String HeadingMagnetic = "M"; // Magnetic heading
const String HeadingTrue = "T"; // True heading
// Bearing constants
const String BearingMagnetic =
"M"; // Angle between Earth's magnetic north and an object observed from the vessel
const String BearingTrue =
"T"; // Angle between Earth's true (geographical) north and an object observed from the vessel
// FAAMode constants
const String FAAModeAutonomous = "A"; // Autonomous mode
const String FAAModeDifferential = "D"; // Differential Mode
const String FAAModeEstimated = "E"; // Estimated (dead-reckoning) mode
const String FAAModeRTKFloat = "F"; // RTK Float mode
const String FAAModeManualInput = "M"; // Manual Input Mode
const String FAAModeDataNotValid = "N"; // Data Not Valid
const String FAAModePrecise = "P"; // Precise (NMEA4.00+)
const String FAAModeRTKInteger = "R"; // RTK Integer mode
const String FAAModeSimulated = "S"; // Simulated Mode
// Navigation Status constants
const String NavStatusSimulated = "S"; // Deprecated: use NavStatusSafe
const String NavStatusDataValid = "V"; // Deprecated: use NavStatusNotValid
const String NavStatusSafe = "S"; // Safe (within selected accuracy level)
const String NavStatusCaution = "C"; // Caution (integrity not available)
const String NavStatusUnsafe = "U"; // Unsafe (outside selected accuracy level)
const String NavStatusNotValid =
"V"; // Not Valid (equipment does not provide navigation status information)
// DistanceUnit constants
const String DistanceUnitKilometre = "K"; // unit for distance in kilometres
const String DistanceUnitNauticalMile =
"N"; // unit for distance in nautical miles
const String DistanceUnitStatuteMile =
"S"; // unit for distance in statute miles
const String DistanceUnitMetre = "M"; // unit for distance in metres
const String DistanceUnitFeet = "f"; // unit for distance in feet
const String DistanceUnitFathom = "F"; // unit for distance in fathoms
// Other constants
const String Degrees = "\u00B0";
const String Minutes = "'";
const String Seconds = "\"";
const String Point = ".";
const String North = "N";
const String South = "S";
const String East = "E";
const String West = "W";
const String Left = "L";
const String Right = "R";
double parseLatLong(String s) {
double l = 0;
// try {
// double v = parseDMS(s);
// l = v;
// } catch (e) {
try {
double v = parseGPS(s);
l = v;
} catch (e) {
try {
double v = parseDecimal(s);
l = v;
} catch (e) {
print("cannot parse [$s], unknown format");
}
}
// }
return l;
}
double parseGPS(String s) {
List<String> parts = s.split(" ");
if (parts.length != 2) {
throw FormatException("invalid format: $s");
}
String dir = parts[1];
double value = double.parse(parts[0]);
int degrees = value ~/ 100;
double minutes = value - (degrees * 100);
value = degrees + (minutes / 60);
if (dir == 'N' || dir == 'E') {
return value;
} else if (dir == 'S' || dir == 'W') {
return -value;
} else {
throw FormatException("invalid direction [$dir]");
}
}
String formatGPS(double l) {
String padding = "";
int degrees = l.floor().abs();
double fraction = (l.abs() - degrees) * 60;
if (fraction < 10) {
padding = "0";
}
return "$degrees$padding${fraction.toStringAsFixed(4)}";
}
double parseDecimal(String s) {
double l = double.parse(s);
if (l.isNaN || (s[0] != '-' && s.split(".")[0].length > 3)) {
throw const FormatException("parse error (not decimal coordinate)");
}
return l;
}
double parseDMS(String s) {
int degrees = 0;
int minutes = 0;
double seconds = 0.0;
//
bool endNumber = false;
//
List<int> tmpBytes = [];
String? error;
for (int i = 0; i < s.length; i++) {
String char = s[i];
if (RegExp(r'[0-9.]').hasMatch(char)) {
if (!endNumber) {
tmpBytes.add(int.parse(s[i]));
} else {
return 0.0;
}
} else if (RegExp(r'\s').hasMatch(char) && tmpBytes.isNotEmpty) {
endNumber = true;
} else if (char == '°') {
degrees = int.parse(String.fromCharCodes(tmpBytes));
tmpBytes.clear();
endNumber = false;
} else if (char == "'") {
minutes = int.parse(String.fromCharCodes(tmpBytes));
tmpBytes.clear();
endNumber = false;
} else if (char == '"') {
seconds = double.parse(String.fromCharCodes(tmpBytes));
tmpBytes.clear();
endNumber = false;
} else if (RegExp(r'\s').hasMatch(char) && tmpBytes.isEmpty) {
continue;
} else {
error = "parse error (unknown symbol [$char])";
break;
}
}
if (tmpBytes.isNotEmpty) {
return 0.0;
}
double val = degrees + (minutes / 60) + (seconds / 3600);
if (error != null) {
throw FormatException(error);
}
return val;
}
Date parseDate(String ddmmyy) {
if (ddmmyy == "") {
return Date(false, 0, 0, 0);
}
if (ddmmyy.length != 6) {
throw Exception("parse date: expected ddmmyy format, got '$ddmmyy'");
}
int dd = int.parse(ddmmyy.substring(0, 2));
int mm = int.parse(
ddmmyy.substring(2, 4),
);
int yy = int.parse(
ddmmyy.substring(4, 6),
);
return Date(true, dd, mm, yy);
}
class Date {
bool isValid;
int dd;
int mm;
int yy;
Date(this.isValid, this.dd, this.mm, this.yy);
}

View File

@ -1,34 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'parser.dart';
import 'sentence.dart';
const TypeVTG = "VTG";
class VTG {
double trueTrack;
double magneticTrack;
double groundSpeedKnots;
double groundSpeedKPH;
String ffaMode;
VTG(
{required this.trueTrack,
required this.magneticTrack,
required this.groundSpeedKnots,
required this.groundSpeedKPH,
required this.ffaMode});
static VTG newVTG(BaseSentence s) {
var p = Parser(s);
String ffaMode = "";
if (s.fields.length > 8) {
ffaMode = p.string(8, "FAA mode");
}
return VTG(
trueTrack: p.float64(0, "true track"),
magneticTrack: p.float64(2, "magnetic track"),
groundSpeedKnots: p.float64(4, "ground speed (knots)"),
groundSpeedKPH: p.float64(6, "ground speed (km/h)"),
ffaMode: ffaMode);
}
}

View File

@ -1,36 +0,0 @@
// ignore_for_file: constant_identifier_names
import 'sentence.dart';
import 'parser.dart';
const TypeZDA = "ZDA";
class ZDA {
Time time;
int day;
int month;
int year;
int offsetHours; // Local time zone offset from GMT, hours
int offsetMinutes; // Local time zone offset from GMT, minutes
ZDA({
required this.time,
required this.day,
required this.month,
required this.year,
required this.offsetHours,
required this.offsetMinutes,
});
static ZDA newZDA(BaseSentence s) {
var p = Parser(s);
return ZDA(
time: p.time(0, "time"),
day: p.int64(1, "day"),
month: p.int64(2, "month"),
year: p.int64(3, "year"),
offsetHours: p.int64(4, "offset (hours)"),
offsetMinutes: p.int64(5, "offset (minutes)"),
);
}
}

View File

@ -1,97 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
class RtkBase {
// String host = "192.168.1.6";
// String host = "120.253.239.161"; //ip地址
// int port = 8001; //
// String account = "csar6309"; //
// String password = "9kd6kmd3"; //
// String mountPoint = "RTCM33_GRCE"; //
String host = "vrs.sixents.com";
int port = 8005; //
String account = "uhjns21929"; //
String password = "UpqbKp4Q"; //
String mountPoint = "RTCM32_GRECJ2"; //
String lastGGA = ""; //GGA
Socket? _client;
bool isConnected = false;
int lastSendGGATime = 0;
var rtcmStreamController = StreamController<Uint8List>.broadcast();
Stream<Uint8List> get rtcmStream => rtcmStreamController.stream;
var updateCount = 0; //
dispose() {
close();
}
connect() {
var headers = [
"GET /$mountPoint HTTP/1.0",
"Host: $host",
"Ntrip-Version: Ntrip/2.0",
"User-Agent: NTRIP u-blox",
"Accept: */*",
"Authorization: Basic ${base64Encode(('$account:$password').codeUnits)}",
"Connection: close",
"\r\n"
];
Socket.connect(host, port).then((Socket client) {
_client = client;
log('Connected to: ${client.remoteAddress.address}:${client.remotePort}');
var reqStr = headers.join("\r\n");
client.write(reqStr);
log(reqStr);
client.listen(
(Uint8List data) {
if (data[0] == 211) {
rtcmStreamController.add(data);
} else {
String response = String.fromCharCodes(data);
log("Connected to NTRIP caster: $response");
if (response.contains("ICY 200 OK")) {
if (lastGGA.isNotEmpty) {
_client!.write(lastGGA);
lastSendGGATime = DateTime.now().millisecondsSinceEpoch;
}
} else {
log("Failed to connect to NTRIP caster", error: response);
client.close();
_client = null;
}
}
},
onError: (error) {
log("Error reading from response body: $error");
// client.close();
},
);
client.done.then((_) {
log('Connection to NTRIP caster closed');
_client = null;
});
}).catchError((error) {
log("Error connecting to server: $error");
_client = null;
});
}
close() {
if (_client != null) {
_client!.close();
_client = null;
}
}
sendGGA(String gga) {
var now = DateTime.now().millisecondsSinceEpoch;
if (now - lastSendGGATime > 10000 && _client != null) {
lastGGA = "$gga\r\n";
_client!.write(lastGGA);
lastSendGGATime = now;
}
}
}

View File

@ -1,61 +0,0 @@
name: gnss
description: "A new Flutter package project."
version: 0.0.1
homepage:
publish_to: none
environment:
sdk: '>=3.4.4 <4.0.0'
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
libserialport :
git:
url: https://git.mcxa.cn:89/flutter/libserialport.git
ref: main
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View File

@ -1,19 +0,0 @@
import 'dart:developer';
import 'package:flutter_test/flutter_test.dart';
import 'package:gnss/gnss.dart';
void main() {
test('adds one to input values', () {
Gnss gnss = Gnss();
// gnss.connectSerialPort("COM25", 115200);
// gnss.locationStream.listen((event) {
// log("Location: $event");
// });
// final calculator = Calculator();
// expect(calculator.addOne(2), 3);
// expect(calculator.addOne(-7), -6);
// expect(calculator.addOne(0), 1);
});
}