public bool TryReadFrame(ref ReadOnlySequence <byte> buffer, out Frame frame) { var sequenceReader = new SequenceReader <byte>(buffer); frame = Frame.InvalidFrame; if (!headerReader.TryReadHeader(ref sequenceReader, out var header)) { return(false); } var frameSizeIncludingOpeningAndEndingFlags = header.FrameSize + 2; // Ensure that we have a complete frame. if (sequenceReader.Remaining < (frameSizeIncludingOpeningAndEndingFlags - sequenceReader.Consumed)) { return(false); } /// Check var frameBody = sequenceReader.Sequence.Slice(header.StartPosition, header.FrameSize - FRAME_CHECK_SEQUENCE_LENGTH).ToArray(); var frameCheckSequenceBytes = sequenceReader.Sequence.Slice((header.StartPosition + header.FrameSize) - 2, FRAME_CHECK_SEQUENCE_LENGTH).ToArray(); var frameCheckSequence = (ushort)(frameCheckSequenceBytes[1] << 8 | frameCheckSequenceBytes[0]); if (!cyclicRedundancyChecker.Check(frameCheckSequence, frameBody)) { return(false); } // Advance past the LLC PDU section. Nothing relevant here. sequenceReader.Advance(8); // Skip reading this byte since not all meters sends this byte // 09 which indicates the COSEM datatype "octet-string" is propably found to be redundant as we will always have a timestamp here. if (sequenceReader.TryPeek(out var dataType)) { if (dataType == 0x09) { sequenceReader.Advance(1); } } var timeStamp = dateTimeReader.Read(ref sequenceReader); var payload = payLoadReader.Read(ref sequenceReader); frame = new Frame(header, timeStamp, payload); // Advance past the frame check sequence bytes and the end flag; sequenceReader.Advance(3); return(true); }
public bool TryReadHeader(ref SequenceReader <byte> sequenceReader, out Header header) { header = Header.InvalidHeader; if (!sequenceReader.TryAdvanceTo(START_FLAG)) { return(false); } var headerStartPosition = sequenceReader.Consumed; if (sequenceReader.Remaining < 2) { // We don't have enough bytes to read the frame format field. return(false); } sequenceReader.TryRead(out var firstFrameFormatByte); sequenceReader.TryRead(out var secondFrameFormatByte); int frameFormat = firstFrameFormatByte << 8 | secondFrameFormatByte; // Right shift the frame size and segmentation bit (12 bits) leaving only the frame format type (4 bits). var frameFormatType = frameFormat >> 12; // Get the frame size from the last 11 bits. var frameSize = frameFormat & 0b0000011111111111; if (!TryReadPastAddress(ref sequenceReader) || !TryReadPastAddress(ref sequenceReader)) { return(false); } // Ensure that we have at least the control byte and the two bytes containing the check sum if (sequenceReader.Remaining < 3) { return(false); } // Advance past the control byte sequenceReader.Advance(1); sequenceReader.TryRead(out var firstHeaderCheckSequenceByte); sequenceReader.TryRead(out var secondHeaderCheckSequenceByte); var headerCheckSequence = (ushort)(secondHeaderCheckSequenceByte << 8 | firstHeaderCheckSequenceByte); var headerBody = sequenceReader.Sequence.Slice(headerStartPosition, (sequenceReader.Consumed - headerStartPosition) - 2).ToArray(); if (!cyclicRedundancyChecker.Check(headerCheckSequence, headerBody)) { return(false); } var frameSizeIncludingOpeningAndEndingFlags = frameSize + 2; // Ensure that we have a complete frame. if (sequenceReader.Remaining < (frameSizeIncludingOpeningAndEndingFlags - sequenceReader.Consumed)) { return(false); } var frameBody = sequenceReader.Sequence.Slice(headerStartPosition, frameSize - 2).ToArray(); var frameCheckSequenceBytes = sequenceReader.Sequence.Slice((headerStartPosition - 2) + frameSize, 2).ToArray(); var frameCheckSequence = (ushort)(frameCheckSequenceBytes[1] << 8 | frameCheckSequenceBytes[0]); if (!cyclicRedundancyChecker.Check(frameCheckSequence, frameBody)) { return(false); } var headerSize = sequenceReader.Consumed - headerStartPosition; header = new Header(frameSize, headerStartPosition, headerSize); return(true); }