mirror of
https://github.com/dotMorten/NmeaParser.git
synced 2025-12-06 07:12:04 +01:00
Added support for writing to the devices - useful for transmitting DGPS corrections (For instance RTCM from NTRIP etc) to the device
This commit is contained in:
parent
3e26a65a7b
commit
4d55b6d5e5
|
|
@ -1,18 +1,18 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
#if NETFX_CORE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -23,7 +23,8 @@ using System.Threading.Tasks;
|
|||
using Windows.Networking.Sockets;
|
||||
using Windows.Devices.Bluetooth.Rfcomm;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using System.Threading;
|
||||
using Windows.Devices.Enumeration;
|
||||
#if WINDOWS_UWP
|
||||
using Windows.Networking.Proximity;
|
||||
#endif
|
||||
|
|
@ -39,16 +40,33 @@ namespace NmeaParser
|
|||
#if WINDOWS_UWP
|
||||
private Windows.Networking.Proximity.PeerInformation m_devicePeer;
|
||||
#endif
|
||||
private StreamSocket m_socket;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BluetoothDevice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="service">The RF Comm Device service.</param>
|
||||
public BluetoothDevice(Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService service)
|
||||
private StreamSocket m_socket;
|
||||
private bool m_disposeService;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of bluetooth devices that supports serial communication
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static async Task<IEnumerable<RfcommDeviceService>> GetBluetoothSerialDevicesAsync()
|
||||
{
|
||||
string serialDeviceType = RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort);
|
||||
var devices = await DeviceInformation.FindAllAsync(serialDeviceType);
|
||||
List<RfcommDeviceService> services = new List<RfcommDeviceService>();
|
||||
foreach(var d in devices)
|
||||
services.Add(await RfcommDeviceService.FromIdAsync(d.Id));
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BluetoothDevice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="service">The RF Comm Device service.</param>
|
||||
/// <param name="disposeService">Whether this devicee should also dispose the RfcommDeviceService provided when this device disposes.</param>
|
||||
public BluetoothDevice(RfcommDeviceService service, bool disposeService = false)
|
||||
{
|
||||
m_deviceService = service;
|
||||
}
|
||||
m_disposeService = disposeService;
|
||||
}
|
||||
|
||||
#if WINDOWS_UWP
|
||||
|
||||
|
|
@ -62,6 +80,16 @@ namespace NmeaParser
|
|||
}
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (m_disposeService && m_deviceService != null)
|
||||
m_deviceService.Dispose();
|
||||
m_deviceService = null;
|
||||
m_devicePeer = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the stream the NmeaDevice is working on top off.
|
||||
/// </summary>
|
||||
|
|
@ -69,6 +97,7 @@ namespace NmeaParser
|
|||
protected override async Task<System.IO.Stream> OpenStreamAsync()
|
||||
{
|
||||
var socket = new Windows.Networking.Sockets.StreamSocket();
|
||||
socket.Control.KeepAlive = true;
|
||||
#if WINDOWS_UWP
|
||||
if (m_devicePeer != null)
|
||||
{
|
||||
|
|
@ -80,7 +109,7 @@ namespace NmeaParser
|
|||
await socket.ConnectAsync(m_deviceService.ConnectionHostName, m_deviceService.ConnectionServiceName);
|
||||
}
|
||||
m_socket = socket;
|
||||
return socket.InputStream.AsStreamForRead();
|
||||
return null; //We're going to use WinRT buffers instead and will handle read/write, so no reason to return a stream
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -90,13 +119,52 @@ namespace NmeaParser
|
|||
/// <returns></returns>
|
||||
protected override Task CloseStreamAsync(System.IO.Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException("stream");
|
||||
stream.Dispose();
|
||||
if(m_socket == null)
|
||||
throw new InvalidOperationException("No connection to close");
|
||||
m_socket.Dispose();
|
||||
m_socket = null;
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
// Reading and writing to the Bluetooth serial connection at the same time seems very unstable in UWP,
|
||||
// so we use a semaphore to ensure we don't read and write at the same time
|
||||
await semaphoreSlim.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var r = await m_socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)count, Windows.Storage.Streams.InputStreamOptions.None);
|
||||
return (int)r.Length;
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task WriteAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (m_socket == null)
|
||||
throw new InvalidOperationException("Device not open");
|
||||
// Reading and writing to the Bluetooth serial connection at the same time seems very unstable in UWP,
|
||||
// so we use a semaphore to ensure we don't read and write at the same time
|
||||
await semaphoreSlim.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await m_socket.OutputStream.WriteAsync(buffer.AsBuffer(offset, length)).AsTask().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -20,6 +20,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace NmeaParser
|
||||
{
|
||||
|
|
@ -40,6 +41,8 @@ namespace NmeaParser
|
|||
protected NmeaDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool isOpening;
|
||||
/// <summary>
|
||||
/// Opens the device connection.
|
||||
/// </summary>
|
||||
|
|
@ -48,13 +51,18 @@ namespace NmeaParser
|
|||
{
|
||||
lock (m_lockObject)
|
||||
{
|
||||
if (IsOpen) return;
|
||||
IsOpen = true;
|
||||
if (IsOpen || isOpening) return;
|
||||
isOpening = true;
|
||||
}
|
||||
m_cts = new System.Threading.CancellationTokenSource();
|
||||
m_stream = await OpenStreamAsync();
|
||||
StartParser();
|
||||
MultiPartMessageCache.Clear();
|
||||
lock (m_lockObject)
|
||||
{
|
||||
IsOpen = true;
|
||||
isOpening = false;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "_")]
|
||||
|
|
@ -64,14 +72,13 @@ namespace NmeaParser
|
|||
System.Diagnostics.Debug.WriteLine("Starting parser...");
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
var stream = m_stream;
|
||||
byte[] buffer = new byte[1024];
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
int readCount = 0;
|
||||
try
|
||||
{
|
||||
readCount = await stream.ReadAsync(buffer, 0, 1024, token).ConfigureAwait(false);
|
||||
readCount = await ReadAsync(buffer, 0, 1024, token).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
if (token.IsCancellationRequested)
|
||||
|
|
@ -87,11 +94,33 @@ namespace NmeaParser
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a read operation of the stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write the data into.</param>
|
||||
/// <param name="offset">The byte offset in buffer at which to begin writing data from the stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is System.Threading.CancellationToken.None.</param>
|
||||
/// <returns>
|
||||
/// 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.
|
||||
/// </returns>
|
||||
protected virtual Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
if (m_stream == null)
|
||||
return Task.FromResult(0);
|
||||
return m_stream.ReadAsync(buffer, 0, 1024, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the stream the NmeaDevice is working on top off.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract Task<Stream> OpenStreamAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Closes the device.
|
||||
/// </summary>
|
||||
|
|
@ -110,7 +139,10 @@ namespace NmeaParser
|
|||
MultiPartMessageCache.Clear();
|
||||
m_stream = null;
|
||||
lock (m_lockObject)
|
||||
{
|
||||
isOpening = false;
|
||||
IsOpen = false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Closes the stream the NmeaDevice is working on top off.
|
||||
|
|
@ -235,6 +267,27 @@ namespace NmeaParser
|
|||
/// <c>true</c> if this instance is open; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsOpen { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this device supports writing
|
||||
/// </summary>
|
||||
/// <seealso cref="WriteAsync(byte[], int, int)"/>
|
||||
public virtual bool CanWrite { get => false; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes to the device stream. Useful for transmitting RTCM corrections to the device
|
||||
/// Check the <see cref="CanWrite"/> property before calling this method.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte array that contains the data to write to the port.</param>
|
||||
/// <param name="offset">The zero-based byte offset in the buffer parameter at which to begin copying
|
||||
/// bytes to the port.</param>
|
||||
/// <param name="length">The number of bytes to write.</param>
|
||||
/// <returns>Task</returns>
|
||||
/// <seealso cref="CanWrite"/>
|
||||
public virtual Task WriteAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<Description>An NMEA stream parser for serial port, bluetooth and file-based nmea simulation.</Description>
|
||||
<PackageTags>nmea winrt wpf uwp xamarin gps serialport bluetooth</PackageTags>
|
||||
<PackageId>SharpGIS.NmeaParser</PackageId>
|
||||
<Version>1.10.1</Version>
|
||||
<Version>1.11</Version>
|
||||
<PackageLicenseUrl>http://opensource.org/licenses/ms-pl.html</PackageLicenseUrl>
|
||||
<PackageProjectUrl>https://github.com/dotMorten/NmeaParser</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/dotMorten/NmeaParser</RepositoryUrl>
|
||||
|
|
|
|||
|
|
@ -81,10 +81,24 @@ namespace NmeaParser
|
|||
/// <param name="offset">The zero-based byte offset in the buffer parameter at which to begin copying
|
||||
/// bytes to the port.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
[Obsolete("Use WriteAsync")]
|
||||
public void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
m_port.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
m_port.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (!m_port.IsOpen)
|
||||
throw new InvalidOperationException("Device not open");
|
||||
|
||||
m_port.Write(buffer, offset, length);
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
#if WINDOWS_UWP
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -21,7 +21,8 @@ using System.Text;
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Devices.SerialCommunication;
|
||||
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
|
||||
namespace NmeaParser
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -80,10 +81,23 @@ namespace NmeaParser
|
|||
/// <param name="offset">The zero-based byte offset in the buffer parameter at which to begin copying
|
||||
/// bytes to the port.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
[Obsolete("Use WriteAsync")]
|
||||
public void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
m_port.OutputStream.AsStreamForWrite().Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (m_port == null)
|
||||
throw new InvalidOperationException("Device not open");
|
||||
|
||||
return m_port.OutputStream.WriteAsync(buffer.AsBuffer(offset, length)).AsTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -66,6 +66,18 @@ namespace NmeaParser
|
|||
if (m_stream != null)
|
||||
m_stream.Dispose();
|
||||
m_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite => m_stream?.CanWrite == true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (m_stream == null)
|
||||
throw new InvalidOperationException("Device not open");
|
||||
return m_stream.WriteAsync(buffer, offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue