diff --git a/CLZ Builds/PepperDash_Core.clz b/CLZ Builds/PepperDash_Core.clz
index f3a2ec2..6899b0e 100644
Binary files a/CLZ Builds/PepperDash_Core.clz and b/CLZ Builds/PepperDash_Core.clz differ
diff --git a/CLZ Builds/PepperDash_Core.dll b/CLZ Builds/PepperDash_Core.dll
index 43d7667..9bdbeb2 100644
Binary files a/CLZ Builds/PepperDash_Core.dll and b/CLZ Builds/PepperDash_Core.dll differ
diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs
index 3d1101a..6af5d7b 100644
--- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs
+++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs
@@ -174,8 +174,8 @@ namespace PepperDash.Core
if (Client != null)
{
Debug.Console(1, this, "Program stopping. Closing connection");
- Client.Disconnect();
- Client.Dispose();
+ Disconnect();
+ //Client.Dispose();
}
}
}
diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpServer.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpServer.cs
index 2ef2845..da5c6fe 100644
--- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpServer.cs
+++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpServer.cs
@@ -387,13 +387,16 @@ namespace PepperDash.Core
myTcpServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5);
// myTcpServer.HandshakeTimeout = 30;
- myTcpServer.SocketStatusChange += new TCPServerSocketStatusChangeEventHandler(TcpServer_SocketStatusChange);
}
else
{
KillServer();
myTcpServer.PortNumber = Port;
}
+
+ myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange;
+ myTcpServer.SocketStatusChange += TcpServer_SocketStatusChange;
+
ServerStopped = false;
myTcpServer.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback);
OnServerStateChange(myTcpServer.State);
diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs
index a67a05f..5b1bf3f 100644
--- a/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs
+++ b/Pepperdash Core/Pepperdash Core/Comm/GenericUdpServer.cs
@@ -1,231 +1,311 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-
-using Crestron.SimplSharp;
-using Crestron.SimplSharp.CrestronSockets;
-
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-
-namespace PepperDash.Core
-{
- public class GenericUdpServer : Device, IBasicCommunication
- {
- ///
- ///
- ///
- public event EventHandler BytesReceived;
-
- ///
- ///
- ///
- public event EventHandler TextReceived;
-
- ///
- ///
- ///
- //public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
- public event EventHandler ConnectionChange;
-
- public SocketStatus ClientStatus
- {
- get
- {
- return 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;
- }
-
- ///
- /// Defaults to 2000
- ///
- 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;
-
- 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();
- }
- }
-
- ///
- /// Enables the UDP Server
- ///
- 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);
- }
-
- ///
- /// Disabled the UDP Server
- ///
- public void Disconnect()
- {
- if(Server != null)
- Server.DisableUDPServer();
-
- IsConnected = false;
- }
-
-
- ///
- /// Recursive method to receive data
- ///
- ///
- ///
- 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);
- }
-
- ///
- /// General send method
- ///
- ///
- 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; }
-
- ///
- /// Defaults to 32768
- ///
- public int BufferSize { get; set; }
-
- public UdpServerPropertiesConfig()
- {
- BufferSize = 32768;
- }
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Crestron.SimplSharp;
+using Crestron.SimplSharp.CrestronSockets;
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+
+
+
+namespace PepperDash.Core
+{
+ public class GenericUdpServer : Device, IBasicCommunication
+ {
+ ///
+ ///
+ ///
+ 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;
+
+ ///
+ /// Queue to temporarily store received messages with the source IP and Port info
+ ///
+ private CrestronQueue MessageQueue;
+
+ ///
+ ///
+ ///
+ //public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
+ public event EventHandler ConnectionChange;
+
+ public SocketStatus ClientStatus
+ {
+ get
+ {
+ return Server.ServerStatus;
+ }
+ }
+
+
+ CCriticalSection DequeueLock;
+ ///
+ /// Address of server
+ ///
+ public string Hostname { get; set; }
+
+ ///
+ /// IP Address of the sender of the last recieved message
+ ///
+
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// Defaults to 2000
+ ///
+ 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();
+
+ 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();
+ }
+ }
+
+ ///
+ /// Enables the UDP Server
+ ///
+ 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);
+ }
+
+ ///
+ /// Disabled the UDP Server
+ ///
+ public void Disconnect()
+ {
+ if(Server != null)
+ Server.DisableUDPServer();
+
+ IsConnected = false;
+ }
+
+
+ ///
+ /// Recursive method to receive data
+ ///
+ ///
+ ///
+ 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);
+
+ // Attempt to enter the CCritical Secion and if we can, start the dequeue thread
+ var gotLock = DequeueLock.TryEnter();
+ if (gotLock)
+ CrestronInvoke.BeginInvoke((o) => DequeueEvent());
+ }
+
+ ///
+ /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently.
+ /// It will dequeue items as they are enqueued automatically.
+ ///
+ void DequeueEvent()
+ {
+ try
+ {
+ while (true)
+ {
+ // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather.
+ var message = MessageQueue.Dequeue();
+ var dataRecivedExtra = DataRecievedExtra;
+ if (dataRecivedExtra != null)
+ {
+ dataRecivedExtra(this, message);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Debug.Console(0, "GenericUdpServer DequeueEvent error: {0}\r", e);
+ }
+ finally
+ {
+ // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it.
+ DequeueLock.Leave();
+ }
+ }
+
+ ///
+ /// General send method
+ ///
+ ///
+ 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 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;
+ }
+ }
}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj
index f9584be..8a033a2 100644
--- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj
+++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj
@@ -59,7 +59,7 @@
False
- ..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll
+ ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll
diff --git a/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs b/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs
index 658a74f..973cc52 100644
--- a/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs
+++ b/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs
@@ -4,4 +4,4 @@
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Pepperdash_Core")]
[assembly: AssemblyCopyright("Copyright © PepperDash 2019")]
-[assembly: AssemblyVersion("1.0.16.*")]
+[assembly: AssemblyVersion("1.0.17.*")]