diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs index 9db81122..56b36791 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs @@ -179,7 +179,7 @@ namespace PepperDash.Essentials.Core { public static eDeviceRegistrationUnRegistrationResponse RegisterWithLogging(this GenericBase device, string key) { - var result = device.Register(); + var result = device.Register(); var level = result == eDeviceRegistrationUnRegistrationResponse.Success ? Debug.ErrorLogLevel.Notice : Debug.ErrorLogLevel.Error; Debug.Console(0, level, "Register device result: '{0}', type '{1}', result {2}", key, device, result); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 06978313..ae420105 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -98,12 +98,12 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll False False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll False @@ -113,7 +113,7 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe False @@ -223,8 +223,12 @@ + + + + @@ -239,6 +243,7 @@ + @@ -314,6 +319,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs new file mode 100644 index 00000000..92c97248 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs @@ -0,0 +1,73 @@ +using System; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + /// + /// IBasicCommunication Message for IQueue + /// + public class ComsMessage : IQueueMessage + { + private readonly byte[] _bytes; + private readonly IBasicCommunication _coms; + private readonly string _string; + private readonly bool _isByteMessage; + + /// + /// Constructor for a string message + /// + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, string message) + { + Validate(coms, message); + _coms = coms; + _string = message; + } + + /// + /// Constructor for a byte message + /// + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, byte[] message) + { + Validate(coms, message); + _coms = coms; + _bytes = message; + _isByteMessage = true; + } + + private void Validate(IBasicCommunication coms, object message) + { + if (_coms == null) + throw new ArgumentNullException("coms"); + + if (message == null) + throw new ArgumentNullException("message"); + } + + /// + /// Dispatchs the string/byte[] to the IBasicCommunication specified + /// + public void Dispatch() + { + if (_isByteMessage) + { + _coms.SendBytes(_bytes); + } + else + { + _coms.SendText(_string); + } + } + + /// + /// Shows either the byte[] or string to be sent + /// + public override string ToString() + { + return _bytes != null ? _bytes.ToString() : _string; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs new file mode 100644 index 00000000..1f27fe1e --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs @@ -0,0 +1,144 @@ +using System; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.CrestronThread; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + /// + /// Threadsafe processing of queued items with pacing if required + /// + public class GenericQueue : IQueue + { + private readonly string _key; + protected readonly CrestronQueue _queue; + protected readonly Thread _worker; + protected readonly CEvent _waitHandle = new CEvent(); + + private readonly bool _delayEnabled; + private readonly int _delayTime; + + /// + /// If the instance has been disposed. + /// + public bool Disposed { get; private set; } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + public GenericQueue(string key) + { + _key = key; + _queue = new CrestronQueue(); + _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running); + + CrestronEnvironment.ProgramStatusEventHandler += programEvent => + { + if (programEvent != eProgramStatusEventType.Stopping) + return; + + Dispose(); + }; + } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + /// Pacing in ms between actions + public GenericQueue(string key, int pacing) + : this(key) + { + _delayEnabled = pacing > 0; + _delayTime = pacing; + } + + /// + /// Thread callback + /// + /// The action used to process dequeued items + /// Null when the thread is exited + private object ProcessQueue(object obj) + { + while (true) + { + IQueueMessage item = null; + + if (_queue.Count > 0) + { + item = _queue.Dequeue(); + if (item == null) + break; + } + if (item != null) + { + try + { + Debug.Console(2, this, "Processing queue item: '{0}'", item.ToString()); + item.Dispatch(); + + if (_delayEnabled) + Thread.Sleep(_delayTime); + } + catch (Exception ex) + { + Debug.ConsoleWithLog(0, this, "Caught an exception in the Queue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace); + } + } + else _waitHandle.Wait(); + } + + return null; + } + + public void Enqueue(IQueueMessage item) + { + _queue.Enqueue(item); + _waitHandle.Set(); + } + + /// + /// Disposes the thread and cleans up resources. Thread cannot be restarted once + /// disposed. + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + /// + /// Actually does the disposing. If you override this method, be sure to either call the base implementation + /// or clean up all the resources yourself. + /// + /// set to true unless called from finalizer + protected void Dispose(bool disposing) + { + if (Disposed) + return; + + if (disposing) + { + Enqueue(null); + _worker.Join(); + _waitHandle.Close(); + } + + Disposed = true; + } + + ~GenericQueue() + { + Dispose(false); + } + + /// + /// Key + /// + public string Key + { + get { return _key; } + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs new file mode 100644 index 00000000..852542d5 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + public interface IQueue : IKeyed, IDisposable where T : class + { + void Enqueue(T item); + bool Disposed { get; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs new file mode 100644 index 00000000..ee0d87d2 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs @@ -0,0 +1,7 @@ +namespace PepperDash_Essentials_Core.Queues +{ + public interface IQueueMessage + { + void Dispatch(); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs new file mode 100644 index 00000000..a15f7231 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs @@ -0,0 +1,44 @@ +using System; + +namespace PepperDash_Essentials_Core.Queues +{ + /// + /// Message class for processing strings via an IQueue + /// + public class ProcessStringMessage : IQueueMessage + { + private readonly Action _action; + private readonly string _message; + + /// + /// Constructor + /// + /// Message to be processed + /// Action to invoke on the message + public ProcessStringMessage(string message, Action action) + { + _message = message; + _action = action; + } + + /// + /// Processes the string with the given action + /// + public void Dispatch() + { + if (_action == null || String.IsNullOrEmpty(_message)) + return; + + _action(_message); + } + + /// + /// To string + /// + /// The current message + public override string ToString() + { + return _message ?? String.Empty; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs new file mode 100644 index 00000000..7f6477a3 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs @@ -0,0 +1,106 @@ +using System; +using Crestron.SimplSharp; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + public sealed class StringResponseProcessor : IKeyed, IDisposable + { + private readonly Action _processStringAction; + private readonly IQueue _queue; + private readonly IBasicCommunication _coms; + private readonly CommunicationGather _gather; + + private StringResponseProcessor(string key, Action processStringAction) + { + _processStringAction = processStringAction; + _queue = new GenericQueue(key); + + CrestronEnvironment.ProgramStatusEventHandler += programEvent => + { + if (programEvent != eProgramStatusEventType.Stopping) + return; + + Dispose(); + }; + } + + /// + /// Constructor that builds an instance and subscribes to coms TextReceived for processing + /// + /// Com port to process strings from + /// Action to process the incoming strings + public StringResponseProcessor(IBasicCommunication coms, Action processStringAction) + : this(coms.Key, processStringAction) + { + _coms = coms; + coms.TextReceived += OnResponseReceived; + } + + /// + /// Constructor that builds an instance and subscribes to gather Line Received for processing + /// + /// Gather to process strings from + /// Action to process the incoming strings + public StringResponseProcessor(CommunicationGather gather, Action processStringAction) + : this(gather.Port.Key, processStringAction) + { + _gather = gather; + gather.LineReceived += OnResponseReceived; + } + + private void OnResponseReceived(object sender, GenericCommMethodReceiveTextArgs args) + { + _queue.Enqueue(new ProcessStringMessage(args.Text, _processStringAction)); + } + + /// + /// Key + /// + public string Key + { + get { return _queue.Key; } + } + + /// + /// Disposes the instance and cleans up resources. + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) + return; + + if (disposing) + { + if (_coms != null) + _coms.TextReceived -= OnResponseReceived; + + if (_gather != null) + { + _gather.LineReceived -= OnResponseReceived; + _gather.Stop(); + } + + _queue.Dispose(); + } + + Disposed = true; + } + + /// + /// If the instance has been disposed or not. If it has, you can not use it anymore + /// + public bool Disposed { get; private set; } + + ~StringResponseProcessor() + { + Dispose(false); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials DM/Essentials_DM/PepperDash_Essentials_DM.csproj b/essentials-framework/Essentials DM/Essentials_DM/PepperDash_Essentials_DM.csproj index a8843496..7c8b163a 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/PepperDash_Essentials_DM.csproj +++ b/essentials-framework/Essentials DM/Essentials_DM/PepperDash_Essentials_DM.csproj @@ -68,12 +68,12 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll False False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll False @@ -83,7 +83,7 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe False diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index 00612bab..d18cb6ce 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -73,12 +73,12 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll False False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll False @@ -88,7 +88,7 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe False