109 lines
4.3 KiB
C#
109 lines
4.3 KiB
C#
using Sick.SafetyScanners.DataStructures;
|
|
|
|
namespace Sick.SafetyScanners.DataProcessing;
|
|
|
|
/// <summary>
|
|
/// Main parser that coordinates parsing of all data blocks from UDP packets
|
|
/// Thread-safe implementation
|
|
/// </summary>
|
|
public sealed class ParseData
|
|
{
|
|
private readonly ParseDataHeader _headerParser;
|
|
private readonly ParseDerivedValues _derivedValuesParser;
|
|
private readonly ParseMeasurementData _measurementDataParser;
|
|
private readonly ParseGeneralSystemState _generalSystemStateParser;
|
|
private readonly ParseIntrusionData _intrusionDataParser;
|
|
private readonly ParseApplicationData _applicationDataParser;
|
|
|
|
/// <summary>
|
|
/// Creates a new ParseData instance
|
|
/// </summary>
|
|
public ParseData()
|
|
{
|
|
_headerParser = new ParseDataHeader();
|
|
_derivedValuesParser = new ParseDerivedValues();
|
|
_measurementDataParser = new ParseMeasurementData();
|
|
_generalSystemStateParser = new ParseGeneralSystemState();
|
|
_intrusionDataParser = new ParseIntrusionData();
|
|
_applicationDataParser = new ParseApplicationData();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses the complete UDP sequence into UdpScanData
|
|
/// </summary>
|
|
public UdpScanData ParseUdpSequence(PacketBuffer buffer)
|
|
{
|
|
if (buffer == null)
|
|
throw new ArgumentNullException(nameof(buffer));
|
|
|
|
// Parse header first (required for all other parsers)
|
|
var header = _headerParser.ParseUdpSequence(buffer);
|
|
|
|
// Validate packet size before parsing other blocks
|
|
ValidatePacketSize(buffer, header);
|
|
|
|
// Parse all data blocks in order
|
|
// 1. DerivedValues (needed for MeasurementData and IntrusionData)
|
|
var derivedValues = _derivedValuesParser.ParseUdpSequence(buffer, header);
|
|
|
|
// 2. MeasurementData (needs DerivedValues for angle calculation)
|
|
var measurementData = _measurementDataParser.ParseUdpSequence(buffer, header, derivedValues);
|
|
|
|
// 3. GeneralSystemState (independent)
|
|
var generalSystemState = _generalSystemStateParser.ParseUdpSequence(buffer, header);
|
|
|
|
// 4. IntrusionData (needs DerivedValues for number of scan points)
|
|
var intrusionData = _intrusionDataParser.ParseUdpSequence(buffer, header, derivedValues);
|
|
|
|
// 5. ApplicationData (independent)
|
|
var applicationData = _applicationDataParser.ParseUdpSequence(buffer, header);
|
|
|
|
return new UdpScanData
|
|
{
|
|
Header = header,
|
|
DerivedValues = derivedValues.IsEmpty ? null : derivedValues,
|
|
MeasurementData = measurementData.IsEmpty ? null : measurementData,
|
|
GeneralSystemState = generalSystemState.IsEmpty ? null : generalSystemState,
|
|
IntrusionData = intrusionData.IsEmpty ? null : intrusionData,
|
|
ApplicationData = applicationData.IsEmpty ? null : applicationData
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses the complete TCP sequence (from COLA2 command response) into UdpScanData
|
|
/// Note: TCP and UDP use the same data structure format, only the transport differs
|
|
/// </summary>
|
|
public UdpScanData ParseTcpSequence(PacketBuffer buffer)
|
|
{
|
|
// TCP sequence uses the same format as UDP for the data payload
|
|
return ParseUdpSequence(buffer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that the packet buffer contains enough data for all enabled blocks
|
|
/// </summary>
|
|
private static void ValidatePacketSize(PacketBuffer buffer, DataHeader header)
|
|
{
|
|
if (header.IsEmpty)
|
|
return;
|
|
|
|
// Calculate expected minimum size
|
|
var expectedSize = (uint)(
|
|
header.DerivedValuesBlockSize +
|
|
header.MeasurementDataBlockSize +
|
|
header.GeneralSystemStateBlockSize +
|
|
header.IntrusionDataBlockSize +
|
|
header.ApplicationDataBlockSize);
|
|
|
|
var actualSize = (uint)buffer.GetBuffer().Length;
|
|
|
|
if (actualSize < expectedSize)
|
|
{
|
|
// Log warning would go here in production
|
|
// For now, we'll let individual parsers handle missing data gracefully
|
|
// by checking block offsets and sizes
|
|
}
|
|
}
|
|
}
|
|
|