From 897908bf138e92ec98d4b494c33608a1b3fd37f6 Mon Sep 17 00:00:00 2001 From: Jonas Arnold Date: Thu, 11 May 2023 15:50:55 +0200 Subject: [PATCH] changed to using only one udp client, enables to reply from the same port that the message was received on, implemented LongInstanceIdentifier to show full identifier in the UI ToolTip --- MultiTerm.Core/ViewModel/TerminalViewModel.cs | 8 +++ MultiTerm.Protocols/CommunicationProtocol.cs | 1 + .../Helpers/NetworkProtocolHelpers.cs | 5 +- MultiTerm.Protocols/ICommunicationProtocol.cs | 7 ++ MultiTerm.Protocols/Model/ExtendedByte.cs | 3 +- MultiTerm.Protocols/Serial/SerialProtocol.cs | 2 + MultiTerm.Protocols/Tcp/TcpClientProtocol.cs | 15 +---- MultiTerm.Protocols/Udp/UdpProtocol.cs | 67 +++++++------------ MultiTerm.Protocols/UsbHid/UsbHidProtocol.cs | 2 + MultiTerm.Wpf/View/ShellView.xaml | 4 +- 10 files changed, 52 insertions(+), 62 deletions(-) diff --git a/MultiTerm.Core/ViewModel/TerminalViewModel.cs b/MultiTerm.Core/ViewModel/TerminalViewModel.cs index 74cfb1e..2bf7392 100644 --- a/MultiTerm.Core/ViewModel/TerminalViewModel.cs +++ b/MultiTerm.Core/ViewModel/TerminalViewModel.cs @@ -95,6 +95,13 @@ public abstract partial class TerminalViewModel : ObservableObject, ITerminalVie [ObservableProperty] private ProtocolConnectionState communicationProtocolConnectionState; + /// + /// as ObservableProperty. + /// Required since does not implement . + /// + [ObservableProperty] + private string communicationProtocolLongIdentifier = string.Empty; + #endregion @@ -167,6 +174,7 @@ public abstract partial class TerminalViewModel : ObservableObject, ITerminalVie { // update internal state this.CommunicationProtocolConnectionState = e; + this.CommunicationProtocolLongIdentifier = this.CommunicationProtocol.LongInstanceIdentifier; // If ViewModel still displays connected after unintentional disconnect => force to disconnected state // allows user to change settings diff --git a/MultiTerm.Protocols/CommunicationProtocol.cs b/MultiTerm.Protocols/CommunicationProtocol.cs index 1ddf17a..a4b1c9b 100644 --- a/MultiTerm.Protocols/CommunicationProtocol.cs +++ b/MultiTerm.Protocols/CommunicationProtocol.cs @@ -24,6 +24,7 @@ public abstract class CommunicationProtocol : ICommunicationProtocol public abstract ProtocolType ProtocolType { get; } public abstract string InstanceIdentifier { get; protected set; } + public abstract string LongInstanceIdentifier { get; protected set; } private ProtocolConnectionState state = ProtocolConnectionState.NotConnected; public ProtocolConnectionState State diff --git a/MultiTerm.Protocols/Helpers/NetworkProtocolHelpers.cs b/MultiTerm.Protocols/Helpers/NetworkProtocolHelpers.cs index 8adecad..f58d605 100644 --- a/MultiTerm.Protocols/Helpers/NetworkProtocolHelpers.cs +++ b/MultiTerm.Protocols/Helpers/NetworkProtocolHelpers.cs @@ -6,7 +6,7 @@ internal static class NetworkProtocolHelpers { /// /// Returns the hostname of the but limited to amount of characters. - /// If the hostname is longer than , '...' will be prefixed. The resulting string may also be +3 characters long. + /// If the hostname is longer than , '...' will be postfixed. The resulting string may also be +3 characters long. /// If the hostname cannot be read, the result will be "invalid". /// /// settings object containing hostname @@ -15,11 +15,10 @@ internal static class NetworkProtocolHelpers public static string GetLimitedLengthHostname(INetworkProtocolSettings settingsObject, int maxLength = 20) { string limitedHostname = "invalid"; - string prefix = "..."; if (settingsObject.Hostname != null && settingsObject.Hostname.Length >= maxLength) { - limitedHostname = $"{prefix}{settingsObject.Hostname.Substring(settingsObject.Hostname.Length - maxLength, maxLength)}"; + limitedHostname = $"{settingsObject.Hostname.Substring(maxLength)}..."; } else if (settingsObject.Hostname != null) { diff --git a/MultiTerm.Protocols/ICommunicationProtocol.cs b/MultiTerm.Protocols/ICommunicationProtocol.cs index 8753739..20d2c1f 100644 --- a/MultiTerm.Protocols/ICommunicationProtocol.cs +++ b/MultiTerm.Protocols/ICommunicationProtocol.cs @@ -14,9 +14,16 @@ public interface ICommunicationProtocol /// /// Short identifier string that allows the user to distinguish different instances. + /// e.g. Cut off IPv6 after first 15 characters. /// string InstanceIdentifier { get; } + /// + /// Long identifier string that provides full information about the instance. + /// e.g. full IPv6. + /// + string LongInstanceIdentifier { get; } + /// /// New data received from connected device. /// diff --git a/MultiTerm.Protocols/Model/ExtendedByte.cs b/MultiTerm.Protocols/Model/ExtendedByte.cs index 90b2f25..b207c37 100644 --- a/MultiTerm.Protocols/Model/ExtendedByte.cs +++ b/MultiTerm.Protocols/Model/ExtendedByte.cs @@ -1,5 +1,4 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System.Text; +using System.Text; namespace MultiTerm.Protocols.Model; diff --git a/MultiTerm.Protocols/Serial/SerialProtocol.cs b/MultiTerm.Protocols/Serial/SerialProtocol.cs index 48674bb..90186bf 100644 --- a/MultiTerm.Protocols/Serial/SerialProtocol.cs +++ b/MultiTerm.Protocols/Serial/SerialProtocol.cs @@ -12,6 +12,7 @@ public class SerialProtocol : CommunicationProtocol public override ProtocolType ProtocolType => ProtocolType.Serial; public override string InstanceIdentifier { get; protected set; } = string.Empty; + public override string LongInstanceIdentifier { get; protected set; } = string.Empty; private ISerialProtocolSettings? serialSettings; private SerialPortStream serialPort = new(); @@ -34,6 +35,7 @@ public class SerialProtocol : CommunicationProtocol // update identifier this.InstanceIdentifier = this.serialSettings.PortName; + this.LongInstanceIdentifier = this.serialSettings.PortName; // create new serial port this.serialPort = new() diff --git a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs index 7378448..dd3d7ec 100644 --- a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs +++ b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs @@ -15,6 +15,7 @@ public class TcpClientProtocol : CommunicationProtocol public override Types.ProtocolType ProtocolType => Types.ProtocolType.Tcp_Client; public override string InstanceIdentifier { get; protected set; } = string.Empty; + public override string LongInstanceIdentifier { get; protected set; } = string.Empty; private INetworkProtocolSettings? settings; private TcpClient? client; @@ -41,6 +42,7 @@ public class TcpClientProtocol : CommunicationProtocol // update identifier this.InstanceIdentifier = NetworkProtocolHelpers.GetLimitedLengthHostname(this.settings); + this.LongInstanceIdentifier = this.settings.Hostname; // check if client is null if (this.client != null) @@ -48,19 +50,6 @@ public class TcpClientProtocol : CommunicationProtocol throw new Exception($"The TCP client was not null when {nameof(InternalConnect)} was called."); } - ///* resolve hostname */ - //IPAddress ipAddress; - //try - //{ - // IPHostEntry ipHostInfo = Dns.GetHostEntry(this.settings.Hostname); - // ipAddress = ipHostInfo.AddressList[0]; - //} - //catch (Exception ex) - //{ - // this.logger.LogException(ex, $"'{nameof(InternalConnect)}()' Failed to resolve hostname '{this.settings.Hostname}'.", nameof(TcpClientProtocol)); - // return false; - //} - /* create client */ //var ipEndPoint = new IPEndPoint(ipAddress, this.settings.Port); this.client = new(AddressFamily.Unknown); // creates dual stack tcp client (ipv4 and ipv6) diff --git a/MultiTerm.Protocols/Udp/UdpProtocol.cs b/MultiTerm.Protocols/Udp/UdpProtocol.cs index 353c35c..bdf3260 100644 --- a/MultiTerm.Protocols/Udp/UdpProtocol.cs +++ b/MultiTerm.Protocols/Udp/UdpProtocol.cs @@ -15,10 +15,10 @@ public class UdpProtocol : CommunicationProtocol public override Types.ProtocolType ProtocolType => Types.ProtocolType.Udp; public override string InstanceIdentifier { get; protected set; } = string.Empty; + public override string LongInstanceIdentifier { get; protected set; } = string.Empty; private INetworkProtocolSettings? settings; - private UdpClient? receivingUdpClient; - private UdpClient? sendingUdpClient; + private UdpClient? udpClient; private const int ReadTimeoutMs = 100; // milliseconds until the read operation timeouts private const int WriteTimeoutMs = 100; // milliseconds until the write operation timeouts @@ -38,68 +38,49 @@ public class UdpProtocol : CommunicationProtocol // store locally this.settings = networkSettings; - // update identifier + // update identifiers this.InstanceIdentifier = NetworkProtocolHelpers.GetLimitedLengthHostname(this.settings); + this.LongInstanceIdentifier = this.settings.Hostname; - // check if clients are null - if(this.receivingUdpClient != null || this.sendingUdpClient != null) + // check if client is null + if(this.udpClient != null) { - throw new Exception($"A UDP client was not null when {nameof(InternalConnect)} was called: " + - $"{nameof(receivingUdpClient)} isnull={this.receivingUdpClient == null}," + - $"{nameof(sendingUdpClient)} isnull={this.sendingUdpClient == null}"); + throw new Exception($"UDP client was not null when {nameof(InternalConnect)} was called: " + + $"{nameof(udpClient)} isnull={this.udpClient == null},"); } - /* create udp clients */ - // try opening receiving udp socket + /* create udp client */ + // try opening udp socket try { - this.receivingUdpClient = new UdpClient(this.settings.Port); + // opens an udp client on this pc and binds it to the port provided + this.udpClient = new UdpClient(this.settings.Port); + // define default remote host and port + this.udpClient.Connect(this.settings.Hostname!, this.settings.Port); } catch (Exception ex) { - this.logger.LogException(ex, $"'{nameof(InternalConnect)}()' Opening Receiving UDP socket failed:", nameof(UdpProtocol)); - // rollback - this.InternalDisconnect(); - return false; - } - - - // try opening sending udp socket - try - { - this.sendingUdpClient = new UdpClient(); - this.sendingUdpClient.Connect(this.settings.Hostname!, this.settings.Port); - } - catch (Exception ex) - { - this.logger.LogException(ex, $"'{nameof(InternalConnect)}()' Opening Sending UDP Socket failed:", nameof(UdpProtocol)); + this.logger.LogException(ex, $"'{nameof(InternalConnect)}()' Opening UDP socket failed:", nameof(UdpProtocol)); // rollback this.InternalDisconnect(); return false; } // set static settings - this.receivingUdpClient.Client.ReceiveTimeout = ReadTimeoutMs; - this.sendingUdpClient.Client.SendTimeout = WriteTimeoutMs; + this.udpClient.Client.ReceiveTimeout = ReadTimeoutMs; + this.udpClient.Client.SendTimeout = WriteTimeoutMs; return true; } protected override void InternalDisconnect() { - // close receiving udp client - if(this.receivingUdpClient != null) - { - this.receivingUdpClient?.Close(); - this.receivingUdpClient?.Dispose(); - this.receivingUdpClient = null; - } - // close sending udp client - if (this.sendingUdpClient != null) + // close udp client + if(this.udpClient != null) { - this.sendingUdpClient?.Close(); - this.sendingUdpClient?.Dispose(); - this.sendingUdpClient = null; + this.udpClient?.Close(); + this.udpClient?.Dispose(); + this.udpClient = null; } // reset settings this.settings = null; @@ -117,7 +98,7 @@ public class UdpProtocol : CommunicationProtocol try { // will throw ObjectDisposedException if null - receivedBytes = this.receivingUdpClient!.Receive(ref remoteEndPoint); + receivedBytes = this.udpClient!.Receive(ref remoteEndPoint); } catch (OperationCanceledException) // intentionally cancelled => just break { @@ -171,7 +152,7 @@ public class UdpProtocol : CommunicationProtocol try { // will throw ObjectDisposedException if null - this.sendingUdpClient!.Send(bytes, bytes.Length); + this.udpClient!.Send(bytes, bytes.Length); } catch (ObjectDisposedException objex) { diff --git a/MultiTerm.Protocols/UsbHid/UsbHidProtocol.cs b/MultiTerm.Protocols/UsbHid/UsbHidProtocol.cs index 8c576dc..b98db9f 100644 --- a/MultiTerm.Protocols/UsbHid/UsbHidProtocol.cs +++ b/MultiTerm.Protocols/UsbHid/UsbHidProtocol.cs @@ -12,6 +12,7 @@ public class UsbHidProtocol : CommunicationProtocol public override ProtocolType ProtocolType => ProtocolType.UsbHid; public override string InstanceIdentifier { get; protected set; } = string.Empty; + public override string LongInstanceIdentifier { get; protected set; } = string.Empty; private const uint ReadTimeoutMs = 100; // timeout after which a new read cycle is started private const uint MaxBytesPerReport = 100; // maximum number of bytes to send per report, including report ID and pther prefixes @@ -37,6 +38,7 @@ public class UsbHidProtocol : CommunicationProtocol // update Identifier this.InstanceIdentifier = $"V:{this.usbHidSettings.VendorId:X4} P:{this.usbHidSettings.ProductId:X4}"; + this.LongInstanceIdentifier = $"Vendor ID:{this.usbHidSettings.VendorId:X4} Product ID:{this.usbHidSettings.ProductId:X4}"; // try create usb hid device try diff --git a/MultiTerm.Wpf/View/ShellView.xaml b/MultiTerm.Wpf/View/ShellView.xaml index 9063ad0..53ddcd7 100644 --- a/MultiTerm.Wpf/View/ShellView.xaml +++ b/MultiTerm.Wpf/View/ShellView.xaml @@ -163,7 +163,9 @@ Source="{Binding Path=ProtocolType, Converter={StaticResource ProtocolTypeIconConverter}}" ToolTip="{Binding Path=ProtocolType,Converter={StaticResource EnumDescriptionConverter}}" ToolTipService.InitialShowDelay="200"/> - +