tbf/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/IperlHatProtocol/IperlHatFrameParser.cs
Michal Buzik 865528e344 iPerlASIC - additional parameters.
Add protocolCommons classes and enhance RadioService with support for CalibrationFactor, VersionType, ReadingUnits, and FlipMode operations. Add corresponding unit tests for validation. Update project files.
2026-08-03 15:42:16 +02:00

155 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)
{
if (!IsPrefixValid(data, prefix, end))
return Array.Empty<byte>();
int payloadLength = data.Length - (prefix.Count + end.Count);
if (payloadLength <= 0)
return Array.Empty<byte>();
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)
{
if (data == null ||
prefix == null ||
end == null ||
data.Length < prefix.Count + end.Count)
{
return false;
}
// Check frame prefix.
byte[] commandPrefix = new byte[prefix.Count];
Buffer.BlockCopy(
data,
0,
commandPrefix,
0,
prefix.Count);
if (!StartsWithPrefix(prefix, commandPrefix))
return false;
// Check frame ending.
byte[] commandEnd = new byte[end.Count];
Buffer.BlockCopy(
data,
data.Length - end.Count,
commandEnd,
0,
end.Count);
if (!StartsWithPrefix(end, commandEnd))
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;
}
}
}