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 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 options, ) { String? s = string(i, context); if (_err != null || s == '') { return ''; } if (options.contains(s)) { return s; } else { setErr(context, s); return ''; } } List enumChars(int i, String context, List options) { String? s = string(i, context); if (_err != null || s == '') { return []; } List 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 sixBitASCIIArmour(int i, int fillBits, String context) { if (_err != null) { return []; } if (fillBits < 0 || fillBits >= 6) { setErr(context, 'fill bits'); return []; } List payload = string(i, 'encoded payload').codeUnits; int numBits = payload.length * 6 - fillBits; if (numBits < 0) { setErr(context, 'num bits'); return []; } List 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); }