diff --git a/src/NmeaParser/Nmea/Dtm.cs b/src/NmeaParser/Nmea/Dtm.cs
new file mode 100644
index 0000000..2924d6c
--- /dev/null
+++ b/src/NmeaParser/Nmea/Dtm.cs
@@ -0,0 +1,149 @@
+// *******************************************************************************
+// * 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
+{
+ ///
+ /// Local geodetic datum and datum offsets from a reference datum.
+ ///
+ ///
+ /// This sentence is used to define the datum to which a position location and geographic
+ /// locations in subsequent sentences, is referenced. Latitude, longitude and altitude offsets
+ /// from the reference datum, and the selection of reference datum, are also provided.
+ ///
+ /// The datum sentence should be transmitted immediately prior to every positional sentence (e.g., GLL,
+ /// BWC, WPL) that is referenced to a datum other than WGS84, which is the datum recommended by IMO.
+ ///
+ ///
+ /// For all datums the DTM sentence should be transmitted prior to any datum change and periodically at
+ /// intervals of not greater than 30 seconds.
+ ///
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dtm")]
+ [NmeaMessageType("--DTM")]
+ public class Dtm : NmeaMessage
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message type
+ /// The NMEA message values.
+ public Dtm (string type, string[] message) : base(type, message)
+ {
+ if (message == null || message.Length < 6)
+ throw new ArgumentException("Invalid DTM", "message");
+ LocalDatumCode = message[0];
+ if (message[1].Length > 0)
+ LocalDatumSubdivisionCode = message[1][0];
+ LatitudeOffset = NmeaMessage.StringToDouble(message[2]);
+ LongitudeOffset = NmeaMessage.StringToDouble(message[3]);
+ AltitudeOffset = NmeaMessage.StringToDouble(message[4]);
+ ReferenceDatumCode = message[5];
+ }
+
+ ///
+ /// Local datum code
+ ///
+ ///
+ /// Three character alpha code for local datum. If not one of the listed earth-centered datums, or 999
+ /// for user defined datum, use IHO datum code from International Hydrographic Organization Publication S-60
+ /// Appendices B and C. String.Empty if unknown.
+ ///
+ /// Users should be aware that chart transformations based on IHO S60 parameters may result in significant
+ /// positional errors when applied to chart data.
+ ///
+ ///
+ /// Common known datum codes are:
+ ///
+ ///
+ /// | Code |
+ /// Datum |
+ ///
+ /// | W84 | WGS 84 |
+ /// | W72 | WGS 72 |
+ /// | S85 | SGS 85 |
+ /// | P90 | PE 90 |
+ /// | 999 | User Defined |
+ /// | Others | IHO Datum Code |
+ ///
+ ///
+ ///
+ public string LocalDatumCode { get; }
+
+ ///
+ /// Local datum subdivision code.
+ ///
+ ///
+ /// One character subdivision datum code when available or user defined reference character
+ /// for user defined datums, null field otherwise. Subdivision character from IHO Publication S-60
+ /// Appendices B and C.
+ ///
+ public char? LocalDatumSubdivisionCode { get; }
+
+ ///
+ /// Latitude Offset, decimal degrees
+ ///
+ ///
+ /// Latitude and longitude offsets are positive numbers, the altitude offset may be negative. Offsets
+ /// change with position; position in the local datum is offset from the position in the reference datum in the directions
+ /// indicated:
+ /// P_local_datum = P_ref_datum + offset
+ ///
+ public double LatitudeOffset { get; }
+
+ ///
+ /// Longitude Offset in minutes
+ ///
+ ///
+ /// Latitude and longitude offsets are positive numbers, the altitude offset may be negative. Offsets
+ /// change with position; position in the local datum is offset from the position in the reference datum in the directions
+ /// indicated:
+ /// P_local_datum = P_ref_datum + offset
+ ///
+ public double LongitudeOffset { get; }
+
+ ///
+ /// Altitude Offset in minutes
+ ///
+ ///
+ /// Latitude and longitude offsets are positive numbers, the altitude offset may be negative. Offsets
+ /// change with position; position in the local datum is offset from the position in the reference datum in the directions
+ /// indicated:
+ /// P_local_datum = P_ref_datum + offset
+ ///
+ public double AltitudeOffset { get; }
+
+ ///
+ /// Reference datum code
+ ///
+ ///
+ ///
+ /// Common known datum codes are:
+ ///
+ ///
+ /// | Code |
+ /// Datum |
+ ///
+ /// | W84 | WGS 84 |
+ /// | W72 | WGS 72 |
+ /// | S85 | SGS 85 |
+ /// | P90 | PE 90 |
+ ///
+ ///
+ ///
+ public string ReferenceDatumCode { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/NmeaParser/Nmea/Gbs.cs b/src/NmeaParser/Nmea/Gbs.cs
new file mode 100644
index 0000000..c83edc6
--- /dev/null
+++ b/src/NmeaParser/Nmea/Gbs.cs
@@ -0,0 +1,135 @@
+// *******************************************************************************
+// * 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;
+
+namespace NmeaParser.Messages
+{
+ ///
+ /// GNSS Satellite Fault Detection
+ ///
+ ///
+ ///
+ /// This sentence is used to support Receiver Autonomous Integrity Monitoring (RAIM). Given that a GNSS
+ /// receiver is tracking enough satellites to perform integrity checks of the positioning quality of the position
+ /// solution a sentence is needed to report the output of this process to other systems to advise the system
+ /// user.With the RAIM in the GNSS receiver, the receiver can isolate faults to individual satellites and not
+ /// use them in its position and velocity calculations.Also, the GNSS receiver can still track the satellite and
+ /// easily judge when it is back within tolerance.This sentence shall be used for reporting this RAIM
+ /// information. To perform this integrity function, the GNSS receiver must have at least two observables in
+ /// addition to the minimum required for navigation.Normally these observables take the form of additional
+ /// redundant satellites.
+ ///
+ ///
+ /// If only GPS, GLONASS, Galileo, BDS, QZSS, NavIC (IRNSS) is used for the reported position solution
+ /// the talker ID is GP, GL, GA, GB, GQ, GI respectively and the errors pertain to the individual system.If
+ /// satellites from multiple systems are used to obtain the reported position solution the talker ID is GN and
+ /// the errors pertain to the combined solution.
+ ///
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dtm")]
+ [NmeaMessageType("--GBS")]
+ public class Gbs : NmeaMessage, ITimestampedMessage
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message type
+ /// The NMEA message values.
+ public Gbs (string type, string[] message) : base(type, message)
+ {
+ if (message == null || message.Length < 8)
+ throw new ArgumentException("Invalid GBS", "message");
+ FixTime = StringToTimeSpan(message[0]);
+ LatitudeError = NmeaMessage.StringToDouble(message[1]);
+ LongitudeError = NmeaMessage.StringToDouble(message[2]);
+ AltitudeError = NmeaMessage.StringToDouble(message[3]);
+ if (int.TryParse(message[4], System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int id))
+ SatelliteId = id;
+ MissedDetectionProbability = NmeaMessage.StringToDouble(message[5]);
+ BiasEstimate = NmeaMessage.StringToDouble(message[6]);
+ StandardDeviation = NmeaMessage.StringToDouble(message[7]);
+ }
+ ///
+ /// UTC time of the GGA or GNS fix associated with this sentence.
+ ///
+ public TimeSpan FixTime { get; }
+
+ TimeSpan ITimestampedMessage.Timestamp => FixTime;
+
+ ///
+ /// Expected Error in latitude
+ ///
+ ///
+ /// Expected error in meters due to bias, with noise = 0
+ ///
+ public double LatitudeError { get; }
+
+ ///
+ /// Expected Error in longitude
+ ///
+ ///
+ /// Expected error in meters due to bias, with noise = 0
+ ///
+ public double LongitudeError { get; }
+
+ ///
+ /// Expected Error in altitude
+ ///
+ ///
+ /// Expected error in meters due to bias, with noise = 0
+ ///
+ public double AltitudeError { get; }
+
+ ///
+ /// ID number of most likely failed satellite
+ ///
+ ///
+ ///
+ /// Satellite ID numbers. To avoid possible confusion caused by repetition of satellite ID numbers when using
+ /// multiple satellite systems, the following convention has been adopted:
+ ///
+ /// - a) GPS satellites are identified by their PRN numbers, which range from 1 to 32.
+ /// - b) The numbers 33-64 are reserved for SBAS satellites. The SBAS system PRN numbers are 120-138.
+ /// The offset from NMEA SBAS SV ID to SBAS PRN number is 87. A SBAS PRN number of 120
+ /// minus 87 yields the SV ID of 33. The addition of 87 to the SV ID yields the SBAS PRN number.
+ /// - c) The numbers 65-96 are reserved for GLONASS satellites. GLONASS satellites are identified by
+ /// 64+satellite slot number.The slot numbers are 1 through 24 for the full GLONASS constellation
+ /// of 24 satellites, this gives a range of 65 through 88. The numbers 89 through 96 are available if
+ /// slot numbers above 24 are allocated to on-orbit spares.
+ ///
+ /// - See Note 3 for other GNSS not listed in a), b), or c) above to determine meaning of satellite ID when Talker ID GN is used
+ ///
+ ///
+ ///
+ ///
+ public int? SatelliteId { get; }
+
+ ///
+ /// Probability of missed detection for most likely failed satellite
+ ///
+ public double MissedDetectionProbability { get; }
+
+ ///
+ /// Estimate of bias in meters on most likely failed satellite
+ ///
+ public double BiasEstimate { get; }
+
+ ///
+ /// Standard deviation of bias estimate
+ ///
+ public double StandardDeviation { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/NmeaParser/Nmea/Grs.cs b/src/NmeaParser/Nmea/Grs.cs
new file mode 100644
index 0000000..8e99a61
--- /dev/null
+++ b/src/NmeaParser/Nmea/Grs.cs
@@ -0,0 +1,134 @@
+// *******************************************************************************
+// * 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.Collections.Generic;
+using System.Globalization;
+
+namespace NmeaParser.Messages
+{
+ ///
+ /// GNSS Range Residuals
+ ///
+ ///
+ ///
+ /// This sentence is used to support Receiver Autonomous Integrity Monitoring (RAIM). Range residuals can be
+ /// computed in two ways for this process. The basic measurement integration cycle of most navigation filters
+ /// generates a set of residuals and uses these to update the position state of the receiver.
+ ///
+ ///
+ /// These residuals can be reported with GRS, but because of the fact that these were used to generate the navigation
+ /// solution they should be recomputed using the new solution in order to reflect the residuals for the position solution in
+ /// the GGA or GNS sentence.
+ ///
+ ///
+ /// The MODE field should indicate which computation method was used. An integrity process that uses these
+ /// range residuals would also require GGA or GNS, GSA, and GSV sentences to be sent.
+ ///
+ ///
+ /// If only GPS, or GLONASS, or Galileo, or BDS, or QZSS, or NavIC (IRNSS)is used for the reported position
+ /// solution, the talker ID is GP, GL, GA, GB, GQ, GI respectively and the range residuals pertain to the individual
+ /// system.
+ ///
+ ///
+ /// If GPS, GLONASS, Galileo, BDS, QZSS, NavIC (IRNSS) are combined to obtain the position solution multiple
+ /// GRS sentences are produced, one with the GPS satellites, another with the GLONASS satellites, etc. Each of these
+ /// GRS sentences shall have talker ID “GN”, to indicate that the satellites are used in a combined solution. The GNSS
+ /// System ID data field identifies the specific satellite system. It is important to distinguish the residuals from those that
+ /// would be produced by a GPS-only, GLONASS-only, etc. position solution. In general, the residuals for a combined
+ /// solution will be different from the residual for a GPS-only, GLONASS-only, etc. solution.
+ ///
+ ///
+ /// When multiple GRS sentences are necessary, use of the NMEA TAG Block structure (§ 7) and the TAG Block
+ /// Sentence-grouping Parameter (§ 7.9.3) reliably links the related sentences together over any transport medium.
+ ///
+ ///
+ /// When GRS sentences are provided with related GSA and/or GSV sentences, use of the NMEA TAG Block structure
+ /// (§ 7) and the TAG Block Sentence-grouping Parameter (§ 7.9.3) reliably links the related (different sentence
+ /// formatters) sentences together over any transport medium.
+ ///
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dtm")]
+ [NmeaMessageType("--GRS")]
+ public class Grs : NmeaMessage, ITimestampedMessage
+ {
+ ///
+ /// Determines the way the residuals were calculated.
+ ///
+ public enum GrsMode
+ {
+ ///
+ /// Residuals were used to calculate the position given in the matching GGA or GNS sentence
+ ///
+ UsedForPosition,
+ ///
+ /// Residuals were recomputed after the GGA or GNS position was computed
+ ///
+ RecomputedFromPosition
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message type
+ /// The NMEA message values.
+ public Grs (string type, string[] message) : base(type, message)
+ {
+ if (message == null || message.Length < 8)
+ throw new ArgumentException("Invalid Grs", "message");
+ FixTime = StringToTimeSpan(message[0]);
+ Mode = message[1] == "1" ? GrsMode.RecomputedFromPosition : GrsMode.UsedForPosition;
+ double[] residuals = new double[message.Length - 2];
+ for (int i = 2; i < message.Length; i++)
+ {
+ residuals[i-2] = NmeaMessage.StringToDouble(message[i]);
+ }
+ Residuals = residuals;
+ }
+
+ ///
+ /// UTC time of the GGA or GNS fix associated with this sentence
+ ///
+ public TimeSpan FixTime { get; }
+
+ ///
+ /// Residual calculation mode
+ ///
+ public GrsMode Mode { get; }
+
+ TimeSpan ITimestampedMessage.Timestamp => FixTime;
+
+ ///
+ /// Range residuals in meters for satellites used in the navigation solution
+ ///
+ ///
+ ///
+ /// Order must match order of the satellite ID3 numbers in GSA. When GRS is used GSA and GSV are generally required
+ ///
+ ///
+ /// Notes:
+ ///
+ /// - If the range residual exceeds +99.9 meters, then the decimal part is dropped, resulting in an integer (-103.7 becomes -103).
+ /// The maximum value for this field is +999.
+ /// - The sense or sign of the range residual is determined by the order of parameters used in the calculation. The
+ /// expected order is as follows: range residual = calculated range - measured range.
+ /// - When multiple GRS sentences are being sent then their order of transmission must match the order of
+ /// corresponding GSA sentences.Listeners shall keep track of pairs of GSA and GRS sentences and discard data
+ /// if pairs are incomplete.
+ ///
+ ///
+ ///
+ public double[] Residuals { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/NmeaParser/Nmea/Vlw.cs b/src/NmeaParser/Nmea/Vlw.cs
new file mode 100644
index 0000000..a0b2c5d
--- /dev/null
+++ b/src/NmeaParser/Nmea/Vlw.cs
@@ -0,0 +1,56 @@
+// *******************************************************************************
+// * 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
+{
+ ///
+ /// Dual Ground/Water Distance
+ ///
+ ///
+ /// The distance traveled, relative to the water and over the ground.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dtm")]
+ [NmeaMessageType("--VLW")]
+ public class Vlw : NmeaMessage
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message type
+ /// The NMEA message values.
+ public Vlw (string type, string[] message) : base(type, message)
+ {
+ if (message == null || message.Length < 7)
+ throw new ArgumentException("Invalid VLW", "message");
+ WaterDistanceCumulative = NmeaMessage.StringToDouble(message[0]);
+ WaterDistanceSinceReset = NmeaMessage.StringToDouble(message[2]);
+ GroundDistanceCumulative = NmeaMessage.StringToDouble(message[4]);
+ GroundDistanceSinceReset = NmeaMessage.StringToDouble(message[6]);
+ }
+
+ /// Total cumulative water distance, nautical miles
+ public double WaterDistanceCumulative { get; }
+
+ /// Water distance since reset, nautical miles
+ public double WaterDistanceSinceReset { get; }
+
+ /// Total cumulative ground distance, nautical miles
+ public double GroundDistanceCumulative { get; }
+
+ /// Ground distance since reset, nautical miles
+ public double GroundDistanceSinceReset { get; }
+ }
+}
\ No newline at end of file