diff --git a/src/NmeaParser/NmeaDevice.cs b/src/NmeaParser/NmeaDevice.cs
index 3d7acd2..f45a348 100644
--- a/src/NmeaParser/NmeaDevice.cs
+++ b/src/NmeaParser/NmeaDevice.cs
@@ -11,52 +11,52 @@
// * See the License for the specific language governing permissions and
// * limitations under the License.
// ******************************************************************************
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.IO;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
using System.Threading;
using NmeaParser.Messages;
-namespace NmeaParser
-{
- ///
- /// A generic abstract NMEA device
- ///
- public abstract class NmeaDevice : IDisposable
- {
- private readonly object m_lockObject = new object();
- private string m_message = "";
- private Stream? m_stream;
- private CancellationTokenSource? m_cts;
+namespace NmeaParser
+{
+ ///
+ /// A generic abstract NMEA device
+ ///
+ public abstract class NmeaDevice : IDisposable
+ {
+ private readonly object m_lockObject = new object();
+ private string m_message = "";
+ private Stream? m_stream;
+ private CancellationTokenSource? m_cts;
private bool m_isOpening;
private Task? m_ParserTask;
- ///
- /// Initializes a new instance of the class.
- ///
- protected NmeaDevice()
- {
- }
-
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected NmeaDevice()
+ {
+ }
+
///
/// Creates and opens the stream the will be working on top off.
///
- /// A task that represents the asynchronous action.
- public async Task OpenAsync()
- {
- lock (m_lockObject)
- {
- if (IsOpen || m_isOpening) return;
+ /// A task that represents the asynchronous action.
+ public async Task OpenAsync()
+ {
+ lock (m_lockObject)
+ {
+ if (IsOpen || m_isOpening) return;
m_isOpening = true;
- }
- m_cts = new CancellationTokenSource();
- m_stream = await OpenStreamAsync();
- StartParser(m_cts.Token);
- _lastMultiMessage = null;
+ }
+ m_cts = new CancellationTokenSource();
+ m_stream = await OpenStreamAsync();
+ StartParser(m_cts.Token);
+ _lastMultiMessage = null;
lock (m_lockObject)
{
IsOpen = true;
@@ -64,32 +64,32 @@ namespace NmeaParser
}
}
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "_")]
- private void StartParser(CancellationToken token)
- {
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "_")]
+ private void StartParser(CancellationToken token)
+ {
System.Diagnostics.Debug.WriteLine("Starting parser...");
- m_ParserTask = Task.Run(async () =>
- {
- byte[] buffer = new byte[1024];
- while (!token.IsCancellationRequested)
- {
- int readCount = 0;
- try
- {
- readCount = await ReadAsync(buffer, 0, 1024, token).ConfigureAwait(false);
- }
- catch { }
- if (token.IsCancellationRequested)
- break;
- if (readCount > 0)
- {
- OnData(buffer, readCount);
- }
- await Task.Yield();
- }
- });
- }
-
+ m_ParserTask = Task.Run(async () =>
+ {
+ byte[] buffer = new byte[1024];
+ while (!token.IsCancellationRequested)
+ {
+ int readCount = 0;
+ try
+ {
+ readCount = await ReadAsync(buffer, 0, 1024, token).ConfigureAwait(false);
+ }
+ catch { }
+ if (token.IsCancellationRequested)
+ break;
+ if (readCount > 0)
+ {
+ OnData(buffer, readCount);
+ }
+ await Task.Yield();
+ }
+ });
+ }
+
///
/// Performs a read operation of the stream
///
@@ -97,13 +97,13 @@ namespace NmeaParser
/// The byte offset in buffer at which to begin writing data from the stream.
/// The maximum number of bytes to read.
/// The token to monitor for cancellation requests. The default value is System.Threading.CancellationToken.None.
- ///
- /// A task that represents the asynchronous read operation. The value of the TResult
- /// parameter contains the total number of bytes read into the buffer. The result
- /// value can be less than the number of bytes requested if the number of bytes currently
- /// available is less than the requested number, or it can be 0 (zero) if the end
- /// of the stream has been reached.
- ///
+ ///
+ /// A task that represents the asynchronous read operation. The value of the TResult
+ /// parameter contains the total number of bytes read into the buffer. The result
+ /// value can be less than the number of bytes requested if the number of bytes currently
+ /// available is less than the requested number, or it can be 0 (zero) if the end
+ /// of the stream has been reached.
+ ///
protected virtual Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (m_stream == null)
@@ -111,180 +111,182 @@ namespace NmeaParser
return m_stream.ReadAsync(buffer, 0, 1024, cancellationToken);
}
- ///
- /// Creates and opens the stream the NmeaDevice is working on top off.
- ///
- /// The opened data stream.
- ///
- protected abstract Task OpenStreamAsync();
-
- ///
- /// Closes the device.
- ///
- /// A task that represents the asynchronous action.
- public async Task CloseAsync()
- {
- if (m_cts != null)
- {
- if (m_cts != null)
- m_cts.Cancel();
- m_cts = null;
- }
+ ///
+ /// Creates and opens the stream the NmeaDevice is working on top off.
+ ///
+ /// The opened data stream.
+ ///
+ protected abstract Task OpenStreamAsync();
+
+ ///
+ /// Closes the device.
+ ///
+ /// A task that represents the asynchronous action.
+ public async Task CloseAsync()
+ {
+ if (m_cts != null)
+ {
+ if (m_cts != null)
+ m_cts.Cancel();
+ m_cts = null;
+ }
if (m_ParserTask != null)
- await m_ParserTask;
+ await m_ParserTask;
if (m_stream != null)
- await CloseStreamAsync(m_stream);
- _lastMultiMessage = null;
+ await CloseStreamAsync(m_stream);
+ _lastMultiMessage = null;
m_stream = null;
lock (m_lockObject)
{
m_isOpening = false;
IsOpen = false;
- }
- }
- ///
- /// Closes the stream the NmeaDevice is working on top off.
- ///
- /// The stream to be closed.
+ }
+ }
+ ///
+ /// Closes the stream the NmeaDevice is working on top off.
+ ///
+ /// The stream to be closed.
/// A task that represents the asynchronous action.
///
- protected abstract Task CloseStreamAsync(Stream stream);
-
- private void OnData(byte[] data, int count)
- {
- var nmea = System.Text.Encoding.UTF8.GetString(data, 0, count);
- List lines = new List();
- lock (m_lockObject)
- {
- m_message += nmea;
-
- var lineEnd = m_message.IndexOf("\n", StringComparison.Ordinal);
- while (lineEnd > -1)
- {
- string line = m_message.Substring(0, lineEnd).Trim();
- m_message = m_message.Substring(lineEnd + 1);
- if (!string.IsNullOrEmpty(line))
- lines.Add(line);
- lineEnd = m_message.IndexOf("\n", StringComparison.Ordinal);
- }
- }
- foreach(var line in lines)
- ProcessMessage(line);
+ protected abstract Task CloseStreamAsync(Stream stream);
+
+ private void OnData(byte[] data, int count)
+ {
+ var nmea = System.Text.Encoding.UTF8.GetString(data, 0, count);
+ List lines = new List();
+ lock (m_lockObject)
+ {
+ m_message += nmea;
+
+ var lineEnd = m_message.IndexOf("\n", StringComparison.Ordinal);
+ while (lineEnd > -1)
+ {
+ string line = m_message.Substring(0, lineEnd).Trim();
+ m_message = m_message.Substring(lineEnd + 1);
+ if (!string.IsNullOrEmpty(line))
+ lines.Add(line);
+ lineEnd = m_message.IndexOf("\n", StringComparison.Ordinal);
+ }
+ }
+ 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 = NmeaMessage.Parse(p, _lastMultiMessage);
+ private IMultiSentenceMessage? _lastMultiMessage;
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="Must silently handle invalid/corrupt input")]
+ private void ProcessMessage(string p)
+ {
+ try
+ {
+ if (p.Length == 0 || p[0] != '$')
+ return;
+ var msg = 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 { }
+ if (msg != null)
+ OnMessageReceived(msg);
+ }
+ catch { }
}
private void OnMessageReceived(NmeaMessage msg)
- {
- if (msg == null)
- return;
+ {
+ if (msg == null)
+ return;
MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg));
- }
-
- //private readonly Dictionary> MultiPartMessageCache = new Dictionary>();
-
- ///
- /// Occurs when an NMEA message is received.
- ///
- public event EventHandler? MessageReceived;
-
- ///
- /// Releases unmanaged and - optionally - managed resources.
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Releases unmanaged and - optionally - managed resources.
- ///
- /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
- protected virtual void Dispose(bool disposing)
- {
- if (m_stream != null)
- {
- if (m_cts != null)
- {
- m_cts.Cancel();
- m_cts = null;
- }
- CloseStreamAsync(m_stream);
- if (disposing && m_stream != null)
- m_stream.Dispose();
- m_stream = null;
- }
- }
-
- ///
- /// Gets a value indicating whether this device is open.
- ///
- ///
- /// true if this instance is open; otherwise, false.
- ///
- public bool IsOpen { get; private set; }
-
+ }
+
+ //private readonly Dictionary> MultiPartMessageCache = new Dictionary>();
+
+ ///
+ /// Occurs when an NMEA message is received.
+ ///
+ public event EventHandler? MessageReceived;
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (m_stream != null)
+ {
+ if (m_cts != null)
+ {
+ m_cts.Cancel();
+ m_cts = null;
+ }
+ CloseStreamAsync(m_stream);
+ if (disposing && m_stream != null)
+ m_stream.Dispose();
+ m_stream = null;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this device is open.
+ ///
+ ///
+ /// true if this instance is open; otherwise, false.
+ ///
+ public bool IsOpen { get; private set; }
+
///
/// Gets a value indicating whether this device supports writing
- ///
- ///
- public virtual bool CanWrite { get => false; }
-
+ ///
+ ///
+ public virtual bool CanWrite { get => false; }
+
///
/// Writes to the device stream. Useful for transmitting RTCM corrections to the device
/// Check the property before calling this method.
///
- /// The byte array that contains the data to write to the port.
- /// The zero-based byte offset in the buffer parameter at which to begin copying
- /// bytes to the port.
- /// The number of bytes to write.
- /// Task
- ///
+ /// The byte array that contains the data to write to the port.
+ /// The zero-based byte offset in the buffer parameter at which to begin copying
+ /// bytes to the port.
+ /// The number of bytes to write.
+ /// Task
+ ///
public virtual Task WriteAsync(byte[] buffer, int offset, int length)
{
throw new NotSupportedException();
- }
- }
-
- ///
- /// Event argument for the
- ///
- public sealed class NmeaMessageReceivedEventArgs : EventArgs
- {
+ }
+ }
+
+ ///
+ /// Event argument for the
+ ///
+ public sealed class NmeaMessageReceivedEventArgs : EventArgs
+ {
internal NmeaMessageReceivedEventArgs(NmeaMessage message)
- {
- Message = message;
- }
-
- ///
- /// Gets the nmea message.
- ///
- ///
- /// The nmea message.
- ///
+ {
+ Message = message;
+ }
+
+ ///
+ /// Gets the nmea message.
+ ///
+ ///
+ /// The nmea message.
+ ///
public NmeaMessage Message { get; }
- }
-}
+ }
+}