diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
index c31a46b8..fad95abf 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
@@ -158,6 +158,7 @@
+
@@ -222,8 +223,10 @@
+
+
@@ -313,6 +316,8 @@
+
+
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/BytesQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/BytesQueue.cs
new file mode 100644
index 00000000..aad96cf1
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/BytesQueue.cs
@@ -0,0 +1,67 @@
+using System;
+using PepperDash.Core;
+
+namespace PepperDash_Essentials_Core.Queues
+{
+ ///
+ /// Byte implementation of Action queue
+ ///
+ public class BytesQueue : IQueue
+ {
+ private readonly IQueue _queue;
+
+ ///
+ /// Constructor for BytesQueue
+ ///
+ /// Key
+ /// Action to process queued bytes
+ public BytesQueue(string key, Action processBytesAction)
+ {
+ _queue = new GenericQueue(key, processBytesAction);
+ }
+
+ ///
+ /// Constructor for BytesQueue
+ ///
+ /// Key
+ /// Action to process queued bytes
+ /// Delay in ms between actions being invoked
+ public BytesQueue(string key, Action processBytesAction, int pacing)
+ {
+ _queue = new GenericQueue(key, processBytesAction, pacing);
+ }
+
+ ///
+ /// Enqueue a byte array to be processed
+ ///
+ /// Byte array to be processed
+ public void Enqueue(byte[] item)
+ {
+ _queue.Enqueue(item);
+ }
+
+ ///
+ /// If the instance has been disposed
+ ///
+ public bool Disposed
+ {
+ get { return _queue.Disposed; }
+ }
+
+ ///
+ /// Key
+ ///
+ public string Key
+ {
+ get { return _queue.Key; }
+ }
+
+ ///
+ /// Disposes of resources
+ ///
+ public void Dispose()
+ {
+ _queue.Dispose();
+ }
+ }
+}
\ 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..6a06cab8
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs
@@ -0,0 +1,156 @@
+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
+ ///
+ /// Type of item to be processed
+ public class GenericQueue : IQueue where T : class
+ {
+ 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
+ /// Action to process items in the queue
+ public GenericQueue(string key, Action processQueueAction)
+ {
+ _key = key;
+ _queue = new CrestronQueue();
+ _worker = new Thread(ProcessQueue, processQueueAction, Thread.eThreadStartOptions.Running);
+
+ CrestronEnvironment.ProgramStatusEventHandler += programEvent =>
+ {
+ if (programEvent != eProgramStatusEventType.Stopping)
+ return;
+
+ Dispose();
+ };
+ }
+
+ ///
+ /// Constructor for generic queue with no pacing
+ ///
+ /// Key
+ /// Action to process items in the queue
+ /// Pacing in ms between actions
+ public GenericQueue(string key, Action processQueueAction, int pacing)
+ : this(key, processQueueAction)
+ {
+ _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)
+ {
+ var action = obj as Action;
+ if (action == null)
+ throw new ArgumentNullException("obj");
+
+ while (true)
+ {
+ T 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());
+ action(item);
+
+ if (_delayEnabled)
+ Thread.Sleep(_delayTime);
+ }
+ catch (Exception ex)
+ {
+ Debug.ConsoleWithLog(0, this, "Caught an exception in the ComsQueue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace);
+ }
+ }
+ else _waitHandle.Wait();
+ }
+
+ return null;
+ }
+
+ ///
+ /// Enqueues an item and processes the queue. If 'null' is enqueued the thread will close and
+ /// the class must be reinstantiated.
+ ///
+ /// Item to be processed
+ public virtual void Enqueue(T 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..9d69f7fa
--- /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/StringQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringQueue.cs
new file mode 100644
index 00000000..2be49f74
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringQueue.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace PepperDash_Essentials_Core.Queues
+{
+ ///
+ /// String implementation of Action Queue
+ ///
+ public class StringQueue : IQueue
+ {
+ private readonly IQueue _queue;
+
+ ///
+ /// Constructor for BytesQueue
+ ///
+ /// Key
+ /// Action to process queued strings
+ public StringQueue(string key, Action processStringAction)
+ {
+ _queue = new GenericQueue(key, processStringAction);
+ }
+
+ ///
+ /// Constructor for StringQueue
+ ///
+ /// Key
+ /// Action to process queued strings
+ /// Delay in ms between actions being invoked
+ public StringQueue(string key, Action processStringAction, int pacing)
+ {
+ _queue = new GenericQueue(key, processStringAction, pacing);
+ }
+
+ ///
+ /// Enqueue a byte array to be processed
+ ///
+ /// Byte array to be processed
+ public void Enqueue(string item)
+ {
+ _queue.Enqueue(item);
+ }
+
+ ///
+ /// Key
+ ///
+ public string Key
+ {
+ get { return _queue.Key; }
+ }
+
+ ///
+ /// Disposes of resources
+ ///
+ public void Dispose()
+ {
+ _queue.Dispose();
+ }
+
+ ///
+ /// If the instance has been disposed
+ ///
+ public bool Disposed
+ {
+ get { return _queue.Disposed; }
+ }
+ }
+}
\ 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..a3c90689
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs
@@ -0,0 +1,104 @@
+using System;
+using Crestron.SimplSharp;
+using PepperDash.Core;
+
+namespace PepperDash_Essentials_Core.Queues
+{
+ public sealed class StringResponseProcessor : IKeyed, IDisposable
+ {
+ private readonly IQueue _queue;
+ private readonly IBasicCommunication _coms;
+ private readonly CommunicationGather _gather;
+
+ private StringResponseProcessor(string key, Action processStringAction)
+ {
+ _queue = new StringQueue(key, processStringAction);
+
+ 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(args.Text);
+ }
+
+ ///
+ /// 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 7c978bd8..22a1dc1d 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
@@ -77,12 +77,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
@@ -92,7 +92,7 @@
False
- ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe
+ ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe
False