From 6ed7c96ec71c8d074bcdc3c84da49a21461647c3 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 3 Nov 2025 10:53:21 -0600 Subject: [PATCH] fix: centralize debug printing into extension methods Stream debugging now uses CrestronConsole instead of debug methods, so that the debug statements will be printed regardless of console debug level. This also means that comm debug statements will NOT be in the Crestron Error log or in the files created by the logging system --- src/PepperDash.Core/ComTextHelper.cs | 43 ++ .../Comm/CommunicationStreamDebugging.cs | 56 +-- src/PepperDash.Core/Comm/GenericSshClient.cs | 17 +- .../Comm/GenericTcpIpClient.cs | 369 +++++++++--------- src/PepperDash.Core/Comm/GenericUdpServer.cs | 58 ++- .../Comm/StreamDebuggingExtensionMethods.cs | 69 ++++ .../Comm/eStreamDebuggingDataTypeSettings.cs | 24 ++ .../Comm/eStreamDebuggingSetting.cs | 28 ++ src/PepperDash.Core/CommunicationExtras.cs | 158 +++----- .../Comm and IR/CecPortController.cs | 47 ++- .../Comm and IR/ComPortController.cs | 32 +- .../SetDeviceStreamDebugRequestHandler.cs | 46 +-- 12 files changed, 493 insertions(+), 454 deletions(-) create mode 100644 src/PepperDash.Core/ComTextHelper.cs create mode 100644 src/PepperDash.Core/Comm/StreamDebuggingExtensionMethods.cs create mode 100644 src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs create mode 100644 src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs diff --git a/src/PepperDash.Core/ComTextHelper.cs b/src/PepperDash.Core/ComTextHelper.cs new file mode 100644 index 00000000..06b996be --- /dev/null +++ b/src/PepperDash.Core/ComTextHelper.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace PepperDash.Core +{ + /// + /// + /// + public class ComTextHelper + { + /// + /// Gets escaped text for a byte array + /// + /// + /// string with all bytes escaped + public static string GetEscapedText(byte[] bytes) + { + return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); + } + + /// + /// Gets escaped text for a string + /// + /// + /// string with all bytes escaped + public static string GetEscapedText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); + } + + /// + /// Gets debug text for a string + /// + /// + /// string with all non-printable characters escaped + public static string GetDebugText(string text) + { + return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs index 33141f0c..780e65d0 100644 --- a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs +++ b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; @@ -37,14 +36,14 @@ namespace PepperDash.Core { get { - return _DebugTimeoutInMs/60000; + return _DebugTimeoutInMs / 60000; } } /// /// Gets or sets the RxStreamDebuggingIsEnabled /// - public bool RxStreamDebuggingIsEnabled{ get; private set; } + public bool RxStreamDebuggingIsEnabled { get; private set; } /// /// Indicates that transmit stream debugging is enabled @@ -108,7 +107,7 @@ namespace PepperDash.Core TxStreamDebuggingIsEnabled = true; Debug.SetDeviceDebugSettings(ParentDeviceKey, setting); - + } /// @@ -136,51 +135,4 @@ namespace PepperDash.Core DebugExpiryPeriod = null; } } - - /// - /// The available settings for stream debugging - /// - [Flags] - /// - /// Enumeration of eStreamDebuggingSetting values - /// - public enum eStreamDebuggingSetting - { - /// - /// Debug off - /// - Off = 0, - /// - /// Debug received data - /// - Rx = 1, - /// - /// Debug transmitted data - /// - Tx = 2, - /// - /// Debug both received and transmitted data - /// - Both = Rx | Tx - } - - /// - /// The available settings for stream debugging response types - /// - [Flags] - public enum eStreamDebuggingDataTypeSettings - { - /// - /// Debug data in byte format - /// - Bytes = 0, - /// - /// Debug data in text format - /// - Text = 1, - /// - /// Debug data in both byte and text formats - /// - Both = Bytes | Text, - } } diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs index 13192ed5..8ea5138e 100644 --- a/src/PepperDash.Core/Comm/GenericSshClient.cs +++ b/src/PepperDash.Core/Comm/GenericSshClient.cs @@ -416,18 +416,14 @@ namespace PepperDash.Core if (bytesHandler != null) { var bytes = Encoding.UTF8.GetBytes(response); - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } + this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response)); + this.PrintReceivedText(response); textHandler(this, new GenericCommMethodReceiveTextArgs(response)); } @@ -484,11 +480,7 @@ namespace PepperDash.Core { if (Client != null && TheStream != null && IsConnected) { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - this.LogInformation( - "Sending {length} characters of text: '{text}'", - text.Length, - ComTextHelper.GetDebugText(text)); + this.PrintSentText(text); TheStream.Write(text); TheStream.Flush(); @@ -521,8 +513,7 @@ namespace PepperDash.Core { if (Client != null && TheStream != null && IsConnected) { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + this.PrintSentBytes(bytes); TheStream.Write(bytes, 0, bytes.Length); TheStream.Flush(); diff --git a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs index c9235411..17507851 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs @@ -19,44 +19,44 @@ namespace PepperDash.Core /// public CommunicationStreamDebugging StreamDebugging { get; private set; } - /// - /// Fires when data is received from the server and returns it as a Byte array - /// - public event EventHandler BytesReceived; + /// + /// Fires when data is received from the server and returns it as a Byte array + /// + public event EventHandler BytesReceived; - /// - /// Fires when data is received from the server and returns it as text - /// - public event EventHandler TextReceived; + /// + /// Fires when data is received from the server and returns it as text + /// + public event EventHandler TextReceived; - /// - /// - /// - //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; - public event EventHandler ConnectionChange; + /// + /// + /// + //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; + public event EventHandler ConnectionChange; - private string _hostname; + private string _hostname; /// /// Address of server /// public string Hostname { - get - { - return _hostname; - } + get + { + return _hostname; + } - set - { - _hostname = value; - if (_client != null) - { - _client.AddressClientConnectedTo = _hostname; - } - } - } + set + { + _hostname = value; + if (_client != null) + { + _client.AddressClientConnectedTo = _hostname; + } + } + } /// /// Gets or sets the Port @@ -78,19 +78,19 @@ namespace PepperDash.Core /// public int BufferSize { get; set; } - /// - /// The actual client class - /// - private TCPClient _client; + /// + /// The actual client class + /// + private TCPClient _client; - /// - /// Bool showing if socket is connected - /// - public bool IsConnected - { - get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } - + /// /// S+ helper for IsConnected /// @@ -99,15 +99,15 @@ namespace PepperDash.Core get { return (ushort)(IsConnected ? 1 : 0); } } - /// - /// _client socket status Read only - /// - public SocketStatus ClientStatus - { - get + /// + /// _client socket status Read only + /// + public SocketStatus ClientStatus + { + get { - return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; - } + return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; + } } /// @@ -119,26 +119,26 @@ namespace PepperDash.Core get { return (ushort)ClientStatus; } } - /// + /// /// Status text shows the message associated with socket status - /// - public string ClientStatusText { get { return ClientStatus.ToString(); } } + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } - /// - /// Ushort representation of client status - /// + /// + /// Ushort representation of client status + /// [Obsolete] - public ushort UClientStatus { get { return (ushort)ClientStatus; } } + public ushort UClientStatus { get { return (ushort)ClientStatus; } } - /// - /// Connection failure reason - /// - public string ConnectionFailure { get { return ClientStatus.ToString(); } } + /// + /// Connection failure reason + /// + public string ConnectionFailure { get { return ClientStatus.ToString(); } } - /// - /// Gets or sets the AutoReconnect - /// - public bool AutoReconnect { get; set; } + /// + /// Gets or sets the AutoReconnect + /// + public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect @@ -149,29 +149,29 @@ namespace PepperDash.Core set { AutoReconnect = value == 1; } } - /// - /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 - /// - public int AutoReconnectIntervalMs { get; set; } + /// + /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 + /// + public int AutoReconnectIntervalMs { get; set; } - /// - /// Set only when the disconnect method is called - /// - bool DisconnectCalledByUser; + /// + /// Set only when the disconnect method is called + /// + bool DisconnectCalledByUser; - /// - /// - /// - public bool Connected - { - get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } + /// + /// + /// + public bool Connected + { + get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } //Lock object to prevent simulatneous connect/disconnect operations private CCriticalSection connectLock = new CCriticalSection(); // private Timer for auto reconnect - private CTimer RetryTimer; + private CTimer RetryTimer; /// /// Constructor @@ -181,8 +181,8 @@ namespace PepperDash.Core /// /// public GenericTcpIpClient(string key, string address, int port, int bufferSize) - : base(key) - { + : base(key) + { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; @@ -218,18 +218,18 @@ namespace PepperDash.Core /// Default constructor for S+ /// public GenericTcpIpClient() - : base(SplusKey) + : base(SplusKey) { StreamDebugging = new CommunicationStreamDebugging(SplusKey); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; BufferSize = 2000; RetryTimer = new CTimer(o => { Reconnect(); }, Timeout.Infinite); - } + } /// /// Initialize method @@ -255,26 +255,26 @@ namespace PepperDash.Core /// /// /// - /// - /// Deactivate method - /// - public override bool Deactivate() - { + /// + /// Deactivate method + /// + public override bool Deactivate() + { RetryTimer.Stop(); RetryTimer.Dispose(); if (_client != null) { - _client.SocketStatusChange -= this.Client_SocketStatusChange; + _client.SocketStatusChange -= this.Client_SocketStatusChange; DisconnectClient(); } - return true; - } + return true; + } - /// - /// Connect method - /// - public void Connect() - { + /// + /// Connect method + /// + public void Connect() + { if (string.IsNullOrEmpty(Hostname)) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key); @@ -310,7 +310,7 @@ namespace PepperDash.Core { connectLock.Leave(); } - } + } private void Reconnect() { @@ -337,11 +337,11 @@ namespace PepperDash.Core } } - /// - /// Disconnect method - /// - public void Disconnect() - { + /// + /// Disconnect method + /// + public void Disconnect() + { try { connectLock.Enter(); @@ -355,7 +355,7 @@ namespace PepperDash.Core { connectLock.Leave(); } - } + } /// /// DisconnectClient method @@ -375,7 +375,7 @@ namespace PepperDash.Core /// /// void ConnectToServerCallback(TCPClient c) - { + { if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus); @@ -385,13 +385,13 @@ namespace PepperDash.Core { Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); } - } + } /// /// Disconnects, waits and attemtps to connect again /// void WaitAndTryReconnect() - { + { CrestronInvoke.BeginInvoke(o => { try @@ -409,7 +409,7 @@ namespace PepperDash.Core connectLock.Leave(); } }); - } + } /// /// Recieves incoming data @@ -417,7 +417,7 @@ namespace PepperDash.Core /// /// void Receive(TCPClient client, int numBytes) - { + { if (client != null) { if (numBytes > 0) @@ -426,10 +426,7 @@ namespace PepperDash.Core var bytesHandler = BytesReceived; if (bytesHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } + this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; @@ -437,58 +434,54 @@ namespace PepperDash.Core { var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); - } + this.PrintReceivedText(str); textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } + } } client.ReceiveDataAsync(Receive); } - } + } - /// - /// SendText method - /// - public void SendText(string text) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - // Check debug level before processing byte array - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + /// + /// SendText method + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + // Check debug level before processing byte array + this.PrintSentText(text); if (_client != null) - _client.SendData(bytes, bytes.Length); - } + _client.SendData(bytes, bytes.Length); + } - /// - /// SendEscapedText method - /// - public void SendEscapedText(string text) - { - var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s => - { - var hex = s.Groups[1].Value; - return ((char)Convert.ToByte(hex, 16)).ToString(); - }); - SendText(unescapedText); - } + /// + /// SendEscapedText method + /// + public void SendEscapedText(string text) + { + var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s => + { + var hex = s.Groups[1].Value; + return ((char)Convert.ToByte(hex, 16)).ToString(); + }); + SendText(unescapedText); + } /// /// Sends Bytes to the server /// /// - /// - /// SendBytes method - /// - public void SendBytes(byte[] bytes) - { + /// + /// SendBytes method + /// + public void SendBytes(byte[] bytes) + { if (StreamDebugging.TxStreamDebuggingIsEnabled) Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); if (_client != null) - _client.SendData(bytes, bytes.Length); - } + _client.SendData(bytes, bytes.Length); + } /// /// Socket Status Change Handler @@ -496,7 +489,7 @@ namespace PepperDash.Core /// /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) - { + { if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); @@ -505,68 +498,68 @@ namespace PepperDash.Core else { Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); - _client.ReceiveDataAsync(Receive); + _client.ReceiveDataAsync(Receive); } - var handler = ConnectionChange; - if (handler != null) - ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); - } - } + var handler = ConnectionChange; + if (handler != null) + ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); + } + } - /// - /// Represents a TcpSshPropertiesConfig - /// - public class TcpSshPropertiesConfig - { + /// + /// Represents a TcpSshPropertiesConfig + /// + public class TcpSshPropertiesConfig + { /// /// Address to connect to /// [JsonProperty(Required = Required.Always)] - public string Address { get; set; } - + public string Address { get; set; } + /// /// Port to connect to /// - [JsonProperty(Required = Required.Always)] - public int Port { get; set; } - + [JsonProperty(Required = Required.Always)] + public int Port { get; set; } + /// /// Username credential /// - public string Username { get; set; } - /// - /// Gets or sets the Password - /// - public string Password { get; set; } + public string Username { get; set; } + /// + /// Gets or sets the Password + /// + public string Password { get; set; } - /// - /// Defaults to 32768 - /// - public int BufferSize { get; set; } + /// + /// Defaults to 32768 + /// + public int BufferSize { get; set; } - /// - /// Gets or sets the AutoReconnect - /// - public bool AutoReconnect { get; set; } + /// + /// Gets or sets the AutoReconnect + /// + public bool AutoReconnect { get; set; } - /// - /// Gets or sets the AutoReconnectIntervalMs - /// - public int AutoReconnectIntervalMs { get; set; } + /// + /// Gets or sets the AutoReconnectIntervalMs + /// + public int AutoReconnectIntervalMs { get; set; } /// /// Default constructor /// public TcpSshPropertiesConfig() - { - BufferSize = 32768; - AutoReconnect = true; - AutoReconnectIntervalMs = 5000; + { + BufferSize = 32768; + AutoReconnect = true; + AutoReconnectIntervalMs = 5000; Username = ""; Password = ""; - } + } - } + } } diff --git a/src/PepperDash.Core/Comm/GenericUdpServer.cs b/src/PepperDash.Core/Comm/GenericUdpServer.cs index 52ac627a..a713872a 100644 --- a/src/PepperDash.Core/Comm/GenericUdpServer.cs +++ b/src/PepperDash.Core/Comm/GenericUdpServer.cs @@ -124,7 +124,7 @@ namespace PepperDash.Core CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); } - + /// /// /// @@ -135,7 +135,7 @@ namespace PepperDash.Core public GenericUdpServer(string key, string address, int port, int bufferSize) : base(key) { - StreamDebugging = new CommunicationStreamDebugging(key); + StreamDebugging = new CommunicationStreamDebugging(key); Hostname = address; Port = port; BufferSize = bufferSize; @@ -180,7 +180,7 @@ namespace PepperDash.Core /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { - if (programEventType != eProgramStatusEventType.Stopping) + if (programEventType != eProgramStatusEventType.Stopping) return; Debug.Console(1, this, "Program stopping. Disabling Server"); @@ -243,7 +243,7 @@ namespace PepperDash.Core /// public void Disconnect() { - if(Server != null) + if (Server != null) Server.DisableUDPServer(); IsConnected = false; @@ -265,7 +265,7 @@ namespace PepperDash.Core try { - if (numBytes <= 0) + if (numBytes <= 0) return; var sourceIp = Server.IPAddressLastMessageReceivedFrom; @@ -281,17 +281,13 @@ namespace PepperDash.Core var bytesHandler = BytesReceived; if (bytesHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } + this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); + this.PrintReceivedText(str); textHandler(this, new GenericCommMethodReceiveTextArgs(str)); } } @@ -318,8 +314,7 @@ namespace PepperDash.Core if (IsConnected && Server != null) { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + this.PrintSentText(text); Server.SendData(bytes, bytes.Length); } @@ -334,8 +329,7 @@ namespace PepperDash.Core /// public void SendBytes(byte[] bytes) { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + this.PrintSentBytes(bytes); if (IsConnected && Server != null) Server.SendData(bytes, bytes.Length); @@ -343,11 +337,11 @@ namespace PepperDash.Core } - /// - /// Represents a GenericUdpReceiveTextExtraArgs - /// - public class GenericUdpReceiveTextExtraArgs : EventArgs - { + /// + /// Represents a GenericUdpReceiveTextExtraArgs + /// + public class GenericUdpReceiveTextExtraArgs : EventArgs + { /// /// /// @@ -359,7 +353,7 @@ namespace PepperDash.Core /// /// /// - public int Port { get; private set; } + public int Port { get; private set; } /// /// /// @@ -373,18 +367,18 @@ namespace PepperDash.Core /// /// public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes) - { - Text = text; - IpAddress = ipAddress; - Port = port; - Bytes = bytes; - } + { + Text = text; + IpAddress = ipAddress; + Port = port; + Bytes = bytes; + } - /// - /// Stupid S+ Constructor - /// - public GenericUdpReceiveTextExtraArgs() { } - } + /// + /// Stupid S+ Constructor + /// + public GenericUdpReceiveTextExtraArgs() { } + } /// /// diff --git a/src/PepperDash.Core/Comm/StreamDebuggingExtensionMethods.cs b/src/PepperDash.Core/Comm/StreamDebuggingExtensionMethods.cs new file mode 100644 index 00000000..9fd7544d --- /dev/null +++ b/src/PepperDash.Core/Comm/StreamDebuggingExtensionMethods.cs @@ -0,0 +1,69 @@ +using System; +using Crestron.SimplSharp; + +namespace PepperDash.Core +{ + /// + /// Extension methods for stream debugging + /// + public static class StreamDebuggingExtensions + { + private static readonly string app = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"{InitialParametersClass.RoomId}"; + + /// + /// Print the sent bytes to the console + /// + /// comms device + /// bytes to print + public static void PrintSentBytes(this IStreamDebugging comms, byte[] bytes) + { + if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return; + + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'"); + } + + /// + /// Print the received bytes to the console + /// + /// comms device + /// bytes to print + public static void PrintReceivedBytes(this IStreamDebugging comms, byte[] bytes) + { + if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return; + + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'"); + } + + /// + /// Print the sent text to the console + /// + /// comms device + /// text to print + public static void PrintSentText(this IStreamDebugging comms, string text) + { + if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return; + + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending Text: '{ComTextHelper.GetDebugText(text)}'"); + } + + /// + /// Print the received text to the console + /// + /// comms device + /// text to print + public static void PrintReceivedText(this IStreamDebugging comms, string text) + { + if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return; + + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received Text: '{ComTextHelper.GetDebugText(text)}'"); + } + } +} diff --git a/src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs b/src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs new file mode 100644 index 00000000..24bd18d5 --- /dev/null +++ b/src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs @@ -0,0 +1,24 @@ +using System; + +namespace PepperDash.Core +{ + /// + /// The available settings for stream debugging response types + /// + [Flags] + public enum eStreamDebuggingDataTypeSettings + { + /// + /// Debug data in byte format + /// + Bytes = 0, + /// + /// Debug data in text format + /// + Text = 1, + /// + /// Debug data in both byte and text formats + /// + Both = Bytes | Text, + } +} diff --git a/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs b/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs new file mode 100644 index 00000000..f9f7eb3f --- /dev/null +++ b/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs @@ -0,0 +1,28 @@ +using System; + +namespace PepperDash.Core +{ + /// + /// The available settings for stream debugging + /// + [Flags] + public enum eStreamDebuggingSetting + { + /// + /// Debug off + /// + Off = 0, + /// + /// Debug received data + /// + Rx = 1, + /// + /// Debug transmitted data + /// + Tx = 2, + /// + /// Debug both received and transmitted data + /// + Both = Rx | Tx + } +} diff --git a/src/PepperDash.Core/CommunicationExtras.cs b/src/PepperDash.Core/CommunicationExtras.cs index d16ea761..a8bc57d3 100644 --- a/src/PepperDash.Core/CommunicationExtras.cs +++ b/src/PepperDash.Core/CommunicationExtras.cs @@ -1,10 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; -using System.Text.RegularExpressions; using Newtonsoft.Json; namespace PepperDash.Core @@ -42,7 +39,7 @@ namespace PepperDash.Core /// Defines the contract for IBasicCommunication /// public interface IBasicCommunication : ICommunicationReceiver - { + { /// /// Send text to the device /// @@ -54,7 +51,7 @@ namespace PepperDash.Core /// /// void SendBytes(byte[] bytes); - } + } /// /// Represents a device that implements IBasicCommunication and IStreamDebugging @@ -67,7 +64,7 @@ namespace PepperDash.Core /// /// Represents a device with stream debugging capablities /// - public interface IStreamDebugging + public interface IStreamDebugging : IKeyed { /// /// Object to enable stream debugging @@ -76,12 +73,12 @@ namespace PepperDash.Core CommunicationStreamDebugging StreamDebugging { get; } } - /// - /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, - /// GenericTcpIpClient - /// - public interface ISocketStatus : IBasicCommunication - { + /// + /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, + /// GenericTcpIpClient + /// + public interface ISocketStatus : IBasicCommunication + { /// /// Notifies of socket status changes /// @@ -93,7 +90,7 @@ namespace PepperDash.Core [JsonProperty("clientStatus")] [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] SocketStatus ClientStatus { get; } - } + } /// /// Describes a device that implements ISocketStatus and IStreamDebugging @@ -107,24 +104,24 @@ namespace PepperDash.Core /// Describes a device that can automatically attempt to reconnect /// public interface IAutoReconnect - { + { /// /// Enable automatic recconnect /// [JsonProperty("autoReconnect")] - bool AutoReconnect { get; set; } + bool AutoReconnect { get; set; } /// /// Interval in ms to attempt automatic recconnections /// [JsonProperty("autoReconnectIntervalMs")] - int AutoReconnectIntervalMs { get; set; } - } + int AutoReconnectIntervalMs { get; set; } + } - /// - /// - /// - public enum eGenericCommMethodStatusChangeType - { + /// + /// + /// + public enum eGenericCommMethodStatusChangeType + { /// /// Connected /// @@ -133,45 +130,45 @@ namespace PepperDash.Core /// Disconnected /// Disconnected - } + } - /// - /// This delegate defines handler for IBasicCommunication status changes - /// - /// Device firing the status change - /// - public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); + /// + /// This delegate defines handler for IBasicCommunication status changes + /// + /// Device firing the status change + /// + public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); - /// - /// - /// - public class GenericCommMethodReceiveBytesArgs : EventArgs - { - /// - /// Gets or sets the Bytes - /// - public byte[] Bytes { get; private set; } + /// + /// + /// + public class GenericCommMethodReceiveBytesArgs : EventArgs + { + /// + /// Gets or sets the Bytes + /// + public byte[] Bytes { get; private set; } /// /// /// /// public GenericCommMethodReceiveBytesArgs(byte[] bytes) - { - Bytes = bytes; - } + { + Bytes = bytes; + } - /// - /// S+ Constructor - /// - public GenericCommMethodReceiveBytesArgs() { } - } + /// + /// S+ Constructor + /// + public GenericCommMethodReceiveBytesArgs() { } + } - /// - /// - /// - public class GenericCommMethodReceiveTextArgs : EventArgs - { + /// + /// + /// + public class GenericCommMethodReceiveTextArgs : EventArgs + { /// /// /// @@ -185,9 +182,9 @@ namespace PepperDash.Core /// /// public GenericCommMethodReceiveTextArgs(string text) - { - Text = text; - } + { + Text = text; + } /// /// @@ -195,59 +192,14 @@ namespace PepperDash.Core /// /// public GenericCommMethodReceiveTextArgs(string text, string delimiter) - :this(text) + : this(text) { Delimiter = delimiter; } - /// - /// S+ Constructor - /// - public GenericCommMethodReceiveTextArgs() { } - } - - - - /// - /// - /// - public class ComTextHelper - { /// - /// Gets escaped text for a byte array + /// S+ Constructor /// - /// - /// - public static string GetEscapedText(byte[] bytes) - { - return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); - } - - /// - /// Gets escaped text for a string - /// - /// - /// - /// - /// GetEscapedText method - /// - public static string GetEscapedText(string text) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); - } - - /// - /// Gets debug text for a string - /// - /// - /// - /// - /// GetDebugText method - /// - public static string GetDebugText(string text) - { - return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); - } - } + public GenericCommMethodReceiveTextArgs() { } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs index 7dacce5c..2dd4f2ba 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs @@ -12,15 +12,15 @@ using Serilog.Events; namespace PepperDash.Essentials.Core { - /// - /// Represents a CecPortController - /// - public class CecPortController : Device, IBasicCommunicationWithStreamDebugging + /// + /// Represents a CecPortController + /// + public class CecPortController : Device, IBasicCommunicationWithStreamDebugging { - /// - /// Gets or sets the StreamDebugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } + /// + /// Gets or sets the StreamDebugging + /// + public CommunicationStreamDebugging StreamDebugging { get; private set; } public event EventHandler BytesReceived; public event EventHandler TextReceived; @@ -33,16 +33,16 @@ namespace PepperDash.Essentials.Core ICec Port; public CecPortController(string key, Func postActivationFunc, - EssentialsControlPropertiesConfig config):base(key) + EssentialsControlPropertiesConfig config) : base(key) { - StreamDebugging = new CommunicationStreamDebugging(key); + StreamDebugging = new CommunicationStreamDebugging(key); AddPostActivationAction(() => { Port = postActivationFunc(config); Port.StreamCec.CecChange += StreamCec_CecChange; - }); + }); } public CecPortController(string key, ICec port) @@ -58,27 +58,25 @@ namespace PepperDash.Essentials.Core if (args.EventId == CecEventIds.CecMessageReceivedEventId) OnDataReceived(cecDevice.Received.StringValue); else if (args.EventId == CecEventIds.ErrorFeedbackEventId) - if(cecDevice.ErrorFeedback.BoolValue) + if (cecDevice.ErrorFeedback.BoolValue) Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error"); } void OnDataReceived(string s) { - var bytesHandler = BytesReceived; + var bytesHandler = BytesReceived; if (bytesHandler != null) { var bytes = Encoding.GetEncoding(28591).GetBytes(s); - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); + this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; - if (textHandler != null) - { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); - textHandler(this, new GenericCommMethodReceiveTextArgs(s)); - } + if (textHandler != null) + { + this.PrintReceivedText(s); + textHandler(this, new GenericCommMethodReceiveTextArgs(s)); + } } #region IBasicCommunication Members @@ -90,8 +88,7 @@ namespace PepperDash.Essentials.Core { if (Port == null) return; - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); + this.PrintSentText(text); Port.StreamCec.Send.StringValue = text; } @@ -103,8 +100,8 @@ namespace PepperDash.Essentials.Core if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + this.PrintSentBytes(bytes); + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Port.StreamCec.Send.StringValue = text; } diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs index ba599ead..d3c46196 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs @@ -23,10 +23,10 @@ namespace PepperDash.Essentials.Core /// Event fired when bytes are received /// public event EventHandler BytesReceived; - + /// - /// Event fired when text is received - /// + /// Event fired when text is received + /// public event EventHandler TextReceived; /// @@ -38,12 +38,12 @@ namespace PepperDash.Essentials.Core ComPort.ComPortSpec Spec; /// - /// Constructor - /// - /// - /// - /// - /// + /// Constructor + /// + /// + /// + /// + /// public ComPortController(string key, Func postActivationFunc, ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key) { @@ -100,7 +100,7 @@ namespace PepperDash.Essentials.Core return; // false } } - + var specResult = Port.SetComPortSpec(Spec); if (specResult != 0) { @@ -165,16 +165,14 @@ namespace PepperDash.Essentials.Core if (bytesHandler != null) { var bytes = Encoding.GetEncoding(28591).GetBytes(s); - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); + this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); eventSubscribed = true; } var textHandler = TextReceived; if (textHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); + this.PrintReceivedText(s); textHandler(this, new GenericCommMethodReceiveTextArgs(s)); eventSubscribed = true; } @@ -201,8 +199,7 @@ namespace PepperDash.Essentials.Core if (Port == null) return; - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); + this.PrintSentText(text); Port.Send(text); } @@ -214,8 +211,7 @@ namespace PepperDash.Essentials.Core if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + this.PrintSentBytes(bytes); Port.Send(text); } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs index 72758b0e..7c6aea26 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs @@ -6,9 +6,9 @@ using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { - /// - /// Represents a SetDeviceStreamDebugRequestHandler - /// + /// + /// Represents a SetDeviceStreamDebugRequestHandler + /// public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler { /// @@ -122,23 +122,23 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device)) - { - context.Response.StatusCode = 404; - context.Response.StatusDescription = "Not Found"; - context.Response.End(); + if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device)) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); - return; - } + return; + } - eStreamDebuggingSetting debugSetting; + eStreamDebuggingSetting debugSetting; try { - debugSetting = (eStreamDebuggingSetting) Enum.Parse(typeof (eStreamDebuggingSetting), body.Setting, true); + debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), body.Setting, true); } catch (Exception ex) { - Debug.LogMessage(ex, "Exception handling set debug request"); + Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); @@ -164,7 +164,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers } catch (Exception ex) { - Debug.LogMessage(ex, "Exception handling set debug request"); + Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); @@ -198,21 +198,21 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers public class SetDeviceStreamDebugConfig { [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)] - /// - /// Gets or sets the DeviceKey - /// + /// + /// Gets or sets the DeviceKey + /// public string DeviceKey { get; set; } [JsonProperty("setting", NullValueHandling = NullValueHandling.Include)] - /// - /// Gets or sets the Setting - /// + /// + /// Gets or sets the Setting + /// public string Setting { get; set; } [JsonProperty("timeout")] - /// - /// Gets or sets the Timeout - /// + /// + /// Gets or sets the Timeout + /// public int Timeout { get; set; } public SetDeviceStreamDebugConfig()