Example #1
0
        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);
        }
Example #2
0
        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);
        }