diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 17fcebf..9e09430 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -44,7 +44,7 @@ jobs:
shell: powershell
run: |
$version = ./.github/scripts/GenerateVersionNumber.ps1
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
# Use the version number to set the version of the assemblies
- name: Update AssemblyInfo.cs
shell: powershell
@@ -123,7 +123,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
@@ -178,7 +178,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
# Checkout/Create the branch
@@ -255,7 +255,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
# Checkout/Create the branch
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b41e08c..db83b18 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -37,7 +37,7 @@ jobs:
shell: powershell
env:
TAG_NAME: ${{ github.event.release.tag_name }}
- run: Write-Output "::set-env name=VERSION::$($Env:TAG_NAME)"
+ run: echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
# Use the version number to set the version of the assemblies
- name: Update AssemblyInfo.cs
shell: powershell
@@ -98,7 +98,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
@@ -152,7 +152,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
# Checkout/Create the branch
@@ -225,7 +225,7 @@ jobs:
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
- Write-Output "::set-env name=VERSION::$version"
+ echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
# Checkout/Create the branch
diff --git a/Pepperdash Core/Pepperdash Core/Comm/CommunicationStreamDebugging.cs b/Pepperdash Core/Pepperdash Core/Comm/CommunicationStreamDebugging.cs
index f3b5613..b5b1c15 100644
--- a/Pepperdash Core/Pepperdash Core/Comm/CommunicationStreamDebugging.cs
+++ b/Pepperdash Core/Pepperdash Core/Comm/CommunicationStreamDebugging.cs
@@ -79,10 +79,7 @@ namespace PepperDash.Core
_DebugTimeoutInMs = minutes * 60000;
- if (DebugExpiryPeriod != null)
- {
- DisableDebugging();
- }
+ StopDebugTimer();
DebugExpiryPeriod = new CTimer((o) => DisableDebugging(), _DebugTimeoutInMs);
@@ -101,14 +98,24 @@ namespace PepperDash.Core
///
private void DisableDebugging()
{
- DebugExpiryPeriod.Stop();
- DebugExpiryPeriod.Dispose();
- DebugExpiryPeriod = null;
+ StopDebugTimer();
+ Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off);
+ }
+
+ private void StopDebugTimer()
+ {
RxStreamDebuggingIsEnabled = false;
TxStreamDebuggingIsEnabled = false;
- Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off);
+ if (DebugExpiryPeriod == null)
+ {
+ return;
+ }
+
+ DebugExpiryPeriod.Stop();
+ DebugExpiryPeriod.Dispose();
+ DebugExpiryPeriod = null;
}
}
@@ -123,4 +130,4 @@ namespace PepperDash.Core
Tx = 2,
Both = Rx | Tx
}
-}
\ No newline at end of file
+}
diff --git a/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs b/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs
index 5a7a6ea..4e5d2eb 100644
--- a/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs
+++ b/Pepperdash Core/Pepperdash Core/Comm/eControlMethods.cs
@@ -11,6 +11,6 @@ namespace PepperDash.Core
///
public enum eControlMethod
{
- None = 0, Com, IpId, IpidTcp, IR, Ssh, Tcpip, Telnet, Cresnet, Cec, Udp
+ None = 0, Com, IpId, IpidTcp, IR, Ssh, Tcpip, Telnet, Cresnet, Cec, Udp, Http, Https, Ws, Wss
}
}
\ 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 d4fbf18..f746202 100644
--- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj
+++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj
@@ -122,6 +122,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/IXSigSerialization.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/IXSigSerialization.cs
new file mode 100644
index 0000000..074d8a5
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/IXSigSerialization.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using PepperDash.Core.Intersystem.Tokens;
+
+namespace PepperDash.Core.Intersystem.Serialization
+{
+ ///
+ /// Interface to determine XSig serialization for an object.
+ ///
+ public interface IXSigSerialization
+ {
+ IEnumerable Serialize();
+ T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization;
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/XSigSerializationException.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/XSigSerializationException.cs
new file mode 100644
index 0000000..f1c50f5
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Serialization/XSigSerializationException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace PepperDash.Core.Intersystem.Serialization
+{
+ public class XSigSerializationException : Exception
+ {
+ public XSigSerializationException() { }
+ public XSigSerializationException(string message) : base(message) { }
+ public XSigSerializationException(string message, Exception inner) : base(message, inner) { }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigAnalogToken.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigAnalogToken.cs
new file mode 100644
index 0000000..41427fe
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigAnalogToken.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace PepperDash.Core.Intersystem.Tokens
+{
+ public sealed class XSigAnalogToken : XSigToken, IFormattable
+ {
+ private readonly ushort _value;
+
+ public XSigAnalogToken(int index, ushort value)
+ : base(index)
+ {
+ // 10-bits available for analog encoded data
+ if (index >= 1024 || index < 0)
+ throw new ArgumentOutOfRangeException("index");
+
+ _value = value;
+ }
+
+ public ushort Value
+ {
+ get { return _value; }
+ }
+
+ public override XSigTokenType TokenType
+ {
+ get { return XSigTokenType.Analog; }
+ }
+
+ public override byte[] GetBytes()
+ {
+ return new[] {
+ (byte)(0xC0 | ((Value & 0xC000) >> 10) | (Index >> 7)),
+ (byte)((Index - 1) & 0x7F),
+ (byte)((Value & 0x3F80) >> 7),
+ (byte)(Value & 0x7F)
+ };
+ }
+
+ public override XSigToken GetTokenWithOffset(int offset)
+ {
+ if (offset == 0) return this;
+ return new XSigAnalogToken(Index + offset, Value);
+ }
+
+ public override string ToString()
+ {
+ return Index + " = 0x" + Value.ToString("X4");
+ }
+
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Value.ToString(format, formatProvider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigDigitalToken.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigDigitalToken.cs
new file mode 100644
index 0000000..f721387
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigDigitalToken.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace PepperDash.Core.Intersystem.Tokens
+{
+ public sealed class XSigDigitalToken : XSigToken
+ {
+ private readonly bool _value;
+
+ public XSigDigitalToken(int index, bool value)
+ : base(index)
+ {
+ // 12-bits available for digital encoded data
+ if (index >= 4096 || index < 0)
+ throw new ArgumentOutOfRangeException("index");
+
+ _value = value;
+ }
+
+ public bool Value
+ {
+ get { return _value; }
+ }
+
+ public override XSigTokenType TokenType
+ {
+ get { return XSigTokenType.Digital; }
+ }
+
+ public override byte[] GetBytes()
+ {
+ return new[] {
+ (byte)(0x80 | (Value ? 0 : 0x20) | (Index >> 7)),
+ (byte)((Index - 1) & 0x7F)
+ };
+ }
+
+ public override XSigToken GetTokenWithOffset(int offset)
+ {
+ if (offset == 0) return this;
+ return new XSigDigitalToken(Index + offset, Value);
+ }
+
+ public override string ToString()
+ {
+ return Index + " = " + (Value ? "High" : "Low");
+ }
+
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return Value.ToString(formatProvider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigSerialToken.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigSerialToken.cs
new file mode 100644
index 0000000..cc61b1f
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigSerialToken.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Text;
+
+namespace PepperDash.Core.Intersystem.Tokens
+{
+ public sealed class XSigSerialToken : XSigToken
+ {
+ private readonly string _value;
+
+ public XSigSerialToken(int index, string value)
+ : base(index)
+ {
+ // 10-bits available for serial encoded data
+ if (index >= 1024 || index < 0)
+ throw new ArgumentOutOfRangeException("index");
+
+ _value = value;
+ }
+
+ public string Value
+ {
+ get { return _value; }
+ }
+
+ public override XSigTokenType TokenType
+ {
+ get { return XSigTokenType.Serial; }
+ }
+
+ public override byte[] GetBytes()
+ {
+ var serialBytes = String.IsNullOrEmpty(Value) ? new byte[0] : Encoding.GetEncoding(28591).GetBytes(Value);
+
+ var xsig = new byte[serialBytes.Length + 3];
+ xsig[0] = (byte)(0xC8 | (Index >> 7));
+ xsig[1] = (byte)((Index - 1) & 0x7F);
+ xsig[xsig.Length - 1] = 0xFF;
+
+ Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length);
+ return xsig;
+ }
+
+ public override XSigToken GetTokenWithOffset(int offset)
+ {
+ if (offset == 0) return this;
+ return new XSigSerialToken(Index + offset, Value);
+ }
+
+ public override string ToString()
+ {
+ return Index + " = \"" + Value + "\"";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigToken.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigToken.cs
new file mode 100644
index 0000000..4c00a2e
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigToken.cs
@@ -0,0 +1,45 @@
+namespace PepperDash.Core.Intersystem.Tokens
+{
+ ///
+ /// Represents the base class for all XSig datatypes.
+ ///
+ public abstract class XSigToken
+ {
+ private readonly int _index;
+
+ ///
+ /// Constructs an XSigToken with the specified index.
+ ///
+ /// Index for the data.
+ protected XSigToken(int index)
+ {
+ _index = index;
+ }
+
+ ///
+ /// XSig 1-based index.
+ ///
+ public int Index
+ {
+ get { return _index; }
+ }
+
+ ///
+ /// XSigToken type.
+ ///
+ public abstract XSigTokenType TokenType { get; }
+
+ ///
+ /// Generates the XSig bytes for the corresponding token.
+ ///
+ /// XSig byte array.
+ public abstract byte[] GetBytes();
+
+ ///
+ /// Returns a new token if necessary with an updated index based on the specified offset.
+ ///
+ /// Offset to adjust the index with.
+ /// XSigToken
+ public abstract XSigToken GetTokenWithOffset(int offset);
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigTokenType.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigTokenType.cs
new file mode 100644
index 0000000..26d6c12
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/Tokens/XSigTokenType.cs
@@ -0,0 +1,23 @@
+namespace PepperDash.Core.Intersystem.Tokens
+{
+ ///
+ /// XSig token types.
+ ///
+ public enum XSigTokenType
+ {
+ ///
+ /// Digital signal datatype.
+ ///
+ Digital,
+
+ ///
+ /// Analog signal datatype.
+ ///
+ Analog,
+
+ ///
+ /// Serial signal datatype.
+ ///
+ Serial
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/XSigHelpers.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigHelpers.cs
new file mode 100644
index 0000000..4ea6f63
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigHelpers.cs
@@ -0,0 +1,239 @@
+using System;
+using System.Linq;
+using Crestron.SimplSharp.CrestronIO;
+using PepperDash.Core.Intersystem.Serialization;
+using PepperDash.Core.Intersystem.Tokens;
+
+/*
+ Digital (2 bytes)
+ 10C##### 0####### (mask = 11000000_10000000b -> 0xC080)
+
+ Analog (4 bytes)
+ 11aa0### 0####### (mask = 11001000_10000000b -> 0xC880)
+ 0aaaaaaa 0aaaaaaa
+
+ Serial (Variable length)
+ 11001### 0####### (mask = 11111000_10000000b -> 0xF880)
+ dddddddd ........ <- up to 252 bytes of serial data (255 - 3)
+ 11111111 <- denotes end of data
+*/
+
+namespace PepperDash.Core.Intersystem
+{
+ ///
+ /// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
+ ///
+ ///
+ /// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal
+ /// the Intersystem Communications (ISC) symbol.
+ ///
+ public static class XSigHelpers
+ {
+ ///
+ /// Forces all outputs to 0.
+ ///
+ /// Bytes in XSig format for clear outputs trigger.
+ public static byte[] ClearOutputs()
+ {
+ return new byte[] { 0xFC };
+ }
+
+ ///
+ /// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0.
+ ///
+ /// Bytes in XSig format for send status trigger.
+ public static byte[] SendStatus()
+ {
+ return new byte[] { 0xFD };
+ }
+
+ ///
+ /// Get bytes for an IXSigStateResolver object.
+ ///
+ /// XSig state resolver.
+ /// Bytes in XSig format for each token within the state representation.
+ public static byte[] GetBytes(IXSigSerialization xSigSerialization)
+ {
+ return GetBytes(xSigSerialization, 0);
+ }
+
+ ///
+ /// Get bytes for an IXSigStateResolver object, with a specified offset.
+ ///
+ /// XSig state resolver.
+ /// Offset to which the data will be aligned.
+ /// Bytes in XSig format for each token within the state representation.
+ public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset)
+ {
+ var tokens = xSigSerialization.Serialize();
+ if (tokens == null) return new byte[0];
+ using (var memoryStream = new MemoryStream())
+ {
+ using (var tokenWriter = new XSigTokenStreamWriter(memoryStream))
+ tokenWriter.WriteXSigData(xSigSerialization, offset);
+
+ return memoryStream.ToArray();
+ }
+ }
+
+ ///
+ /// Get bytes for a single digital signal.
+ ///
+ /// 1-based digital index
+ /// Digital data to be encoded
+ /// Bytes in XSig format for digtial information.
+ public static byte[] GetBytes(int index, bool value)
+ {
+ return GetBytes(index, 0, value);
+ }
+
+ ///
+ /// Get bytes for a single digital signal.
+ ///
+ /// 1-based digital index
+ /// Index offset.
+ /// Digital data to be encoded
+ /// Bytes in XSig format for digtial information.
+ public static byte[] GetBytes(int index, int offset, bool value)
+ {
+ return new XSigDigitalToken(index + offset, value).GetBytes();
+ }
+
+ ///
+ /// Get byte sequence for multiple digital signals.
+ ///
+ /// Starting index of the sequence.
+ /// Digital signal value array.
+ /// Byte sequence in XSig format for digital signal information.
+ public static byte[] GetBytes(int startIndex, bool[] values)
+ {
+ return GetBytes(startIndex, 0, values);
+ }
+
+ ///
+ /// Get byte sequence for multiple digital signals.
+ ///
+ /// Starting index of the sequence.
+ /// Index offset.
+ /// Digital signal value array.
+ /// Byte sequence in XSig format for digital signal information.
+ public static byte[] GetBytes(int startIndex, int offset, bool[] values)
+ {
+ // Digital XSig data is 2 bytes per value
+ const int fixedLength = 2;
+ var bytes = new byte[values.Length * fixedLength];
+ for (var i = 0; i < values.Length; i++)
+ Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength);
+
+ return bytes;
+ }
+
+ ///
+ /// Get bytes for a single analog signal.
+ ///
+ /// 1-based analog index
+ /// Analog data to be encoded
+ /// Bytes in XSig format for analog signal information.
+ public static byte[] GetBytes(int index, ushort value)
+ {
+ return GetBytes(index, 0, value);
+ }
+
+ ///
+ /// Get bytes for a single analog signal.
+ ///
+ /// 1-based analog index
+ /// Index offset.
+ /// Analog data to be encoded
+ /// Bytes in XSig format for analog signal information.
+ public static byte[] GetBytes(int index, int offset, ushort value)
+ {
+ return new XSigAnalogToken(index + offset, value).GetBytes();
+ }
+
+ ///
+ /// Get byte sequence for multiple analog signals.
+ ///
+ /// Starting index of the sequence.
+ /// Analog signal value array.
+ /// Byte sequence in XSig format for analog signal information.
+ public static byte[] GetBytes(int startIndex, ushort[] values)
+ {
+ return GetBytes(startIndex, 0, values);
+ }
+
+ ///
+ /// Get byte sequence for multiple analog signals.
+ ///
+ /// Starting index of the sequence.
+ /// Index offset.
+ /// Analog signal value array.
+ /// Byte sequence in XSig format for analog signal information.
+ public static byte[] GetBytes(int startIndex, int offset, ushort[] values)
+ {
+ // Analog XSig data is 4 bytes per value
+ const int fixedLength = 4;
+ var bytes = new byte[values.Length * fixedLength];
+ for (var i = 0; i < values.Length; i++)
+ Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength);
+
+ return bytes;
+ }
+
+ ///
+ /// Get bytes for a single serial signal.
+ ///
+ /// 1-based serial index
+ /// Serial data to be encoded
+ /// Bytes in XSig format for serial signal information.
+ public static byte[] GetBytes(int index, string value)
+ {
+ return GetBytes(index, 0, value);
+ }
+
+ ///
+ /// Get bytes for a single serial signal.
+ ///
+ /// 1-based serial index
+ /// Index offset.
+ /// Serial data to be encoded
+ /// Bytes in XSig format for serial signal information.
+ public static byte[] GetBytes(int index, int offset, string value)
+ {
+ return new XSigSerialToken(index + offset, value).GetBytes();
+ }
+
+ ///
+ /// Get byte sequence for multiple serial signals.
+ ///
+ /// Starting index of the sequence.
+ /// Serial signal value array.
+ /// Byte sequence in XSig format for serial signal information.
+ public static byte[] GetBytes(int startIndex, string[] values)
+ {
+ return GetBytes(startIndex, 0, values);
+ }
+
+ ///
+ /// Get byte sequence for multiple serial signals.
+ ///
+ /// Starting index of the sequence.
+ /// Index offset.
+ /// Serial signal value array.
+ /// Byte sequence in XSig format for serial signal information.
+ public static byte[] GetBytes(int startIndex, int offset, string[] values)
+ {
+ // Serial XSig data is not fixed-length like the other formats
+ var dstOffset = 0;
+ var bytes = new byte[values.Sum(v => v.Length + 3)];
+ for (var i = 0; i < values.Length; i++)
+ {
+ var data = GetBytes(startIndex++, offset, values[i]);
+ Buffer.BlockCopy(data, 0, bytes, dstOffset, data.Length);
+ dstOffset += data.Length;
+ }
+
+ return bytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamReader.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamReader.cs
new file mode 100644
index 0000000..9d70d02
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamReader.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using Crestron.SimplSharp.CrestronIO;
+using PepperDash.Core.Intersystem.Serialization;
+using PepperDash.Core.Intersystem.Tokens;
+
+namespace PepperDash.Core.Intersystem
+{
+ ///
+ /// XSigToken stream reader.
+ ///
+ public sealed class XSigTokenStreamReader : IDisposable
+ {
+ private readonly Stream _stream;
+ private readonly bool _leaveOpen;
+
+ ///
+ ///
+ /// XSigToken stream reader constructor.
+ ///
+ /// Input stream to read from.
+ /// Stream is null.
+ /// Stream cannot be read from.
+ public XSigTokenStreamReader(Stream stream)
+ : this(stream, false) { }
+
+ ///
+ /// XSigToken stream reader constructor.
+ ///
+ /// Input stream to read from.
+ /// Determines whether to leave the stream open or not.
+ /// Stream is null.
+ /// Stream cannot be read from.
+ public XSigTokenStreamReader(Stream stream, bool leaveOpen)
+ {
+ if (stream == null)
+ throw new ArgumentNullException("stream");
+ if (!stream.CanRead)
+ throw new ArgumentException("The specified stream cannot be read from.");
+
+ _stream = stream;
+ _leaveOpen = leaveOpen;
+ }
+
+ ///
+ /// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order.
+ ///
+ /// Input stream
+ /// Result
+ /// True if successful, otherwise false.
+ public static bool TryReadUInt16BE(Stream stream, out ushort value)
+ {
+ value = 0;
+ if (stream.Length < 2)
+ return false;
+
+ var buffer = new byte[2];
+ stream.Read(buffer, 0, 2);
+ value = (ushort)((buffer[0] << 8) | buffer[1]);
+ return true;
+ }
+
+ ///
+ /// Read XSig token from the stream.
+ ///
+ /// XSigToken
+ /// Offset is less than 0.
+ public XSigToken ReadXSigToken()
+ {
+ ushort prefix;
+ if (!TryReadUInt16BE(_stream, out prefix))
+ return null;
+
+ if ((prefix & 0xF880) == 0xC800) // Serial data
+ {
+ var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F);
+ var n = 0;
+ const int maxSerialDataLength = 252;
+ var chars = new char[maxSerialDataLength];
+ int ch;
+ while ((ch = _stream.ReadByte()) != 0xFF)
+ {
+ if (ch == -1) // Reached end of stream without end of data marker
+ return null;
+
+ chars[n++] = (char)ch;
+ }
+
+ return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n));
+ }
+
+ if ((prefix & 0xC880) == 0xC000) // Analog data
+ {
+ ushort data;
+ if (!TryReadUInt16BE(_stream, out data))
+ return null;
+
+ var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F);
+ var value = ((prefix & 0x3000) << 2) | ((data & 0x7F00) >> 1) | (data & 0x7F);
+ return new XSigAnalogToken((ushort)(index + 1), (ushort)value);
+ }
+
+ if ((prefix & 0xC080) == 0x8000) // Digital data
+ {
+ var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F);
+ var value = (prefix & 0x2000) == 0;
+ return new XSigDigitalToken((ushort)(index + 1), value);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Reads all available XSig tokens from the stream.
+ ///
+ /// XSigToken collection.
+ public IEnumerable ReadAllXSigTokens()
+ {
+ var tokens = new List();
+ XSigToken token;
+ while ((token = ReadXSigToken()) != null)
+ tokens.Add(token);
+
+ return tokens;
+ }
+
+ ///
+ /// Attempts to deserialize all XSig data within the stream from the current position.
+ ///
+ /// Type to deserialize the information to.
+ /// Deserialized object.
+ public T DeserializeStream()
+ where T : class, IXSigSerialization, new()
+ {
+ return new T().Deserialize(ReadAllXSigTokens());
+ }
+
+ ///
+ /// Disposes of the internal stream if specified to not leave open.
+ ///
+ public void Dispose()
+ {
+ if (!_leaveOpen)
+ _stream.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamWriter.cs b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamWriter.cs
new file mode 100644
index 0000000..934f2c2
--- /dev/null
+++ b/Pepperdash Core/Pepperdash Core/XSigUtility/XSigTokenStreamWriter.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using Crestron.SimplSharp.CrestronIO;
+using PepperDash.Core.Intersystem.Serialization;
+using PepperDash.Core.Intersystem.Tokens;
+
+namespace PepperDash.Core.Intersystem
+{
+ ///
+ /// XSigToken stream writer.
+ ///
+ public sealed class XSigTokenStreamWriter : IDisposable
+ {
+ private readonly Stream _stream;
+ private readonly bool _leaveOpen;
+
+ ///
+ ///
+ /// XSigToken stream writer constructor.
+ ///
+ /// Input stream to write to.
+ /// Stream is null.
+ /// Stream cannot be written to.
+ public XSigTokenStreamWriter(Stream stream)
+ : this(stream, false) { }
+
+ ///
+ /// XSigToken stream writer constructor.
+ ///
+ /// Input stream to write to.
+ /// Determines whether to leave the stream open or not.
+ /// Stream is null.
+ /// Stream cannot be written to.
+ public XSigTokenStreamWriter(Stream stream, bool leaveOpen)
+ {
+ if (stream == null)
+ throw new ArgumentNullException("stream");
+ if (!stream.CanWrite)
+ throw new ArgumentException("The specified stream cannot be written to.");
+
+ _stream = stream;
+ _leaveOpen = leaveOpen;
+ }
+
+ ///
+ /// Write XSig data gathered from an IXSigStateResolver to the stream.
+ ///
+ /// IXSigStateResolver object.
+ public void WriteXSigData(IXSigSerialization xSigSerialization)
+ {
+ WriteXSigData(xSigSerialization, 0);
+ }
+
+ ///
+ /// Write XSig data gathered from an IXSigStateResolver to the stream.
+ ///
+ /// IXSigStateResolver object.
+ /// Index offset for each XSigToken.
+ public void WriteXSigData(IXSigSerialization xSigSerialization, int offset)
+ {
+ if (xSigSerialization == null)
+ throw new ArgumentNullException("xSigSerialization");
+
+ var tokens = xSigSerialization.Serialize();
+ WriteXSigData(tokens, offset);
+ }
+
+ ///
+ /// Write XSigToken to the stream.
+ ///
+ /// XSigToken object.
+ public void WriteXSigData(XSigToken token)
+ {
+ WriteXSigData(token, 0);
+ }
+
+ ///
+ /// Write XSigToken to the stream.
+ ///
+ /// XSigToken object.
+ /// Index offset for each XSigToken.
+ public void WriteXSigData(XSigToken token, int offset)
+ {
+ WriteXSigData(new[] { token }, offset);
+ }
+
+ ///
+ /// Writes an array of XSigTokens to the stream.
+ ///
+ /// XSigToken objects.
+ public void WriteXSigData(XSigToken[] tokens)
+ {
+ WriteXSigData(tokens.AsEnumerable());
+ }
+
+ ///
+ /// Write an enumerable collection of XSigTokens to the stream.
+ ///
+ /// XSigToken objects.
+ public void WriteXSigData(IEnumerable tokens)
+ {
+ WriteXSigData(tokens, 0);
+ }
+
+ ///
+ /// Write an enumerable collection of XSigTokens to the stream.
+ ///
+ /// XSigToken objects.
+ /// Index offset for each XSigToken.
+ public void WriteXSigData(IEnumerable tokens, int offset)
+ {
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0.");
+
+ if (tokens != null)
+ {
+ foreach (var token in tokens)
+ {
+ if (token == null) continue;
+ var bytes = token.GetTokenWithOffset(offset).GetBytes();
+ _stream.Write(bytes, 0, bytes.Length);
+ }
+ }
+ }
+
+ ///
+ /// Disposes of the internal stream if specified to not leave open.
+ ///
+ public void Dispose()
+ {
+ if (!_leaveOpen)
+ _stream.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Readme.md b/Readme.md
index ab3ecf9..36f157c 100644
--- a/Readme.md
+++ b/Readme.md
@@ -3,9 +3,11 @@
## [Latest Release](https://github.com/PepperDash/PepperDashCore/releases/latest)
## License
+
Provided under MIT license
## Overview
+
PepperDash Core is an open source Crestron SIMPL# library that can be used in SIMPL# Pro applications such as Essentials or as a standalone library with SIMPL+ wrappers to expose functionality in SIMPL Windows programs.
## Constituent Elements
@@ -13,23 +15,24 @@ PepperDash Core is an open source Crestron SIMPL# library that can be used in SI
- JSON Configuration File reading/writing
- PortalConfigReader
- Generic config classes
-- Communications
- - TCP/IP client and server
- - Secure TCP/IP client and server
- - UDP server
- - SSH client
- - HTTP SSE client
- - HTTP (RESTful client)
+- Communications
+ - TCP/IP client and server
+ - Secure TCP/IP client and server
+ - UDP server
+ - SSH client
+ - HTTP SSE client
+ - HTTP (RESTful client)
- Debugging
- - Console debugging
- - Logging both to Crestron error log as well as a custom log file
+ - Console debugging
+ - Logging both to Crestron error log as well as a custom log file
- System Info
- Reports system and Ethernet information to SIMPL via SIMPL+
- Device Class, IKeyed and IKeyName Interfaces
- - Base level device class that most classes derive from
+ - Base level device class that most classes derive from
- Password Manager
## Minimum Requirements
+
- PepperDash Core runs on any Crestron 3-series processor or Crestron's VC-4 platform.
- To edit and compile the source, Microsoft Visual Studio 2008 Professional with SP1 is required.
- Crestron's Simpl# Plugin is also required (must be obtained from Crestron).
@@ -39,12 +42,16 @@ PepperDash Core is an open source Crestron SIMPL# library that can be used in SI
None
## Utilization
+
PepperDash Core has two main applications:
- 1. As a utility library for SIMPL# Pro applications like [Essentials]([Essentials](https://github.com/PepperDash/Essentials))
- 2. As a library referenced by SIMPL+ wrapper modules in a SIMPL Windows application
+1. As a utility library for SIMPL# Pro applications like [Essentials](<[Essentials](https://github.com/PepperDash/Essentials)>)
+2. As a library referenced by SIMPL+ wrapper modules in a SIMPL Windows application
- ## Documentation
- For detailed documentation, follow this [LINK](https://github.com/PepperDash/PepperDashCore/wiki) to the Wiki.
+## Documentation
+For detailed documentation, follow this [LINK](https://github.com/PepperDash/PepperDashCore/wiki) to the Wiki.
+## XSigUtility
+
+ `XSigUtility` classes included with permission of Troy Garner. See https://github.com/bitm0de/XSigUtilityLibrary for more information