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(); } }