diff --git a/src/NmeaParser/Gnss/GnssMonitor.cs b/src/NmeaParser/Gnss/GnssMonitor.cs index b92fe2d..85abc4f 100644 --- a/src/NmeaParser/Gnss/GnssMonitor.cs +++ b/src/NmeaParser/Gnss/GnssMonitor.cs @@ -75,9 +75,12 @@ namespace NmeaParser.Gnss List properties = new List(); lock (m_lock) { - if(m_allMessages.ContainsKey(message.MessageType) && m_allMessages[message.MessageType].Equals(message)) + string msgid = message.MessageType; + if (message is Gsv gsv && gsv.GnssSignalId != '0') + msgid = msgid + "|" + gsv.GnssSignalId; + if (m_allMessages.ContainsKey(msgid) && m_allMessages[msgid].Equals(message)) return; // Nothing to update/notify - m_allMessages[message.MessageType] = message; + m_allMessages[msgid] = message; } properties.Add(nameof(AllMessages)); if(message.TalkerId != NmeaParser.Talker.GlobalNavigationSatelliteSystem && !(message is Gsv) && message.MessageType.Length > 2) diff --git a/src/NmeaParser/Nmea/Gsv.cs b/src/NmeaParser/Nmea/Gsv.cs index 15ad778..4bf368e 100644 --- a/src/NmeaParser/Nmea/Gsv.cs +++ b/src/NmeaParser/Nmea/Gsv.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace NmeaParser.Messages { @@ -58,12 +59,20 @@ namespace NmeaParser.Messages else if ( satellites != SatellitesInView) return false; // Messages do not match + if ((message.Length - 3) % 4 == 1) // v4.1+ adds system id to the last message. Example L1=1, and L2=6 on GPS satellites + { + var id = message.Last(); + if (id.Length == 1) + { + GnssSignalId = id[0]; + } + } for (int i = 3; i < message.Length - 3; i += 4) { if (message[i].Length == 0) continue; else - svs.Add(new SatelliteVehicle(talkerType, message, i)); + svs.Add(new SatelliteVehicle(talkerType, GnssSignalId, message, i)); } return true; } @@ -79,6 +88,78 @@ namespace NmeaParser.Messages /// public IReadOnlyList SVs => svs.AsReadOnly(); + /// + /// Gets the GNSS Signal ID + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
SystemSignal IDSignal Channel
GPS0All signals
1L1 C/1
2L1 P(Y)
3L1 M
4L2 P(Y)
5L2C-M
6L2C-L
7L5-I
8L5-Q
9-FReserved
GLONASS0All signals
1G1 C/A
2G1 P
3G2 C/A
4GLONASS (M) G2 P
5-FReserved
GALILEO0All signals
1E5a
2E5b
3E5 a+b
4E6-A
5E6-BC
6L1-A
7L1-BC
8-FReserved
BeiDou System0All signals
1B1I
2B1Q
3B1C
4B1A
5B2-a
6B2-b
7B2 a+b
8B3I
9B3Q
AB3A
BB2I
CB2Q
D-FReserved
QZSS0All signals
1L1 C/A
2L1C (D)
3L1C (P)
4LIS
5L2C-M
6L2C-L
7L5-I
8L5-Q
9L6D
AL6E
B-FReserved
NavIC (IRNSS)0All signals
1L5-SPS
2S-SPS
3L5-RS
4S-RS
5L1-SPS
6-FReserved
+ ///
+ public char GnssSignalId { get; private set; } = '0'; + /// /// Returns an enumerator that iterates through the collection. /// @@ -103,7 +184,7 @@ namespace NmeaParser.Messages /// public sealed class SatelliteVehicle { - internal SatelliteVehicle(Talker talker, string[] message, int startIndex) + internal SatelliteVehicle(Talker talker, char signalId, string[] message, int startIndex) { Id = int.Parse(message[startIndex], CultureInfo.InvariantCulture); if (double.TryParse(message[startIndex + 1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double e)) @@ -113,6 +194,7 @@ namespace NmeaParser.Messages int snr = -1; if (int.TryParse(message[startIndex + 3], out snr)) SignalToNoiseRatio = snr; + GnssSignalId = signalId; TalkerId = talker; } @@ -121,6 +203,12 @@ namespace NmeaParser.Messages /// public Talker TalkerId { get; } + /// + /// Gets the GNSS Signal ID. + /// + /// + public char GnssSignalId { get; } + /// /// Satellite ID number /// diff --git a/src/SampleApp.WinDesktop/SatelliteSnr.xaml b/src/SampleApp.WinDesktop/SatelliteSnr.xaml index 981f6d1..37ed6cc 100644 --- a/src/SampleApp.WinDesktop/SatelliteSnr.xaml +++ b/src/SampleApp.WinDesktop/SatelliteSnr.xaml @@ -54,8 +54,30 @@ BorderBrush="Black" Margin="5,0" Width="20" BorderThickness="1" - ToolTip="{Binding SignalToNoiseRatio}" VerticalAlignment="Bottom"> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SampleApp.WinDesktop/SatelliteSnr.xaml.cs b/src/SampleApp.WinDesktop/SatelliteSnr.xaml.cs index cb8e720..24f93e4 100644 --- a/src/SampleApp.WinDesktop/SatelliteSnr.xaml.cs +++ b/src/SampleApp.WinDesktop/SatelliteSnr.xaml.cs @@ -27,10 +27,10 @@ namespace SampleApp.WinDesktop { InitializeComponent(); } - Dictionary messages = new Dictionary(); + Dictionary messages = new Dictionary(); public void SetGsv(Gsv message) { - messages[message.TalkerId] = message; + messages[message.TalkerId + "+" + message.GnssSignalId] = message; UpdateSatellites(); } public void ClearGsv() @@ -41,16 +41,128 @@ namespace SampleApp.WinDesktop private void UpdateSatellites() { - satellites.ItemsSource = messages.Values.SelectMany(g => g.SVs); - } - } + satellites.ItemsSource = messages.Values.SelectMany(g => g.SVs).OrderBy(s=>s.GnssSignalId).OrderBy(s => s.Id).OrderByDescending(s => s.TalkerId); + } + + internal static string SignalIdToName(char signalId, Talker talkerId) + { + if (signalId != '0') + { + var talker = talkerId; + if (talker == Talker.GlobalPositioningSystem) + { + switch (signalId) + { + case '1': return "L1 C/A"; + case '2': return "L1 P(Y)"; + case '3': return "L1 M"; + case '4': return "L2 P(Y)"; + case '5': return "L2C-M"; + case '6': return "L2C-L"; + case '7': return "L5-I"; + case '8': return "L5-Q"; + } + } + else if (talker == Talker.GlonassReceiver) + { + switch (signalId) + { + case '1': return "G1 C/A"; + case '2': return "G1 P"; + case '3': return "G2 C/A"; + case '4': return "GLONASS (M) G2 P"; + } + } + else if (talker == Talker.GalileoPositioningSystem) + { + switch (signalId) + { + case '1': return "E5a"; + case '2': return "E5b"; + case '3': return "E5 a+b"; + case '4': return "E6-A"; + case '5': return "E6-BC"; + case '6': return "L1-A"; + case '7': return "L1-BC"; + } + } + else if (talker == Talker.BeiDouNavigationSatelliteSystem) + { + switch (signalId) + { + case '1': return "B1I"; + case '2': return "B1Q"; + case '3': return "B1C"; + case '4': return "B1A"; + case '5': return "B2-a"; + case '6': return "B2-b"; + case '7': return "B2 a+b"; + case '8': return "B3I"; + case '9': return "B3Q"; + case 'A': return "B3A"; + case 'B': return "B2I"; + case 'C': return "B2Q"; + } + } + else if (talker == Talker.QuasiZenithSatelliteSystem) + { + switch (signalId) + { + case '1': return "L1 C/A"; + case '2': return "L1C (D)"; + case '3': return "L1C (P)"; + case '4': return "LIS"; + case '5': return "L2C-M"; + case '6': return "L2C-L"; + case '7': return "L5-I"; + case '8': return "L5-Q"; + case '9': return "L6D"; + case 'A': return "L6E"; + } + } + else if (talker == Talker.IndianRegionalNavigationSatelliteSystem) + { + switch (signalId) + { + case '1': return "L5-SPS"; + case '2': return "S-SPS<"; + case '3': return "L5-RS"; + case '4': return "S-RS"; + case '5': return "L1-SPS"; + } + } + } + return string.Empty; + } + } public class SnrToHeightConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if(value is SatelliteVehicle sv) { - return Math.Max(10, sv.SignalToNoiseRatio * 2); + if (parameter as string == "Name") + { + string name; + if (sv.TalkerId == Talker.GlobalPositioningSystem) + name = "GPS"; + else if (sv.TalkerId == Talker.GlonassReceiver) + name = "GLONASS"; + else if (sv.TalkerId == Talker.BeiDouNavigationSatelliteSystem) + name = "BeiDou"; + else if (sv.TalkerId == Talker.QuasiZenithSatelliteSystem) + name = "QZSS"; + else if (sv.TalkerId == Talker.IndianRegionalNavigationSatelliteSystem) + name = "NavIC IRNSS"; + else + name = sv.TalkerId.ToString(); + var signalName = SatelliteSnr.SignalIdToName(sv.GnssSignalId, sv.TalkerId); + if (!string.IsNullOrEmpty(signalName)) + name += " (" + signalName + ")"; + return name; + } + else + return Math.Max(10, sv.SignalToNoiseRatio * 2); } return value; } diff --git a/src/SampleApp.WinDesktop/SatelliteView.xaml.cs b/src/SampleApp.WinDesktop/SatelliteView.xaml.cs index c4351df..7803d2f 100644 --- a/src/SampleApp.WinDesktop/SatelliteView.xaml.cs +++ b/src/SampleApp.WinDesktop/SatelliteView.xaml.cs @@ -27,10 +27,10 @@ namespace SampleApp.WinDesktop { InitializeComponent(); } - Dictionary messages = new Dictionary(); + Dictionary messages = new Dictionary(); public void SetGsv(Gsv message) { - messages[message.TalkerId] = message; + messages[message.TalkerId + "+" + message.GnssSignalId] = message; UpdateSatellites(); } public void ClearGsv()