//****************************************************************************************************** // HeaderFrame.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 01/14/2005 - J. Ritchie Carroll // Generated original version of source code. // 09/15/2009 - Stephen C. Wills // Added new header and license agreement. // 12/17/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Serialization; using GSF.IO.Checksums; using GSF.Parsing; namespace GSF.PhasorProtocols.IEEE1344 { /// /// Represents the IEEE 1344 implementation of a that can be sent or received. /// [Serializable] public class HeaderFrame : HeaderFrameBase, ISupportSourceIdentifiableFrameImage { #region [ Members ] // Fields private CommonFrameHeader m_frameHeader; private ulong m_idCode; #endregion #region [ Constructors ] /// /// Creates a new . /// /// /// This constructor is used by a consumer to generate an IEEE 1344 configuration frame and by the /// to parse an IEEE 1344 configuration frame. /// [EditorBrowsable(EditorBrowsableState.Never)] public HeaderFrame() : base(new HeaderCellCollection(Common.MaximumDataLength - 1)) { } /// /// Creates a new from serialization parameters. /// /// The with populated with data. /// The source for this deserialization. protected HeaderFrame(SerializationInfo info, StreamingContext context) : base(info, context) { // Deserialize header frame m_frameHeader = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader)); m_idCode = info.GetUInt64("idCode64Bit"); } #endregion #region [ Properties ] /// /// Gets or sets the ID code of this . /// public new ulong IDCode { get => m_idCode; set { m_idCode = value; // Base classes constrain maximum value to 65535 base.IDCode = value > ushort.MaxValue ? ushort.MaxValue : (ushort)value; } } /// /// Gets or sets exact timestamp, in ticks, of the data represented by this . /// /// /// The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001. /// public override Ticks Timestamp { get => CommonHeader.Timestamp; set { // Keep timestamp updates synchronized... CommonHeader.Timestamp = value; base.Timestamp = value; } } /// /// Gets the timestamp of this frame in NTP format. /// public new NtpTimeTag TimeTag => CommonHeader.TimeTag; /// /// Gets the identifier that is used to identify the IEEE 1344 frame. /// public FrameType TypeID => IEEE1344.FrameType.HeaderFrame; /// /// Gets or sets current . /// public CommonFrameHeader CommonHeader { // Make sure frame header exists - using base class timestamp to // prevent recursion (m_frameHeader doesn't exist yet) get => m_frameHeader ??= new CommonFrameHeader(TypeID, base.Timestamp); set { m_frameHeader = value; if (m_frameHeader is null) return; State = m_frameHeader.State as IHeaderFrameParsingState; base.Timestamp = m_frameHeader.Timestamp; } } // This interface implementation satisfies ISupportFrameImage.CommonHeader ICommonHeader ISupportFrameImage.CommonHeader { get => CommonHeader; set => CommonHeader = value as CommonFrameHeader; } /// /// Gets the length of the . /// protected override int HeaderLength => CommonFrameHeader.FixedLength; /// /// Gets the binary header image of the object. /// protected override byte[] HeaderImage { get { // Make sure to provide proper frame length for use in the common header image unchecked { CommonHeader.FrameLength = (ushort)BinaryLength; } return CommonHeader.BinaryImage; } } /// /// of string based property names and values for the object. /// public override Dictionary Attributes { get { Dictionary baseAttributes = base.Attributes; CommonHeader.AppendHeaderAttributes(baseAttributes); baseAttributes.Add("64-Bit ID Code", IDCode.ToString()); return baseAttributes; } } #endregion #region [ Methods ] /// /// Parses the binary image. /// /// Binary image to parse. /// Start index into to begin parsing. /// Length of valid data within . /// The length of the data that was parsed. /// /// This method is overridden to parse from cumulated frame images. /// public override int ParseBinaryImage(byte[] buffer, int startIndex, int length) { // If frame image collector was used, make sure and parse from entire frame image... if (m_frameHeader is null) return base.ParseBinaryImage(buffer, startIndex, length); // If all header frame images have been received, we can safely start parsing if (m_frameHeader.IsLastFrame) { FrameImageCollector frameImages = m_frameHeader.FrameImages; if (frameImages is not null) { // Each individual frame will already have had a CRC check, so we implement standard parse to // bypass ChannelBase CRC frame validation on cumulative frame image buffer = frameImages.BinaryImage; length = frameImages.BinaryLength; startIndex = 0; // Parse out header, body and footer images startIndex += ParseHeaderImage(buffer, startIndex, length); startIndex += ParseBodyImage(buffer, startIndex, length - startIndex); startIndex += ParseFooterImage(buffer, startIndex, length - startIndex); // Include 2 bytes for CRC that was already validated return startIndex + 2; } } // There are more header frame images coming, keep parser moving by returning total // frame length that was already parsed. return State.ParsedBinaryLength; } /// /// Parses the binary header image. /// /// Binary image to parse. /// Start index into to begin parsing. /// Length of valid data within . /// The length of the data that was parsed. protected override int ParseHeaderImage(byte[] buffer, int startIndex, int length) { // We already parsed the frame header, so we just skip past it... return CommonFrameHeader.FixedLength; } /// /// Calculates checksum of given . /// /// Buffer image over which to calculate checksum. /// Start index into to calculate checksum. /// Length of data within to calculate checksum. /// Checksum over specified portion of . protected override ushort CalculateChecksum(byte[] buffer, int offset, int length) { // IEEE 1344 uses CRC-CCITT to calculate checksum for frames return buffer.CrcCCITTChecksum(offset, length); } /// /// Populates a with the data needed to serialize the target object. /// /// The to populate with data. /// The destination for this serialization. public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); // Serialize configuration frame info.AddValue("frameHeader", m_frameHeader, typeof(CommonFrameHeader)); info.AddValue("idCode64Bit", m_idCode); } #endregion } }