# GenericUdpServer

- Adds an event GenericUdpReceiveTextExtraArgs which has args that include TextRx, BytesRx, IpAddressRecivedFrom, PortRecievedFrom
- Removes the getter property for LastMessageReceivedFrom
This commit is contained in:
Jason T Alborough
2019-04-22 10:30:39 -04:00
parent 73b9cd8c31
commit 54324d7e43

View File

@@ -1,240 +1,301 @@
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
{
public class GenericUdpServer : Device, IBasicCommunication namespace PepperDash.Core
{ {
/// <summary> public class GenericUdpServer : Device, IBasicCommunication
/// {
/// </summary> /// <summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived; ///
/// </summary>
/// <summary> public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
///
/// </summary> /// <summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived; ///
/// </summary>
/// <summary> public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// public event EventHandler<GenericUdpReceiveTextExtraArgs> DataRecievedExtra;
/// </summary> private CrestronQueue<GenericUdpReceiveTextExtraArgs> MessageQueue;
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange; /// <summary>
///
public SocketStatus ClientStatus /// </summary>
{ //public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
get public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
{
return Server.ServerStatus; public SocketStatus ClientStatus
} {
} get
{
/// <summary> return Server.ServerStatus;
/// Address of server }
/// </summary> }
CCriticalSection DequeueLock;
/// <summary>
/// Address of server
/// </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>
public string LastMessageReceivedFrom
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints
/// which screws up things
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Indicates that the UDP Server is enabled
/// </summary>
public bool IsConnected
{
get;
private set;
}
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
public UDPServer Server { get; private set; }
public GenericUdpServer(string key, string address, int port, int buffefSize)
: base(key)
{
Hostname = address;
Port = port;
BufferSize = buffefSize;
DequeueLock = new CCriticalSection();
MessageQueue = new CrestronQueue<GenericUdpReceiveTextExtraArgs>();
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
}
void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs)
{
// Re-enable the server if the link comes back up and the status should be connected
if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp
&& IsConnected)
{
Connect();
}
}
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
Debug.Console(1, this, "Program stopping. Disabling Server");
Disconnect();
}
}
/// <summary>
/// Enables the UDP Server
/// </summary>
public void Connect()
{
if (Server == null)
{
Server = new UDPServer();
}
if (string.IsNullOrEmpty(Hostname))
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key);
return;
}
if (Port < 1 || Port > 65535)
{
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key);
return;
}
}
var status = Server.EnableUDPServer(Hostname, Port);
Debug.Console(2, this, "SocketErrorCode: {0}", status);
if (status == SocketErrorCodes.SOCKET_OK)
IsConnected = true;
// Start receiving data
Server.ReceiveDataAsync(Receive);
}
/// <summary>
/// Disabled the UDP Server
/// </summary>
public void Disconnect()
{
if(Server != null)
Server.DisableUDPServer();
IsConnected = false;
}
/// <summary>
/// Recursive method to receive data
/// </summary>
/// <param name="server"></param>
/// <param name="numBytes"></param>
void Receive(UDPServer server, int numBytes)
{
Debug.Console(2, this, "Received {0} bytes", numBytes);
if (numBytes > 0)
{
var sourceIp = Server.IPAddressLastMessageReceivedFrom;
var sourcePort = Server.IPPortLastMessageReceivedFrom;
var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray();
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
MessageQueue.TryToEnqueue(new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes));
Debug.Console(2, this, "Bytes: {0}", bytes.ToString());
var bytesHandler = BytesReceived;
if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
else
Debug.Console(2, this, "bytesHandler is null");
var textHandler = TextReceived;
if (textHandler != null)
{
Debug.Console(2, this, "RX: {0}", str);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
else
Debug.Console(2, this, "textHandler is null");
}
server.ReceiveDataAsync(Receive);
CrestronInvoke.BeginInvoke(DequeueEvent);
}
void DequeueEvent(object notUsed)
{ {
get { return Server.IPAddressLastMessageReceivedFrom; } try
{
} // Add CCritical Section
DequeueLock.TryEnter();
/// <summary> while (!MessageQueue.IsEmpty)
/// Port on server {
/// </summary> // Pull from Queue and fire an event.
public int Port { get; set; } var Message = MessageQueue.TryToDequeue();
var dataRecivedExtra = DataRecievedExtra;
/// <summary> if (dataRecivedExtra != null)
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints {
/// which screws up things dataRecivedExtra(this, Message);
/// </summary> }
public ushort UPort
{
get { return Convert.ToUInt16(Port); } }
set { Port = Convert.ToInt32(value); }
} }
catch (Exception e)
/// <summary> {
/// Indicates that the UDP Server is enabled Debug.Console(0, "GenericUdpServer DequeueEvent error: {0}\r", e);
/// </summary> }
public bool IsConnected finally
{ {
get; DequeueLock.Leave();
private set; }
} }
/// <summary> /// <summary>
/// Defaults to 2000 /// General send method
/// </summary> /// </summary>
public int BufferSize { get; set; } /// <param name="text"></param>
public void SendText(string text)
public UDPServer Server { get; private set; } {
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
public GenericUdpServer(string key, string address, int port, int buffefSize)
: base(key) if (IsConnected && Server != null)
{ {
Hostname = address; Debug.Console(2, this, "TX: {0}", text);
Port = port; Server.SendData(bytes, bytes.Length);
BufferSize = buffefSize; }
}
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); public void SendBytes(byte[] bytes)
} {
//if (Debug.Level == 2)
void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) // Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
{ if (IsConnected && Server != null)
// Re-enable the server if the link comes back up and the status should be connected Server.SendData(bytes, bytes.Length);
if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp }
&& IsConnected)
{
Connect();
} }
}
public class GenericUdpReceiveTextExtraArgs : EventArgs
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) {
{ public string Text { get; private set; }
if (programEventType == eProgramStatusEventType.Stopping) public string IpAddress { get; private set; }
{ public int Port { get; private set; }
Debug.Console(1, this, "Program stopping. Disabling Server"); public byte[] Bytes { get; private set; }
Disconnect();
} public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
} {
Text = text;
/// <summary> IpAddress = ipAddress;
/// Enables the UDP Server Port = port;
/// </summary> Bytes = bytes;
public void Connect() }
{
if (Server == null) /// <summary>
{ /// Stupid S+ Constructor
Server = new UDPServer(); /// </summary>
public GenericUdpReceiveTextExtraArgs() { }
} }
if (string.IsNullOrEmpty(Hostname)) public class UdpServerPropertiesConfig
{ {
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key); [JsonProperty(Required = Required.Always)]
return; public string Address { get; set; }
}
if (Port < 1 || Port > 65535) [JsonProperty(Required = Required.Always)]
{ public int Port { get; set; }
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key); /// <summary>
return; /// Defaults to 32768
} /// </summary>
} public int BufferSize { get; set; }
var status = Server.EnableUDPServer(Hostname, Port); public UdpServerPropertiesConfig()
{
Debug.Console(2, this, "SocketErrorCode: {0}", status); BufferSize = 32768;
if (status == SocketErrorCodes.SOCKET_OK) }
IsConnected = true; }
// Start receiving data
Server.ReceiveDataAsync(Receive);
}
/// <summary>
/// Disabled the UDP Server
/// </summary>
public void Disconnect()
{
if(Server != null)
Server.DisableUDPServer();
IsConnected = false;
}
/// <summary>
/// Recursive method to receive data
/// </summary>
/// <param name="server"></param>
/// <param name="numBytes"></param>
void Receive(UDPServer server, int numBytes)
{
Debug.Console(2, this, "Received {0} bytes", numBytes);
if (numBytes > 0)
{
var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray();
Debug.Console(2, this, "Bytes: {0}", bytes.ToString());
var bytesHandler = BytesReceived;
if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
else
Debug.Console(2, this, "bytesHandler is null");
var textHandler = TextReceived;
if (textHandler != null)
{
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
Debug.Console(2, this, "RX: {0}", str);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
else
Debug.Console(2, this, "textHandler is null");
}
server.ReceiveDataAsync(Receive);
}
/// <summary>
/// General send method
/// </summary>
/// <param name="text"></param>
public void SendText(string text)
{
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
if (IsConnected && Server != null)
{
Debug.Console(2, this, "TX: {0}", text);
Server.SendData(bytes, bytes.Length);
}
}
public void SendBytes(byte[] bytes)
{
//if (Debug.Level == 2)
// Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
if (IsConnected && Server != null)
Server.SendData(bytes, bytes.Length);
}
}
public class UdpServerPropertiesConfig
{
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
/// <summary>
/// Defaults to 32768
/// </summary>
public int BufferSize { get; set; }
public UdpServerPropertiesConfig()
{
BufferSize = 32768;
}
}
} }