using System;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json;
using PepperDash.Core.Logging;
namespace PepperDash.Core
{
///
/// Generic UDP Server device
///
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{
private const string SplusKey = "Uninitialized Udp Server";
///
/// Object to enable stream debugging
///
public CommunicationStreamDebugging StreamDebugging { get; private set; }
///
///
///
public event EventHandler BytesReceived;
///
///
///
public event EventHandler TextReceived;
///
/// 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.
///
public event EventHandler DataRecievedExtra;
///
///
///
public event EventHandler ConnectionChange;
///
///
///
public event EventHandler UpdateConnectionStatus;
///
///
///
public SocketStatus ClientStatus
{
get
{
return Server.ServerStatus;
}
}
///
///
///
public ushort UStatus
{
get { return (ushort)Server.ServerStatus; }
}
///
/// Address of server
///
public string Hostname { get; set; }
///
/// Port on server
///
public int Port { get; set; }
///
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints
/// which screws up things
///
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
///
/// Indicates that the UDP Server is enabled
///
public bool IsConnected
{
get;
private set;
}
///
/// Numeric value indicating
///
public ushort UIsConnected
{
get { return IsConnected ? (ushort)1 : (ushort)0; }
}
///
/// Defaults to 2000
///
public int BufferSize { get; set; }
///
/// The server
///
public UDPServer Server { get; private set; }
///
/// Constructor for S+. Make sure to set key, address, port, and buffersize using init method
///
public GenericUdpServer()
: base(SplusKey)
{
StreamDebugging = new CommunicationStreamDebugging(SplusKey);
BufferSize = 5000;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
}
///
///
///
///
///
///
///
public GenericUdpServer(string key, string address, int port, int bufferSize)
: base(key)
{
StreamDebugging = new CommunicationStreamDebugging(key);
Hostname = address;
Port = port;
BufferSize = bufferSize;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
}
///
/// Call from S+ to initialize values
///
///
///
///
///
/// Initialize method
///
public void Initialize(string key, string address, ushort port)
{
Key = key;
Hostname = address;
UPort = port;
}
///
///
///
///
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)
return;
Debug.Console(1, this, "Program stopping. Disabling Server");
Disconnect();
}
///
/// Connect method
///
public void Connect()
{
if (Server == null)
{
try
{
var address = IPAddress.Parse(Hostname);
Server = new UDPServer(address, Port, BufferSize);
}
catch (Exception ex)
{
this.LogError("Error parsing IP Address '{ipAddress}': message: {message}", Hostname, ex.Message);
this.LogInformation("Creating UDPServer with default buffersize");
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;
var handler = UpdateConnectionStatus;
if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
// Start receiving data
Server.ReceiveDataAsync(Receive);
}
///
/// Disconnect method
///
public void Disconnect()
{
if (Server != null)
Server.DisableUDPServer();
IsConnected = false;
var handler = UpdateConnectionStatus;
if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
}
///
/// Recursive method to receive data
///
///
///
void Receive(UDPServer server, int numBytes)
{
Debug.Console(2, this, "Received {0} bytes", numBytes);
try
{
if (numBytes <= 0)
return;
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);
var dataRecivedExtra = DataRecievedExtra;
if (dataRecivedExtra != null)
dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes));
Debug.Console(2, this, "Bytes: {0}", bytes.ToString());
var bytesHandler = BytesReceived;
if (bytesHandler != null)
{
this.PrintReceivedBytes(bytes);
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
}
var textHandler = TextReceived;
if (textHandler != null)
{
this.PrintReceivedText(str);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
}
catch (Exception ex)
{
this.LogException(ex, "GenericUdpServer Receive error");
}
finally
{
server.ReceiveDataAsync(Receive);
}
}
///
/// General send method
///
///
///
/// SendText method
///
public void SendText(string text)
{
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
if (IsConnected && Server != null)
{
this.PrintSentText(text);
Server.SendData(bytes, bytes.Length);
}
}
///
///
///
///
///
/// SendBytes method
///
public void SendBytes(byte[] bytes)
{
this.PrintSentBytes(bytes);
if (IsConnected && Server != null)
Server.SendData(bytes, bytes.Length);
}
}
///
/// Represents a GenericUdpReceiveTextExtraArgs
///
public class GenericUdpReceiveTextExtraArgs : EventArgs
{
///
///
///
public string Text { get; private set; }
///
///
///
public string IpAddress { get; private set; }
///
///
///
public int Port { get; private set; }
///
///
///
public byte[] Bytes { get; private set; }
///
///
///
///
///
///
///
public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
{
Text = text;
IpAddress = ipAddress;
Port = port;
Bytes = bytes;
}
///
/// Stupid S+ Constructor
///
public GenericUdpReceiveTextExtraArgs() { }
}
///
///
///
public class UdpServerPropertiesConfig
{
///
///
///
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
///
///
///
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
///
/// Defaults to 32768
///
public int BufferSize { get; set; }
///
///
///
public UdpServerPropertiesConfig()
{
BufferSize = 32768;
}
}
}