Skip to content

Commit

Permalink
Finished support for sending messages by typing in Hex values in the Gui
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandKoenig committed Dec 3, 2020
1 parent 0397e71 commit aeedc1c
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
namespace MessageCommunicator.TestGui.Tests
{
[TestClass]
public class ConnectionProfileViewTests
public class ConnectionProfileViewModelTests
{
[TestMethod]
public void SendPlainMessage()
{
var connParams = new ConnectionParameters();
var connProfile = this.BuildFakeConnectionProfile(connParams);
var connProfile = BuildFakeConnectionProfile(connParams);

// Catch outgoing message
string? sentMessage = null;
Expand All @@ -39,7 +39,7 @@ public void SendPlainMessage()
public void SendEscapedMessage()
{
var connParams = new ConnectionParameters();
var connProfile = this.BuildFakeConnectionProfile(connParams);
var connProfile = BuildFakeConnectionProfile(connParams);

// Catch outgoing message
string? sentMessage = null;
Expand All @@ -61,7 +61,7 @@ public void SendEscapedMessage()
public void SendHexMessage()
{
var connParams = new ConnectionParameters();
var connProfile = this.BuildFakeConnectionProfile(connParams);
var connProfile = BuildFakeConnectionProfile(connParams);

// Catch outgoing message
string? sentMessage = null;
Expand All @@ -73,13 +73,13 @@ public void SendHexMessage()
});

var testObject = new ConnectionProfileViewModel(connProfile);
testObject.SendFormattingMode = SendFormattingMode.Hex;
testObject.Command_SendMessage.Execute("DummyMessage \\\\");
testObject.SendFormattingMode = SendFormattingMode.BinaryHex;
testObject.Command_SendMessage.Execute("41 42 43");

Assert.IsTrue(sentMessage == "DummyMessage \\");
Assert.IsTrue(sentMessage == "ABC");
}

private IConnectionProfile BuildFakeConnectionProfile(ConnectionParameters connParams)
private static IConnectionProfile BuildFakeConnectionProfile(ConnectionParameters connParams)
{
var loggingMessages = new ObservableCollection<LoggingMessageWrapper>();
var sendReceiveMessages = new ObservableCollection<LoggingMessageWrapper>();
Expand All @@ -95,6 +95,5 @@ private IConnectionProfile BuildFakeConnectionProfile(ConnectionParameters connP

return connProfile;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace MessageCommunicator.TestGui.Data
{
public interface IMessageRecognizerAppSettings
{
public MessageRecognizerSettings CreateLibSettings();
string Encoding { get; }

MessageRecognizerSettings CreateLibSettings();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Reactive;
using System.Text;
using System.Text.RegularExpressions;
using MessageCommunicator.TestGui.Logic;
using MessageCommunicator.Util;
using ReactiveUI;

namespace MessageCommunicator.TestGui.Views
Expand Down Expand Up @@ -99,7 +101,7 @@ public ConnectionProfileViewModel(IConnectionProfile connProfile)
{
try
{
if (message == null) { message = string.Empty; }
message ??= string.Empty;

switch (this.SendFormattingMode)
{
Expand All @@ -110,9 +112,13 @@ public ConnectionProfileViewModel(IConnectionProfile connProfile)
message = Regex.Unescape(message);
break;

case SendFormattingMode.Hex:

case SendFormattingMode.BinaryHex:
var encoding = Encoding.GetEncoding(this.Model.Parameters.RecognizerSettings.Encoding);
message = encoding.GetString(HexFormatUtil.ToByteArray(message));
break;

default:
throw new InvalidOperationException($"Unhandled {nameof(Views.SendFormattingMode)} {this.SendFormattingMode}!");
}

await this.Model.SendMessageAsync(message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public enum SendFormattingMode

Escaped,

Hex
BinaryHex
}
}
103 changes: 103 additions & 0 deletions MessageCommunicator.Tests/HexFormatUtilTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MessageCommunicator.Util;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MessageCommunicator.Tests
{
[TestClass]
public class HexFormatUtilTests
{
[TestMethod]
public void BytesToHexString()
{
var testArray = new byte[] {1, 2, 3, 16, 17, 255};

var hexString = HexFormatUtil.ToHexString(testArray);

Assert.IsTrue(hexString == "01 02 03 10 11 FF");
}

[TestMethod]
public void HexStringToBytes()
{
var hexString = "01 02 03 10 11 FF";

var byteArray = HexFormatUtil.ToByteArray(hexString);

Assert.IsTrue(byteArray.Length == 6);
Assert.IsTrue(byteArray[0] == 1);
Assert.IsTrue(byteArray[1] == 2);
Assert.IsTrue(byteArray[2] == 3);
Assert.IsTrue(byteArray[3] == 16);
Assert.IsTrue(byteArray[4] == 17);
Assert.IsTrue(byteArray[5] == 255);
}

[TestMethod]
public void HexStringToBytes_WithoutSpaces()
{
var hexString = "0102031011FF";

var byteArray = HexFormatUtil.ToByteArray(hexString);

Assert.IsTrue(byteArray.Length == 6);
Assert.IsTrue(byteArray[0] == 1);
Assert.IsTrue(byteArray[1] == 2);
Assert.IsTrue(byteArray[2] == 3);
Assert.IsTrue(byteArray[3] == 16);
Assert.IsTrue(byteArray[4] == 17);
Assert.IsTrue(byteArray[5] == 255);
}

[TestMethod]
public void HexStringToBytes_MixedFormat()
{
var hexString = " 010203 1 011fF ";

var byteArray = HexFormatUtil.ToByteArray(hexString);

Assert.IsTrue(byteArray.Length == 6);
Assert.IsTrue(byteArray[0] == 1);
Assert.IsTrue(byteArray[1] == 2);
Assert.IsTrue(byteArray[2] == 3);
Assert.IsTrue(byteArray[3] == 16);
Assert.IsTrue(byteArray[4] == 17);
Assert.IsTrue(byteArray[5] == 255);
}

[TestMethod]
public void HexStringToBytes_EmptyString()
{
var hexString = string.Empty;

var byteArray = HexFormatUtil.ToByteArray(hexString);

Assert.IsTrue(byteArray.Length == 0);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void HexStringToBytes_NullString()
{
HexFormatUtil.ToByteArray(null!);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void HexStringToBytes_InvalidCharCount()
{
HexFormatUtil.ToByteArray("01 0");
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void HexStringToBytes_InvalidCharacter()
{
HexFormatUtil.ToByteArray("t");
}
}
}
105 changes: 105 additions & 0 deletions MessageCommunicator/Util/HexFormatUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text;
using Light.GuardClauses;

namespace MessageCommunicator.Util
{
public static class HexFormatUtil
{
private const string HEX_ALPHABET = "0123456789ABCDEF";

public static string ToHexString(byte[] bytes)
{
return ToHexString(new ArraySegment<byte>(bytes, 0, bytes.Length));
}

public static string ToHexString(ArraySegment<byte> bytes)
{
bytes.MustNotBeDefault(nameof(bytes));

if (bytes.Count == 0) { return string.Empty; }

var length = bytes.Count;
if (length > 1) { length += (length - 1); }
var stringBuffer = StringBuffer.Acquire(length);
var bytesSpan = bytes.AsSpan();
try
{
for (var loop = 0; loop < bytesSpan.Length; loop++)
{
if(stringBuffer.Count > 0){ stringBuffer.Append(' '); }

var actByte = bytesSpan[loop];
stringBuffer.Append(HEX_ALPHABET[actByte >> 4]);
stringBuffer.Append(HEX_ALPHABET[actByte & 0xF]);
}

return stringBuffer.ToString();
}
finally
{
StringBuffer.Release(stringBuffer);
}
}

public static unsafe byte[] ToByteArray(string hexString)
{
hexString.MustNotBeNull(nameof(hexString));

// Count hex characters
var hexCharCount = 0;
for (var loop = 0; loop < hexString.Length; loop++)
{
if(hexString[loop] == ' '){ continue; }
hexCharCount++;
}
if (hexCharCount == 0) { return new byte[0]; }
if (hexCharCount % 2 != 0)
{
throw new ArgumentException("Provided uneven count of hex characters!", nameof(hexString));
}

// Parse all bytes
var result = new byte[hexCharCount / 2];
var resultPos = 0;
var hexPos = 0;
var hexValues = stackalloc int[2];
for (var loop = 0; loop < hexString.Length; loop++)
{
if(hexString[loop] == ' '){ continue; }

var asciiValue = (int) (hexString[loop]);
if ((asciiValue > 47) && (asciiValue < 58))
{
// 0, 1, 2...
hexValues[hexPos] = asciiValue - 48;
}
else if ((asciiValue > 64) && (asciiValue < 71))
{
// A, B, C...
hexValues[hexPos] = (asciiValue - 65) + 10;
}
else if ((asciiValue > 96) && (asciiValue < 103))
{
// a, b, c...
hexValues[hexPos] = (asciiValue - 97) + 10;
}
else
{
throw new ArgumentException($"Invalid hex sign '{hexString[loop]}' at position {loop}!", nameof(hexString));
}

hexPos++;
if (hexPos == 2)
{
result[resultPos] = (byte)(hexValues[0] * 16 + hexValues[1]);
resultPos++;
hexPos = 0;
}
}

return result;
}
}
}
31 changes: 0 additions & 31 deletions MessageCommunicator/_ByteStreamHandler/_Tcp/TcpAsyncUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,5 @@ public static void SafeDispose(Socket? socket)

socket = null;
}

public static string ToHexString(ArraySegment<byte> bytes)
{
bytes.MustNotBeDefault(nameof(bytes));

if (bytes.Count == 0) { return string.Empty; }

const string HEX_ALPHABET = "0123456789ABCDEF";

var length = bytes.Count;
if (length > 1) { length += (length - 1); }
var stringBuffer = StringBuffer.Acquire(length);
var bytesSpan = bytes.AsSpan();
try
{
for (var loop = 0; loop < bytesSpan.Length; loop++)
{
if(stringBuffer.Count > 0){ stringBuffer.Append(' '); }

var actByte = bytesSpan[loop];
stringBuffer.Append(HEX_ALPHABET[actByte >> 4]);
stringBuffer.Append(HEX_ALPHABET[actByte & 0xF]);
}

return stringBuffer.ToString();
}
finally
{
StringBuffer.Release(stringBuffer);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ await currentClient.Client.SendAsync(buffer, SocketFlags.None)
{
this.Log(
LoggingMessageType.Info,
StringBuffer.Format("Sent {0} bytes: {1}", buffer.Count, TcpAsyncUtil.ToHexString(buffer)));
StringBuffer.Format("Sent {0} bytes: {1}", buffer.Count, HexFormatUtil.ToHexString(buffer)));
}

return true;
Expand Down Expand Up @@ -342,7 +342,7 @@ private void ProcessReceivedBytes(bool newConnection, byte[] buffer, int receive
{
this.Log(
LoggingMessageType.Info,
StringBuffer.Format("Received {0} bytes: {1}", receiveBuffer.Count, TcpAsyncUtil.ToHexString(receiveBuffer)));
StringBuffer.Format("Received {0} bytes: {1}", receiveBuffer.Count, HexFormatUtil.ToHexString(receiveBuffer)));
}

// Notify received bytes
Expand Down

0 comments on commit aeedc1c

Please sign in to comment.