using Sick.SafetyScanners.DataStructures; using Sick.SafetyScanners.Helpers; namespace Sick.SafetyScanners.DataProcessing; /// /// Parser for incoming TCP packets in COLA2 format /// Thread-safe implementation /// public sealed class ParseTcpPacket { private const int HeaderSize = 18; // COLA2 header size /// /// Gets the expected packet length from the header /// Matches: ParseTCPPacket::getExpectedPacketLength in C++ /// public uint GetExpectedPacketLength(PacketBuffer buffer) { var bufferData = buffer.GetBuffer(); var length = ReadWriteHelper.ReadUint32BigEndian(bufferData.Span, 4); return length + 8; // for STX and Length which is not included in length datafield } /// /// Gets the request ID from the packet header /// Matches: ParseTCPPacket::getRequestID in C++ /// public ushort GetRequestId(PacketBuffer buffer) { var bufferData = buffer.GetBuffer(); return ReadWriteHelper.ReadUint16BigEndian(bufferData.Span, 14); } /// /// Parses the TCP sequence to extract COLA2 header information /// Matches: ParseTCPPacket::parseTCPSequence in C++ /// public ParseResult ParseTcpSequence(PacketBuffer buffer) { var bufferData = buffer.GetBuffer(); var span = bufferData.Span; // Read header fields var stx = ReadWriteHelper.ReadUint32BigEndian(span, 0); var length = ReadWriteHelper.ReadUint32BigEndian(span, 4); var hubCntr = ReadWriteHelper.ReadUint8BigEndian(span, 8); var noc = ReadWriteHelper.ReadUint8BigEndian(span, 9); var sessionId = ReadWriteHelper.ReadUint32BigEndian(span, 10); var requestId = ReadWriteHelper.ReadUint16BigEndian(span, 14); var commandType = ReadWriteHelper.ReadUint8BigEndian(span, 16); var commandMode = ReadWriteHelper.ReadUint8BigEndian(span, 17); // Read data payload (everything after header, starting at offset 20) // Matches: ParseTCPPacket::readData in C++ - returns data from offset 20 ReadOnlyMemory data = ReadOnlyMemory.Empty; if (bufferData.Length >= 20) { var dataStart = 20; data = bufferData[dataStart..]; } return new ParseResult { Stx = stx, Length = length, HubCntr = hubCntr, NoC = noc, SessionId = sessionId, RequestId = requestId, CommandType = commandType, CommandMode = commandMode, ErrorCode = null, Data = data }; } /// /// Result of parsing a TCP packet /// public sealed class ParseResult { public uint Stx { get; init; } public uint Length { get; init; } public byte HubCntr { get; init; } public byte NoC { get; init; } public uint SessionId { get; init; } public ushort RequestId { get; init; } public byte CommandType { get; init; } public byte CommandMode { get; init; } public ushort? ErrorCode { get; init; } public ReadOnlyMemory Data { get; init; } } }