using Sick.SafetyScanners.DataStructures; using Sick.SafetyScanners.Helpers; using System.Net; namespace Sick.SafetyScanners.DataProcessing; /// /// Parser for MeasurementPersistentConfigData response from COLA2 variable command /// Thread-safe implementation /// public sealed class ParseMeasurementPersistentConfigData { private const double AngleResolution = 4194304.0; // Sensor units per radian /// /// Parses the persistent measurement config from a TCP sequence (COLA2 response) /// Matches: ParseMeasurementPersistentConfigData::parseTCPSequence in C++ /// public ConfigData ParseTcpSequence(PacketBuffer buffer) { var span = buffer.GetBufferSpan(); var features = ReadFeatures(span); return new ConfigData { VersionCVersion = ReadVersionIndicator(span), VersionMajorVersionNumber = ReadMajorNumber(span), VersionMinorVersionNumber = ReadMinorNumber(span), VersionReleaseNumber = ReadReleaseNumber(span), Enabled = ReadEnabled(span), EInterfaceType = (InterfaceType)ReadInterfaceType(span), HostIp = ReadHostIp(span), HostUdpPort = ReadHostPort(span), PublishingFrequency = ReadPublishingFreq(span), StartAngle = ConvertToRadians(ReadStartAngle(span)), EndAngle = ConvertToRadians(ReadEndAngle(span)), Features = features, GeneralSystemStateEnabled = SensorDataFeatures.IsFlagSet(features, SensorDataFeatures.GeneralSystemState), DerivedSettingsEnabled = SensorDataFeatures.IsFlagSet(features, SensorDataFeatures.DerivedSettings), MeasurementDataEnabled = SensorDataFeatures.IsFlagSet(features, SensorDataFeatures.MeasurementData), IntrusionDataEnabled = SensorDataFeatures.IsFlagSet(features, SensorDataFeatures.IntrusionData), ApplicationDataEnabled = SensorDataFeatures.IsFlagSet(features, SensorDataFeatures.ApplicationData) }; } /// /// Matches: ParseMeasurementPersistentConfigData::readVersionIndicator in C++ /// private string ReadVersionIndicator(ReadOnlySpan span) { byte ch = ReadWriteHelper.ReadUint8(span, 0); return ((char)ch).ToString(); } /// /// Matches: ParseMeasurementPersistentConfigData::readMajorNumber in C++ /// private byte ReadMajorNumber(ReadOnlySpan span) { return ReadWriteHelper.ReadUint8(span, 1); } /// /// Matches: ParseMeasurementPersistentConfigData::readMinorNumber in C++ /// private byte ReadMinorNumber(ReadOnlySpan span) { return ReadWriteHelper.ReadUint8(span, 2); } /// /// Matches: ParseMeasurementPersistentConfigData::readReleaseNumber in C++ /// private byte ReadReleaseNumber(ReadOnlySpan span) { return ReadWriteHelper.ReadUint8(span, 3); } /// /// Matches: ParseMeasurementPersistentConfigData::readEnabled in C++ /// private bool ReadEnabled(ReadOnlySpan span) { return ReadWriteHelper.ReadUint8(span, 4) != 0; } /// /// Matches: ParseMeasurementPersistentConfigData::readInterfaceType in C++ /// private byte ReadInterfaceType(ReadOnlySpan span) { return ReadWriteHelper.ReadUint8(span, 5); } private string ReadHostIp(ReadOnlySpan span) { uint word = ReadWriteHelper.ReadUint32LittleEndian(span, 8); // Convert uint32 (little endian from packet) to IP address bytes // IPAddress constructor expects bytes in network byte order (big endian) // word is little endian: [b0, b1, b2, b3] represents IP b0.b1.b2.b3 // We need to extract bytes in order: b0, b1, b2, b3 byte[] ipBytes = new byte[4]; ipBytes[0] = (byte)(word & 0xFF); ipBytes[1] = (byte)((word >> 8) & 0xFF); ipBytes[2] = (byte)((word >> 16) & 0xFF); ipBytes[3] = (byte)((word >> 24) & 0xFF); var address = new IPAddress(ipBytes); return address.ToString(); } private ushort ReadHostPort(ReadOnlySpan span) { return ReadWriteHelper.ReadUint16LittleEndian(span, 12); } private ushort ReadPublishingFreq(ReadOnlySpan span) { return ReadWriteHelper.ReadUint16LittleEndian(span, 14); } private uint ReadStartAngle(ReadOnlySpan span) { return ReadWriteHelper.ReadUint32LittleEndian(span, 16); } private uint ReadEndAngle(ReadOnlySpan span) { return ReadWriteHelper.ReadUint32LittleEndian(span, 20); } private ushort ReadFeatures(ReadOnlySpan span) { return ReadWriteHelper.ReadUint16LittleEndian(span, 24); } private double ConvertToRadians(uint sensorUnits) { return (sensorUnits / AngleResolution); } }