From 9a71ca4db6cfd7d1e8f79e25ca66ad87b2173fec Mon Sep 17 00:00:00 2001 From: Morten Nielsen Date: Tue, 28 Jul 2020 20:14:40 -0700 Subject: [PATCH] Improved location datasource to better handle multiple gps systems --- src/NmeaParser.sln | 1 + .../NmeaLocationDataSourcer.cs | 114 ++++++++++++++++++ src/SampleApp.WinDesktop/NmeaProvider.cs | 100 --------------- src/SampleApp.WinDesktop/View2D.xaml.cs | 4 +- 4 files changed, 117 insertions(+), 102 deletions(-) create mode 100644 src/SampleApp.WinDesktop/NmeaLocationDataSourcer.cs delete mode 100644 src/SampleApp.WinDesktop/NmeaProvider.cs diff --git a/src/NmeaParser.sln b/src/NmeaParser.sln index deb258b..d5e43f6 100644 --- a/src/NmeaParser.sln +++ b/src/NmeaParser.sln @@ -39,6 +39,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp.NetCore", "Sample EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution + UnitTests\NmeaParser.Tests\NmeaParser.Tests.projitems*{73efb2ef-de40-46c4-9685-745a9815c0d2}*SharedItemsImports = 5 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 diff --git a/src/SampleApp.WinDesktop/NmeaLocationDataSourcer.cs b/src/SampleApp.WinDesktop/NmeaLocationDataSourcer.cs new file mode 100644 index 0000000..3be9a21 --- /dev/null +++ b/src/SampleApp.WinDesktop/NmeaLocationDataSourcer.cs @@ -0,0 +1,114 @@ +using Esri.ArcGISRuntime.Geometry; +using System; +using System.Threading.Tasks; + +namespace SampleApp.WinDesktop +{ + public class NmeaLocationDataSource : Esri.ArcGISRuntime.Location.LocationDataSource + { + private NmeaParser.NmeaDevice device; + private double m_Accuracy = 0; + private double m_altitude = double.NaN; + private double m_speed = 0; + private double m_course = 0; + private bool supportGNMessages; // If device detect GN* messages, ignore all other Talker ID + private bool supportGGaMessages; //If device support GGA, ignore RMC for location + + public NmeaLocationDataSource(NmeaParser.NmeaDevice device) + { + this.device = device; + if(device != null) + device.MessageReceived += device_MessageReceived; + } + void device_MessageReceived(object sender, NmeaParser.NmeaMessageReceivedEventArgs e) + { + var message = e.Message; + ParseMessage(message); + } + public void ParseMessage(NmeaParser.Messages.NmeaMessage message) + { + bool isNewFix = false; + bool lostFix = false; + double lat = 0; + double lon = 0; + if (message.TalkerId == NmeaParser.Talker.GlobalNavigationSatelliteSystem) + supportGNMessages = true; + else if(supportGNMessages && message.TalkerId != NmeaParser.Talker.GlobalNavigationSatelliteSystem) + return; // If device supports combined GN* messages, ignore non-GN messages + + if (message is NmeaParser.Messages.Garmin.Pgrme rme) + { + m_Accuracy = rme.HorizontalError; + } + else if(message is NmeaParser.Messages.Gst gst) + { + Gst = gst; + m_Accuracy = Math.Sqrt(Gst.SigmaLatitudeError * Gst.SigmaLatitudeError + Gst.SigmaLongitudeError * Gst.SigmaLongitudeError); + } + else if (message is NmeaParser.Messages.Rmc rmc) + { + Rmc = rmc; + if (Rmc.Active) + { + m_speed = double.IsNaN(Rmc.Speed) ? Rmc.Speed : 0; + if (!double.IsNaN(Rmc.Course)) + m_course = Rmc.Course; + lat = Rmc.Latitude; + lon = Rmc.Longitude; + } + else + { + lostFix = true; + } + isNewFix = !supportGGaMessages; + } + else if (message is NmeaParser.Messages.Gga gga) + { + supportGGaMessages = true; + if (gga.Quality != NmeaParser.Messages.Gga.FixQuality.Invalid) + { + lat = Rmc.Latitude; + lon = Rmc.Longitude; + m_altitude = gga.Altitude + gga.GeoidalSeparation; //Convert to ellipsoidal height + } + if (gga.Quality != NmeaParser.Messages.Gga.FixQuality.Invalid || gga.Quality == NmeaParser.Messages.Gga.FixQuality.Estimated) + { + lostFix = true; + } + isNewFix = true; + } + else if (message is NmeaParser.Messages.Gsa gsa) + { + Gsa = gsa; + } + if (isNewFix) + { + base.UpdateLocation(new Esri.ArcGISRuntime.Location.Location( + !double.IsNaN(m_altitude) ? new MapPoint(lon, lat, m_altitude, wgs84_ellipsoidHeight) : new MapPoint(lon, lat, SpatialReferences.Wgs84), + m_Accuracy, m_speed, m_course, lostFix)); + } + } + private static SpatialReference wgs84_ellipsoidHeight = SpatialReference.Create(4326, 115700); + protected override Task OnStartAsync() + { + if (device != null) + return this.device.OpenAsync(); + else + return System.Threading.Tasks.Task.FromResult(true); + } + + protected override Task OnStopAsync() + { + m_Accuracy = double.NaN; + if(this.device != null) + return this.device.CloseAsync(); + else + return System.Threading.Tasks.Task.FromResult(true); + } + + public NmeaParser.Messages.Gsa Gsa { get; private set; } + public NmeaParser.Messages.Gga Gga { get; private set; } + public NmeaParser.Messages.Rmc Rmc { get; private set; } + public NmeaParser.Messages.Gst Gst { get; private set; } + } +} diff --git a/src/SampleApp.WinDesktop/NmeaProvider.cs b/src/SampleApp.WinDesktop/NmeaProvider.cs deleted file mode 100644 index d26024c..0000000 --- a/src/SampleApp.WinDesktop/NmeaProvider.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Esri.ArcGISRuntime.Geometry; -using System; -using System.Threading.Tasks; - -namespace SampleApp.WinDesktop -{ - public class NmeaLocationProvider : Esri.ArcGISRuntime.Location.LocationDataSource - { - private NmeaParser.NmeaDevice device; - double m_Accuracy = 0; - double m_altitude = double.NaN; - double m_speed = 0; - double m_course = 0; - - public NmeaLocationProvider(NmeaParser.NmeaDevice device) - { - this.device = device; - if(device != null) - device.MessageReceived += device_MessageReceived; - } - void device_MessageReceived(object sender, NmeaParser.NmeaMessageReceivedEventArgs e) - { - var message = e.Message; - ParseMessage(message); - } - - public void ParseMessage(NmeaParser.Messages.NmeaMessage message) - { - bool isNewFix = false; - bool lostFix = false; - double lat = 0; - double lon = 0; - if (message is NmeaParser.Messages.Garmin.Pgrme) - { - m_Accuracy = ((NmeaParser.Messages.Garmin.Pgrme)message).HorizontalError; - } - else if(message is NmeaParser.Messages.Gst) - { - Gst = ((NmeaParser.Messages.Gst)message); - m_Accuracy = Math.Sqrt(Gst.SigmaLatitudeError * Gst.SigmaLatitudeError + Gst.SigmaLongitudeError * Gst.SigmaLongitudeError); - } - else if(message is NmeaParser.Messages.Gga) - { - Gga = ((NmeaParser.Messages.Gga)message); - isNewFix = Gga.Quality != NmeaParser.Messages.Gga.FixQuality.Invalid; - lostFix = !isNewFix; - m_altitude = Gga.Altitude; - lat = Gga.Latitude; - lon = Gga.Longitude; - } - else if (message is NmeaParser.Messages.Rmc) - { - Rmc = (NmeaParser.Messages.Rmc)message; - if (Rmc.Active) - { - isNewFix = true; - m_speed = Rmc.Speed; - m_course = Rmc.Course; - lat = Rmc.Latitude; - lon = Rmc.Longitude; - } - else lostFix = true; - } - else if (message is NmeaParser.Messages.Gsa) - { - Gsa = (NmeaParser.Messages.Gsa)message; - } - if (isNewFix) - { - base.UpdateLocation(new Esri.ArcGISRuntime.Location.Location(new MapPoint(lon, lat, m_altitude, SpatialReferences.Wgs84), m_Accuracy, m_speed, m_course, false)); - } - else if (lostFix) - { - - } - } - - protected override Task OnStartAsync() - { - if (device != null) - return this.device.OpenAsync(); - else - return System.Threading.Tasks.Task.FromResult(true); - } - - protected override Task OnStopAsync() - { - m_Accuracy = double.NaN; - if(this.device != null) - return this.device.CloseAsync(); - else - return System.Threading.Tasks.Task.FromResult(true); - } - - public NmeaParser.Messages.Gsa Gsa { get; private set; } - public NmeaParser.Messages.Gga Gga { get; private set; } - public NmeaParser.Messages.Rmc Rmc { get; private set; } - public NmeaParser.Messages.Gst Gst { get; private set; } - } -} diff --git a/src/SampleApp.WinDesktop/View2D.xaml.cs b/src/SampleApp.WinDesktop/View2D.xaml.cs index bf9408a..05a05da 100644 --- a/src/SampleApp.WinDesktop/View2D.xaml.cs +++ b/src/SampleApp.WinDesktop/View2D.xaml.cs @@ -28,7 +28,7 @@ namespace SampleApp.WinDesktop } mapView.LocationDisplay.InitialZoomScale = 5000; - mapView.LocationDisplay.AutoPanMode = Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode.Navigation; + mapView.LocationDisplay.AutoPanMode = Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode.Recenter; } public NmeaDevice NmeaDevice @@ -51,7 +51,7 @@ namespace SampleApp.WinDesktop mapView.LocationDisplay.IsEnabled = false; if (newDevice != null) { - mapView.LocationDisplay.DataSource = new NmeaLocationProvider(newDevice); + mapView.LocationDisplay.DataSource = new NmeaLocationDataSource(newDevice); mapView.LocationDisplay.IsEnabled = true; } }