using Sick.SafetyScanners.DataStructures;
using Sick.SafetyScanners.Helpers;
using System.Text;
namespace Sick.SafetyScanners.DataProcessing;
///
/// Parser for FieldHeaderData response from COLA2 variable command
/// Thread-safe implementation
///
public sealed class ParseFieldHeaderData
{
///
/// Parses the field header data from a TCP sequence (COLA2 response)
/// Matches: ParseFieldHeaderData::parseTCPSequence in C++
///
public FieldData ParseTcpSequence(PacketBuffer buffer)
{
var span = buffer.GetBufferSpan();
bool valid = IsValid(span);
if (!valid)
{
return new FieldData
{
IsValid = false
};
}
SetFieldType(span, out bool isWarningField, out bool isProtectiveField);
ushort setIndex = ReadSetIndex(span);
uint nameLength = ReadNameLength(span);
return new FieldData
{
IsValid = true,
VersionCVersion = ReadVersionIndicator(span),
VersionMajorVersionNumber = ReadMajorNumber(span),
VersionMinorVersionNumber = ReadMinorNumber(span),
VersionReleaseNumber = ReadReleaseNumber(span),
IsDefined = ReadIsDefined(span),
EvalMethod = ReadEvalMethod(span),
MultiSampling = ReadMultiSampling(span),
ObjectResolution = ReadObjectResolution(span),
FieldSetIndex = setIndex,
NameLength = nameLength,
FieldName = ReadFieldName(span, nameLength),
IsWarningField = isWarningField,
IsProtectiveField = isProtectiveField
};
}
///
/// Matches: ParseFieldHeaderData::isValid in C++
///
private bool IsValid(ReadOnlySpan span)
{
byte byteValue = ReadWriteHelper.ReadUint8(span, 0);
return byteValue == 'R' || byteValue == 'Y';
}
///
/// Matches: ParseFieldHeaderData::setFieldType in C++
///
private void SetFieldType(ReadOnlySpan span, out bool isWarningField, out bool isProtectiveField)
{
byte fieldType = ReadEvalMethod(span);
isWarningField = false;
isProtectiveField = false;
if (fieldType == 4 || fieldType == 14)
{
isProtectiveField = true;
}
else if (fieldType == 5 || fieldType == 15)
{
isWarningField = true;
}
}
///
/// Matches: ParseFieldHeaderData::readVersionIndicator in C++
///
private string ReadVersionIndicator(ReadOnlySpan span)
{
byte ch = ReadWriteHelper.ReadUint8(span, 0);
return ((char)ch).ToString();
}
///
/// Matches: ParseFieldHeaderData::readMajorNumber in C++
///
private byte ReadMajorNumber(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint8(span, 1);
}
///
/// Matches: ParseFieldHeaderData::readMinorNumber in C++
///
private byte ReadMinorNumber(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint8(span, 2);
}
///
/// Matches: ParseFieldHeaderData::readReleaseNumber in C++
///
private byte ReadReleaseNumber(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint8(span, 3);
}
///
/// Matches: ParseFieldHeaderData::readIsDefined in C++
///
private bool ReadIsDefined(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint8(span, 72) != 0;
}
///
/// Matches: ParseFieldHeaderData::readEvalMethod in C++
///
private byte ReadEvalMethod(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint8(span, 73);
}
///
/// Matches: ParseFieldHeaderData::readMultiSampling in C++
///
private ushort ReadMultiSampling(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint16LittleEndian(span, 74);
}
///
/// Matches: ParseFieldHeaderData::readObjectResolution in C++
///
private ushort ReadObjectResolution(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint16LittleEndian(span, 78);
}
///
/// Matches: ParseFieldHeaderData::readSetIndex in C++
///
private ushort ReadSetIndex(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint16LittleEndian(span, 82);
}
///
/// Matches: ParseFieldHeaderData::readNameLength in C++
///
private uint ReadNameLength(ReadOnlySpan span)
{
return ReadWriteHelper.ReadUint32LittleEndian(span, 84);
}
///
/// Matches: ParseFieldHeaderData::readFieldName in C++
///
private string ReadFieldName(ReadOnlySpan span, uint nameLength)
{
var nameBuilder = new StringBuilder((int)nameLength);
for (uint i = 0; i < nameLength; i++)
{
byte ch = ReadWriteHelper.ReadUint8(span, 88 + (int)i);
nameBuilder.Append((char)ch);
}
return nameBuilder.ToString();
}
}