//****************************************************************************************************** // CommandFrame.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; // ReSharper disable VirtualMemberCallInConstructor namespace GSF.PhasorProtocols.IEEE1344 { /// /// Represents the IEEE 1344 implementation of a that can be sent or received. /// /// /// IEEE 1344 command frames are designed only to be sent to a device, not received from a device. As a result /// this frame does not implement for automated frame parsing. This class /// exposes a constructor that accepts a binary image in order to manually parse a command frame. /// [Serializable] public class CommandFrame : CommandFrameBase { #region [ Members ] /// /// Total frame length of a IEEE 1344 . /// public const ushort FrameLength = 16; // Fields private ulong m_idCode; #endregion #region [ Constructors ] /// /// Creates a new from the given . /// /// Binary image to parse. /// Start index into to begin parsing. /// Length of valid data within . /// /// This constructor is used by a consumer to parse a received IEEE 1344 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. /// /// must be at least 16. public CommandFrame(byte[] buffer, int startIndex, int length) : base(new CommandCellCollection(0), DeviceCommand.ReservedBits) { if (length < FrameLength) throw new ArgumentOutOfRangeException(nameof(length)); // Validate check-sum const int sumLength = FrameLength - 2; if (BigEndian.ToUInt16(buffer, startIndex + sumLength) != CalculateChecksum(buffer, startIndex, sumLength)) throw new InvalidOperationException($"Invalid binary image detected - check sum of {GetType().Name} did not match"); ParseBinaryImage(buffer, startIndex, length); } /// /// Creates a new from specified parameters. /// /// The ID code of this . /// The for this . /// /// This constructor is used by a consumer to generate an IEEE 1344 command frame. /// public CommandFrame(ulong idCode, DeviceCommand command) : base(new CommandCellCollection(0), command) { m_idCode = idCode; Timestamp = DateTime.UtcNow.Ticks; } /// /// Creates a new from serialization parameters. /// /// The with populated with data. /// The source for this deserialization. protected CommandFrame(SerializationInfo info, StreamingContext context) : base(info, context) { // Deserialize command frame m_idCode = info.GetUInt64("idCode64Bit"); } #endregion #region [ Properties ] /// /// Gets reference to the for this . /// [EditorBrowsable(EditorBrowsableState.Never)] // IEEE 1344 command frame doesn't support extended data - so we hide cell collection property... public override CommandCellCollection Cells => base.Cells; /// /// Gets or sets extended binary image data for this . /// [EditorBrowsable(EditorBrowsableState.Never)] // IEEE 1344 command frame doesn't support extended data - so we hide extended data property... public override byte[] ExtendedData { get => base.ExtendedData; set => base.ExtendedData = value; } /// /// 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 = m_idCode > ushort.MaxValue ? ushort.MaxValue : (ushort)value; } } /// /// Gets NTP based time representation of the ticks of this . /// public new NtpTimeTag TimeTag => new(Timestamp); /// /// Gets the length of the . /// protected override int HeaderLength => 12; /// /// Gets the binary header image of the object. /// protected override byte[] HeaderImage { get { byte[] buffer = new byte[HeaderLength]; BigEndian.CopyBytes((uint)TimeTag.Value, buffer, 0); BigEndian.CopyBytes(m_idCode, buffer, 4); return buffer; } } /// /// of string based property names and values for the object. /// public override Dictionary Attributes { get { Dictionary baseAttributes = base.Attributes; baseAttributes.Add("64-Bit ID Code", IDCode.ToString()); return baseAttributes; } } #endregion #region [ Methods ] /// /// 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) { Timestamp = new NtpTimeTag(BigEndian.ToUInt32(buffer, startIndex), 0).ToDateTime().Ticks; m_idCode = BigEndian.ToUInt64(buffer, startIndex + 4); return 12; } /// /// 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 command frame info.AddValue("idCode64Bit", m_idCode); } #endregion } }