diff --git a/src/NmeaParser/IMultiPartMessage.cs b/src/NmeaParser/IMultiSentenceMessage.cs
similarity index 72%
rename from src/NmeaParser/IMultiPartMessage.cs
rename to src/NmeaParser/IMultiSentenceMessage.cs
index 0f79943..b825393 100644
--- a/src/NmeaParser/IMultiPartMessage.cs
+++ b/src/NmeaParser/IMultiSentenceMessage.cs
@@ -18,19 +18,14 @@ using System.Text;
namespace NmeaParser
{
- interface IMultiPartMessage : System.Collections.IEnumerable
+ public interface IMultiSentenceMessage : System.Collections.IEnumerable
{
- ///
- /// Total number of messages of this type in this cycle
- ///
- int TotalMessages { get; }
-
- ///
- /// Message number
- ///
- int MessageNumber { get; }
+ bool TryAppend(string[] values);
+ bool IsComplete { get; }
+ IEnumerable SerializeParts();
}
- interface IMultiPartMessage : IMultiPartMessage, IEnumerable
- {
+
+ public interface IMultiSentenceMessage : IMultiSentenceMessage, IEnumerable
+ {
}
}
diff --git a/src/NmeaParser/Nmea/Gsv.cs b/src/NmeaParser/Nmea/Gsv.cs
index f4a67b9..50ad9fd 100644
--- a/src/NmeaParser/Nmea/Gsv.cs
+++ b/src/NmeaParser/Nmea/Gsv.cs
@@ -24,8 +24,13 @@ namespace NmeaParser.Nmea
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gsv")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
[NmeaMessageType("--GSV")]
- public class Gsv : NmeaMessage, IMultiPartMessage
+ public class Gsv : NmeaMessage, IMultiSentenceMessage
{
+ private readonly List svs = new List();
+ private int lastMessageNumber = 0;
+ private int totalMessages;
+ private readonly int firstMessageNumber;
+
///
/// Initializes a new instance of the class.
///
@@ -36,9 +41,10 @@ namespace NmeaParser.Nmea
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);
+ totalMessages = int.Parse(message[0], CultureInfo.InvariantCulture);
+ firstMessageNumber = int.Parse(message[1], CultureInfo.InvariantCulture);
SVsInView = int.Parse(message[2], CultureInfo.InvariantCulture);
+ AppendParts(message);
List svs = new List();
for (int i = 3; i < message.Length - 3; i += 4)
@@ -48,18 +54,37 @@ namespace NmeaParser.Nmea
else
svs.Add(new SatelliteVehicle(message, i));
}
- this.SVs = svs.ToArray();
+ this.SVs = svs.AsReadOnly();
}
- ///
- /// Total number of messages of this type in this cycle
- ///
- public int TotalMessages { get; }
+ bool IMultiSentenceMessage.TryAppend(string[] values) => AppendParts(values);
+ bool IMultiSentenceMessage.IsComplete => firstMessageNumber == 1 && lastMessageNumber == totalMessages;
- ///
- /// Message number
- ///
- public int MessageNumber { get; }
+ private bool AppendParts(string[] message)
+ {
+ int msgCount = int.Parse(message[0], CultureInfo.InvariantCulture);
+ int msgNumber = int.Parse(message[1], CultureInfo.InvariantCulture);
+ var satellites = int.Parse(message[2], CultureInfo.InvariantCulture);
+
+ if (msgCount != totalMessages || msgNumber != lastMessageNumber + 1 || satellites != SVsInView)
+ return false; // Messages do not match
+
+ for (int i = 3; i < message.Length - 3; i += 4)
+ {
+ if (message[i].Length == 0)
+ continue;
+ else
+ svs.Add(new SatelliteVehicle(message, i));
+ }
+ lastMessageNumber = msgNumber;
+ this.SVs = svs.AsReadOnly();
+ return true;
+ }
+
+ IEnumerable IMultiSentenceMessage.SerializeParts()
+ {
+ throw new NotImplementedException();
+ }
///
/// Total number of SVs in view
@@ -69,7 +94,7 @@ namespace NmeaParser.Nmea
///
/// Satellite vehicles in this message part.
///
- public IReadOnlyList SVs { get; }
+ public IReadOnlyList SVs { get; private set; }
///
/// Returns an enumerator that iterates through the collection.
diff --git a/src/NmeaParser/Nmea/NmeaMessage.cs b/src/NmeaParser/Nmea/NmeaMessage.cs
index 14c4ce4..52ebbaf 100644
--- a/src/NmeaParser/Nmea/NmeaMessage.cs
+++ b/src/NmeaParser/Nmea/NmeaMessage.cs
@@ -92,10 +92,10 @@ namespace NmeaParser.Nmea
/// Invalid nmea message: Missing starting character '$'
/// or checksum failure
///
- public static NmeaMessage Parse(string message)
+ public static NmeaMessage Parse(string message, IMultiSentenceMessage? previousSentence = null)
{
if (string.IsNullOrEmpty(message))
- throw new ArgumentNullException("message");
+ throw new ArgumentNullException(nameof(message));
int checksum = -1;
if (message[0] != '$')
@@ -120,6 +120,13 @@ namespace NmeaParser.Nmea
string[] parts = message.Split(new char[] { ',' });
string MessageType = parts[0].Substring(1);
string[] MessageParts = parts.Skip(1).ToArray();
+ if(previousSentence is NmeaMessage pmsg && pmsg.MessageType == MessageType)
+ {
+ if (previousSentence.TryAppend(MessageParts))
+ {
+ return pmsg;
+ }
+ }
if (messageTypes.ContainsKey(MessageType))
{
return (NmeaMessage)messageTypes[MessageType].Invoke(new object[] { MessageType, MessageParts });
diff --git a/src/NmeaParser/NmeaDevice.cs b/src/NmeaParser/NmeaDevice.cs
index 7ad7b77..992cccb 100644
--- a/src/NmeaParser/NmeaDevice.cs
+++ b/src/NmeaParser/NmeaDevice.cs
@@ -55,8 +55,8 @@ namespace NmeaParser
m_cts = new CancellationTokenSource();
m_stream = await OpenStreamAsync();
StartParser(m_cts.Token);
- MultiPartMessageCache.Clear();
- lock (m_lockObject)
+ _lastMultiMessage = null;
+ lock (m_lockObject)
{
IsOpen = true;
m_isOpening = false;
@@ -132,7 +132,7 @@ namespace NmeaParser
await m_ParserTask;
if (m_stream != null)
await CloseStreamAsync(m_stream);
- MultiPartMessageCache.Clear();
+ _lastMultiMessage = null;
m_stream = null;
lock (m_lockObject)
{
@@ -167,58 +167,41 @@ namespace NmeaParser
}
foreach(var line in lines)
ProcessMessage(line);
- }
+ }
+
+
+ private IMultiSentenceMessage? _lastMultiMessage;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="Must silently handle invalid/corrupt input")]
private void ProcessMessage(string p)
{
try
{
- var msg = NmeaParser.Nmea.NmeaMessage.Parse(p);
+ var msg = NmeaParser.Nmea.NmeaMessage.Parse(p, _lastMultiMessage);
+ if(msg is IMultiSentenceMessage multi)
+ {
+ if (!multi.IsComplete)
+ {
+ _lastMultiMessage = multi; //Keep it around until next time
+ return;
+ }
+ _lastMultiMessage = null;
+ }
if (msg != null)
OnMessageReceived(msg);
}
catch { }
}
- private void OnMessageReceived(Nmea.NmeaMessage msg)
+ private void OnMessageReceived(Nmea.NmeaMessage msg)
{
if (msg == null)
return;
- Nmea.NmeaMessage[]? messageParts = null;
- if (msg is IMultiPartMessage multi)
- {
- string messageType = msg.MessageType.Substring(2); //We don't care about the two first characters. Ie GPGSV, GLGSV, GAGSV etc are all part of the same multi-part message
- if (MultiPartMessageCache.ContainsKey(messageType))
- {
- var dic = MultiPartMessageCache[messageType];
- if (dic.ContainsKey(multi.MessageNumber - 1) && !dic.ContainsKey(multi.MessageNumber))
- {
- dic[multi.MessageNumber] = msg;
- }
- else //Something is out of order. Clear cache
- MultiPartMessageCache.Remove(messageType);
- }
- else if (multi.MessageNumber == 1)
- {
- MultiPartMessageCache[messageType] = new Dictionary(multi.TotalMessages);
- MultiPartMessageCache[messageType][1] = msg;
- }
- if (MultiPartMessageCache.ContainsKey(messageType))
- {
- var dic = MultiPartMessageCache[messageType];
- if (dic.Count == multi.TotalMessages) //We have a full list
- {
- MultiPartMessageCache.Remove(messageType);
- messageParts = dic.Values.ToArray();
- }
- }
- }
-
- MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg, messageParts));
+
+ MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg));
}
- private readonly Dictionary> MultiPartMessageCache = new Dictionary>();
+ //private readonly Dictionary> MultiPartMessageCache = new Dictionary>();
///
/// Occurs when an NMEA message is received.
@@ -289,10 +272,9 @@ namespace NmeaParser
///
public sealed class NmeaMessageReceivedEventArgs : EventArgs
{
- internal NmeaMessageReceivedEventArgs(Nmea.NmeaMessage message, IReadOnlyList? messageParts)
+ internal NmeaMessageReceivedEventArgs(Nmea.NmeaMessage message)
{
Message = message;
- MessageParts = messageParts;
}
///
@@ -309,7 +291,7 @@ namespace NmeaParser
///
/// true if this instance is multi part; otherwise, false.
///
- public bool IsMultipart => Message is IMultiPartMessage;
+ public bool IsMultipart => Message is IMultiSentenceMessage;
///
/// Gets the message parts if this is a multi-part message and all message parts has been received.