diff --git a/README.md b/README.md index 476508f..e1da276 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,15 @@ It makes it easy to connect and listen for NMEA messages coming from various dev The following inputs are supported: - System.IO.Stream (all platforms) - Emulation from NMEA log file (all platforms) -- Bluetooth: Windows Store, Windows Phone, Windows Universal. Desktop is supported using the bluetooth device via the SerialPortDevice. +- Bluetooth: Windows Universal. Desktop is supported using the bluetooth device via the SerialPortDevice. - Serial Device: Windows Desktop and Windows Universal. Currently supported NMEA messages: -- Generic GPS NMEA (GPRMC, GPGGA, GPGLL, GPGSA, GPGSCV, GPRMB, GPRMC, GPBOD, GPRTE, GPGST) +- GPS: GPBOD, GPGGA, GPGLL, GPGNS, GPGSA, GPGST, GPGSV, GPRMB, GPRMC, GPRTE +- GLONASS: GLGNS, GLGSV +- GALILEO: GAGSV +- Generic GNSS: GNGGA, GNGLL, GNGNS, GNGSA, GNGST, GNRMC - Garmin GPS NMEA (PGRME, PGRMZ) - Trimble Laser Range Finder (PTNLA, PTNLB) - TruePulse Laser Range Finder (PLTIT) diff --git a/src/NmeaParser.sln b/src/NmeaParser.sln index 1b85bd9..02a9b2e 100644 --- a/src/NmeaParser.sln +++ b/src/NmeaParser.sln @@ -1,13 +1,16 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27130.2010 +VisualStudioVersion = 15.0.27130.2003 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NmeaParser", "NmeaParser", "{1701F3BA-A09C-4706-A612-24FD9340FC18}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CF767486-305D-40EE-8845-58EF76C16D85}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp.WinDesktop", "SampleApp.WinDesktop\SampleApp.WinDesktop.csproj", "{5DB6C7C7-A19C-4BE3-AFE6-26E3061DA01F}" + ProjectSection(ProjectDependencies) = postProject + {1ADC3666-1DDB-48C4-9811-1E58B6D09A7C} = {1ADC3666-1DDB-48C4-9811-1E58B6D09A7C} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop", "Desktop", "{7ABA337E-6748-484E-A0F4-E1715E1C95F1}" EndProject @@ -31,8 +34,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NmeaParser.Tests.UWP", "Uni EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "NmeaParser.Tests", "UnitTests\NmeaParser.Tests\NmeaParser.Tests.shproj", "{979AE182-EB59-4181-9D45-3FD6E4817F11}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NmeaParser.Tests.NET45", "UnitTests\NmeaParser.Tests.NET45\NmeaParser.Tests.NET45.csproj", "{170EE734-37F0-425F-822B-B865348ECEC6}" + ProjectSection(ProjectDependencies) = postProject + {1ADC3666-1DDB-48C4-9811-1E58B6D09A7C} = {1ADC3666-1DDB-48C4-9811-1E58B6D09A7C} + EndProjectSection +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution + UnitTests\NmeaParser.Tests\NmeaParser.Tests.projitems*{170ee734-37f0-425f-822b-b865348ecec6}*SharedItemsImports = 4 UnitTests\NmeaParser.Tests\NmeaParser.Tests.projitems*{92cad93b-6c3b-45a0-a723-be046de50fec}*SharedItemsImports = 4 UnitTests\NmeaParser.Tests\NmeaParser.Tests.projitems*{979ae182-eb59-4181-9d45-3fd6e4817f11}*SharedItemsImports = 13 EndGlobalSection @@ -125,6 +134,22 @@ Global {92CAD93B-6C3B-45A0-A723-BE046DE50FEC}.Release|x86.ActiveCfg = Release|x86 {92CAD93B-6C3B-45A0-A723-BE046DE50FEC}.Release|x86.Build.0 = Release|x86 {92CAD93B-6C3B-45A0-A723-BE046DE50FEC}.Release|x86.Deploy.0 = Release|x86 + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|ARM.Build.0 = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|x64.ActiveCfg = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|x64.Build.0 = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|x86.ActiveCfg = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Debug|x86.Build.0 = Debug|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|Any CPU.Build.0 = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|ARM.ActiveCfg = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|ARM.Build.0 = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|x64.ActiveCfg = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|x64.Build.0 = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|x86.ActiveCfg = Release|Any CPU + {170EE734-37F0-425F-822B-B865348ECEC6}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -138,6 +163,7 @@ Global {1ADC3666-1DDB-48C4-9811-1E58B6D09A7C} = {1701F3BA-A09C-4706-A612-24FD9340FC18} {92CAD93B-6C3B-45A0-A723-BE046DE50FEC} = {28B8E327-C504-4E08-B2CE-09D1CBB8B904} {979AE182-EB59-4181-9D45-3FD6E4817F11} = {28B8E327-C504-4E08-B2CE-09D1CBB8B904} + {170EE734-37F0-425F-822B-B865348ECEC6} = {28B8E327-C504-4E08-B2CE-09D1CBB8B904} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {03788B53-C0BF-485B-AA19-A9EAB0E9AF7B} diff --git a/src/NmeaParser/Nmea/Galileo/Gagsv.cs b/src/NmeaParser/Nmea/Galileo/Gagsv.cs new file mode 100644 index 0000000..4f191dc --- /dev/null +++ b/src/NmeaParser/Nmea/Galileo/Gagsv.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea.Galileo +{ + /// + /// GALILEO Satellites in view + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gagsv")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + [NmeaMessageType("GAGSV")] + public sealed class Gagsv : Gsv + { + } +} diff --git a/src/NmeaParser/Nmea/Gll.cs b/src/NmeaParser/Nmea/Gll.cs new file mode 100644 index 0000000..e7c15bb --- /dev/null +++ b/src/NmeaParser/Nmea/Gll.cs @@ -0,0 +1,73 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea +{ + /// + /// Geographic position, latitude / longitude + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gll")] + public abstract class Gll : NmeaMessage + { + /// + /// Called when the message is being loaded. + /// + /// The NMEA message values. + protected override void OnLoadMessage(string[] message) + { + if (message == null || message.Length < 4) + throw new ArgumentException("Invalid GPGLL", "message"); + Latitude = NmeaMessage.StringToLatitude(message[0], message[1]); + Longitude = NmeaMessage.StringToLongitude(message[2], message[3]); + if (message.Length >= 5) //Some older GPS doesn't broadcast fix time + { + FixTime = StringToTimeSpan(message[4]); + } + DataActive = (message.Length < 6 || message[5] == "A"); + } + + /// + /// Latitude + /// + public double Latitude { get; private set; } + + /// + /// Longitude + /// + public double Longitude { get; private set; } + + /// + /// Time since last DGPS update + /// + public TimeSpan FixTime { get; private set; } + + /// + /// Gets a value indicating whether data is active. + /// + /// + /// true if data is active; otherwise, false. + /// + public bool DataActive { get; private set; } + + } +} diff --git a/src/NmeaParser/Nmea/Glonass/Glgns.cs b/src/NmeaParser/Nmea/Glonass/Glgns.cs new file mode 100644 index 0000000..f114048 --- /dev/null +++ b/src/NmeaParser/Nmea/Glonass/Glgns.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NmeaParser.Nmea.Glonass +{ + /// + /// Fix data for GLONASS satellite navigation systems + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Glgns")] + [NmeaMessageType("GLGNS")] + public class Glgns : Gns + { + } +} diff --git a/src/NmeaParser/Nmea/Glonass/Glgsv.cs b/src/NmeaParser/Nmea/Glonass/Glgsv.cs new file mode 100644 index 0000000..5a9efa8 --- /dev/null +++ b/src/NmeaParser/Nmea/Glonass/Glgsv.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea.Glonass +{ + /// + /// GLONASS Satellites in view + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Glgsv")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + [NmeaMessageType("GLGSV")] + public sealed class Glgsv : Gsv + { + } +} diff --git a/src/NmeaParser/Nmea/Gns.cs b/src/NmeaParser/Nmea/Gns.cs new file mode 100644 index 0000000..d717f3b --- /dev/null +++ b/src/NmeaParser/Nmea/Gns.cs @@ -0,0 +1,241 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea +{ + /// + /// Fixes data for single or combined (GPS, GLONASS, possible future satellite systems, and systems combining these) satellite navigation systems + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gns")] + public abstract class Gns : NmeaMessage + { + /* + * Example of GNS messages: + * $GNGNS,014035.00,4332.69262,S,17235.48549,E,RR,13,0.9,25.63,11.24,,*70 //GLONASS + * $GPGNS,014035.00,,,,,,8,,,,1.0,23*76 //GPS + * $GLGNS,014035.00,,,,,,5,,,,1.0,23*67 //GALILEO + */ + + /// + /// GNS Mode Indicator + /// + public enum Mode + { + /// + /// No fix. Satellite system not used in position fix, or fix not valid + /// + NoFix, + /// + /// Autonomous. Satellite system used in non-differential mode in position fix + /// + Autonomous, + /// + /// Differential (including all OmniSTAR services). Satellite system used in differential mode in position fix + /// + Differential, + /// + /// Precise. Satellite system used in precision mode. Precision mode is defined as no deliberate degradation (such as Selective Availability) and higher resolution code (P-code) is used to compute position fix. + /// + Precise, + /// + /// Real Time Kinematic. Satellite system used in RTK mode with fixed integers + /// + RealTimeKinematic, + /// + /// Float RTK. Satellite system used in real time kinematic mode with floating integers + /// + FloatRtk, + /// + /// Estimated (dead reckoning) mode + /// + Estimated, + /// + /// Manual input mode + /// + Manual, + /// + /// Simulator mode + /// + Simulator + } + + /// + /// Navigational status + /// + public enum NavigationalStatus + { + /// + /// Not valid for navigation + /// + NotValid, + /// + /// Safe + /// + Safe, + /// + /// Caution + /// + Caution, + /// + /// Unsafe + /// + Unsafe + } + + private static Mode ParseModeIndicator(char c) + { + switch (c) + { + case 'A': return Mode.Autonomous; + case 'D': return Mode.Differential; + case 'P': return Mode.Precise; + case 'R': return Mode.RealTimeKinematic; + case 'F': return Mode.FloatRtk; + case 'E': return Mode.Estimated; + case 'M': return Mode.Manual; + case 'S': return Mode.Simulator; + case 'N': + default: return Mode.NoFix; + } + } + + /// + /// Called when the message is being loaded. + /// + /// The NMEA message values. + protected override void OnLoadMessage(string[] message) + { + if (message == null || message.Length < 12) + throw new ArgumentException("Invalid GNS", "message"); + FixTime = StringToTimeSpan(message[0]); + Latitude = NmeaMessage.StringToLatitude(message[1], message[2]); + Longitude = NmeaMessage.StringToLongitude(message[3], message[4]); + if (message[5].Length > 0) + GpsModeIndicator = ParseModeIndicator(message[5][0]); + if (message[5].Length > 1) + GlonassModeIndicator = ParseModeIndicator(message[5][1]); + if (message[5].Length > 2) + { + FutureModeIndicator = message[5].Skip(2).Select(t => ParseModeIndicator(t)).ToArray(); + } + else + FutureModeIndicator = new Mode[] { }; + NumberOfSatellites = int.Parse(message[6], CultureInfo.InvariantCulture); + Hdop = NmeaMessage.StringToDouble(message[7]); + OrhometricHeight = NmeaMessage.StringToDouble(message[8]); + GeoidalSeparation = NmeaMessage.StringToDouble(message[9]); + var timeInSeconds = StringToDouble(message[10]); + if (!double.IsNaN(timeInSeconds)) + TimeSinceLastDgpsUpdate = TimeSpan.FromSeconds(timeInSeconds); + else + TimeSinceLastDgpsUpdate = TimeSpan.MaxValue; + if (message[11].Length > 0) + DgpsStationId = message[11]; + + if (message.Length > 12) + { + switch (message[12]) + { + case "S": Status = NavigationalStatus.Safe; break; + case "C": Status = NavigationalStatus.Caution; break; + case "U": Status = NavigationalStatus.Unsafe; break; + case "V": + default: Status = NavigationalStatus.NotValid; break; + } + } + } + + /// + /// Time of day fix was taken + /// + public TimeSpan FixTime { get; private set; } + + /// + /// Latitude + /// + public double Latitude { get; private set; } + + /// + /// Longitude + /// + public double Longitude { get; private set; } + + /// + /// Mode indicator for GPS + /// + /// + /// + public Mode GpsModeIndicator { get; private set; } + + /// + /// Mode indicator for GLONASS + /// + /// + /// + public Mode GlonassModeIndicator { get; private set; } + + /// + /// Mode indicator for future constallations + /// + /// + /// + public Mode[] FutureModeIndicator { get; private set; } + + /// + /// Number of satellites (SVs) in use + /// + public int NumberOfSatellites { get; private set; } + + /// + /// Horizontal Dilution of Precision (HDOP), calculated using all the satellites (GPS, GLONASS, and any future satellites) used in computing the solution reported in each GNS sentence. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Hdop")] + public double Hdop { get; private set; } + + /// + /// Orthometric height in meters (MSL reference) + /// + public double OrhometricHeight { get; private set; } + + /// + /// Geoidal separation in meters - the difference between the earth ellipsoid surface and mean-sea-level (geoid) surface defined by the reference datum used in the position solution
+ /// '-' = mean-sea-level surface below ellipsoid. + ///
+ public double GeoidalSeparation { get; private set; } + + /// + /// Age of differential data - if talker ID is GN, additional GNS messages follow with GP and/or GL Age of differential data + /// + public TimeSpan TimeSinceLastDgpsUpdate { get; private set; } + + /// + /// eference station ID1, range 0000-4095 - Null if talker ID is GN, additional GNS messages follow with GP and/or GL Reference station ID + /// + public string DgpsStationId { get; private set; } + + /// + /// Navigational status + /// + public NavigationalStatus Status { get; private set; } + } +} diff --git a/src/NmeaParser/Nmea/Gnss/Gngga.cs b/src/NmeaParser/Nmea/Gnss/Gngga.cs index 448eb0d..251d50d 100644 --- a/src/NmeaParser/Nmea/Gnss/Gngga.cs +++ b/src/NmeaParser/Nmea/Gnss/Gngga.cs @@ -26,7 +26,7 @@ namespace NmeaParser.Nmea.Gnss /// /// Global Positioning System Fix Data /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgga")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gngga")] [NmeaMessageType("GNGGA")] public class Gngga : Gga { diff --git a/src/NmeaParser/Nmea/Gnss/Gngll.cs b/src/NmeaParser/Nmea/Gnss/Gngll.cs new file mode 100644 index 0000000..fbbdeea --- /dev/null +++ b/src/NmeaParser/Nmea/Gnss/Gngll.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea.Gnss +{ + /// + /// Geographic position, latitude / longitude + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gngll")] + [NmeaMessageType("GNGLL")] + public class Gngll : Gll + { + } +} diff --git a/src/NmeaParser/Nmea/Gnss/Gngns.cs b/src/NmeaParser/Nmea/Gnss/Gngns.cs new file mode 100644 index 0000000..289081f --- /dev/null +++ b/src/NmeaParser/Nmea/Gnss/Gngns.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NmeaParser.Nmea.Gps +{ + /// + /// Fixes data for single or combined (GPS, GLONASS, possible future satellite systems, and systems combining these) satellite navigation systems + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gngns")] + [NmeaMessageType("GNGNS")] + public class Gngns : Gns + { + } +} diff --git a/src/NmeaParser/Nmea/Gnss/Gngsa.cs b/src/NmeaParser/Nmea/Gnss/Gngsa.cs new file mode 100644 index 0000000..9a3894a --- /dev/null +++ b/src/NmeaParser/Nmea/Gnss/Gngsa.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea.Gnss +{ + /// + /// Global Positioning System Fix Data + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gngsa")] + [NmeaMessageType("GNGSA")] + public class Gngsa : Gsa + { + } +} diff --git a/src/NmeaParser/Nmea/Gnss/Gnrmc.cs b/src/NmeaParser/Nmea/Gnss/Gnrmc.cs index b0bb136..2a2a534 100644 --- a/src/NmeaParser/Nmea/Gnss/Gnrmc.cs +++ b/src/NmeaParser/Nmea/Gnss/Gnrmc.cs @@ -26,7 +26,7 @@ namespace NmeaParser.Nmea.Gnss /// /// Recommended Minimum /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gprmc")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gnrmc")] [NmeaMessageType("GNRMC")] public class Gnrmc : Rmc { diff --git a/src/NmeaParser/Nmea/Gps/GPGLL.cs b/src/NmeaParser/Nmea/Gps/GPGLL.cs index c5a2dc0..05fb2b8 100644 --- a/src/NmeaParser/Nmea/Gps/GPGLL.cs +++ b/src/NmeaParser/Nmea/Gps/GPGLL.cs @@ -28,47 +28,7 @@ namespace NmeaParser.Nmea.Gps /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgll")] [NmeaMessageType("GPGLL")] - public class Gpgll : NmeaMessage + public class Gpgll : Gll { - /// - /// Called when the message is being loaded. - /// - /// The NMEA message values. - protected override void OnLoadMessage(string[] message) - { - if (message == null || message.Length < 4) - throw new ArgumentException("Invalid GPGLL", "message"); - Latitude = NmeaMessage.StringToLatitude(message[0], message[1]); - Longitude = NmeaMessage.StringToLongitude(message[2], message[3]); - if (message.Length >= 5) //Some older GPS doesn't broadcast fix time - { - FixTime = StringToTimeSpan(message[4]); - } - DataActive = (message.Length < 6 || message[5] == "A"); - } - - /// - /// Latitude - /// - public double Latitude { get; private set; } - - /// - /// Longitude - /// - public double Longitude { get; private set; } - - /// - /// Time since last DGPS update - /// - public TimeSpan FixTime { get; private set; } - - /// - /// Gets a value indicating whether data is active. - /// - /// - /// true if data is active; otherwise, false. - /// - public bool DataActive { get; private set; } - } } diff --git a/src/NmeaParser/Nmea/Gps/GPGSA.cs b/src/NmeaParser/Nmea/Gps/GPGSA.cs index 648fc11..caefb32 100644 --- a/src/NmeaParser/Nmea/Gps/GPGSA.cs +++ b/src/NmeaParser/Nmea/Gps/GPGSA.cs @@ -28,7 +28,7 @@ namespace NmeaParser.Nmea.Gps /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgsa")] [NmeaMessageType("GPGSA")] - public class Gpgsa : NmeaMessage + public class Gpgsa : Gsa { /// /// Mode selection @@ -63,76 +63,5 @@ namespace NmeaParser.Nmea.Gps /// Fix3D = 3 } - - /// - /// Called when the message is being loaded. - /// - /// The NMEA message values. - protected override void OnLoadMessage(string[] message) - { - if (message == null || message.Length < 17) - throw new ArgumentException("Invalid GPGSA", "message"); - - GpsMode = message[0] == "A" ? ModeSelection.Auto : ModeSelection.Manual; - FixMode = (Mode)int.Parse(message[1], CultureInfo.InvariantCulture); - - List svs = new List(); - for (int i = 2; i < 14; i++) - { - int id = -1; - if (message[i].Length > 0 && int.TryParse(message[i], out id)) - svs.Add(id); - } - SVs = svs.ToArray(); - - double tmp; - if (double.TryParse(message[14], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) - Pdop = tmp; - else - Pdop = double.NaN; - - if (double.TryParse(message[15], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) - Hdop = tmp; - else - Hdop = double.NaN; - - if (double.TryParse(message[16], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) - Vdop = tmp; - else - Vdop = double.NaN; - } - - /// - /// Mode - /// - public ModeSelection GpsMode { get; private set; } - - /// - /// Mode - /// - public Mode FixMode { get; private set; } - - /// - /// IDs of SVs used in position fix - /// - public IReadOnlyList SVs { get; private set; } - - /// - /// Dilution of precision - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Pdop")] - public double Pdop { get; private set; } - - /// - /// Horizontal dilution of precision - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Hdop")] - public double Hdop { get; private set; } - - /// - /// Vertical dilution of precision - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Vdop")] - public double Vdop { get; private set; } } } diff --git a/src/NmeaParser/Nmea/Gps/GPGSV.cs b/src/NmeaParser/Nmea/Gps/GPGSV.cs index 5feb5b8..af55e8e 100644 --- a/src/NmeaParser/Nmea/Gps/GPGSV.cs +++ b/src/NmeaParser/Nmea/Gps/GPGSV.cs @@ -23,149 +23,92 @@ using System.Threading.Tasks; namespace NmeaParser.Nmea.Gps { - /// - /// GPS Satellites in view - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgsv")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] - [NmeaMessageType("GPGSV")] - public sealed class Gpgsv : NmeaMessage, IMultiPartMessage - { - /// - /// Called when the message is being loaded. - /// - /// The NMEA message values. - protected override void OnLoadMessage(string[] message) - { - if (message == null || message.Length < 3) - throw new ArgumentException("Invalid GPGSV", "message"); - - TotalMessages = int.Parse(message[0], CultureInfo.InvariantCulture); - MessageNumber = int.Parse(message[1], CultureInfo.InvariantCulture); - SVsInView = int.Parse(message[2], CultureInfo.InvariantCulture); + /// + /// GLONASS Satellites in view + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgsv")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + [NmeaMessageType("GPGSV")] + public sealed class Gpgsv : Gsv + { + } - List svs = new List(); - for (int i = 3; i < message.Length - 3; i += 4) - { - if (message[i].Length == 0) - continue; - else - svs.Add(new SatelliteVehicle(message, i)); - } - this.SVs = svs.ToArray(); - } + /// + /// Satellite vehicle + /// + public sealed class SatelliteVehicle + { + internal SatelliteVehicle(string[] message, int startIndex) + { + PrnNumber = int.Parse(message[startIndex], CultureInfo.InvariantCulture); + Elevation = double.Parse(message[startIndex + 1], CultureInfo.InvariantCulture); + Azimuth = double.Parse(message[startIndex + 2], CultureInfo.InvariantCulture); + int snr = -1; + if (int.TryParse(message[startIndex + 3], out snr)) + SignalToNoiseRatio = snr; + } + /// + /// SV PRN number + /// + public int PrnNumber { get; set; } + /// + /// Elevation in degrees, 90 maximum + /// + public double Elevation { get; private set; } + /// + /// Azimuth, degrees from true north, 000 to 359 + /// + public double Azimuth { get; private set; } + /// + /// Signal-to-Noise ratio, 0-99 dB (-1 when not tracking) + /// + public int SignalToNoiseRatio { get; private set; } - /// - /// Total number of messages of this type in this cycle - /// - public int TotalMessages { get; private set; } + /// + /// Satellite system + /// + public SatelliteSystem System + { + get + { + if (PrnNumber >= 1 && PrnNumber <= 32) + return SatelliteSystem.Gps; + if (PrnNumber >= 33 && PrnNumber <= 64) + return SatelliteSystem.Waas; + if (PrnNumber >= 65 && PrnNumber <= 96) + return SatelliteSystem.Glonass; + return SatelliteSystem.Unknown; + } + } + } - /// - /// Message number - /// - public int MessageNumber { get; private set; } - - /// - /// Total number of SVs in view - /// - public int SVsInView { get; private set; } - - /// - /// Dilution of precision - /// - public IReadOnlyList SVs { get; private set; } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// A System.Collections.Generic.IEnumerator{SatelliteVehicle} that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - foreach(var sv in SVs) - yield return sv; - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An System.Collections.IEnumerator object that can be used to iterate through the collection. - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - /// - /// Satellite vehicle - /// - public sealed class SatelliteVehicle - { - internal SatelliteVehicle(string[] message, int startIndex) - { - PrnNumber = int.Parse(message[startIndex], CultureInfo.InvariantCulture); - Elevation = double.Parse(message[startIndex+1], CultureInfo.InvariantCulture); - Azimuth = double.Parse(message[startIndex + 2], CultureInfo.InvariantCulture); - int snr = -1; - if (int.TryParse(message[startIndex + 3], out snr)) - SignalToNoiseRatio = snr; - } - /// - /// SV PRN number - /// - public int PrnNumber { get; set; } - /// - /// Elevation in degrees, 90 maximum - /// - public double Elevation { get; private set; } - /// - /// Azimuth, degrees from true north, 000 to 359 - /// - public double Azimuth { get; private set; } - /// - /// Signal-to-Noise ratio, 0-99 dB (-1 when not tracking) - /// - public int SignalToNoiseRatio { get; private set; } - - /// - /// Satellite system - /// - public SatelliteSystem System - { - get - { - if (PrnNumber >= 1 && PrnNumber <= 32) - return SatelliteSystem.Gps; - if (PrnNumber >= 33 && PrnNumber <= 64) - return SatelliteSystem.Waas; - if (PrnNumber >= 65 && PrnNumber <= 96) - return SatelliteSystem.Glonass; - return SatelliteSystem.Unknown; - } - } - } - - /// - /// Satellite system - /// - public enum SatelliteSystem - { - /// - /// Unknown - /// - Unknown, - /// - /// GPS - Global Positioning System (NAVSTAR) - /// - Gps, - /// - /// WAAS - Wide Area Augmentation System - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Waas")] - Waas, - /// - /// GLONASS - Globalnaya navigatsionnaya sputnikovaya sistema - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Glonass")] - Glonass - } -} + /// + /// Satellite system + /// + public enum SatelliteSystem + { + /// + /// Unknown + /// + Unknown, + /// + /// GPS - Global Positioning System (NAVSTAR) + /// + Gps, + /// + /// WAAS - Wide Area Augmentation System + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Waas")] + Waas, + /// + /// GLONASS - Globalnaya navigatsionnaya sputnikovaya sistema + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Glonass")] + Glonass, + /// + /// Galileo + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Galileo")] + Galileo + } +} \ No newline at end of file diff --git a/src/NmeaParser/Nmea/Gps/Gpgns.cs b/src/NmeaParser/Nmea/Gps/Gpgns.cs new file mode 100644 index 0000000..f901423 --- /dev/null +++ b/src/NmeaParser/Nmea/Gps/Gpgns.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NmeaParser.Nmea.Gps +{ + /// + /// Fixes data for GPS satellite navigation systems + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gpgns")] + [NmeaMessageType("GPGNS")] + public class Gpgns : Gns + { + } +} diff --git a/src/NmeaParser/Nmea/Gsa.cs b/src/NmeaParser/Nmea/Gsa.cs new file mode 100644 index 0000000..32a7859 --- /dev/null +++ b/src/NmeaParser/Nmea/Gsa.cs @@ -0,0 +1,103 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea +{ + /// + /// Global Positioning System Fix Data + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gsa")] + public abstract class Gsa : NmeaMessage + { + /// + /// Called when the message is being loaded. + /// + /// The NMEA message values. + protected override void OnLoadMessage(string[] message) + { + if (message == null || message.Length < 17) + throw new ArgumentException("Invalid GPGSA", "message"); + + GpsMode = message[0] == "A" ? Gps.Gpgsa.ModeSelection.Auto : Gps.Gpgsa.ModeSelection.Manual; + FixMode = (Gps.Gpgsa.Mode)int.Parse(message[1], CultureInfo.InvariantCulture); + + List svs = new List(); + for (int i = 2; i < 14; i++) + { + int id = -1; + if (message[i].Length > 0 && int.TryParse(message[i], out id)) + svs.Add(id); + } + SVs = svs.ToArray(); + + double tmp; + if (double.TryParse(message[14], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) + Pdop = tmp; + else + Pdop = double.NaN; + + if (double.TryParse(message[15], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) + Hdop = tmp; + else + Hdop = double.NaN; + + if (double.TryParse(message[16], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) + Vdop = tmp; + else + Vdop = double.NaN; + } + + /// + /// Mode + /// + public Gps.Gpgsa.ModeSelection GpsMode { get; private set; } + + /// + /// Mode + /// + public Gps.Gpgsa.Mode FixMode { get; private set; } + + /// + /// IDs of SVs used in position fix + /// + public IReadOnlyList SVs { get; private set; } + + /// + /// Dilution of precision + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Pdop")] + public double Pdop { get; private set; } + + /// + /// Horizontal dilution of precision + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Hdop")] + public double Hdop { get; private set; } + + /// + /// Vertical dilution of precision + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Vdop")] + public double Vdop { get; private set; } + } +} diff --git a/src/NmeaParser/Nmea/Gsv.cs b/src/NmeaParser/Nmea/Gsv.cs new file mode 100644 index 0000000..f6e7c8c --- /dev/null +++ b/src/NmeaParser/Nmea/Gsv.cs @@ -0,0 +1,97 @@ +// +// Copyright (c) 2014 Morten Nielsen +// +// Licensed under the Microsoft Public License (Ms-PL) (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://opensource.org/licenses/Ms-PL.html +// +// 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 NmeaParser.Nmea.Gps; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NmeaParser.Nmea +{ + /// + /// GPS Satellites in view + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gsv")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + public abstract class Gsv : NmeaMessage, IMultiPartMessage + { + /// + /// Called when the message is being loaded. + /// + /// The NMEA message values. + protected override void OnLoadMessage(string[] message) + { + if (message == null || message.Length < 3) + throw new ArgumentException("Invalid GSV", "message"); + + TotalMessages = int.Parse(message[0], CultureInfo.InvariantCulture); + MessageNumber = int.Parse(message[1], CultureInfo.InvariantCulture); + SVsInView = int.Parse(message[2], CultureInfo.InvariantCulture); + + List svs = new List(); + for (int i = 3; i < message.Length - 3; i += 4) + { + if (message[i].Length == 0) + continue; + else + svs.Add(new SatelliteVehicle(message, i)); + } + this.SVs = svs.ToArray(); + } + + /// + /// Total number of messages of this type in this cycle + /// + public int TotalMessages { get; private set; } + + /// + /// Message number + /// + public int MessageNumber { get; private set; } + + /// + /// Total number of SVs in view + /// + public int SVsInView { get; private set; } + + /// + /// Dilution of precision + /// + public IReadOnlyList SVs { get; private set; } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// A System.Collections.Generic.IEnumerator{SatelliteVehicle} that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + foreach(var sv in SVs) + yield return sv; + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An System.Collections.IEnumerator object that can be used to iterate through the collection. + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/NmeaParser/NmeaParser.csproj b/src/NmeaParser/NmeaParser.csproj index 4afa43d..5099205 100644 --- a/src/NmeaParser/NmeaParser.csproj +++ b/src/NmeaParser/NmeaParser.csproj @@ -9,16 +9,19 @@ Morten Nielsen Morten Nielsen An NMEA stream parser for serial port, bluetooth and file-based nmea simulation. - nmea winrt wpf win8 win8.1 wp8.1 uwp xamarin gps serialport bluetooth + nmea winrt wpf uwp xamarin gps serialport bluetooth SharpGIS.NmeaParser - 1.8.0 + 1.9.0 http://opensource.org/licenses/ms-pl.html https://github.com/dotMorten/NmeaParser https://github.com/dotMorten/NmeaParser en-US Copyright © Morten Nielsen 2015-2017 - $(MSBuildThisFileDirectory)..\Bin\$(Configuration) - $(OutDir) + $(MSBuildThisFileDirectory)..\Bin\$(Configuration) + $(OutDir) + 1.9.0.0 + 1.9.0.0 + Added new GLONASS and GALILEO. Moved more GPS message to abstract base classes for better handling of multiple satelitte constellations. @@ -50,8 +53,8 @@ - - + + diff --git a/src/SampleApp.WinDesktop/SampleApp.WinDesktop.csproj b/src/SampleApp.WinDesktop/SampleApp.WinDesktop.csproj index 65d4c7d..254e3d7 100644 --- a/src/SampleApp.WinDesktop/SampleApp.WinDesktop.csproj +++ b/src/SampleApp.WinDesktop/SampleApp.WinDesktop.csproj @@ -38,10 +38,6 @@ PackageReference - - False - ..\NmeaParser\bin\$(Configuration)\net451\NmeaParser.dll - @@ -171,6 +167,12 @@ PreserveNewest + + + {1adc3666-1ddb-48c4-9811-1e58b6d09a7c} + NmeaParser + +