368 lines · 14.1 KB · C#
RawDownload
//******************************************************************************************************//  CommonFrameHeader.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://  ----------------------------------------------------------------------------------------------------//  11/12/2004 - J. Ritchie Carroll//       Generated original version of source code.//  08/07/2009 - Josh L. Patterson//       Edited Comments.//  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.Runtime.Serialization;using GSF.IO.Checksums;using GSF.Parsing; namespace GSF.PhasorProtocols.IEEE1344{    /// <summary>    /// Represents the common header for all IEEE 1344 frames of data.    /// </summary>    [Serializable]    public class CommonFrameHeader : ICommonHeader<FrameType>, ISerializable    {        #region [ Members ]         // Constants         /// <summary>        /// Total fixed length of <see cref="CommonFrameHeader"/>.        /// </summary>        public const ushort FixedLength = 6;         // Fields        private FrameImageCollector m_frameImages;        private ushort m_sampleCount;        private ushort m_statusFlags;        private Ticks m_timestamp;        private IChannelParsingState m_state;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new <see cref="CommonFrameHeader"/> from specified parameters.        /// </summary>        /// <param name="typeID">The IEEE 1344 specific frame type of this frame.</param>        /// <param name="timestamp">The timestamp of this frame.</param>        public CommonFrameHeader(FrameType typeID, Ticks timestamp)        {            m_timestamp = timestamp;            TypeID = typeID;            FrameCount = 1;            IsFirstFrame = true;            IsLastFrame = true;        }         /// <summary>        /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>.        /// </summary>        /// <param name="buffer">Buffer that contains data to parse.</param>        /// <param name="startIndex">Start index into buffer where valid data begins.</param>        public CommonFrameHeader(byte[] buffer, int startIndex)        {            uint secondOfCentury = BigEndian.ToUInt32(buffer, startIndex);            m_sampleCount = BigEndian.ToUInt16(buffer, startIndex + 4);             // We go ahead and pre-grab cell's status flags so we can determine frame length - we            // leave start index at 6 so that cell will be able to parse flags as needed - note            // this increases needed common frame header size by 2 (i.e., BinaryLength + 2)            m_statusFlags = BigEndian.ToUInt16(buffer, startIndex + FixedLength);             // NTP timestamps based on NtpTimeTag class are designed to work for dates between            // 1968-01-20 and 2104-02-26 based on recommended bit interpretation in RFC-2030.            NtpTimeTag timetag = new(secondOfCentury, 0);             // Cache timestamp value            m_timestamp = timetag.ToDateTime().Ticks;        }         /// <summary>        /// Creates a new <see cref="CommonFrameHeader"/> 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 CommonFrameHeader(SerializationInfo info, StreamingContext context)        {            // Deserialize common frame header            m_sampleCount = info.GetUInt16("sampleCount");            m_statusFlags = info.GetUInt16("statusFlags");        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets the timestamp of this frame in NTP format.        /// </summary>        public NtpTimeTag TimeTag => new(m_timestamp);         /// <summary>        /// Gets or sets timestamp of this <see cref="CommonFrameHeader"/>.        /// </summary>        public Ticks Timestamp        {            get => m_timestamp;            set => m_timestamp = value;        }         /// <summary>        /// Gets or sets the IEEE 1344 specific frame type of this frame.        /// </summary>        /// <remarks>        /// <para>        /// This returns the protocol specific frame classification which uniquely identifies the frame type.        /// </para>        /// <para>        /// This is the <see cref="ICommonHeader{TTypeIdentifier}.TypeID"/> implementation.        /// </para>        /// </remarks>        public FrameType TypeID        {            get => (FrameType)(m_sampleCount & Common.FrameTypeMask);            set => m_sampleCount = (ushort)((m_sampleCount & ~Common.FrameTypeMask) | (ushort)value);        }         /// <summary>        /// Gets or sets flag from that determines if this is the first frame image in a series of images representing an entire frame.        /// </summary>        public bool IsFirstFrame        {            get => (m_sampleCount & (ushort)Bits.Bit12) == 0;            set            {                if (value)                    m_sampleCount = (ushort)(m_sampleCount & ~(ushort)Bits.Bit12);                else                    m_sampleCount = (ushort)(m_sampleCount | (ushort)Bits.Bit12);            }        }         /// <summary>        /// Gets or sets flag that determines if this is the last frame image in a series of images representing an entire frame.        /// </summary>        public bool IsLastFrame        {            get => (m_sampleCount & (ushort)Bits.Bit11) == 0;            set            {                if (value)                    m_sampleCount = (ushort)(m_sampleCount & ~(ushort)Bits.Bit11);                else                    m_sampleCount = (ushort)(m_sampleCount | (ushort)Bits.Bit11);            }        }         /// <summary>        /// Gets or sets the total frame count.        /// </summary>        public ushort FrameCount        {            get => (ushort)(m_sampleCount & Common.FrameCountMask);            set            {                if (value > Common.MaximumFrameCount)                    throw new OverflowException($"Frame count value cannot exceed {Common.MaximumFrameCount}");                 m_sampleCount = (ushort)((m_sampleCount & ~Common.FrameCountMask) | value);            }        }         /// <summary>        /// Gets or sets the parsing state for the <see cref="CommonFrameHeader"/> object.        /// </summary>        public IChannelParsingState State        {            get => m_state;            set => m_state = value;        }         // Gets or sets any additional state information - satisfies ICommonHeader<FrameType>.State interface property        object ICommonHeader<FrameType>.State        {            get => m_state;            set => m_state = value as IChannelParsingState;        }         /// <summary>        /// Gets the fundamental frame type of this frame.        /// </summary>        /// <remarks>        /// Frames are generally classified as data, configuration or header frames. This returns the general frame classification.        /// </remarks>        public FundamentalFrameType FrameType        {            get            {                // Translate IEEE 1344 specific frame type to fundamental frame type                return TypeID switch                {                    IEEE1344.FrameType.DataFrame => FundamentalFrameType.DataFrame,                    IEEE1344.FrameType.ConfigurationFrame => FundamentalFrameType.ConfigurationFrame,                    IEEE1344.FrameType.HeaderFrame => FundamentalFrameType.HeaderFrame,                    _ => FundamentalFrameType.Undetermined,                };            }        }         /// <summary>        /// Gets or sets reference to a <see cref="FrameImageCollector"/> associated the IEEE 1344 frame, if any.        /// </summary>        public FrameImageCollector FrameImages        {            get => m_frameImages;            set => m_frameImages = value;        }         /// <summary>        /// Gets or sets the entire length of the IEEE 1344 frame.        /// </summary>        public ushort FrameLength        {            get => (ushort)(m_statusFlags & Common.FrameLengthMask);            set            {                if (value > Common.MaximumFrameLength)                    throw new OverflowException($"Frame length value cannot exceed {Common.MaximumFrameLength}");                 m_statusFlags = (ushort)((m_statusFlags & ~Common.FrameLengthMask) | value);            }        }         /// <summary>        /// Gets or sets the length of the data in the IEEE 1344 frame (i.e., the <see cref="FrameLength"/> minus the header length and checksum: <see cref="FrameLength"/> - 8).        /// </summary>        public ushort DataLength        {            get =>                // Data length will be frame length minus common header length minus crc16                (ushort)(FrameLength - FixedLength - 2);            set            {                if (value > Common.MaximumDataLength)                    throw new OverflowException($"Data length value cannot exceed {Common.MaximumDataLength}");                 FrameLength = (ushort)(value + FixedLength + 2);            }        }         /// <summary>        /// Gets or sets the sample number (i.e., frame count) of this frame.        /// </summary>        public ushort SampleCount        {            get => (ushort)(m_sampleCount & ~Common.FrameTypeMask);            set            {                if (value > Common.MaximumSampleCount)                    throw new OverflowException($"Sample count value cannot exceed {Common.MaximumSampleCount}");                 m_sampleCount = (ushort)((m_sampleCount & Common.FrameTypeMask) | value);            }        }         /// <summary>        /// Gets the binary image of the common header portion of this frame.        /// </summary>        public byte[] BinaryImage        {            get            {                byte[] buffer = new byte[FixedLength];                 // Make sure frame length gets included in status flags for generated binary image                FrameLength = FixedLength;                 BigEndian.CopyBytes((uint)TimeTag.Value, buffer, 0);                BigEndian.CopyBytes(m_sampleCount, buffer, 4);                 return buffer;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Appends header specific attributes to <paramref name="attributes"/> dictionary.        /// </summary>        /// <param name="attributes">Dictionary to append header specific attributes to.</param>        internal void AppendHeaderAttributes(Dictionary<string, string> attributes)        {            attributes.Add("Frame Type", $"{(ushort)TypeID}: {TypeID}");             if (FrameImages is null)            {                attributes.Add("Frame Length", FrameLength.ToString());                attributes.Add("Frame Images", "0");            }            else            {                attributes.Add("Frame Length", FrameImages.BinaryLength.ToString());                attributes.Add("Frame Images", FrameImages.Count.ToString());            }             attributes.Add("Frame Count", FrameCount.ToString());            attributes.Add("Sample Count", m_sampleCount.ToString());            attributes.Add("Status Flags", m_statusFlags.ToString());            attributes.Add("Is First Frame", IsFirstFrame.ToString());            attributes.Add("Is Last Frame", IsLastFrame.ToString());        }         /// <summary>        /// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the target object.        /// </summary>        /// <param name="info">The <see cref="SerializationInfo"/> to populate with data.</param>        /// <param name="context">The destination <see cref="StreamingContext"/> for this serialization.</param>        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)        {            // Serialize unique common frame header values            info.AddValue("sampleCount", m_sampleCount);            info.AddValue("statusFlags", m_statusFlags);        }         #endregion         #region [ Static ]         // Static Methods         /// <summary>        /// Validates the CRC-CCITT for the specified IEEE 1344 buffer.        /// </summary>        /// <returns>A <see cref="bool"/> indicating whether the checksum is valid.</returns>        /// <param name="buffer">A <see cref="byte"/> array buffer.</param>        /// <param name="length">An <see cref="int"/> value as the number of bytes to read for the checksum.</param>        /// <param name="startIndex">An <see cref="int"/> value as the start index into being reading the value at.</param>        public static bool ChecksumIsValid(byte[] buffer, int startIndex, int length)        {            int sumLength = length - 2;            return BigEndian.ToUInt16(buffer, startIndex + sumLength) == buffer.CrcCCITTChecksum(startIndex, sumLength);        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t