/// <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); }
/// <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"); }
/// <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); }
/// <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); }
/// <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)); }