mirror of
https://github.com/PepperDash/PepperDashCore.git
synced 2026-01-11 19:44:44 +00:00
add XSigUtility from Troy Garner
https://github.com/bitm0de/XSigUtilityLibrary
This commit is contained in:
@@ -122,6 +122,16 @@
|
||||
<Compile Include="WebApi\Presets\Preset.cs" />
|
||||
<Compile Include="WebApi\Presets\User.cs" />
|
||||
<Compile Include="WebApi\Presets\WebApiPasscodeClient.cs" />
|
||||
<Compile Include="XSigUtility\Serialization\IXSigSerialization.cs" />
|
||||
<Compile Include="XSigUtility\Serialization\XSigSerializationException.cs" />
|
||||
<Compile Include="XSigUtility\Tokens\XSigAnalogToken.cs" />
|
||||
<Compile Include="XSigUtility\Tokens\XSigDigitalToken.cs" />
|
||||
<Compile Include="XSigUtility\Tokens\XSigSerialToken.cs" />
|
||||
<Compile Include="XSigUtility\Tokens\XSigToken.cs" />
|
||||
<Compile Include="XSigUtility\Tokens\XSigTokenType.cs" />
|
||||
<Compile Include="XSigUtility\XSigHelpers.cs" />
|
||||
<Compile Include="XSigUtility\XSigTokenStreamReader.cs" />
|
||||
<Compile Include="XSigUtility\XSigTokenStreamWriter.cs" />
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using PepperDash.Core.Intersystem.Tokens;
|
||||
|
||||
namespace PepperDash.Core.Intersystem.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to determine XSig serialization for an object.
|
||||
/// </summary>
|
||||
public interface IXSigSerialization
|
||||
{
|
||||
IEnumerable<XSigToken> Serialize();
|
||||
T Deserialize<T>(IEnumerable<XSigToken> tokens) where T : class, IXSigSerialization;
|
||||
}
|
||||
}
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
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 = 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 + "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace PepperDash.Core.Intersystem.Tokens
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the base class for all XSig datatypes.
|
||||
/// </summary>
|
||||
public abstract class XSigToken
|
||||
{
|
||||
private readonly int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an XSigToken with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Index for the data.</param>
|
||||
protected XSigToken(int index)
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// XSig 1-based index.
|
||||
/// </summary>
|
||||
public int Index
|
||||
{
|
||||
get { return _index; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// XSigToken type.
|
||||
/// </summary>
|
||||
public abstract XSigTokenType TokenType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Generates the XSig bytes for the corresponding token.
|
||||
/// </summary>
|
||||
/// <returns>XSig byte array.</returns>
|
||||
public abstract byte[] GetBytes();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new token if necessary with an updated index based on the specified offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset to adjust the index with.</param>
|
||||
/// <returns>XSigToken</returns>
|
||||
public abstract XSigToken GetTokenWithOffset(int offset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace PepperDash.Core.Intersystem.Tokens
|
||||
{
|
||||
/// <summary>
|
||||
/// XSig token types.
|
||||
/// </summary>
|
||||
public enum XSigTokenType
|
||||
{
|
||||
/// <summary>
|
||||
/// Digital signal datatype.
|
||||
/// </summary>
|
||||
Digital,
|
||||
|
||||
/// <summary>
|
||||
/// Analog signal datatype.
|
||||
/// </summary>
|
||||
Analog,
|
||||
|
||||
/// <summary>
|
||||
/// Serial signal datatype.
|
||||
/// </summary>
|
||||
Serial
|
||||
}
|
||||
}
|
||||
239
Pepperdash Core/Pepperdash Core/XSigUtility/XSigHelpers.cs
Normal file
239
Pepperdash Core/Pepperdash Core/XSigUtility/XSigHelpers.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public static class XSigHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Forces all outputs to 0.
|
||||
/// </summary>
|
||||
/// <returns>Bytes in XSig format for clear outputs trigger.</returns>
|
||||
public static byte[] ClearOutputs()
|
||||
{
|
||||
return new byte[] { 0xFC };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0.
|
||||
/// </summary>
|
||||
/// <returns>Bytes in XSig format for send status trigger.</returns>
|
||||
public static byte[] SendStatus()
|
||||
{
|
||||
return new byte[] { 0xFD };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for an IXSigStateResolver object.
|
||||
/// </summary>
|
||||
/// <param name="xSigSerialization">XSig state resolver.</param>
|
||||
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
|
||||
public static byte[] GetBytes(IXSigSerialization xSigSerialization)
|
||||
{
|
||||
return GetBytes(xSigSerialization, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for an IXSigStateResolver object, with a specified offset.
|
||||
/// </summary>
|
||||
/// <param name="xSigSerialization">XSig state resolver.</param>
|
||||
/// <param name="offset">Offset to which the data will be aligned.</param>
|
||||
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single digital signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based digital index</param>
|
||||
/// <param name="value">Digital data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for digtial information.</returns>
|
||||
public static byte[] GetBytes(int index, bool value)
|
||||
{
|
||||
return GetBytes(index, 0, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single digital signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based digital index</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="value">Digital data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for digtial information.</returns>
|
||||
public static byte[] GetBytes(int index, int offset, bool value)
|
||||
{
|
||||
return new XSigDigitalToken(index + offset, value).GetBytes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple digital signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="values">Digital signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
|
||||
public static byte[] GetBytes(int startIndex, bool[] values)
|
||||
{
|
||||
return GetBytes(startIndex, 0, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple digital signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="values">Digital signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single analog signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based analog index</param>
|
||||
/// <param name="value">Analog data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for analog signal information.</returns>
|
||||
public static byte[] GetBytes(int index, ushort value)
|
||||
{
|
||||
return GetBytes(index, 0, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single analog signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based analog index</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="value">Analog data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for analog signal information.</returns>
|
||||
public static byte[] GetBytes(int index, int offset, ushort value)
|
||||
{
|
||||
return new XSigAnalogToken(index + offset, value).GetBytes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple analog signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="values">Analog signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
|
||||
public static byte[] GetBytes(int startIndex, ushort[] values)
|
||||
{
|
||||
return GetBytes(startIndex, 0, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple analog signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="values">Analog signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single serial signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based serial index</param>
|
||||
/// <param name="value">Serial data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for serial signal information.</returns>
|
||||
public static byte[] GetBytes(int index, string value)
|
||||
{
|
||||
return GetBytes(index, 0, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes for a single serial signal.
|
||||
/// </summary>
|
||||
/// <param name="index">1-based serial index</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="value">Serial data to be encoded</param>
|
||||
/// <returns>Bytes in XSig format for serial signal information.</returns>
|
||||
public static byte[] GetBytes(int index, int offset, string value)
|
||||
{
|
||||
return new XSigSerialToken(index + offset, value).GetBytes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple serial signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="values">Serial signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
|
||||
public static byte[] GetBytes(int startIndex, string[] values)
|
||||
{
|
||||
return GetBytes(startIndex, 0, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get byte sequence for multiple serial signals.
|
||||
/// </summary>
|
||||
/// <param name="startIndex">Starting index of the sequence.</param>
|
||||
/// <param name="offset">Index offset.</param>
|
||||
/// <param name="values">Serial signal value array.</param>
|
||||
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// XSigToken stream reader.
|
||||
/// </summary>
|
||||
public sealed class XSigTokenStreamReader : IDisposable
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _leaveOpen;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// XSigToken stream reader constructor.
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream to read from.</param>
|
||||
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
|
||||
/// <exception cref="T:System.ArgumentException">Stream cannot be read from.</exception>
|
||||
public XSigTokenStreamReader(Stream stream)
|
||||
: this(stream, false) { }
|
||||
|
||||
/// <summary>
|
||||
/// XSigToken stream reader constructor.
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream to read from.</param>
|
||||
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
|
||||
/// <exception cref="ArgumentNullException">Stream is null.</exception>
|
||||
/// <exception cref="ArgumentException">Stream cannot be read from.</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream</param>
|
||||
/// <param name="value">Result</param>
|
||||
/// <returns>True if successful, otherwise false.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read XSig token from the stream.
|
||||
/// </summary>
|
||||
/// <returns>XSigToken</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Offset is less than 0.</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all available XSig tokens from the stream.
|
||||
/// </summary>
|
||||
/// <returns>XSigToken collection.</returns>
|
||||
public IEnumerable<XSigToken> ReadAllXSigTokens()
|
||||
{
|
||||
var tokens = new List<XSigToken>();
|
||||
XSigToken token;
|
||||
while ((token = ReadXSigToken()) != null)
|
||||
tokens.Add(token);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deserialize all XSig data within the stream from the current position.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type to deserialize the information to.</typeparam>
|
||||
/// <returns>Deserialized object.</returns>
|
||||
public T DeserializeStream<T>()
|
||||
where T : class, IXSigSerialization, new()
|
||||
{
|
||||
return new T().Deserialize<T>(ReadAllXSigTokens());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the internal stream if specified to not leave open.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_leaveOpen)
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// XSigToken stream writer.
|
||||
/// </summary>
|
||||
public sealed class XSigTokenStreamWriter : IDisposable
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _leaveOpen;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// XSigToken stream writer constructor.
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream to write to.</param>
|
||||
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
|
||||
/// <exception cref="T:System.ArgumentException">Stream cannot be written to.</exception>
|
||||
public XSigTokenStreamWriter(Stream stream)
|
||||
: this(stream, false) { }
|
||||
|
||||
/// <summary>
|
||||
/// XSigToken stream writer constructor.
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream to write to.</param>
|
||||
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
|
||||
/// <exception cref="ArgumentNullException">Stream is null.</exception>
|
||||
/// <exception cref="ArgumentException">Stream cannot be written to.</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write XSig data gathered from an IXSigStateResolver to the stream.
|
||||
/// </summary>
|
||||
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
|
||||
public void WriteXSigData(IXSigSerialization xSigSerialization)
|
||||
{
|
||||
WriteXSigData(xSigSerialization, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write XSig data gathered from an IXSigStateResolver to the stream.
|
||||
/// </summary>
|
||||
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
|
||||
/// <param name="offset">Index offset for each XSigToken.</param>
|
||||
public void WriteXSigData(IXSigSerialization xSigSerialization, int offset)
|
||||
{
|
||||
if (xSigSerialization == null)
|
||||
throw new ArgumentNullException("xSigSerialization");
|
||||
|
||||
var tokens = xSigSerialization.Serialize();
|
||||
WriteXSigData(tokens, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write XSigToken to the stream.
|
||||
/// </summary>
|
||||
/// <param name="token">XSigToken object.</param>
|
||||
public void WriteXSigData(XSigToken token)
|
||||
{
|
||||
WriteXSigData(token, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write XSigToken to the stream.
|
||||
/// </summary>
|
||||
/// <param name="token">XSigToken object.</param>
|
||||
/// <param name="offset">Index offset for each XSigToken.</param>
|
||||
public void WriteXSigData(XSigToken token, int offset)
|
||||
{
|
||||
WriteXSigData(new[] { token }, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an array of XSigTokens to the stream.
|
||||
/// </summary>
|
||||
/// <param name="tokens">XSigToken objects.</param>
|
||||
public void WriteXSigData(XSigToken[] tokens)
|
||||
{
|
||||
WriteXSigData(tokens.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an enumerable collection of XSigTokens to the stream.
|
||||
/// </summary>
|
||||
/// <param name="tokens">XSigToken objects.</param>
|
||||
public void WriteXSigData(IEnumerable<XSigToken> tokens)
|
||||
{
|
||||
WriteXSigData(tokens, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an enumerable collection of XSigTokens to the stream.
|
||||
/// </summary>
|
||||
/// <param name="tokens">XSigToken objects.</param>
|
||||
/// <param name="offset">Index offset for each XSigToken.</param>
|
||||
public void WriteXSigData(IEnumerable<XSigToken> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the internal stream if specified to not leave open.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_leaveOpen)
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user