diff --git a/Lawo.EmberPlusSharp/Lawo.EmberPlusSharp.csproj b/Lawo.EmberPlusSharp/Lawo.EmberPlusSharp.csproj
index 41eb5496..26ad03a1 100644
--- a/Lawo.EmberPlusSharp/Lawo.EmberPlusSharp.csproj
+++ b/Lawo.EmberPlusSharp/Lawo.EmberPlusSharp.csproj
@@ -179,6 +179,7 @@
+
diff --git a/Lawo.EmberPlusSharp/S101/DeframingStream.cs b/Lawo.EmberPlusSharp/S101/DeframingStream.cs
index 330ddd83..3c48a72a 100644
--- a/Lawo.EmberPlusSharp/S101/DeframingStream.cs
+++ b/Lawo.EmberPlusSharp/S101/DeframingStream.cs
@@ -6,6 +6,7 @@
namespace Lawo.EmberPlusSharp.S101
{
+ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
@@ -19,6 +20,7 @@ namespace Lawo.EmberPlusSharp.S101
///
internal sealed class DeframingStream : BufferStream
{
+ private readonly Action outOfFrameByteReceived;
private State state;
private ushort crc = 0xFFFF;
private readonly Queue decodedQueue = new Queue();
@@ -55,8 +57,9 @@ public sealed override async Task ReadAsync(
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Initializes a new instance of the class.
- internal DeframingStream(ReadBuffer readBuffer) : base(readBuffer, null)
+ internal DeframingStream(ReadBuffer readBuffer, Action outOfFrameByteReceived) : base(readBuffer, null)
{
+ this.outOfFrameByteReceived = outOfFrameByteReceived;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -68,13 +71,15 @@ private bool ReadByte(ReadBuffer readBuffer, byte[] buffer, ref int index)
switch (this.state)
{
case State.BeforeFrame:
- if (currentByte != Frame.BeginOfFrame)
+ if (currentByte == Frame.BeginOfFrame)
{
- this.state = State.AfterFrame;
- throw new S101Exception("Unexpected byte while looking for BOF.");
+ this.state = State.InFrame;
+ }
+ else
+ {
+ this.outOfFrameByteReceived(currentByte);
}
- this.state = State.InFrame;
break;
case State.InFrame:
if (currentByte < Frame.InvalidStart)
diff --git a/Lawo.EmberPlusSharp/S101/EventInfo.cs b/Lawo.EmberPlusSharp/S101/EventInfo.cs
index a946728e..40ec7d87 100644
--- a/Lawo.EmberPlusSharp/S101/EventInfo.cs
+++ b/Lawo.EmberPlusSharp/S101/EventInfo.cs
@@ -14,22 +14,11 @@ namespace Lawo.EmberPlusSharp.S101
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "There's no point in comparing instances of this type.")]
public struct EventInfo
{
- private readonly DateTime? timeUtc;
- private readonly int? number;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
/// Gets the time when the event was logged.
- public DateTime? TimeUtc
- {
- get { return this.timeUtc; }
- }
+ public DateTime? TimeUtc { get; }
/// Gets the number of the event.
- public int? Number
- {
- get { return this.number; }
- }
+ public int? Number { get; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -39,8 +28,8 @@ internal EventInfo(DateTime? timeUtc) : this(timeUtc, null)
internal EventInfo(DateTime? timeUtc, int? number)
{
- this.timeUtc = timeUtc;
- this.number = number;
+ this.TimeUtc = timeUtc;
+ this.Number = number;
}
}
}
diff --git a/Lawo.EmberPlusSharp/S101/MessageDecodingStream.cs b/Lawo.EmberPlusSharp/S101/MessageDecodingStream.cs
index 0f73cac5..c0a3e63a 100644
--- a/Lawo.EmberPlusSharp/S101/MessageDecodingStream.cs
+++ b/Lawo.EmberPlusSharp/S101/MessageDecodingStream.cs
@@ -6,11 +6,12 @@
namespace Lawo.EmberPlusSharp.S101
{
+ using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
- using Lawo.IO;
+ using IO;
/// Transparently decodes a single S101 message.
///
@@ -29,6 +30,7 @@ internal sealed class MessageDecodingStream : NonSeekableStream
private DeframingStream deframingStream;
private readonly ReadBuffer deframedBuffer;
private readonly byte[] discardBuffer;
+ private readonly Action outOfFrameByteReceived;
private S101Message message;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -70,9 +72,12 @@ public sealed override Task ReadAsync(
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
internal static async Task CreateAsync(
- ReadBuffer rawBuffer, byte[] discardBuffer, CancellationToken cancellationToken)
+ ReadBuffer rawBuffer,
+ byte[] discardBuffer,
+ Action outOfFrameByteReceived,
+ CancellationToken cancellationToken)
{
- var result = new MessageDecodingStream(rawBuffer, discardBuffer);
+ var result = new MessageDecodingStream(rawBuffer, discardBuffer, outOfFrameByteReceived);
var newMessage = await S101Message.ReadFromAsync(result.deframedBuffer, cancellationToken);
if ((newMessage != null) && newMessage.CanHaveMultiplePackets &&
@@ -93,10 +98,10 @@ internal S101Message Message
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private MessageDecodingStream(ReadBuffer rawBuffer, byte[] discardBuffer)
+ private MessageDecodingStream(ReadBuffer rawBuffer, byte[] discardBuffer, Action outOfFrameByteReceived)
{
this.rawBuffer = rawBuffer;
- this.deframingStream = new DeframingStream(this.rawBuffer);
+ this.deframingStream = new DeframingStream(this.rawBuffer, outOfFrameByteReceived);
// This buffer is kept small in size, because a new one is allocated for each message.
// This has the effect that only the bytes of reads <= MessageHeaderMaxLength bytes are actually copied into
@@ -109,6 +114,7 @@ private MessageDecodingStream(ReadBuffer rawBuffer, byte[] discardBuffer)
this.deframedBuffer =
new ReadBuffer((ReadAsyncCallback)this.ReadDeframedAsync, Constants.MessageHeaderMaxLength);
this.discardBuffer = discardBuffer;
+ this.outOfFrameByteReceived = outOfFrameByteReceived;
}
private async Task ReadFromCurrentPacketAsync(
@@ -121,7 +127,7 @@ private async Task ReadFromCurrentPacketAsync(
this.message.CanHaveMultiplePackets && ((this.message.PacketFlags & PacketFlags.LastPacket) == 0))
{
this.deframingStream.Dispose();
- this.deframingStream = new DeframingStream(this.rawBuffer);
+ this.deframingStream = new DeframingStream(this.rawBuffer, this.outOfFrameByteReceived);
this.ValidateMessage(await S101Message.ReadFromAsync(this.deframedBuffer, cancellationToken));
}
diff --git a/Lawo.EmberPlusSharp/S101/MessageEncodingStream.cs b/Lawo.EmberPlusSharp/S101/MessageEncodingStream.cs
index a8fe1da3..cddfef82 100644
--- a/Lawo.EmberPlusSharp/S101/MessageEncodingStream.cs
+++ b/Lawo.EmberPlusSharp/S101/MessageEncodingStream.cs
@@ -42,12 +42,11 @@ public sealed override async Task DisposeAsync(CancellationToken cancellationTok
{
if (this.message.CanHaveMultiplePackets)
{
- await this.CreateFramingStreamAsync(
+ await this.DisposeAndCreateFramingStreamAsync(
PacketFlags.EmptyPacket | PacketFlags.LastPacket, cancellationToken);
}
- await this.unframedBuffer.FlushAsync(cancellationToken);
- await this.framingStream.DisposeAsync(cancellationToken);
+ await this.DisposeFramingStream(cancellationToken);
await this.rawBuffer.FlushAsync(cancellationToken);
await base.DisposeAsync(cancellationToken);
}
@@ -73,7 +72,7 @@ public sealed override async Task WriteAsync(
{
if (this.framingStream.TotalCount >= MaxFrameLength)
{
- await this.CreateFramingStreamAsync(PacketFlags.None, cancellationToken);
+ await this.DisposeAndCreateFramingStreamAsync(PacketFlags.None, cancellationToken);
}
var countToWrite = Math.Min(count, MaxFrameLength - this.framingStream.TotalCount);
@@ -92,6 +91,14 @@ public sealed override async Task FlushAsync(CancellationToken cancellationToken
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ internal async Task WriteOutOfFrameByteAsync(byte value, CancellationToken cancellationToken)
+ {
+ await this.DisposeFramingStream(cancellationToken);
+ await this.rawBuffer.ReserveAsync(1, cancellationToken);
+ this.rawBuffer[this.rawBuffer.Count++] = value;
+ await this.CreateFramingStream(PacketFlags.None, cancellationToken);
+ }
+
internal static async Task CreateAsync(
WriteBuffer rawBuffer, S101Message message, CancellationToken cancellationToken)
{
@@ -114,10 +121,20 @@ private MessageEncodingStream(WriteBuffer rawBuffer, FramingStream framingStream
this.message = message;
}
- private async Task CreateFramingStreamAsync(PacketFlags packetFlags, CancellationToken cancellationToken)
+ private async Task DisposeAndCreateFramingStreamAsync(PacketFlags packetFlags, CancellationToken cancellationToken)
+ {
+ await DisposeFramingStream(cancellationToken);
+ await CreateFramingStream(packetFlags, cancellationToken);
+ }
+
+ private async Task DisposeFramingStream(CancellationToken cancellationToken)
{
await this.unframedBuffer.FlushAsync(cancellationToken);
await this.framingStream.DisposeAsync(cancellationToken);
+ }
+
+ private async Task CreateFramingStream(PacketFlags packetFlags, CancellationToken cancellationToken)
+ {
this.framingStream = await FramingStream.CreateAsync(this.rawBuffer, cancellationToken);
this.message.PacketFlags = packetFlags;
await this.message.WriteToAsync(this.unframedBuffer, cancellationToken);
diff --git a/Lawo.EmberPlusSharp/S101/OutOfFrameByteReceivedEventArgs.cs b/Lawo.EmberPlusSharp/S101/OutOfFrameByteReceivedEventArgs.cs
new file mode 100644
index 00000000..0f600fbd
--- /dev/null
+++ b/Lawo.EmberPlusSharp/S101/OutOfFrameByteReceivedEventArgs.cs
@@ -0,0 +1,33 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2012-2015 Lawo AG (http://www.lawo.com).
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Lawo.EmberPlusSharp.S101
+{
+ using System;
+
+ /// Provides the data for the and
+ /// events.
+ ///
+ public sealed class OutOfFrameByteReceivedEventArgs : EventArgs
+ {
+ private readonly byte value;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /// Gets the message.
+ public byte Value
+ {
+ get { return this.value; }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ internal OutOfFrameByteReceivedEventArgs(byte value)
+ {
+ this.value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Lawo.EmberPlusSharp/S101/S101Client.cs b/Lawo.EmberPlusSharp/S101/S101Client.cs
index 4b7949b3..8926ebed 100644
--- a/Lawo.EmberPlusSharp/S101/S101Client.cs
+++ b/Lawo.EmberPlusSharp/S101/S101Client.cs
@@ -225,6 +225,14 @@ public Task SendMessageAsync(S101Message message, byte[] payload)
return this.SendMessageAsyncCore(message, payload);
}
+ /// Sends as an out-of-frame byte.
+ /// The byte to write.
+ /// equals 0xFE.
+ public Task SendOutOfFrameByte(byte value)
+ {
+ return this.writer.WriteOutOfFrameByte(value, this.source.Token);
+ }
+
/// See .
/// Cancels all communication currently in progress and calls on the
/// connection object passed to the constructor.
@@ -238,6 +246,9 @@ public void Dispose()
/// command.
public event EventHandler EmberDataReceived;
+ /// Occurs when an out-of-frame byte has been received.
+ public event EventHandler OutOfFrameByteReceived;
+
/// Occurs when the connection to the provider has been lost.
///
/// This event is raised in the following situations:
@@ -275,6 +286,7 @@ private async void ReadLoop(IDisposable connection, S101Reader reader)
this.source.Token.Register(() => disposed.SetResult(true));
await this.EnqueueLogOperation(() => this.logger.LogEvent("StartingReadLoop"));
+ reader.OutOfFrameByteReceived += this.OnOutOfFrameByteReceived;
Exception exception;
bool remote = false;
@@ -304,6 +316,7 @@ private async void ReadLoop(IDisposable connection, S101Reader reader)
}
finally
{
+ reader.OutOfFrameByteReceived -= this.OnOutOfFrameByteReceived;
this.DisposeCore(false);
if (connection != null)
@@ -437,6 +450,11 @@ await this.SendMessageAsyncCore(
}
}
+ private void OnOutOfFrameByteReceived(object sender, OutOfFrameByteReceivedEventArgs e)
+ {
+ this.OnEvent(this.OutOfFrameByteReceived, e);
+ }
+
private void OnEvent(EventHandler handler, TEventArgs args) where TEventArgs : EventArgs
{
if (handler != null)
diff --git a/Lawo.EmberPlusSharp/S101/S101Reader.cs b/Lawo.EmberPlusSharp/S101/S101Reader.cs
index 169ea8a3..26967b6a 100644
--- a/Lawo.EmberPlusSharp/S101/S101Reader.cs
+++ b/Lawo.EmberPlusSharp/S101/S101Reader.cs
@@ -29,7 +29,8 @@ public sealed class S101Reader
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Initializes a new instance of the class by calling
- /// S101Reader(, 8192).
+ /// S101Reader(, 8192).
+ ///
[CLSCompliant(false)]
public S101Reader(ReadAsyncCallback readAsync) : this(readAsync, Constants.PhysicalStreamBufferSize)
{
@@ -143,6 +144,9 @@ public bool IsAnotherMessageAvailable
}
}
+ /// Occurs when an out-of-frame byte has been received.
+ public event EventHandler OutOfFrameByteReceived;
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private async Task DisposeCoreAsync(CancellationToken cancellationToken)
@@ -171,10 +175,20 @@ private async Task ReadCoreAsync(CancellationToken cancellationToken)
}
this.stream = await MessageDecodingStream.CreateAsync(
- this.readBuffer, this.discardBuffer, cancellationToken);
+ this.readBuffer, this.discardBuffer, this.OnOutOfFrameByteReceived, cancellationToken);
return this.stream.Message != null;
}
+ private void OnOutOfFrameByteReceived(byte value)
+ {
+ var handler = this.OutOfFrameByteReceived;
+
+ if (handler != null)
+ {
+ handler(this, new OutOfFrameByteReceivedEventArgs(value));
+ }
+ }
+
private void AssertNotDisposed()
{
if (this.disposed)
diff --git a/Lawo.EmberPlusSharp/S101/S101Writer.cs b/Lawo.EmberPlusSharp/S101/S101Writer.cs
index 26e99c6f..5e56aad4 100644
--- a/Lawo.EmberPlusSharp/S101/S101Writer.cs
+++ b/Lawo.EmberPlusSharp/S101/S101Writer.cs
@@ -7,6 +7,7 @@
namespace Lawo.EmberPlusSharp.S101
{
using System;
+ using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -90,6 +91,15 @@ public Task WriteMessageAsync(S101Message message, Cancellati
return this.taskSingleton.Execute(() => this.WriteMessageCoreAsync(message, cancellationToken));
}
+ /// Writes as an out-of-frame byte.
+ /// The byte to write.
+ /// The token to monitor for cancellation requests.
+ /// equals 0xFE.
+ public Task WriteOutOfFrameByte(byte value, CancellationToken cancellationToken)
+ {
+ return this.taskSingleton.Execute(() => this.WriteOutOfFrameByteCore(value, cancellationToken));
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private async Task DisposeCoreAsync(CancellationToken cancellationToken)
@@ -135,6 +145,29 @@ private async Task WriteMessageCoreAsync(
return this.stream;
}
+ private async Task WriteOutOfFrameByteCore(byte value, CancellationToken cancellationToken)
+ {
+ this.AssertNotDisposed();
+
+ if (value == Frame.BeginOfFrame)
+ {
+ var message = string.Format(
+ CultureInfo.InvariantCulture, "A value not equal to {0:X2} is required.", Frame.BeginOfFrame);
+ throw new ArgumentException(message, "value");
+ }
+
+ if ((this.stream == null) || !this.stream.CanWrite)
+ {
+ await this.writeBuffer.ReserveAsync(1, cancellationToken);
+ this.writeBuffer[this.writeBuffer.Count++] = value;
+ await this.writeBuffer.FlushAsync(cancellationToken);
+ }
+ else
+ {
+ await this.stream.WriteOutOfFrameByteAsync(value, cancellationToken);
+ }
+ }
+
private void AssertNotDisposed()
{
if (this.disposed)
diff --git a/Lawo.EmberPlusSharpTest/S101/S101ClientTest.cs b/Lawo.EmberPlusSharpTest/S101/S101ClientTest.cs
index 837f3e14..601a1200 100644
--- a/Lawo.EmberPlusSharpTest/S101/S101ClientTest.cs
+++ b/Lawo.EmberPlusSharpTest/S101/S101ClientTest.cs
@@ -8,6 +8,7 @@ namespace Lawo.EmberPlusSharp.S101
{
using System;
using System.IO;
+ using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -102,20 +103,33 @@ public void EmberDataTest()
var data = new byte[this.Random.Next(512, 16384)];
this.Random.NextBytes(data);
- var received = new TaskCompletionSource();
- EventHandler handler =
+ var emberDataReceived = new TaskCompletionSource();
+ EventHandler emberDataHandler =
(s, e) =>
{
Assert.AreEqual(slot, e.Message.Slot);
Assert.IsInstanceOfType(e.Message.Command, typeof(EmberData));
CollectionAssert.AreEqual(data, e.GetPayload());
- received.SetResult(true);
+ emberDataReceived.SetResult(true);
};
- provider.EmberDataReceived += handler;
+ var outOfFrameByte = GetRandomByteExcept(0xFE);
+ var outOfFrameByteReceived = new TaskCompletionSource();
+ EventHandler outOfFrameByteHandler =
+ (s, e) =>
+ {
+ Assert.AreEqual(outOfFrameByte, e.Value);
+ outOfFrameByteReceived.SetResult(true);
+ };
+
+ provider.EmberDataReceived += emberDataHandler;
+ provider.OutOfFrameByteReceived += outOfFrameByteHandler;
await consumer.SendMessageAsync(new S101Message(slot, EmberDataCommand), data);
- await received.Task;
- provider.EmberDataReceived -= handler;
+ await emberDataReceived.Task;
+ await consumer.SendOutOfFrameByte(outOfFrameByte);
+ await outOfFrameByteReceived.Task;
+ provider.OutOfFrameByteReceived -= outOfFrameByteHandler;
+ provider.EmberDataReceived -= emberDataHandler;
},
() => ConnectAsync(-1, null),
() => WaitForConnectionAsync(null)));
@@ -193,6 +207,7 @@ await AssertThrowAsync(
await AssertThrowAsync(
() => client.SendMessageAsync(null));
await AssertThrowAsync(() => client.SendMessageAsync(EmberDataMessage));
+ await AssertThrowAsync(() => client.SendOutOfFrameByte(0xFE));
client.Dispose();
await AssertThrowAsync(
@@ -223,5 +238,18 @@ public void VersionTest()
null,
null));
}
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ private byte GetRandomByteExcept(params byte[] exceptions)
+ {
+ byte result;
+
+ while (exceptions.Contains(result = (byte)this.Random.Next(byte.MinValue, byte.MaxValue + 1)))
+ {
+ }
+
+ return result;
+ }
}
}
diff --git a/Lawo.EmberPlusSharpTest/S101/S101LoggerTest.cs b/Lawo.EmberPlusSharpTest/S101/S101LoggerTest.cs
index 3c114809..4b66209f 100644
--- a/Lawo.EmberPlusSharpTest/S101/S101LoggerTest.cs
+++ b/Lawo.EmberPlusSharpTest/S101/S101LoggerTest.cs
@@ -10,9 +10,10 @@ namespace Lawo.EmberPlusSharp.S101
using System.Globalization;
using System.IO;
using System.Xml;
- using Lawo.EmberPlusSharp.Glow;
- using Lawo.UnitTesting;
+ using Ember;
+ using Glow;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using UnitTesting;
/// Tests .
[TestClass]
@@ -28,7 +29,8 @@ public void MainTest()
AssertThrow(
() => new S101Logger(null, writer).Dispose(),
() => new S101Logger(GlowTypes.Instance, (TextWriter)null).Dispose(),
- () => new S101Logger(GlowTypes.Instance, (XmlWriter)null).Dispose());
+ () => new S101Logger(GlowTypes.Instance, (XmlWriter)null).Dispose(),
+ () => new S101Logger((IEmberConverter)null, XmlWriter.Create(writer)).Dispose());
using (var logger = new S101Logger(GlowTypes.Instance, writer))
{
diff --git a/Lawo.EmberPlusSharpTest/S101/S101ReaderTest.cs b/Lawo.EmberPlusSharpTest/S101/S101ReaderTest.cs
index deee13e7..f2582648 100644
--- a/Lawo.EmberPlusSharpTest/S101/S101ReaderTest.cs
+++ b/Lawo.EmberPlusSharpTest/S101/S101ReaderTest.cs
@@ -85,8 +85,6 @@ public void ExceptionTest()
() => reader.Message.ToString(), () => reader.Payload.ToString());
}
- await AssertS101Exception("Unexpected byte while looking for BOF.", GetRandomByteExcept(0xFE));
-
await AssertS101Exception("CRC failed.", 0xFE, 0xFF);
await AssertS101Exception("Invalid byte in frame.", 0xFE, 0xFE);
@@ -160,17 +158,6 @@ public void MessageTest()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private byte GetRandomByteExcept(params byte[] exceptions)
- {
- byte result;
-
- while (exceptions.Contains(result = (byte)this.Random.Next(byte.MinValue, byte.MaxValue + 1)))
- {
- }
-
- return result;
- }
-
private static async Task AssertDecode(byte[] bytes, byte[] expectedPayload = null, byte slot = 0x00)
where TCommand : S101Command
{
diff --git a/Lawo.EmberPlusSharpTest/S101/S101WriterTest.cs b/Lawo.EmberPlusSharpTest/S101/S101WriterTest.cs
index a3bf969e..0505e300 100644
--- a/Lawo.EmberPlusSharpTest/S101/S101WriterTest.cs
+++ b/Lawo.EmberPlusSharpTest/S101/S101WriterTest.cs
@@ -10,13 +10,13 @@ namespace Lawo.EmberPlusSharp.S101
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
+ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
- using Lawo.IO;
- using Lawo.Threading.Tasks;
- using Lawo.UnitTesting;
+ using IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Threading.Tasks;
/// Tests .
[TestClass]
@@ -46,6 +46,48 @@ public void WriteTest()
});
}
+ /// Tests .
+ [TestCategory("Unattended")]
+ [TestMethod]
+ public void OutOfFrameByteTest()
+ {
+ AsyncPump.Run(
+ async () =>
+ {
+ using (var asyncStream = new MemoryStream())
+ {
+ var writer = new S101Writer(asyncStream.WriteAsync);
+
+ try
+ {
+ await writer.WriteMessageAsync(
+ new S101Message(0x00, new KeepAliveRequest()), CancellationToken.None);
+ await writer.WriteOutOfFrameByte((byte)this.Random.Next(0xFE), CancellationToken.None);
+ await writer.WriteMessageAsync(
+ new S101Message(0x00, new KeepAliveResponse()), CancellationToken.None);
+
+ using (var encodingStream = await writer.WriteMessageAsync(EmberDataMessage, CancellationToken.None))
+ {
+ var prefix = new byte[] { 0x42 };
+ var postfix = new byte[] { 0x43 };
+ await encodingStream.WriteAsync(prefix, 0, prefix.Length, CancellationToken.None);
+ await writer.WriteOutOfFrameByte(0xEE, CancellationToken.None);
+ await encodingStream.WriteAsync(postfix, 0, postfix.Length, CancellationToken.None);
+ await encodingStream.DisposeAsync(CancellationToken.None);
+ }
+ }
+ finally
+ {
+ await writer.DisposeAsync(CancellationToken.None);
+ }
+
+ var stringBytes =
+ asyncStream.ToArray().Select(b => b.ToString("X2", CultureInfo.InvariantCulture));
+ var result = string.Join(", ", stringBytes).ToUpperInvariant();
+ }
+ });
+ }
+
/// Tests whether random written payload is read back the same.
[TestCategory("Unattended")]
[TestMethod]