mirror of
https://github.com/dotMorten/NmeaParser.git
synced 2026-01-13 04:00:25 +01:00
Add early beginnings of NTRIP tab
This commit is contained in:
parent
9db4db4212
commit
b035adda26
|
|
@ -75,7 +75,7 @@
|
|||
<TextBlock Text="Serial port:" />
|
||||
<ComboBox x:Name="serialPorts" />
|
||||
<TextBlock Text="Baud rate:" />
|
||||
<ComboBox x:Name="baudRates" SelectedIndex="3">
|
||||
<ComboBox x:Name="baudRates" SelectedIndex="5">
|
||||
<ComboBoxItem>1200</ComboBoxItem>
|
||||
<ComboBoxItem>2400</ComboBoxItem>
|
||||
<ComboBoxItem>4800</ComboBoxItem>
|
||||
|
|
@ -91,6 +91,9 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="NTRIP">
|
||||
<local:NtripView />
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace SampleApp.WinDesktop
|
|||
public partial class MainWindow : Window
|
||||
{
|
||||
private Queue<string> messages = new Queue<string>(101);
|
||||
private NmeaParser.NmeaDevice currentDevice;
|
||||
public static NmeaParser.NmeaDevice currentDevice;
|
||||
//Dialog for browsing to nmea log files
|
||||
private Microsoft.Win32.OpenFileDialog nmeaOpenFileDialog = new Microsoft.Win32.OpenFileDialog()
|
||||
{
|
||||
|
|
|
|||
23
src/SampleApp.WinDesktop/Ntrip/Carrier.cs
Normal file
23
src/SampleApp.WinDesktop/Ntrip/Carrier.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// *******************************************************************************
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * 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.
|
||||
// ******************************************************************************
|
||||
|
||||
namespace NmeaParser.Gnss.Ntrip
|
||||
{
|
||||
public enum Carrier : int
|
||||
{
|
||||
No = 0,
|
||||
L1 = 1,
|
||||
L1L2 = 2
|
||||
}
|
||||
}
|
||||
59
src/SampleApp.WinDesktop/Ntrip/Caster.cs
Normal file
59
src/SampleApp.WinDesktop/Ntrip/Caster.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// *******************************************************************************
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * 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.
|
||||
// ******************************************************************************
|
||||
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
|
||||
namespace NmeaParser.Gnss.Ntrip
|
||||
{
|
||||
public class Caster : NtripSource
|
||||
{
|
||||
internal Caster (string[] d)
|
||||
{
|
||||
var a = d[1].Split(':');
|
||||
Address = IPAddress.Parse(a[0]);
|
||||
Port = int.Parse(a[1]);
|
||||
Identifier = d[3];
|
||||
Operator = d[4];
|
||||
SupportsNmea = d[5] == "1";
|
||||
CountryCode = d[6];
|
||||
Latitude = double.Parse(d[7], CultureInfo.InvariantCulture);
|
||||
Longitude = double.Parse(d[8], CultureInfo.InvariantCulture);
|
||||
FallbackAddress = IPAddress.Parse(d[9]);
|
||||
}
|
||||
|
||||
public Caster(IPAddress address, int port, string identifier, string _operator, bool supportsNmea, string countryCode, double latitude, double longitude, IPAddress fallbackkAddress)
|
||||
{
|
||||
Address = address;
|
||||
Port = port;
|
||||
Identifier = identifier;
|
||||
Operator = _operator;
|
||||
SupportsNmea = supportsNmea;
|
||||
CountryCode = countryCode;
|
||||
Latitude = latitude;
|
||||
Longitude = longitude;
|
||||
FallbackAddress = fallbackkAddress;
|
||||
}
|
||||
|
||||
public IPAddress Address { get; }
|
||||
public int Port { get; }
|
||||
public string Identifier { get; }
|
||||
public string Operator { get; }
|
||||
public bool SupportsNmea { get; }
|
||||
public string CountryCode { get; }
|
||||
public double Latitude { get; }
|
||||
public double Longitude { get; }
|
||||
public IPAddress FallbackAddress { get; }
|
||||
}
|
||||
}
|
||||
140
src/SampleApp.WinDesktop/Ntrip/Client.cs
Normal file
140
src/SampleApp.WinDesktop/Ntrip/Client.cs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
// *******************************************************************************
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * 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.
|
||||
// ******************************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NmeaParser.Gnss.Ntrip
|
||||
{
|
||||
public class Client : IDisposable
|
||||
{
|
||||
private readonly string _host;
|
||||
private readonly int _port;
|
||||
private string? _auth;
|
||||
private Socket? sckt;
|
||||
private bool connected;
|
||||
private Task? runningTask;
|
||||
|
||||
public Client(string host, int port)
|
||||
{
|
||||
_host = host;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
public Client(string host, int port, string username, string password) : this(host, port)
|
||||
{
|
||||
_auth = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(username + ":" + password));
|
||||
}
|
||||
|
||||
public IEnumerable<NtripSource> GetSourceTable()
|
||||
{
|
||||
string data = "";
|
||||
byte[] buffer = new byte[1024];
|
||||
using (var sck = Request(""))
|
||||
{
|
||||
int count;
|
||||
while ((count = sck.Receive(buffer)) > 0)
|
||||
{
|
||||
data += System.Text.Encoding.UTF8.GetString(buffer, 0, count);
|
||||
}
|
||||
}
|
||||
var lines = data.Split('\n');
|
||||
List<NtripSource> sources = new List<NtripSource>();
|
||||
foreach (var item in lines)
|
||||
{
|
||||
var d = item.Split(';');
|
||||
if (d.Length == 0) continue;
|
||||
if (d[0] == "ENDSOURCETABLE")
|
||||
break;
|
||||
if (d[0] == "CAS")
|
||||
{
|
||||
sources.Add(new Caster(d));
|
||||
}
|
||||
else if (d[0] == "STR")
|
||||
{
|
||||
sources.Add(new NtripStream(d));
|
||||
}
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
private Socket Request(string path)
|
||||
{
|
||||
var sckt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
sckt.Blocking = true;
|
||||
sckt.Connect(_host, _port);
|
||||
|
||||
string msg = $"GET /{path} HTTP/1.1\r\n";
|
||||
msg += "User-Agent: NTRIP ntripclient\r\n";
|
||||
if (_auth != null)
|
||||
{
|
||||
msg += "Authorization: Basic " + _auth + "\r\n";
|
||||
}
|
||||
msg += "Accept: */*\r\nConnection: close\r\n";
|
||||
msg += "\r\n";
|
||||
|
||||
byte[] data = System.Text.Encoding.ASCII.GetBytes(msg);
|
||||
sckt.Send(data);
|
||||
return sckt;
|
||||
}
|
||||
|
||||
public void Connect(string strName)
|
||||
{
|
||||
if (sckt != null) throw new Exception("Connection already open");
|
||||
sckt = Request(strName);
|
||||
connected = true;
|
||||
runningTask = Task.Run(ReceiveThread);
|
||||
}
|
||||
|
||||
private async Task ReceiveThread()
|
||||
{
|
||||
byte[] buffer = new byte[65536];
|
||||
|
||||
while (connected && sckt != null)
|
||||
{
|
||||
int count = sckt.Receive(buffer);
|
||||
if (count > 0)
|
||||
{
|
||||
DataReceived?.Invoke(this, buffer.Take(count).ToArray());
|
||||
}
|
||||
await Task.Delay(10);
|
||||
}
|
||||
sckt?.Shutdown(SocketShutdown.Both);
|
||||
sckt?.Dispose();
|
||||
sckt = null;
|
||||
}
|
||||
|
||||
public Task CloseAsync()
|
||||
{
|
||||
if (runningTask != null)
|
||||
{
|
||||
connected = false;
|
||||
var t = runningTask;
|
||||
runningTask = null;
|
||||
return t;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ = CloseAsync();
|
||||
}
|
||||
|
||||
public event EventHandler<byte[]>? DataReceived;
|
||||
}
|
||||
}
|
||||
23
src/SampleApp.WinDesktop/Ntrip/NtripSource.cs
Normal file
23
src/SampleApp.WinDesktop/Ntrip/NtripSource.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// *******************************************************************************
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * 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.
|
||||
// ******************************************************************************
|
||||
|
||||
namespace NmeaParser.Gnss.Ntrip
|
||||
{
|
||||
public class NtripSource
|
||||
{
|
||||
protected NtripSource()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/SampleApp.WinDesktop/Ntrip/NtripStream.cs
Normal file
52
src/SampleApp.WinDesktop/Ntrip/NtripStream.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// *******************************************************************************
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * 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.
|
||||
// ******************************************************************************
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace NmeaParser.Gnss.Ntrip
|
||||
{
|
||||
public class NtripStream : NtripSource
|
||||
{
|
||||
internal NtripStream(string[] d)
|
||||
{
|
||||
Mountpoint = d[1];
|
||||
Identifier = d[2];
|
||||
Format = d[3];
|
||||
FormatDetails = d[4];
|
||||
if (int.TryParse(d[5], out int carrier))
|
||||
Carrier = (Carrier)carrier;
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
Network = d[7];
|
||||
CountryCode = d[8];
|
||||
Latitude = double.Parse(d[9], CultureInfo.InvariantCulture);
|
||||
Longitude = double.Parse(d[10], CultureInfo.InvariantCulture);
|
||||
SupportsNmea = d[11] == "1";
|
||||
}
|
||||
|
||||
public string Mountpoint { get; }
|
||||
public string Identifier { get; }
|
||||
public string Format { get; }
|
||||
public string FormatDetails { get; }
|
||||
public Carrier Carrier { get; }
|
||||
public string Network { get; }
|
||||
public string CountryCode { get; }
|
||||
public double Latitude { get; }
|
||||
public double Longitude { get; }
|
||||
public bool SupportsNmea { get; }
|
||||
}
|
||||
}
|
||||
74
src/SampleApp.WinDesktop/NtripView.xaml
Normal file
74
src/SampleApp.WinDesktop/NtripView.xaml
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<UserControl x:Class="SampleApp.WinDesktop.NtripView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SampleApp.WinDesktop"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="80" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="Server: " />
|
||||
<TextBox Text="esricaster.esri.com" Grid.Column="1" x:Name="host" />
|
||||
<TextBlock Text="Port: " Grid.Row="1" />
|
||||
<TextBox Text="2101" Grid.Row="1" Grid.Column="1" x:Name="port" />
|
||||
<TextBlock Text="Username: " Grid.Row="2" />
|
||||
<TextBox Text="" Grid.Row="2" Grid.Column="1" x:Name="username" />
|
||||
<TextBlock Text="Password: " Grid.Row="3" />
|
||||
<PasswordBox Grid.Row="3" Grid.Column="1" x:Name="password" />
|
||||
<Button Content="Get Available Streams" Grid.Row="4" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="5" Click="Button_Click"/>
|
||||
<TextBlock Text="Available streams:" Grid.Row="5" Grid.ColumnSpan="2" />
|
||||
<ListView x:Name="sourceList" Grid.Row="6" >
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Identifier}" FontWeight="Bold" />
|
||||
<TextBlock Text=" (" />
|
||||
<TextBlock Text="{Binding CountryCode}" FontWeight="Bold" />
|
||||
<TextBlock Text=")" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Format}" />
|
||||
<TextBlock Text=" - " />
|
||||
<TextBlock Text="{Binding Carrier}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<Grid Grid.Row="6" Grid.Column="1" DataContext="{Binding SelectedItem, ElementName=sourceList}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Identifier}" FontWeight="Bold" FontSize="14" />
|
||||
<TextBlock Text="{Binding CountryCode, StringFormat='Country code: {0}'}" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Location: " />
|
||||
<TextBlock Text="{Binding Latitude}" />
|
||||
<TextBlock Text="," />
|
||||
<TextBlock Text="{Binding Longitude}" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding Carrier, StringFormat='Carrier: {0}'}" />
|
||||
<TextBlock Text="{Binding Format, StringFormat='Format: {0}'}" />
|
||||
<TextBlock Text="{Binding FormatDetails, StringFormat='Format details: {0}'}" />
|
||||
<TextBlock Text="{Binding Mountpoint, StringFormat='Mount point: {0}'}" />
|
||||
<TextBlock Text="{Binding Network, StringFormat='Network: {0}'}" />
|
||||
<TextBlock Text="{Binding SupportsNmea, StringFormat='Supports NMEA: {0}'}" />
|
||||
<Button Content="Connect" Click="Connect_Click" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock Text="Not connected" x:Name="ntripstatus" Grid.Column="1" Grid.Row="9" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
102
src/SampleApp.WinDesktop/NtripView.xaml.cs
Normal file
102
src/SampleApp.WinDesktop/NtripView.xaml.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using NmeaParser.Gnss.Ntrip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace SampleApp.WinDesktop
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for NtripView.xaml
|
||||
/// </summary>
|
||||
public partial class NtripView : UserControl
|
||||
{
|
||||
public NtripView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
NmeaParser.Gnss.Ntrip.Client client;
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
sourceList.ItemsSource = null;
|
||||
if (!int.TryParse(port.Text, out int portNumber))
|
||||
{
|
||||
MessageBox.Show("Invalid port number");
|
||||
return;
|
||||
}
|
||||
client = new NmeaParser.Gnss.Ntrip.Client(host.Text, portNumber, username.Text, password.Password);
|
||||
client.DataReceived += Client_DataReceived;
|
||||
List<NtripStream> sources;
|
||||
try
|
||||
{
|
||||
sources = client.GetSourceTable().OfType<NtripStream>().ToList();
|
||||
}
|
||||
catch(System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("Failed to connect: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
sourceList.ItemsSource = sources.OrderBy(s=>s.CountryCode);
|
||||
}
|
||||
Func<Task> stop;
|
||||
private async void Connect_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var stream = ((Button)sender).DataContext as NtripStream;
|
||||
if (stream == null)
|
||||
return;
|
||||
if (stop != null)
|
||||
{
|
||||
await stop();
|
||||
}
|
||||
counter = 0;
|
||||
client.Connect(stream.Mountpoint);
|
||||
stop = client.CloseAsync;
|
||||
ntripstatus.Text = $"Connected";
|
||||
}
|
||||
|
||||
System.Threading.Tasks.Task writingTask;
|
||||
object writeLock = new object();
|
||||
long counter = 0;
|
||||
private async void Client_DataReceived(object sender, byte[] rtcm)
|
||||
{
|
||||
var device = MainWindow.currentDevice;
|
||||
if (device != null && device.CanWrite)
|
||||
{
|
||||
try
|
||||
{
|
||||
//lock (writeLock)
|
||||
{
|
||||
await device.WriteAsync(rtcm, 0, rtcm.Length);
|
||||
counter += rtcm.Length;
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ntripstatus.Text = $"Transmitted {counter} bytes";
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
//ParseData(rtcm);
|
||||
}
|
||||
Queue<byte> rtcmData = new Queue<byte>();
|
||||
private void ParseData(byte[] rtcm)
|
||||
{
|
||||
foreach (var b in rtcm)
|
||||
rtcmData.Enqueue(b);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue