Пример #1
0
        /// <summary>
        /// Creates a new <see cref="CommandFrame"/> from the given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Binary image to parse.</param>
        /// <param name="startIndex">Start index into <paramref name="buffer"/> to begin parsing.</param>
        /// <param name="length">Length of valid data within <paramref name="buffer"/>.</param>
        /// <remarks>
        /// This constructor is used by a consumer to parse a received IEEE C37.118 command frame. Typically
        /// command frames are sent to a device. This constructor would used if this code was being used
        /// inside of a phasor measurement device.
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is not large enough to parse frame.</exception>
        public CommandFrame(byte[] buffer, int startIndex, int length)
            : base(new CommandCellCollection(Common.MaximumExtendedDataLength), DeviceCommand.ReservedBits)
        {
            if (length < CommonFrameHeader.FixedLength)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            m_frameHeader = new CommonFrameHeader(null, buffer, startIndex);

            if (m_frameHeader.TypeID != IEEEC37_118.FrameType.CommandFrame)
            {
                throw new InvalidOperationException("Binary image does not represent an IEEE C37.118 command frame");
            }

            if (length < m_frameHeader.FrameLength)
            {
                throw new ArgumentOutOfRangeException("length", string.Format("Buffer size, {0}, is not large enough to parse IEEE C37.118 command frame with a length of {1}", length, m_frameHeader.FrameLength));
            }

            // Validate check-sum
            int sumLength = m_frameHeader.FrameLength - 2;

            if (BigEndian.ToUInt16(buffer, startIndex + sumLength) != CalculateChecksum(buffer, startIndex, sumLength))
            {
                throw new InvalidOperationException("Invalid binary image detected - check sum of " + this.GetType().Name + " did not match");
            }

            m_frameHeader.State = new CommandFrameParsingState(m_frameHeader.FrameLength, m_frameHeader.DataLength, true, true);
            CommonHeader        = m_frameHeader;
            ParseBinaryImage(buffer, startIndex, length);
        }
Пример #2
0
 /// <summary>
 /// Creates a new <see cref="ConfigurationFrame1"/> from serialization parameters.
 /// </summary>
 /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param>
 /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param>
 protected ConfigurationFrame1(SerializationInfo info, StreamingContext context)
     : base(info, context)
 {
     // Deserialize configuration frame
     m_frameHeader = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader));
     m_timebase    = info.GetUInt32("timebase");
 }
Пример #3
0
        /// <summary>
        /// Parses the binary image.
        /// </summary>
        /// <param name="buffer">Binary image to parse.</param>
        /// <param name="startIndex">Start index into <paramref name="buffer"/> to begin parsing.</param>
        /// <param name="length">Length of valid data within <paramref name="buffer"/>.</param>
        /// <returns>The length of the data that was parsed.</returns>
        /// <remarks>
        /// This method is overridden to parse from cumulated frame images.
        /// </remarks>
        public override int ParseBinaryImage(byte[] buffer, int startIndex, int length)
        {
            CommonFrameHeader frameHeader = CommonHeader;

            // Handle normal parsing if configuration frame is not fragmented
            if (frameHeader is null || frameHeader.ContinuationIndex == 0)
            {
                return(base.ParseBinaryImage(buffer, startIndex, length));
            }

            // If all configuration frame images have been received, we can safely start parsing
            if (frameHeader.IsLastFrame)
            {
                using (FrameImageCollector frameImages = frameHeader.FrameImages)
                {
                    if (frameImages is null)
                    {
                        return(State.ParsedBinaryLength);
                    }

                    buffer     = frameImages.BinaryImage;
                    length     = frameImages.BinaryLength;
                    startIndex = 0;

                    // Base class will check CRC for entire image
                    return(base.ParseBinaryImage(buffer, startIndex, length));
                }
            }

            // There are more configuration frame 3 images coming, keep parser moving
            // by returning total frame length that was already parsed (or cumulated).
            return(State.ParsedBinaryLength);
        }
Пример #4
0
        /// <summary>
        /// Parses a common header instance that implements <see cref="ICommonHeader{TTypeIdentifier}"/> for the output type represented
        /// in the binary image.
        /// </summary>
        /// <param name="buffer">Buffer containing data to parse.</param>
        /// <param name="offset">Offset index into buffer that represents where to start parsing.</param>
        /// <param name="length">Maximum length of valid data from offset.</param>
        /// <returns>The <see cref="ICommonHeader{TTypeIdentifier}"/> which includes a type ID for the <see cref="Type"/> to be parsed.</returns>
        /// <remarks>
        /// <para>
        /// Derived classes need to provide a common header instance (i.e., class that implements <see cref="ICommonHeader{TTypeIdentifier}"/>)
        /// for the output types; this will primarily include an ID of the <see cref="Type"/> that the data image represents.  This parsing is
        /// only for common header information, actual parsing will be handled by output type via its <see cref="ISupportBinaryImage.ParseBinaryImage"/>
        /// method. This header image should also be used to add needed complex state information about the output type being parsed if needed.
        /// </para>
        /// <para>
        /// If there is not enough buffer available to parse common header (as determined by <paramref name="length"/>), return null.  Also, if
        /// the protocol allows frame length to be determined at the time common header is being parsed and there is not enough buffer to parse
        /// the entire frame, it will be optimal to prevent further parsing by returning null.
        /// </para>
        /// </remarks>
        protected override ICommonHeader <FrameType> ParseCommonHeader(byte[] buffer, int offset, int length)
        {
            // See if there is enough data in the buffer to parse the common frame header.
            if (length >= CommonFrameHeader.FixedLength)
            {
                // Parse common frame header
                CommonFrameHeader parsedFrameHeader = new CommonFrameHeader(m_configurationFrame2, buffer, offset);

                // Look for probable misaligned bad frame header parse
                if (parsedFrameHeader.FrameType == FundamentalFrameType.Undetermined || parsedFrameHeader.Version > 3)
                {
                    throw new InvalidOperationException("Probable frame misalignment detected, forcing scan ahead to next sync byte");
                }

                // As an optimization, we also make sure entire frame buffer image is available to be parsed - by doing this
                // we eliminate the need to validate length on all subsequent data elements that comprise the frame
                if (length >= parsedFrameHeader.FrameLength)
                {
                    // Expose the frame buffer image in case client needs this data for any reason
                    OnReceivedFrameBufferImage(parsedFrameHeader.FrameType, buffer, offset, parsedFrameHeader.FrameLength);

                    // Handle special parsing states
                    switch (parsedFrameHeader.TypeID)
                    {
                    case FrameType.DataFrame:
                        // Assign data frame parsing state
                        parsedFrameHeader.State = new DataFrameParsingState(parsedFrameHeader.FrameLength, m_configurationFrame2, DataCell.CreateNewCell, TrustHeaderLength, ValidateDataFrameCheckSum);
                        break;

                    case FrameType.ConfigurationFrame1:
                    case FrameType.ConfigurationFrame2:
                        // Assign configuration frame parsing state
                        parsedFrameHeader.State = new ConfigurationFrameParsingState(parsedFrameHeader.FrameLength, ConfigurationCell.CreateNewCell, TrustHeaderLength, ValidateConfigurationFrameCheckSum);
                        break;

                    case FrameType.ConfigurationFrame3:
                        // parsedFrameHeader.State = new ConfigurationFrameParsingState(parsedFrameHeader.FrameLength, ConfigurationCell3.CreateNewCell, TrustHeaderLength, ValidateConfigurationFrameCheckSum);
                        break;

                    case FrameType.HeaderFrame:
                        // Assign header frame parsing state
                        parsedFrameHeader.State = new HeaderFrameParsingState(parsedFrameHeader.FrameLength, parsedFrameHeader.DataLength, TrustHeaderLength, ValidateHeaderFrameCheckSum);
                        break;
                    }

                    return(parsedFrameHeader);
                }
            }

            return(null);
        }
Пример #5
0
 /// <summary>
 /// Creates a new <see cref="CommandFrame"/> from serialization parameters.
 /// </summary>
 /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param>
 /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param>
 protected CommandFrame(SerializationInfo info, StreamingContext context)
     : base(info, context)
 {
     // Deserialize command frame
     m_frameHeader = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader));
 }