From eb9904e1df9ac59be7ee383d3740acd1222d4ded Mon Sep 17 00:00:00 2001 From: Joachim Spange Date: Tue, 4 Feb 2025 14:11:35 +0100 Subject: [PATCH] =?UTF-8?q?=E2=8F=AA=EF=B8=8F=20evert=20PTNL,GGK=20and=20A?= =?UTF-8?q?ML,SVM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/NmeaParser/Nmea/Ggk.cs | 165 ------------------ src/NmeaParser/Nmea/NmeaMessage.cs | 68 -------- src/NmeaParser/Nmea/Svm.cs | 76 -------- .../NmeaParser.Tests/NmeaMessages.cs | 33 ---- 4 files changed, 342 deletions(-) delete mode 100644 src/NmeaParser/Nmea/Ggk.cs delete mode 100644 src/NmeaParser/Nmea/Svm.cs diff --git a/src/NmeaParser/Nmea/Ggk.cs b/src/NmeaParser/Nmea/Ggk.cs deleted file mode 100644 index 589e7b3..0000000 --- a/src/NmeaParser/Nmea/Ggk.cs +++ /dev/null @@ -1,165 +0,0 @@ -// ******************************************************************************* -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// ****************************************************************************** - -using System; -using System.Globalization; -using System.Linq; - -namespace NmeaParser.Messages -{ - /// - /// PTNL,GGK: Time, position, position type, DOP - /// - /// - /// - /// 1.: UTC time of position fix, in hhmmss.ss format. Hours must be two numbers, so may be padded. For example, 7 is shown as 07. - /// 2.: UTC date of position fix, in mmddyy format. Day must be two numbers, so may be padded. For example, 8 is shown as 08. - /// 3.: Latitude, in degrees and decimal minutes (dddmm.mmmmmmm) - /// 4.: Direction of latitude: N: North S: South - /// 5.: Longitude, in degrees and decimal minutes (dddmm.mmmmmmm). Should contain three digits of ddd. - /// 6.: Direction of longitude: E: East W: West - /// 7.: GPS Quality indicator: - /// 0: Fix not available or invalid - /// 1: Autonomous GPS fix - /// 2: RTK float solution - /// 3: RTK fix solution - /// 4: Differential, code phase only solution(DGPS) - /// 5: SBAS solution – WAAS/EGNOS/MSAS - /// 6: RTK float or RTK location 3D Network solution - /// 7: RTK fixed 3D Network solution - /// 8: RTK float or RTK location 2D in a Network solution - /// 9: RTK fixed 2D Network solution - /// 10: OmniSTAR HP / XP solution - /// 11: OmniSTAR VBS solution - /// 12: Location RTK solution - /// 13: Beacon DGPS - /// 14: CenterPoint RTX - /// 15: xFill - /// 8.: Number of satellites in fix - /// 9.: Dilution of Precision of fix (DOP) - /// 10.: Ellipsoidal height of fix (antenna height above ellipsoid). - /// 11.: M: ellipsoidal height is measured in meters - /// - /// - /// NOTE – The PTNL,GGK message is longer than the NMEA-0183 standard of 80 characters - /// NOTE – Even if a user-defined geoid model, or an inclined plane is loaded into the receiver, then the height output in the NMEA GGK string is always an ellipsoid height, for example, EHT24.123. - /// - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ggk")] - [NmeaMessageType("GGK")] - public class Ggk : NmeaMessage - { - /// - /// Initializes a new instance of the class. - /// - /// The message type - /// The NMEA message values. - public Ggk(string type, string[] message) : base(type, message) - { - if (message == null || message.Length < 11) - throw new ArgumentException("Invalid Ggk", "message"); - - UtcTime = StringsToUtcDateTime(message[1], message[0]); - Latitude = StringToLatitude(message[2], message[3]); - Longitude = StringToLongitude(message[4], message[5]); - if (!string.IsNullOrEmpty(message[6])) - Quality = (Ggk.QualityIndicator)int.Parse(message[6], CultureInfo.InvariantCulture); - if (!string.IsNullOrEmpty(message[7])) - NumberOfSatellites = int.Parse(message[7], CultureInfo.InvariantCulture); - DilutionOfPrecision = StringToDouble(message[8]); - EllipsoidalHeightOfFix = StringToDouble(message[9]); - EllipsoidalHeightIsMeasuredInMeters = message[10] == "M"; - } - - /// - /// UTC time of position fix, in DateTime format. - /// DateTime(fullYear, month, day, hours, minutes, seconds, milliseconds, DateTimeKind.Utc) - /// - public DateTime? UtcTime { get; } - - /// - /// Latitude, in degrees and decimal minutes (dddmm.mmmmmmm) - /// - public double Latitude { get; } - - /// - /// Longitude, in degrees and decimal minutes (dddmm.mmmmmmm) - /// - public double Longitude { get; } - - /// - /// GPS Quality indicator - /// - public Ggk.QualityIndicator Quality { get; } - - /// - /// Number of satellites in fix - /// - public int NumberOfSatellites { get; } - - /// - /// Dilution of Precision of fix (DOP) - /// - public double DilutionOfPrecision { get; } - - /// - /// Ellipsoidal height of fix (antenna height above ellipsoid). Must start with EHT. - /// - public double EllipsoidalHeightOfFix { get; } - - /// - /// M: ellipsoidal height is measured in meters - /// - public bool EllipsoidalHeightIsMeasuredInMeters { get; } - - /// - /// GPS Quality indicator - /// - public enum QualityIndicator : int - { - /// Fix not available or invalid - Invalid = 0, - /// Autonomous GPS fix - GpsFix = 1, - /// RTK float solution - RtkFloat = 2, - /// RTK fix solution - RtkFix = 3, - /// Differential, code phase only solution(DGPS) - Ggps = 4, - /// SBAS solution – WAAS/EGNOS/MSAS - Sbas = 5, - /// RTK float or RTK location 3D Network solution - RtkFloatOrLocation3DNetworkSolution = 6, - /// RTK fixed 3D Network solution - RtkFixed3DNetworkSolution = 7, - /// RTK float or RTK location 2D in a Network solution - RtkFloatOrLocation2DNetworkSolution = 8, - /// RTK fixed 2D Network solution - RtkFixed2DNetworkSolution = 9, - /// OmniSTAR HP / XP solution - OmistarHpXp = 10, - /// OmniSTAR VBS solution - OmniStarVbs = 11, - /// Location RTK solution - LocationRtk = 12, - /// Beacon DGPS - BeaconDgps = 13, - /// CenterPoint RTX - CenterPointRtx = 14, - /// xFill - XFill = 15, - } - } -} \ No newline at end of file diff --git a/src/NmeaParser/Nmea/NmeaMessage.cs b/src/NmeaParser/Nmea/NmeaMessage.cs index 3ea186a..0c474e1 100644 --- a/src/NmeaParser/Nmea/NmeaMessage.cs +++ b/src/NmeaParser/Nmea/NmeaMessage.cs @@ -188,12 +188,6 @@ namespace NmeaParser.Messages string[] parts = message.Split(new char[] { ',' }); string MessageType = parts[0].Substring(1); - if (MessageType is "PTNL" or "AML") { - // PTNL is parent to e.g. AVR, GGK etc. - // AML is parent to e.g. SVT, SV, SVP etc - MessageType = parts[1]; - parts = parts.Skip(1).ToArray(); - } if (MessageType == string.Empty) throw new ArgumentException("Missing NMEA Message Type"); string[] MessageParts = parts.Skip(1).ToArray(); @@ -310,68 +304,6 @@ namespace NmeaParser.Messages return TimeSpan.Zero; } - /// - /// Parse from mmddyy + hhmmss.ss to DateTime (used in e.g. Ggk) - /// https://receiverhelp.trimble.com/alloy-gnss/en-us/NMEA-0183messages_PTNL_GGK.html - /// - internal static DateTime? StringsToUtcDateTime(string dateField, string timeField) - { - if (string.IsNullOrWhiteSpace(dateField) || string.IsNullOrWhiteSpace(timeField)) - return null; - - // 2. Parse date (mmddyy) - // - Typically the year is 2 digits; you must decide how to handle the century. - // - For example, if year < 80 => 20xx; else => 19xx - if (dateField.Length < 6) return null; - if (!int.TryParse(dateField.Substring(0, 2), out int month)) return null; // mm - if (!int.TryParse(dateField.Substring(2, 2), out int day)) return null; // dd - if (!int.TryParse(dateField.Substring(4, 2), out int year)) return null; // yy - - int fullYear = (year < 80) ? (2000 + year) : (1900 + year); - - // 3. Parse time (hhmmss.ss) - // - The fractional seconds might be optional or might have variable length. - // - Parse hours, minutes, and then the part after the decimal. - // - Time can be "hhmmss", or "hhmmss.sss", etc. - // Example: "102939.00" => hh=10, mm=29, ss=39, fraction=0 - if (timeField.Length < 6) return null; - if (!int.TryParse(timeField.Substring(0, 2), out int hours)) return null; // hh - if (!int.TryParse(timeField.Substring(2, 2), out int minutes)) return null; // mm - - // The seconds part can have a decimal fraction - // So we split around the decimal point: - double secondsDouble; - if (timeField.Length > 4) - { - string secString = timeField.Substring(4); // "39.00 in example above" - if (!double.TryParse(secString, - System.Globalization.NumberStyles.Float, - System.Globalization.CultureInfo.InvariantCulture, - out secondsDouble)) - { - return null; - } - } - else - { - secondsDouble = 0.0; - } - int seconds = (int)secondsDouble; - int milliseconds = (int)((secondsDouble - seconds) * 1000.0); - - // 4. Construct the UTC DateTime - try - { - var result = new DateTime(fullYear, month, day, hours, minutes, seconds, milliseconds, DateTimeKind.Utc); - return result; - } - catch - { - // If the date/time is invalid (e.g. month=13, day=32), we return null or handle differently - return null; - } - } - /// /// Indicates whether the current object is equal to another object of the same type. /// diff --git a/src/NmeaParser/Nmea/Svm.cs b/src/NmeaParser/Nmea/Svm.cs deleted file mode 100644 index 57755a3..0000000 --- a/src/NmeaParser/Nmea/Svm.cs +++ /dev/null @@ -1,76 +0,0 @@ -// ******************************************************************************* -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// ****************************************************************************** - -using System; - -namespace NmeaParser.Messages -{ - /// - /// AML Sound Velocity (m/s), Temperature (C) - /// AML Oceanographic Svm sensor - /// - /// - /// - /// 1.: Sound Velocity m/s - /// 2.: Unit of temperature, TC = Celcius - /// 3.: Temperature - /// 4.: Label, SN: Serial number - /// 5.: Device serial number - /// - /// - [NmeaMessageType("SVM")] - public class Svm : NmeaMessage - { - /// - /// Initializes a new instance of the class. - /// - /// The message type - /// The NMEA message values. - public Svm(string type, string[] message) : base(type, message) - { - if (message == null || message.Length < 5) - throw new ArgumentException("Invalid Svm", "message"); - SoundVelocity = StringToDouble(message[0]); - TemperatureUnit = message[1]; - Temperature = StringToDouble(message[2]); - IsSerialNumber = message[3] == "SN"; - SerialNumber = StringToDouble(message[4]); - } - - /// - /// Sound Velocity m/s - /// - public double SoundVelocity { get; } - - /// - /// Temperature Unit - /// - public string TemperatureUnit { get; } - - /// - /// Temperature - /// - public double Temperature { get; } - - /// - /// String indicating Serial number - /// - public bool IsSerialNumber { get; } - - /// - /// Serial Number - /// - public double SerialNumber { get; } - } -} \ No newline at end of file diff --git a/src/UnitTests/NmeaParser.Tests/NmeaMessages.cs b/src/UnitTests/NmeaParser.Tests/NmeaMessages.cs index 7721b0c..50ed8cd 100644 --- a/src/UnitTests/NmeaParser.Tests/NmeaMessages.cs +++ b/src/UnitTests/NmeaParser.Tests/NmeaMessages.cs @@ -85,8 +85,6 @@ namespace NmeaParser.Tests { var msg = NmeaMessage.Parse(line, previousMessage as IMultiSentenceMessage); Assert.IsNotNull(msg); - if (line.IndexOf("PTNL,") > 0) continue; // TODO PTNL - if (line.IndexOf("AML,") > 0) continue; // TODO AML var idx = line.IndexOf('*'); if (idx >= 0) { @@ -126,20 +124,6 @@ namespace NmeaParser.Tests Assert.ThrowsException(() => NmeaMessage.Parse(input, ignoreChecksum: false)); } - [TestMethod] - public void TestAmlSvm() - { - string input = "$AML,SVM,1468.951,TC,15.753,SN,168753*0F"; - var msg = NmeaMessage.Parse(input); - Assert.IsInstanceOfType(msg, typeof(Svm)); - Svm svm = (Svm)msg; - Assert.AreEqual(1468.951, svm.SoundVelocity); - Assert.AreEqual("TC", svm.TemperatureUnit); - Assert.AreEqual(15.753, svm.Temperature); - Assert.IsTrue(svm.IsSerialNumber); - Assert.AreEqual(168753, svm.SerialNumber); - } - [TestMethod] public void TestDPT() { @@ -366,23 +350,6 @@ namespace NmeaParser.Tests Assert.AreEqual('M', ptlna.SlopeDistanceUnits); } - [TestMethod] - public void TestPtnlGgk() - { - string input = "$PTNL,GGK,133703.14,012925,6104.64373420,N,01027.91199999,E,2,08,1.0,0.0,M,*0B"; - var msg = NmeaMessage.Parse(input); - Assert.IsInstanceOfType(msg, typeof(Ggk)); - Ggk ggk = (Ggk)msg; - Assert.AreEqual(new DateTime(2025, 1, 29, 13, 37, 3, 140, DateTimeKind.Utc), ggk.UtcTime); - Assert.AreEqual(61.07739557, ggk.Latitude); - Assert.AreEqual(10.465199999833333, ggk.Longitude); - Assert.AreEqual(Ggk.QualityIndicator.RtkFloat, ggk.Quality); - Assert.AreEqual(8, ggk.NumberOfSatellites); - Assert.AreEqual(1, ggk.DilutionOfPrecision); - Assert.AreEqual(0, ggk.EllipsoidalHeightOfFix); - Assert.IsTrue(ggk.EllipsoidalHeightIsMeasuredInMeters); - } - [TestMethod] public void TestPgrme() {