diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index b8b715f..c1384f9 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -11,15 +11,18 @@ using Newtonsoft.Json.Linq; namespace PepperDash.Core { + /// + /// A class to handle basic TCP/IP communications with a server + /// public class GenericTcpIpClient : Device, ISocketStatus, IAutoReconnect { /// - /// + /// Fires when data is received from the server and returns it as a Byte array /// public event EventHandler BytesReceived; /// - /// + /// Fires when data is received from the server and returns it as text /// public event EventHandler TextReceived; @@ -72,12 +75,12 @@ namespace PepperDash.Core public int BufferSize { get; set; } /// - /// + /// The actual client class /// public TCPClient Client { get; private set; } /// - /// + /// True if connected to the server /// public bool IsConnected { @@ -93,7 +96,7 @@ namespace PepperDash.Core } /// - /// + /// Status of the socket /// public SocketStatus ClientStatus { @@ -115,23 +118,23 @@ namespace PepperDash.Core } /// - /// + /// Status of the socket /// public string ClientStatusText { get { return ClientStatus.ToString(); } } [Obsolete] /// - /// + /// Ushort representation of client status /// public ushort UClientStatus { get { return (ushort)ClientStatus; } } /// - /// + /// Connection failure reason /// public string ConnectionFailure { get { return ClientStatus.ToString(); } } /// - /// + /// If true, enables AutoConnect /// public bool AutoReconnect { get; set; } @@ -164,7 +167,7 @@ namespace PepperDash.Core CTimer RetryTimer; /// - /// + /// Constructor /// /// /// @@ -180,26 +183,10 @@ namespace PepperDash.Core AutoReconnectIntervalMs = 5000; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - - //if (string.IsNullOrEmpty(address)) - //{ - // Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", key); - // return; - //} - //if (port < 1 || port > 65535) - //{ - // { - // Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': Invalid port", key); - // return; - // } - //} - - //Client = new TCPClient(address, port, bufferSize); - //Client.SocketStatusChange += Client_SocketStatusChange; } /// - /// + /// Constructor /// /// public GenericTcpIpClient(string key) @@ -241,18 +228,23 @@ namespace PepperDash.Core } } - //public override bool CustomActivate() - //{ - // return true; - //} - + /// + /// + /// + /// public override bool Deactivate() { - if(Client != null) - Client.SocketStatusChange -= this.Client_SocketStatusChange; + if (Client != null) + { + Client.SocketStatusChange -= this.Client_SocketStatusChange; + DisconnectClient(); + } return true; } + /// + /// Attempts to connect to the server + /// public void Connect() { if (IsConnected) @@ -274,6 +266,7 @@ namespace PepperDash.Core if (Client == null) { Client = new TCPClient(Hostname, Port, BufferSize); + Client.SocketStatusChange -= Client_SocketStatusChange; Client.SocketStatusChange += Client_SocketStatusChange; } DisconnectCalledByUser = false; @@ -281,23 +274,37 @@ namespace PepperDash.Core Client.ConnectToServerAsync(ConnectToServerCallback); // (null); } + /// + /// Attempts to disconnect the client + /// public void Disconnect() { - DisconnectCalledByUser = true; - DisconnectClient(); + if (Client != null) + { + DisconnectCalledByUser = true; + DisconnectClient(); + Client = null; + Debug.Console(1, this, "Disconnected"); + } } + /// + /// Does the actual disconnect business + /// public void DisconnectClient() { if (Client != null) { Debug.Console(1, this, "Disconnecting client"); - //Client.SocketStatusChange -= Client_SocketStatusChange; if(IsConnected) Client.DisconnectFromServer(); } } + /// + /// Callback method for connection attempt + /// + /// void ConnectToServerCallback(TCPClient c) { Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); @@ -305,31 +312,48 @@ namespace PepperDash.Core WaitAndTryReconnect(); } + /// + /// Disconnects, waits and attemtps to connect again + /// void WaitAndTryReconnect() { DisconnectClient(); + + if (Client != null) + { + Debug.Console(1, "Attempting reconnect, status={0}", Client.ClientStatus); + + if (!DisconnectCalledByUser) + RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, AutoReconnectIntervalMs); + } - Debug.Console(1, "Attempting reconnect, status={0}", Client.ClientStatus); - if(!DisconnectCalledByUser) - RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, AutoReconnectIntervalMs); } + /// + /// Recieves incoming data + /// + /// + /// void Receive(TCPClient client, int numBytes) { - if (numBytes > 0) - { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - var bytesHandler = BytesReceived; - if (bytesHandler != null) - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - { - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } - } - Client.ReceiveDataAsync(Receive); + if (client != null) + { + if (numBytes > 0) + { + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + { + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + + client.ReceiveDataAsync(Receive); + } } /// @@ -358,6 +382,10 @@ namespace PepperDash.Core SendText(unescapedText); } + /// + /// Sends Bytes to the server + /// + /// public void SendBytes(byte[] bytes) { //if (Debug.Level == 2) @@ -366,7 +394,11 @@ namespace PepperDash.Core Client.SendData(bytes, bytes.Length); } - + /// + /// Socket Status Change Handler + /// + /// + /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) { Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); @@ -393,15 +425,30 @@ namespace PepperDash.Core } } + /// + /// Configuration properties for TCP/SSH Connections + /// public class TcpSshPropertiesConfig { + /// + /// Address to connect to + /// [JsonProperty(Required = Required.Always)] public string Address { get; set; } + /// + /// Port to connect to + /// [JsonProperty(Required = Required.Always)] public int Port { get; set; } + /// + /// Username credential + /// public string Username { get; set; } + /// + /// Passord credential + /// public string Password { get; set; } /// @@ -430,35 +477,4 @@ namespace PepperDash.Core } - //public class TcpIpConfig - //{ - // [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; } - - // /// - // /// Defaults to true - // /// - // public bool AutoReconnect { get; set; } - - // /// - // /// Defaults to 5000ms - // /// - // public int AutoReconnectIntervalMs { get; set; } - - // public TcpIpConfig() - // { - // BufferSize = 32768; - // AutoReconnect = true; - // AutoReconnectIntervalMs = 5000; - // } - //} - } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Logging/Debug.cs b/Pepperdash Core/Pepperdash Core/Logging/Debug.cs index 14da95e..14c6b37 100644 --- a/Pepperdash Core/Pepperdash Core/Logging/Debug.cs +++ b/Pepperdash Core/Pepperdash Core/Logging/Debug.cs @@ -28,6 +28,8 @@ namespace PepperDash.Core public static int Level { get; private set; } + public static bool DoNotLoadOnNextBoot { get; private set; } + static DebugContextCollection Contexts; static int SaveTimeoutMs = 30000; @@ -65,6 +67,9 @@ namespace PepperDash.Core if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) { // Add command to console + CrestronConsole.AddNewConsoleCommand(SetDoNotLoadOnNextBootFromConsole, "donotloadonnextboot", + "donotloadonnextboot:P [true/false]: Should the application load on next boot", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", "appdebug:P [0-2]: Sets the application's console debug message level", ConsoleAccessLevelEnum.AccessOperator); @@ -81,7 +86,12 @@ namespace PepperDash.Core CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; LoadMemory(); - Level = Contexts.GetOrCreateItem("DEFAULT").Level; + + var context = Contexts.GetOrCreateItem("DEFAULT"); + Level = context.Level; + DoNotLoadOnNextBoot = context.DoNotLoadOnNextBoot; + + CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber)); try { @@ -140,6 +150,32 @@ namespace PepperDash.Core } } + /// + /// Callback for console command + /// + /// + public static void SetDoNotLoadOnNextBootFromConsole(string stateString) + { + try + { + if (string.IsNullOrEmpty(stateString.Trim())) + { + CrestronConsole.PrintLine("DoNotLoadOnNextBoot = {0}", DoNotLoadOnNextBoot); + return; + } + + SetDoNotLoadOnNextBoot(Boolean.Parse(stateString)); + } + catch + { + CrestronConsole.PrintLine("Usage: donotloadonnextboot:P [true/false]"); + } + } + + /// + /// Callback for console command + /// + /// public static void SetDebugFilterFromConsole(string items) { var str = items.Trim(); @@ -237,6 +273,20 @@ namespace PepperDash.Core } } + /// + /// Sets the flag to prevent application starting on next boot + /// + /// + public static void SetDoNotLoadOnNextBoot(bool state) + { + DoNotLoadOnNextBoot = state; + Contexts.GetOrCreateItem("DEFAULT").DoNotLoadOnNextBoot = state; + SaveMemoryOnTimeout(); + + CrestronConsole.PrintLine("[Application {0}], Do Not Start on Next Boot set to {1}", + InitialParametersClass.ApplicationNumber, DoNotLoadOnNextBoot); + } + /// /// /// diff --git a/Pepperdash Core/Pepperdash Core/Logging/DebugMemory.cs b/Pepperdash Core/Pepperdash Core/Logging/DebugMemory.cs index 82ad51f..6dcb65f 100644 --- a/Pepperdash Core/Pepperdash Core/Logging/DebugMemory.cs +++ b/Pepperdash Core/Pepperdash Core/Logging/DebugMemory.cs @@ -47,9 +47,19 @@ namespace PepperDash.Core.DebugThings public class DebugContextItem { + /// + /// The level of debug messages to print + /// [JsonProperty("level")] public int Level { get; set; } + /// + /// Property to tell the program not to intitialize when it boots, if desired + /// + [JsonProperty("doNotLoadOnNextBoot")] + public bool DoNotLoadOnNextBoot { get; set; } + + public DebugContextItem(DebugContextCollection parent) {