Merge branch 'development' into hotfix/udp-server-queue

This commit is contained in:
Andrew Welker
2021-07-01 14:24:41 -06:00
committed by GitHub
4 changed files with 419 additions and 402 deletions

View File

@@ -379,18 +379,24 @@ namespace PepperDash.Core
if (bytes.Length > 0) if (bytes.Length > 0)
{ {
var bytesHandler = BytesReceived; var bytesHandler = BytesReceived;
if (bytesHandler != null) if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); {
if (StreamDebugging.RxStreamDebuggingIsEnabled)
{
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
}
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
}
var textHandler = TextReceived; var textHandler = TextReceived;
if (textHandler != null) if (textHandler != null)
{ {
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
if (StreamDebugging.RxStreamDebuggingIsEnabled) if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Recevied: '{0}'", str); Debug.Console(0, this, "Received: '{0}'", ComTextHelper.GetDebugText(str));
} textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
} }
} }
@@ -432,7 +438,7 @@ namespace PepperDash.Core
if (Client != null) if (Client != null)
{ {
if (StreamDebugging.TxStreamDebuggingIsEnabled) if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, text); Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text));
TheStream.Write(text); TheStream.Write(text);
TheStream.Flush(); TheStream.Flush();

View File

@@ -364,14 +364,20 @@ namespace PepperDash.Core
var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray();
var bytesHandler = BytesReceived; var bytesHandler = BytesReceived;
if (bytesHandler != null) if (bytesHandler != null)
{
if (StreamDebugging.RxStreamDebuggingIsEnabled)
{
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
}
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
}
var textHandler = TextReceived; var textHandler = TextReceived;
if (textHandler != null) if (textHandler != null)
{ {
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
if (StreamDebugging.RxStreamDebuggingIsEnabled) if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Recevied: '{0}'", str); Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length);
textHandler(this, new GenericCommMethodReceiveTextArgs(str)); textHandler(this, new GenericCommMethodReceiveTextArgs(str));
@@ -392,7 +398,7 @@ namespace PepperDash.Core
var bytes = Encoding.GetEncoding(28591).GetBytes(text); var bytes = Encoding.GetEncoding(28591).GetBytes(text);
// Check debug level before processing byte array // Check debug level before processing byte array
if (StreamDebugging.TxStreamDebuggingIsEnabled) if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text));
if(Client != null) if(Client != null)
Client.SendData(bytes, bytes.Length); Client.SendData(bytes, bytes.Length);

View File

@@ -1,393 +1,393 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace PepperDash.Core namespace PepperDash.Core
{ {
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{ {
private const string SplusKey = "Uninitialized Udp Server"; private const string SplusKey = "Uninitialized Udp Server";
public CommunicationStreamDebugging StreamDebugging { get; private set; } public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived; public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived; public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary> /// <summary>
/// This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data. /// This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data.
/// </summary> /// </summary>
public event EventHandler<GenericUdpReceiveTextExtraArgs> DataRecievedExtra; public event EventHandler<GenericUdpReceiveTextExtraArgs> DataRecievedExtra;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange; public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public event EventHandler<GenericUdpConnectedEventArgs> UpdateConnectionStatus; public event EventHandler<GenericUdpConnectedEventArgs> UpdateConnectionStatus;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public SocketStatus ClientStatus public SocketStatus ClientStatus
{ {
get get
{ {
return Server.ServerStatus; return Server.ServerStatus;
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort UStatus public ushort UStatus
{ {
get { return (ushort)Server.ServerStatus; } get { return (ushort)Server.ServerStatus; }
} }
/// <summary> /// <summary>
/// Address of server /// Address of server
/// </summary> /// </summary>
public string Hostname { get; set; } public string Hostname { get; set; }
/// <summary> /// <summary>
/// IP Address of the sender of the last recieved message /// IP Address of the sender of the last recieved message
/// </summary> /// </summary>
/// <summary> /// <summary>
/// Port on server /// Port on server
/// </summary> /// </summary>
public int Port { get; set; } public int Port { get; set; }
/// <summary> /// <summary>
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints /// Another damn S+ helper because S+ seems to treat large port nums as signed ints
/// which screws up things /// which screws up things
/// </summary> /// </summary>
public ushort UPort public ushort UPort
{ {
get { return Convert.ToUInt16(Port); } get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); } set { Port = Convert.ToInt32(value); }
} }
/// <summary> /// <summary>
/// Indicates that the UDP Server is enabled /// Indicates that the UDP Server is enabled
/// </summary> /// </summary>
public bool IsConnected public bool IsConnected
{ {
get; get;
private set; private set;
} }
public ushort UIsConnected public ushort UIsConnected
{ {
get { return IsConnected ? (ushort)1 : (ushort)0; } get { return IsConnected ? (ushort)1 : (ushort)0; }
} }
/// <summary> /// <summary>
/// Defaults to 2000 /// Defaults to 2000
/// </summary> /// </summary>
public int BufferSize { get; set; } public int BufferSize { get; set; }
public UDPServer Server { get; private set; } public UDPServer Server { get; private set; }
/// <summary> /// <summary>
/// Constructor for S+. Make sure to set key, address, port, and buffersize using init method /// Constructor for S+. Make sure to set key, address, port, and buffersize using init method
/// </summary> /// </summary>
public GenericUdpServer() public GenericUdpServer()
: base(SplusKey) : base(SplusKey)
{ {
StreamDebugging = new CommunicationStreamDebugging(SplusKey); StreamDebugging = new CommunicationStreamDebugging(SplusKey);
BufferSize = 5000; BufferSize = 5000;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="address"></param> /// <param name="address"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="buffefSize"></param> /// <param name="buffefSize"></param>
public GenericUdpServer(string key, string address, int port, int buffefSize) public GenericUdpServer(string key, string address, int port, int buffefSize)
: base(key) : base(key)
{ {
StreamDebugging = new CommunicationStreamDebugging(key); StreamDebugging = new CommunicationStreamDebugging(key);
Hostname = address; Hostname = address;
Port = port; Port = port;
BufferSize = buffefSize; BufferSize = buffefSize;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
} }
/// <summary> /// <summary>
/// Call from S+ to initialize values /// Call from S+ to initialize values
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="address"></param> /// <param name="address"></param>
/// <param name="port"></param> /// <param name="port"></param>
public void Initialize(string key, string address, ushort port) public void Initialize(string key, string address, ushort port)
{ {
Key = key; Key = key;
Hostname = address; Hostname = address;
UPort = port; UPort = port;
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="ethernetEventArgs"></param> /// <param name="ethernetEventArgs"></param>
void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs)
{ {
// Re-enable the server if the link comes back up and the status should be connected // Re-enable the server if the link comes back up and the status should be connected
if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp
&& IsConnected) && IsConnected)
{ {
Connect(); Connect();
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="programEventType"></param> /// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{ {
if (programEventType != eProgramStatusEventType.Stopping) if (programEventType != eProgramStatusEventType.Stopping)
return; return;
Debug.Console(1, this, "Program stopping. Disabling Server"); Debug.Console(1, this, "Program stopping. Disabling Server");
Disconnect(); Disconnect();
} }
/// <summary> /// <summary>
/// Enables the UDP Server /// Enables the UDP Server
/// </summary> /// </summary>
public void Connect() public void Connect()
{ {
if (Server == null) if (Server == null)
{ {
Server = new UDPServer(); Server = new UDPServer();
} }
if (string.IsNullOrEmpty(Hostname)) if (string.IsNullOrEmpty(Hostname))
{ {
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key); Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key);
return; return;
} }
if (Port < 1 || Port > 65535) if (Port < 1 || Port > 65535)
{ {
{ {
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key); Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key);
return; return;
} }
} }
var status = Server.EnableUDPServer(Hostname, Port); var status = Server.EnableUDPServer(Hostname, Port);
Debug.Console(2, this, "SocketErrorCode: {0}", status); Debug.Console(2, this, "SocketErrorCode: {0}", status);
if (status == SocketErrorCodes.SOCKET_OK) if (status == SocketErrorCodes.SOCKET_OK)
IsConnected = true; IsConnected = true;
var handler = UpdateConnectionStatus; var handler = UpdateConnectionStatus;
if (handler != null) if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
// Start receiving data // Start receiving data
Server.ReceiveDataAsync(Receive); Server.ReceiveDataAsync(Receive);
} }
/// <summary> /// <summary>
/// Disabled the UDP Server /// Disabled the UDP Server
/// </summary> /// </summary>
public void Disconnect() public void Disconnect()
{ {
if(Server != null) if(Server != null)
Server.DisableUDPServer(); Server.DisableUDPServer();
IsConnected = false; IsConnected = false;
var handler = UpdateConnectionStatus; var handler = UpdateConnectionStatus;
if (handler != null) if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
} }
/// <summary> /// <summary>
/// Recursive method to receive data /// Recursive method to receive data
/// </summary> /// </summary>
/// <param name="server"></param> /// <param name="server"></param>
/// <param name="numBytes"></param> /// <param name="numBytes"></param>
void Receive(UDPServer server, int numBytes) void Receive(UDPServer server, int numBytes)
{ {
Debug.Console(2, this, "Received {0} bytes", numBytes); Debug.Console(2, this, "Received {0} bytes", numBytes);
try try
{ {
if (numBytes <= 0) if (numBytes <= 0)
return; return;
var sourceIp = Server.IPAddressLastMessageReceivedFrom; var sourceIp = Server.IPAddressLastMessageReceivedFrom;
var sourcePort = Server.IPPortLastMessageReceivedFrom; var sourcePort = Server.IPPortLastMessageReceivedFrom;
var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray(); var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray();
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
var dataRecivedExtra = DataRecievedExtra; var dataRecivedExtra = DataRecievedExtra;
if (dataRecivedExtra != null) if (dataRecivedExtra != null)
dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes)); dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes));
Debug.Console(2, this, "Bytes: {0}", bytes.ToString()); Debug.Console(2, this, "Bytes: {0}", bytes.ToString());
var bytesHandler = BytesReceived; var bytesHandler = BytesReceived;
if (bytesHandler != null) if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); {
else if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(2, this, "bytesHandler is null"); {
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
var textHandler = TextReceived; }
if (textHandler != null) bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
{ }
if (StreamDebugging.RxStreamDebuggingIsEnabled) var textHandler = TextReceived;
Debug.Console(0, this, "Recevied: '{0}'", str); if (textHandler != null)
{
textHandler(this, new GenericCommMethodReceiveTextArgs(str)); if (StreamDebugging.RxStreamDebuggingIsEnabled)
} Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length);
else textHandler(this, new GenericCommMethodReceiveTextArgs(str));
Debug.Console(2, this, "textHandler is null"); }
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Console(0, "GenericUdpServer Receive error: {0}{1}", ex.Message, ex.StackTrace); Debug.Console(0, "GenericUdpServer Receive error: {0}{1}", ex.Message, ex.StackTrace);
} }
finally finally
{ {
server.ReceiveDataAsync(Receive); server.ReceiveDataAsync(Receive);
} }
} }
/// <summary> /// <summary>
/// General send method /// General send method
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
public void SendText(string text) public void SendText(string text)
{ {
var bytes = Encoding.GetEncoding(28591).GetBytes(text); var bytes = Encoding.GetEncoding(28591).GetBytes(text);
if (IsConnected && Server != null) if (IsConnected && Server != null)
{ {
if (StreamDebugging.TxStreamDebuggingIsEnabled) if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, text); Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text));
Server.SendData(bytes, bytes.Length); Server.SendData(bytes, bytes.Length);
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="bytes"></param> /// <param name="bytes"></param>
public void SendBytes(byte[] bytes) public void SendBytes(byte[] bytes)
{ {
if (StreamDebugging.TxStreamDebuggingIsEnabled) if (StreamDebugging.TxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
if (IsConnected && Server != null) if (IsConnected && Server != null)
Server.SendData(bytes, bytes.Length); Server.SendData(bytes, bytes.Length);
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class GenericUdpReceiveTextExtraArgs : EventArgs public class GenericUdpReceiveTextExtraArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Text { get; private set; } public string Text { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string IpAddress { get; private set; } public string IpAddress { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int Port { get; private set; } public int Port { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public byte[] Bytes { get; private set; } public byte[] Bytes { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="bytes"></param> /// <param name="bytes"></param>
public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes) public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
{ {
Text = text; Text = text;
IpAddress = ipAddress; IpAddress = ipAddress;
Port = port; Port = port;
Bytes = bytes; Bytes = bytes;
} }
/// <summary> /// <summary>
/// Stupid S+ Constructor /// Stupid S+ Constructor
/// </summary> /// </summary>
public GenericUdpReceiveTextExtraArgs() { } public GenericUdpReceiveTextExtraArgs() { }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class UdpServerPropertiesConfig public class UdpServerPropertiesConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
[JsonProperty(Required = Required.Always)] [JsonProperty(Required = Required.Always)]
public string Address { get; set; } public string Address { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
[JsonProperty(Required = Required.Always)] [JsonProperty(Required = Required.Always)]
public int Port { get; set; } public int Port { get; set; }
/// <summary> /// <summary>
/// Defaults to 32768 /// Defaults to 32768
/// </summary> /// </summary>
public int BufferSize { get; set; } public int BufferSize { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public UdpServerPropertiesConfig() public UdpServerPropertiesConfig()
{ {
BufferSize = 32768; BufferSize = 32768;
} }
} }
} }

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using System.Text.RegularExpressions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -138,5 +138,10 @@ namespace PepperDash.Core
var bytes = Encoding.GetEncoding(28591).GetBytes(text); var bytes = Encoding.GetEncoding(28591).GetBytes(text);
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
} }
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
} }
} }