132 lines
5.5 KiB
C#
132 lines
5.5 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
|
||
|
|
namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol
|
||
|
|
{
|
||
|
|
public sealed class IperlHatFrameParser
|
||
|
|
{
|
||
|
|
|
||
|
|
public IperlHatResponse Parse(byte[] data)
|
||
|
|
{
|
||
|
|
if (data == null)
|
||
|
|
throw new ArgumentNullException(nameof(data));
|
||
|
|
|
||
|
|
if (data.Length < 5)
|
||
|
|
throw new FormatException("Frame too short.");
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
if (data[0] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start)
|
||
|
|
{
|
||
|
|
//if version parse version
|
||
|
|
if (data[0] == TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question)
|
||
|
|
{
|
||
|
|
//Define Question answer
|
||
|
|
var prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question };
|
||
|
|
var end = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End };
|
||
|
|
|
||
|
|
if (IsPrefixValid(data, prefix, end))
|
||
|
|
{
|
||
|
|
//whole payload may be like "vers: Harry T:B800, V:06.06.01, FW:190215, 7ECE, B1.6.01, HW:4, Serial:0"
|
||
|
|
prefix = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question };
|
||
|
|
byte[] payloadVersion = ExtractPayloadUsePrefix(data, prefix, end);
|
||
|
|
return new IperlHatResponse(TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Question, payloadVersion.Length > 0 ? TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusOk : TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.StatusNok, payloadVersion);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
throw new FormatException("Invalid START byte.");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (data[1] != TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Read)
|
||
|
|
throw new FormatException("Frame is no Response.");
|
||
|
|
|
||
|
|
byte length = data[2];
|
||
|
|
if (length != data.Length)
|
||
|
|
throw new FormatException("Length mismatch.");
|
||
|
|
|
||
|
|
byte direction = data[1];
|
||
|
|
byte status = data[3];
|
||
|
|
|
||
|
|
var prefixCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.Start,direction,length,status };
|
||
|
|
var endCommand = new List<byte>{ TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol.IperlHatProtocolConstants.End };
|
||
|
|
|
||
|
|
byte[] payload = ExtractPayloadUsePrefix(data,prefixCommand,endCommand);
|
||
|
|
|
||
|
|
return new IperlHatResponse(0x00, status, payload);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private static byte[] ExtractPayloadUsePrefix(byte[] data, List<byte> prefix, List<byte> end)
|
||
|
|
{
|
||
|
|
// payload exists only if frame longer than:
|
||
|
|
// START + DIRECTION + LEN + CTRL + END = 5 bytes
|
||
|
|
// OR VERSION_START + VERSION = 5 bytes
|
||
|
|
if (data.Length <= 5)
|
||
|
|
return Array.Empty<byte>();
|
||
|
|
|
||
|
|
//check prefix is equal
|
||
|
|
int prefixLength = prefix.Count;
|
||
|
|
byte[] commandPrefix = new byte[prefixLength];
|
||
|
|
Buffer.BlockCopy(data, 0, commandPrefix, 0, prefixLength);
|
||
|
|
|
||
|
|
if (StartsWithPrefix(end, commandPrefix))
|
||
|
|
{
|
||
|
|
return Array.Empty<byte>();
|
||
|
|
}
|
||
|
|
|
||
|
|
int payloadLength = data.Length - (prefix.Count + end.Count);
|
||
|
|
byte[] payload = new byte[payloadLength];
|
||
|
|
Buffer.BlockCopy(data, prefix.Count, payload, 0, payloadLength);
|
||
|
|
return payload;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool IsPrefixValid(byte[] data, List<byte> prefix, List<byte> end)
|
||
|
|
{
|
||
|
|
int prefixLength = prefix.Count;
|
||
|
|
// payload exists only if frame longer than:
|
||
|
|
// OR VERSION_START + VERSION = 5 bytes - "?VERS" version implemented
|
||
|
|
if (data.Length <= prefixLength) // need be and on END
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//check prefix is equal
|
||
|
|
byte[] commandPrefix = new byte[prefixLength];
|
||
|
|
Buffer.BlockCopy(data, 0, commandPrefix, 0, prefixLength);
|
||
|
|
|
||
|
|
if (StartsWithPrefix(end, commandPrefix))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool StartsWithPrefix(List<byte> data, byte[] prefix)
|
||
|
|
{
|
||
|
|
if (data.Count < prefix.Length)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
for (int i = 0; i < prefix.Length; i++)
|
||
|
|
{
|
||
|
|
if (data[i] != prefix[i])
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static byte[] ExtractVersionPayload(byte[] data)
|
||
|
|
{
|
||
|
|
// payload exists only if frame longer than:
|
||
|
|
// START + LEN + CTRL + STATUS + CHK_HI + CHK_LO = 6 bytes
|
||
|
|
if (data.Length <= 5)
|
||
|
|
return Array.Empty<byte>();
|
||
|
|
|
||
|
|
int payloadLength = data.Length - 4;
|
||
|
|
byte[] payload = new byte[payloadLength];
|
||
|
|
Buffer.BlockCopy(data, 5, payload, 0, payloadLength);
|
||
|
|
return payload;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|