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
This commit is contained in:
Andrew Welker
2025-11-03 10:53:21 -06:00
parent 666be5ae59
commit 6ed7c96ec7
12 changed files with 493 additions and 454 deletions

View File

@@ -0,0 +1,43 @@
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace PepperDash.Core
{
/// <summary>
///
/// </summary>
public class ComTextHelper
{
/// <summary>
/// Gets escaped text for a byte array
/// </summary>
/// <param name="bytes"></param>
/// <returns>string with all bytes escaped</returns>
public static string GetEscapedText(byte[] bytes)
{
return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
}
/// <summary>
/// Gets escaped text for a string
/// </summary>
/// <param name="text"></param>
/// <returns>string with all bytes escaped</returns>
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());
}
/// <summary>
/// Gets debug text for a string
/// </summary>
/// <param name="text"></param>
/// <returns>string with all non-printable characters escaped</returns>
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
}
}

View File

@@ -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;
}
}
/// <summary>
/// Gets or sets the RxStreamDebuggingIsEnabled
/// </summary>
public bool RxStreamDebuggingIsEnabled{ get; private set; }
public bool RxStreamDebuggingIsEnabled { get; private set; }
/// <summary>
/// Indicates that transmit stream debugging is enabled
@@ -136,51 +135,4 @@ namespace PepperDash.Core
DebugExpiryPeriod = null;
}
}
/// <summary>
/// The available settings for stream debugging
/// </summary>
[Flags]
/// <summary>
/// Enumeration of eStreamDebuggingSetting values
/// </summary>
public enum eStreamDebuggingSetting
{
/// <summary>
/// Debug off
/// </summary>
Off = 0,
/// <summary>
/// Debug received data
/// </summary>
Rx = 1,
/// <summary>
/// Debug transmitted data
/// </summary>
Tx = 2,
/// <summary>
/// Debug both received and transmitted data
/// </summary>
Both = Rx | Tx
}
/// <summary>
/// The available settings for stream debugging response types
/// </summary>
[Flags]
public enum eStreamDebuggingDataTypeSettings
{
/// <summary>
/// Debug data in byte format
/// </summary>
Bytes = 0,
/// <summary>
/// Debug data in text format
/// </summary>
Text = 1,
/// <summary>
/// Debug data in both byte and text formats
/// </summary>
Both = Bytes | Text,
}
}

View File

@@ -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();

View File

@@ -19,44 +19,44 @@ namespace PepperDash.Core
/// </summary>
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary>
/// Fires when data is received from the server and returns it as a Byte array
/// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Fires when data is received from the server and returns it as a Byte array
/// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Fires when data is received from the server and returns it as text
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// Fires when data is received from the server and returns it as text
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
///
/// </summary>
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary>
///
/// </summary>
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
private string _hostname;
private string _hostname;
/// <summary>
/// Address of server
/// </summary>
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;
}
}
}
/// <summary>
/// Gets or sets the Port
@@ -78,15 +78,15 @@ namespace PepperDash.Core
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// The actual client class
/// </summary>
private TCPClient _client;
/// <summary>
/// The actual client class
/// </summary>
private TCPClient _client;
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
{
get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
@@ -99,10 +99,10 @@ namespace PepperDash.Core
get { return (ushort)(IsConnected ? 1 : 0); }
}
/// <summary>
/// _client socket status Read only
/// </summary>
public SocketStatus ClientStatus
/// <summary>
/// _client socket status Read only
/// </summary>
public SocketStatus ClientStatus
{
get
{
@@ -119,26 +119,26 @@ namespace PepperDash.Core
get { return (ushort)ClientStatus; }
}
/// <summary>
/// <summary>
/// Status text shows the message associated with socket status
/// </summary>
public string ClientStatusText { get { return ClientStatus.ToString(); } }
/// </summary>
public string ClientStatusText { get { return ClientStatus.ToString(); } }
/// <summary>
/// Ushort representation of client status
/// </summary>
/// <summary>
/// Ushort representation of client status
/// </summary>
[Obsolete]
public ushort UClientStatus { get { return (ushort)ClientStatus; } }
public ushort UClientStatus { get { return (ushort)ClientStatus; } }
/// <summary>
/// Connection failure reason
/// </summary>
public string ConnectionFailure { get { return ClientStatus.ToString(); } }
/// <summary>
/// Connection failure reason
/// </summary>
public string ConnectionFailure { get { return ClientStatus.ToString(); } }
/// <summary>
/// Gets or sets the AutoReconnect
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// Gets or sets the AutoReconnect
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// S+ helper for AutoReconnect
@@ -149,29 +149,29 @@ namespace PepperDash.Core
set { AutoReconnect = value == 1; }
}
/// <summary>
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Set only when the disconnect method is called
/// </summary>
bool DisconnectCalledByUser;
/// <summary>
/// Set only when the disconnect method is called
/// </summary>
bool DisconnectCalledByUser;
/// <summary>
///
/// </summary>
public bool Connected
{
get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
/// <summary>
///
/// </summary>
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;
/// <summary>
/// Constructor
@@ -181,8 +181,8 @@ namespace PepperDash.Core
/// <param name="port"></param>
/// <param name="bufferSize"></param>
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+
/// </summary>
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);
}
}
/// <summary>
/// Initialize method
@@ -255,26 +255,26 @@ namespace PepperDash.Core
///
/// </summary>
/// <returns></returns>
/// <summary>
/// Deactivate method
/// </summary>
public override bool Deactivate()
{
/// <summary>
/// Deactivate method
/// </summary>
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;
}
/// <summary>
/// Connect method
/// </summary>
public void Connect()
{
/// <summary>
/// Connect method
/// </summary>
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
}
}
/// <summary>
/// Disconnect method
/// </summary>
public void Disconnect()
{
/// <summary>
/// Disconnect method
/// </summary>
public void Disconnect()
{
try
{
connectLock.Enter();
@@ -355,7 +355,7 @@ namespace PepperDash.Core
{
connectLock.Leave();
}
}
}
/// <summary>
/// DisconnectClient method
@@ -375,7 +375,7 @@ namespace PepperDash.Core
/// </summary>
/// <param name="c"></param>
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);
}
}
}
/// <summary>
/// Disconnects, waits and attemtps to connect again
/// </summary>
void WaitAndTryReconnect()
{
{
CrestronInvoke.BeginInvoke(o =>
{
try
@@ -409,7 +409,7 @@ namespace PepperDash.Core
connectLock.Leave();
}
});
}
}
/// <summary>
/// Recieves incoming data
@@ -417,7 +417,7 @@ namespace PepperDash.Core
/// <param name="client"></param>
/// <param name="numBytes"></param>
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);
}
}
}
/// <summary>
/// SendText method
/// </summary>
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));
/// <summary>
/// SendText method
/// </summary>
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);
}
/// <summary>
/// SendEscapedText method
/// </summary>
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);
}
/// <summary>
/// SendEscapedText method
/// </summary>
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);
}
/// <summary>
/// Sends Bytes to the server
/// </summary>
/// <param name="bytes"></param>
/// <summary>
/// SendBytes method
/// </summary>
public void SendBytes(byte[] bytes)
{
/// <summary>
/// SendBytes method
/// </summary>
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);
}
/// <summary>
/// Socket Status Change Handler
@@ -496,7 +489,7 @@ namespace PepperDash.Core
/// <param name="client"></param>
/// <param name="clientSocketStatus"></param>
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));
}
}
/// <summary>
/// Represents a TcpSshPropertiesConfig
/// </summary>
public class TcpSshPropertiesConfig
{
/// <summary>
/// Represents a TcpSshPropertiesConfig
/// </summary>
public class TcpSshPropertiesConfig
{
/// <summary>
/// Address to connect to
/// </summary>
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
public string Address { get; set; }
/// <summary>
/// Port to connect to
/// </summary>
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
/// <summary>
/// Username credential
/// </summary>
public string Username { get; set; }
/// <summary>
/// Gets or sets the Password
/// </summary>
public string Password { get; set; }
public string Username { get; set; }
/// <summary>
/// Gets or sets the Password
/// </summary>
public string Password { get; set; }
/// <summary>
/// Defaults to 32768
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Defaults to 32768
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Gets or sets the AutoReconnect
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// Gets or sets the AutoReconnect
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// Gets or sets the AutoReconnectIntervalMs
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Gets or sets the AutoReconnectIntervalMs
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public TcpSshPropertiesConfig()
{
BufferSize = 32768;
AutoReconnect = true;
AutoReconnectIntervalMs = 5000;
{
BufferSize = 32768;
AutoReconnect = true;
AutoReconnectIntervalMs = 5000;
Username = "";
Password = "";
}
}
}
}
}

View File

@@ -243,7 +243,7 @@ namespace PepperDash.Core
/// </summary>
public void Disconnect()
{
if(Server != null)
if (Server != null)
Server.DisableUDPServer();
IsConnected = false;
@@ -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
/// </summary>
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
}
/// <summary>
/// Represents a GenericUdpReceiveTextExtraArgs
/// </summary>
public class GenericUdpReceiveTextExtraArgs : EventArgs
{
/// <summary>
/// Represents a GenericUdpReceiveTextExtraArgs
/// </summary>
public class GenericUdpReceiveTextExtraArgs : EventArgs
{
/// <summary>
///
/// </summary>
@@ -359,7 +353,7 @@ namespace PepperDash.Core
/// <summary>
///
/// </summary>
public int Port { get; private set; }
public int Port { get; private set; }
/// <summary>
///
/// </summary>
@@ -373,18 +367,18 @@ namespace PepperDash.Core
/// <param name="port"></param>
/// <param name="bytes"></param>
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;
}
/// <summary>
/// Stupid S+ Constructor
/// </summary>
public GenericUdpReceiveTextExtraArgs() { }
}
/// <summary>
/// Stupid S+ Constructor
/// </summary>
public GenericUdpReceiveTextExtraArgs() { }
}
/// <summary>
///

View File

@@ -0,0 +1,69 @@
using System;
using Crestron.SimplSharp;
namespace PepperDash.Core
{
/// <summary>
/// Extension methods for stream debugging
/// </summary>
public static class StreamDebuggingExtensions
{
private static readonly string app = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"{InitialParametersClass.RoomId}";
/// <summary>
/// Print the sent bytes to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="bytes">bytes to print</param>
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)}'");
}
/// <summary>
/// Print the received bytes to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="bytes">bytes to print</param>
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)}'");
}
/// <summary>
/// Print the sent text to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="text">text to print</param>
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)}'");
}
/// <summary>
/// Print the received text to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="text">text to print</param>
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)}'");
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace PepperDash.Core
{
/// <summary>
/// The available settings for stream debugging response types
/// </summary>
[Flags]
public enum eStreamDebuggingDataTypeSettings
{
/// <summary>
/// Debug data in byte format
/// </summary>
Bytes = 0,
/// <summary>
/// Debug data in text format
/// </summary>
Text = 1,
/// <summary>
/// Debug data in both byte and text formats
/// </summary>
Both = Bytes | Text,
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace PepperDash.Core
{
/// <summary>
/// The available settings for stream debugging
/// </summary>
[Flags]
public enum eStreamDebuggingSetting
{
/// <summary>
/// Debug off
/// </summary>
Off = 0,
/// <summary>
/// Debug received data
/// </summary>
Rx = 1,
/// <summary>
/// Debug transmitted data
/// </summary>
Tx = 2,
/// <summary>
/// Debug both received and transmitted data
/// </summary>
Both = Rx | Tx
}
}

View File

@@ -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
/// </summary>
public interface IBasicCommunication : ICommunicationReceiver
{
{
/// <summary>
/// Send text to the device
/// </summary>
@@ -54,7 +51,7 @@ namespace PepperDash.Core
/// </summary>
/// <param name="bytes"></param>
void SendBytes(byte[] bytes);
}
}
/// <summary>
/// Represents a device that implements IBasicCommunication and IStreamDebugging
@@ -67,7 +64,7 @@ namespace PepperDash.Core
/// <summary>
/// Represents a device with stream debugging capablities
/// </summary>
public interface IStreamDebugging
public interface IStreamDebugging : IKeyed
{
/// <summary>
/// Object to enable stream debugging
@@ -76,12 +73,12 @@ namespace PepperDash.Core
CommunicationStreamDebugging StreamDebugging { get; }
}
/// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// GenericTcpIpClient
/// </summary>
public interface ISocketStatus : IBasicCommunication
{
/// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// GenericTcpIpClient
/// </summary>
public interface ISocketStatus : IBasicCommunication
{
/// <summary>
/// Notifies of socket status changes
/// </summary>
@@ -93,7 +90,7 @@ namespace PepperDash.Core
[JsonProperty("clientStatus")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
SocketStatus ClientStatus { get; }
}
}
/// <summary>
/// Describes a device that implements ISocketStatus and IStreamDebugging
@@ -107,24 +104,24 @@ namespace PepperDash.Core
/// Describes a device that can automatically attempt to reconnect
/// </summary>
public interface IAutoReconnect
{
{
/// <summary>
/// Enable automatic recconnect
/// </summary>
[JsonProperty("autoReconnect")]
bool AutoReconnect { get; set; }
bool AutoReconnect { get; set; }
/// <summary>
/// Interval in ms to attempt automatic recconnections
/// </summary>
[JsonProperty("autoReconnectIntervalMs")]
int AutoReconnectIntervalMs { get; set; }
}
int AutoReconnectIntervalMs { get; set; }
}
/// <summary>
///
/// </summary>
public enum eGenericCommMethodStatusChangeType
{
/// <summary>
///
/// </summary>
public enum eGenericCommMethodStatusChangeType
{
/// <summary>
/// Connected
/// </summary>
@@ -133,45 +130,45 @@ namespace PepperDash.Core
/// Disconnected
/// </summary>
Disconnected
}
}
/// <summary>
/// This delegate defines handler for IBasicCommunication status changes
/// </summary>
/// <param name="comm">Device firing the status change</param>
/// <param name="status"></param>
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
/// <summary>
/// This delegate defines handler for IBasicCommunication status changes
/// </summary>
/// <param name="comm">Device firing the status change</param>
/// <param name="status"></param>
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveBytesArgs : EventArgs
{
/// <summary>
/// Gets or sets the Bytes
/// </summary>
public byte[] Bytes { get; private set; }
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveBytesArgs : EventArgs
{
/// <summary>
/// Gets or sets the Bytes
/// </summary>
public byte[] Bytes { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
public GenericCommMethodReceiveBytesArgs(byte[] bytes)
{
Bytes = bytes;
}
{
Bytes = bytes;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveBytesArgs() { }
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveBytesArgs() { }
}
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
@@ -185,9 +182,9 @@ namespace PepperDash.Core
/// </summary>
/// <param name="text"></param>
public GenericCommMethodReceiveTextArgs(string text)
{
Text = text;
}
{
Text = text;
}
/// <summary>
///
@@ -195,59 +192,14 @@ namespace PepperDash.Core
/// <param name="text"></param>
/// <param name="delimiter"></param>
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
:this(text)
: this(text)
{
Delimiter = delimiter;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveTextArgs() { }
}
/// <summary>
///
/// </summary>
public class ComTextHelper
{
/// <summary>
/// Gets escaped text for a byte array
/// S+ Constructor
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string GetEscapedText(byte[] bytes)
{
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
}
/// <summary>
/// Gets escaped text for a string
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
/// <summary>
/// GetEscapedText method
/// </summary>
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());
}
/// <summary>
/// Gets debug text for a string
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
/// <summary>
/// GetDebugText method
/// </summary>
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
}
public GenericCommMethodReceiveTextArgs() { }
}
}

View File

@@ -12,15 +12,15 @@ using Serilog.Events;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Represents a CecPortController
/// </summary>
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
/// <summary>
/// Represents a CecPortController
/// </summary>
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
{
/// <summary>
/// Gets or sets the StreamDebugging
/// </summary>
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary>
/// Gets or sets the StreamDebugging
/// </summary>
public CommunicationStreamDebugging StreamDebugging { get; private set; }
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
@@ -33,9 +33,9 @@ namespace PepperDash.Essentials.Core
ICec Port;
public CecPortController(string key, Func<EssentialsControlPropertiesConfig, ICec> postActivationFunc,
EssentialsControlPropertiesConfig config):base(key)
EssentialsControlPropertiesConfig config) : base(key)
{
StreamDebugging = new CommunicationStreamDebugging(key);
StreamDebugging = new CommunicationStreamDebugging(key);
AddPostActivationAction(() =>
{
@@ -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;
}

View File

@@ -25,8 +25,8 @@ namespace PepperDash.Essentials.Core
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Event fired when text is received
/// </summary>
/// Event fired when text is received
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
@@ -38,12 +38,12 @@ namespace PepperDash.Essentials.Core
ComPort.ComPortSpec Spec;
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="postActivationFunc"></param>
/// <param name="spec"></param>
/// <param name="config"></param>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="postActivationFunc"></param>
/// <param name="spec"></param>
/// <param name="config"></param>
public ComPortController(string key, Func<EssentialsControlPropertiesConfig, ComPort> postActivationFunc,
ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key)
{
@@ -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);
}

View File

@@ -6,9 +6,9 @@ using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
/// <summary>
/// Represents a SetDeviceStreamDebugRequestHandler
/// </summary>
/// <summary>
/// Represents a SetDeviceStreamDebugRequestHandler
/// </summary>
public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
@@ -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)]
/// <summary>
/// Gets or sets the DeviceKey
/// </summary>
/// <summary>
/// Gets or sets the DeviceKey
/// </summary>
public string DeviceKey { get; set; }
[JsonProperty("setting", NullValueHandling = NullValueHandling.Include)]
/// <summary>
/// Gets or sets the Setting
/// </summary>
/// <summary>
/// Gets or sets the Setting
/// </summary>
public string Setting { get; set; }
[JsonProperty("timeout")]
/// <summary>
/// Gets or sets the Timeout
/// </summary>
/// <summary>
/// Gets or sets the Timeout
/// </summary>
public int Timeout { get; set; }
public SetDeviceStreamDebugConfig()